PageSourceSearch

https://www.greendogdental.com/sites/default/files/js/js_7ot7_wVaM7rBbirlNCEF4OChSaLfT8hZpwIpJrPrwZg.js

js greendogdental.com collected 2026-09-24 11:55:54 UTC 85,684 bytes, 2,506 lines download raw bytes

1/**
2* DO NOT EDIT THIS FILE.
3* See the following change record for more information,
4* https://www.drupal.org/node/2815083
5* @preserve
6**/
7
8Drupal.debounce = function (func, wait, immediate) {
9  var timeout = void 0;
10  var result = void 0;
11  return function () {
12    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
13      args[_key] = arguments[_key];
14    }
15
16    var context = this;
17    var later = function later() {
18      timeout = null;
19      if (!immediate) {
20        result = func.apply(context, args);
21      }
22    };
23    var callNow = immediate && !timeout;
24    clearTimeout(timeout);
25    timeout = setTimeout(later, wait);
26    if (callNow) {
27      result = func.apply(context, args);
28    }
29    return result;
30  };
31};;
32/**
33* DO NOT EDIT THIS FILE.
34* See the following change record for more information,
35* https://www.drupal.org/node/2815083
36* @preserve
37**/
38
39(function ($, Drupal, debounce) {
40  $.fn.drupalGetSummary = function () {
41    var callback = this.data('summaryCallback');
42    return this[0] && callback ? $.trim(callback(this[0])) : '';
43  };
44
45  $.fn.drupalSetSummary = function (callback) {
46    var self = this;
47
48    if (typeof callback !== 'function') {
49      var val = callback;
50      callback = function callback() {
51        return val;
52      };
53    }
54
55    return this.data('summaryCallback', callback).off('formUpdated.summary').on('formUpdated.summary', function () {
56      self.trigger('summaryUpdated');
57    }).trigger('summaryUpdated');
58  };
59
60  Drupal.behaviors.formSingleSubmit = {
61    attach: function attach() {
62      function onFormSubmit(e) {
63        var $form = $(e.currentTarget);
64        var formValues = $form.serialize();
65        var previousValues = $form.attr('data-drupal-form-submit-last');
66        if (previousValues === formValues) {
67          e.preventDefault();
68        } else {
69          $form.attr('data-drupal-form-submit-last', formValues);
70        }
71      }
72
73      $('body').once('form-single-submit').on('submit.singleSubmit', 'form:not([method~="GET"])', onFormSubmit);
74    }
75  };
76
77  function triggerFormUpdated(element) {
78    $(element).trigger('formUpdated');
79  }
80
81  function fieldsList(form) {
82    var $fieldList = $(form).find('[name]').map(function (index, element) {
83      return element.getAttribute('id');
84    });
85
86    return $.makeArray($fieldList);
87  }
88
89  Drupal.behaviors.formUpdated = {
90    attach: function attach(context) {
91      var $context = $(context);
92      var contextIsForm = $context.is('form');
93      var $forms = (contextIsForm ? $context : $context.find('form')).once('form-updated');
94      var formFields = void 0;
95
96      if ($forms.length) {
97        $.makeArray($forms).forEach(function (form) {
98          var events = 'change.formUpdated input.formUpdated ';
99          var eventHandler = debounce(function (event) {
100            triggerFormUpdated(event.target);
101          }, 300);
102          formFields = fieldsList(form).join(',');
103
104          form.setAttribute('data-drupal-form-fields', formFields);
105          $(form).on(events, eventHandler);
106        });
107      }
108
109      if (contextIsForm) {
110        formFields = fieldsList(context).join(',');
111
112        var currentFields = $(context).attr('data-drupal-form-fields');
113
114        if (formFields !== currentFields) {
115          triggerFormUpdated(context);
116        }
117      }
118    },
119    detach: function detach(context, settings, trigger) {
120      var $context = $(context);
121      var contextIsForm = $context.is('form');
122      if (trigger === 'unload') {
123        var $forms = (contextIsForm ? $context : $context.find('form')).removeOnce('form-updated');
124        if ($forms.length) {
125          $.makeArray($forms).forEach(function (form) {
126            form.removeAttribute('data-drupal-form-fields');
127            $(form).off('.formUpdated');
128          });
129        }
130      }
131    }
132  };
133
134  Drupal.behaviors.fillUserInfoFromBrowser = {
135    attach: function attach(context, settings) {
136      var userInfo = ['name', 'mail', 'homepage'];
137      var $forms = $('[data-user-info-from-browser]').once('user-info-from-browser');
138      if ($forms.length) {
139        userInfo.forEach(function (info) {
140          var $element = $forms.find('[name=' + info + ']');
141          var browserData = localStorage.getItem('Drupal.visitor.' + info);
142          var emptyOrDefault = $element.val() === '' || $element.attr('data-drupal-default-value') === $element.val();
143          if ($element.length && emptyOrDefault && browserData) {
144            $element.val(browserData);
145          }
146        });
147      }
148      $forms.on('submit', function () {
149        userInfo.forEach(function (info) {
150          var $element = $forms.find('[name=' + info + ']');
151          if ($element.length) {
152            localStorage.setItem('Drupal.visitor.' + info, $element.val());
153          }
154        });
155      });
156    }
157  };
158
159  var handleFragmentLinkClickOrHashChange = function handleFragmentLinkClickOrHashChange(e) {
160    var url = void 0;
161    if (e.type === 'click') {
162      url = e.currentTarget.location ? e.currentTarget.location : e.currentTarget;
163    } else {
164      url = window.location;
165    }
166    var hash = url.hash.substr(1);
167    if (hash) {
168      var $target = $('#' + hash);
169      $('body').trigger('formFragmentLinkClickOrHashChange', [$target]);
170
171      setTimeout(function () {
172        return $target.trigger('focus');
173      }, 300);
174    }
175  };
176
177  var debouncedHandleFragmentLinkClickOrHashChange = debounce(handleFragmentLinkClickOrHashChange, 300, true);
178
179  $(window).on('hashchange.form-fragment', debouncedHandleFragmentLinkClickOrHashChange);
180
181  $(document).on('click.form-fragment', 'a[href*="#"]', debouncedHandleFragmentLinkClickOrHashChange);
182})(jQuery, Drupal, Drupal.debounce);;
183/**
184 * @file
185 * Webform behaviors.
186 */
187
188(function ($, Drupal) {
189
190  'use strict';
191
192  // Trigger Drupal's attaching of behaviors after the page is
193  // completely loaded.
194  // @see https://stackoverflow.com/questions/37838430/detect-if-page-is-load-from-back-button
195  // @see https://stackoverflow.com/questions/20899274/how-to-refresh-page-on-back-button-click/20899422#20899422
196  var isChrome = (/chrom(e|ium)/.test(window.navigator.userAgent.toLowerCase()));
197  if (isChrome) {
198    // Track back button in navigation.
199    // @see https://stackoverflow.com/questions/37838430/detect-if-page-is-load-from-back-button
200    var backButton = false;
201    if (window.performance) {
202      var navEntries = window.performance.getEntriesByType('navigation');
203      if (navEntries.length > 0 && navEntries[0].type === 'back_forward') {
204        backButton = true;
205      }
206      else if (window.performance.navigation
207        && window.performance.navigation.type === window.performance.navigation.TYPE_BACK_FORWARD) {
208        backButton = true;
209      }
210    }
211
212    // If the back button is pressed, delay Drupal's attaching of behaviors.
213    if (backButton) {
214      var attachBehaviors = Drupal.attachBehaviors;
215      Drupal.attachBehaviors = function (context, settings) {
216        setTimeout(function (context, settings) {
217          attachBehaviors(context, settings);
218        }, 300);
219      };
220    }
221  }
222
223})(jQuery, Drupal);
224;
225/**
226* DO NOT EDIT THIS FILE.
227* See the following change record for more information,
228* https://www.drupal.org/node/2815083
229* @preserve
230**/
231
232(function ($, Drupal) {
233  var states = {
234    postponed: []
235  };
236
237  Drupal.states = states;
238
239  function invert(a, invertState) {
240    return invertState && typeof a !== 'undefined' ? !a : a;
241  }
242
243  function _compare2(a, b) {
244    if (a === b) {
245      return typeof a === 'undefined' ? a : true;
246    }
247
248    return typeof a === 'undefined' || typeof b === 'undefined';
249  }
250
251  function ternary(a, b) {
252    if (typeof a === 'undefined') {
253      return b;
254    }
255    if (typeof b === 'undefined') {
256      return a;
257    }
258
259    return a && b;
260  }
261
262  Drupal.behaviors.states = {
263    attach: function attach(context, settings) {
264      var $states = $(context).find('[data-drupal-states]');
265      var il = $states.length;
266
267      var _loop = function _loop(i) {
268        var config = JSON.parse($states[i].getAttribute('data-drupal-states'));
269        Object.keys(config || {}).forEach(function (state) {
270          new states.Dependent({
271            element: $($states[i]),
272            state: states.State.sanitize(state),
273            constraints: config[state]
274          });
275        });
276      };
277
278      for (var i = 0; i < il; i++) {
279        _loop(i);
280      }
281
282      while (states.postponed.length) {
283        states.postponed.shift()();
284      }
285    }
286  };
287
288  states.Dependent = function (args) {
289    var _this = this;
290
291    $.extend(this, { values: {}, oldValue: null }, args);
292
293    this.dependees = this.getDependees();
294    Object.keys(this.dependees || {}).forEach(function (selector) {
295      _this.initializeDependee(selector, _this.dependees[selector]);
296    });
297  };
298
299  states.Dependent.comparisons = {
300    RegExp: function RegExp(reference, value) {
301      return reference.test(value);
302    },
303    Function: function Function(reference, value) {
304      return reference(value);
305    },
306    Number: function Number(reference, value) {
307      return typeof value === 'string' ? _compare2(reference.toString(), value) : _compare2(reference, value);
308    }
309  };
310
311  states.Dependent.prototype = {
312    initializeDependee: function initializeDependee(selector, dependeeStates) {
313      var _this2 = this;
314
315      this.values[selector] = {};
316
317      Object.keys(dependeeStates).forEach(function (i) {
318        var state = dependeeStates[i];
319
320        if ($.inArray(state, dependeeStates) === -1) {
321          return;
322        }
323
324        state = states.State.sanitize(state);
325
326        _this2.values[selector][state.name] = null;
327
328        $(selector).on('state:' + state, { selector: selector, state: state }, function (e) {
329          _this2.update(e.data.selector, e.data.state, e.value);
330        });
331
332        new states.Trigger({ selector: selector, state: state });
333      });
334    },
335    compare: function compare(reference, selector, state) {
336      var value = this.values[selector][state.name];
337      if (reference.constructor.name in states.Dependent.comparisons) {
338        return states.Dependent.comparisons[reference.constructor.name](reference, value);
339      }
340
341      return _compare2(reference, value);
342    },
343    update: function update(selector, state, value) {
344      if (value !== this.values[selector][state.name]) {
345        this.values[selector][state.name] = value;
346        this.reevaluate();
347      }
348    },
349    reevaluate: function reevaluate() {
350      var value = this.verifyConstraints(this.constraints);
351
352      if (value !== this.oldValue) {
353        this.oldValue = value;
354
355        value = invert(value, this.state.invert);
356
357        this.element.trigger({
358          type: 'state:' + this.state,
359          value: value,
360          trigger: true
361        });
362      }
363    },
364    verifyConstraints: function verifyConstraints(constraints, selector) {
365      var result = void 0;
366      if ($.isArray(constraints)) {
367        var hasXor = $.inArray('xor', constraints) === -1;
368        var len = constraints.length;
369        for (var i = 0; i < len; i++) {
370          if (constraints[i] !== 'xor') {
371            var constraint = this.checkConstraints(constraints[i], selector, i);
372
373            if (constraint && (hasXor || result)) {
374              return hasXor;
375            }
376            result = result || constraint;
377          }
378        }
379      } else if ($.isPlainObject(constraints)) {
380          for (var n in constraints) {
381            if (constraints.hasOwnProperty(n)) {
382              result = ternary(result, this.checkConstraints(constraints[n], selector, n));
383
384              if (result === false) {
385                return false;
386              }
387            }
388          }
389        }
390      return result;
391    },
392    checkConstraints: function checkConstraints(value, selector, state) {
393      if (typeof state !== 'string' || /[0-9]/.test(state[0])) {
394        state = null;
395      } else if (typeof selector === 'undefined') {
396        selector = state;
397        state = null;
398      }
399
400      if (state !== null) {
401        state = states.State.sanitize(state);
402        return invert(this.compare(value, selector, state), state.invert);
403      }
404
405      return this.verifyConstraints(value, selector);
406    },
407    getDependees: function getDependees() {
408      var cache = {};
409
410      var _compare = this.compare;
411      this.compare = function (reference, selector, state) {
412        (cache[selector] || (cache[selector] = [])).push(state.name);
413      };
414
415      this.verifyConstraints(this.constraints);
416
417      this.compare = _compare;
418
419      return cache;
420    }
421  };
422
423  states.Trigger = function (args) {
424    $.extend(this, args);
425
426    if (this.state in states.Trigger.states) {
427      this.element = $(this.selector);
428
429      if (!this.element.data('trigger:' + this.state)) {
430        this.initialize();
431      }
432    }
433  };
434
435  states.Trigger.prototype = {
436    initialize: function initialize() {
437      var _this3 = this;
438
439      var trigger = states.Trigger.states[this.state];
440
441      if (typeof trigger === 'function') {
442        trigger.call(window, this.element);
443      } else {
444        Object.keys(trigger || {}).forEach(function (event) {
445          _this3.defaultTrigger(event, trigger[event]);
446        });
447      }
448
449      this.element.data('trigger:' + this.state, true);
450    },
451    defaultTrigger: function defaultTrigger(event, valueFn) {
452      var oldValue = valueFn.call(this.element);
453
454      this.element.on(event, $.proxy(function (e) {
455        var value = valueFn.call(this.element, e);
456
457        if (oldValue !== value) {
458          this.element.trigger({
459            type: 'state:' + this.state,
460            value: value,
461            oldValue: oldValue
462          });
463          oldValue = value;
464        }
465      }, this));
466
467      states.postponed.push($.proxy(function () {
468        this.element.trigger({
469          type: 'state:' + this.state,
470          value: oldValue,
471          oldValue: null
472        });
473      }, this));
474    }
475  };
476
477  states.Trigger.states = {
478    empty: {
479      keyup: function keyup() {
480        return this.val() === '';
481      }
482    },
483
484    checked: {
485      change: function change() {
486        var checked = false;
487        this.each(function () {
488          checked = $(this).prop('checked');
489
490          return !checked;
491        });
492        return checked;
493      }
494    },
495
496    value: {
497      keyup: function keyup() {
498        if (this.length > 1) {
499          return this.filter(':checked').val() || false;
500        }
501        return this.val();
502      },
503      change: function change() {
504        if (this.length > 1) {
505          return this.filter(':checked').val() || false;
506        }
507        return this.val();
508      }
509    },
510
511    collapsed: {
512      collapsed: function collapsed(e) {
513        return typeof e !== 'undefined' && 'value' in e ? e.value : !this.is('[open]');
514      }
515    }
516  };
517
518  states.State = function (state) {
519    this.pristine = state;
520    this.name = state;
521
522    var process = true;
523    do {
524      while (this.name.charAt(0) === '!') {
525        this.name = this.name.substring(1);
526        this.invert = !this.invert;
527      }
528
529      if (this.name in states.State.aliases) {
530        this.name = states.State.aliases[this.name];
531      } else {
532        process = false;
533      }
534    } while (process);
535  };
536
537  states.State.sanitize = function (state) {
538    if (state instanceof states.State) {
539      return state;
540    }
541
542    return new states.State(state);
543  };
544
545  states.State.aliases = {
546    enabled: '!disabled',
547    invisible: '!visible',
548    invalid: '!valid',
549    untouched: '!touched',
550    optional: '!required',
551    filled: '!empty',
552    unchecked: '!checked',
553    irrelevant: '!relevant',
554    expanded: '!collapsed',
555    open: '!collapsed',
556    closed: 'collapsed',
557    readwrite: '!readonly'
558  };
559
560  states.State.prototype = {
561    invert: false,
562
563    toString: function toString() {
564      return this.name;
565    }
566  };
567
568  var $document = $(document);
569  $document.on('state:disabled', function (e) {
570    if (e.trigger) {
571      $(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);
572    }
573  });
574
575  $document.on('state:required', function (e) {
576    if (e.trigger) {
577      if (e.value) {
578        var label = 'label' + (e.target.id ? '[for=' + e.target.id + ']' : '');
579        var $label = $(e.target).attr({ required: 'required', 'aria-required': 'true' }).closest('.js-form-item, .js-form-wrapper').find(label);
580
581        if (!$label.hasClass('js-form-required').length) {
582          $label.addClass('js-form-required form-required');
583        }
584      } else {
585        $(e.target).removeAttr('required aria-required').closest('.js-form-item, .js-form-wrapper').find('label.js-form-required').removeClass('js-form-required form-required');
586      }
587    }
588  });
589
590  $document.on('state:visible', function (e) {
591    if (e.trigger) {
592      $(e.target).closest('.js-form-item, .js-form-submit, .js-form-wrapper').toggle(e.value);
593    }
594  });
595
596  $document.on('state:checked', function (e) {
597    if (e.trigger) {
598      $(e.target).prop('checked', e.value);
599    }
600  });
601
602  $document.on('state:collapsed', function (e) {
603    if (e.trigger) {
604      if ($(e.target).is('[open]') === e.value) {
605        $(e.target).find('> summary').trigger('click');
606      }
607    }
608  });
609})(jQuery, Drupal);;
610/**
611 * @file
612 * JavaScript behaviors for custom webform #states.
613 */
614
615(function ($, Drupal) {
616
617  'use strict';
618
619  Drupal.webform = Drupal.webform || {};
620  Drupal.webform.states = Drupal.webform.states || {};
621  Drupal.webform.states.slideDown = Drupal.webform.states.slideDown || {};
622  Drupal.webform.states.slideDown.duration = 'slow';
623  Drupal.webform.states.slideUp = Drupal.webform.states.slideUp || {};
624  Drupal.webform.states.slideUp.duration = 'fast';
625
626  /* ************************************************************************ */
627  // jQuery functions.
628  /* ************************************************************************ */
629
630  /**
631   * Check if an element has a specified data attribute.
632   *
633   * @param {string} data
634   *   The data attribute name.
635   *
636   * @return {boolean}
637   *   TRUE if an element has a specified data attribute.
638   */
639  $.fn.hasData = function (data) {
640    return (typeof this.data(data) !== 'undefined');
641  };
642
643  /**
644   * Check if element is within the webform or not.
645   *
646   * @return {boolean}
647   *   TRUE if element is within the webform.
648   */
649  $.fn.isWebform = function () {
650    return $(this).closest('form.webform-submission-form, form[id^="webform"], form[data-is-webform]').length ? true : false;
651  };
652
653  /**
654   * Check if element is to be treated as a webform element.
655   *
656   * @return {boolean}
657   *   TRUE if element is to be treated as a webform element.
658   */
659  $.fn.isWebformElement = function () {
660    return ($(this).isWebform() || $(this).closest('[data-is-webform-element]').length) ? true : false;
661  };
662
663  /* ************************************************************************ */
664  // Trigger.
665  /* ************************************************************************ */
666
667  // The change event is triggered by cut-n-paste and select menus.
668  // Issue #2445271: #states element empty check not triggered on mouse
669  // based paste.
670  // @see https://www.drupal.org/node/2445271
671  Drupal.states.Trigger.states.empty.change = function change() {
672    return this.val() === '';
673  };
674
675  /* ************************************************************************ */
676  // Dependents.
677  /* ************************************************************************ */
678
679
680  // Apply solution included in #1962800 patch.
681  // Issue #1962800: Form #states not working with literal integers as
682  // values in IE11.
683  // @see https://www.drupal.org/project/drupal/issues/1962800
684  // @see https://www.drupal.org/files/issues/core-states-not-working-with-integers-ie11_1962800_46.patch
685  //
686  // This issue causes pattern, less than, and greater than support to break.
687  // @see https://www.drupal.org/project/webform/issues/2981724
688  var states = Drupal.states;
689  Drupal.states.Dependent.prototype.compare = function compare(reference, selector, state) {
690    var value = this.values[selector][state.name];
691
692    var name = reference.constructor.name;
693    if (!name) {
694      name = $.type(reference);
695
696      name = name.charAt(0).toUpperCase() + name.slice(1);
697    }
698    if (name in states.Dependent.comparisons) {
699      return states.Dependent.comparisons[name](reference, value);
700    }
701
702    if (reference.constructor.name in states.Dependent.comparisons) {
703      return states.Dependent.comparisons[reference.constructor.name](reference, value);
704    }
705
706    return _compare2(reference, value);
707  };
708  function _compare2(a, b) {
709    if (a === b) {
710      return typeof a === 'undefined' ? a : true;
711    }
712
713    return typeof a === 'undefined' || typeof b === 'undefined';
714  }
715
716  // Adds pattern, less than, and greater than support to #state API.
717  // @see http://drupalsun.com/julia-evans/2012/03/09/extending-form-api-states-regular-expressions
718  Drupal.states.Dependent.comparisons.Object = function (reference, value) {
719    if ('pattern' in reference) {
720      return (new RegExp(reference['pattern'])).test(value);
721    }
722    else if ('!pattern' in reference) {
723      return !((new RegExp(reference['!pattern'])).test(value));
724    }
725    else if ('less' in reference) {
726      return (value !== '' && parseFloat(reference['less']) > parseFloat(value));
727    }
728    else if ('less_equal' in reference) {
729      return (value !== '' && parseFloat(reference['less_equal']) >= parseFloat(value));
730    }
731    else if ('greater' in reference) {
732      return (value !== '' && parseFloat(reference['greater']) < parseFloat(value));
733    }
734    else if ('greater_equal' in reference) {
735      return (value !== '' && parseFloat(reference['greater_equal']) <= parseFloat(value));
736    }
737    else if ('between' in reference || '!between' in reference) {
738      if (value === '') {
739        return false;
740      }
741
742      var between = reference['between'] || reference['!between'];
743      var betweenParts = between.split(':');
744      var greater = betweenParts[0];
745      var less = (typeof betweenParts[1] !== 'undefined') ? betweenParts[1] : null;
746      var isGreaterThan = (greater === null || greater === '' || parseFloat(value) >= parseFloat(greater));
747      var isLessThan = (less === null || less === '' || parseFloat(value) <= parseFloat(less));
748      var result = (isGreaterThan && isLessThan);
749      return (reference['!between']) ? !result : result;
750    }
751    else {
752      return reference.indexOf(value) !== false;
753    }
754  };
755
756  /* ************************************************************************ */
757  // States events.
758  /* ************************************************************************ */
759
760  var $document = $(document);
761
762  $document.on('state:required', function (e) {
763    if (e.trigger && $(e.target).isWebformElement()) {
764      var $target = $(e.target);
765      // Fix #required file upload.
766      // @see Issue #2860529: Conditional required File upload field don't work.
767      toggleRequired($target.find('input[type="file"]'), e.value);
768
769      // Fix #required for radios and likert.
770      // @see Issue #2856795: If radio buttons are required but not filled form is nevertheless submitted.
771      if ($target.is('.js-form-type-radios, .js-form-type-webform-radios-other, .js-webform-type-radios, .js-webform-type-webform-radios-other, .js-webform-type-webform-entity-radios, .webform-likert-table')) {
772        $target.toggleClass('required', e.value);
773        toggleRequired($target.find('input[type="radio"]'), e.value);
774      }
775
776      // Fix #required for checkboxes.
777      // @see Issue #2938414: Checkboxes don't support #states required.
778      // @see checkboxRequiredhandler
779      if ($target.is('.js-form-type-checkboxes, .js-form-type-webform-checkboxes-other, .js-webform-type-checkboxes, .js-webform-type-webform-checkboxes-other')) {
780        $target.toggleClass('required', e.value);
781        var $checkboxes = $target.find('input[type="checkbox"]');
782        if (e.value) {
783          // Add event handler.
784          $checkboxes.on('click', statesCheckboxesRequiredEventHandler);
785          // Initialize and add required attribute.
786          checkboxesRequired($target);
787        }
788        else {
789          // Remove event handler.
790          $checkboxes.off('click', statesCheckboxesRequiredEventHandler);
791          // Remove required attribute.
792          toggleRequired($checkboxes, false);
793        }
794      }
795
796      // Fix #required for tableselect.
797      // @see Issue #3212581: Table select does not trigger client side validation
798      if ($target.is('.js-webform-tableselect')) {
799        $target.toggleClass('required', e.value);
800        var isMultiple = $target.is('[multiple]');
801        if (isMultiple) {
802          // Checkboxes.
803          var $tbody = $target.find('tbody');
804          var $checkboxes = $tbody.find('input[type="checkbox"]');
805          copyRequireMessage($target, $checkboxes);
806          if (e.value) {
807            $checkboxes.on('click change', statesCheckboxesRequiredEventHandler);
808            checkboxesRequired($tbody);
809          }
810          else {
811            $checkboxes.off('click change ', statesCheckboxesRequiredEventHandler);
812            toggleRequired($tbody, false);
813          }
814        }
815        else {
816          // Radios.
817          var $radios = $target.find('input[type="radio"]');
818          copyRequireMessage($target, $radios);
819          toggleRequired($radios, e.value);
820        }
821      }
822
823      // Fix required label for elements without the for attribute.
824      // @see Issue #3145300: Conditional Visible Select Other not working.
825      if ($target.is('.js-form-type-webform-select-other, .js-webform-type-webform-select-other')) {
826        var $select = $target.find('select');
827        toggleRequired($select, e.value);
828        copyRequireMessage($target, $select);
829      }
830      if ($target.find('> label:not([for])').length) {
831        $target.find('> label').toggleClass('js-form-required form-required', e.value);
832      }
833
834      // Fix required label for checkboxes and radios.
835      // @see Issue #2938414: Checkboxes don't support #states required
836      // @see Issue #2731991: Setting required on radios marks all options required.
837      // @see Issue #2856315: Conditional Logic - Requiring Radios in a Fieldset.
838      // Fix #required for fieldsets.
839      // @see Issue #2977569: Hidden fieldsets that become visible with conditional logic cannot be made required.
840      if ($target.is('.js-webform-type-radios, .js-webform-type-checkboxes, fieldset')) {
841        $target.find('legend span.fieldset-legend:not(.visually-hidden)').toggleClass('js-form-required form-required', e.value);
842      }
843
844      // Issue #2986017: Fieldsets shouldn't have required attribute.
845      if ($target.is('fieldset')) {
846        $target.removeAttr('required aria-required');
847      }
848    }
849  });
850
851  $document.on('state:checked', function (e) {
852    if (e.trigger) {
853      $(e.target).trigger('change');
854    }
855  });
856
857  $document.on('state:readonly', function (e) {
858    if (e.trigger && $(e.target).isWebformElement()) {
859      $(e.target).prop('readonly', e.value).closest('.js-form-item, .js-form-wrapper').toggleClass('webform-readonly', e.value).find('input, textarea').prop('readonly', e.value);
860
861      // Trigger webform:readonly.
862      $(e.target).trigger('webform:readonly')
863        .find('select, input, textarea, button').trigger('webform:readonly');
864    }
865  });
866
867  $document.on('state:visible state:visible-slide', function (e) {
868    if (e.trigger && $(e.target).isWebformElement()) {
869      if (e.value) {
870        $(':input', e.target).addBack().each(function () {
871          restoreValueAndRequired(this);
872          triggerEventHandlers(this);
873        });
874      }
875      else {
876        // @see https://www.sitepoint.com/jquery-function-clear-form-data/
877        $(':input', e.target).addBack().each(function () {
878          backupValueAndRequired(this);
879          clearValueAndRequired(this);
880          triggerEventHandlers(this);
881        });
882      }
883    }
884  });
885
886  $document.on('state:visible-slide', function (e) {
887    if (e.trigger && $(e.target).isWebformElement()) {
888      var effect = e.value ? 'slideDown' : 'slideUp';
889      var duration = Drupal.webform.states[effect].duration;
890      $(e.target).closest('.js-form-item, .js-form-submit, .js-form-wrapper')[effect](duration);
891    }
892  });
893  Drupal.states.State.aliases['invisible-slide'] = '!visible-slide';
894
895  $document.on('state:disabled', function (e) {
896    if (e.trigger && $(e.target).isWebformElement()) {
897      // Make sure disabled property is set before triggering webform:disabled.
898      // Copied from: core/misc/states.js
899      $(e.target)
900        .prop('disabled', e.value)
901        .closest('.js-form-item, .js-form-submit, .js-form-wrapper').toggleClass('form-disabled', e.value)
902        .find('select, input, textarea, button').prop('disabled', e.value);
903
904      // Never disable hidden file[fids] because the existing values will
905      // be completely lost when the webform is submitted.
906      var fileElements = $(e.target)
907        .find(':input[type="hidden"][name$="[fids]"]');
908      if (fileElements.length) {
909        // Remove 'disabled' attribute from fieldset which will block
910        // all disabled elements from being submitted.
911        if ($(e.target).is('fieldset')) {
912          $(e.target).prop('disabled', false);
913        }
914        fileElements.removeAttr('disabled');
915      }
916
917      // Trigger webform:disabled.
918      $(e.target).trigger('webform:disabled')
919        .find('select, input, textarea, button').trigger('webform:disabled');
920    }
921  });
922
923  /* ************************************************************************ */
924  // Behaviors.
925  /* ************************************************************************ */
926
927  /**
928   * Adds HTML5 validation to required checkboxes.
929   *
930   * @type {Drupal~behavior}
931   *
932   * @see https://www.drupal.org/project/webform/issues/3068998
933   */
934  Drupal.behaviors.webformCheckboxesRequired = {
935    attach: function (context) {
936      $('.js-form-type-checkboxes.required, .js-form-type-webform-checkboxes-other.required, .js-webform-type-checkboxes.required, .js-webform-type-webform-checkboxes-other.required, .js-webform-type-webform-radios-other.checkboxes', context)
937        .once('webform-checkboxes-required')
938        .each(function () {
939          var $element = $(this);
940          $element.find('input[type="checkbox"]').on('click', statesCheckboxesRequiredEventHandler);
941          setTimeout(function () {checkboxesRequired($element);});
942        });
943    }
944  };
945
946  /**
947   * Adds HTML5 validation to required radios.
948   *
949   * @type {Drupal~behavior}
950   *
951   * @see https://www.drupal.org/project/webform/issues/2856795
952   */
953  Drupal.behaviors.webformRadiosRequired = {
954    attach: function (context) {
955      $('.js-form-type-radios, .js-form-type-webform-radios-other, .js-webform-type-radios, .js-webform-type-webform-radios-other, .js-webform-type-webform-entity-radios, .js-webform-type-webform-scale', context)
956        .once('webform-radios-required')
957        .each(function () {
958          var $element = $(this);
959          setTimeout(function () {radiosRequired($element);});
960        });
961    }
962  };
963
964 /**
965   * Adds HTML5 validation to required table select.
966   *
967   * @type {Drupal~behavior}
968   *
969   * @see https://www.drupal.org/project/webform/issues/2856795
970   */
971  Drupal.behaviors.webformTableSelectRequired = {
972    attach: function (context) {
973      $('.js-webform-tableselect.required', context)
974        .once('webform-tableselect-required')
975        .each(function () {
976          var $element = $(this);
977          var $tbody = $element.find('tbody');
978          var isMultiple = $element.is('[multiple]');
979
980          if (isMultiple) {
981            // Check all checkbox triggers checkbox 'change' event on
982            // select and deselect all.
983            // @see Drupal.tableSelect
984            $tbody.find('input[type="checkbox"]').on('click change', function () {
985              checkboxesRequired($tbody);
986            });
987          }
988
989          setTimeout(function () {
990            isMultiple ? checkboxesRequired($tbody) : radiosRequired($element);
991          });
992        });
993    }
994  };
995
996  /**
997   * Add HTML5 multiple checkboxes required validation.
998   *
999   * @param {jQuery} $element
1000   *   An jQuery object containing HTML5 radios.
1001   *
1002   * @see https://stackoverflow.com/a/37825072/145846
1003   */
1004  function checkboxesRequired($element) {
1005    var $firstCheckbox = $element.find('input[type="checkbox"]').first();
1006    var isChecked = $element.find('input[type="checkbox"]').is(':checked');
1007    toggleRequired($firstCheckbox, !isChecked);
1008    copyRequireMessage($element, $firstCheckbox);
1009  }
1010
1011  /**
1012   * Add HTML5 radios required validation.
1013   *
1014   * @param {jQuery} $element
1015   *   An jQuery object containing HTML5 radios.
1016   *
1017   * @see https://www.drupal.org/project/webform/issues/2856795
1018   */
1019  function radiosRequired($element) {
1020    var $radios = $element.find('input[type="radio"]');
1021    var isRequired = $element.hasClass('required');
1022    toggleRequired($radios, isRequired);
1023    copyRequireMessage($element, $radios);
1024  }
1025
1026  /* ************************************************************************ */
1027  // Event handlers.
1028  /* ************************************************************************ */
1029
1030  /**
1031   * Trigger #states API HTML5 multiple checkboxes required validation.
1032   *
1033   * @see https://stackoverflow.com/a/37825072/145846
1034   */
1035  function statesCheckboxesRequiredEventHandler() {
1036    var $element = $(this).closest('.js-webform-type-checkboxes, .js-webform-type-webform-checkboxes-other');
1037    checkboxesRequired($element);
1038  }
1039
1040  /**
1041   * Trigger an input's event handlers.
1042   *
1043   * @param {element} input
1044   *   An input.
1045   */
1046  function triggerEventHandlers(input) {
1047    var $input = $(input);
1048    var type = input.type;
1049    var tag = input.tagName.toLowerCase();
1050    // Add 'webform.states' as extra parameter to event handlers.
1051    // @see Drupal.behaviors.webformUnsaved
1052    var extraParameters = ['webform.states'];
1053    if (type === 'checkbox' || type === 'radio') {
1054      $input
1055        .trigger('change', extraParameters)
1056        .trigger('blur', extraParameters);
1057    }
1058    else if (tag === 'select') {
1059      // Do not trigger the onchange event for Address element's country code
1060      // when it is initialized.
1061      // @see \Drupal\address\Element\Country
1062      if ($input.closest('.webform-type-address').length) {
1063        if (!$input.data('webform-states-address-initialized')
1064          && $input.attr('autocomplete') === 'country'
1065          && $input.val() === $input.find("option[selected]").attr('value')) {
1066          return;
1067        }
1068        $input.data('webform-states-address-initialized', true);
1069      }
1070
1071      $input
1072        .trigger('change', extraParameters)
1073        .trigger('blur', extraParameters);
1074    }
1075    else if (type !== 'submit' && type !== 'button' && type !== 'file') {
1076      // Make sure input mask is removed and then reset when value is restored.
1077      // @see https://www.drupal.org/project/webform/issues/3124155
1078      // @see https://www.drupal.org/project/webform/issues/3202795
1079      var hasInputMask = ($.fn.inputmask && $input.hasClass('js-webform-input-mask'));
1080      hasInputMask && $input.inputmask('remove');
1081
1082      $input
1083        .trigger('input', extraParameters)
1084        .trigger('change', extraParameters)
1085        .trigger('keydown', extraParameters)
1086        .trigger('keyup', extraParameters)
1087        .trigger('blur', extraParameters);
1088
1089      hasInputMask && $input.inputmask();
1090    }
1091  }
1092
1093  /* ************************************************************************ */
1094  // Backup and restore value functions.
1095  /* ************************************************************************ */
1096
1097  /**
1098   * Backup an input's current value and required attribute
1099   *
1100   * @param {element} input
1101   *   An input.
1102   */
1103  function backupValueAndRequired(input) {
1104    var $input = $(input);
1105    var type = input.type;
1106    var tag = input.tagName.toLowerCase(); // Normalize case.
1107
1108    // Backup required.
1109    if ($input.prop('required') && !$input.hasData('webform-required')) {
1110      $input.data('webform-required', true);
1111    }
1112
1113    // Backup value.
1114    if (!$input.hasData('webform-value')) {
1115      if (type === 'checkbox' || type === 'radio') {
1116        $input.data('webform-value', $input.prop('checked'));
1117      }
1118      else if (tag === 'select') {
1119        var values = [];
1120        $input.find('option:selected').each(function (i, option) {
1121          values[i] = option.value;
1122        });
1123        $input.data('webform-value', values);
1124      }
1125      else if (type !== 'submit' && type !== 'button') {
1126        $input.data('webform-value', input.value);
1127      }
1128    }
1129  }
1130
1131  /**
1132   * Restore an input's value and required attribute.
1133   *
1134   * @param {element} input
1135   *   An input.
1136   */
1137  function restoreValueAndRequired(input) {
1138    var $input = $(input);
1139
1140    // Restore value.
1141    var value = $input.data('webform-value');
1142    if (typeof value !== 'undefined') {
1143      var type = input.type;
1144      var tag = input.tagName.toLowerCase(); // Normalize case.
1145
1146      if (type === 'checkbox' || type === 'radio') {
1147        $input.prop('checked', value);
1148      }
1149      else if (tag === 'select') {
1150        $.each(value, function (i, option_value) {
1151          // Prevent "Syntax error, unrecognized expression" error by
1152          // escaping single quotes.
1153          // @see https://forum.jquery.com/topic/escape-characters-prior-to-using-selector
1154          option_value = option_value.replace(/'/g, "\\\'");
1155          $input.find("option[value='" + option_value + "']").prop('selected', true);
1156        });
1157      }
1158      else if (type !== 'submit' && type !== 'button') {
1159        input.value = value;
1160      }
1161      $input.removeData('webform-value');
1162    }
1163
1164    // Restore required.
1165    var required = $input.data('webform-required');
1166    if (typeof required !== 'undefined') {
1167      if (required) {
1168        $input.prop('required', true);
1169      }
1170      $input.removeData('webform-required');
1171    }
1172  }
1173
1174  /**
1175   * Clear an input's value and required attributes.
1176   *
1177   * @param {element} input
1178   *   An input.
1179   */
1180  function clearValueAndRequired(input) {
1181    var $input = $(input);
1182
1183    // Check for #states no clear attribute.
1184    // @see https://css-tricks.com/snippets/jquery/make-an-jquery-hasattr/
1185    if ($input.closest('[data-webform-states-no-clear]').length) {
1186      return;
1187    }
1188
1189    // Clear value.
1190    var type = input.type;
1191    var tag = input.tagName.toLowerCase(); // Normalize case.
1192    if (type === 'checkbox' || type === 'radio') {
1193      $input.prop('checked', false);
1194    }
1195    else if (tag === 'select') {
1196      if ($input.find('option[value=""]').length) {
1197        $input.val('');
1198      }
1199      else {
1200        input.selectedIndex = -1;
1201      }
1202    }
1203    else if (type !== 'submit' && type !== 'button') {
1204      input.value = (type === 'color') ? '#000000' : '';
1205    }
1206
1207    // Clear required.
1208    $input.prop('required', false);
1209  }
1210
1211  /* ************************************************************************ */
1212  // Helper functions.
1213  /* ************************************************************************ */
1214
1215  /**
1216   * Toggle an input's required attributes.
1217   *
1218   * @param {element} $input
1219   *   An input.
1220   * @param {boolean} required
1221   *   Is input required.
1222   */
1223  function toggleRequired($input, required) {
1224    var isCheckboxOrRadio = ($input.attr('type') === 'radio' || $input.attr('type') === 'checkbox');
1225    if (required) {
1226      if (isCheckboxOrRadio) {
1227        $input.attr({'required': 'required'});
1228      }
1229      else {
1230        $input.attr({'required': 'required', 'aria-required': 'true'});
1231      }
1232    }
1233    else {
1234      if (isCheckboxOrRadio) {
1235        $input.removeAttr('required');
1236      }
1237      else {
1238        $input.removeAttr('required aria-required');
1239      }
1240    }
1241  }
1242
1243  /**
1244   * Copy the clientside_validation.module's message.
1245   *
1246   * @param {jQuery} $source
1247   *   The source element.
1248   * @param {jQuery} $destination
1249   *   The destination element.
1250   */
1251  function copyRequireMessage($source, $destination) {
1252    if ($source.attr('data-msg-required')) {
1253      $destination.attr('data-msg-required', $source.attr('data-msg-required'));
1254    }
1255  }
1256
1257})(jQuery, Drupal);
1258;
1259/**
1260 * @file
1261 * JavaScript behaviors for webforms.
1262 */
1263
1264(function ($, Drupal) {
1265
1266  'use strict';
1267
1268  /**
1269   * Remove single submit event listener.
1270   *
1271   * @type {Drupal~behavior}
1272   *
1273   * @prop {Drupal~behaviorAttach} attach
1274   *   Attaches the behavior for removing single submit event listener.
1275   *
1276   * @see Drupal.behaviors.formSingleSubmit
1277   */
1278  Drupal.behaviors.webformRemoveFormSingleSubmit = {
1279    attach: function attach() {
1280      function onFormSubmit(e) {
1281        var $form = $(e.currentTarget);
1282        $form.removeAttr('data-drupal-form-submit-last');
1283      }
1284      $('body')
1285        .once('webform-single-submit')
1286        .on('submit.singleSubmit', 'form.webform-remove-single-submit', onFormSubmit);
1287    }
1288  };
1289
1290  /**
1291   * Prevent webform autosubmit on wizard pages.
1292   *
1293   * @type {Drupal~behavior}
1294   *
1295   * @prop {Drupal~behaviorAttach} attach
1296   *   Attaches the behavior for disabling webform autosubmit.
1297   *   Wizard pages need to be progressed with the Previous or Next buttons,
1298   *   not by pressing Enter.
1299   */
1300  Drupal.behaviors.webformDisableAutoSubmit = {
1301    attach: function (context) {
1302      // Not using context so that inputs loaded via Ajax will have autosubmit
1303      // disabled.
1304      // @see http://stackoverflow.com/questions/11235622/jquery-disable-form-submit-on-enter
1305      $('.js-webform-disable-autosubmit input')
1306        .not(':button, :submit, :reset, :image, :file')
1307        .once('webform-disable-autosubmit')
1308        .on('keyup keypress', function (e) {
1309          if (e.which === 13) {
1310            e.preventDefault();
1311            return false;
1312          }
1313        });
1314    }
1315  };
1316
1317  /**
1318   * Custom required and pattern validation error messages.
1319   *
1320   * @type {Drupal~behavior}
1321   *
1322   * @prop {Drupal~behaviorAttach} attach
1323   *   Attaches the behavior for the webform custom required and pattern
1324   *   validation error messages.
1325   *
1326   * @see http://stackoverflow.com/questions/5272433/html5-form-required-attribute-set-custom-validation-message
1327   **/
1328  Drupal.behaviors.webformRequiredError = {
1329    attach: function (context) {
1330      $(context).find(':input[data-webform-required-error], :input[data-webform-pattern-error]').once('webform-required-error')
1331        .on('invalid', function () {
1332          this.setCustomValidity('');
1333          if (this.valid) {
1334            return;
1335          }
1336
1337          if (this.validity.patternMismatch && $(this).attr('data-webform-pattern-error')) {
1338            this.setCustomValidity($(this).attr('data-webform-pattern-error'));
1339          }
1340          else if (this.validity.valueMissing && $(this).attr('data-webform-required-error')) {
1341            this.setCustomValidity($(this).attr('data-webform-required-error'));
1342          }
1343        })
1344        .on('input change', function () {
1345          // Find all related elements by name and reset custom validity.
1346          // This specifically applies to required radios and checkboxes.
1347          var name = $(this).attr('name');
1348          $(this.form).find(':input[name="' + name + '"]').each(function () {
1349            this.setCustomValidity('');
1350          });
1351        });
1352    }
1353  };
1354
1355  // When #state:required is triggered we need to reset the target elements
1356  // custom validity.
1357  $(document).on('state:required', function (e) {
1358    $(e.target).filter('[data-webform-required-error]')
1359      .each(function () {this.setCustomValidity('');});
1360  });
1361
1362})(jQuery, Drupal);
1363;
1364/**
1365* DO NOT EDIT THIS FILE.
1366* See the following change record for more information,
1367* https://www.drupal.org/node/2815083
1368* @preserve
1369**/
1370
1371(function (Drupal, debounce) {
1372  var liveElement = void 0;
1373  var announcements = [];
1374
1375  Drupal.behaviors.drupalAnnounce = {
1376    attach: function attach(context) {
1377      if (!liveElement) {
1378        liveElement = document.createElement('div');
1379        liveElement.id = 'drupal-live-announce';
1380        liveElement.className = 'visually-hidden';
1381        liveElement.setAttribute('aria-live', 'polite');
1382        liveElement.setAttribute('aria-busy', 'false');
1383        document.body.appendChild(liveElement);
1384      }
1385    }
1386  };
1387
1388  function announce() {
1389    var text = [];
1390    var priority = 'polite';
1391    var announcement = void 0;
1392
1393    var il = announcements.length;
1394    for (var i = 0; i < il; i++) {
1395      announcement = announcements.pop();
1396      text.unshift(announcement.text);
1397
1398      if (announcement.priority === 'assertive') {
1399        priority = 'assertive';
1400      }
1401    }
1402
1403    if (text.length) {
1404      liveElement.innerHTML = '';
1405
1406      liveElement.setAttribute('aria-busy', 'true');
1407
1408      liveElement.setAttribute('aria-live', priority);
1409
1410      liveElement.innerHTML = text.join('\n');
1411
1412      liveElement.setAttribute('aria-busy', 'false');
1413    }
1414  }
1415
1416  Drupal.announce = function (text, priority) {
1417    announcements.push({
1418      text: text,
1419      priority: priority
1420    });
1421
1422    return debounce(announce, 200)();
1423  };
1424})(Drupal, Drupal.debounce);;
1425/**
1426 * @file
1427 * JavaScript behaviors for details element.
1428 */
1429
1430(function ($, Drupal) {
1431
1432  'use strict';
1433
1434  Drupal.webform = Drupal.webform || {};
1435  Drupal.webform.detailsToggle = Drupal.webform.detailsToggle || {};
1436  Drupal.webform.detailsToggle.options = Drupal.webform.detailsToggle.options || {};
1437
1438  /**
1439   * Attach handler to toggle details open/close state.
1440   *
1441   * @type {Drupal~behavior}
1442   */
1443  Drupal.behaviors.webformDetailsToggle = {
1444    attach: function (context) {
1445      $('.js-webform-details-toggle', context).once('webform-details-toggle').each(function () {
1446        var $form = $(this);
1447        var $tabs = $form.find('.webform-tabs');
1448
1449        // Get only the main details elements and ignore all nested details.
1450        var selector = ($tabs.length) ? '.webform-tab' : '.js-webform-details-toggle, .webform-elements';
1451        var $details = $form.find('details').filter(function () {
1452          var $parents = $(this).parentsUntil(selector);
1453          return ($parents.find('details').length === 0);
1454        });
1455
1456        // Toggle is only useful when there are two or more details elements.
1457        if ($details.length < 2) {
1458          return;
1459        }
1460
1461        var options = $.extend({
1462          button: '<button type="button" class="webform-details-toggle-state"></button>'
1463        }, Drupal.webform.detailsToggle.options);
1464
1465        // Create toggle buttons.
1466        var $toggle = $(options.button)
1467          .attr('title', Drupal.t('Toggle details widget state.'))
1468          .on('click', function (e) {
1469            // Get details that are not vertical tabs pane.
1470            var $details = $form.find('details:not(.vertical-tabs__pane)');
1471            var open;
1472            if (Drupal.webform.detailsToggle.isFormDetailsOpen($form)) {
1473              $details.removeAttr('open');
1474              open = 0;
1475            }
1476            else {
1477              $details.attr('open', 'open');
1478              open = 1;
1479            }
1480            Drupal.webform.detailsToggle.setDetailsToggleLabel($form);
1481
1482            // Set the saved states for all the details elements.
1483            // @see webform.element.details.save.js
1484            if (Drupal.webformDetailsSaveGetName) {
1485              $details.each(function () {
1486                // Note: Drupal.webformDetailsSaveGetName checks if localStorage
1487                // exists and is enabled.
1488                // @see webform.element.details.save.js
1489                var name = Drupal.webformDetailsSaveGetName($(this));
1490                if (name) {
1491                  localStorage.setItem(name, open);
1492                }
1493              });
1494            }
1495          })
1496          .wrap('<div class="webform-details-toggle-state-wrapper"></div>')
1497          .parent();
1498
1499        if ($tabs.length) {
1500          // Add toggle state before the tabs.
1501          $tabs.find('.item-list:first-child').eq(0).before($toggle);
1502        }
1503        else {
1504          // Add toggle state link to first details element.
1505          $details.eq(0).before($toggle);
1506        }
1507
1508        Drupal.webform.detailsToggle.setDetailsToggleLabel($form);
1509      });
1510    }
1511  };
1512
1513  /**
1514   * Determine if a webform's details are all opened.
1515   *
1516   * @param {jQuery} $form
1517   *   A webform.
1518   *
1519   * @return {boolean}
1520   *   TRUE if a webform's details are all opened.
1521   */
1522  Drupal.webform.detailsToggle.isFormDetailsOpen = function ($form) {
1523    return ($form.find('details[open]').length === $form.find('details').length);
1524  };
1525
1526  /**
1527   * Set a webform's details toggle state widget label.
1528   *
1529   * @param {jQuery} $form
1530   *   A webform.
1531   */
1532  Drupal.webform.detailsToggle.setDetailsToggleLabel = function ($form) {
1533    var isOpen = Drupal.webform.detailsToggle.isFormDetailsOpen($form);
1534
1535    var label = (isOpen) ? Drupal.t('Collapse all') : Drupal.t('Expand all');
1536    $form.find('.webform-details-toggle-state').html(label);
1537
1538    var text = (isOpen) ? Drupal.t('All details have been expanded.') : Drupal.t('All details have been collapsed.');
1539    Drupal.announce(text);
1540  };
1541
1542})(jQuery, Drupal);
1543;
1544/**
1545* DO NOT EDIT THIS FILE.
1546* See the following change record for more information,
1547* https://www.drupal.org/node/2815083
1548* @preserve
1549**/
1550
1551(function ($, Drupal) {
1552  Drupal.behaviors.detailsAria = {
1553    attach: function attach() {
1554      $('body').once('detailsAria').on('click.detailsAria', 'summary', function (event) {
1555        var $summary = $(event.currentTarget);
1556        var open = $(event.currentTarget.parentNode).attr('open') === 'open' ? 'false' : 'true';
1557
1558        $summary.attr({
1559          'aria-expanded': open,
1560          'aria-pressed': open
1561        });
1562      });
1563    }
1564  };
1565})(jQuery, Drupal);;
1566/**
1567* DO NOT EDIT THIS FILE.
1568* See the following change record for more information,
1569* https://www.drupal.org/node/2815083
1570* @preserve
1571**/
1572
1573(function ($, Modernizr, Drupal) {
1574  function CollapsibleDetails(node) {
1575    this.$node = $(node);
1576    this.$node.data('details', this);
1577
1578    var anchor = window.location.hash && window.location.hash !== '#' ? ', ' + window.location.hash : '';
1579    if (this.$node.find('.error' + anchor).length) {
1580      this.$node.attr('open', true);
1581    }
1582
1583    this.setupSummary();
1584
1585    this.setupLegend();
1586  }
1587
1588  $.extend(CollapsibleDetails, {
1589    instances: []
1590  });
1591
1592  $.extend(CollapsibleDetails.prototype, {
1593    setupSummary: function setupSummary() {
1594      this.$summary = $('<span class="summary"></span>');
1595      this.$node.on('summaryUpdated', $.proxy(this.onSummaryUpdated, this)).trigger('summaryUpdated');
1596    },
1597    setupLegend: function setupLegend() {
1598      var $legend = this.$node.find('> summary');
1599
1600      $('<span class="details-summary-prefix visually-hidden"></span>').append(this.$node.attr('open') ? Drupal.t('Hide') : Drupal.t('Show')).prependTo($legend).after(document.createTextNode(' '));
1601
1602      $('<a class="details-title"></a>').attr('href', '#' + this.$node.attr('id')).prepend($legend.contents()).appendTo($legend);
1603
1604      $legend.append(this.$summary).on('click', $.proxy(this.onLegendClick, this));
1605    },
1606    onLegendClick: function onLegendClick(e) {
1607      this.toggle();
1608      e.preventDefault();
1609    },
1610    onSummaryUpdated: function onSummaryUpdated() {
1611      var text = $.trim(this.$node.drupalGetSummary());
1612      this.$summary.html(text ? ' (' + text + ')' : '');
1613    },
1614    toggle: function toggle() {
1615      var _this = this;
1616
1617      var isOpen = !!this.$node.attr('open');
1618      var $summaryPrefix = this.$node.find('> summary span.details-summary-prefix');
1619      if (isOpen) {
1620        $summaryPrefix.html(Drupal.t('Show'));
1621      } else {
1622        $summaryPrefix.html(Drupal.t('Hide'));
1623      }
1624
1625      setTimeout(function () {
1626        _this.$node.attr('open', !isOpen);
1627      }, 0);
1628    }
1629  });
1630
1631  Drupal.behaviors.collapse = {
1632    attach: function attach(context) {
1633      if (Modernizr.details) {
1634        return;
1635      }
1636      var $collapsibleDetails = $(context).find('details').once('collapse').addClass('collapse-processed');
1637      if ($collapsibleDetails.length) {
1638        for (var i = 0; i < $collapsibleDetails.length; i++) {
1639          CollapsibleDetails.instances.push(new CollapsibleDetails($collapsibleDetails[i]));
1640        }
1641      }
1642    }
1643  };
1644
1645  var handleFragmentLinkClickOrHashChange = function handleFragmentLinkClickOrHashChange(e, $target) {
1646    $target.parents('details').not('[open]').find('> summary').trigger('click');
1647  };
1648
1649  $('body').on('formFragmentLinkClickOrHashChange.details', handleFragmentLinkClickOrHashChange);
1650
1651  Drupal.CollapsibleDetails = CollapsibleDetails;
1652})(jQuery, Modernizr, Drupal);;
1653/**
1654 * @file
1655 * JavaScript behaviors for select menu.
1656 */
1657
1658(function ($, Drupal) {
1659
1660  'use strict';
1661
1662  /**
1663   * Disable select menu options using JavaScript.
1664   *
1665   * @type {Drupal~behavior}
1666   */
1667  Drupal.behaviors.webformSelectOptionsDisabled = {
1668    attach: function (context) {
1669      $('select[data-webform-select-options-disabled]', context).once('webform-select-options-disabled').each(function () {
1670        var $select = $(this);
1671        var disabled = $select.attr('data-webform-select-options-disabled').split(/\s*,\s*/);
1672        $select.find('option').filter(function isDisabled() {
1673          return ($.inArray(this.value, disabled) !== -1);
1674        }).attr('disabled', 'disabled');
1675      });
1676    }
1677  };
1678
1679
1680})(jQuery, Drupal);
1681;
1682/**
1683 * @file
1684 * Javascript for the Geojson Google Maps.
1685 *
1686 * @source: https://github.com/JasonSanford/GeoJSON-to-Google-Maps
1687 */
1688
1689(function ($, Drupal) {
1690
1691  'use strict';
1692
1693  Drupal.googleGeoJson = function (geojson, options) {
1694
1695    let _geometryToGoogleMaps = function (geojsonGeometry, opts, geojsonProperties) {
1696
1697      let googleObj;
1698      let bounds;
1699      let paths = [];
1700      let path = [];
1701      let i;
1702      let j;
1703      let k;
1704      let coord;
1705      let ll;
1706
1707      switch (geojsonGeometry.type) {
1708        case 'Point':
1709          opts.position = new google.maps.LatLng(geojsonGeometry.coordinates[1], geojsonGeometry.coordinates[0]);
1710          bounds = new google.maps.LatLngBounds();
1711          bounds.extend(opts.position);
1712          googleObj = new google.maps.Marker(opts);
1713          googleObj.set('bounds', bounds);
1714          if (geojsonProperties) {
1715            googleObj.set('geojsonProperties', geojsonProperties);
1716          }
1717          break;
1718
1719        case 'MultiPoint':
1720          googleObj = [];
1721          bounds = new google.maps.LatLngBounds();
1722          for (i = 0; i < geojsonGeometry.coordinates.length; i++) {
1723            opts.position = new google.maps.LatLng(geojsonGeometry.coordinates[i][1], geojsonGeometry.coordinates[i][0]);
1724            bounds.extend(opts.position);
1725            googleObj.push(new google.maps.Marker(opts));
1726          }
1727          if (geojsonProperties) {
1728            for (k = 0; k < googleObj.length; k++) {
1729              googleObj[k].set('geojsonProperties', geojsonProperties);
1730            }
1731          }
1732          for (k = 0; k < googleObj.length; k++) {
1733            googleObj[k].set('bounds', bounds);
1734          }
1735          break;
1736
1737        case 'LineString':
1738          bounds = new google.maps.LatLngBounds();
1739          path = [];
1740          for (i = 0; i < geojsonGeometry.coordinates.length; i++) {
1741            coord = geojsonGeometry.coordinates[i];
1742            ll = new google.maps.LatLng(coord[1], coord[0]);
1743            bounds.extend(ll);
1744            path.push(ll);
1745          }
1746          opts.path = path;
1747          googleObj = new google.maps.Polyline(opts);
1748          googleObj.set('bounds', bounds);
1749          if (geojsonProperties) {
1750            googleObj.set('geojsonProperties', geojsonProperties);
1751          }
1752          break;
1753
1754        case 'MultiLineString':
1755          googleObj = [];
1756          bounds = new google.maps.LatLngBounds();
1757          for (i = 0; i < geojsonGeometry.coordinates.length; i++) {
1758            path = [];
1759            for (j = 0; j < geojsonGeometry.coordinates[i].length; j++) {
1760              coord = geojsonGeometry.coordinates[i][j];
1761              ll = new google.maps.LatLng(coord[1], coord[0]);
1762              bounds.extend(ll);
1763              path.push(ll);
1764            }
1765            opts.path = path;
1766            googleObj.push(new google.maps.Polyline(opts));
1767          }
1768          if (geojsonProperties) {
1769            for (k = 0; k < googleObj.length; k++) {
1770              googleObj[k].set('geojsonProperties', geojsonProperties);
1771            }
1772          }
1773          for (k = 0; k < googleObj.length; k++) {
1774            googleObj[k].set('bounds', bounds);
1775          }
1776          break;
1777
1778        case 'Polygon':
1779          paths = [];
1780          bounds = new google.maps.LatLngBounds();
1781          for (i = 0; i < geojsonGeometry.coordinates.length; i++) {
1782            path = [];
1783            for (j = 0; j < geojsonGeometry.coordinates[i].length; j++) {
1784              ll = new google.maps.LatLng(geojsonGeometry.coordinates[i][j][1], geojsonGeometry.coordinates[i][j][0]);
1785              bounds.extend(ll);
1786              path.push(ll);
1787            }
1788            paths.push(path);
1789          }
1790          opts.paths = paths;
1791          googleObj = new google.maps.Polygon(opts);
1792          googleObj.set('bounds', bounds);
1793          if (geojsonProperties) {
1794            googleObj.set('geojsonProperties', geojsonProperties);
1795          }
1796          break;
1797
1798        case 'MultiPolygon':
1799          googleObj = [];
1800          bounds = new google.maps.LatLngBounds();
1801          for (i = 0; i < geojsonGeometry.coordinates.length; i++) {
1802            paths = [];
1803            for (j = 0; j < geojsonGeometry.coordinates[i].length; j++) {
1804              path = [];
1805              for (k = 0; k < geojsonGeometry.coordinates[i][j].length; k++) {
1806                ll = new google.maps.LatLng(geojsonGeometry.coordinates[i][j][k][1], geojsonGeometry.coordinates[i][j][k][0]);
1807                bounds.extend(ll);
1808                path.push(ll);
1809              }
1810              paths.push(path);
1811            }
1812            opts.paths = paths;
1813            googleObj.push(new google.maps.Polygon(opts));
1814          }
1815          if (geojsonProperties) {
1816            for (k = 0; k < googleObj.length; k++) {
1817              googleObj[k].set('geojsonProperties', geojsonProperties);
1818            }
1819          }
1820          for (k = 0; k < googleObj.length; k++) {
1821            googleObj[k].set('bounds', bounds);
1822          }
1823          break;
1824
1825        case 'GeometryCollection':
1826          googleObj = [];
1827          if (!geojsonGeometry.geometries) {
1828            googleObj = _error('Invalid GeoJSON object: GeometryCollection object missing \'geometries\' member.');
1829          }
1830          else {
1831            for (i = 0; i < geojsonGeometry.geometries.length; i++) {
1832              googleObj.push(_geometryToGoogleMaps(geojsonGeometry.geometries[i], opts, geojsonProperties || null));
1833            }
1834          }
1835          break;
1836
1837        default:
1838          googleObj = _error('Invalid GeoJSON object: Geometry object must be one of \'Point\', \'LineString\', \'Polygon\' or \'MultiPolygon\'.');
1839      }
1840
1841      return googleObj;
1842
1843    };
1844
1845    let _error = function (message) {
1846
1847      return {
1848        type: 'Error',
1849        message: message
1850      };
1851
1852    };
1853
1854    let obj;
1855
1856    let opts = options || {};
1857
1858    switch (geojson.type) {
1859      case 'FeatureCollection':
1860        if (!geojson.features) {
1861          obj = _error('Invalid GeoJSON object: FeatureCollection object missing \'features\' member.');
1862        }
1863        else {
1864          obj = [];
1865          for (let y = 0; y < geojson.features.length; y++) {
1866            obj.push(_geometryToGoogleMaps(geojson.features[y].geometry, opts, geojson.features[y].properties));
1867          }
1868        }
1869        break;
1870
1871      case 'GeometryCollection':
1872        if (!geojson.geometries) {
1873          obj = _error('Invalid GeoJSON object: GeometryCollection object missing \'geometries\' member.');
1874        }
1875        else {
1876          obj = [];
1877          for (let z = 0; z < geojson.geometries.length; z++) {
1878            obj.push(_geometryToGoogleMaps(geojson.geometries[z], opts, geojson.geometries[z].properties));
1879          }
1880        }
1881        break;
1882
1883      case 'Feature':
1884        if (!(geojson.properties && geojson.geometry)) {
1885          obj = _error('Invalid GeoJSON object: Feature object missing \'properties\' or \'geometry\' member.');
1886        }
1887        else {
1888          obj = _geometryToGoogleMaps(geojson.geometry, opts, geojson.properties);
1889        }
1890        break;
1891
1892      case 'Point': case 'MultiPoint': case 'LineString': case 'MultiLineString': case 'Polygon': case 'MultiPolygon':
1893        obj = geojson.coordinates
1894          ? obj = _geometryToGoogleMaps(geojson, opts, geojson.properties)
1895          : _error('Invalid GeoJSON object: Geometry object missing \'coordinates\' member.');
1896        break;
1897
1898      default:
1899        obj = _error('Invalid GeoJSON object: GeoJSON object must be one of \'Point\', \'LineString\', \'Polygon\', \'MultiPolygon\', \'Feature\', \'FeatureCollection\' or \'GeometryCollection\'.');
1900
1901    }
1902
1903    return obj;
1904  };
1905
1906})(jQuery, Drupal);
1907;
1908/**
1909 * @file
1910 * Javascript for the Geofield Google Map formatter.
1911 */
1912
1913(function ($, Drupal) {
1914
1915  'use strict';
1916
1917  /**
1918   * The Geofield Google Map formatter behavior.
1919   *
1920   * @type {Drupal~behavior}
1921   *
1922   * @prop {Drupal~behaviorAttach} attach
1923   *   Attaches the Geofield Google Map formatter behavior.
1924   */
1925  Drupal.behaviors.geofieldGoogleMap = {
1926    attach: function (context, drupalSettings) {
1927
1928      function loadMap(mapId) {
1929        // Check if the Map container really exists and hasn't been yet
1930        // initialized.
1931        if (drupalSettings['geofield_google_map'][mapId] && !Drupal.geoFieldMapFormatter.map_data[mapId]) {
1932
1933          let map_settings = drupalSettings['geofield_google_map'][mapId]['map_settings'];
1934          let data = drupalSettings['geofield_google_map'][mapId]['data'];
1935
1936          // Set the map_data[mapid] settings.
1937          Drupal.geoFieldMapFormatter.map_data[mapId] = map_settings;
1938
1939          // Load before the GMap Library, if needed.
1940          Drupal.geoFieldMapFormatter.loadGoogle(mapId, map_settings.gmap_api_key, map_settings.map_additional_libraries, function () {
1941            if (!document.getElementById(mapId)) {
1942              return;
1943            }
1944            Drupal.geoFieldMapFormatter.map_initialize(mapId, map_settings, data, context);
1945          });
1946        }
1947      }
1948
1949      if (drupalSettings['geofield_google_map']) {
1950
1951        // If the IntersectionObserver API is available, create an observer to load the map when it enters the viewport
1952        // It will be used to handle map loading instead of displaying the map on page load.
1953        let mapObserver = null;
1954        if ('IntersectionObserver' in window){
1955          mapObserver = new IntersectionObserver(function (entries, observer) {
1956            for(var i = 0; i < entries.length; i++) {
1957              if(entries[i].isIntersecting){
1958                const mapId = entries[i].target.id;
1959                loadMap(mapId);
1960              }
1961            }
1962          });
1963        }
1964
1965        $(context).find('.geofield-google-map').once('geofield-processed').each(function (index, element) {
1966          const mapId = $(element).attr('id');
1967          if (drupalSettings['geofield_google_map'][mapId]) {
1968            const map_settings = drupalSettings['geofield_google_map'][mapId]['map_settings'];
1969            if (mapObserver && map_settings['map_lazy_load']['lazy_load']) {
1970              mapObserver.observe(element)
1971            } else {
1972              loadMap(mapId);
1973            }
1974          }
1975        });
1976      }
1977    }
1978  };
1979
1980  Drupal.geoFieldMapFormatter = {
1981
1982    map_start: {
1983      center: {lat: 41.85, lng: -87.65},
1984      zoom: 18
1985    },
1986
1987    map_data: {},
1988
1989    // Google Maps are loaded lazily. In some situations load_google() is
1990    // called twice, which results in "You have included the Google Maps API
1991    // multiple times on this page. This may cause unexpected errors." errors.
1992    // This flag will prevent repeat $.getScript() calls.
1993    maps_api
1993_loading: false,
1994
1995    /**
1996     * Returns the re-coded google maps api language parameter, from html lang attribute.
1997     *
1998     * @param {string} html_language - The language id string
1999     *
2000     * @return {string} - The transformed language id string
2001     */
2002    googleMapsLanguage: function (html_language) {
2003      switch (html_language) {
2004        case 'zh-hans':
2005          html_language = 'zh-CN';
2006          break;
2007
2008        case 'zh-hant':
2009          html_language = 'zh-TW';
2010          break;
2011      }
2012      return html_language;
2013    },
2014
2015    /**
2016     * Provides the callback that is called when maps loads.
2017     */
2018    googleCallback: function () {
2019      let self = this;
2020      // Wait until the window load event to try to use the maps library.
2021      $(document).ready(function (e) {
2022        _.each(self.googleCallbacks, function (callback) {
2023          callback.callback();
2024        });
2025        self.googleCallbacks = [];
2026      });
2027    },
2028
2029    /**
2030     * Adds a callback that will be called once the maps library is loaded.
2031     *
2032     * @param {string} callback - The callback
2033     */
2034    addCallback: function (callback) {
2035      let self = this;
2036      // Ensure callbacks array.
2037      self.googleCallbacks = self.googleCallbacks || [];
2038      self.googleCallbacks.push({callback: callback});
2039    },
2040
2041    /**
2042     * Load Google Maps library.
2043     *
2044     * @param {string} mapid - The map id
2045     * @param {string} gmap_api_key - The gmap api key
2046     * @param {array} additional_libraries - Additional Libraries list
2047     * @param {string} callback - the Callback function  name
2048     */
2049    loadGoogle: function (mapid, gmap_api_key, additional_libraries, callback) {
2050      let self = this;
2051      let html_language = $('html').attr('lang') || 'en';
2052
2053      // Add the callback.
2054      self.addCallback(callback);
2055
2056      // Check for google maps.
2057      if (typeof google === 'undefined' || typeof google.maps === 'undefined') {
2058        if (self.maps_api_loading === true) {
2059          return;
2060        }
2061
2062        self.maps_api_loading = true;
2063        // Google maps isn't loaded so lazy load google maps.
2064        // Default script path.
2065        let scriptPath = self.map_data[mapid]['gmap_api_localization'] + '?v=3.exp&sensor=false&language=' + self.googleMapsLanguage(html_language);
2066
2067        // If a Google API key is set, use it.
2068        if (gmap_api_key) {
2069          scriptPath += '&key=' + gmap_api_key;
2070        }
2071
2072        if (additional_libraries) {
2073          let libraries = [];
2074          for (let library in additional_libraries) {
2075            if (additional_libraries.hasOwnProperty(library)) {
2076              libraries.push(library);
2077            }
2078          }
2079          scriptPath += '&libraries=' + libraries.join();
2080        }
2081
2082        $.getScript(scriptPath)
2083          .done(function () {
2084            self.maps_api_loading = false;
2085            self.googleCallback();
2086          });
2087
2088      }
2089      else {
2090        // Google maps loaded. Run callback.
2091        self.googleCallback();
2092      }
2093    },
2094
2095    checkImage: function (imageSrc, setIcon, logError) {
2096      let img = new Image();
2097      img.src = imageSrc;
2098      img.onload = setIcon;
2099      img.onerror = logError;
2100    },
2101
2102    place_feature: function (feature, mapid) {
2103      let self = this;
2104      let icon_image = null;
2105
2106      // Override and set icon image with geojsonProperties.icon, if set as not
2107      // null/empty.
2108      if (feature.geojsonProperties.icon && feature.geojsonProperties.icon.length > 0) {
2109        icon_image = feature.geojsonProperties.icon;
2110      }
2111
2112      // Define the OverlappingMarkerSpiderfier flag.
2113      let oms = self.map_data[mapid].oms ? self.map_data[mapid].oms : null;
2114
2115      // Set the personalized Icon Image, if set.
2116      if (feature.setIcon && icon_image && icon_image.length > 0) {
2117        self.checkImage(icon_image,
2118          // Success loading image.
2119          function () {
2120            feature.setIcon(icon_image);
2121          });
2122      }
2123
2124      let map = self.map_data[mapid].map;
2125
2126      // Add a default Tooltip on the title geojsonProperty, if existing.
2127      if (feature.setTitle && feature.geojsonProperties.tooltip) {
2128        feature.setTitle(feature.geojsonProperties.tooltip);
2129      }
2130
2131      // If the feature is a Point, make it a Marker and extend the Map bounds.
2132      if (feature.getPosition) {
2133        if (oms) {
2134          self.map_data[mapid].oms.addMarker(feature);
2135        }
2136        else {
2137          feature.setMap(map);
2138        }
2139
2140        // Generate the markers object index based on entity id (and geofield
2141        // cardinality), and add the marker to the markers object.
2142        let entity_id = feature['geojsonProperties']['entity_id'];
2143        if (self.map_data[mapid].geofield_cardinality && self.map_data[mapid].geofield_cardinality !== 1) {
2144          let i = 0;
2145          while (self.map_data[mapid].markers[entity_id + '-' + i]) {
2146            i++;
2147          }
2148          self.map_data[mapid].markers[entity_id + '-' + i] = feature;
2149        }
2150        else {
2151          self.map_data[mapid].markers[entity_id] = feature;
2152        }
2153
2154        self.map_data[mapid].map_bounds.extend(feature.getPosition());
2155
2156        // Check for eventual simple or OverlappingMarkerSpiderfier click
2157        // Listener.
2158        let clickListener = oms ? 'spider_click' : 'click';
2159        google.maps.event.addListener(feature, clickListener, function () {
2160          self.infowindow_open(mapid, feature);
2161        });
2162      }
2163
2164      // If the feature is a Polyline or a Polygon, add to the Map and extend
2165      // the Map bounds.
2166      if (feature.getPath) {
2167        let feature_options = feature.geojsonProperties.path_options ? JSON.parse(feature.geojsonProperties.path_options) : {};
2168        feature.setOptions(feature_options);
2169        feature.setMap(map);
2170        let path = feature.getPath();
2171        path.forEach(function (element) {
2172          self.map_data[mapid].map_bounds.extend(element);
2173        });
2174        google.maps.event.addListener(feature, 'click', function (event) {
2175          self.infowindow_open(mapid, feature, event.latLng);
2176        });
2177      }
2178
2179    },
2180
2181    // Closes and open the Map Infowindow at the input feature.
2182    infowindow_open: function (mapid, feature, anchor) {
2183      let self = this;
2184      let map = self.map_data[mapid].map;
2185      let properties = feature.get('geojsonProperties');
2186      if (feature.setTitle && properties && properties.title) {
2187        feature.setTitle(properties.title);
2188      }
2189      map.infowindow.close();
2190      if (properties.description) {
2191        map.infowindow.setContent(properties.description);
2192
2193        // Note: if the feature is a Marker (and not a Polyline/Polygon) its
2194        // extensions will override the infowindow anchor position, in the map.
2195        // infowindow.open method.
2196        map.infowindow.setPosition(anchor);
2197        setTimeout(function () {
2198          map.infowindow.open(map, feature);
2199        }, 200);
2200      }
2201    },
2202
2203    map_refresh: function (mapid) {
2204      let self = this;
2205      setTimeout(function () {
2206        google.maps.event.trigger(self.map_data[mapid].map, 'resize');
2207      }, 10);
2208    },
2209
2210    // Init Geofield Google Map and its functions.
2211    map_initialize: function (mapid, map_settings, data, context) {
2212      let self = this;
2213      $.noConflict();
2214
2215      // If google and google.maps have been defined.
2216      if (google && google.maps) {
2217        let styledMapType;
2218
2219        let mapOptions = {
2220          center: map_settings.map_center ? new google.maps.LatLng(map_settings.map_center.lat, map_settings.map_center.lon) : new google.maps.LatLng(42, 12.5),
2221          zoom: map_settings.map_zoom_and_pan.zoom.initial ? parseInt(map_settings.map_zoom_and_pan.zoom.initial) : 8,
2222          minZoom: map_settings.map_zoom_and_pan.zoom.min ? parseInt(map_settings.map_zoom_and_pan.zoom.min) : 1,
2223          maxZoom: map_settings.map_zoom_and_pan.zoom.max ? parseInt(map_settings.map_zoom_and_pan.zoom.max) : 20,
2224          gestureHandling: map_settings.map_zoom_and_pan.gestureHandling || 'auto',
2225          mapTypeId: map_settings.map_controls.map_type_id || 'roadmap'
2226        };
2227
2228        // Manage the old scrollwheel & draggable settings (deprecated by google maps api).
2229        if (!map_settings.map_zoom_and_pan.scrollwheel && !map_settings.map_zoom_and_pan.gestureHandling) {
2230          mapOptions.scrollwheel = false;
2231        }
2232        if (!map_settings.map_zoom_and_pan.draggable && !map_settings.map_zoom_and_pan.gestureHandling) {
2233          mapOptions.draggable = false;
2234        }
2235
2236        if (map_settings.map_controls.disable_default_ui) {
2237          mapOptions.disableDefaultUI = map_settings.map_controls.disable_default_ui;
2238        }
2239        else {
2240          // Implement Custom Style Map, if Set.
2241          if (map_settings.custom_style_map && map_settings.custom_style_map.custom_style_control && map_settings.custom_style_map.custom_style_name.length > 0 && map_settings.custom_style_map.custom_style_options.length > 0) {
2242            let customMapStyleName = map_settings.custom_style_map.custom_style_name;
2243            let customMapStyle = JSON.parse(map_settings.custom_style_map.custom_style_options);
2244            styledMapType = new google.maps.StyledMapType(customMapStyle, {name: customMapStyleName});
2245            map_settings.map_controls.map_type_control_options_type_ids.push('custom_styled_map');
2246          }
2247
2248          mapOptions.zoomControl = !!map_settings.map_controls.zoom_control;
2249          mapOptions.mapTypeControl = !!map_settings.map_controls.map_type_control;
2250          mapOptions.mapTypeControlOptions = {
2251            mapTypeIds: map_settings.map_controls.map_type_control_options_type_ids ? map_settings.map_controls.map_type_control_options_type_ids : ['roadmap', 'satellite', 'hybrid'],
2252            position: google.maps.ControlPosition.TOP_LEFT
2253          };
2254          mapOptions.scaleControl = !!map_settings.map_controls.scale_control;
2255          mapOptions.streetViewControl = !!map_settings.map_controls.street_view_control;
2256          mapOptions.fullscreenControl = !!map_settings.map_controls.fullscreen_control;
2257        }
2258
2259        // Add map_additional_options if any.
2260        if (map_settings.map_additional_options.length > 0) {
2261          let additionalOptions = JSON.parse(map_settings.map_additional_options);
2262          // Transforms additionalOptions "true", "false" values into true &
2263          // false.
2264          for (let prop in additionalOptions) {
2265            if (additionalOptions.hasOwnProperty(prop)) {
2266              if (additionalOptions[prop] === 'true') {
2267                additionalOptions[prop] = true;
2268              }
2269              if (additionalOptions[prop] === 'false') {
2270                additionalOptions[prop] = false;
2271              }
2272            }
2273          }
2274          // Merge mapOptions with additionalOptions.
2275          $.extend(mapOptions, additionalOptions);
2276        }
2277
2278        // Define the Geofield Google Map.
2279        let map = new google.maps.Map(document.getElementById(mapid), mapOptions);
2280
2281        // Add the Map Reset Control, if set.
2282        if (map_settings.map_zoom_and_pan.map_reset) {
2283          let mapResetControlPosition = map_settings.map_zoom_and_pan.map_reset_position || 'TOP_RIGHT';
2284
2285          // Create the DIV to hold the control and call the mapResetControl()
2286          // constructor passing in this DIV.
2287          let mapResetControlDiv = document.createElement('div');
2288          mapResetControlDiv.style.zIndex = "10";
2289          mapResetControlDiv.index = 1;
2290          new self.map_reset_control(mapResetControlDiv, mapid);
2291          map.controls[google.maps.ControlPosition[mapResetControlPosition]].push(mapResetControlDiv);
2292        }
2293
2294        if (Drupal.geoFieldMapGeocoder && map_settings.map_geocoder.control) {
2295          let mapGeocoderControlPosition = map_settings.map_geocoder.settings.position || 'TOP_RIGHT';
2296          let mapGeocoderControlDiv = document.createElement('div');
2297          Drupal.geoFieldMapFormatter.map_data[mapid].geocoder_control = new Drupal.geoFieldMapGeocoder.map_control(mapGeocoderControlDiv, mapid);
2298          mapGeocoderControlDiv.index = 1;
2299          map.controls[google.maps.ControlPosition[mapGeocoderControlPosition]].push(Drupal.geoFieldMapFormatter.map_data[mapid].geocoder_control);
2300          Drupal.geoFieldMapGeocoder.map_control_autocomplete(mapid, map_settings.map_geocoder.settings, $(Drupal.geoFieldMapFormatter.map_data[mapid].geocoder_control), 'formatter', 'gmap');
2301        }
2302
2303        // If defined a Custom Map Style, associate the styled map with
2304        // custom_styled_map MapTypeId and set it to display.
2305        if (styledMapType) {
2306          map.mapTypes.set('custom_styled_map', styledMapType);
2307          // Set Custom Map Style to Default, if requested.
2308          if (map_settings.custom_style_map && map_settings.custom_style_map.custom_style_default) {
2309            map.setMapTypeId('custom_styled_map');
2310          }
2311        }
2312
2313        // Define a mapid self property, so other code can interact with it.
2314        self.map_data[mapid].map = map;
2315        self.map_data[mapid].map_options = mapOptions;
2316        self.map_data[mapid].features = data.features;
2317        self.map_data[mapid].markers = {};
2318
2319        // Define the MapBounds property.
2320        self.map_data[mapid].map_bounds = new google.maps.LatLngBounds();
2321
2322        // Set the zoom force and center property for the map.
2323        self.map_data[mapid].zoom_force = !!map_settings.map_zoom_and_pan.zoom.force;
2324        self.map_data[mapid].center_force = !!map_settings.map_center.center_force;
2325
2326        // Parse the Geojson data into Google Maps Locations.
2327        let features = data.features && data.features.length > 0 ? Drupal.googleGeoJson(data) : null;
2328
2329        if (features && features.length > 0 && (!features.type || features.type !== 'Error')) {
2330
2331          /**
2332           * Implement  OverlappingMarkerSpiderfier if its control set true.
2333           */
2334          if (map_settings.map_oms && map_settings.map_oms.map_oms_control && OverlappingMarkerSpiderfier) {
2335            let omsOptions = map_settings.map_oms.map_oms_options.length > 0 ? JSON.parse(map_settings.map_oms.map_oms_options) : {
2336              markersWontMove: true,
2337              markersWontHide: true,
2338              basicFormatEvents: true,
2339              keepSpiderfied: true
2340            };
2341            self.map_data[mapid].oms = new OverlappingMarkerSpiderfier(map, omsOptions);
2342          }
2343
2344          map.infowindow = new google.maps.InfoWindow({
2345            content: ''
2346          });
2347
2348          // If the map.infowindow is defined, add an event listener for the
2349          // Ajax Infowindow Popup.
2350          google.maps.event.addListener(map.infowindow, 'domready', function () {
2351            let element = document.createElement('div');
2352            element.innerHTML = map.infowindow.getContent().trim();
2353            let content = $('[data-geofield-google-map-ajax-popup]', element);
2354            if (content.length) {
2355              let url = content.data('geofield-google-map-ajax-popup');
2356              Drupal.ajax({url: url}).execute();
2357            }
2358            // Attach drupal behaviors on new content.
2359            $(element).each(function () {
2360              Drupal.attachBehaviors(this, drupalSettings);
2361            })
2362          });
2363
2364          if (features.setMap) {
2365            self.place_feature(features, mapid);
2366          }
2367          else {
2368            for (let i in features) {
2369              if (features[i].setMap) {
2370                self.place_feature(features[i], mapid);
2371              }
2372              else {
2373                for (let j in features[i]) {
2374                  if (features[i][j].setMap) {
2375                    self.place_feature(features[i][j], mapid);
2376                  }
2377                }
2378              }
2379            }
2380          }
2381
2382          // Implement Markeclustering, if more than 1 marker on the map,
2383          // and the markercluster option is set to true.
2384          if (typeof MarkerClusterer !== 'undefined' && map_settings.map_markercluster.markercluster_control) {
2385
2386            let markeclusterOption = {
2387              imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'
2388            };
2389
2390            // Add markercluster_additional_options if any.
2391            if (map_settings.map_markercluster.markercluster_additional_options.length > 0) {
2392              let markeclusterAdditionalOptions = JSON.parse(map_settings.map_markercluster.markercluster_additional_options);
2393              // Merge markeclusterOption with markeclusterAdditionalOptions.
2394              $.extend(markeclusterOption, markeclusterAdditionalOptions);
2395            }
2396
2397            // Define a markerCluster property, so other code can interact with
2398            // it.
2399            let markerCluster = [];
2400            let keys = Object.keys(self.map_data[mapid].markers);
2401            for (let k = 0; k < keys.length; k++) {
2402              markerCluster.push(self.map_data[mapid].markers[keys[k]]);
2403            }
2404            self.map_data[mapid].markerCluster = new MarkerClusterer(map, markerCluster, markeclusterOption);
2405          }
2406
2407          // If the Map Initial State is defined by MapBounds,
2408          // and the map center is not forced.
2409          if (!self.mapBoundsAreNull(self.map_data[mapid].map_bounds) && !self.map_data[mapid].center_force) {
2410            map.fitBounds(self.map_data[mapid].map_bounds);
2411          }
2412          // Else if the Map Initial State is defined by Markers in the exact
2413          // same locations,.
2414          else if (self.map_data[mapid].markers.constructor === Object &&
2415            self.mapBoundsAreNull(self.map_data[mapid].map_bounds) &&
2416            // And the map center is not forced.
2417            !self.map_data[mapid].center_force) {
2418            map.setCenter(self.map_data[mapid].markers[Object.keys(self.map_data[mapid].markers)[0]].getPosition());
2419          }
2420
2421        }
2422
2423        google.maps.event.addListenerOnce(map, 'bounds_changed', function () {
2424          // Force the Map Zoom if requested.
2425          if (self.map_data[mapid].zoom_force) {
2426            self.map_data[mapid].map.setZoom(self.map_data[mapid].map_options.zoom);
2427          }
2428        });
2429
2430        // At the beginning (once) ...
2431        google.maps.event.addListenerOnce(map, 'idle', function () {
2432
2433          // Open the Feature infowindow, if so set.
2434          if (self.map_data[mapid].map_marker_and_infowindow.force_open && parseInt(self.map_data[mapid].map_marker_and_infowindow.force_open) === 1) {
2435            // map.setCenter(features[0].getPosition());
2436            self.infowindow_open(mapid, features[0]);
2437          }
2438
2439          // In case of map initial position not forced, and zooFiner not
2440          // null/neutral, adapt the Map Zoom and the Start Zoom accordingly.
2441          if (!self.map_data[mapid].zoom_force && self.map_data[mapid].map_zoom_and_pan.zoom.finer && self.map_data[mapid].map_zoom_and_pan.zoom.finer !== 0) {
2442            map.setOptions({
2443              zoom: map.getZoom() + parseInt(self.map_data[mapid].map_zoom_and_pan.zoom.finer)
2444            });
2445          }
2446
2447          // Update map initial state after everything is settled.
2448          self.map_set_start_state(mapid, map.getCenter(), map.getZoom());
2449
2450          // Trigger a custom event on Geofield Map initialized, with mapid.
2451          $(context).trigger('geofieldMapInit', mapid);
2452        });
2453
2454      }
2455    },
2456
2457    mapBoundsAreNull: function (mapBounds) {
2458      let north_east = mapBounds.getNorthEast();
2459      let south_west = mapBounds.getSouthWest();
2460      return north_east.toString() === south_west.toString();
2461
2462    },
2463
2464    map_set_start_state: function (mapid, center, zoom) {
2465      let self = this;
2466      self.map_data[mapid].map_start_center = center;
2467      self.map_data[mapid].map_start_zoom = zoom;
2468    },
2469
2470    map_reset_control: function (controlDiv, mapid) {
2471      // Set CSS for the control border.
2472      let controlUI = document.createElement('div');
2473      controlUI.style.backgroundColor = '#fff';
2474      controlUI.style.boxShadow = 'rgba(0,0,0,.3) 0px 1px 4px -1px';
2475      controlUI.style.cursor = 'pointer';
2476      controlUI.title = Drupal.t('Click to reset the map to its initial state');
2477      controlUI.style.margin = '10px';
2478      controlUI.style.position = 'relative';
2479      controlUI.id = 'geofield-map--' + mapid + '--reset-control';
2480      controlDiv.appendChild(controlUI);
2481
2482      // Set CSS for the control interior.
2483      let controlText = document.createElement('div');
2484      controlText.style.position = 'relative';
2485      controlText.innerHTML = Drupal.t('Reset Map');
2486      controlText.style.padding = '0 17px';
2487      controlText.style.display = 'table-cell';
2488      controlText.style.height = '40px';
2489      controlText.style.fontSize = '18px';
2490      controlText.style.color = 'rgb(86,86,86)';
2491      controlText.style.textAlign = 'center';
2492      controlText.style.verticalAlign = 'middle';
2493      controlUI.appendChild(controlText);
2494
2495      // Setup the click event listeners: simply set the map to Chicago.
2496      controlUI.addEventListener('click', function () {
2497        Drupal.geoFieldMapFormatter.map_data[mapid].map.setCenter(Drupal.geoFieldMapFormatter.map_data[mapid].map_start_center);
2498        Drupal.geoFieldMapFormatter.map_data[mapid].map.setZoom(Drupal.geoFieldMapFormatter.map_data[mapid].map_start_zoom);
2499      });
2500      return controlUI;
2501    }
2502
2503  };
2504
2505})(jQuery, Drupal);
2506;

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.