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) {
9 var states = Drupal.states = {
13 Drupal.behaviors.states = {
14 attach: function attach(context, settings) {
15 var $states = $(context).find('[data-drupal-states]');
18 var il = $states.length;
19 for (var i = 0; i < il; i++) {
20 config = JSON.parse($states[i].getAttribute('data-drupal-states'));
21 for (state in config) {
22 if (config.hasOwnProperty(state)) {
23 new states.Dependent({
24 element: $($states[i]),
25 state: states.State.sanitize(state),
26 constraints: config[state]
32 while (states.postponed.length) {
33 states.postponed.shift()();
38 states.Dependent = function (args) {
39 $.extend(this, { values: {}, oldValue: null }, args);
41 this.dependees = this.getDependees();
42 for (var selector in this.dependees) {
43 if (this.dependees.hasOwnProperty(selector)) {
44 this.initializeDependee(selector, this.dependees[selector]);
49 states.Dependent.comparisons = {
50 RegExp: function RegExp(reference, value) {
51 return reference.test(value);
53 Function: function Function(reference, value) {
54 return reference(value);
56 Number: function Number(reference, value) {
57 return typeof value === 'string' ? _compare2(reference.toString(), value) : _compare2(reference, value);
61 states.Dependent.prototype = {
62 initializeDependee: function initializeDependee(selector, dependeeStates) {
66 function stateEventHandler(e) {
67 self.update(e.data.selector, e.data.state, e.value);
70 this.values[selector] = {};
72 for (var i in dependeeStates) {
73 if (dependeeStates.hasOwnProperty(i)) {
74 state = dependeeStates[i];
76 if ($.inArray(state, dependeeStates) === -1) {
80 state = states.State.sanitize(state);
82 this.values[selector][state.name] = null;
84 $(selector).on('state:' + state, { selector: selector, state: state }, stateEventHandler);
86 new states.Trigger({ selector: selector, state: state });
90 compare: function compare(reference, selector, state) {
91 var value = this.values[selector][state.name];
92 if (reference.constructor.name in states.Dependent.comparisons) {
93 return states.Dependent.comparisons[reference.constructor.name](reference, value);
96 return _compare2(reference, value);
98 update: function update(selector, state, value) {
99 if (value !== this.values[selector][state.name]) {
100 this.values[selector][state.name] = value;
104 reevaluate: function reevaluate() {
105 var value = this.verifyConstraints(this.constraints);
107 if (value !== this.oldValue) {
108 this.oldValue = value;
110 value = invert(value, this.state.invert);
112 this.element.trigger({ type: 'state:' + this.state, value: value, trigger: true });
115 verifyConstraints: function verifyConstraints(constraints, selector) {
117 if ($.isArray(constraints)) {
118 var hasXor = $.inArray('xor', constraints) === -1;
119 var len = constraints.length;
120 for (var i = 0; i < len; i++) {
121 if (constraints[i] !== 'xor') {
122 var constraint = this.checkConstraints(constraints[i], selector, i);
124 if (constraint && (hasXor || result)) {
127 result = result || constraint;
130 } else if ($.isPlainObject(constraints)) {
131 for (var n in constraints) {
132 if (constraints.hasOwnProperty(n)) {
133 result = ternary(result, this.checkConstraints(constraints[n], selector, n));
135 if (result === false) {
143 checkConstraints: function checkConstraints(value, selector, state) {
144 if (typeof state !== 'string' || /[0-9]/.test(state[0])) {
146 } else if (typeof selector === 'undefined') {
151 if (state !== null) {
152 state = states.State.sanitize(state);
153 return invert(this.compare(value, selector, state), state.invert);
156 return this.verifyConstraints(value, selector);
158 getDependees: function getDependees() {
161 var _compare = this.compare;
162 this.compare = function (reference, selector, state) {
163 (cache[selector] || (cache[selector] = [])).push(state.name);
166 this.verifyConstraints(this.constraints);
168 this.compare = _compare;
174 states.Trigger = function (args) {
175 $.extend(this, args);
177 if (this.state in states.Trigger.states) {
178 this.element = $(this.selector);
180 if (!this.element.data('trigger:' + this.state)) {
186 states.Trigger.prototype = {
187 initialize: function initialize() {
188 var trigger = states.Trigger.states[this.state];
190 if (typeof trigger === 'function') {
191 trigger.call(window, this.element);
193 for (var event in trigger) {
194 if (trigger.hasOwnProperty(event)) {
195 this.defaultTrigger(event, trigger[event]);
200 this.element.data('trigger:' + this.state, true);
202 defaultTrigger: function defaultTrigger(event, valueFn) {
203 var oldValue = valueFn.call(this.element);
205 this.element.on(event, $.proxy(function (e) {
206 var value = valueFn.call(this.element, e);
208 if (oldValue !== value) {
209 this.element.trigger({ type: 'state:' + this.state, value: value, oldValue: oldValue });
214 states.postponed.push($.proxy(function () {
215 this.element.trigger({ type: 'state:' + this.state, value: oldValue, oldValue: null });
220 states.Trigger.states = {
222 keyup: function keyup() {
223 return this.val() === '';
228 change: function change() {
230 this.each(function () {
231 checked = $(this).prop('checked');
240 keyup: function keyup() {
241 if (this.length > 1) {
242 return this.filter(':checked').val() || false;
246 change: function change() {
247 if (this.length > 1) {
248 return this.filter(':checked').val() || false;
255 collapsed: function collapsed(e) {
256 return typeof e !== 'undefined' && 'value' in e ? e.value : !this.is('[open]');
261 states.State = function (state) {
262 this.pristine = this.name = state;
266 while (this.name.charAt(0) === '!') {
267 this.name = this.name.substring(1);
268 this.invert = !this.invert;
271 if (this.name in states.State.aliases) {
272 this.name = states.State.aliases[this.name];
279 states.State.sanitize = function (state) {
280 if (state instanceof states.State) {
284 return new states.State(state);
287 states.State.aliases = {
288 enabled: '!disabled',
289 invisible: '!visible',
291 untouched: '!touched',
292 optional: '!required',
294 unchecked: '!checked',
295 irrelevant: '!relevant',
296 expanded: '!collapsed',
299 readwrite: '!readonly'
302 states.State.prototype = {
305 toString: function toString() {
310 var $document = $(document);
311 $document.on('state:disabled', function (e) {
313 $(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);
317 $document.on('state:required', function (e) {
320 var label = 'label' + (e.target.id ? '[for=' + e.target.id + ']' : '');
321 var $label = $(e.target).attr({ required: 'required', 'aria-required': 'aria-required' }).closest('.js-form-item, .js-form-wrapper').find(label);
323 if (!$label.hasClass('js-form-required').length) {
324 $label.addClass('js-form-required form-required');
327 $(e.target).removeAttr('required aria-required').closest('.js-form-item, .js-form-wrapper').find('label.js-form-required').removeClass('js-form-required form-required');
332 $document.on('state:visible', function (e) {
334 $(e.target).closest('.js-form-item, .js-form-submit, .js-form-wrapper').toggle(e.value);
338 $document.on('state:checked', function (e) {
340 $(e.target).prop('checked', e.value);
344 $document.on('state:collapsed', function (e) {
346 if ($(e.target).is('[open]') === e.value) {
347 $(e.target).find('> summary').trigger('click');
352 function ternary(a, b) {
353 if (typeof a === 'undefined') {
355 } else if (typeof b === 'undefined') {
362 function invert(a, invertState) {
363 return invertState && typeof a !== 'undefined' ? !a : a;
366 function _compare2(a, b) {
368 return typeof a === 'undefined' ? a : true;
371 return typeof a === 'undefined' || typeof b === 'undefined';