PageSourceSearch

https://www.mcgill.ca/contact-us/modules/contrib/eu_cookie_compliance/js/eu_cookie_compliance.js?tm53z7

js mcgill.ca collected 2026-10-01 07:21:50 UTC 68,689 bytes, 1,611 lines download raw bytes

1/**
2 * @file
3 * eu_cookie_compliance.js
4 *
5 * Defines the behavior of the eu cookie compliance banner.
6 *
7 * Statuses:
8 *  null: not yet agreed (or withdrawn), show popup
9 *  0: Disagreed
10 *  1: Agreed, show thank you banner
11 *  2: Agreed
12 */
13
14(function ($, Drupal, drupalSettings, cookies) {
15
16  'use strict';
17  var euCookieComplianceBlockCookies;
18  var cookieValueDisagreed = (typeof drupalSettings.eu_cookie_compliance.cookie_value_disagreed === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_value_disagreed === '') ? '0' : drupalSettings.eu_cookie_compliance.cookie_value_disagreed;
19  var cookieValueAgreedShowThankYou = (typeof drupalSettings.eu_cookie_compliance.cookie_value_agreed_show_thank_you === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_value_agreed_show_thank_you === '') ? '1' : drupalSettings.eu_cookie_compliance.cookie_value_agreed_show_thank_you;
20  var cookieValueAgreed = (typeof drupalSettings.eu_cookie_compliance.cookie_value_agreed === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_value_agreed === '') ? '2' : drupalSettings.eu_cookie_compliance.cookie_value_agreed;
21
22  function setCookie(name,value,settings) {
23    var expires = "";
24
25    if (settings['expires'] !== undefined) {
26      if (typeof (settings['expires']) == 'number') {
27        var date = new Date();
28        settings['expires'] = date.setTime(date.getTime() + (settings['expires']*24*60*60*1000));
29      }
30      expires = "; expires=" + settings['expires'].toUTCString();
31    }
32    var path = (settings['path'] === undefined)?'/':settings['path'];
33    var domain = "";
34    if (settings['domain'] !== undefined) {
35      domain = "; domain=" + settings['domain'];
36    }
37    document.cookie = name + "=" + (value || "")  + expires + "; path=" + path  + domain + "; SameSite=Strict";
38  }
39
40  function getCookie(name) {
41    var ca = document.cookie.split(';');
42    if (name !== undefined) {
43      var nameEQ = name + "=";
44      for (var i = 0; i < ca.length; i++) {
45        var c = ca[i];
46        while (c.charAt(0) == ' ') c = c.substring(1, c.length);
47        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
48      }
49      return null;
50    }
51    return ca;
52  }
53  function eraseCookie(name) {
54    document.cookie = name +'=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
55  }
56
57  Drupal.behaviors.euCookieCompliancePopup = {
58    attach: function (context) {
59      if (typeof drupalSettings.eu_cookie_compliance !== 'undefined') {
60        const element = document.querySelector(drupalSettings.eu_cookie_compliance.containing_element);
61        if (!element.getAttribute('data-eu-cookie-compliance-once')) {
62          element.setAttribute('data-eu-cookie-compliance-once', 'true');
63        } else {
64          return;
65        }
66        // Initialize internal variables.
67        _euccCurrentStatus = self.getCurrentStatus();
68        _euccSelectedCategories = self.getAcceptedCategories();
69        // If configured, check JSON callback to determine if in EU.
70        if (drupalSettings.eu_cookie_compliance.popup_eu_only_js) {
71          if (Drupal.eu_cookie_compliance.showBanner()) {
72            var url = drupalSettings.path.baseUrl + drupalSettings.path.pathPrefix + 'eu-cookie-compliance-check';
73            var data = {};
74            $.getJSON(url, data, function (data) {
75              // If in the EU, show the compliance banner.
76              if (data.in_eu) {
77                Drupal.eu_cookie_compliance.execute();
78              }
79
80              // If not in EU, set an agreed cookie automatically.
81              else {
82                Drupal.eu_cookie_compliance.setStatus(cookieValueAgreed);
83                // Set the geoip_match to false so it can be used elsewhere.
84                drupalSettings.eu_cookie_compliance.geoip_match = false;
85                if (!euCookieComplianceHasLoadedScripts) {
86                  Drupal.eu_cookie_compliance.loadScripts();
87                }
88                // Also set all the categories as agreed if applicable, and load
89                // scripts.
90                if (drupalSettings.eu_cookie_compliance.method === 'categories') {
91                  var categories = drupalSettings.eu_cookie_compliance.cookie_categories;
92                  Drupal.eu_cookie_compliance.setAcceptedCategories(categories);
93                  Drupal.eu_cookie_compliance.loadCategoryScripts(categories);
94                }
95              }
96            });
97          }
98        }
99
100        // Otherwise, fallback to standard behavior which is to render the banner.
101        else if (!drupalSettings.eu_cookie_compliance.hide_the_banner) {
102          Drupal.eu_cookie_compliance.execute();
103        }
104        $(element).addClass('eu-cookie-compliance-status-' + Drupal.eu_cookie_compliance.getCurrentStatus());
105      }
106    },
107  };
108
109  // Set up the namespace as a function to store list of arguments in a queue.
110  Drupal.eu_cookie_compliance = Drupal.eu_cookie_compliance || function () {
111    (Drupal.eu_cookie_compliance.queue = Drupal.eu_cookie_compliance.queue || []).push(arguments)
112  };
113  // Initialize the object with some data.
114  Drupal.eu_cookie_compliance.a = +new Date;
115  // A shorter name to use when accessing the namespace.
116  var self = Drupal.eu_cookie_compliance;
117  // Save our cookie preferences locally only.
118  // Used by external scripts to modify data before it is used.
119  var _euccSelectedCategories = [];
120  var _euccCurrentStatus = null;
121  self.updateSelectedCategories = function (categories) {
122    _euccSelectedCategories = categories;
123  }
124  self.updateCurrentStatus = function (status) {
125    _euccCurrentStatus = status;
126  }
127
128  Drupal.eu_cookie_compliance.execute = function () {
129    try {
130      if (!drupalSettings.eu_cookie_compliance.popup_enabled) {
131        return;
132      }
133
134      if (!Drupal.eu_cookie_compliance.cookiesEnabled()) {
135        return;
136      }
137
138      if (!drupalSettings.eu_cookie_compliance.modules_allow_popup) {
139        return;
140      }
141
142      _euccCurrentStatus = Drupal.eu_cookie_compliance.getCurrentStatus();
143
144      if (typeof Drupal.eu_cookie_compliance.getVersion() === 'undefined') {
145        // If version doesn't exist as a cookie, set it to a default one.
146        // For sites who update to this version of the module, it helps to
147        // re-trigger the popup in case you switched to category based consent.
148        // For first time runs, it makes no difference as the other IF statements
149        // below will still cause the popup to trigger
150        // For incrementing the version, it also makes no difference as either it's
151        // a returning user and will have a version set, or it's a new user and
152        // the other checks will trigger it.
153        Drupal.eu_cookie_compliance.setVersion("unknown");
154      }
155
156      if (drupalSettings.eu_cookie_compliance.popup_eu_only === true && drupalSettings.eu_cookie_compliance.geoip_match !== true) {
157        return;
158      }
159
160      var versionChanged = Drupal.eu_cookie_compliance.getVersion() !== drupalSettings.eu_cookie_compliance.cookie_policy_version;
161
162      // Closed if status has a value and the version hasn't changed or user has not agreed.
163      var cookieName = (typeof drupalSettings.eu_cookie_compliance.cookie_name === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_name === '') ? 'cookie-agreed' : drupalSettings.eu_cookie_compliance.cookie_name;
164      var closed = !drupalSettings.eu_cookie_compliance.open_by_default ||
165        (_euccCurrentStatus !== null && !versionChanged || (getCookie(cookieName) === 'null' && drupalSettings.eu_cookie_compliance.settings_tab_enabled));
166
167      // Only worried about OPT_IN / GDPR method at present for the perm. settings tab.
168      if (_euccCurrentStatus === cookieValueDisagreed && drupalSettings.eu_cookie_compliance.settings_tab_enabled && (drupalSettings.eu_cookie_compliance.method === 'opt_in' || drupalSettings.eu_cookie_compliance.method === 'categories')) {
169         Drupal.eu_cookie_compliance.createPopup(drupalSettings.eu_cookie_compliance.popup_html_info, (_euccCurrentStatus !== null));
170         $('.eu-cookie-withdraw-tab').click(Drupal.eu_cookie_compliance.toggleWithdrawBanner);
171         Drupal.eu_cookie_compliance.attachAgreeEvents();
172      }
173      else if ((_euccCurrentStatus === cookieValueDisagreed && drupalSettings.eu_cookie_compliance.method === 'default') || _euccCurrentStatus === null || (_euccCurrentStatus !== cookieValueDisagreed && drupalSettings.eu_cookie_compliance.withdraw_enabled && drupalSettings.eu_cookie_compliance.withdraw_button_on_info_popup) || (_euccCurrentStatus !== cookieValueDisagreed && versionChanged)) {
174        if (drupalSettings.eu_cookie_compliance.withdraw_enabled || !drupalSettings.eu_cookie_compliance.disagree_do_not_show_popup || _euccCurrentStatus === null) {
175          // Detect mobile here and use mobile_popup_html_info, if we have a mobile device.
176          if (window.matchMedia('(max-width: ' + drupalSettings.eu_cookie_compliance.mobile_breakpoint + 'px)').matches && drupalSettings.eu_cookie_compliance.use_mobile_message) {
177            Drupal.eu_cookie_compliance.createPopup(drupalSettings.eu_cookie_compliance.mobile_popup_html_info, closed);
178          }
179          else {
180            Drupal.eu_cookie_compliance.createPopup(drupalSettings.eu_cookie_compliance.popup_html_info, closed);
181          }
182          Drupal.eu_cookie_compliance.initPopup();
183          Drupal.eu_cookie_compliance.resizeListener();
184          $('.eu-cookie-withdraw-tab').click(Drupal.eu_cookie_compliance.toggleWithdrawBanner);
185        }
186      }
187      else if (_euccCurrentStatus === cookieValueAgreedShowThankYou && drupalSettings.eu_cookie_compliance.popup_agreed_enabled) {
188        // Thank you banner.
189        Drupal.eu_cookie_compliance.createPopup(drupalSettings.eu_cookie_compliance.popup_html_agreed);
190        Drupal.eu_cookie_compliance.attachHideEvents();
191      }
192      else if (_euccCurrentStatus === cookieValueAgreed && drupalSettings.eu_cookie_compliance.withdraw_enabled) {
193        if (!drupalSettings.eu_cookie_compliance.withdraw_button_on_info_popup) {
194          Drupal.eu_cookie_compliance.createWithdrawBanner(drupalSettings.eu_cookie_compliance.withdraw_markup);
195          Drupal.eu_cookie_compliance.initPopup();
196          Drupal.eu_cookie_compliance.resizeListener();
197          $('.eu-cookie-withdraw-tab').click(Drupal.eu_cookie_compliance.toggleWithdrawBanner);
198        }
199      }
200    }
201    catch (e) {
202    }
203  };
204
205  Drupal.eu_cookie_compliance.initPopup = function () {
206    Drupal.eu_cookie_compliance.attachAgreeEvents();
207
208    if (drupalSettings.eu_cookie_compliance.method === 'categories') {
209      Drupal.eu_cookie_compliance.setPreferenceCheckboxes(_euccSelectedCategories);
210      Drupal.eu_cookie_compliance.attachSavePreferencesEvents();
211    }
212
213    if (drupalSettings.eu_cookie_compliance.withdraw_enabled) {
214      Drupal.eu_cookie_compliance.attachWithdrawEvents();
215      if (_euccCurrentStatus === cookieValueAgreedShowThankYou || _euccCurrentStatus === cookieValueAgreed) {
216        $('.eu-cookie-withdraw-button').removeClass('visually-hidden');
217        $('.eu-cookie-compliance-reject-button').addClass('visually-hidden');
218      }
219    }
220  }
221
222  Drupal.eu_cookie_compliance.positionTab = function () {
223    // We do not use the tab, we use the button in the footer. Do not try to
224    // reposition it.
225    return;
226    if (drupalSettings.eu_cookie_compliance.popup_position) {
227      let totalHeight = $('.eu-cookie-withdraw-tab').outerHeight();
228      if ($('#sliding-popup').length) {
229        totalHeight += $('#sliding-popup').outerHeight();
230      }
231      if ($('.eu-cookie-withdraw-wrapper').length) {
232        $('.eu-cookie-withdraw-tab').css('margin-top', '0');
233      }
234      else {
235        $('.eu-cookie-withdraw-tab').css('margin-top', totalHeight + 'px');
236      }
237    }
238  };
239
240  Drupal.eu_cookie_compliance.createWithdrawBanner = function (html) {
241    var $html = $('<div></div>').html(html);
242    var $banner = $('.eu-cookie-withdraw-banner', $html);
243    $html.attr({
244      'id': 'sliding-popup',
245      'role': 'alertdialog',
246      'aria-describedby': 'popup-text',
247      'aria-label': Drupal.t('Cookie compliance banner'),
248    });
249    $html.addClass('eu-cookie-withdraw-wrapper');
250
251    $html.trigger('eu_cookie_compliance_popup_close');
252
253    if (!drupalSettings.eu_cookie_compliance.popup_use_bare_css && !drupalSettings.eu_cookie_compliance.popup_use_olivero_css) {
254      $banner.height(drupalSettings.eu_cookie_compliance.popup_height)
255          .width(drupalSettings.eu_cookie_compliance.popup_width);
256    }
257    $html.hide();
258    var height = 0;
259    if (drupalSettings.eu_cookie_compliance.popup_position) {
260      $html.prependTo(drupalSettings.eu_cookie_compliance.containing_element);
261      height = parseInt($html.outerHeight());
262
263      $html.show()
264          .addClass('sliding-popup-top')
265          .addClass('clearfix')
266        .css({ top: Drupal.eu_cookie_compliance.getBannerTopHiddenPosition(height)});
267      // For some reason, the tab outerHeight is -10 if we don't use a timeout
268      // function to reveal the tab.
269      setTimeout(function () {
270        var height = $html.outerHeight();
271
272        $html.animate({ top: Drupal.eu_cookie_compliance.getBannerTopHiddenPosition(height) }, drupalSettings.eu_cookie_compliance.popup_delay, null);
273        if (!drupalSettings.eu_cookie_compliance.fixed_top_position) {
274          $('body').animate({ 'margin-top': -height + 'px' });
275        }
276      }.bind($html), 0);
277    }
278    else {
279      if (drupalSettings.eu_cookie_compliance.better_support_for_screen_readers) {
280        $html.prependTo(drupalSettings.eu_cookie_compliance.containing_element);
281      }
282      else {
283        $html.appendTo(drupalSettings.eu_cookie_compliance.containing_element);
284      }
285      height = $html.outerHeight();
286      $html.show()
287          .addClass('sliding-popup-bottom');
288      // Move the popup directly outside at the bottom of the page and remove
289      // drawer animation.
290      height = $html.outerHeight();
291      $html.css({ bottom: -1 * height });
292    }
293    $('body').removeClass('eu-cookie-compliance-popup-open');
294    $banner
295        .attr('aria-hidden', true)
296        .find('a, button, input')
297        .attr('tabindex', -1);
298  };
299
300  Drupal.eu_cookie_compliance.getBannerTopPosition = function (height) {
301    let bannerTopPosition;
302    if (drupalSettings.eu_cookie_compliance.fixed_top_position) {
303      bannerTopPosition = 0;
304    }
305    else {
306      return 0;
307    }
308
309    if ($('.toolbar-tray-horizontal.is-active').length) {
310      bannerTopPosition += parseInt($('.toolbar-tray-horizontal.is-active').css('height'));
311    }
312
313    if ($('.toolbar-bar').length && !$('#gin-toolbar-bar').length) {
314      bannerTopPosition += parseInt($('.toolbar-bar').css('height'));
315    }
316
317    return bannerTopPosition + 'px';
318  }
319
320  Drupal.eu_cookie_compliance.getBannerTopHiddenPosition = function (height) {
321    let bannerTopPosition = 0;
322    if (drupalSettings.eu_cookie_compliance.fixed_top_position) {
323      bannerTopPosition = -height;
324    }
325    else {
326      if ($('.toolbar-tray-horizontal.is-active').length) {
327        bannerTopPosition = -parseInt($('.toolbar-tray-horizontal.is-active').css('height'));
328      }
329
330      if ($('.toolbar-bar').length && !$('#gin-toolbar-bar').length) {
331        bannerTopPosition -= parseInt($('.toolbar-bar').css('height'));
332      }
333    }
334
335    return bannerTopPosition + 'px';
336  }
337
338  Drupal.eu_cookie_compliance.getBannerBottomHiddenPosition = function () {
339    return -($('#sliding-popup').outerHeight()) + 'px';
340  }
341
342  Drupal.eu_cookie_compliance.toggleWithdrawBanner = function () {
343    var $wrapper = $('#sliding-popup');
344    var height = parseInt($wrapper.outerHeight());
345    var bannerIsShowing = ($wrapper.find('.eu-cookie-compliance-banner, .eu-cookie-withdraw-banner').is(':visible'));
346    if (bannerIsShowing) {
347      let bannerTop = parseInt($wrapper.css('top'));
348      let containerPadding = parseInt($(drupalSettings.eu_cookie_compliance.containing_element).css('padding-top'));
349      let containerMargin = parseInt($(drupalSettings.eu_cookie_compliance.containing_element).css('margin-top'));
350
351      if (drupalSettings.eu_cookie_compliance.popup_position) {
352        if (drupalSettings.eu_cookie_compliance.fixed_top_position) {
353          bannerIsShowing = !(bannerTop === -height);
354        }
355        else {
356          bannerIsShowing = !(bannerTop === -(containerPadding + containerMargin + he
356ight));
357        }
358      }
359      else {
360        bannerIsShowing = (parseInt($wrapper.css('bottom')) === 0);
361      }
362    }
363    if (drupalSettings.eu_cookie_compliance.popup_position) {
364      if (bannerIsShowing) {
365        if (!drupalSettings.eu_cookie_compliance.fixed_top_position) {
366          $('body').animate({ 'margin-top': -height + 'px' }, drupalSettings.eu_cookie_compliance.popup_delay);
367        }
368        $wrapper.animate({ top: Drupal.eu_cookie_compliance.getBannerTopHiddenPosition(height) }, drupalSettings.eu_cookie_compliance.popup_delay).trigger('eu_cookie_compliance_popup_close');
369      }
370      else {
371        // If "Do not show cookie policy when the user clicks the Cookie policy button." is
372        // selected, the inner banner may be hidden.
373        if (!drupalSettings.eu_cookie_compliance.fixed_top_position) {
374          $('body').animate({ 'margin-top': '0px' }, drupalSettings.eu_cookie_compliance.popup_delay);
375        }
376        $wrapper.find('.eu-cookie-compliance-banner').show();
377        $wrapper.animate({ top: Drupal.eu_cookie_compliance.getBannerTopPosition(height) }, drupalSettings.eu_cookie_compliance.popup_delay).trigger('eu_cookie_compliance_popup_open');
378      }
379    }
380    else {
381      if (bannerIsShowing) {
382        $wrapper.animate({ 'bottom': -1 * (height) }, drupalSettings.eu_cookie_compliance.popup_delay).trigger('eu_cookie_compliance_popup_close');
383      }
384      else {
385        // If "Do not show cookie policy when the user clicks the Cookie policy button." is
386        // selected, the inner banner may be hidden.
387        $wrapper.find('.eu-cookie-compliance-banner').show();
388        $wrapper.animate({ 'bottom': 0 }, drupalSettings.eu_cookie_compliance.popup_delay).trigger('eu_cookie_compliance_popup_open');
389      }
390    }
391    if (bannerIsShowing) {
392      $('body').removeClass('eu-cookie-compliance-popup-open');
393      $('.eu-cookie-compliance-banner, .eu-cookie-withdraw-banner')
394          .attr('aria-hidden', true)
395          .find('a, button, input')
396          .attr('tabindex', -1);
397    }
398    else {
399      $('body').addClass('eu-cookie-compliance-popup-open');
400      $('.eu-cookie-compliance-banner, .eu-cookie-withdraw-banner')
401          .attr('aria-hidden', false)
402          .find('a, button, input')
403          .attr('tabindex', 0);
404      // Always reset category checkboxes when opening popup.
405      Drupal.eu_cookie_compliance.setPreferenceCheckboxes(Drupal.eu_cookie_compliance.getAcceptedCategories());
406    }
407  };
408
409  Drupal.eu_cookie_compliance.resizeListener = function () {
410    var $wrapper = $('#sliding-popup');
411
412    var debounce = function (func, wait) {
413      var timeout;
414
415      return function executedFunction() {
416        var later = function () {
417          clearTimeout(timeout);
418          func();
419        };
420
421        clearTimeout(timeout);
422        timeout = setTimeout(later, wait);
423      };
424    };
425
426    var checkIfPopupIsClosed = debounce(function () {
427      var wrapperHeight = $wrapper.outerHeight();
428      if (drupalSettings.eu_cookie_compliance.popup_position) {
429        var wrapperTopProperty = parseFloat($wrapper.css('top'));
430        if (wrapperTopProperty < 0) {
431          if ($('body').hasClass('eu-cookie-compliance-popup-open')) {
432            if (!drupalSettings.eu_cookie_compliance.fixed_top_position) {
433              $('body').css({ 'margin-top': '0px' });
434            }
435            $wrapper.css('top', Drupal.eu_cookie_compliance.getBannerTopPosition(wrapperHeight));
436          }
437          else {
438            if (!drupalSettings.eu_cookie_compliance.fixed_top_position) {
439              $('body').css({ 'margin-top': -wrapperHeight + 'px' });
440            }
441            $wrapper.css('top', Drupal.eu_cookie_compliance.getBannerTopHiddenPosition(wrapperHeight));
442          }
443        }
444        Drupal.eu_cookie_compliance.positionTab();
445      }
446      else {
447        var wrapperBottomProperty = parseFloat($wrapper.css('bottom'));
448        if (wrapperBottomProperty !== 0) {
449          $wrapper.css('bottom', wrapperHeight * -1);
450        }
451      }
452      Drupal.eu_cookie_compliance.positionTab();
453    }, 50);
454
455    setTimeout(function () {
456      checkIfPopupIsClosed();
457    });
458
459    window.addEventListener('resize', checkIfPopupIsClosed);
460  };
461
462  Drupal.eu_cookie_compliance.createPopup = function (html, closed) {
463    // This fixes a problem with jQuery 1.9.
464    var popup = $('<div></div>').html(html);
465    popup.attr({
466      'id': 'sliding-popup',
467      'role': 'alertdialog',
468      'aria-describedby': 'popup-text',
469      'aria-label': Drupal.t('Cookie compliance banner'),
470    });
471    if (!drupalSettings.eu_cookie_compliance.popup_use_bare_css && !drupalSettings.eu_cookie_compliance.popup_use_olivero_css) {
472      popup.height(drupalSettings.eu_cookie_compliance.popup_height)
473          .width(drupalSettings.eu_cookie_compliance.popup_width);
474    }
475
476    popup.hide();
477    var height = 0;
478    if (drupalSettings.eu_cookie_compliance.popup_position) {
479      popup.prependTo(drupalSettings.eu_cookie_compliance.containing_element);
480      height = popup.outerHeight();
481      popup.addClass('sliding-popup-top clearfix')
482        .css({ top: Drupal.eu_cookie_compliance.getBannerTopHiddenPosition(height) });
483
484      if (closed !== true) {
485        popup.show();
486        popup.animate({top: Drupal.eu_cookie_compliance.getBannerTopPosition(height)}, drupalSettings.eu_cookie_compliance.popup_delay, null, function () {
487          popup.trigger('eu_cookie_compliance_popup_open');
488          Drupal.eu_cookie_compliance.positionTab();
489        });
490      }
491      else {
492        if (!drupalSettings.eu_cookie_compliance.fixed_top_position) {
493          $('body').css({ 'margin-top': -height + 'px' });
494        }
495        setTimeout(function () {
496          popup.show();
497          Drupal.eu_cookie_compliance.positionTab();
498        }, 0);
499      }
500    }
501    else {
502      if (drupalSettings.eu_cookie_compliance.better_support_for_screen_readers) {
503        popup.prependTo(drupalSettings.eu_cookie_compliance.containing_element);
504      }
505      else {
506        popup.appendTo(drupalSettings.eu_cookie_compliance.containing_element);
507      }
508
509      height = popup.outerHeight();
510      popup.show()
511        .addClass('sliding-popup-bottom')
512        .css({bottom: -1 * height});
513
514      if (closed !== true) {
515        popup.animate({bottom: 0}, drupalSettings.eu_cookie_compliance.popup_delay, null, function () {
516          popup.trigger('eu_cookie_compliance_popup_open');
517        });
518      }
519    }
520    if (closed !== true) {
521      $('body').addClass('eu-cookie-compliance-popup-open');
522      $('.eu-cookie-compliance-banner, .eu-cookie-withdraw-banner')
523          .attr('aria-hidden', false)
524          .find('a, button, input')
525          .attr('tabindex', 0);
526    }
527    else {
528      $('body').removeClass('eu-cookie-compliance-popup-open');
529      $('.eu-cookie-compliance-banner, .eu-cookie-withdraw-banner')
530          .attr('aria-hidden', true)
531          .find('a, button, input')
532          .attr('tabindex', -1);
533    }
534  };
535
536  Drupal.eu_cookie_compliance.attachAgreeEvents = function () {
537    var clickingConfirms = drupalSettings.eu_cookie_compliance.popup_clicking_confirmation;
538    var scrollConfirms = drupalSettings.eu_cookie_compliance.popup_scrolling_confirmation;
539
540    if (drupalSettings.eu_cookie_compliance.method === 'categories' && drupalSettings.eu_cookie_compliance.enable_save_preferences_button) {
541        // The agree button becomes an agree to all categories button when the 'save preferences' button is present.
542        $('.agree-button').click(Drupal.eu_cookie_compliance.acceptAllAction);
543    }
544    else {
545        $('.agree-button').click(Drupal.eu_cookie_compliance.acceptAction);
546    }
547    $('.decline-button').click(Drupal.eu_cookie_compliance.declineAction);
548    $('.eu-cookie-compliance-close-button').click(Drupal.eu_cookie_compliance.closeAction);
549    $('.eu-cookie-compliance-reject-button').click(Drupal.eu_cookie_compliance.rejectAllAction);
550
551    if (clickingConfirms) {
552      $('a, input[type=submit], button[type=submit]').not('.popup-content *').bind('click.euCookieCompliance', Drupal.eu_cookie_compliance.acceptAction);
553    }
554
555    if (scrollConfirms) {
556      var alreadyScrolled = false;
557      var scrollHandler = function () {
558        if (alreadyScrolled) {
559          Drupal.eu_cookie_compliance.acceptAction();
560          $(window).off('scroll', scrollHandler);
561        }
562        else {
563          alreadyScrolled = true;
564        }
565      };
566
567      $(window).bind('scroll', scrollHandler);
568    }
569
570    $('.find-more-button').not('.find-more-button-processed').addClass('find-more-button-processed').click(Drupal.eu_cookie_compliance.moreInfoAction);
571  };
572
573  Drupal.eu_cookie_compliance.closeAction = function () {
574    switch (drupalSettings.eu_cookie_compliance.close_button_action) {
575      case 'close_banner':
576        Drupal.eu_cookie_compliance.toggleWithdrawBanner();
577        break;
578
579      case 'save_preferences':
580        Drupal.eu_cookie_compliance.savePreferencesAction();
581        break;
582
583      case 'reject_all_cookies':
584        Drupal.eu_cookie_compliance.rejectAllAction();
585        break;
586
587      case 'accept_all_cookies':
588        Drupal.eu_cookie_compliance.acceptAllAction();
589        break;
590    }
591  };
592
593  Drupal.eu_cookie_compliance.attachSavePreferencesEvents = function () {
594    $('.eu-cookie-compliance-save-preferences-button').click(Drupal.eu_cookie_compliance.savePreferencesAction);
595  };
596
597  Drupal.eu_cookie_compliance.attachHideEvents = function () {
598    var popupHideAgreed = drupalSettings.eu_cookie_compliance.popup_hide_agreed;
599    var clickingConfirms = drupalSettings.eu_cookie_compliance.popup_clicking_confirmation;
600    $('.hide-popup-button').click(function () {
601          Drupal.eu_cookie_compliance.changeStatus(cookieValueAgreed);
602        }
603    );
604    if (clickingConfirms) {
605      $('a, input[type=submit], button[type=submit]').unbind('click.euCookieCompliance');
606    }
607
608    if (popupHideAgreed) {
609      $('a, input[type=submit], button[type=submit]').bind('click.euCookieComplianceHideAgreed', function () {
610        Drupal.eu_cookie_compliance.changeStatus(cookieValueAgreed);
611      });
612    }
613
614    $('.find-more-button').not('.find-more-button-processed').addClass('find-more-button-processed').click(Drupal.eu_cookie_compliance.moreInfoAction);
615  };
616
617  Drupal.eu_cookie_compliance.attachWithdrawEvents = function () {
618    $('.eu-cookie-withdraw-button').click(Drupal.eu_cookie_compliance.withdrawAction);
619    // Attach withdraw event only once, in initial execute function. Prevents duplicating ecvents.
620    // $('.eu-cookie-withdraw-tab').click(Drupal.eu_cookie_compliance.toggleWithdrawBanner);
621  };
622
623  Drupal.eu_cookie_compliance.acceptAction = function () {
624    var agreedEnabled = drupalSettings.eu_cookie_compliance.popup_agreed_enabled;
625    var nextStatus = cookieValueAgreedShowThankYou;
626    if (!agreedEnabled) {
627      Drupal.eu_cookie_compliance.setStatus(cookieValueAgreedShowThankYou);
628      nextStatus = cookieValueAgreed;
629    }
630
631    if (!euCookieComplianceHasLoadedScripts) {
632      Drupal.eu_cookie_compliance.loadScripts();
633    }
634
635    if (typeof euCookieComplianceBlockCookies !== 'undefined') {
636      clearInterval(euCookieComplianceBlockCookies);
637    }
638
639    if (drupalSettings.eu_cookie_compliance.method === 'categories') {
640      // Select Checked categories.
641      var categories = $("#eu-cookie-compliance-categories input:checkbox:checked").map(function () {
642        return $(this).val();
643      }).get();
644      Drupal.eu_cookie_compliance.setAcceptedCategories(categories);
645      // Load scripts for all categories. If no categories selected, none
646      // will be loaded.
647      Drupal.eu_cookie_compliance.loadCategoryScripts(categories);
648      if (!categories.length) {
649        // No categories selected is the same as declining all cookies.
650        nextStatus = cookieValueDisagreed;
651      }
652    }
653
654    Drupal.eu_cookie_compliance.changeStatus(nextStatus);
655
656    if (drupalSettings.eu_cookie_compliance.withdraw_enabled && drupalSettings.eu_cookie_compliance.withdraw_button_on_info_popup) {
657      Drupal.eu_cookie_compliance.attachWithdrawEvents();
658      if (_euccCurrentStatus === cookieValueAgreedShowThankYou || _euccCurrentStatus === cookieValueAgreed) {
659        $('.eu-cookie-withdraw-button').removeClass('visually-hidden');
660        $('.eu-cookie-compliance-reject-button').addClass('visually-hidden');
661      }
662    }
663  };
664
665  Drupal.eu_cookie_compliance.acceptAllAction = function () {
666    var allCategories = drupalSettings.eu_cookie_compliance.cookie_categories;
667    Drupal.eu_cookie_compliance.setPreferenceCheckboxes(allCategories);
668    Drupal.eu_cookie_compliance.acceptAction();
669  }
670
671  Drupal.eu_cookie_compliance.rejectAllAction = function () {
672    Drupal.eu_cookie_compliance.setStatus(cookieValueDisagreed);
673    Drupal.eu_cookie_compliance.setPreferenceCheckboxes([]);
674    Drupal.eu_cookie_compliance.acceptAction();
675  }
676
677  Drupal.eu_cookie_compliance.savePreferencesAction = function () {
678    var categories = $("#eu-cookie-compliance-categories input:checkbox:checked").map(function () {
679      return $(this).val();
680    }).get();
681    var agreedEnabled = drupalSettings.eu_cookie_compliance.popup_agreed_enabled;
682    var nextStatus = cookieValueAgreedShowThankYou;
683    if (!agreedEnabled) {
684      Drupal.eu_cookie_compliance.setStatus(cookieValueAgreedShowThankYou);
685      nextStatus = cookieValueAgreed;
686    }
687
688    /* Necessary to keep the euCookieComplianceLoadScripts() load order consistent on page load. */
689    if (!euCookieComplianceHasLoadedScripts) {
690      Drupal.eu_cookie_compliance.loadScripts();
691    }
692    euCookieComplianceHasLoadedScripts = true;
693
694    Drupal.eu_cookie_compliance.setAcceptedCategories(categories);
695    // Load scripts for all categories. If no categories selected, none
696    // will be loaded.
697    Drupal.eu_cookie_compliance.loadCategoryScripts(categories);
698    if (!categories.length) {
699      // No categories selected is the same as declining all cookies.
700      nextStatus = cookieValueDisagreed;
701    }
702
703    Drupal.eu_cookie_compliance.changeStatus(nextStatus);
704  };
705
706  Drupal.eu_cookie_compliance.loadCategoryScripts = function (categories) {
707    for (var cat in categories) {
708      if (euCookieComplianceHasLoadedScriptsForCategory[categories[cat]] !== true) {
709        Drupal.eu_cookie_compliance.loadScripts(categories[cat]);
710        euCookieComplianceHasLoadedScriptsForCategory[categories[cat]] = true;
711      }
712    }
713  }
714
715  Drupal.eu_cookie_compliance.loadScripts = function (category) {
716    if (category !== undefined && drupalSettings.eu_cookie_compliance.disabled_javascripts !== undefined && drupalSettings.eu_cookie_compliance.disabled_javascripts[category] !== undefined) {
717      drupalSettings.eu_cookie_compliance.disabled_javascripts[category].forEach(function (item, index) {
718        var scriptTag = document.createElement("script");
719        scriptTag.src = item;
720        document.body.appendChild(scriptTag);
721      });
722    }
723  }
724
725  Drupal.eu_cookie_compliance.declineAction = function () {
726    var set_cookie_session_zero_on_disagree = parseInt(drupalSettings.eu_cookie_compliance.set_cookie_session_zero_on_disagree);
727    if (set_cookie_session_zero_on_disagree) {
728      drupalSettings.eu_cookie_compliance.cookie_session = 1;
729    }
730    Drupal.eu_cookie_compliance.setStatus(cookieValueDisagreed);
731    var popup = $('#sliding-popup');
732    if (popup.hasClass('sliding-popup-top')) {
733      let height = popup.outerHeight();
734      if (!drupalSettings.eu_cookie_compliance.fixed_top_position) {
735        $('body').animate({ 'margin-top': -height + 'px' }, drupalSettings.eu_cookie_compliance.popup_delay);
736      }
737      if (drupalSettings.eu_cookie_compliance.settings_tab_enabled) {
738        popup.animate({top: Drupal.eu_cookie_compliance.getBannerTopHiddenPosition(height)}, drupalSettings.eu_cookie_compliance.popup_delay, null).trigger('eu_cookie_compliance_popup_close');
739      }
740      else {
741        popup.animate({top: Drupal.eu_cookie_compliance.getBannerTopHiddenPosition(height)}, drupalSettings.eu_cookie_compliance.popup_delay, null, function () {
742          if (!drupalSettings.eu_cookie_compliance.fixed_top_position) {
743            $('body').css({ 'margin-top': 0 });
744          }
745          popup.hide();
746        }).trigger('eu_cookie_compliance_popup_close');
747      }
748    }
749    else {
750      if (drupalSettings.eu_cookie_compliance.settings_tab_enabled) {
751        popup.animate({ bottom: popup.outerHeight() * -1 }, drupalSettings.eu_cookie_compliance.popup_delay, null).trigger('eu_cookie_compliance_popup_close');
752      }
753      else {
754        popup.animate({ bottom: popup.outerHeight() * -1 }, drupalSettings.eu_cookie_compliance.popup_delay, null, function () {
755          popup.hide();
756        }).trigger('eu_cookie_compliance_popup_close');
757      }
758    }
759    $('body').removeClass('eu-cookie-compliance-popup-open');
760    $('.eu-cookie-compliance-banner, .eu-cookie-withdraw-banner')
761        .attr('aria-hidden', true)
762        .find('a, button, input')
763        .attr('tabindex', -1);
764  };
765
766  Drupal.eu_cookie_compliance.withdrawAction = function () {
767    var set_cookie_session_zero_on_disagree = parseInt(drupalSettings.eu_cookie_compliance.set_cookie_session_zero_on_disagree);
768    if (set_cookie_session_zero_on_disagree) {
769      drupalSettings.eu_cookie_compliance.cookie_session = 1;
770    }
771    Drupal.eu_cookie_compliance.setStatus(null);
772    Drupal.eu_cookie_compliance.setAcceptedCategories([]);
773    location.reload();
774  };
775
776  Drupal.eu_cookie_compliance.moreInfoAction = function () {
777    if (drupalSettings.eu_cookie_compliance.disagree_do_not_show_popup) {
778      Drupal.eu_cookie_compliance.setStatus(cookieValueDisagreed);
779      if (drupalSettings.eu_cookie_compliance.withdraw_enabled && drupalSettings.eu_cookie_compliance.withdraw_button_on_info_popup) {
780        $('#sliding-popup .eu-cookie-compliance-banner').trigger('eu_cookie_compliance_popup_close').hide();
781      }
782      else {
783        $('#sliding-popup').trigger('eu_cookie_compliance_popup_close').remove();
784      }
785      $('body').removeClass('eu-cookie-compliance-popup-open');
786      $('.eu-cookie-compliance-banner, .eu-cookie-withdraw-banner')
787          .attr('aria-hidden', true)
788          .find('a, button, input')
789          .attr('tabindex', -1);
790    }
791    else {
792      if (drupalSettings.eu_cookie_compliance.popup_link_new_window) {
793        window.open(drupalSettings.eu_cookie_compliance.popup_link);
794      }
795      else {
796        window.location.href = drupalSettings.eu_cookie_compliance.popup_link;
797      }
798    }
799  };
800
801  Drupal.eu_cookie_compliance.getCookieStatus = function () {
802    var cookieName = (typeof drupalSettings.eu_cookie_compliance.cookie_name === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_name === '') ? 'cookie-agreed' : drupalSettings.eu_cookie_compliance.cookie_name;
803    var currentStatus = getCookie(cookieName);
804    if (typeof currentStatus === 'undefined' || currentStatus === 'null') {
805      currentStatus = null;
806    }
807    return currentStatus;
808  }
809
810  Drupal.eu_cookie_compliance.getCurrentStatus = function () {
811    // Make a new observer & fire it to allow other scripts to hook in.
812    var preStatusLoadObject = new PreStatusLoad();
813    self.handleEvent('preStatusLoad', preStatusLoadObject);
814
815    _euccCurrentStatus = Drupal.eu_cookie_compliance.getCookieStatus();
816
817    // Make a new observer & fire it to allow other scripts to hook in.
818    var postStatusLoadObject = new PostStatusLoad();
819    self.handleEvent('postStatusLoad', postStatusLoadObject);
820
821    return _euccCurrentStatus;
822  };
823
824  Drupal.eu_cookie_compliance.setPreferenceCheckboxes = function (categories) {
825    // Unset all categories to prevent a problem where the checkboxes with a
826    // default state set would always show up as checked.
827    $("#eu-cookie-compliance-categories input:checkbox").not(":disabled").prop("checked", false);
828    // Check the appropriate checkboxes.
829    for (var i in categories) {
830      var categoryElement = document.getElementById('cookie-category-' + categories[i]);
831      if (categoryElement !== null) {
832        categoryElement.checked = true;
833      }
834    }
835  }
836
837  Drupal.eu_cookie_compliance.getAcceptedCategories = function () {
838    // Make a new observer & fire it to allow other scripts to hook in.
839    var prePreferencesLoadObject = new PrePreferencesLoad();
840    self.handleEvent('prePreferencesLoad', prePreferencesLoadObject);
841
842    var cookieName = (typeof drupalSettings.eu_cookie_compliance.cookie_name === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_name === '') ? 'cookie-agreed-categories' : drupalSettings.eu_cookie_compliance.cookie_name + '-categories';
843    var storedCategories = getCookie(cookieName);
844
845    if (storedCategories !== null && typeof storedCategories !== 'undefined') {
846      // JS cookie introduced unescaped cookie values.
847      if (storedCategories.indexOf('%') !== -1) {
848        storedCategories = decodeURI(storedCategories).replaceAll(/%2C/g, ',');
849      }
850      _euccSelectedCategories = JSON.parse(storedCategories);
851    }
852    else {
853      _euccSelectedCategories = [];
854    }
855
856    // Merge in required categories if not already present. Mimics old
857    // logic where "fix first category" changed logic in
858    // .hasAgreedWithCategory and this function.
859    for (var _categoryName in drupalSettings.eu_cookie_compliance.cookie_categories_details) {
860      var _category = drupalSettings.eu_cookie_compliance.cookie_categories_details[_categoryName];
861      if (_category.checkbox_default_state === 'required' && $.inArray(_category.id, _euccSelectedCategories) === -1) {
862        _euccSelectedCategories.push(_category.id);
863      }
864    }
865
866    // Make a new observer & fire it to allow other scripts to hook in.
867    var postPreferencesLoadObject = new PostPreferencesLoad();
868    self.handleEvent('postPreferencesLoad', postPreferencesLoadObject);
869
870    return _euccSelectedCategories;
871  };
872
873  Drupal.eu_cookie_compliance.changeStatus = function (value) {
874    var reloadPage = drupalSettings.eu_cookie_compliance.reload_page;
875    var previousState = _euccCurrentStatus;
876    if (_euccCurrentStatus === parseInt(value)) {
877      return;
878    }
879
880    if (drupalSettings.eu_cookie_compliance.popup_position) {
881      let height = $('#sliding-popup').outerHeight();
882      if (!drupalSettings.eu_cookie_compliance.fixed_top_position) {
883        $('body').animate({ 'margin-top': -height + 'px' }, drupalSettings.eu_cookie_compliance.popup_delay);
884      }
885      $('.sliding-popup-top').animate({ top: Drupal.eu_cookie_compliance.getBannerTopHiddenPosition(height) }, drupalSettings.eu_cookie_compliance.popup_delay, function () {
886        if (value === cookieValueAgreedShowThankYou && previousState === null && !reloadPage) {
887          if (!drupalSettings.eu_cookie_compliance.fixed_top_position) {
888            $('body').animate({ 'margin-top': '0px' }, drupalSettings.eu_cookie_compliance.popup_delay);
889          }
890          $('.sliding-popup-top').not('.eu-cookie-withdraw-wrapper').html(drupalSettings.eu_cookie_compliance.popup_html_agreed).animate({ top: Drupal.eu_cookie_compliance.getBannerTopPosition(height) }, drupalSettings.eu_cookie_compliance.popup_delay);
891          Drupal.eu_cookie_compliance.attachHideEvents();
892        }
893        else if (previousState === cookieValueAgreedShowThankYou) {
894          if (drupalSettings.eu_cookie_compliance.withdraw_enabled && drupalSettings.eu_cookie_compliance.withdraw_button_on_info_popup) {
895            $('#sliding-popup').hide();
896            // Restore popup content.
897            if (window.matchMedia('(max-width: ' + drupalSettings.eu_cookie_compliance.mobile_breakpoint + 'px)').matches && drupalSettings.eu_cookie_compliance.use_mobile_message) {
898              $('.sliding-popup-top').not('.eu-cookie-withdraw-wrapper').html(drupalSettings.eu_cookie_compliance.mobile_popup_html_info);
899            }
900            else {
901              $('.sliding-popup-top').not('.eu-cookie-withdraw-wrapper').html(drupalSettings.eu_cookie_compliance.popup_html_info);
902            }
903            height = $('#sliding-popup').outerHeight();
904            if (!drupalSettings.eu_cookie_compliance.fixed_top_position) {
905              $('body').animate({ 'margin-top': -height + 'px' }, drupalSettings.eu_cookie_compliance.popup_delay);
906            }
907            $('.sliding-popup-top').css('top', Drupal.eu_cookie_compliance.getBannerTopHiddenPosition(height));
908            $('.sliding-popup-top').not('.eu-cookie-withdraw-wrapper').trigger('eu_cookie_compliance_popup_close');
909            Drupal.eu_cookie_compliance.initPopup();
910            Drupal.eu_cookie_compliance.resizeListener();
911            $('#sliding-popup').show();
912          }
913          else {
914            $('.sliding-popup-top').not('.eu-cookie-withdraw-wrapper').trigger('eu_cookie_compliance_popup_close').remove();
915            $('body').css({ 'margin-top': '0px' });
916          }
917          $('body').removeClass('eu-cookie-compliance-popup-open');
918          $('.eu-cookie-compliance-banner, .eu-cookie-withdraw-banner')
919              .attr('aria-hidden', true)
920              .find('a, button, input')
921              .attr('tabindex', -1);
922        }
923        if (drupalSettings.eu_cookie_compliance.withdraw_enabled && !drupalSettings.eu_cookie_compliance.withdraw_button_on_info_popup) {
924          Drupal.eu_cookie_compliance.showWithdrawBanner(value);
925        }
926      });
927    }
928    else {
929      $('.sliding-popup-bottom').animate({ bottom: $('#sliding-popup').outerHeight() * -1 }, drupalSettings.eu_cookie_compliance.popup_delay, function () {
930        if (value === cookieValueAgreedShowThankYou && previousState === null && !reloadPage) {
931          $('.sliding-popup-bottom').not('.eu-cookie-withdraw-wrapper').html(drupalSettings.eu_cookie_compliance.popup_html_agreed).animate({ bottom: 0 }, drupalSettings.eu_cookie_compliance.popup_delay);
932          Drupal.eu_cookie_compliance.attachHideEvents();
933        }
934        else if (previousState === cookieValueAgreedShowThankYou) {
935          $('#sliding-popup').css('display', 'none');
936          if (drupalSettings.eu_cookie_compliance.withdraw_enabled && drupalSettings.eu_cookie_compliance.withdraw_button_on_info_popup) {
937            // Restore popup content.
938            if (window.matchMedia('(max-width: ' + drupalSettings.eu_cookie_compliance.mobile_breakpoint + 'px)').matches && drupalSettings.eu_cookie_compliance.use_mobile_message) {
939              $('.sliding-popup-bottom').not('.eu-cookie-withdraw-wrapper').html(drupalSettings.eu_cookie_compliance.mobile_popup_html_info);
940            }
941            else {
942              $('.sliding-popup-bottom').not('.eu-cookie-withdraw-wrapper').html(drupalSettings.eu_cookie_compliance.popup_html_info);
943            }
944            $('.sliding-popup-bottom').css('bottom', Drupal.eu_cookie_compliance.getBannerBottomHiddenPosition());
945            $('.sliding-popup-bottom').not('.eu-cookie-withdraw-wrapper').trigger('eu_cookie_compliance_popup_close');
946            Drupal.eu_cookie_compliance.initPopup();
947            Drupal.eu_cookie_compliance.resizeListener();
948            $('#sliding-popup').css('display', 'block');
949          }
950          else {
951            $('.sliding-popup-bottom').not('.eu-cookie-withdraw-wrapper').trigger('eu_cookie_compliance_popup_close').remove();
952          }
953          $('body').removeClass('eu-cookie-compliance-popup-open');
954          $('.eu-cookie-compliance-banner, .eu-cookie-withdraw-banner')
955              .attr('aria-hidden', true)
956              .find('a, button, input')
957              .attr('tabindex', -1);
958        }
959        if (drupalSettings.eu_cookie_compliance.withdraw_enabled && !drupalSettings.eu_cookie_compliance.withdraw_button_on_info_popup) {
960          Drupal.eu_cookie_compliance.showWithdrawBanner(value);
961        }
962      });
963    }
964
965    if (drupalSettings.eu_cookie_compliance.reload_page) {
966      var reloadRoutesList;
967      // Checks if there's any route on the settings.
968      if ((reloadRoutesList = drupalSettings.eu_cookie_compliance.reload_routes_list).length !== 0) {
969        var currentPath = drupalSettings.path.currentPath;
970        var match = false;
971
972        // If there are routes specified on the settings, it checks if any of
973        // it matches with the current path.
974        for (var n = 0; !match && n < reloadRoutesList.length; n++) {
975          var regExp = new RegExp(reloadRoutesList[n], "g");
976          match = currentPath.match(regExp) !== null;
977        }
978
979        /*
980         * It will reload the page whether if the current path matches with one of the specified routes and the
981         * reload_options setting is set to "Include", which indicates that all matches should reload; OR if
982         * there's no match and the reload_options settings is set to "Exclude", which indicates that if the
983         * current path doesn't match with one of the specified routes, it should be reloaded.
984         */
985        if ((match && !drupalSettings.eu_cookie_compliance.reload_options) || (!match && drupalSettings.eu_cookie_compliance.reload_options)) {
986          location.reload();
987        }
988      }
989      // If no routes specified, then the page will be always reloaded.
990      else {
991        location.reload();
992      }
993    }
994
995    Drupal.eu_cookie_compliance.setStatus(value);
996  };
997
998  Drupal.eu_cookie_compliance.showWithdrawBanner = function (value) {
999    if (value === cookieValueAgreed && drupalSettings.eu_cookie_compliance.withdraw_enabled) {
1000      if (!drupalSettings.eu_cookie_compliance.withdraw_button_on_info_popup) {
1001        Drupal.eu_cookie_compliance.createWithdrawBanner(drupalSettings.eu_cookie_compliance.withdraw_markup);
1002        Drupal.eu_cookie_compliance.resizeListener();
1003      }
1004      Drupal.eu_cookie_compliance.attachWithdrawEvents();
1005      if (drupalSettings.eu_cookie_compliance.popup_position) {
1006        Drupal.eu_cookie_compliance.positionTab();
1007      }
1008    }
1009  };
1010
1011  Drupal.eu_cookie_compliance.setStatus = function (status) {
1012    // Make a new observer & fire it to allow other scripts to hook in.
1013    var preStatusSaveObject = new PreStatusSave();
1014    self.handleEvent('preStatusSave', preStatusSaveObject);
1015
1016    var date = new Date();
1017    var domain = drupalSettings.eu_cookie_compliance.domain ? drupalSettings.eu_cookie_compliance.domain : '';
1018    var path = drupalSettings.eu_cookie_compliance.domain_all_sites ? '/' : drupalSettings.path.baseUrl;
1019    var cookieName = (typeof drupalSettings.eu_cookie_compliance.cookie_name === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_name === '') ? 'cookie-agreed' : drupalSettings.eu_cookie_compliance.cookie_name;
1020    if (path.length > 1) {
1021      var pathEnd = path.length - 1;
1022      if (path.lastIndexOf('/') === pathEnd) {
1023        path = path.substring(0, pathEnd);
1024      }
1025    }
1026
1027    var cookie_session = parseInt(drupalSettings.eu_cookie_compliance.cookie_session);
1028    if (cookie_session) {
1029      setCookie(cookieName, status, { path: path, domain: domain, sameSite: 'strict' });
1030    }
1031    else {
1032      var lifetime = parseInt(drupalSettings.eu_cookie_compliance.cookie_lifetime);
1033      date.setDate(date.getDate() + lifetime);
1034      setCookie(cookieName, status, { expires: date, path: path, domain: domain, sameSite: 'strict' });
1035    }
1036
1037    var currentStatusClass = 'eu-cookie-compliance-status-' + _euccCurrentStatus;
1038    var nextStatusClass = 'eu-cookie-compliance-status-' + status;
1039    $('.' + currentStatusClass).removeClass(currentStatusClass).addClass(nextStatusClass)
1040
1041    _euccCurrentStatus = status;
1042    $(document).trigger('eu_cookie_compliance.changeStatus', [status]);
1043    // Status set means something happened, update the version.
1044    Drupal.eu_cookie_compliance.setVersion();
1045
1046    // Store consent if applicable.
1047    if (drupalSettings.eu_cookie_compliance.store_consent && ((status === cookieValueAgreedShowThankYou && drupalSettings.eu_cookie_compliance.popup_agreed_enabled) || (status === cookieValueAgreed  && !drupalSettings.eu_cookie_compliance.popup_agreed_enabled))) {
1048      var url = drupalSettings.path.baseUrl + drupalSettings.path.pathPrefix + 'eu-cookie-compliance/store_consent/banner';
1049      $.post(url, {}, function (data) { });
1050    }
1051
1052    // Make a new observer & fire it to allow other scripts to hook in.
1053    var postStatusSaveObject = new PostStatusSave();
1054    self.handleEvent('postStatusSave', postStatusSaveObject);
1055
1056    if (status === cookieValueDisagreed && drupalSettings.eu_cookie_compliance.method === 'opt_out') {
1057      euCookieComplianceBlockCookies = setInterval(Drupal.eu_cookie_compliance.BlockCookies, 5000);
1058    }
1059  };
1060
1061  Drupal.eu_cookie_compliance.setAcceptedCategories = function (categories) {
1062    // Make a new observer & fire it to allow other scripts to hook in.
1063    var prePreferencesSaveObject = new PrePreferencesSave();
1064    self.handleEvent('prePreferencesSave', prePreferencesSaveObject);
1065
1066    var date = new Date();
1067    var domain = drupalSettings.eu_cookie_compliance.domain ? drupalSettings.eu_cookie_compliance.domain : '';
1068    var path = drupalSettings.eu_cookie_compliance.domain_all_sites ? '/' : drupalSettings.path.baseUrl;
1069    var cookieName = (typeof drupalSettings.eu_cookie_compliance.cookie_name === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_name === '') ? 'cookie-agreed-categories' : drupalSettings.eu_cookie_compliance.cookie_name + '-categories';
1070    if (path.length > 1) {
1071      var pathEnd = path.length - 1;
1072      if (path.lastIndexOf('/') === pathEnd) {
1073        path = path.substring(0, pathEnd);
1074      }
1075    }
1076    var categoriesString = JSON.stringify(categories);
1077    var cookie_session = parseInt(drupalSettings.eu_cookie_compliance.cookie_session);
1078    if (cookie_session) {
1079      setCookie(cookieName, categoriesString, { path: path, domain: domain, sameSite: 'strict' });
1080    }
1081    else {
1082      var lifetime = parseInt(drupalSettings.eu_cookie_compliance.cookie_lifetime);
1083      date.setDate(date.getDate() + lifetime);
1084      setCookie(cookieName, categoriesString, { expires: date, path: path, domain: domain, sameSite: 'strict' });
1085    }
1086    _euccSelectedCategories = categories;
1087    $(document).trigger('eu_cookie_compliance.changePreferences', [categories]);
1088
1089    // TODO: Store categories with consent if applicable?
1090    // Make a new observer & fire it to allow other scripts to hook in.
1091    var postPreferencesSaveObject = new PostPreferencesSave();
1092    self.handleEvent('postPreferencesSave', postPreferencesSaveObject);
1093  };
1094
1095  Drupal.eu_cookie_compliance.hasAgreed = function (category) {
1096    var agreed = (_euccCurrentStatus === cookieValueAgreedShowThankYou || _euccCurrentStatus === cookieValueAgreed);
1097
1098    if (category !== undefined && agreed && drupalSettings.eu_cookie_compliance.method === 'categories') {
1099      agreed = Drupal.eu_cookie_compliance.hasAgreedWithCategory(category);
1100    }
1101
1102    return agreed;
1103  };
1104
1105  Drupal.eu_cookie_compliance.hasAgreedWithCategory = function (category) {
1106    return $.inArray(category, _euccSelectedCategories) !== -1;
1107  };
1108
1109  Drupal.eu_cookie_compliance.showBanner = function () {
1110    var showBanner = false;
1111    if ((_euccCurrentStatus === cookieValueDisagreed && drupalSettings.eu_cookie_compliance.method === 'default') || _euccCurrentStatus === null) {
1112      if (!drupalSettings.eu_cookie_compliance.disagree_do_not_show_popup || _euccCurrentStatus === null) {
1113        showBanner = true;
1114      }
1115    }
1116    else if (_euccCurrentStatus === cookieValueAgreedShowThankYou && drupalSettings.eu_cookie_compliance.popup_agreed_enabled) {
1117      showBanner = true;
1118    }
1119    else if (_euccCurrentStatus === cookieValueAgreed && drupalSettings.eu_cookie_compliance.withdraw_enabled) {
1120      showBanner = true;
1121    }
1122
1123    return showBanner;
1124  };
1125
1126  Drupal.eu_cookie_compliance.cookiesEnabled = function () {
1127    var cookieEnabled = (navigator.cookieEnabled);
1128    if (typeof navigator.cookieEnabled === 'undefined' && !cookieEnabled) {
1129      date.setDate(date.getDate() + 100);
1130      setCookie('testcookie', 'testcookie', { expires: date, sameSite: 'strict' });
1131      cookieEnabled = (getCookie('testcookie').indexOf('testcookie') !== -1);
1132    }
1133
1134    return (cookieEnabled);
1135  };
1136
1137  Drupal.eu_cookie_compliance.cookieMatches = function (cookieName, pattern) {
1138    if (cookieName === pattern) {
1139      return true;
1140    }
1141    if (pattern.indexOf('*') < 0) {
1142      return false;
1143    }
1144    try {
1145      var regexp = new RegExp('^' + pattern.replace(/\./g, '\\.').replace(/\*/g, '.+') + '$', 'g');
1146      return regexp.test(cookieName);
1147    }
1148    catch (err) {
1149      return false;
1150    }
1151  };
1152
1153  Drupal.eu_cookie_compliance.isAllowed = function (cookieName) {
1154    // Skip the PHP session cookie.
1155    if (cookieName.indexOf('SESS') === 0 || cookieName.indexOf('SSESS') === 0) {
1156      return true;
1157    }
1158    // Split the allowed cookies.
1159    var euCookieComplianceAllowlist = drupalSettings.eu_cookie_compliance.allowed_cookies.split(/\r\n|\n|\r/g);
1160
1161    // Add the EU Cookie Compliance cookie.
1162    euCookieComplianceAllowlist.push((typeof drupalSettings.eu_cookie_compliance.cookie_name === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_name === '') ? 'cookie-agreed' : drupalSettings.eu_cookie_compliance.cookie_name);
1163    euCookieComplianceAllowlist.push((typeof drupalSettings.eu_cookie_compliance.cookie_name === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_name === '') ? 'cookie-agreed-categories' : drupalSettings.eu_cookie_compliance.cookie_name + '-categories');
1164    euCookieComplianceAllowlist.push((typeof drupalSettings.eu_cookie_compliance.cookie_name === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_name === '') ? 'cookie-agreed-version' : drupalSettings.eu_cookie_compliance.cookie_name + '-version');
1165    // Check if the cookie is allowed.
1166    for (var item in euCookieComplianceAllowlist) {
1167      // Defensively check types for comparison.
1168      if (typeof euCookieComplianceAllowlist[item] === "string") {
1169        if (Drupal.eu_cookie_compliance.cookieMatches(cookieName, euCookieComplianceAllowlist[item])) {
1170          return true;
1171        }
1172        // Handle cookie names that are prefixed with a category.
1173        if (drupalSettings.eu_cookie_compliance.method === 'categories') {
1174          var separatorPos = euCookieComplianceAllowlist[item].indexOf(":");
1175          if (separatorPos !== -1) {
1176            var category = euCookieComplianceAllowlist[item].substr(0, separatorPos);
1177            var wlCookieName = euCookieComplianceAllowlist[item].substr(separatorPos + 1);
1178
1179            if (Drupal.eu_cookie_compliance.cookieMatches(cookieName, wlCookieName) && Drupal.eu_cookie_compliance.hasAgreedWithCategory(category)) {
1180              return true;
1181            }
1182          }
1183        }
1184      }
1185    }
1186
1187    return false;
1188  }
1189
1190  Drupal.eu_cookie_compliance.getVersion = function () {
1191    // Only get cookie-agreed-version version cookie, if user agreed.
1192    if (!Drupal.eu_cookie_compliance.hasAgreed()) {
1193      return false;
1194    }
1195
1196    var cookieName = (typeof drupalSettings.eu_cookie_compliance.cookie_name === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_name === '') ? 'cookie-agreed-version' : drupalSettings.eu_cookie_compliance.cookie_name + '-version';
1197    return getCookie(cookieName);
1198  };
1199
1200  Drupal.eu_cookie_compliance.setVersion = function (force_this_version) {
1201    // Only set cookie-agreed-version version cookie, if user agreed.
1202    if (!Drupal.eu_cookie_compliance.hasAgreed()) {
1203      return false;
1204    }
1205
1206    var date = new Date();
1207    var domain = drupalSettings.eu_cookie_compliance.domain ? drupalSettings.eu_cookie_compliance.domain : '';
1208    var path = drupalSettings.eu_cookie_compliance.domain_all_sites ? '/' : drupalSettings.path.baseUrl;
1209    var cookieName = (typeof drupalSettings.eu_cookie_compliance.cookie_name === 'undefined' || drupalSettings.eu_cookie_compliance.cookie_name === '') ? 'cookie-agreed-version' : drupalSettings.eu_cookie_compliance.cookie_name + '-version';
1210    if (path.length > 1) {
1211      var pathEnd = path.length - 1;
1212      if (path.lastIndexOf('/') === pathEnd) {
1213        path = path.substring(0, pathEnd);
1214      }
1215    }
1216
1217    var eucc_version = (force_this_version !== undefined) ? force_this_version : drupalSettings.eu_cookie_compliance.cookie_policy_version;
1218    var cookie_session = parseInt(drupalSettings.eu_cookie_compliance.cookie_session);
1219    if (cookie_session) {
1220      setCookie(cookieName, eucc_version, { path: path, domain: domain, sameSite: 'strict' });
1221    }
1222    else {
1223      var lifetime = parseInt(drupalSettings.eu_cookie_compliance.cookie_lifetime);
1224      date.setDate(date.getDate() + lifetime);
1225      setCookie(cookieName, eucc_version, { expires: date, path: path, domain: domain, sameSite: 'strict' });
1226    }
1227  };
1228
1229  // Load blocked scripts if the user has agreed to being tracked.
1230  var euCookieComplianceHasLoadedScripts = false;
1231  var euCookieComplianceHasLoadedScriptsForCategory = {};
1232  $(function () {
1233    if (typeof drupalSettings.eu_cookie_compliance !== 'undefined') {
1234      if (Drupal.eu_cookie_compliance.hasAgreed()
1235        || (_euccCurrentStatus === null && drupalSettings.eu_cookie_compliance.method !== 'opt_in' && drupalSettings.eu_cookie_compliance.method !== 'categories')
1236      ) {
1237        Drupal.eu_cookie_compliance.loadScripts();
1238        euCookieComplianceHasLoadedScripts = true;
1239
1240        if (drupalSettings.eu_cookie_compliance.method === 'categories') {
1241          Drupal.eu_cookie_compliance.loadCategoryScripts(_euccSelectedCategories);
1242        }
1243      }
1244    }
1245  });
1246
1247  Drupal.eu_cookie_compliance.BlockCookies = function () {
1248    var cookieStatus = Drupal.eu_cookie_compliance.getCookieStatus();
1249    if ((cookieStatus === cookieValueAgreedShowThankYou || cookieStatus === cookieValueAgreed)
1250      && drupalSettings.eu_cookie_compliance.method !== 'categories') {
1251      // Stop blocking the cookies if it's already been agreed to (e.g. in a different tab).
1252      if (typeof euCookieComplianceBlockCookies !== 'undefined') {
1253        clearInterval(euCookieComplianceBlockCookies);
1254        return;
1255      }
1256    }
1257    // Load all cookies from jQuery.
1258    var allCookies = getCookie();
1259
1260    // Check each cookie and try to remove it if it's not allowed.
1261    for (var i in allCookies) {
1262      var remove = true;
1263      var hostname = window.location.hostname;
1264      var cookieRemoved = false;
1265      var index = 0;
1266
1267      remove = !Drupal.eu_cookie_compliance.isAllowed(i);
1268
1269      // Remove the cookie if it's not allowed.
1270      if (remove) {
1271        while (!cookieRemoved && hostname !== '') {
1272          // Attempt to remove.
1273          eraseCookie(i, { domain: '.' + hostname, path: '/' });
1274          cookieRemoved = !getCookie(i);
1275          if (!cookieRemoved) {
1276            eraseCookie(i, { domain: hostname, path: '/' });
1277            cookieRemoved = !getCookie(i);
1278          }
1279
1280          index = hostname.indexOf('.');
1281
1282          // We can be on a sub-domain, so keep checking the main domain as well.
1283          hostname = (index === -1) ? '' : hostname.substring(index + 1);
1284        }
1285
1286        // Some jQuery Cookie versions don't remove cookies well.  Try again
1287        // using plain js.
1288        if (!cookieRemoved) {
1289          document.cookie = i + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/;';
1290        }
1291      }
1292    }
1293  }
1294
1295  // Block cookies when the user hasn't agreed.
1296  if ((typeof drupalSettings.eu_cookie_compliance !== 'undefined') &&
1297    drupalSettings.eu_cookie_compliance.automatic_cookies_removal &&
1298    (
1299      (drupalSettings.eu_cookie_compliance.method === 'opt_in' && (_euccCurrentStatus === null  || !Drupal.eu_cookie_compliance.hasAgreed()))
1300      || (drupalSettings.eu_cookie_compliance.method === 'opt_out' && !Drupal.eu_cookie_compliance.hasAgreed() && _euccCurrentStatus !== null)
1301      || (drupalSettings.eu_cookie_compliance.method === 'categories')
1302    )) {
1303    euCookieComplianceBlockCookies = setInterval(Drupal.eu_cookie_compliance.BlockCookies, 5000);
1304  }
1305
1306  /**
1307   * Filter the event listeners by event name and return the list of handlers.
1308   *
1309   * @param forEventName
1310   *
1311   * @returns {[]}
1312   */
1313  var filterQueue = function (forEventName) {
1314    var handlers = [];
1315    if (typeof Drupal.eu_cookie_compliance !== 'undefined' &&
1316        typeof Drupal.eu_cookie_compliance.queue !== 'undefined' &&
1317        Drupal.eu_cookie_compliance.queue.length) {
1318      // Loop over the list of arguments (objects) pushed into the queue.
1319      for (var i = 0; i < Drupal.eu_cookie_compliance.queue.length; i++) {
1320        if (Drupal.eu_cookie_compliance.queue[i].length) {
1321          var queueItem = Drupal.eu_cookie_compliance.queue[i];
1322          var eventName = queueItem[0];
1323          var eventHandler = queueItem[1];
1324          // If the first element is a string and the second is a function.
1325          if (typeof eventName === 'string' && typeof eventHandler === 'function') {
1326            // And the string matches the event name.
1327            if (eventName === forEventName) {
1328              // Return the functions so they can be executed.
1329              handlers.push(eventHandler);
1330            }
1331          }
1332        }
1333      }
1334    }
1335    return handlers;
1336  }
1337
1338  /**
1339   * Handle event by finding and executing handlers pushed to the queue.
1340   */
1341  self.handleEvent = function (eventName, observer) {
1342    var handlers = filterQueue(eventName);
1343    for (var i = 0; i < handlers.length; i++) {
1344      if (typeof handlers[i] !== 'undefined') {
1345        observer.subscribe(handlers[i]);
1346        observer.fire({
1347          currentStatus: _euccCurrentStatus,
1348          currentCategories: _euccSelectedCategories
1349        });
1350        observer.unsubscribe(handlers[i]);
1351      }
1352    }
1353  };
1354
1355  /**
1356   * Observer: triggered before status gets read from cookie.
1357   */
1358  var PreStatusLoad = (function () {
1359    // Constructor.
1360    var PreStatusLoad = function () {
1361      // Observers.
1362      this.handlers = [];
1363    };
1364    // Convenience var for the prototype.
1365    var prototype = PreStatusLoad.prototype;
1366    prototype.subscribe = function (fn) {
1367      this.handlers.push(fn);
1368    };
1369    prototype.unsubscribe = function (fn) {
1370      this.handlers = this.handlers.filter(
1371          function (item) {
1372            if (item !== fn) {
1373              return item;
1374            }
1375          }
1376      );
1377    };
1378    prototype.fire = function (o, thisObj) {
1379      var scope = thisObj || window;
1380      this.handlers.forEach(function (item) {
1381        item.call(scope, o);
1382      });
1383    };
1384    return PreStatusLoad;
1385  })();
1386
1387  /**
1388   * Observer: when status was read from cookie and stored in private variable.
1389   */
1390  var PostStatusLoad = (function () {
1391    // Constructor.
1392    var PostStatusLoad = function () {
1393      // Observers.
1394      this.handlers = [];
1395    };
1396    // Convenience var for the prototype.
1397    var prototype = PostStatusLoad.prototype;
1398    prototype.subscribe = function (fn) {
1399      this.handlers.push(fn);
1400    };
1401    prototype.unsubscribe = function (fn) {
1402      this.handlers = this.handlers.filter(
1403          function (item) {
1404            if (item !== fn) {
1405              return item;
1406            }
1407          }
1408      );
1409    };
1410    prototype.fire = function (o, thisObj) {
1411      var scope = thisObj || window;
1412      this.handlers.forEach(function (item) {
1413        item.call(scope, o);
1414      });
1415    };
1416    return PostStatusLoad;
1417  })();
1418
1419  /**
1420   * Observer: triggered before status gets saved into cookie.
1421   */
1422  var PreStatusSave = (function () {
1423    // Constructor.
1424    var PreStatusSave = function () {
1425      // Observers.
1426      this.handlers = [];
1427    };
1428    // Convenience var for the prototype.
1429    var prototype = PreStatusSave.prototype;
1430    prototype.subscribe = function (fn) {
1431      this.handlers.push(fn);
1432    };
1433    prototype.unsubscribe = function (fn) {
1434      this.handlers = this.handlers.filter(
1435          function (item) {
1436            if (item !== fn) {
1437              return item;
1438            }
1439          }
1440      );
1441    };
1442    prototype.fire = function (o, thisObj) {
1443      var scope = thisObj || window;
1444      this.handlers.forEach(function (item) {
1445        item.call(scope, o);
1446      });
1447    };
1448    return PreStatusSave;
1449  })();
1450
1451  /**
1452   * Observer: triggered after status was saved into cookie.
1453   */
1454  var PostStatusSave = (function () {
1455    // Constructor.
1456    var PostStatusSave = function () {
1457      // Observers.
1458      this.handlers = [];
1459    };
1460    // Convenience var for the prototype.
1461    var prototype = PostStatusSave.prototype;
1462    prototype.subscribe = function (fn) {
1463      this.handlers.push(fn);
1464    };
1465    prototype.unsubscribe = function (fn) {
1466      this.handlers = this.handlers.filter(
1467          function (item) {
1468            if (item !== fn) {
1469              return item;
1470            }
1471          }
1472      );
1473    };
1474    prototype.fire = function (o, thisObj) {
1475      var scope = thisObj || window;
1476      this.handlers.forEach(function (item) {
1477        item.call(scope, o);
1478      });
1479    };
1480    return PostStatusSave;
1481  })();
1482
1483  /**
1484   * Observer: triggered before categories are read from cookie.
1485   */
1486  var PrePreferencesLoad = (function () {
1487    // Constructor.
1488    var prePreferencesLoad = function () {
1489      // Observers.
1490      this.handlers = [];
1491    };
1492    // Convenience var for the prototype.
1493    var prototype = prePreferencesLoad.prototype;
1494    prototype.subscribe = function (fn) {
1495      this.handlers.push(fn);
1496    };
1497    prototype.unsubscribe = function (fn) {
1498      this.handlers = this.handlers.filter(
1499          function (item) {
1500            if (item !== fn) {
1501              return item;
1502            }
1503          }
1504      );
1505    };
1506    prototype.fire = function (o, thisObj) {
1507      var scope = thisObj || window;
1508      this.handlers.forEach(function (item) {
1509        item.call(scope, o);
1510      });
1511    };
1512    return prePreferencesLoad;
1513  })();
1514
1515  /**
1516   * Observer: triggered after categories were read from cookie.
1517   */
1518  var PostPreferencesLoad = (function () {
1519    // Constructor.
1520    var postPreferencesLoad = function () {
1521      // Observers.
1522      this.handlers = [];
1523    };
1524    // Convenience var for the prototype.
1525    var prototype = postPreferencesLoad.prototype;
1526    prototype.subscribe = function (fn) {
1527      this.handlers.push(fn);
1528    };
1529    prototype.unsubscribe = function (fn) {
1530      this.handlers = this.handlers.filter(
1531          function (item) {
1532            if (item !== fn) {
1533              return item;
1534            }
1535          }
1536      );
1537    };
1538    prototype.fire = function (o, thisObj) {
1539      var scope = thisObj || window;
1540      this.handlers.forEach(function (item) {
1541        item.call(scope, o);
1542      });
1543    };
1544    return postPreferencesLoad;
1545  })();
1546
1547  /**
1548   * Observer: triggered before categories are being saved to cookie.
1549   */
1550  var PrePreferencesSave = (function () {
1551    // Constructor.
1552    var prePreferencesSave = function () {
1553      // Observers.
1554      this.handlers = [];
1555    };
1556    // Convenience var for the prototype.
1557    var prototype = prePreferencesSave.prototype;
1558    prototype.subscribe = function (fn) {
1559      this.handlers.push(fn);
1560    };
1561    prototype.unsubscribe = function (fn) {
1562      this.handlers = this.handlers.filter(
1563          function (item) {
1564            if (item !== fn) {
1565              return item;
1566            }
1567          }
1568      );
1569    };
1570    prototype.fire = function (o, thisObj) {
1571      var scope = thisObj || window;
1572      this.handlers.forEach(function (item) {
1573        item.call(scope, o);
1574      });
1575    };
1576    return prePreferencesSave;
1577  })();
1578
1579  /**
1580   * Observer: triggered after categories were saved to cookie.
1581   */
1582  var PostPreferencesSave = (function () {
1583    // Constructor.
1584    var postPreferencesSave = function () {
1585      // Observers.
1586      this.handlers = [];
1587    };
1588    // Convenience var for the prototype.
1589    var prototype = postPreferencesSave.prototype;
1590    prototype.subscribe = function (fn) {
1591      this.handlers.push(fn);
1592    };
1593    prototype.unsubscribe = function (fn) {
1594      this.handlers = this.handlers.filter(
1595          function (item) {
1596            if (item !== fn) {
1597              return item;
1598            }
1599          }
1600      );
1601    };
1602    prototype.fire = function (o, thisObj) {
1603      var scope = thisObj || window;
1604      this.handlers.forEach(function (item) {
1605        item.call(scope, o);
1606      });
1607    };
1608    return postPreferencesSave;
1609  })();
1610
1611})(jQuery, Drupal, drupalSettings, window.Cookies);

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.