2 * DO NOT EDIT THIS FILE.
3 * See the following change record for more information,
4 * https://www.drupal.org/node/2815083
8 (function ($, Drupal) {
13 Drupal.states = states;
15 function invert(a, invertState) {
16 return invertState && typeof a !== 'undefined' ? !a : a;
19 function _compare2(a, b) {
21 return typeof a === 'undefined' ? a : true;
24 return typeof a === 'undefined' || typeof b === 'undefined';
27 function ternary(a, b) {
28 if (typeof a === 'undefined') {
31 if (typeof b === 'undefined') {
38 Drupal.behaviors.states = {
39 attach: function attach(context, settings) {
40 var $states = $(context).find('[data-drupal-states]');
41 var il = $states.length;
43 var _loop = function _loop(i) {
44 var config = JSON.parse($states[i].getAttribute('data-drupal-states'));
45 Object.keys(config || {}).forEach(function (state) {
46 new states.Dependent({
47 element: $($states[i]),
48 state: states.State.sanitize(state),
49 constraints: config[state]
54 for (var i = 0; i < il; i++) {
58 while (states.postponed.length) {
59 states.postponed.shift()();
64 states.Dependent = function (args) {
67 $.extend(this, { values: {}, oldValue: null }, args);
69 this.dependees = this.getDependees();
70 Object.keys(this.dependees || {}).forEach(function (selector) {
71 _this.initializeDependee(selector, _this.dependees[selector]);
75 states.Dependent.comparisons = {
76 RegExp: function RegExp(reference, value) {
77 return reference.test(value);
79 Function: function Function(reference, value) {
80 return reference(value);
82 Number: function Number(reference, value) {
83 return typeof value === 'string' ? _compare2(reference.toString(), value) : _compare2(reference, value);
87 states.Dependent.prototype = {
88 initializeDependee: function initializeDependee(selector, dependeeStates) {
91 this.values[selector] = {};
93 Object.keys(dependeeStates).forEach(function (i) {
94 var state = dependeeStates[i];
96 if ($.inArray(state, dependeeStates) === -1) {
100 state = states.State.sanitize(state);
102 _this2.values[selector][state.name] = null;
104 $(selector).on('state:' + state, { selector: selector, state: state }, function (e) {
105 _this2.update(e.data.selector, e.data.state, e.value);
108 new states.Trigger({ selector: selector, state: state });
111 compare: function compare(reference, selector, state) {
112 var value = this.values[selector][state.name];
113 if (reference.constructor.name in states.Dependent.comparisons) {
114 return states.Dependent.comparisons[reference.constructor.name](reference, value);
117 return _compare2(reference, value);
119 update: function update(selector, state, value) {
120 if (value !== this.values[selector][state.name]) {
121 this.values[selector][state.name] = value;
125 reevaluate: function reevaluate() {
126 var value = this.verifyConstraints(this.constraints);
128 if (value !== this.oldValue) {
129 this.oldValue = value;
131 value = invert(value, this.state.invert);
133 this.element.trigger({
134 type: 'state:' + this.state,
140 verifyConstraints: function verifyConstraints(constraints, selector) {
142 if ($.isArray(constraints)) {
143 var hasXor = $.inArray('xor', constraints) === -1;
144 var len = constraints.length;
145 for (var i = 0; i < len; i++) {
146 if (constraints[i] !== 'xor') {
147 var constraint = this.checkConstraints(constraints[i], selector, i);
149 if (constraint && (hasXor || result)) {
152 result = result || constraint;
155 } else if ($.isPlainObject(constraints)) {
156 for (var n in constraints) {
157 if (constraints.hasOwnProperty(n)) {
158 result = ternary(result, this.checkConstraints(constraints[n], selector, n));
160 if (result === false) {
168 checkConstraints: function checkConstraints(value, selector, state) {
169 if (typeof state !== 'string' || /[0-9]/.test(state[0])) {
171 } else if (typeof selector === 'undefined') {
176 if (state !== null) {
177 state = states.State.sanitize(state);
178 return invert(this.compare(value, selector, state), state.invert);
181 return this.verifyConstraints(value, selector);
183 getDependees: function getDependees() {
186 var _compare = this.compare;
187 this.compare = function (reference, selector, state) {
188 (cache[selector] || (cache[selector] = [])).push(state.name);
191 this.verifyConstraints(this.constraints);
193 this.compare = _compare;
199 states.Trigger = function (args) {
200 $.extend(this, args);
202 if (this.state in states.Trigger.states) {
203 this.element = $(this.selector);
205 if (!this.element.data('trigger:' + this.state)) {
211 states.Trigger.prototype = {
212 initialize: function initialize() {
215 var trigger = states.Trigger.states[this.state];
217 if (typeof trigger === 'function') {
218 trigger.call(window, this.element);
220 Object.keys(trigger || {}).forEach(function (event) {
221 _this3.defaultTrigger(event, trigger[event]);
225 this.element.data('trigger:' + this.state, true);
227 defaultTrigger: function defaultTrigger(event, valueFn) {
228 var oldValue = valueFn.call(this.element);
230 this.element.on(event, $.proxy(function (e) {
231 var value = valueFn.call(this.element, e);
233 if (oldValue !== value) {
234 this.element.trigger({
235 type: 'state:' + this.state,
243 states.postponed.push($.proxy(function () {
244 this.element.trigger({
245 type: 'state:' + this.state,
253 states.Trigger.states = {
255 keyup: function keyup() {
256 return this.val() === '';
261 change: function change() {
263 this.each(function () {
264 checked = $(this).prop('checked');
273 keyup: function keyup() {
274 if (this.length > 1) {
275 return this.filter(':checked').val() || false;
279 change: function change() {
280 if (this.length > 1) {
281 return this.filter(':checked').val() || false;
288 collapsed: function collapsed(e) {
289 return typeof e !== 'undefined' && 'value' in e ? e.value : !this.is('[open]');
294 states.State = function (state) {
295 this.pristine = state;
300 while (this.name.charAt(0) === '!') {
301 this.name = this.name.substring(1);
302 this.invert = !this.invert;
305 if (this.name in states.State.aliases) {
306 this.name = states.State.aliases[this.name];
313 states.State.sanitize = function (state) {
314 if (state instanceof states.State) {
318 return new states.State(state);
321 states.State.aliases = {
322 enabled: '!disabled',
323 invisible: '!visible',
325 untouched: '!touched',
326 optional: '!required',
328 unchecked: '!checked',
329 irrelevant: '!relevant',
330 expanded: '!collapsed',
333 readwrite: '!readonly'
336 states.State.prototype = {
339 toString: function toString() {
344 var $document = $(document);
345 $document.on('state:disabled', function (e) {
347 $(e.target).prop('disabled', e.value).closest('.js-form-item, .js-form-submit, .js-form-wrapper').toggleClass('form-disabled', e.value).find('select, input, textarea').prop('disabled', e.value);
351 $document.on('state:required', function (e) {
354 var label = 'label' + (e.target.id ? '[for=' + e.target.id + ']' : '');
355 var $label = $(e.target).attr({ required: 'required', 'aria-required': 'aria-required' }).closest('.js-form-item, .js-form-wrapper').find(label);
357 if (!$label.hasClass('js-form-required').length) {
358 $label.addClass('js-form-required form-required');
361 $(e.target).removeAttr('required aria-required').closest('.js-form-item, .js-form-wrapper').find('label.js-form-required').removeClass('js-form-required form-required');
366 $document.on('state:visible', function (e) {
368 $(e.target).closest('.js-form-item, .js-form-submit, .js-form-wrapper').toggle(e.value);
372 $document.on('state:checked', function (e) {
374 $(e.target).prop('checked', e.value);
378 $document.on('state:collapsed', function (e) {
380 if ($(e.target).is('[open]') === e.value) {
381 $(e.target).find('> summary').trigger('click');