PageSourceSearch

https://lewiscountyrec.org/sites/default/files/js/js_ugzTW-oHYZRecTvV85sR945r7slmSvFT7jGv7Q0DQVE.js

js lewiscountyrec.org collected 2026-10-09 22:39:24 UTC 87,258 bytes, 3,062 lines download raw bytes

1(function (Drupal) {
2
3  /**
4   * Command to attach data using jQuery's data API.
5   *
6   * @param {Drupal.Ajax} [ajax]
7   *   {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
8   * @param {object} response
9   *   The response from the Ajax request.
10   * @param {string} response.event_name
11   *   The event name
12   * @param {object} response.data
13   *   The value of the event.
14   */
15  Drupal.AjaxCommands.prototype.gtagEvent = function (ajax, response) {
16    gtag('event', response.event_name, response.data)
17  }
18})(Drupal);
19;
20function ctSetCookie(cookies)
21{
22
23  let useCookies, useAltCookies
24
25  if ('undefined' !== typeof ct_use_cookies) {
26    useCookies = ct_use_cookies;
27  } else {
28    useCookies = false;
29  }
30
31  if ('undefined' !== typeof ct_use_alt_cookies) {
32    useAltCookies = ct_use_alt_cookies;
33  } else {
34    useAltCookies = false
35  }
36
37  if (useCookies) {
38    if (useAltCookies && useAltCookies === 1) {
39      let xhr = new XMLHttpRequest();
40
41      let json = JSON.stringify(cookies);
42
43      xhr.open("POST", '/admin/config/cleantalk/set_alt_cookies')
44      xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
45
46      xhr.send(json);
47    } else {
48      cookies.forEach(
49        function (e) {
50          let ctSecure = location.protocol === "https:" ? "; secure" : "";
51          document.cookie = e.name + "=" + encodeURIComponent(e.value) + "; path=/; expires=0; samesite=lax" + ctSecure;
52        }
53      )
54    }
55  }
56}
57;
58var d = new Date(),
59    ctTimeMs = new Date().getTime(),
60    ctMouseEventTimerFlag = true, //Reading interval flag
61    ctMouseData = "[",
62    ctMouseDataCounter = 0,
63    ctScrollCollected = false,
64    ctEventTokenInterval = null;
65
66ctSetCookie(
67    [
68    {
69        'name' : 'ct_check_js',
70        'value' : ct_check_js_val
71    },
72    {
73        'name' : 'ct_ps_timestamp',
74        'value' : Math.floor(new Date().getTime()/1000)
75    },
76    {
77        'name' : 'ct_fkp_timestamp',
78        'value' : '0'
79    },
80    {
81        'name' : 'ct_pointer_data',
82        'value' : '0'
83    },
84    {
85        'name' : 'ct_timezone',
86        'value' : d.getTimezoneOffset()/60*(-1)
87    },
88    {
89        'name' : 'apbct_antibot',
90        'value' : drupal_ac_antibot_cookie_value
91    },
92    {
93        'name' : 'ct_has_scrolled',
94        'value' : false
95    }
96    ]
97);
98
99//Reading interval
100
101var ctMouseReadInterval = setInterval(
102    function () {
103        ctMouseEventTimerFlag = true;
104    }, 150
105);
106
107//Writting interval
108
109var ctMouseWriteDataInterval = setInterval(
110    function () {
111        if(typeof ct_use_alt_cookies !== "undefined" && ct_use_alt_cookies === 1) {
112            return;
113        }
114        var ctMouseDataToSend = ctMouseData.slice(0,-1).concat("]");
115        ctSetCookie(
116            [
117            {
118                'name' : 'ct_pointer_data',
119                'value' : ctMouseDataToSend
120            }
121            ]
122        );
123    }, 1200
124);
125
126//Stop observing function
127
128function ctMouseStopData()
129{
130    if(typeof window.addEventListener == "function") {
131        window.removeEventListener("mousemove", ctFunctionMouseMove);
132    } else {
133        window.detachEvent("onmousemove", ctFunctionMouseMove);
134    }
135    clearInterval(ctMouseReadInterval);
136    clearInterval(ctMouseWriteDataInterval);
137}
138
139//Logging mouse position each 300 ms
140
141var ctFunctionMouseMove = function output(event)
142{
143    if (ctMouseEventTimerFlag == true) {
144        var mouseDate = new Date();
145        ctMouseData += "[" + Math.round(event.pageY) + "," + Math.round(event.pageX) + "," + Math.round(mouseDate.getTime() - ctTimeMs) + "],";
146        ctMouseDataCounter++;
147        ctMouseEventTimerFlag = false;
148        if(ctMouseDataCounter >= 100) {
149            ctMouseStopData();
150        }
151    }
152};
153
154/**
155 * Set scrolling cookie
156 */
157function ctSetHasScrolled()
158{
159    if(! ctScrollCollected ) {
160        ctSetCookie(
161            [
162            {
163                'name' : 'ct_has_scrolled',
164                'value' : true
165            }
166            ]
167        );
168        ctScrollCollected = true;
169    }
170}
171
172//Stop key listening function
173
174function ctKeyStopStopListening()
175{
176    if (typeof window.addEventListener == "function") {
177        window.removeEventListener("mousedown", ctFunctionFirstKey);
178        window.removeEventListener("keydown", ctFunctionFirstKey);
179    }
180    else {
181        window.detachEvent("mousedown", ctFunctionFirstKey);
182        window.detachEvent("keydown", ctFunctionFirstKey);
183    }
184}
185
186//Writing first key press timestamp
187
188var ctFunctionFirstKey = function output(event)
189{
190    var KeyTimestamp = Math.floor(new Date().getTime()/1000);
191    ctSetCookie(
192        [
193        {
194            'name' : 'ct_fkp_timestamp',
195            'value' : KeyTimestamp
196        }
197        ]
198    );
199    ctKeyStopStopListening();
200};
201
202if (typeof window.addEventListener == "function") {
203    window.addEventListener("mousemove", ctFunctionMouseMove);
204    window.addEventListener("mousedown", ctFunctionFirstKey);
205    window.addEventListener("keydown", ctFunctionFirstKey);
206    window.addEventListener("scroll", ctSetHasScrolled);
207}
208else {
209    window.attachEvent("onmousemove", ctFunctionMouseMove);
210    window.attachEvent("mousedown", ctFunctionFirstKey);
211    window.attachEvent("keydown", ctFunctionFirstKey);
212    window.attachEvent("scroll", ctSetHasScrolled);
213}
214
215function apbct_collect_visible_fields( form )
216{
217
218    // Get only fields
219    var inputs = [],
220        inputs_visible = '',
221        inputs_visible_count = 0,
222        inputs_invisible = '',
223        inputs_invisible_count = 0,
224        inputs_with_duplicate_names = [];
225
226    for(var key in form.elements){
227        if(!isNaN(+key)) {
228            inputs[key] = form.elements[key];
229        }
230    }
231
232    // Filter fields
233    inputs = inputs.filter(
234        function (elem) {
235
236            // Filter already added fields
237            if(inputs_with_duplicate_names.indexOf(elem.getAttribute('name')) !== -1 ) {
238                return false;
239            }
240            // Filter inputs with same names for type == radio
241            if(-1 !== ['radio', 'checkbox'].indexOf(elem.getAttribute("type"))) {
242                inputs_with_duplicate_names.push(elem.getAttribute('name'));
243                return false;
244            }
245            return true;
246        }
247    );
248
249    // Visible fields
250    inputs.forEach(
251        function (elem, i, elements) {
252            // Unnecessary fields
253            if(elem.getAttribute("type")         === "submit"  // type == submit
254                || elem.getAttribute('name')         === null
255                || elem.getAttribute('name')         === 'ct_checkjs'
256            ) {
257                return;
258            }
259            // Invisible fields
260            if(getComputedStyle(elem).display    === "none"    // hidden
261                || getComputedStyle(elem).visibility === "hidden"  // hidden
262                || getComputedStyle(elem).opacity    === "0"       // hidden
263                || elem.getAttribute("type")         === "hidden" // type == hidden
264            ) {
265                if(elem.classList.contains("wp-editor-area") ) {
266                    inputs_visible += " " + elem.getAttribute("name");
267                    inputs_visible_count++;
268                } else {
269                    inputs_invisible += " " + elem.getAttribute("name");
270                    inputs_invisible_count++;
271                }
272            }
273            // Visible fields
274            else {
275                inputs_visible += " " + elem.getAttribute("name");
276                inputs_visible_count++;
277            }
278
279        }
280    );
281
282    inputs_invisible = inputs_invisible.trim();
283    inputs_visible = inputs_visible.trim();
284
285    return {
286        visible_fields : inputs_visible,
287        visible_fields_count : inputs_visible_count,
288        invisible_fields : inputs_invisible,
289        invisible_fields_count : inputs_invisible_count,
290    }
291
292}
293
294function apbct_visible_fields_set_cookie( visible_fields_collection )
295{
296    var collection = typeof visible_fields_collection === 'object' && visible_fields_collection !== null ?  visible_fields_collection : {};
297
298    ctSetCookie(
299        [
300        {
301            'name' : 'apbct_visible_fields',
302            'value' : JSON.stringify(collection)
303        }
304        ]
305    )
306}
307
308// Event token handler class. Get token and save it to the alternative sessions.
309
310class EventTokenHandler {
311
312  constructor(use_alt_cookies_option) {
313    this.token = null;
314    this.lsSavedFlagName = 'event_token_saved_to_alt_sessions';
315    this.lsEVentTokenName = 'bot_detector_event_token';
316    this.intervalValue = 1500;
317    this.init(use_alt_cookies_option);
318  }
319
320  init(use_alt_cookies_option){
321    if ('undefined' !== typeof use_alt_cookies_option && use_alt_cookies_option) {
322      this.setNotSavedFlag();
323      this.startListenTokenLS();
324    }
325  }
326
327
328  setSavedFlag()
329  {
330    localStorage.setItem(this.lsSavedFlagName, '1');
331  }
332
333  setNotSavedFlag()
334  {
335    localStorage.setItem(this.lsSavedFlagName, '0');
336  }
337
338  isSaved()
339  {
340    let event_token_saved = localStorage.getItem(this.lsSavedFlagName);
341    return event_token_saved !== null && event_token_saved !== undefined && event_token_saved === '1';
342  }
343
344  getEventToken()
345  {
346    let event_token = localStorage.getItem(this.lsEVentTokenName);
347    try {
348      event_token = event_token !== null ? JSON.parse(event_token) : false;
349    } catch (e) {
350      return false;
351    }
352    event_token = event_token.hasOwnProperty('value') ? event_token.value : false;
353    if (typeof event_token === 'string' && event_token.length === 64) {
354      return event_token;
355    }
356    return false;
357  }
358
359  setEventTokenCookie()
360  {
361    if (typeof this.token === 'string' && this.token.length === 64) {
362      ctSetCookie(
363        [
364          {
365            'name': 'apbct_event_token',
366            'value': this.token
367          }
368        ]
369      )
370    }
371  }
372
373  stopListenTokenLS()
374  {
375    clearInterval(this.intervalID);
376  }
377
378  startListenTokenLS()
379  {
380    this.intervalID = setInterval( this.intervalRun, this.intervalValue, this)
381  }
382
383  intervalRun(handler)
384  {
385    if ( !handler.isSaved() ) {
386      handler.token = handler.getEventToken();
387      if ( handler.token  ) {
388        handler.setEventTokenCookie();
389        handler.setSavedFlag();
390        handler.stopListenTokenLS();
391      }
392    }
393  }
394}
395
396//Collect event token
397new EventTokenHandler(ct_use_alt_cookies);
398;
399/**
400 * @file
401 * Bootstrap Popovers.
402 */
403
404var Drupal = Drupal || {};
405
406(function ($, Drupal, Bootstrap) {
407  "use strict";
408
409  var $document = $(document);
410
411  /**
412   * Extend the Bootstrap Popover plugin constructor class.
413   */
414  Bootstrap.extendPlugin('popover', function (settings) {
415    return {
416      DEFAULTS: {
417        animation: !!settings.popover_animation,
418        autoClose: !!settings.popover_auto_close,
419        enabled: settings.popover_enabled,
420        html: !!settings.popover_html,
421        placement: settings.popover_placement,
422        selector: settings.popover_selector,
423        trigger: settings.popover_trigger,
424        title: settings.popover_title,
425        content: settings.popover_content,
426        delay: parseInt(settings.popover_delay, 10),
427        container: settings.popover_container
428      }
429    };
430  });
431
432  /**
433   * Bootstrap Popovers.
434   *
435   * @todo This should really be properly delegated if selector option is set.
436   */
437  Drupal.behaviors.bootstrapPopovers = {
438    $activePopover: null,
439    attach: function (context) {
440      // Immediately return if popovers are not available.
441      if (!$.fn.popover || !$.fn.popover.Constructor.DEFAULTS.enabled) {
442        return;
443      }
444
445      var _this = this;
446
447      $document
448        .on('show.bs.popover', '[data-toggle=popover]', function () {
449          var $trigger = $(this);
450          var popover = $trigger.data('bs.popover');
451
452          // Only keep track of clicked triggers that we're manually handling.
453          if (popover.options.originalTrigger === 'click') {
454            if (_this.$activePopover && _this.getOption('autoClose') && !_this.$activePopover.is($trigger)) {
455              _this.$activePopover.popover('hide');
456            }
457            _this.$activePopover = $trigger;
458          }
459        })
460        // Unfortunately, :focusable is only made available when using jQuery
461        // UI. While this would be the most semantic pseudo selector to use
462        // here, jQuery UI may not always be loaded. Instead, just use :visible
463        // here as this just needs some sort of selector here. This activates
464        // delegate binding to elements in jQuery so it can work it's bubbling
465        // focus magic since elements don't really propagate their focus events.
466        // @see https://www.drupal.org/project/bootstrap/issues/3013236
467        .on('focus.bs.popover', ':visible', function (e) {
468          var $target = $(e.target);
469          if (_this.$activePopover && _this.getOption('autoClose') && !_this.$activePopover.is($target) && !$target.closest('.popover.in')[0]) {
470            _this.$activePopover.popover('hide');
471            _this.$activePopover = null;
472          }
473        })
474        .on('click.bs.popover', function (e) {
475          var $target = $(e.target);
476          if (_this.$activePopover && _this.getOption('autoClose') && !$target.is('[data-toggle=popover]') && !$target.closest('.popover.in')[0]) {
477            _this.$activePopover.popover('hide');
478            _this.$activePopover = null;
479          }
480        })
481        .on('keyup.bs.popover', function (e) {
482          if (_this.$activePopover && _this.getOption('autoClose') && e.which === 27) {
483            _this.$activePopover.popover('hide');
484            _this.$activePopover = null;
485          }
486        })
487      ;
488
489      var elements = $(context).find('[data-toggle=popover]').toArray();
490      for (var i = 0; i < elements.length; i++) {
491        var $element = $(elements[i]);
492        var options = $.extend({}, $.fn.popover.Constructor.DEFAULTS, $element.data());
493
494        // Store the original trigger.
495        options.originalTrigger = options.trigger;
496
497        // If the trigger is "click", then we'll handle it manually here.
498        if (options.trigger === 'click') {
499          options.trigger = 'manual';
500        }
501
502        // Retrieve content from a target element.
503        var target = options.target || $element.is('a[href^="#"]') && $element.attr('href');
504        var $target = $document.find(target).clone();
505        if (!options.content && $target[0]) {
506          $target.removeClass('visually-hidden hidden').removeAttr('aria-hidden');
507          options.content = $target.wrap('<div/>').parent()[options.html ? 'html' : 'text']() || '';
508        }
509
510        // Initialize the popover.
511        $element.popover(options);
512
513        // Handle clicks manually.
514        if (options.originalTrigger === 'click') {
515          // To ensure the element is bound multiple times, remove any
516          // previously set event handler before adding another one.
517          $element
518            .off('click.drupal.bootstrap.popover')
519            .on('click.drupal.bootstrap.popover', function (e) {
520              $(this).popover('toggle');
521              e.preventDefault();
522              e.stopPropagation();
523            })
524          ;
525        }
526      }
527    },
528    detach: function (context) {
529      // Immediately return if popovers are not available.
530      if (!$.fn.popover || !$.fn.popover.Constructor.DEFAULTS.enabled) {
531        return;
532      }
533
534      // Destroy all popovers.
535      $(context).find('[data-toggle="popover"]')
536        .off('click.drupal.bootstrap.popover')
537        .popover('destroy')
538      ;
539    },
540    getOption: function(name, defaultValue, element) {
541      var $element = element ? $(element) : this.$activePopover;
542      var options = $.extend(true, {}, $.fn.popover.Constructor.DEFAULTS, ($element && $element.data('bs.popover') || {}).options);
543      if (options[name] !== void 0) {
544        return options[name];
545      }
546      return defaultValue !== void 0 ? defaultValue : void 0;
547    }
548  };
549
550})(window.jQuery, window.Drupal, window.Drupal.bootstrap);
551;
552/**
553 * @file
554 * Bootstrap Tooltips.
555 */
556
557var Drupal = Drupal || {};
558
559(function ($, Drupal, Bootstrap) {
560  "use strict";
561
562  /**
563   * Extend the Bootstrap Tooltip plugin constructor class.
564   */
565  Bootstrap.extendPlugin('tooltip', function (settings) {
566    return {
567      DEFAULTS: {
568        animation: !!settings.tooltip_animation,
569        enabled: settings.tooltip_enabled,
570        html: !!settings.tooltip_html,
571        placement: settings.tooltip_placement,
572        selector: settings.tooltip_selector,
573        trigger: settings.tooltip_trigger,
574        delay: parseInt(settings.tooltip_delay, 10),
575        container: settings.tooltip_container
576      }
577    };
578  });
579
580  /**
581   * Bootstrap Tooltips.
582   *
583   * @todo This should really be properly delegated if selector option is set.
584   */
585  Drupal.behaviors.bootstrapTooltips = {
586    attach: function (context) {
587      // Immediately return if tooltips are not available.
588      if (!$.fn.tooltip || !$.fn.tooltip.Constructor.DEFAULTS.enabled) {
589        return;
590      }
591
592      var elements = $(context).find('[data-toggle="tooltip"]').toArray();
593      for (var i = 0; i < elements.length; i++) {
594        var $element = $(elements[i]);
595        var options = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, $element.data());
596        $element.tooltip(options);
597      }
598    },
599    detach: function (context) {
600      // Immediately return if tooltips are not available.
601      if (!$.fn.tooltip || !$.fn.tooltip.Constructor.DEFAULTS.enabled) {
602        return;
603      }
604
605      // Destroy all tooltips.
606      $(context).find('[data-toggle="tooltip"]').tooltip('destroy');
607    }
608  };
609
610})(window.jQuery, window.Drupal, window.Drupal.bootstrap);
611;
vendor: 29,168 bytes, lines 612-1716
612/*!
613	Colorbox 1.6.4
614	license: MIT
615	http://www.jacklmoore.com/colorbox
616*/
617(function ($, document, window) {
618	var
619	// Default settings object.
620	// See http://jacklmoore.com/colorbox for details.
621	defaults = {
622		// data sources
623		html: false,
624		photo: false,
625		iframe: false,
626		inline: false,
627
628		// behavior and appearance
629		transition: "elastic",
630		speed: 300,
631		fadeOut: 300,
632		width: false,
633		initialWidth: "600",
634		innerWidth: false,
635		maxWidth: false,
636		height: false,
637		initialHeight: "450",
638		innerHeight: false,
639		maxHeight: false,
640		scalePhotos: true,
641		scrolling: true,
642		opacity: 0.9,
643		preloading: true,
644		className: false,
645		overlayClose: true,
646		escKey: true,
647		arrowKey: true,
648		top: false,
649		bottom: false,
650		left: false,
651		right: false,
652		fixed: false,
653		data: undefined,
654		closeButton: true,
655		fastIframe: true,
656		open: false,
657		reposition: true,
658		loop: true,
659		slideshow: false,
660		slideshowAuto: true,
661		slideshowSpeed: 2500,
662		slideshowStart: "start slideshow",
663		slideshowStop: "stop slideshow",
664		photoRegex: /\.(gif|png|jp(e|g|eg)|bmp|ico|webp|jxr|svg)((#|\?).*)?$/i,
665
666		// alternate image paths for high-res displays
667		retinaImage: false,
668		retinaUrl: false,
669		retinaSuffix: '@2x.$1',
670
671		// internationalization
672		current: "image {current} of {total}",
673		previous: "previous",
674		next: "next",
675		close: "close",
676		xhrError: "This content failed to load.",
677		imgError: "This image failed to load.",
678
679		// accessbility
680		returnFocus: true,
681		trapFocus: true,
682
683		// callbacks
684		onOpen: false,
685		onLoad: false,
686		onComplete: false,
687		onCleanup: false,
688		onClosed: false,
689
690		rel: function() {
691			return this.rel;
692		},
693		href: function() {
694			// using this.href would give the absolute url, when the href may have been inteded as a selector (e.g. '#container')
695			return $(this).attr('href');
696		},
697		title: function() {
698			return this.title;
699		},
700		createImg: function() {
701			var img = new Image();
702			var attrs = $(this).data('cbox-img-attrs');
703
704			if (typeof attrs === 'object') {
705				$.each(attrs, function(key, val){
706					img[key] = val;
707				});
708			}
709
710			return img;
711		},
712		createIframe: function() {
713			var iframe = document.createElement('iframe');
714			var attrs = $(this).data('cbox-iframe-attrs');
715
716			if (typeof attrs === 'object') {
717				$.each(attrs, function(key, val){
718					iframe[key] = val;
719				});
720			}
721
722			if ('frameBorder' in iframe) {
723				iframe.frameBorder = 0;
724			}
725			if ('allowTransparency' in iframe) {
726				iframe.allowTransparency = "true";
727			}
728			iframe.name = (new Date()).getTime(); // give the iframe a unique name to prevent caching
729			iframe.allowFullscreen = true;
730
731			return iframe;
732		}
733	},
734
735	// Abstracting the HTML and event identifiers for easy rebranding
736	colorbox = 'colorbox',
737	prefix = 'cbox',
738	boxElement = prefix + 'Element',
739
740	// Events
741	event_open = prefix + '_open',
742	event_load = prefix + '_load',
743	event_complete = prefix + '_complete',
744	event_cleanup = prefix + '_cleanup',
745	event_closed = prefix + '_closed',
746	event_purge = prefix + '_purge',
747
748	// Cached jQuery Object Variables
749	$overlay,
750	$box,
751	$wrap,
752	$content,
753	$topBorder,
754	$leftBorder,
755	$rightBorder,
756	$bottomBorder,
757	$related,
758	$window,
759	$loaded,
760	$loadingBay,
761	$loadingOverlay,
762	$title,
763	$current,
764	$slideshow,
765	$next,
766	$prev,
767	$close,
768	$groupControls,
769	$events = $('<a/>'), // $({}) would be prefered, but there is an issue with jQuery 1.4.2
770
771	// Variables for cached values or use across multiple functions
772	settings,
773	interfaceHeight,
774	interfaceWidth,
775	loadedHeight,
776	loadedWidth,
777	index,
778	photo,
779	open,
780	active,
781	closing,
782	loadingTimer,
783	publicMethod,
784	div = "div",
785	requests = 0,
786	previousCSS = {},
787	init;
788
789	// ****************
790	// HELPER FUNCTIONS
791	// ****************
792
793	// Convenience function for creating new jQuery objects
794	function $tag(tag, id, css) {
795		var element = document.createElement(tag);
796
797		if (id) {
798			element.id = prefix + id;
799		}
800
801		if (css) {
802			element.style.cssText = css;
803		}
804
805		return $(element);
806	}
807
808	// Get the window height using innerHeight when available to avoid an issue with iOS
809	// http://bugs.jquery.com/ticket/6724
810	function winheight() {
811		return window.innerHeight ? window.innerHeight : $(window).height();
812	}
813
814	function Settings(element, options) {
815		if (options !== Object(options)) {
816			options = {};
817		}
818
819		this.cache = {};
820		this.el = element;
821
822		this.value = function(key) {
823			var dataAttr;
824
825			if (this.cache[key] === undefined) {
826				dataAttr = $(this.el).attr('data-cbox-'+key);
827
828				if (dataAttr !== undefined) {
829					this.cache[key] = dataAttr;
830				} else if (options[key] !== undefined) {
831					this.cache[key] = options[key];
832				} else if (defaults[key] !== undefined) {
833					this.cache[key] = defaults[key];
834				}
835			}
836
837			return this.cache[key];
838		};
839
840		this.get = function(key) {
841			var value = this.value(key);
842			return $.isFunction(value) ? value.call(this.el, this) : value;
843		};
844	}
845
846	// Determine the next and previous members in a group.
847	function getIndex(increment) {
848		var
849		max = $related.length,
850		newIndex = (index + increment) % max;
851
852		return (newIndex < 0) ? max + newIndex : newIndex;
853	}
854
855	// Convert '%' and 'px' values to integers
856	function setSize(size, dimension) {
857		return Math.round((/%/.test(size) ? ((dimension === 'x' ? $window.width() : winheight()) / 100) : 1) * parseInt(size, 10));
858	}
859
860	// Checks an href to see if it is a photo.
861	// There is a force photo option (photo: true) for hrefs that cannot be matched by the regex.
862	function isImage(settings, url) {
863		return settings.get('photo') || settings.get('photoRegex').test(url);
864	}
865
866	function retinaUrl(settings, url) {
867		return settings.get('retinaUrl') && window.devicePixelRatio > 1 ? url.replace(settings.get('photoRegex'), settings.get('retinaSuffix')) : url;
868	}
869
870	function trapFocus(e) {
871		if ('contains' in $box[0] && !$box[0].contains(e.target) && e.target !== $overlay[0]) {
872			e.stopPropagation();
873			$box.focus();
874		}
875	}
876
877	function setClass(str) {
878		if (setClass.str !== str) {
879			$box.add($overlay).removeClass(setClass.str).addClass(str);
880			setClass.str = str;
881		}
882	}
883
884	function getRelated(rel) {
885		index = 0;
886
887		if (rel && rel !== false && rel !== 'nofollow') {
888			$related = $('.' + boxElement).filter(function () {
889				var options = $.data(this, colorbox);
890				var settings = new Settings(this, options);
891				return (settings.get('rel') === rel);
892			});
893			index = $related.index(settings.el);
894
895			// Check direct calls to Colorbox.
896			if (index === -1) {
897				$related = $related.add(settings.el);
898				index = $related.length - 1;
899			}
900		} else {
901			$related = $(settings.el);
902		}
903	}
904
905	function trigger(event) {
906		// for external use
907		$(document).trigger(event);
908		// for internal use
909		$events.triggerHandler(event);
910	}
911
912	var slideshow = (function(){
913		var active,
914			className = prefix + "Slideshow_",
915			click = "click." + prefix,
916			timeOut;
917
918		function clear () {
919			clearTimeout(timeOut);
920		}
921
922		function set() {
923			if (settings.get('loop') || $related[index + 1]) {
924				clear();
925				timeOut = setTimeout(publicMethod.next, settings.get('slideshowSpeed'));
926			}
927		}
928
929		function start() {
930			$slideshow
931				.html(settings.get('slideshowStop'))
932				.unbind(click)
933				.one(click, stop);
934
935			$events
936				.bind(event_complete, set)
937				.bind(event_load, clear);
938
939			$box.removeClass(className + "off").addClass(className + "on");
940		}
941
942		function stop() {
943			clear();
944
945			$events
946				.unbind(event_complete, set)
947				.unbind(event_load, clear);
948
949			$slideshow
950				.html(settings.get('slideshowStart'))
951				.unbind(click)
952				.one(click, function () {
953					publicMethod.next();
954					start();
955				});
956
957			$box.removeClass(className + "on").addClass(className + "off");
958		}
959
960		function reset() {
961			active = false;
962			$slideshow.hide();
963			clear();
964			$events
965				.unbind(event_complete, set)
966				.unbind(event_load, clear);
967			$box.removeClass(className + "off " + className + "on");
968		}
969
970		return function(){
971			if (active) {
972				if (!settings.get('slideshow')) {
973					$events.unbind(event_cleanup, reset);
974					reset();
975				}
976			} else {
977				if (settings.get('slideshow') && $related[1]) {
978					active = true;
979					$events.one(event_cleanup, reset);
980					if (settings.get('slideshowAuto')) {
981						start();
982					} else {
983						stop();
984					}
985					$slideshow.show();
986				}
987			}
988		};
989
990	}());
991
992
993	function launch(element) {
994		var options;
995
996		if (!closing) {
997
998			options = $(element).data(colorbox);
999
1000			settings = new Settings(element, options);
1001
1002			getRelated(settings.get('rel'));
1003
1004			if (!open) {
1005				open = active = true; // Prevents the page-change action from queuing up if the visitor holds down the left or right keys.
1006
1007				setClass(settings.get('className'));
1008
1009				// Show colorbox so the sizes can be calculated in older versions of jQuery
1010				$box.css({visibility:'hidden', display:'block', opacity:''});
1011
1012				$loaded = $tag(div, 'LoadedContent', 'width:0; height:0; overflow:hidden; visibility:hidden');
1013				$content.css({width:'', height:''}).append($loaded);
1014
1015				// Cache values needed for size calculations
1016				interfaceHeight = $topBorder.height() + $bottomBorder.height() + $content.outerHeight(true) - $content.height();
1017				interfaceWidth = $leftBorder.width() + $rightBorder.width() + $content.outerWidth(true) - $content.width();
1018				loadedHeight = $loaded.outerHeight(true);
1019				loadedWidth = $loaded.outerWidth(true);
1020
1021				// Opens inital empty Colorbox prior to content being loaded.
1022				var initialWidth = setSize(settings.get('initialWidth'), 'x');
1023				var initialHeight = setSize(settings.get('initialHeight'), 'y');
1024				var maxWidth = settings.get('maxWidth');
1025				var maxHeight = settings.get('maxHeight');
1026
1027				settings.w = Math.max((maxWidth !== false ? Math.min(initialWidth, setSize(maxWidth, 'x')) : initialWidth) - loadedWidth - interfaceWidth, 0);
1028				settings.h = Math.max((maxHeight !== false ? Math.min(initialHeight, setSize(maxHeight, 'y')) : initialHeight) - loadedHeight - interfaceHeight, 0);
1029
1030				$loaded.css({width:'', height:settings.h});
1031				publicMethod.position();
1032
1033				trigger(event_open);
1034				settings.get('onOpen');
1035
1036				$groupControls.add($title).hide();
1037
1038				$box.focus();
1039
1040				if (settings.get('trapFocus')) {
1041					// Confine focus to the modal
1042					// Uses event capturing that is not supported in IE8-
1043					if (document.addEventListener) {
1044
1045						document.addEventListener('focus', trapFocus, true);
1046
1047						$events.one(event_closed, function () {
1048							document.removeEventListener('focus', trapFocus, true);
1049						});
1050					}
1051				}
1052
1053				// Return focus on closing
1054				if (settings.get('returnFocus')) {
1055					$events.one(event_closed, function () {
1056						$(settings.el).focus();
1057					});
1058				}
1059			}
1060
1061			var opacity = parseFloat(settings.get('opacity'));
1062			$overlay.css({
1063				opacity: opacity === opacity ? opacity : '',
1064				cursor: settings.get('overlayClose') ? 'pointer' : '',
1065				visibility: 'visible'
1066			}).show();
1067
1068			if (settings.get('closeButton')) {
1069				$close.html(settings.get('close')).appendTo($content);
1070			} else {
1071				$close.appendTo('<div/>'); // replace with .detach() when dropping jQuery < 1.4
1072			}
1073
1074			load();
1075		}
1076	}
1077
1078	// Colorbox's markup needs to be added to the DOM prior to being called
1079	// so that the browser will go ahead and load the CSS background images.
1080	function appendHTML() {
1081		if (!$box) {
1082			init = false;
1083			$window = $(window);
1084			$box = $tag(div).attr({
1085				id: colorbox,
1086				'class': $.support.opacity === false ? prefix + 'IE' : '', // class for optional IE8 & lower targeted CSS.
1087				role: 'dialog',
1088				tabindex: '-1'
1089			}).hide();
1090			$overlay = $tag(div, "Overlay").hide();
1091			$loadingOverlay = $([$tag(div, "LoadingOverlay")[0],$tag(div, "LoadingGraphic")[0]]);
1092			$wrap = $tag(div, "Wrapper");
1093			$content = $tag(div, "Content").append(
1094				$title = $tag(div, "Title"),
1095				$current = $tag(div, "Current"),
1096				$prev = $('<button type="button"/>').attr({id:prefix+'Previous'}),
1097				$next = $('<button type="button"/>').attr({id:prefix+'Next'}),
1098				$slideshow = $('<button type="button"/>').attr({id:prefix+'Slideshow'}),
1099				$loadingOverlay
1100			);
1101
1102			$close = $('<button type="button"/>').attr({id:prefix+'Close'});
1103
1104			$wrap.append( // The 3x3 Grid that makes up Colorbox
1105				$tag(div).append(
1106					$tag(div, "TopLeft"),
1107					$topBorder = $tag(div, "TopCenter"),
1108					$tag(div, "TopRight")
1109				),
1110				$tag(div, false, 'clear:left').append(
1111					$leftBorder = $tag(div, "MiddleLeft"),
1112					$content,
1113					$rightBorder = $tag(div, "MiddleRight")
1114				),
1115				$tag(div, false, 'clear:left').append(
1116					$tag(div, "BottomLeft"),
1117					$bottomBorder = $tag(div, "BottomCenter"),
1118					$tag(div, "BottomRight")
1119				)
1120			).find('div div').css({'float': 'left'});
1121
1122			$loadingBay = $tag(div, false, 'position:absolute; width:9999px; visibility:hidden; display:none; max-width:none;');
1123
1124			$groupControls = $next.add($prev).add($current).add($slideshow);
1125		}
1126		if (document.body && !$box.parent().length) {
1127			$(document.body).append($overlay, $box.append($wrap, $loadingBay));
1128		}
1129	}
1130
1131	// Add Colorbox's event bindings
1132	function addBindings() {
1133		function clickHandler(e) {
1134			// ignore non-left-mouse-clicks and clicks modified with ctrl / command, shift, or alt.
1135			// See: http://jacklmoore.com/notes/click-events/
1136			if (!(e.which > 1 || e.shiftKey || e.altKey || e.metaKey || e.ctrlKey)) {
1137				e.preventDefault();
1138				launch(this);
1139			}
1140		}
1141
1142		if ($box) {
1143			if (!init) {
1144				init = true;
1145
1146				// Anonymous functions here keep the public method from being cached, thereby allowing them to be redefined on the fly.
1147				$next.click(function () {
1148					publicMethod.next();
1149				});
1150				$prev.click(function () {
1151					publicMethod.prev();
1152				});
1153				$close.click(function () {
1154					publicMethod.close();
1155				});
1156				$overlay.click(function () {
1157					if (settings.get('overlayClose')) {
1158						publicMethod.close();
1159					}
1160				});
1161
1162				// Key Bindings
1163				$(document).bind('keydown.' + prefix, function (e) {
1164					var key = e.keyCode;
1165					if (open && settings.get('escKey') && key === 27) {
1166						e.preventDefault();
1167						publicMethod.close();
1168					}
1169					if (open && settings.get('arrowKey') && $related[1] && !e.altKey) {
1170						if (key === 37) {
1171							e.preventDefault();
1172							$prev.click();
1173						} else if (key === 39) {
1174							e.preventDefault();
1175							$next.click();
1176						}
1177					}
1178				});
1179
1180				if ($.isFunction($.fn.on)) {
1181					// For jQuery 1.7+
1182					$(document).on('click.'+prefix, '.'+boxElement, clickHandler);
1183				} else {
1184					// For jQuery 1.3.x -> 1.6.x
1185					// This code is never reached in jQuery 1.9, so do not contact me about 'live' being removed.
1186					// This is not here for jQuery 1.9, it's here for legacy users.
1187					$('.'+boxElement).live('click.'+prefix, clickHandler);
1188				}
1189			}
1190			return true;
1191		}
1192		return false;
1193	}
1194
1195	// Don't do anything if Colorbox already exists.
1196	if ($[colorbox]) {
1197		return;
1198	}
1199
1200	// Append the HTML when the DOM loads
1201	$(appendHTML);
1202
1203
1204	// ****************
1205	// PUBLIC FUNCTIONS
1206	// Usage format: $.colorbox.close();
1207	// Usage from within an iframe: parent.jQuery.colorbox.close();
1208	// ****************
1209
1210	publicMethod = $.fn[colorbox] = $[colorbox] = function (options, callback) {
1211		var settings;
1212		var $obj = this;
1213
1214		options = options || {};
1215
1216		if ($.isFunction($obj)) { // assume a call to $.colorbox
1217			$obj = $('<a/>');
1218			options.open = true;
1219		}
1220
1221		if (!$obj[0]) { // colorbox being applied to empty collection
1222			return $obj;
1223		}
1224
1225		appendHTML();
1226
1227		if (addBindings()) {
1228
1229			if (callback) {
1230				options.onComplete = callback;
1231			}
1232
1233			$obj.each(function () {
1234				var old = $.data(this, colorbox) || {};
1235				$.data(this, colorbox, $.extend(old, options));
1236			}).addClass(boxElement);
1237
1238			settings = new Settings($obj[0], options);
1239
1240			if (settings.get('open')) {
1241				launch($obj[0]);
1242			}
1243		}
1244
1245		return $obj;
1246	};
1247
1248	publicMethod.position = function (speed, loadedCallback) {
1249		var
1250		css,
1251		top = 0,
1252		left = 0,
1253		offset = $box.offset(),
1254		scrollTop,
1255		scrollLeft;
1256
1257		$window.unbind('resize.' + prefix);
1258
1259		// remove the modal so that it doesn't influence the document width/height
1260		$box.css({top: -9e4, left: -9e4});
1261
1262		scrollTop = $window.scrollTop();
1263		scrollLeft = $window.scrollLeft();
1264
1265		if (settings.get('fixed')) {
1266			offset.top -= scrollTop;
1267			offset.left -= scrollLeft;
1268			$box.css({position: 'fixed'});
1269		} else {
1270			top = scrollTop;
1271			left = scrollLeft;
1272			$box.css({position: 'absolute'});
1273		}
1274
1275		// keeps the top and left positions within the browser's viewport.
1276		if (settings.get('right') !== false) {
1277			left += Math.max($window.width() - settings.w - loadedWidth - interfaceWidth - setSize(settings.get('right'), 'x'), 0);
1278		} else if (settings.get('left') !== false) {
1279			left += setSize(settings.get('left'), 'x');
1280		} else {
1281			left += Math.round(Math.max($window.width() - settings.w - loadedWidth - interfaceWidth, 0) / 2);
1282		}
1283
1284		if (settings.get('bottom') !== false) {
1285			top += Math.max(winheight() - settings.h - loadedHeight - interfaceHeight - setSize(settings.get('bottom'), 'y'), 0);
1286		} else if (settings.get('top') !== false) {
1287			top += setSize(settings.get('top'), 'y');
1288		} else {
1289			top += Math.round(Math.max(winheight() - settings.h - loadedHeight - interfaceHeight, 0) / 2);
1290		}
1291
1292		$box.css({top: offset.top, left: offset.left, visibility:'visible'});
1293
1294		// this gives the wrapper plenty of breathing room so it's floated contents can move around smoothly,
1295		// but it has to be shrank down around the size of div#colorbox when it's done.  If not,
1296		// it can invoke an obscure IE bug when using iframes.
1297		$wrap[0].style.width = $wrap[0].style.height = "9999px";
1298
1299		function modalDimensions() {
1300			$topBorder[0].style.width = $bottomBorder[0].style.width = $content[0].style.width = (parseInt($box[0].style.width,10) - interfaceWidth)+'px';
1301			$content[0].style.height = $leftBorder[0].style.height = $rightBorder[0].style.height = (parseInt($box[0].style.height,10) - interfaceHeight)+'px';
1302		}
1303
1304		css = {width: settings.w + loadedWidth + interfaceWidth, height: settings.h + loadedHeight + interfaceHeight, top: top, left: left};
1305
1306		// setting the speed to 0 if the content hasn't changed size or position
1307		if (speed) {
1308			var tempSpeed = 0;
1309			$.each(css, function(i){
1310				if (css[i] !== previousCSS[i]) {
1311					tempSpeed = speed;
1312					return;
1313				}
1314			});
1315			speed = tempSpeed;
1316		}
1317
1318		previousCSS = css;
1319
1320		if (!speed) {
1321			$box.css(css);
1322		}
1323
1324		$box.dequeue().animate(css, {
1325			duration: speed || 0,
1326			complete: function () {
1327				modalDimensions();
1328
1329				active = false;
1330
1331				// shrink the wrapper down to exactly the size of colorbox to avoid a bug in IE's iframe implementation.
1332				$wrap[0].style.width = (settings.w + loadedWidth + interfaceWidth) + "px";
1333				$wrap[0].style.height = (settings.h + loadedHeight + interfaceHeight) + "px";
1334
1335				if (settings.get('reposition')) {
1336					setTimeout(function () {  // small delay before binding onresize due to an IE8 bug.
1337						$window.bind('resize.' + prefix, publicMethod.position);
1338					}, 1);
1339				}
1340
1341				if ($.isFunction(loadedCallback)) {
1342					loadedCallback();
1343				}
1344			},
1345			step: modalDimensions
1346		});
1347	};
1348
1349	publicMethod.resize = function (options) {
1350		var scrolltop;
1351
1352		if (open) {
1353			options = options || {};
1354
1355			if (options.width) {
1356				settings.w = setSize(options.width, 'x') - loadedWidth - interfaceWidth;
1357			}
1358
1359			if (options.innerWidth) {
1360				settings.w = setSize(options.innerWidth, 'x');
1361			}
1362
1363			$loaded.css({width: settings.w});
1364
1365			if (options.height) {
1366				settings.h = setSize(options.height, 'y') - loadedHeight - interfaceHeight;
1367			}
1368
1369			if (options.innerHeight) {
1370				settings.h = setSize(options.innerHeight, 'y');
1371			}
1372
1373			if (!options.innerHeight && !options.height) {
1374				scrolltop = $loaded.scrollTop();
1375				$loaded.css({height: "auto"});
1376				settings.h = $loaded.height();
1377			}
1378
1379			$loaded.css({height: settings.h});
1380
1381			if(scrolltop) {
1382				$loaded.scrollTop(scrolltop);
1383			}
1384
1385			publicMethod.position(settings.get('transition') === "none" ? 0 : settings.get('speed'));
1386		}
1387	};
1388
1389	publicMethod.prep = function (object) {
1390		if (!open) {
1391			return;
1392		}
1393
1394		var callback, speed = settings.get('transition') === "none" ? 0 : settings.get('speed');
1395
1396		$loaded.remove();
1397
1398		$loaded = $tag(div, 'LoadedContent').append(object);
1399
1400		function getWidth() {
1401			settings.w = settings.w || $loaded.width();
1402			settings.w = settings.mw && settings.mw < settings.w ? settings.mw : settings.w;
1403			return settings.w;
1404		}
1405		function getHeight() {
1406			settings.h = settings.h || $loaded.height();
1407			settings.h = settings.mh && settings.mh < settings.h ? settings.mh : settings.h;
1408			return settings.h;
1409		}
1410
1411		$loaded.hide()
1412		.appendTo($loadingBay.show())// content has to be appended to the DOM for accurate size calculations.
1413		.css({width: getWidth(), overflow: settings.get('scrolling') ? 'auto' : 'hidden'})
1414		.css({height: getHeight()})// sets the height independently from the width in case the new width influences the value of height.
1415		.prependTo($content);
1416
1417		$loadingBay.hide();
1418
1419		// floating the IMG removes the bottom line-height and fixed a problem where IE miscalculates the width of the parent element as 100% of the document width.
1420
1421		$(photo).css({'float': 'none'});
1422
1423		setClass(settings.get('className'));
1424
1425		callback = function () {
1426			var total = $related.length,
1427				iframe,
1428				complete;
1429
1430			if (!open) {
1431				return;
1432			}
1433
1434			function removeFilter() { // Needed for IE8 in versions of jQuery prior to 1.7.2
1435				if ($.support.opacity === false) {
1436					$box[0].style.removeAttribute('filter');
1437				}
1438			}
1439
1440			complete = function () {
1441				clearTimeout(loadingTimer);
1442				$loadingOverlay.hide();
1443				trigger(event_complete);
1444				settings.get('onComplete');
1445			};
1446
1447
1448			$title.html(settings.get('title')).show();
1449			$loaded.show();
1450
1451			if (total > 1) { // handle grouping
1452				if (typeof settings.get('current') === "string") {
1453					$current.html(settings.get('current').replace('{current}', index + 1).replace('{total}', total)).show();
1454				}
1455
1456				$next[(settings.get('loop') || index < total - 1) ? "show" : "hide"]().html(settings.get('next'));
1457				$prev[(settings.get('loop') || index) ? "show" : "hide"]().html(settings.get('previous'));
1458
1459				slideshow();
1460
1461				// Preloads images within a rel group
1462				if (settings.get('preloading')) {
1463					$.each([getIndex(-1), getIndex(1)], function(){
1464						var img,
1465							i = $related[this],
1466							settings = new Settings(i, $.data(i, colorbox)),
1467							src = settings.get('href');
1468
1469						if (src && isImage(settings, src)) {
1470							src = retinaUrl(settings, src);
1471							img = document.createElement('img');
1472							img.src = src;
1473						}
1474					});
1475				}
1476			} else {
1477				$groupControls.hide();
1478			}
1479
1480			if (settings.get('iframe')) {
1481
1482				iframe = settings.get('createIframe');
1483
1484				if (!settings.get('scrolling')) {
1485					iframe.scrolling = "no";
1486				}
1487
1488				$(iframe)
1489					.attr({
1490						src: settings.get('href'),
1491						'class': prefix + 'Iframe'
1492					})
1493					.one('load', complete)
1494					.appendTo($loaded);
1495
1496				$events.one(event_purge, function () {
1497					iframe.src = "//about:blank";
1498				});
1499
1500				if (settings.get('fastIframe')) {
1501					$(iframe).trigger('load');
1502				}
1503			} else {
1504				complete();
1505			}
1506
1507			if (settings.get('transition') === 'fade') {
1508				$box.fadeTo(speed, 1, removeFilter);
1509			} else {
1510				removeFilter();
1511			}
1512		};
1513
1514		if (settings.get('transition') === 'fade') {
1515			$box.fadeTo(speed, 0, function () {
1516				publicMethod.position(0, callback);
1517			});
1518		} else {
1519			publicMethod.position(speed, callback);
1520		}
1521	};
1522
1523	function load () {
1524		var href, setResize, prep = publicMethod.prep, $inline, request = ++requests;
1525
1526		active = true;
1527
1528		photo = false;
1529
1530		trigger(event_purge);
1531		trigger(event_load);
1532		settings.get('onLoad');
1533
1534		settings.h = settings.get('height') ?
1535				setSize(settings.get('height'), 'y') - loadedHeight - interfaceHeight :
1536				settings.get('innerHeight') && setSize(settings.get('innerHeight'), 'y');
1537
1538		settings.w = settings.get('width') ?
1539				setSize(settings.get('width'), 'x') - loadedWidth - interfaceWidth :
1540				settings.get('innerWidth') && setSize(settings.get('innerWidth'), 'x');
1541
1542		// Sets the minimum dimensions for use in image scaling
1543		settings.mw = settings.w;
1544		settings.mh = settings.h;
1545
1546		// Re-evaluate the minimum width and height based on maxWidth and maxHeight values.
1547		// If the width or height exceed the maxWidth or maxHeight, use the maximum values instead.
1548		if (settings.get('maxWidth')) {
1549			settings.mw = setSize(settings.get('maxWidth'), 'x') - loadedWidth - interfaceWidth;
1550			settings.mw = settings.w && settings.w < settings.mw ? settings.w : settings.mw;
1551		}
1552		if (settings.get('maxHeight')) {
1553			settings.mh = setSize(settings.get('maxHeight'), 'y') - loadedHeight - interfaceHeight;
1554			settings.mh = settings.h && settings.h < settings.mh ? settings.h : settings.mh;
1555		}
1556
1557		href = settings.get('href');
1558
1559		loadingTimer = setTimeout(function () {
1560			$loadingOverlay.show();
1561		}, 100);
1562
1563		if (settings.get('inline')) {
1564			var $target = $(href).eq(0);
1565			// Inserts an empty placeholder where inline content is being pulled from.
1566			// An event is bound to put inline content back when Colorbox closes or loads new content.
1567			$inline = $('<div>').hide().insertBefore($target);
1568
1569			$events.one(event_purge, function () {
1570				$inline.replaceWith($target);
1571			});
1572
1573			prep($target);
1574		} else if (settings.get('iframe')) {
1575			// IFrame element won't be added to the DOM until it is ready to be displayed,
1576			// to avoid problems with DOM-ready JS that might be trying to run in that iframe.
1577			prep(" ");
1578		} else if (settings.get('html')) {
1579			prep(settings.get('html'));
1580		} else if (isImage(settings, href)) {
1581
1582			href = retinaUrl(settings, href);
1583
1584			photo = settings.get('createImg');
1585
1586			$(photo)
1587			.addClass(prefix + 'Photo')
1588			.bind('error.'+prefix,function () {
1589				prep($tag(div, 'Error').html(settings.get('imgError')));
1590			})
1591			.one('load', function () {
1592				if (request !== requests) {
1593					return;
1594				}
1595
1596				// A small pause because some browsers will occassionaly report a
1597				// img.width and img.height of zero immediately after the img.onload fires
1598				setTimeout(function(){
1599					var percent;
1600
1601					if (settings.get('retinaImage') && window.devicePixelRatio > 1) {
1602						photo.height = photo.height / window.devicePixelRatio;
1603						photo.width = photo.width / window.devicePixelRatio;
1604					}
1605
1606					if (settings.get('scalePhotos')) {
1607						setResize = function () {
1608							photo.height -= photo.height * percent;
1609							photo.width -= photo.width * percent;
1610						};
1611						if (settings.mw && photo.width > settings.mw) {
1612							percent = (photo.width - settings.mw) / photo.width;
1613							setResize();
1614						}
1615						if (settings.mh && photo.height > settings.mh) {
1616							percent = (photo.height - settings.mh) / photo.height;
1617							setResize();
1618						}
1619					}
1620
1621					if (settings.h) {
1622						photo.style.marginTop = Math.max(settings.mh - photo.height, 0) / 2 + 'px';
1623					}
1624
1625					if ($related[1] && (settings.get('loop') || $related[index + 1])) {
1626						photo.style.cursor = 'pointer';
1627
1628						$(photo).bind('click.'+prefix, function () {
1629							publicMethod.next();
1630						});
1631					}
1632
1633					photo.style.width = photo.width + 'px';
1634					photo.style.height = photo.height + 'px';
1635					prep(photo);
1636				}, 1);
1637			});
1638
1639			photo.src = href;
1640
1641		} else if (href) {
1642			$loadingBay.load(href, settings.get('data'), function (data, status) {
1643				if (request === requests) {
1644					prep(status === 'error' ? $tag(div, 'Error').html(settings.get('xhrError')) : $(this).contents());
1645				}
1646			});
1647		}
1648	}
1649
1650	// Navigates to the next page/image in a set.
1651	publicMethod.next = function () {
1652		if (!active && $related[1] && (settings.get('loop') || $related[index + 1])) {
1653			index = getIndex(1);
1654			launch($related[index]);
1655		}
1656	};
1657
1658	publicMethod.prev = function () {
1659		if (!active && $related[1] && (settings.get('loop') || index)) {
1660			index = getIndex(-1);
1661			launch($related[index]);
1662		}
1663	};
1664
1665	// Note: to use this within an iframe use the following format: parent.jQuery.colorbox.close();
1666	publicMethod.close = function () {
1667		if (open && !closing) {
1668
1669			closing = true;
1670			open = false;
1671			trigger(event_cleanup);
1672			settings.get('onCleanup');
1673			$window.unbind('.' + prefix);
1674			$overlay.fadeTo(settings.get('fadeOut') || 0, 0);
1675
1676			$box.stop().fadeTo(settings.get('fadeOut') || 0, 0, function () {
1677				$box.hide();
1678				$overlay.hide();
1679				trigger(event_purge);
1680				$loaded.remove();
1681
1682				setTimeout(function () {
1683					closing = false;
1684					trigger(event_closed);
1685					settings.get('onClosed');
1686				}, 1);
1687			});
1688		}
1689	};
1690
1691	// Removes changes Colorbox made to the document, but does not remove the plugin.
1692	publicMethod.remove = function () {
1693		if (!$box) { return; }
1694
1695		$box.stop();
1696		$[colorbox].close();
1697		$box.stop(false, true).remove();
1698		$overlay.remove();
1699		closing = false;
1700		$box = null;
1701		$('.' + boxElement)
1702			.removeData(colorbox)
1703			.removeClass(boxElement);
1704
1705		$(document).unbind('click.'+prefix).unbind('keydown.'+prefix);
1706	};
1707
1708	// A method for fetching the current element Colorbox is referencing.
1709	// returns a jQuery object.
1710	publicMethod.element = function () {
1711		return $(settings.el);
1712	};
1713
1714	publicMethod.settings = defaults;
1715
1716}(jQuery, document, window));
1717;
1718(function ($) {
1719  Drupal.behaviors.pdf_reader_colorbox = {
1720    attach: function(context, settings) {
1721      $(".iframe").colorbox({iframe:true, width:"80%", height:"80%"});
1722    }}})(jQuery);;
1723/**
1724 * @file
1725 * Defines Javascript behaviors for MegaMenu frontend.
1726 */
1727
1728(function ($, Drupal, drupalSettings, once) {
1729  "use strict";
1730
1731  Drupal.TBMegaMenu = Drupal.TBMegaMenu || {};
1732
1733  Drupal.TBMegaMenu.oldWindowWidth = 0;
1734  Drupal.TBMegaMenu.displayedMenuMobile = false;
1735  Drupal.TBMegaMenu.supportedScreens = [980];
1736  Drupal.TBMegaMenu.focusableElements = 'a:not([disabled]), button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), details:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])';
1737  Drupal.TBMegaMenu.menuResponsive = function () {
1738    var windowWidth = window.innerWidth ? window.innerWidth : $(window).width();
1739    var navCollapse = $('.tb-megamenu').children('.nav-collapse');
1740    if (windowWidth < Drupal.TBMegaMenu.supportedScreens[0]) {
1741      navCollapse.addClass('collapse');
1742      if (Drupal.TBMegaMenu.displayedMenuMobile) {
1743        navCollapse.css({height: 'auto', overflow: 'visible'});
1744      }
1745      else {
1746        navCollapse.css({height: 0, overflow: 'hidden'});
1747      }
1748    }
1749    else {
1750      // If width of window is greater than 980 (supported screen).
1751      navCollapse.removeClass('collapse');
1752      if (navCollapse.height() <= 0) {
1753        navCollapse.css({height: 'auto', overflow: 'visible'});
1754      }
1755    }
1756  };
1757
1758  Drupal.TBMegaMenu.focusNextPrevElement = function (direction) {
1759    // Add all the elements we want to include in our selection
1760    var $current = $(document.activeElement);
1761
1762    if ($current.length) {
1763      var $focusable = $(Drupal.TBMegaMenu.focusableElements).filter(function () {
1764        var $this = $(this);
1765        return $this.closest('.tb-megamenu-subnav').length === 0 && $this.is(':visible');
1766      })
1767
1768      var index = $focusable.index($current);
1769      if (index > -1) {
1770        if (direction === 'next') {
1771          var nextElement = $focusable[index + 1] || $focusable[0];
1772        }
1773        else {
1774          var nextElement = $focusable[index - 1] || $focusable[0];
1775        }
1776
1777        nextElement.focus();
1778      }
1779    }
1780  }
1781
1782
1783  Drupal.behaviors.tbMegaMenuAction = {
1784    attach: function (context, settings) {
1785
1786      $(once('tb-megamenu', '.tb-megamenu', context)).each(function () {
1787
1788        /* Keyboard Control Setup */
1789        // Semi-Global Variables
1790        var navParent = document.querySelector('.tb-megamenu'),
1791            linkArray = new Array(),
1792            curPos = new Array(-1,-1,-1);
1793
1794        // Each Top-Level Link
1795        $(this).find('.level-1').children('a, span').not('.mobile-only').each(function (i, toplink) {
1796          linkArray[i] = new Array();
1797
1798          // Add Link to Array
1799          linkArray[i][-1] = toplink;
1800
1801          // Determine Coordinates
1802          $(toplink).data({ coordinate: [i, -1] });
1803
1804          // Each Column
1805          $(toplink).next().children().children().children('.mega-col-nav').each(function (j, column) {
1806            // Only add to the linkArray if menu items exist.
1807            // TODO - this does not allow for tabbing to links in blocks, only menu item links.
1808            if ($(column).find(Drupal.TBMegaMenu.focusableElements).length > 0) {
1809
1810              linkArray[i][j] = new Array();
1811
1812              // Each Link
1813              $(column).find(Drupal.TBMegaMenu.focusableElements).each(function (k, sublink) {
1814
1815                // Add Link to Array
1816                linkArray[i][j][k] = sublink;
1817
1818                // Determine Coordinates
1819                $(sublink).data({ coordinate: [i, j, k] });
1820              }); // each link
1821            }
1822
1823          }); // each column
1824
1825        }); // each top-level link
1826
1827        // Update Position on Focus
1828        $(this).find(Drupal.TBMegaMenu.focusableElements).focus(function () {
1829          curPos = $(this).data('coordinate');
1830        });
1831
1832        // Key Pressed
1833        function keydownEvent(k) {
1834          // Determine Key
1835          switch(k.keyCode) {
1836
1837            // TAB
1838            case 9:
1839              k.preventDefault();
1840              nav_tab(k);
1841              break;
1842
1843            // RETURN
1844            case 13:
1845              nav_open_link();
1846              break;
1847
1848            // ESC
1849            case 27:
1850              nav_esc();
1851              break;
1852
1853            // LEFT
1854            case 37:
1855              k.preventDefault();
1856              nav_left();
1857              break;
1858
1859            // UP
1860            case 38:
1861              k.preventDefault();
1862              nav_up();
1863              break;
1864
1865            // RIGHT
1866            case 39:
1867              k.preventDefault();
1868              nav_right();
1869              break;
1870
1871            // DOWN
1872            case 40:
1873              k.preventDefault();
1874              nav_down();
1875              break;
1876
1877            // HOME
1878            case 36:
1879              nav_home();
1880              break;
1881
1882            // END
1883            case 35:
1884              nav_end();
1885              break;
1886
1887            // Else
1888            default:
1889              // Do nothing
1890
1891          } // determine key
1892        } // keydownEvent
1893
1894        /* Keypress Functions */
1895        // Tab
1896        function nav_tab(k) {
1897          if (nav_is_toplink()) {
1898            if (k.shiftKey) {
1899              nav_prev_toplink();
1900            }
1901            else {
1902              nav_next_toplink();
1903            }
1904          }
1905          else {
1906            if (k.shiftKey) {
1907              nav_up();
1908            }
1909            else {
1910              nav_down();
1911            }
1912          }
1913        }
1914
1915        // Open Link
1916        function nav_open_link() {
1917          linkArray[curPos[0]][curPos[1]][curPos[2]].click();
1918        }
1919
1920        // Escape
1921        function nav_esc() {
1922          nav_close_megamenu();
1923        }
1924
1925        // Left
1926        function nav_left() {
1927          if (nav_is_toplink()) {
1928            nav_prev_toplink();
1929          }
1930          else {
1931            nav_prev_column();
1932          }
1933        }
1934
1935        // Right
1936        function nav_right() {
1937          if (nav_is_toplink()) {
1938            nav_next_toplink();
1939          }
1940          else {
1941            nav_next_column();
1942          }
1943        }
1944
1945        // Up
1946        function nav_up() {
1947          if (nav_is_toplink()) {
1948            nav_prev_toplink();
1949          }
1950          else {
1951            if (linkArray[curPos[0]][curPos[1]][curPos[2] - 1]) {
1952              // If the previous link in the array is hidden (ie, it's in a
1953              // submenu that is not currently expanded), then skip to the next
1954              // item in the array until we find one that's visible.
1955              if ($(linkArray[curPos[0]][curPos[1]][curPos[2] - 1]).is(':visible')) {
1956                linkArray[curPos[0]][curPos[1]][curPos[2] - 1].focus();
1957              }
1958              else {
1959                curPos = [curPos[0], curPos[1], curPos[2] - 1];
1960                nav_up();
1961              }
1962            }
1963            else {
1964              nav_prev_column();
1965            }
1966          }
1967        }
1968
1969        // Down
1970        function nav_down() {
1971          if (nav_is_toplink()) {
1972            nav_next_column();
1973          }
1974          else {
1975            if (linkArray[curPos[0]][curPos[1]][curPos[2] + 1]) {
1976              linkArray[curPos[0]][curPos[1]][curPos[2] + 1].focus();
1977            }
1978            else {
1979              nav_next_column();
1980            }
1981          }
1982        }
1983
1984        // Home Button
1985        function nav_home() {
1986          if (nav_is_toplink()) {
1987            linkArray[0][-1].focus();
1988          }
1989          else {
1990            linkArray[curPos[0]][0][0].focus();
1991          }
1992        }
1993
1994        // End Button
1995        function nav_end() {
1996          if (nav_is_toplink()) {
1997            linkArray.slice(-1)[0][-1].focus();
1998          }
1999          else {
2000            linkArray[curPos[0]].slice(-1)[0].slice(-1)[0].focus();
2001          }
2002        }
2003
2004        /* Helper Functions */
2005        // Determine Link Level
2006        function nav_is_toplink() {
2007          return (curPos[1] < 0);
2008        }
2009
2010        // Close Mega Menu
2011        function nav_close_megamenu() {
2012          $('.tb-megamenu .open').removeClass('open');
2013          ariaCheck();
2014        }
2015
2016        // Next Toplink
2017        function nav_next_toplink() {
2018          if (linkArray[curPos[0] + 1]) {
2019            linkArray[curPos[0] + 1][-1].focus();
2020          }
2021          else {
2022            nav_close_megamenu();
2023
2024            // Focus on the next element.
2025            Drupal.TBMegaMenu.focusNextPrevElement('next');
2026          }
2027        }
2028
2029        // Previous Toplink
2030        function nav_prev_toplink() {
2031          if (linkArray[curPos[0] - 1]) {
2032            linkArray[curPos[0] - 1][-1].focus();
2033          }
2034          else {
2035            // Focus on the previous element.
2036            Drupal.TBMegaMenu.focusNextPrevElement('prev');
2037          }
2038        }
2039
2040        // Previous Column
2041        function nav_prev_column() {
2042          if (linkArray[curPos[0]][curPos[1] - 1][0]) {
2043            linkArray[curPos[0]][curPos[1] - 1][0].focus();
2044          }
2045          else {
2046            nav_parent_toplink();
2047          }
2048        }
2049
2050        // Next Column
2051        function nav_next_column() {
2052          if (linkArray[curPos[0]][curPos[1] + 1]) {
2053            linkArray[curPos[0]][curPos[1] + 1][0].focus();
2054          }
2055          else {
2056            nav_parent_toplink();
2057          }
2058        }
2059
2060        // Go to Parent Toplink
2061        function nav_parent_toplink() {
2062          linkArray[curPos[0]][-1].focus();
2063        }
2064
2065        var ariaCheck = function () {
2066          $("li.tb-megamenu-item", this).each(function () {
2067            if ($(this).is('.mega-group')) {
2068              // Mega menu item has mega class (it's a true mega menu)
2069              if (!$(this).parents().is('.open')) {
2070                // Mega menu item has mega class and its ancestor is closed, so apply appropriate ARIA attributes
2071                $(this).children().attr('aria-expanded', 'false');
2072              }
2073              else if ($(this).parents().is('.open')) {
2074                // Mega menu item has mega class and its ancestor is o
2074pen, so apply appropriate ARIA attributes
2075                $(this).children().attr('aria-expanded', 'true');
2076              }
2077            }
2078            else if ($(this).is('.dropdown') || $(this).is('.dropdown-submenu')) {
2079              // Mega menu item has dropdown (it's a flyout menu)
2080              if (!$(this).is('.open')) {
2081                // Mega menu item has dropdown class and is closed, so apply appropriate ARIA attributes
2082                $(this).children().attr('aria-expanded', 'false');
2083              }
2084              else if ($(this).is('.open')) {
2085                // Mega menu item has dropdown class and is open, so apply appropriate ARIA attributes
2086                $(this).children().attr('aria-expanded', 'true');
2087              }
2088            }
2089            else {
2090              // Mega menu item is neither a mega or dropdown class, so remove ARIA attributes (it doesn't have children)
2091              $(this).children().removeAttr('aria-expanded');
2092            }
2093          });
2094        };
2095
2096        var showMenu = function ($subMenu, mm_timeout) {
2097          if ($subMenu.hasClass('mega')) {
2098            $subMenu.addClass('animating');
2099            clearTimeout($subMenu.data('animatingTimeout'));
2100            $subMenu.data('animatingTimeout', setTimeout(function () {
2101              $subMenu.removeClass('animating')
2102            }, mm_timeout));
2103            clearTimeout($subMenu.data('hoverTimeout'));
2104            $subMenu.data('hoverTimeout', setTimeout(function () {
2105              $subMenu.addClass('open');
2106              ariaCheck();
2107            }, 100));
2108          }
2109          else {
2110            clearTimeout($subMenu.data('hoverTimeout'));
2111            $subMenu.data('hoverTimeout',
2112                setTimeout(function () {
2113                  $subMenu.addClass('open');
2114                  ariaCheck();
2115                }, 100));
2116          }
2117        };
2118
2119        var hideMenu = function ($subMenu, mm_timeout) {
2120          $subMenu.children('.dropdown-toggle').attr('aria-expanded', 'false');
2121          if ($subMenu.hasClass('mega')) {
2122            $subMenu.addClass('animating');
2123            clearTimeout($subMenu.data('animatingTimeout'));
2124            $subMenu.data('animatingTimeout', setTimeout(function () {
2125              $subMenu.removeClass('animating')
2126            }, mm_timeout));
2127            clearTimeout($subMenu.data('hoverTimeout'));
2128            $subMenu.data('hoverTimeout', setTimeout(function () {
2129              $subMenu.removeClass('open');
2130              ariaCheck();
2131            }, 100));
2132          }
2133          else {
2134            clearTimeout($subMenu.data('hoverTimeout'));
2135            $subMenu.data('hoverTimeout', setTimeout(function () {
2136              $subMenu.removeClass('open');
2137              ariaCheck();
2138            }, 100));
2139          }
2140        };
2141
2142        $('.tb-megamenu-button', this).click(function () {
2143          if (parseInt($(this).parent().children('.nav-collapse').height())) {
2144            $(this).parent().children('.nav-collapse').css({height: 0, overflow: 'hidden'});
2145            Drupal.TBMegaMenu.displayedMenuMobile = false;
2146          }
2147          else {
2148            $(this).parent().children('.nav-collapse').css({height: 'auto', overflow: 'visible'});
2149            Drupal.TBMegaMenu.displayedMenuMobile = true;
2150          }
2151        });
2152
2153        var isTouch = window.matchMedia('(pointer: coarse)').matches;
2154
2155        if (!isTouch) {
2156          var mm_duration = 0;
2157
2158          $('.tb-megamenu', context).each(function () {
2159            if ($(this).data('duration')) {
2160              mm_duration = $(this).data('duration');
2161            }
2162          });
2163
2164          var mm_timeout = mm_duration ? 100 + mm_duration : 500;
2165          $('.nav > li, li.mega', context).bind('mouseenter', function (event) {
2166            showMenu($(this), mm_timeout);
2167          });
2168
2169          $('.nav > li > .dropdown-toggle, li.mega > .dropdown-toggle', context).bind('focus', function (event) {
2170            var $this = $(this);
2171            var $subMenu = $this.closest('li');
2172            showMenu($subMenu, mm_timeout);
2173            // If the focus moves outside of the subMenu, close it.
2174            $(document).bind('focusin', function (event) {
2175              if ($subMenu.has(event.target).length) {
2176                return;
2177              }
2178              $(document).unbind(event);
2179              hideMenu($subMenu, mm_timeout);
2180            });
2181          });
2182
2183          $('.nav > li, li.mega', context).bind('mouseleave', function (event) {
2184            hideMenu($(this), mm_timeout);
2185          });
2186
2187          /**
2188           * Allow tabbing by appending the open class.
2189           * Works in tandem with CSS changes that utilize opacity rather than
2190           * display none
2191           */
2192          // If the selected anchor is not in the TB Megamenu, remove all "open"
2193          // class occurrences
2194          $('a, span').focus(function (event) {
2195            if (!$(this).parent().hasClass('tb-megamenu-item') && !$(this).parents('.tb-megamenu-block').length) {
2196              nav_close_megamenu();
2197            }
2198          });
2199
2200          $('.nav > li > a, li.mega > a').focus(function (event) {
2201            // Remove all occurrences of "open" from other menu trees
2202            var siblings = $(this).parents('.tb-megamenu-item').siblings();
2203            // var siblings = $(this).closest('.tb-megamenu-item.level-1').siblings();
2204            $.each(siblings, function (i, v) {
2205              var cousins = $(v).find('.open');
2206              $.each(cousins, function (index, value) {
2207                $(value).removeClass('open');
2208                ariaCheck($(this));
2209              });
2210              $(v).removeClass('open');
2211              ariaCheck();
2212            });
2213            // Open the submenu if the selected item has one
2214            if ($(this).next(".tb-megamenu-submenu").length > 0) {
2215              if (!$(this).parent().hasClass("open")) {
2216                $(this).parent().addClass("open");
2217              }
2218            }
2219            // If the anchor's top-level parent is not open, open it
2220            if (!$(this).closest('.tb-megamenu-item.dropdown').hasClass('open') && $(this).closest('.tb-megamenu-item.dropdown').find('.tb-megamenu-submenu').length > 0) {
2221              $(this).closest('.tb-megamenu-item.dropdown').addClass('open');
2222              ariaCheck();
2223            }
2224            // If anchor's parent submenus are not open, open them
2225            var parents = $(this).parents('.tb-megamenu-item.dropdown-submenu');
2226            $.each(parents, function (i, v) {
2227              if (!$(v).hasClass('open')) {
2228                $(v).addClass('open');
2229                ariaCheck();
2230              }
2231            });
2232          });
2233        }
2234
2235        // Define actions for touch devices.
2236        var createTouchMenu = function (items) {
2237          items.children("a, span").each(function () {
2238            var $item = $(this);
2239            var tbitem = $(this).parent();
2240
2241            $item.click(function (event) {
2242              // If the menu link has already been clicked once...
2243              if ($item.hasClass("tb-megamenu-clicked")) {
2244                var $uri = $item.attr("href");
2245
2246                // If the menu link has a URI, go to the link.
2247                // <nolink> menu items will not have a URI.
2248                if ($uri) {
2249                  window.location.href = $uri;
2250                }
2251                else {
2252                  $item.removeClass("tb-megamenu-clicked");
2253                  hideMenu(tbitem, mm_timeout);
2254                }
2255              }
2256              else {
2257                event.preventDefault();
2258
2259                // Hide any already open menus.
2260                nav_close_megamenu();
2261                $(".tb-megamenu").find(".tb-megamenu-clicked").removeClass("tb-megamenu-clicked");
2262
2263                // Open the submenu.
2264                $item.addClass("tb-megamenu-clicked");
2265                showMenu(tbitem, mm_timeout);
2266              }
2267            });
2268          });
2269
2270          // Anytime there's a click outside the menu, close the menu.
2271          $(document).on('click', function (event) {
2272            if ($(event.target).closest('.tb-megamenu-nav').length === 0) {
2273              nav_close_megamenu();
2274              $(".tb-megamenu").find(".tb-megamenu-clicked").removeClass("tb-megamenu-clicked");
2275            };
2276          })
2277        };
2278
2279        if (isTouch) {
2280          createTouchMenu($(".tb-megamenu ul.nav li.mega", context).has(".dropdown-menu"));
2281        };
2282
2283        $(window).on('load resize', function () {
2284          var windowWidth = window.innerWidth ? window.innerWidth : $(window).width();
2285          if (windowWidth != Drupal.TBMegaMenu.oldWindowWidth) {
2286            Drupal.TBMegaMenu.oldWindowWidth = windowWidth;
2287            Drupal.TBMegaMenu.menuResponsive();
2288
2289            if (windowWidth >= Drupal.TBMegaMenu.supportedScreens[0]) {
2290              navParent.addEventListener('keydown',keydownEvent);
2291            }
2292            else {
2293              navParent.removeEventListener('keydown',keydownEvent);
2294            }
2295          }
2296        });
2297
2298      });
2299
2300    }
2301  }
2302})(jQuery, Drupal, drupalSettings, once);
2303;
2304((Drupal) => {
2305  'use strict';
2306
2307  /**
2308   * Factory for generating alert classes for different callback styles.
2309   *
2310   * Each alert style's ticker class is responsible for registering its type
2311   * with this factory.
2312   *
2313   * @type {{get(*): *, register(*, *): this}}
2314   */
2315  Drupal.alertFactory = (function () {
2316
2317    /**
2318     * Object of factory callbacks for each alert type, keyed by their
2319     * respective alert style names.
2320     *
2321     * @type {{}}
2322     */
2323    let callbacks = {};
2324
2325    /**
2326     * Return a factory object for registering and retrieving ticker classes.
2327     */
2328    return {
2329
2330      /**
2331       * Register's an alert style's factory callback.
2332       *
2333       * @param {string} type
2334       *  The name of the alert style for which to register a factory callback.
2335       * @param {function} callback
2336       *  The callback to invoke for generating an alert display class for this
2337       *  alert style.
2338       * @returns {Drupal.alertFactory}
2339       *  Reference to self.
2340       */
2341      register(type, callback) {
2342        if (typeof callback === 'function') {
2343          callbacks[type] = callback;
2344        }
2345        return this;
2346      },
2347
2348      /**
2349       * Returns the factory callback for the specified alert style.
2350       *
2351       * @param {string} type
2352       *  The name of the alert style for which to return a factory callback.
2353       * @returns {function}
2354       *  The factory callback that will return the ticker class for the
2355       *  specified ticker style.
2356       */
2357      get(type) {
2358        return callbacks[type];
2359      }
2360    }
2361  })();
2362})(Drupal);
2363;
2364((Drupal, undefined) => {
2365  'use strict';
2366
2367  /**
2368   * Represents a single, ticker-style alerts display.
2369   */
2370  class AlertsTicker {
2371
2372    /**
2373     * If TRUE, the current ticker is actively running.
2374     *
2375     * @type {boolean}
2376     */
2377    #running = false;
2378
2379    /**
2380     * Index of the alert that is currently displayed or will be displayed when
2381     * the ticker starts.
2382     *
2383     * @type {number}
2384     */
2385    #current = 0;
2386
2387    /**
2388     * The ID of the currently running setTimeout() invocation.
2389     *
2390     * @type {int}
2391     */
2392    #timeoutId;
2393
2394    /**
2395     * Reference to the promise chain that controls the ticker animations.
2396     *
2397     * @type {Promise}
2398     */
2399    animationChain;
2400
2401    /**
2402     * True if the next/prev pagers should do nothing (e.g. if the ticker is
2403     * currently advancing to the next alert item).
2404     *
2405     * @type {boolean}
2406     */
2407    pagerLocked = false;
2408
2409    /**
2410     * Constructs a new AlertsTicker object.
2411     *
2412     * @param {HTMLElement} ticker
2413     *  Reference to the outermost element that represents this ticker display.
2414     * @param {{}} selectors
2415     *  Object of selectors for identifying:
2416     *    - The element that acts as the direct container for the individual
2417     *      alert items.
2418     *    - The counter element.
2419     *    - The clickable element to display the previous alert.
2420     *    - The clickable element to display the next alert.
2421     * @param {{}} alerts
2422     *  An object whose keys are HTML IDs that identify individual alert items,
2423     *  and whose values are each objects containing the following configuration
2424     *  data per alert item:
2425     *    - delay: The number of milliseconds that a given alert item should be
2426     *      displayed before advancing to the next alert item.
2427     */
2428    constructor(ticker, selectors, alerts, ) {
2429      this.ticker = ticker;
2430      this.container = document.querySelector(selectors.container);
2431      this.counter = document.querySelector(selectors.counter);
2432      this.pager = {
2433        'prev': document.querySelector(selectors.prev),
2434        'next': document.querySelector(selectors.next)
2435      };
2436
2437      /**
2438       * Set up AlertItem objects, each with doubly-linked references.
2439       */
2440      this.alerts = [];
2441      Object.keys(alerts).forEach(id => {
2442        const
2443          alert = new AlertItem(id, alerts[id], this),
2444          sequence = this.alerts.push(alert)
2445        ;
2446        alert.sequence = sequence;
2447        if (sequence > 1) {
2448          // Create linked references between immediate siblings.
2449          const prev = this.alerts[sequence - 2];
2450          alert.prev = prev;
2451          prev.next = alert;
2452        }
2453      });
2454      // Make the associations circular.
2455      this.alerts[ this.#lastIndex() ].next = this.alerts[0];
2456      this.alerts[0].prev = this.alerts[ this.#lastIndex() ];
2457
2458      /**
2459       * Set up prev/next event handlers.
2460       */
2461      this.pager.next.onclick = e => {
2462        if (this.pagerLocked) {
2463          return;
2464        }
2465        this.animationChain = this.animationChain
2466          .then(() => this.cancel())
2467          .then(() => this.#doAdvance());
2468      }
2469      this.pager.prev.onclick = e => {
2470        if (this.pagerLocked) {
2471          return;
2472        }
2473        this.animationChain = this.animationChain
2474          .then(() => this.cancel())
2475          .then(() => this.#doAdvance(true));
2476      }
2477    }
2478
2479    /**
2480     * Returns a reference to the current alert item.
2481     *
2482     * @returns {AlertItem}
2483     */
2484    current () {
2485      return this.alerts[this.#current];
2486    }
2487
2488    /**
2489     * Advances the current marker to the next alert item in sequence and
2490     * returns a reference to that alert item.
2491     *
2492     * @returns {AlertItem}
2493     */
2494    next () {
2495      this.#current = (this.#current < this.#lastIndex())
2496        ? this.#current + 1
2497        : 0;
2498      return this.current();
2499    }
2500
2501    /**
2502     * Advances the current marker to the previous alert item in sequence and
2503     * returns a reference to that alert item.
2504     *
2505     * @returns {AlertItem}
2506     */
2507    prev () {
2508      this.#current = (this.#current > 0)
2509        ? this.#current - 1
2510        : this.#lastIndex();
2511      return this.current();
2512    }
2513
2514    /**
2515     * Calls .next() or .prev(), based on the value of reverse, and returns the
2516     * resultant value.
2517     *
2518     * @param reverse
2519     *  TRUE if .prev() should be returned. Otherwise, .next() will be returned.
2520     * @returns {AlertItem}
2521     *  Reference to the newly queued AlertItem.
2522     */
2523    #page (reverse = false) {
2524      return reverse ? this.prev() : this.next();
2525    }
2526
2527    /**
2528     * Begin the ticker animation sequence.
2529     *
2530     * @returns {AlertsTicker}
2531     *  Reference to self.
2532     */
2533    start () {
2534      if (this.#running) {
2535        return this;
2536      }
2537      this.animationChain = new Promise((resolve, reject) => {
2538        this.current().display()
2539        resolve(this);
2540      }).then(() => this.advance());
2541      this.#running = true;
2542      return this;
2543    }
2544
2545    /**
2546     * Sets an animation timer for the next ticker transition and returns the
2547     * promise that will resolve when the timer expires.
2548     *
2549     * @returns {Promise<unknown>}
2550     *  A promise that resolves when the timer expires.
2551     */
2552    advance () {
2553      return new Promise((resolve, reject) => {
2554        this.#timeoutId = setTimeout(() => {
2555          this.#doAdvance();
2556          return resolve(this.current());
2557        }, this.current().settings.delay)
2558      });
2559    }
2560
2561    /**
2562     * Returns a promise that resolves by hiding the current alert and advancing
2563     * the next alert into the display.
2564     *
2565     * @param reverse
2566     *  True if the previous alert should be advanced. Otherwise, the next alert
2567     *  will advance.
2568     * @returns {Promise<unknown>}
2569     *  A promise that resolves once the transition sequence has been inited.
2570     */
2571    #doAdvance (reverse = false) {
2572      return new Promise((resolve, reject) => {
2573        this.current().hide(reverse)
2574          .then(() => this.#page(reverse).display(reverse))
2575          .then(() => this.advance());
2576        resolve(this.current());
2577      });
2578    }
2579
2580    /**
2581     * Clears the current setTimeout() invocation and returns an immediately
2582     * resolved promise.
2583     *
2584     * @returns {Promise<unknown>}
2585     */
2586    cancel () {
2587      clearTimeout(this.#timeoutId);
2588      return new Promise((resolve, reject) => {
2589        resolve(this.current());
2590      });
2591    }
2592
2593    /**
2594     * Returns an immediately resolved promise that sets the current pager
2595     * sequence value in the ticker's pager.
2596     *
2597     * @returns {AlertsTicker}
2598     *  Reference to self.
2599     */
2600    setSequence () {
2601      this.counter.textContent = this.current().sequence
2602      return this;
2603    }
2604
2605    /**
2606     * Returns the ordinal index number that represents the last alert in the
2607     * alerts[] property array.
2608     *
2609     * @returns {number}
2610     */
2611    #lastIndex () {
2612      return this.alerts.length - 1;
2613    }
2614
2615  }
2616
2617  /**
2618   * Represents a single alert display item.
2619   */
2620  class AlertItem {
2621
2622    /**
2623     * The render classes to apply to the alert item's element on every class
2624     * name change.
2625     *
2626     * @type {[]}
2627     */
2628    #baseClasses = [];
2629
2630    /**
2631     * The sequence number of this alert item.
2632     *
2633     * @type {number}
2634     */
2635    sequence;
2636
2637    /**
2638     * Reference to the AlertItem that precedes this AlertItem in the sequence.
2639     *
2640     * @type {AlertItem}
2641     */
2642    prev;
2643
2644    /**
2645     * Reference to the AlertItem that follows this AlertItem in the sequence.
2646     *
2647     * @type {AlertItem}
2648     */
2649    next;
2650
2651    /**
2652     * Constructs a new AlertItem object.
2653     *
2654     * @param {string} id
2655     *  The HTML ID of the element that this alert item represents.
2656     * @param {[]} settings
2657     *  An object of settings, with the following key/value pairs:
2658     *    - delay: The number of milliseconds to display this Alert before
2659     *      cycling to the next alert in sequence.
2660     * @param {AlertsTicker} parent
2661     *  Reference to the parent ticker object.
2662     */
2663    constructor(id, settings, parent) {
2664      this.parent = parent;
2665      this.id = id;
2666      this.element = document.getElementById(id);
2667      this.settings = settings;
2668      this.oscillator = new Oscillator(
2669        this.parent.container,
2670        this.element.querySelector('.alert-message'),
2671        this.settings.delay
2672      );
2673      this.#baseClasses = this
2674        .element.className
2675        .replace('hidden', '')
2676        .split(' ');
2677      this.#baseClasses.push('animate__animated');
2678    }
2679
2680    /**
2681     * Animates this alert item entering the display container from the left.
2682     *
2683     * @param reverse
2684     *  If true, the animation enters from the right.
2685     * @returns {Promise}
2686     *  Reference to self.
2687     */
2688    display (reverse = false) {
2689      return new Promise((resolve, reject) => {
2690        this.element.addEventListener('animationend', () => {
2691          this.reset();
2692          this.parent.pagerLocked = false;
2693          return resolve(this);
2694        }, {once: true});
2695        this.parent.pagerLocked = true;
2696        this.element.className = this.#concatClasses(Animation.getShow(reverse));
2697        this.parent.setSequence();
2698        this.oscillator
2699          .animate()
2700          .monitorResize();
2701      });
2702    }
2703
2704    /**
2705     * Animates this alert item exiting the display container to the right.
2706     *
2707     * @param reverse
2708     *  If true, the animation exits to the left.
2709     * @returns {Promise}
2710     *  Reference to self.
2711     */
2712    hide (reverse = false) {
2713      return new Promise((resolve, reject) => {
2714        this.element.addEventListener('animationend', () => {
2715          this.parent.pagerLocked = false;
2716          return resolve(this);
2717        }, {once: true});
2718        this.parent.pagerLocked = true;
2719        this.element.className = this
2720          .#concatClasses(Animation.getHide(reverse)).concat(' animate__fast');
2721        this.oscillator.clear();
2722      });
2723    }
2724
2725    /**
2726     * Resets this AlertItem's element's class string to this alert's base
2727     * classes.
2728     *
2729     * @returns {AlertItem}
2730     *  Reference to self.
2731     */
2732    reset () {
2733      this.element.className = this.#baseClasses.join(' ');
2734      return this;
2735    }
2736
2737    /**
2738     * Returns the classes to apply based on the specified operation.
2739     *
2740     * @param {string} op_class
2741     *  The operation class to concatenate with the base classes.
2742     * @returns {string}
2743     *  Returns the space-delimited list of classes to apply.
2744     */
2745    #concatClasses (op_class) {
2746      return this.#baseClasses.concat(op_class).join(' ');
2747    }
2748
2749  }
2750
2751  /**
2752   * Static class that acts as a canonical enum for animation classes.
2753   *
2754   * @see library.animate.css in cwb_alerts.libraries.yml
2755   */
2756  class Animation {
2757    static ShowNext = new Animation('animate__fadeInLeftBig');
2758    static ShowPrev = new Animation('animate__fadeInRightBig');
2759    static HideNext = new Animation('animate__fadeOutRightBig');
2760    static HidePrev = new Animation('animate__fadeOutLeftBig');
2761
2762    constructor (name) {
2763      this.name = name;
2764    }
2765
2766    /**
2767     * Returns the class to animate an alert item into the ticker display from
2768     * the left.
2769     *
2770     * @param reverse
2771     *  True if the ticker should animate in from the right.
2772     * @returns {string}
2773     */
2774    static getShow (reverse = false) {
2775      return reverse ? Animation.ShowPrev.name : Animation.ShowNext.name
2776    }
2777
2778    /**
2779     * Returns the class to animate an alert item out of the ticker display to
2780     * the right.
2781     *
2782     * @param reverse
2783     *  True if the ticker should animate out to the left.
2784     * @returns {string}
2785     */
2786    static getHide (reverse = false) {
2787      return reverse ? Animation.HidePrev.name : Animation.HideNext.name;
2788    }
2789
2790  }
2791
2792  /**
2793   * An object for managing alert messages that are longer than their container.
2794   * When an alert message is detected to be longer than its enclosing element,
2795   * it will be horizontally oscillated back and forth.
2796   */
2797  class Oscillator {
2798
2799    /**
2800     * Amount of overflow, in pixels, that needs to be oscillated.
2801     *
2802     * @type {number}
2803     */
2804    #overflow;
2805
2806    /**
2807     * The transition time for each oscillation.
2808     *
2809     * @type {number}
2810     */
2811    #animationSpeed;
2812
2813    /**
2814     * The original CSS transition value for this oscillator's element.
2815     *
2816     * @type {string}
2817     */
2818    #originalTransition;
2819
2820    /**
2821     * The original CSS margin-left value for this oscillator's element.
2822     *
2823     * @type {string}
2824     */
2825    #originalMarginLeft;
2826
2827    /**
2828     * A canvas object that provides a computational manifold that does not
2829     * result in DOM reflow.
2830     *
2831     * @type {HTMLCanvasElement}
2832     */
2833    #canvas = document.createElement("canvas");
2834
2835    /**
2836     * Constructs a new oscillator object.
2837     *
2838     * @param {HTMLElement} textContainer
2839     *  Reference to the element that acts as the enclosing container for all
2840     *  alerts.
2841     * @param {HTMLElement} textElement
2842     *  Reference to a specific element whose content should be oscillated
2843     *  within the enclosing container.
2844     * @param {number} delay
2845     *  The number of seconds that this alert will be displayed.
2846     */
2847    constructor (textContainer, textElement, delay) {
2848      this.container = textContainer;
2849      this.element = textElement;
2850      this.delay = delay;
2851      this.#originalTransition = this.element.style.transition;
2852      this.#originalMarginLeft = this.element.style.marginLeft;
2853    }
2854
2855    /**
2856     * Returns the CSS computed value for a specific CSS style.
2857     *
2858     * @param {string} property
2859     *  The name of the CSS property whose computed value should be returned.
2860     * @returns {string}
2861     *  The computed CSS value.
2862     */
2863    #getComputedStyle (property) {
2864      return window.getComputedStyle(this.element, null)
2865        .getPropertyValue(property);
2866    }
2867
2868    /**
2869     * Returns a canvas context whose font has been set to the same as the
2870     * current text element.
2871     *
2872     * @returns {CanvasRenderingContext2D}
2873     *  Canvas rendering context.
2874     */
2875    #getFontContext () {
2876      const context = this.#canvas.getContext("2d");
2877      context.font = this.#getComputedStyle('font');
2878      return context;
2879    }
2880
2881    /**
2882     * Returns the width, in pixels, of the container element.
2883     *
2884     * @returns {number}
2885     *  The pixel width of the container element.
2886     */
2887    getContainerWidth () {
2888      return this.container.offsetWidth;
2889    }
2890
2891    /**
2892     * Returns the width, in pixels, of the text element's text content.
2893     *
2894     * @returns {number}
2895     *  The pixel width of the text element's text content.
2896     */
2897    getTextWidth () {
2898      const context = this.#getFontContext();
2899      const metrics = context.measureText(this.element.textContent);
2900      return metrics.width;
2901    }
2902
2903    /**
2904     * Returns the number of pixels difference between the container element and
2905     * the text element. Positive values indicate surplus space in the
2906     * container; negative values indicate overflowing text.
2907     *
2908     * @returns {number}
2909     *  The number of pixels difference between container and text element
2910     *  width.
2911     */
2912    overflow () {
2913      return this.getContainerWidth() - this.getTextWidth();
2914    }
2915
2916    /**
2917     * Detects any text overflow and animates an oscillation of necessary.
2918     *
2919     * @returns {Oscillator}
2920     *  Reference to self.
2921     */
2922    animate () {
2923      this.#calculate();
2924      if (this.#overflow >= 0) {
2925        return this;
2926      }
2927      const delay = '0.5'; //Math.min(2, this.#animationSpeed);
2928      this.element.style.transition = this
2929        .#originalTransition
2930        .concat(` margin-left ${this.#animationSpeed}s ease-in-out 2s`);
2931      this.element.style.marginLeft = this.#getMarginLeft(this.element.direction);
2932      this.toggleOscillation = e => {
2933        e.target.direction *= -1;
2934        e.target.style.marginLeft = this.#getMarginLeft(e.target.direction);
2935      };
2936      this.element.addEventListener('transitionend', this.toggleOscillation);
2937      return this;
2938    }
2939
2940    /**
2941     * Invokes a window resize event listener in order that will respond to
2942     * resize events be re-calculating the overflow and transition time.
2943     *
2944     * @returns {Oscillator}
2945     *  Reference to self.
2946     */
2947    monitorResize () {
2948      this.listenResize = Drupal.debounce(() => {
2949        this.element.removeEventListener('transitionend', this.toggleOscillation);
2950        this.animate();
2951      }, 300);
2952      window.addEventListener('resize', this.listenResize);
2953      return this;
2954    }
2955
2956    /**
2957     * Clears all oscillation animations for this container/text element pair.
2958     *
2959     * @returns {Oscillator}
2960     *  Reference to self.
2961     */
2962    clear () {
2963      this.element.style.transition = this.#originalTransition;
2964      this.element.style.marginLeft = this.#originalMarginLeft;
2965      this.element.direction = 1;
2966      this.element.removeEventListener('transitionend', this.toggleOscillation);
2967      window.removeEventListener('resize', this.listenResize)
2968      return this;
2969    }
2970
2971    /**
2972     * Calculates the overflow and animation speed and stores those values in
2973     * private local properties.
2974     *
2975     * @returns {Oscillator}
2976     *  Reference ot self.
2977     */
2978    #calculate () {
2979      this.#overflow = Math.min(this.overflow() - this.#totalPadding(), 0);
2980      if (this.#overflow >= 0) {
2981        return this;
2982      }
2983      this.#animationSpeed = Math.min(Math.max(
2984        (this.delay / 1000) - 3,
2985      1), 10);
2986      return this;
2987    }
2988
2989    /**
2990     * Returns an appropriate margin left values based on the direction of
2991     * oscillation.
2992     *
2993     * @param {number} direction
2994     *  A value of 1 for the initial oscillation direction (left to right), or
2995     *  -1 for the reverse oscillation (right to left).
2996     * @returns {string}
2997     *  A valid CSS value for the margin-left property.
2998     */
2999    #getMarginLeft (direction = 1) {
3000      return direction > 0 ? `${this.#overflow}px` : '0';
3001    }
3002
3003    /**
3004     * Returns the total width of the text element's left and right padding.
3005     *
3006     * @returns {number}
3007     *  Number of total pixels of left and right padding.
3008     */
3009    #totalPadding () {
3010      return parseInt(this.#getComputedStyle('padding-left'))
3011        + parseInt(this.#getComputedStyle('padding-right'));
3012    }
3013
3014    /**
3015     * Returns the current font size for the text element.
3016     *
3017     * @returns {number}
3018     *  The pixel size of the text element's font.
3019     */
3020    #fontSize () {
3021      return parseInt(this.#getComputedStyle('font-size'));
3022    }
3023
3024  }
3025
3026  // Register the AlertsTicker class with the alertFactory.
3027  Drupal.alertFactory
3028    .register('ticker', (ticker, selectors, alerts) => {
3029      return new AlertsTicker(ticker, selectors, alerts);
3030    });
3031})(Drupal);
3032;
3033(function ($, undefined) {
3034  'use strict';
3035
3036  /**
3037   * Attach ticker alerts behavior.
3038   *
3039   * @type {Drupal~behavior}
3040   *
3041   * @prop {Drupal~behaviorAttach} attach
3042   *  Initializes the ticker's operation for each instance on page.
3043   *
3044   */
3045  Drupal.behaviors.cwb_alerts_ticker = {
3046    attach: function (context, settings) {
3047      $('body').once('cwb-alerts-ticker').each(function () {
3048        const
3049          _settings = settings.cwb_alerts_ticker,
3050          selectors = _settings.selectors,
3051          alerts = _settings.data.alerts
3052        ;
3053        $(selectors.ticker, context).each(function () {
3054          const alerts_ticker = Drupal.alertFactory
3055            .get('ticker')(this, selectors, alerts);
3056          alerts_ticker.start();
3057        });
3058      });
3059    }
3060  }
3061})(jQuery);
3062;

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.