PageSourceSearch

https://www.tpcdct.org/sites/default/files/js/js_FYzabNTAz2xfdqgIf_2b9v5uWfG-kklEmqwutjrHGJk.js

js tpcdct.org collected 2026-10-02 04:23:00 UTC 22,589 bytes, 689 lines download raw bytes

1(function ($) {
2
3/**
4 * The base States namespace.
5 *
6 * Having the local states variable allows us to use the States namespace
7 * without having to always declare "Drupal.states".
8 */
9var states = Drupal.states = {
10  // An array of functions that should be postponed.
11  postponed: []
12};
13
14/**
15 * Attaches the states.
16 */
17Drupal.behaviors.states = {
18  attach: function (context, settings) {
19    var $context = $(context);
20    for (var selector in settings.states) {
21      for (var state in settings.states[selector]) {
22        new states.Dependent({
23          element: $context.find(selector),
24          state: states.State.sanitize(state),
25          constraints: settings.states[selector][state]
26        });
27      }
28    }
29
30    // Execute all postponed functions now.
31    while (states.postponed.length) {
32      (states.postponed.shift())();
33    }
34  }
35};
36
37/**
38 * Object representing an element that depends on other elements.
39 *
40 * @param args
41 *   Object with the following keys (all of which are required):
42 *   - element: A jQuery object of the dependent element
43 *   - state: A State object describing the state that is dependent
44 *   - constraints: An object with dependency specifications. Lists all elements
45 *     that this element depends on. It can be nested and can contain arbitrary
46 *     AND and OR clauses.
47 */
48states.Dependent = function (args) {
49  $.extend(this, { values: {}, oldValue: null }, args);
50
51  this.dependees = this.getDependees();
52  for (var selector in this.dependees) {
53    this.initializeDependee(selector, this.dependees[selector]);
54  }
55};
56
57/**
58 * Comparison functions for comparing the value of an element with the
59 * specification from the dependency settings. If the object type can't be
60 * found in this list, the === operator is used by default.
61 */
62states.Dependent.comparisons = {
63  'RegExp': function (reference, value) {
64    return reference.test(value);
65  },
66  'Function': function (reference, value) {
67    // The "reference" variable is a comparison function.
68    return reference(value);
69  },
70  'Number': function (reference, value) {
71    // If "reference" is a number and "value" is a string, then cast reference
72    // as a string before applying the strict comparison in compare(). Otherwise
73    // numeric keys in the form's #states array fail to match string values
74    // returned from jQuery's val().
75    return (typeof value === 'string') ? compare(reference.toString(), value) : compare(reference, value);
76  }
77};
78
79states.Dependent.prototype = {
80  /**
81   * Initializes one of the elements this dependent depends on.
82   *
83   * @param selector
84   *   The CSS selector describing the dependee.
85   * @param dependeeStates
86   *   The list of states that have to be monitored for tracking the
87   *   dependee's compliance status.
88   */
89  initializeDependee: function (selector, dependeeStates) {
90    var state;
91
92    // Cache for the states of this dependee.
93    this.values[selector] = {};
94
95    for (var i in dependeeStates) {
96      if (dependeeStates.hasOwnProperty(i)) {
97        state = dependeeStates[i];
98        // Make sure we're not initializing this selector/state combination twice.
99        if ($.inArray(state, dependeeStates) === -1) {
100          continue;
101        }
102
103        state = states.State.sanitize(state);
104
105        // Initialize the value of this state.
106        this.values[selector][state.name] = null;
107
108        // Monitor state changes of the specified state for this dependee.
109        $(selector).bind('state:' + state, $.proxy(function (e) {
110          this.update(selector, state, e.value);
111        }, this));
112
113        // Make sure the event we just bound ourselves to is actually fired.
114        new states.Trigger({ selector: selector, state: state });
115      }
116    }
117  },
118
119  /**
120   * Compares a value with a reference value.
121   *
122   * @param reference
123   *   The value used for reference.
124   * @param selector
125   *   CSS selector describing the dependee.
126   * @param state
127   *   A State object describing the dependee's updated state.
128   *
129   * @return
130   *   true or false.
131   */
132  compare: function (reference, selector, state) {
133    var value = this.values[selector][state.name];
134    if (reference.constructor.name in states.Dependent.comparisons) {
135      // Use a custom compare function for certain reference value types.
136      return states.Dependent.comparisons[reference.constructor.name](reference, value);
137    }
138    else {
139      // Do a plain comparison otherwise.
140      return compare(reference, value);
141    }
142  },
143
144  /**
145   * Update the value of a dependee's state.
146   *
147   * @param selector
148   *   CSS selector describing the dependee.
149   * @param state
150   *   A State object describing the dependee's updated state.
151   * @param value
152   *   The new value for the dependee's updated state.
153   */
154  update: function (selector, state, value) {
155    // Only act when the 'new' value is actually new.
156    if (value !== this.values[selector][state.name]) {
157      this.values[selector][state.name] = value;
158      this.reevaluate();
159    }
160  },
161
162  /**
163   * Triggers change events in case a state changed.
164   */
165  reevaluate: function () {
166    // Check whether any constraint for this dependent state is satisifed.
167    var value = this.verifyConstraints(this.constraints);
168
169    // Only invoke a state change event when the value actually changed.
170    if (value !== this.oldValue) {
171      // Store the new value so that we can compare later whether the value
172      // actually changed.
173      this.oldValue = value;
174
175      // Normalize the value to match the normalized state name.
176      value = invert(value, this.state.invert);
177
178      // By adding "trigger: true", we ensure that state changes don't go into
179      // infinite loops.
180      this.element.trigger({ type: 'state:' + this.state, value: value, trigger: true });
181    }
182  },
183
184  /**
185   * Evaluates child constraints to determine if a constraint is satisfied.
186   *
187   * @param constraints
188   *   A constraint object or an array of constraints.
189   * @param selector
190   *   The selector for these constraints. If undefined, there isn't yet a
191   *   selector that these constraints apply to. In that case, the keys of the
192   *   object are interpreted as the selector if encountered.
193   *
194   * @return
195   *   true or false, depending on whether these constraints are satisfied.
196   */
197  verifyConstraints: function(constraints, selector) {
198    var result;
199    if ($.isArray(constraints)) {
200      // This constraint is an array (OR or XOR).
201      var hasXor = $.inArray('xor', constraints) === -1;
202      for (var i = 0, len = constraints.length; i < len; i++) {
203        if (constraints[i] != 'xor') {
204          var constraint = this.checkConstraints(constraints[i], selector, i);
205          // Return if this is OR and we have a satisfied constraint or if this
206          // is XOR and we have a second satisfied constraint.
207          if (constraint && (hasXor || result)) {
208            return hasXor;
209          }
210          result = result || constraint;
211        }
212      }
213    }
214    // Make sure we don't try to iterate over things other than objects. This
215    // shouldn't normally occur, but in case the condition definition is bogus,
216    // we don't want to end up with an infinite loop.
217    else if ($.isPlainObject(constraints)) {
218      // This constraint is an object (AND).
219      for (var n in constraints) {
220        if (constraints.hasOwnProperty(n)) {
221          result = ternary(result, this.checkConstraints(constraints[n], selector, n));
222          // False and anything else will evaluate to false, so return when any
223          // false condition is found.
224          if (result === false) { return false; }
225        }
226      }
227    }
228    return result;
229  },
230
231  /**
232   * Checks whether the value matches the requirements for this constraint.
233   *
234   * @param value
235   *   Either the value of a state or an array/object of constraints. In the
236   *   latter case, resolving the constraint continues.
237   * @param selector
238   *   The selector for this constraint. If undefined, there isn't yet a
239   *   selector that this constraint applies to. In that case, the state key is
240   *   propagates to a selector and resolving continues.
241   * @param state
242   *   The state to check for this constraint. If undefined, resolving
243   *   continues.
244   *   If both selector and state aren't undefined and valid non-numeric
245   *   strings, a lookup for the actual value of that selector's state is
246   *   performed. This parameter is not a State object but a pristine state
247   *   string.
248   *
249   * @return
250   *   true or false, depending on whether this constraint is satisfied.
251   */
252  checkConstraints: function(value, selector, state) {
253    // Normalize the last parameter. If it's non-numeric, we treat it either as
254    // a selector (in case there isn't one yet) or as a trigger/state.
255    if (typeof state !== 'string' || (/[0-9]/).test(state[0])) {
256      state = null;
257    }
258    else if (typeof selector === 'undefined') {
259      // Propagate the state to the selector when there isn't one yet.
260      selector = state;
261      state = null;
262    }
263
264    if (state !== null) {
265      // constraints is the actual constraints of an element to check for.
266      state = states.State.sanitize(state);
267      return invert(this.compare(value, selector, state), state.invert);
268    }
269    else {
270      // Resolve this constraint as an AND/OR operator.
271      return this.verifyConstraints(value, selector);
272    }
273  },
274
275  /**
276   * Gathers information about all required triggers.
277   */
278  getDependees: function() {
279    var cache = {};
280    // Swivel the lookup function so that we can record all available selector-
281    // state combinations for initialization.
282    var _compare = this.compare;
283    this.compare = function(reference, selector, state) {
284      (cache[selector] || (cache[selector] = [])).push(state.name);
285      // Return nothing (=== undefined) so that the constraint loops are not
286      // broken.
287    };
288
289    // This call doesn't actually verify anything but uses the resolving
290    // mechanism to go through the constraints array, trying to look up each
291    // value. Since we swivelled the compare function, this comparison returns
292    // undefined and lookup continues until the very end. Instead of lookup up
293    // the value, we record that combination of selector and state so that we
294    // can initialize all triggers.
295    this.verifyConstraints(this.constraints);
296    // Restore the original function.
297    this.compare = _compare;
298
299    return cache;
300  }
301};
302
303states.Trigger = function (args) {
304  $.extend(this, args);
305
306  if (this.state in states.Trigger.states) {
307    this.element = $(this.selector);
308
309    // Only call the trigger initializer when it wasn't yet attached to this
310    // element. Otherwise we'd end up with duplicate events.
311    if (!this.element.data('trigger:' + this.state)) {
312      this.initialize();
313    }
314  }
315};
316
317states.Trigger.prototype = {
318  initialize: function () {
319    var trigger = states.Trigger.states[this.state];
320
321    if (typeof trigger == 'function') {
322      // We have a custom trigger initialization function.
323      trigger.call(window, this.element);
324    }
325    else {
326      for (var event in trigger) {
327        if (trigger.hasOwnProperty(event)) {
328          this.defaultTrigger(event, trigger[event]);
329        }
330      }
331    }
332
333    // Mark this trigger as initialized for this element.
334    this.element.data('trigger:' + this.state, true);
335  },
336
337  defaultTrigger: function (event, valueFn) {
338    var oldValue = valueFn.call(this.element);
339
340    // Attach the event callback.
341    this.element.bind(event, $.proxy(function (e) {
342      var value = valueFn.call(this.element, e);
343      // Only trigger the event if the value has actually changed.
344      if (oldValue !== value) {
345        this.element.trigger({ type: 'state:' + this.state, value: value, oldValue: oldValue });
346        oldValue = value;
347      }
348    }, this));
349
350    states.postponed.push($.proxy(function () {
351      // Trigger the event once for initialization purposes.
352      this.element.trigger({ type: 'state:' + this.state, value: oldValue, oldValue: null });
353    }, this));
354  }
355};
356
357/**
358 * This list of states contains functions that are used to monitor the state
359 * of an element. Whenever an element depends on the state of another element,
360 * one of these trigger functions is added to the dependee so that the
361 * dependent element can be updated.
362 */
363states.Trigger.states = {
364  // 'empty' describes the state to be monitored
365  empty: {
366    // 'keyup' is the (native DOM) event that we watch for.
367    'keyup': function () {
368      // The function associated to that trigger returns the new value for the
369      // state.
370      return this.val() == '';
371    }
372  },
373
374  checked: {
375    'change': function () {
376      return this.is(':checked');
377    }
378  },
379
380  // For radio buttons, only return the value if the radio button is selected.
381  value: {
382    'keyup': function () {
383      // Radio buttons share the same :input[name="key"] selector.
384      if (this.length > 1) {
385        // Initial checked value of radios is undefined, so we return false.
386        return this.filter(':checked').val() || false;
387      }
388      return this.val();
389    },
390    'change': function () {
391      // Radio buttons share the same :input[name="key"] selector.
392      if (this.length > 1) {
393        // Initial checked value of radios is undefined, so we return false.
394        return this.filter(':checked').val() || false;
395      }
396      return this.val();
397    }
398  },
399
400  collapsed: {
401    'collapsed': function(e) {
402      return (typeof e !== 'undefined' && 'value' in e) ? e.value : this.is('.collapsed');
403    }
404  }
405};
406
407
408/**
409 * A state object is used for describing the state and performing aliasing.
410 */
411states.State = function(state) {
412  // We may need the original unresolved name later.
413  this.pristine = this.name = state;
414
415  // Normalize the state name.
416  while (true) {
417    // Iteratively remove exclamation marks and invert the value.
418    while (this.name.charAt(0) == '!') {
419      this.name = this.name.substring(1);
420      this.invert = !this.invert;
421    }
422
423    // Replace the state with its normalized name.
424    if (this.name in states.State.aliases) {
425      this.name = states.State.aliases[this.name];
426    }
427    else {
428      break;
429    }
430  }
431};
432
433/**
434 * Creates a new State object by sanitizing the passed value.
435 */
436states.State.sanitize = function (state) {
437  if (state instanceof states.State) {
438    return state;
439  }
440  else {
441    return new states.State(state);
442  }
443};
444
445/**
446 * This list of aliases is used to normalize states and associates negated names
447 * with their respective inverse state.
448 */
449states.State.aliases = {
450  'enabled': '!disabled',
451  'invisible': '!visible',
452  'invalid': '!valid',
453  'untouched': '!touched',
454  'optional': '!required',
455  'filled': '!empty',
456  'unchecked': '!checked',
457  'irrelevant': '!relevant',
458  'expanded': '!collapsed',
459  'readwrite': '!readonly'
460};
461
462states.State.prototype = {
463  invert: false,
464
465  /**
466   * Ensures that just using the state object returns the name.
467   */
468  toString: function() {
469    return this.name;
470  }
471};
472
473/**
474 * Global state change handlers. These are bound to "document" to cover all
475 * elements whose state changes. Events sent to elements within the page
476 * bubble up to these handlers. We use this system so that themes and modules
477 * can override these state change handlers for particular parts of a page.
478 */
479$(document).bind('state:disabled', function(e) {
480  // Only act when this change was triggered by a dependency and not by the
481  // element monitoring itself.
482  if (e.trigger) {
483    $(e.target)
484      .attr('disabled', e.value)
485        .closest('.form-item, .form-submit, .form-wrapper').toggleClass('form-disabled', e.value)
486        .find('select, input, textarea').attr('disabled', e.value);
487
488    // Note: WebKit nightlies don't reflect that change correctly.
489    // See https://bugs.webkit.org/show_bug.cgi?id=23789
490  }
491});
492
493$(document).bind('state:required', function(e) {
494  if (e.trigger) {
495    if (e.value) {
496      var $label = $(e.target).closest('.form-item, .form-wrapper').find('label');
497      // Avoids duplicate required markers on initialization.
498      if (!$label.find('.form-required').length) {
499        $label.append('<span class="form-required">*</span>');
500      }
501    }
502    else {
503      $(e.target).closest('.form-item, .form-wrapper').find('label .form-required').remove();
504    }
505  }
506});
507
508$(document).bind('state:visible', function(e) {
509  if (e.trigger) {
510      $(e.target).closest('.form-item, .form-submit, .form-wrapper').toggle(e.value);
511  }
512});
513
514$(document).bind('state:checked', function(e) {
515  if (e.trigger) {
516    $(e.target).attr('checked', e.value);
517  }
518});
519
520$(document).bind('state:collapsed', function(e) {
521  if (e.trigger) {
522    if ($(e.target).is('.collapsed') !== e.value) {
523      $('> legend a', e.target).click();
524    }
525  }
526});
527
528/**
529 * These are helper functions implementing addition "operators" and don't
530 * implement any logic that is particular to states.
531 */
532
533// Bitwise AND with a third undefined state.
534function ternary (a, b) {
535  return typeof a === 'undefined' ? b : (typeof b === 'undefined' ? a : a && b);
536}
537
538// Inverts a (if it's not undefined) when invert is true.
539function invert (a, invert) {
540  return (invert && typeof a !== 'undefined') ? !a : a;
541}
542
543// Compares two values while ignoring undefined values.
544function compare (a, b) {
545  return (a === b) ? (typeof a === 'undefined' ? a : true) : (typeof a === 'undefined' || typeof b === 'undefined');
546}
547
548})(jQuery);
549;
550(function ($) {
551
552/**
553 * Prevents consecutive form submissions of identical form values.
554 *
555 * Repetitive form submissions that would submit the identical form values are
556 * prevented, unless the form values are different from the previously
557 * submitted values.
558 *
559 * This is a simplified re-implementation of a user-agent behavior that should
560 * be natively supported by major web browsers, but at this time, only Firefox
561 * has a built-in protection.
562 *
563 * A form value-based approach ensures that the constraint is triggered for
564 * consecutive, identical form submissions only. Compared to that, a form
565 * button-based approach would (1) rely on [visible] buttons to exist where
566 * technically not required and (2) require more complex state management if
567 * there are multiple buttons in a form.
568 *
569 * This implementation is based on form-level submit events only and relies on
570 * jQuery's serialize() method to determine submitted form values. As such, the
571 * following limitations exist:
572 *
573 * - Event handlers on form buttons that preventDefault() do not receive a
574 *   double-submit protection. That is deemed to be fine, since such button
575 *   events typically trigger reversible client-side or server-side operations
576 *   that are local to the context of a form only.
577 * - Changed values in advanced form controls, such as file inputs, are not part
578 *   of the form values being compared between consecutive form submits (due to
579 *   limitations of jQuery.serialize()). That is deemed to be acceptable,
580 *   because if the user forgot to attach a file, then the size of HTTP payload
581 *   will most likely be small enough to be fully passed to the server endpoint
582 *   within (milli)seconds. If a user mistakenly attached a wrong file and is
583 *   technically versed enough to cancel the form submission (and HTTP payload)
584 *   in order to attach a different file, then that edge-case is not supported
585 *   here.
586 *
587 * Lastly, all forms submitted via HTTP GET are idempotent by definition of HTTP
588 * standards, so excluded in this implementation.
589 */
590Drupal.behaviors.formSingleSubmit = {
591  attach: function () {
592    function onFormSubmit (e) {
593      var $form = $(e.currentTarget);
594      var formValues = $form.serialize();
595      var previousValues = $form.attr('data-drupal-form-submit-last');
596      if (previousValues === formValues) {
597        e.preventDefault();
598      }
599      else {
600        $form.attr('data-drupal-form-submit-last', formValues);
601      }
602    }
603
604    $('body').once('form-single-submit')
605      .delegate('form:not([method~="GET"])', 'submit.singleSubmit', onFormSubmit);
606  }
607};
608
609})(jQuery);
610;
611(function ($) {
612
613/**
614 * Retrieves the summary for the first element.
615 */
616$.fn.drupalGetSummary = function () {
617  var callback = this.data('summaryCallback');
618  return (this[0] && callback) ? $.trim(callback(this[0])) : '';
619};
620
621/**
622 * Sets the summary for all matched elements.
623 *
624 * @param callback
625 *   Either a function that will be called each time the summary is
626 *   retrieved or a string (which is returned each time).
627 */
628$.fn.drupalSetSummary = function (callback) {
629  var self = this;
630
631  // To facilitate things, the callback should always be a function. If it's
632  // not, we wrap it into an anonymous function which just returns the value.
633  if (typeof callback != 'function') {
634    var val = callback;
635    callback = function () { return val; };
636  }
637
638  return this
639    .data('summaryCallback', callback)
640    // To prevent duplicate events, the handlers are first removed and then
641    // (re-)added.
642    .unbind('formUpdated.summary')
643    .bind('formUpdated.summary', function () {
644      self.trigger('summaryUpdated');
645    })
646    // The actual summaryUpdated handler doesn't fire when the callback is
647    // changed, so we have to do this manually.
648    .trigger('summaryUpdated');
649};
650
651/**
652 * Sends a 'formUpdated' event each time a form element is modified.
653 */
654Drupal.behaviors.formUpdated = {
655  attach: function (context) {
656    // These events are namespaced so that we can remove them later.
657    var events = 'change.formUpdated click.formUpdated blur.formUpdated keyup.formUpdated';
658    $(context)
659      // Since context could be an input element itself, it's added back to
660      // the jQuery object and filtered again.
661      .find(':input').andSelf().filter(':input')
662      // To prevent duplicate events, the handlers are first removed and then
663      // (re-)added.
664      .unbind(events).bind(events, function () {
665        $(this).trigger('formUpdated');
666      });
667  }
668};
669
670/**
671 * Prepopulate form fields with information from the visitor cookie.
672 */
673Drupal.behaviors.fillUserInfoFromCookie = {
674  attach: function (context, settings) {
675    $('form.user-info-from-cookie').once('user-info-from-cookie', function () {
676      var formContext = this;
677      $.each(['name', 'mail', 'homepage'], function () {
678        var $element = $('[name=' + this + ']', formContext);
679        var cookie = $.cookie('Drupal.visitor.' + this);
680        if ($element.length && cookie) {
681          $element.val(cookie);
682        }
683      });
684    });
685  }
686};
687
688})(jQuery);
689;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.