PageSourceSearch

https://www.phoenix.gov/etc.clientlibs/phx/clientlibs/clientlib-ba…-53907a01560660166323aab7b2852b54-lc.min.js

js phoenix.gov collected 2026-09-24 08:28:38 UTC 123,445 bytes, 3,270 lines download raw bytes

1/*******************************************************************************
2 * Copyright 2019 Adobe
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 ******************************************************************************/
16
17/**
18 * Element.matches()
19 * https://developer.mozilla.org/enUS/docs/Web/API/Element/matches#Polyfill
20 */
21if (!Element.prototype.matches) {
22    Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
23}
24
25// eslint-disable-next-line valid-jsdoc
26/**
27 * Element.closest()
28 * https://developer.mozilla.org/enUS/docs/Web/API/Element/closest#Polyfill
29 */
30if (!Element.prototype.closest) {
31    Element.prototype.closest = function(s) {
32        "use strict";
33        var el = this;
34        if (!document.documentElement.contains(el)) {
35            return null;
36        }
37        do {
38            if (el.matches(s)) {
39                return el;
40            }
41            el = el.parentElement || el.parentNode;
42        } while (el !== null && el.nodeType === 1);
43        return null;
44    };
45}
46
47/*******************************************************************************
48 * Copyright 2019 Adobe
49 *
50 * Licensed under the Apache License, Version 2.0 (the "License");
51 * you may not use this file except in compliance with the License.
52 * You may obtain a copy of the License at
53 *
54 *     http://www.apache.org/licenses/LICENSE-2.0
55 *
56 * Unless required by applicable law or agreed to in writing, software
57 * distributed under the License is distributed on an "AS IS" BASIS,
58 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
59 * See the License for the specific language governing permissions and
60 * limitations under the License.
61 ******************************************************************************/
62(function() {
63    "use strict";
64
65    var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined;
66    if (!containerUtils) {
67        // eslint-disable-next-line no-console
68        console.warn("Accordion: container utilities at window.CQ.CoreComponents.container.utils are not available. This can lead to missing features. Ensure the core.wcm.components.commons.site.container client library is included on the page.");
69    }
70    var dataLayerEnabled;
71    var dataLayer;
72    var dataLayerName;
73    var delay = 100;
74
75    var NS = "cmp";
76    var IS = "accordion";
77
78    var keyCodes = {
79        ENTER: 13,
80        SPACE: 32,
81        END: 35,
82        HOME: 36,
83        ARROW_LEFT: 37,
84        ARROW_UP: 38,
85        ARROW_RIGHT: 39,
86        ARROW_DOWN: 40
87    };
88
89    var selectors = {
90        self: "[data-" + NS + '-is="' + IS + '"]'
91    };
92
93    var cssClasses = {
94        button: {
95            disabled: "cmp-accordion__button--disabled",
96            expanded: "cmp-accordion__button--expanded"
97        },
98        panel: {
99            hidden: "cmp-accordion__panel--hidden",
100            expanded: "cmp-accordion__panel--expanded"
101        }
102    };
103
104    var dataAttributes = {
105        item: {
106            expanded: "data-cmp-expanded"
107        }
108    };
109
110    var properties = {
111        /**
112         * Determines whether a single accordion item is forced to be expanded at a time.
113         * Expanding one item will collapse all others.
114         *
115         * @memberof Accordion
116         * @type {Boolean}
117         * @default false
118         */
119        "singleExpansion": {
120            "default": false,
121            "transform": function(value) {
122                return !(value === null || typeof value === "undefined");
123            }
124        }
125    };
126
127    /**
128     * Accordion Configuration.
129     *
130     * @typedef {Object} AccordionConfig Represents an Accordion configuration
131     * @property {HTMLElement} element The HTMLElement representing the Accordion
132     * @property {Object} options The Accordion options
133     */
134
135    /**
136     * Accordion.
137     *
138     * @class Accordion
139     * @classdesc An interactive Accordion component for toggling panels of related content
140     * @param {AccordionConfig} config The Accordion configuration
141     */
142    function Accordion(config) {
143        var that = this;
144
145        if (config && config.element) {
146            init(config);
147        }
148
149        /**
150         * Initializes the Accordion.
151         *
152         * @private
153         * @param {AccordionConfig} config The Accordion configuration
154         */
155        function init(config) {
156            that._config = config;
157
158            // prevents multiple initialization
159            config.element.removeAttribute("data-" + NS + "-is");
160
161            setupProperties(config.options);
162            cacheElements(config.element);
163
164            if (that._elements["item"]) {
165                // ensures multiple element types are arrays.
166                that._elements["item"] = Array.isArray(that._elements["item"]) ? that._elements["item"] : [that._elements["item"]];
167                that._elements["button"] = Array.isArray(that._elements["button"]) ? that._elements["button"] : [that._elements["button"]];
168                that._elements["panel"] = Array.isArray(that._elements["panel"]) ? that._elements["panel"] : [that._elements["panel"]];
169
170                if (that._properties.singleExpansion) {
171                    var expandedItems = getExpandedItems();
172                    // multiple expanded items annotated, display the last item open.
173                    if (expandedItems.length > 1) {
174                        toggle(expandedItems.length - 1);
175                    }
176                }
177
178                refreshItems();
179                bindEvents();
180                scrollToDeepLinkIdInAccordion();
181            }
182            if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) {
183                /*
184                 * Editor message handling:
185                 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
186                 * - check that the message data panel container type is correct and that the id (path) matches this specific Accordion component
187                 * - if so, route the "navigate" operation to enact a navigation of the Accordion based on index data
188                 */
189                window.CQ.CoreComponents.MESSAGE_CHANNEL = window.CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window);
190                window.CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) {
191                    if (message.data && message.data.type === "cmp-accordion" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) {
192                        if (message.data.operation === "navigate") {
193                            // switch to single expansion mode when navigating in edit mode.
194                            var singleExpansion = that._properties.singleExpansion;
195                            that._properties.singleExpansion = true;
196                            toggle(message.data.index);
197
198                            // revert to the configured state.
199                            that._properties.singleExpansion = singleExpansion;
200                        }
201                    }
202                });
203            }
204        }
205
206        /**
207         * Displays the panel containing the element that corresponds to the deep link in the URI fragment
208         * and scrolls the browser to this element.
209         */
210        function scrollToDeepLinkIdInAccordion() {
211            if (containerUtils) {
212                var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "item", "item");
213                if (deepLinkItemIdx > -1) {
214                    var deepLinkItem = that._elements["item"][deepLinkItemIdx];
215                    if (deepLinkItem && !deepLinkItem.hasAttribute(dataAttributes.item.expanded)) {
216                        // if single expansion: close all accordion items
217                        if (that._properties.singleExpansion) {
218                            for (var j = 0; j < that._elements["item"].length; j++) {
219                                if (that._elements["item"][j].hasAttribute(dataAttributes.item.expanded)) {
220                                    setItemExpanded(that._elements["item"][j], false, true);
221                                }
222                            }
223                        }
224                        // expand the accordion item containing the deep link
225                        setItemExpanded(deepLinkItem, true, true);
226                    }
227                    var hashId = window.location.hash.substring(1);
228                    if (hashId) {
229                        var hashItem = document.querySelector("[id='" + hashId + "']");
230                        if (hashItem) {
231                            hashItem.scrollIntoView();
232                        }
233                    }
234                }
235            }
236        }
237
238        /**
239         * Caches the Accordion elements as defined via the {@code data-accordion-hook="ELEMENT_NAME"} markup API.
240         *
241         * @private
242         * @param {HTMLElement} wrapper The Accordion wrapper element
243         */
244        function cacheElements(wrapper) {
245            that._elements = {};
246            that._elements.self = wrapper;
247            var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
248
249            for (var i = 0; i < hooks.length; i++) {
250                var hook = hooks[i];
251                if (hook.closest("." + NS + "-" + IS) === that._elements.self) { // only process own accordion elements
252                    var capitalized = IS;
253                    capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
254                    var key = hook.dataset[NS + "Hook" + capitalized];
255                    if (that._elements[key]) {
256                        if (!Array.isArray(that._elements[key])) {
257                            var tmp = that._elements[key];
258                            that._elements[key] = [tmp];
259                        }
260                        that._elements[key].push(hook);
261                    } else {
262                        that._elements[key] = hook;
263                    }
264                }
265            }
266        }
267
268        /**
269         * Sets up properties for the Accordion based on the passed options.
270         *
271         * @private
272         * @param {Object} options The Accordion options
273         */
274        function setupProperties(options) {
275            that._properties = {};
276
277            for (var key in properties) {
278                if (Object.prototype.hasOwnProperty.call(properties, key)) {
279                    var property = properties[key];
280                    var value = null;
281
282                    if (options && options[key] != null) {
283                        value = options[key];
284
285                        // transform the provided option
286                        if (property && typeof property.transform === "function") {
287                            value = property.transform(value);
288                        }
289                    }
290
291                    if (value === null) {
292                        // value still null, take the property default
293                        value = properties[key]["default"];
294                    }
295
296                    that._properties[key] = value;
297                }
298            }
299        }
300
301        /**
302         * Binds Accordion event handling.
303         *
304         * @private
305         */
306        function bindEvents() {
307            window.addEventListener("hashchange", scrollToDeepLinkIdInAccordion, false);
308            var buttons = that._elements["button"];
309            if (buttons) {
310                for (var i = 0; i < buttons.length; i++) {
311                    (function(index) {
312                        buttons[i].addEventListener("click", function(event) {
313                            toggle(index);
314                            focusButton(index);
315                        });
316                        buttons[i].addEventListener("keydown", function(event) {
317                            onButtonKeyDown(event, index);
318                        });
319                    })(i);
320                }
321            }
322        }
323
324        /**
325         * Handles button keydown events.
326         *
327         * @private
328         * @param {Object} event The keydown event
329         * @param {Number} index The index of the button triggering the event
330         */
331        function onButtonKeyDown(event, index) {
332            var lastIndex = that._elements["button"].length - 1;
333
334            switch (event.keyCode) {
335                case keyCodes.ARROW_LEFT:
336                case keyCodes.ARROW_UP:
337                    event.preventDefault();
338                    if (index > 0) {
339                        focusButton(index - 1);
340                    }
341                    break;
342                case keyCodes.ARROW_RIGHT:
343                case keyCodes.ARROW_DOWN:
344                    event.preventDefault();
345                    if (index < lastIndex) {
346                        focusButton(index + 1);
347                    }
348                    break;
349                case keyCodes.HOME:
350                    event.preventDefault();
351                    focusButton(0);
352                    break;
353                case keyCodes.END:
354                    event.preventDefault();
355                    focusButton(lastIndex);
356                    break;
357                case keyCodes.ENTER:
358                case keyCodes.SPACE:
359                    event.preventDefault();
360                    toggle(index);
361                    focusButton(index);
362                    break;
363                default:
364                    return;
365            }
366        }
367
368        /**
369         * General handler for toggle of an item.
370         *
371         * @private
372         * @param {Number} index The index of the item to toggle
373         */
374        function toggle(index) {
375            var item = that._elements["item"][index];
376            if (item) {
377                if (that._properties.singleExpansion) {
378                    // ensure only a single item is expanded if single expansion is enabled.
379                    for (var i = 0; i < that._elements["item"].length; i++) {
380                        if (that._elements["item"][i] !== item) {
381                            var expanded = getItemExpanded(that._elements["item"][i]);
382                            if (expanded) {
383                                setItemExpanded(that._elements["item"][i], false);
384                            }
385                        }
386                    }
387                }
388                setItemExpanded(item, !getItemExpanded(item));
389
390                if (dataLayerEnabled) {
391                    var accordionId = that._elements.self.id;
392                    var expandedItems = getExpandedItems()
393                        .map(function(item) {
394                            return getDataLayerId(item);
395                        });
396
397                    var uploadPayload = { component: {} };
398                    uploadPayload.component[accordionId] = { shownItems: expandedItems };
399
400                    var removePayload = { component: {} };
401                    removePayload.component[accordionId] = { shownItems: undefined };
402
403                    dataLayer.push(removePayload);
404                    dataLayer.push(uploadPayload);
405                }
406            }
407        }
408
409        /**
410         * Sets an item's expanded state based on the provided flag and refreshes its internals.
411         *
412         * @private
413         * @param {HTMLElement} item The item to mark as expanded, or not expanded
414         * @param {Boolean} expanded true to mark the item expanded, false otherwise
415         * @param {Boolean} keepHash true to keep the hash in the URL, false to update it
416         */
417        function setItemExpanded(item, expanded, keepHash) {
418            if (expanded) {
419                item.setAttribute(dataAttributes.item.expanded, "");
420                var index = that._elements["item"].indexOf(item);
421                if (!keepHash && containerUtils) {
422                    containerUtils.updateUrlHash(that, "item", index);
423                }
424                if (dataLayerEnabled) {
425                    dataLayer.push({
426                        event: "cmp:show",
427                        eventInfo: {
428                            path: "component." + getDataLayerId(item)
429                        }
430                    });
431                }
432
433            } else {
434                item.removeAttribute(dataAttributes.item.expanded);
435                if (!keepHash && containerUtils) {
436                    containerUtils.removeUrlHash();
437                }
438                if (dataLayerEnabled) {
439                    dataLayer.push({
440                        event: "cmp:hide",
441                        eventInfo: {
442                            path: "component." + getDataLayerId(item)
443                        }
444                    });
445                }
446            }
447            refreshItem(item);
448        }
449
450        /**
451         * Gets an item's expanded state.
452         *
453         * @private
454         * @param {HTMLElement} item The item for checking its expanded state
455         * @returns {Boolean} true if the item is expanded, false otherwise
456         */
457        function getItemExpanded(item) {
458            return item && item.dataset && item.dataset["cmpExpanded"] !== undefined;
459        }
460
461        /**
462         * Refreshes an item based on its expanded state.
463         *
464         * @private
465         * @param {HTMLElement} item The item to refresh
466         */
467        function refreshItem(item) {
468            var expanded = getItemExpanded(item);
469            if (expanded) {
470                expandItem(item);
471            } else {
472                collapseItem(item);
473            }
474        }
475
476        /**
477         * Refreshes all items based on their expanded state.
478         *
479         * @private
480         */
481        function refreshItems() {
482            for (var i = 0; i < that._elements["item"].length; i++) {
483                refreshItem(that._elements["item"][i]);
484            }
485        }
486
487        /**
488         * Returns all expanded items.
489         *
490         * @private
491         * @returns {HTMLElement[]} The expanded items
492         */
493        function getExpandedItems() {
494            var expandedItems = [];
495
496            for (var i = 0; i < that._elements["item"].length; i++) {
497                var item = that._elements["item"][i];
498                var expanded = getItemExpanded(item);
499                if (expanded) {
500                    expandedItems.push(item);
501                }
502            }
503
504            return expandedItems;
505        }
506
507        /**
508         * Annotates the item and its internals with
509         * the necessary style and accessibility attributes to indicate it is expanded.
510         *
511         * @private
512         * @param {HTMLElement} item The item to annotate as expanded
513         */
514        function expandItem(item) {
515            var index = that._elements["item"].indexOf(item);
516            if (index > -1) {
517                var button = that._elements["button"][index];
518                var panel = that._elements["panel"][index];
519                button.classList.add(cssClasses.button.expanded);
520                // used to fix some known screen readers issues in reading the correct state of the 'aria-expanded' attribute
521                // e.g. https://bugs.webkit.org/show_bug.cgi?id=210934
522                setTimeout(function() {
523                    button.setAttribute("aria-expanded", true);
524                }, delay);
525                panel.classList.add(cssClasses.panel.expanded);
526                panel.classList.remove(cssClasses.panel.hidden);
527                panel.setAttribute("aria-hidden", false);
528            }
529        }
530
531        /**
532         * Annotates the item and its internals with
533         * the necessary style and accessibility attributes to indicate it is not expanded.
534         *
535         * @private
536         * @param {HTMLElement} item The item to annotate as not expanded
537         */
538        function collapseItem(item) {
539            var index = that._elements["item"].indexOf(item);
540            if (index > -1) {
541                var button = that._elements["button"][index];
542                var panel = that._elements["panel"][index];
543                button.classList.remove(cssClasses.button.expanded);
544                // used to fix some known screen readers issues in reading the correct state of the 'aria-expanded' attribute
545                // e.g. https://bugs.webkit.org/show_bug.cgi?id=210934
546                setTimeout(function() {
547                    button.setAttribute("aria-expanded", false);
548                }, delay);
549                panel.classList.add(cssClasses.panel.hidden);
550                panel.classList.remove(cssClasses.panel.expanded);
551                panel.setAttribute("aria-hidden", true);
552            }
553        }
554
555        /**
556         * Focuses the button at the provided index.
557         *
558         * @private
559         * @param {Number} index The index of the button to focus
560         */
561        function focusButton(index) {
562            var button = that._elements["button"][index];
563            button.focus();
564        }
565    }
566
567    /**
568     * Reads options data from the Accordion wrapper element, defined via {@code data-cmp-*} data attributes.
569     *
570     * @private
571     * @param {HTMLElement} element The Accordion element to read options data from
572     * @returns {Object} The options read from the component data attributes
573     */
574    function readData(element) {
575        var data = element.dataset;
576        var options = [];
577        var capitalized = IS;
578        capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
579        var reserved = ["is", "hook" + capitalized];
580
581        for (var key in data) {
582            if (Object.prototype.hasOwnProperty.call(data, key)) {
583                var value = data[key];
584
585                if (key.indexOf(NS) === 0) {
586                    key = key.slice(NS.length);
587                    key = key.charAt(0).toLowerCase() + key.substring(1);
588
589                    if (reserved.indexOf(key) === -1) {
590                        options[key] = value;
591                    }
592                }
593            }
594        }
595
596        return options;
597    }
598
599    /**
600     * Parses the dataLayer string and returns the ID
601     *
602     * @private
603     * @param {HTMLElement} item the accordion item
604     * @returns {String} dataLayerId or undefined
605     */
606    function getDataLayerId(item) {
607        if (item) {
608            if (item.dataset.cmpDataLayer) {
609                return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0];
610            } else {
611                return item.id;
612            }
613        }
614        return null;
615    }
616
617    /**
618     * Document ready handler and DOM mutation observers. Initializes Accordion components as necessary.
619     *
620     * @private
621     */
622    function onDocumentReady() {
623        dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled");
624        if (dataLayerEnabled) {
625            dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer";
626            dataLayer = window[dataLayerName] = window[dataLayerName] || [];
627        }
628
629        var elements = document.querySelectorAll(selectors.self);
630        for (var i = 0; i < elements.length; i++) {
631            new Accordion({ element: elements[i], options: readData(elements[i]) });
632        }
633
634        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
635        var body = document.querySelector("body");
636        var observer = new MutationObserver(function(mutations) {
637            mutations.forEach(function(mutation) {
638                // needed for IE
639                var nodesArray = [].slice.call(mutation.addedNodes);
640                if (nodesArray.length > 0) {
641                    nodesArray.forEach(function(addedNode) {
642                        if (addedNode.querySelectorAll) {
643                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
644                            elementsArray.forEach(function(element) {
645                                new Accordion({ element: element, options: readData(element) });
646                            });
647                        }
648                    });
649                }
650            });
651        });
652
653        observer.observe(body, {
654            subtree: true,
655            childList: true,
656            characterData: true
657        });
658    }
659
660    if (document.readyState !== "loading") {
661        onDocumentReady();
662    } else {
663        document.addEventListener("DOMContentLoaded", onDocumentReady);
664    }
665
666    if (containerUtils) {
667        window.addEventListener("load", containerUtils.scrollToAnchor, false);
668    }
669
670}());
671
672
673/*******************************************************************************
674 * Copyright 2018 Adobe
675 *
676 * Licensed under the Apache License, Version 2.0 (the "License");
677 * you may not use this file except in compliance with the License.
678 * You may obtain a copy of the License at
679 *
680 *     http://www.apache.org/licenses/LICENSE2.0
681 *
682 * Unless required by applicable law or agreed to in writing, software
683 * distributed under the License is distributed on an "AS IS" BASIS,
684 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
685 * See the License for the specific language governing permissions and
686 * limitations under the License.
687 ******************************************************************************/
688
689/**
690 * Element.matches()
691 * https://developer.mozilla.org/enUS/docs/Web/API/Element/matches#Polyfill
692 */
693if (!Element.prototype.matches) {
694    Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
695}
696
697// eslint-disable-next-line valid-jsdoc
698/**
699 * Element.closest()
700 * https://developer.mozilla.org/enUS/docs/Web/API/Element/closest#Polyfill
701 */
702if (!Element.prototype.closest) {
703    Element.prototype.closest = function(s) {
704        "use strict";
705        var el = this;
706        if (!document.documentElement.contains(el)) {
707            return null;
708        }
709        do {
710            if (el.matches(s)) {
711                return el;
712            }
713            el = el.parentElement || el.parentNode;
714        } while (el !== null && el.nodeType === 1);
715        return null;
716    };
717}
718
719/*******************************************************************************
720 * Copyright 2018 Adobe
721 *
722 * Licensed under the Apache License, Version 2.0 (the "License");
723 * you may not use this file except in compliance with the License.
724 * You may obtain a copy of the License at
725 *
726 *     http://www.apache.org/licenses/LICENSE-2.0
727 *
728 * Unless required by applicable law or agreed to in writing, software
729 * distributed under the License is distributed on an "AS IS" BASIS,
730 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
731 * See the License for the specific language governing permissions and
732 * limitations under the License.
733 ******************************************************************************/
734/* global
735    CQ
736 */
737(function() {
738    "use strict";
739
740    var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined;
741    if (!containerUtils) {
742        // eslint-disable-next-line no-console
743        console.warn("Tabs: container utilities at window.CQ.CoreComponents.container.utils are not available. This can lead to missing features. Ensure the core.wcm.components.commons.site.container client library is included on the page.");
744    }
745    var dataLayerEnabled;
746    var dataLayer;
747    var dataLayerName;
748
749    var NS = "cmp";
750    var IS = "tabs";
751
752    var keyCodes = {
753        END: 35,
754        HOME: 36,
755        ARROW_LEFT: 37,
756        ARROW_UP: 38,
757        ARROW_RIGHT: 39,
758        ARROW_DOWN: 40
759    };
760
761    var selectors = {
762        self: "[data-" + NS + '-is="' + IS + '"]',
763        active: {
764            tab: "cmp-tabs__tab--active",
765            tabpanel: "cmp-tabs__tabpanel--active"
766        }
767    };
768
769    /**
770     * Tabs Configuration
771     *
772     * @typedef {Object} TabsConfig Represents a Tabs configuration
773     * @property {HTMLElement} element The HTMLElement representing the Tabs
774     * @property {Object} options The Tabs options
775     */
776
777    /**
778     * Tabs
779     *
780     * @class Tabs
781     * @classdesc An interactive Tabs component for navigating a list of tabs
782     * @param {TabsConfig} config The Tabs configuration
783     */
784    function Tabs(config) {
785        var that = this;
786
787        if (config && config.element) {
788            init(config);
789        }
790
791        /**
792         * Initializes the Tabs
793         *
794         * @private
795         * @param {TabsConfig} config The Tabs configuration
796         */
797        function init(config) {
798            that._config = config;
799
800            // prevents multiple initialization
801            config.element.removeAttribute("data-" + NS + "-is");
802
803            cacheElements(config.element);
804            that._active = getActiveIndex(that._elements["tab"]);
805
806            if (that._elements.tabpanel) {
807                refreshActive();
808                bindEvents();
809                scrollToDeepLinkIdInTabs();
810            }
811
812            if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) {
813                /*
814                 * Editor message handling:
815                 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
816                 * - check that the message data panel container type is correct and that the id (path) matches this specific Tabs component
817                 * - if so, route the "navigate" operation to enact a navigation of the Tabs based on index data
818                 */
819                CQ.CoreComponents.MESSAGE_CHANNEL = CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window);
820                CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) {
821                    if (message.data && message.data.type === "cmp-tabs" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) {
822                        if (message.data.operation === "navigate") {
823                            navigate(message.data.index);
824                        }
825                    }
826                });
827            }
828        }
829
830        /**
831         * Displays the panel containing the element that corresponds to the deep link in the URI fragment
832         * and scrolls the browser to this element.
833         */
834        function scrollToDeepLinkIdInTabs() {
835            if (containerUtils) {
836                var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "tab", "tabpanel");
837                if (deepLinkItemIdx > -1) {
838                    var deepLinkItem = that._elements["tab"][deepLinkItemIdx];
839                    if (deepLinkItem && that._elements["tab"][that._active].id !== deepLinkItem.id) {
840                        navigateAndFocusTab(deepLinkItemIdx, true);
841                    }
842                    var hashId = window.location.hash.substring(1);
843                    if (hashId) {
844                        var hashItem = document.querySelector("[id='" + hashId + "']");
845                        if (hashItem) {
846                            hashItem.scrollIntoView();
847                        }
848                    }
849                }
850            }
851        }
852
853        /**
854         * Returns the index of the active tab, if no tab is active returns 0
855         *
856         * @param {Array} tabs Tab elements
857         * @returns {Number} Index of the active tab, 0 if none is active
858         */
859        function getActiveIndex(tabs) {
860            if (tabs) {
861                for (var i = 0; i < tabs.length; i++) {
862                    if (tabs[i].classList.contains(selectors.active.tab)) {
863                        return i;
864                    }
865                }
866            }
867            return 0;
868        }
869
870        /**
871         * Caches the Tabs elements as defined via the {@code data-tabs-hook="ELEMENT_NAME"} markup API
872         *
873         * @private
874         * @param {HTMLElement} wrapper The Tabs wrapper element
875         */
876        function cacheElements(wrapper) {
877            that._elements = {};
878            that._elements.self = wrapper;
879            var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
880
881            for (var i = 0; i < hooks.length; i++) {
882                var hook = hooks[i];
883                if (hook.closest("." + NS + "-" + IS) === that._elements.self) { // only process own tab elements
884                    var capitalized = IS;
885                    capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
886                    var key = hook.dataset[NS + "Hook" + capitalized];
887                    if (that._elements[key]) {
888                        if (!Array.isArray(that._elements[key])) {
889                            var tmp = that._elements[key];
890                            that._elements[key] = [tmp];
891                        }
892                        that._elements[key].push(hook);
893                    } else {
894                        that._elements[key] = hook;
895                    }
896                }
897            }
898        }
899
900        /**
901         * Binds Tabs event handling
902         *
903         * @private
904         */
905        function bindEvents() {
906            window.addEventListener("hashchange", scrollToDeepLinkIdInTabs, false);
907            var tabs = that._elements["tab"];
908            if (tabs) {
909                for (var i = 0; i < tabs.length; i++) {
910                    (function(index) {
911                        tabs[i].addEventListener("click", function(event) {
912                            navigateAndFocusTab(index);
913                        });
914                        tabs[i].addEventListener("keydown", function(event) {
915                            onKeyDown(event);
916                        });
917                    })(i);
918                }
919            }
920        }
921
922        /**
923         * Handles tab keydown events
924         *
925         * @private
926         * @param {Object} event The keydown event
927         */
928        function onKeyDown(event) {
929            var index = that._active;
930            var lastIndex = that._elements["tab"].length - 1;
931
932            switch (event.keyCode) {
933                case keyCodes.ARROW_LEFT:
934                case keyCodes.ARROW_UP:
935                    event.preventDefault();
936                    if (index > 0) {
937                        navigateAndFocusTab(index - 1);
938                    }
939                    break;
940                case keyCodes.ARROW_RIGHT:
941                case keyCodes.ARROW_DOWN:
942                    event.preventDefault();
943                    if (index < lastIndex) {
944                        navigateAndFocusTab(index + 1);
945                    }
946                    break;
947                case keyCodes.HOME:
948                    event.preventDefault();
949                    navigateAndFocusTab(0);
950                    break;
951                case keyCodes.END:
952                    event.preventDefault();
953                    navigateAndFocusTab(lastIndex);
954                    break;
955                default:
956                    return;
957            }
958        }
959
960        /**
961         * Refreshes the tab markup based on the current {@code Tabs#_active} index
962         *
963         * @private
964         */
965        function refreshActive() {
966            var tabpanels = that._elements["tabpanel"];
967            var tabs = that._elements["tab"];
968
969            if (tabpanels) {
970                if (Array.isArray(tabpanels)) {
971                    for (var i = 0; i < tabpanels.length; i++) {
972                        if (i === parseInt(that._active)) {
973                            tabpanels[i].classList.add(selectors.active.tabpanel);
974                            tabpanels[i].removeAttribute("aria-hidden");
975                            tabs[i].classList.add(selectors.active.tab);
976                            tabs[i].setAttribute("aria-selected", true);
977                            tabs[i].setAttribute("tabindex", "0");
978                        } else {
979                            tabpanels[i].classList.remove(selectors.active.tabpanel);
980                            tabpanels[i].setAttribute("aria-hidden", true);
981                            tabs[i].classList.remove(selectors.active.tab);
982                            tabs[i].setAttribute("aria-selected", false);
983                            tabs[i].setAttribute("tabindex", "-1");
984                        }
985                    }
986                } else {
987                    // only one tab
988                    tabpanels.classList.add(selectors.active.tabpanel);
989                    tabs.classList.add(selectors.active.tab);
990                }
991            }
992        }
993
994        /**
995         * Focuses the element and prevents scrolling the element into view
996         *
997         * @param {HTMLElement} element Element to focus
998         */
999        function focusWithoutScroll(element) {
1000            var x = window.scrollX || window.pageXOffset;
1001            var y = window.scrollY || window.pageYOffset;
1002            element.focus();
1003            window.scrollTo(x, y);
1004        }
1005
1006        /**
1007         * Navigates to the tab at the provided index
1008         *
1009         * @private
1010         * @param {Number} index The index of the tab to navigate to
1011         */
1012        function navigate(index) {
1013            that._active = index;
1014            refreshActive();
1015        }
1016
1017        /**
1018         * Navigates to the item at the provided index and ensures the active tab gains focus
1019         *
1020         * @private
1021         * @param {Number} index The index of the item to navigate to
1022         * @param {Boolean} keepHash true to keep the hash in the URL, false to update it
1023         */
1024        function navigateAndFocusTab(index, keepHash) {
1025            var exActive = that._active;
1026            if (!keepHash && containerUtils) {
1027                containerUtils.updateUrlHash(that, "tab", index);
1028            }
1029            navigate(index);
1030            focusWithoutScroll(that._elements["tab"][index]);
1031
1032            if (dataLayerEnabled) {
1033
1034                var activeItem = getDataLayerId(that._elements.tabpanel[index]);
1035                var exActiveItem = getDataLayerId(that._elements.tabpanel[exActive]);
1036
1037                dataLayer.push({
1038                    event: "cmp:show",
1039                    eventInfo: {
1040                        path: "component." + activeItem
1041                    }
1042                });
1043
1044                dataLayer.push({
1045                    event: "cmp:hide",
1046                    eventInfo: {
1047                        path: "component." + exActiveItem
1048                    }
1049                });
1050
1051                var tabsId = that._elements.self.id;
1052                var uploadPayload = { component: {} };
1053                uploadPayload.component[tabsId] = { shownItems: [activeItem] };
1054
1055                var removePayload = { component: {} };
1056                removePayload.component[tabsId] = { shownItems: undefined };
1057
1058                dataLayer.push(removePayload);
1059                dataLayer.push(uploadPayload);
1060            }
1061        }
1062    }
1063
1064    /**
1065     * Reads options data from the Tabs wrapper element, defined via {@code data-cmp-*} data attributes
1066     *
1067     * @private
1068     * @param {HTMLElement} element The Tabs element to read options data from
1069     * @returns {Object} The options read from the component data attributes
1070     */
1071    function readData(element) {
1072        var data = element.dataset;
1073        var options = [];
1074        var capitalized = IS;
1075        capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
1076        var reserved = ["is", "hook" + capitalized];
1077
1078        for (var key in data) {
1079            if (Object.prototype.hasOwnProperty.call(data, key)) {
1080                var value = data[key];
1081
1082                if (key.indexOf(NS) === 0) {
1083                    key = key.slice(NS.length);
1084                    key = key.charAt(0).toLowerCase() + key.substring(1);
1085
1086                    if (reserved.indexOf(key) === -1) {
1087                        options[key] = value;
1088                    }
1089                }
1090            }
1091        }
1092
1093        return options;
1094    }
1095
1096    /**
1097     * Parses the dataLayer string and returns the ID
1098     *
1099     * @private
1100     * @param {HTMLElement} item the accordion item
1101     * @returns {String} dataLayerId or undefined
1102     */
1103    function getDataLayerId(item) {
1104        if (item) {
1105            if (item.dataset.cmpDataLayer) {
1106                return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0];
1107            } else {
1108                return item.id;
1109            }
1110        }
1111        return null;
1112    }
1113
1114    /**
1115     * Document ready handler and DOM mutation observers. Initializes Tabs components as necessary.
1116     *
1117     * @private
1118     */
1119    function onDocumentReady() {
1120        dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled");
1121        if (dataLayerEnabled) {
1122            dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer";
1123            dataLayer = window[dataLayerName] = window[dataLayerName] || [];
1124        }
1125
1126        var elements = document.querySelectorAll(selectors.self);
1127        for (var i = 0; i < elements.length; i++) {
1128            new Tabs({ element: elements[i], options: readData(elements[i]) });
1129        }
1130
1131        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
1132        var body = document.querySelector("body");
1133        var observer = new MutationObserver(function(mutations) {
1134            mutations.forEach(function(mutation) {
1135                // needed for IE
1136                var nodesArray = [].slice.call(mutation.addedNodes);
1137                if (nodesArray.length > 0) {
1138                    nodesArray.forEach(function(addedNode) {
1139                        if (addedNode.querySelectorAll) {
1140                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
1141                            elementsArray.forEach(function(element) {
1142                                new Tabs({ element: element, options: readData(element) });
1143                            });
1144                        }
1145                    });
1146                }
1147            });
1148        });
1149
1150        observer.observe(body, {
1151            subtree: true,
1152            childList: true,
1153            characterData: true
1154        });
1155    }
1156
1157    if (document.readyState !== "loading") {
1158        onDocumentReady();
1159    } else {
1160        document.addEventListener("DOMContentLoaded", onDocumentReady);
1161    }
1162
1163    if (containerUtils) {
1164        window.addEventListener("load", containerUtils.scrollToAnchor, false);
1165    }
1166
1167}());
1168
1169
1170/*******************************************************************************
1171 * Copyright 2022 Adobe
1172 *
1173 * Licensed under the Apache License, Version 2.0 (the "License");
1174 * you may not use this file except in compliance with the License.
1175 * You may obtain a copy of the License at
1176 *
1177 *     http://www.apache.org/licenses/LICENSE-2.0
1178 *
1179 * Unless required by applicable law or agreed to in writing, software
1180 * distributed under the License is distributed on an "AS IS" BASIS,
1181 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1182 * See the License for the specific language governing permissions and
1183 * limitations under the License.
1184 ******************************************************************************/
1185(function(document) {
1186    "use strict";
1187
1188    window.CMP = window.CMP || {};
1189    window.CMP.utils = (function() {
1190        var NS = "cmp";
1191
1192        /**
1193         * Reads options data from the Component wrapper element, defined via {@code data-cmp-*} data attributes
1194         *
1195         * @param {HTMLElement} element The component element to read options data from
1196         * @param {String} is The component identifier
1197         * @returns {String[]} The options read from the component data attributes
1198         */
1199        var readData = function(element, is) {
1200            var data = element.dataset;
1201            var options = [];
1202            var capitalized = is;
1203            capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
1204            var reserved = ["is", "hook" + capitalized];
1205
1206            for (var key in data) {
1207                if (Object.prototype.hasOwnProperty.call(data, key)) {
1208                    var value = data[key];
1209
1210                    if (key.indexOf(NS) === 0) {
1211                        key = key.slice(NS.length);
1212                        key = key.charAt(0).toLowerCase() + key.substring(1);
1213
1214                        if (reserved.indexOf(key) === -1) {
1215                            options[key] = value;
1216                        }
1217                    }
1218                }
1219            }
1220            return options;
1221        };
1222
1223        /**
1224         * Set up the final properties of a component by evaluating the transform function or fall back to the default value on demand
1225         * @param {String[]} options the options to transform
1226         * @param {Object} properties object of properties of property functions
1227         * @returns {Object} transformed properties
1228         */
1229        var setupProperties = function(options, properties) {
1230            var transformedProperties = {};
1231
1232            for (var key in properties) {
1233                if (Object.prototype.hasOwnProperty.call(properties, key)) {
1234                    var property = properties[key];
1235                    if (options && options[key] != null) {
1236                        if (property && typeof property.transform === "function") {
1237                            transformedProperties[key] = property.transform(options[key]);
1238                        } else {
1239                            transformedProperties[key] = options[key];
1240                        }
1241                    } else {
1242                        transformedProperties[key] = properties[key]["default"];
1243                    }
1244                }
1245            }
1246            return transformedProperties;
1247        };
1248
1249
1250        return {
1251            readData: readData,
1252            setupProperties: setupProperties
1253        };
1254    }());
1255}(window.document));
1256
1257/*******************************************************************************
1258 * Copyright 2018 Adobe
1259 *
1260 * Licensed under the Apache License, Version 2.0 (the "License");
1261 * you may not use this file except in compliance with the License.
1262 * You may obtain a copy of the License at
1263 *
1264 *     http://www.apache.org/licenses/LICENSE-2.0
1265 *
1266 * Unless required by applicable law or agreed to in writing, software
1267 * distributed under the License is distributed on an "AS IS" BASIS,
1268 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1269 * See the License for the specific language governing permissions and
1270 * limitations under the License.
1271 ******************************************************************************/
1272(function() {
1273    "use strict";
1274
1275    var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined;
1276    if (!containerUtils) {
1277        // eslint-disable-next-line no-console
1278        console.warn("Tabs: container utilities at window.CQ.CoreComponents.container.utils are not available. This can lead to missing features. Ensure the core.wcm.components.commons.site.container client library is included on the page.");
1279    }
1280    var dataLayerEnabled;
1281    var dataLayer;
1282    var dataLayerName;
1283
1284    var NS = "cmp";
1285    var IS = "carousel";
1286
1287    var keyCodes = {
1288        SPACE: 32,
1289        END: 35,
1290        HOME: 36,
1291        ARROW_LEFT: 37,
1292        ARROW_UP: 38,
1293        ARROW_RIGHT: 39,
1294        ARROW_DOWN: 40
1295    };
1296
1297    var selectors = {
1298        self: "[data-" + NS + '-is="' + IS + '"]'
1299    };
1300
1301    var properties = {
1302        /**
1303         * Determines whether the Carousel will automatically transition between slides
1304         *
1305         * @memberof Carousel
1306         * @type {Boolean}
1307         * @default false
1308         */
1309        "autoplay": {
1310            "default": false,
1311            "transform": function(value) {
1312                return !(value === null || typeof value === "undefined");
1313            }
1314        },
1315        /**
1316         * Duration (in milliseconds) before automatically transitioning to the next slide
1317         *
1318         * @memberof Carousel
1319         * @type {Number}
1320         * @default 5000
1321         */
1322        "delay": {
1323            "default": 5000,
1324            "transform": function(value) {
1325                value = parseFloat(value);
1326                return !isNaN(value) ? value : null;
1327            }
1328        },
1329        /**
1330         * Determines whether automatic pause on hovering the carousel is disabled
1331         *
1332         * @memberof Carousel
1333         * @type {Boolean}
1334         * @default false
1335         */
1336        "autopauseDisabled": {
1337            "default": false,
1338            "transform": function(value) {
1339                return !(value === null || typeof value === "undefined");
1340            }
1341        }
1342    };
1343
1344    /**
1345     * Carousel Configuration
1346     *
1347     * @typedef {Object} CarouselConfig Represents a Carousel configuration
1348     * @property {HTMLElement} element The HTMLElement representing the Carousel
1349     * @property {*[]} options The Carousel options
1350     */
1351
1352    /**
1353     * Carousel
1354     *
1355     * @class Carousel
1356     * @classdesc An interactive Carousel component for navigating a list of generic items
1357     * @param {CarouselConfig} config The Carousel configuration
1358     */
1359    function Carousel(config) {
1360        var that = this;
1361
1362        if (config && config.element) {
1363            init(config);
1364        }
1365
1366        /**
1367         * Initializes the Carousel
1368         *
1369         * @private
1370         * @param {CarouselConfig} config The Carousel configuration
1371         */
1372        function init(config) {
1373            that._config = config;
1374
1375            // prevents multiple initialization
1376            config.element.removeAttribute("data-" + NS + "-is");
1377
1378            setupProperties(config.options);
1379            cacheElements(config.element);
1380
1381            that._active = 0;
1382            that._paused = false;
1383
1384            if (that._elements.item) {
1385                initializeActive();
1386                bindEvents();
1387                resetAutoplayInterval();
1388                refreshPlayPauseActions();
1389                scrollToDeepLinkIdInCarousel();
1390            }
1391
1392            // TODO: This section is only relevant in edit mode and should move to the editor clientLib
1393            if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) {
1394                /*
1395                 * Editor message handling:
1396                 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
1397                 * - check that the message data panel container type is correct and that the id (path) matches this specific Carousel component
1398                 * - if so, route the "navigate" operation to enact a navigation of the Carousel based on index data
1399                 */
1400                window.CQ = window.CQ || {};
1401                window.CQ.CoreComponents = window.CQ.CoreComponents || {};
1402                window.CQ.CoreComponents.MESSAGE_CHANNEL = window.CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window);
1403                window.CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) {
1404                    if (message.data && message.data.type === "cmp-carousel" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) {
1405                        if (message.data.operation === "navigate") {
1406                            navigate(message.data.index);
1407                        }
1408                    }
1409                });
1410            }
1411        }
1412
1413        /**
1414         * Displays the slide containing the element that corresponds to the deep link in the URI fragment
1415         * and scrolls the browser to this element.
1416         */
1417        function scrollToDeepLinkIdInCarousel() {
1418            if (containerUtils) {
1419                var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "item", "item");
1420                if (deepLinkItemIdx > -1) {
1421                    var deepLinkItem = that._elements["item"][deepLinkItemIdx];
1422                    if (deepLinkItem && that._elements["item"][that._active].id !== deepLinkItem.id) {
1423                        navigateAndFocusIndicator(deepLinkItemIdx, true);
1424                        // pause the carousel auto-rotation
1425                        pause();
1426                    }
1427                    var hashId = window.location.hash.substring(1);
1428                    if (hashId) {
1429                        var hashItem = document.querySelector("[id='" + hashId + "']");
1430                        if (hashItem) {
1431                            hashItem.scrollIntoView();
1432                        }
1433                    }
1434                }
1435            }
1436        }
1437
1438        /**
1439         * Caches the Carousel elements as defined via the {@code data-carousel-hook="ELEMENT_NAME"} markup API
1440         *
1441         * @private
1442         * @param {HTMLElement} wrapper The Carousel wrapper element
1443         */
1444        function cacheElements(wrapper) {
1445            that._elements = {};
1446            that._elements.self = wrapper;
1447            var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
1448
1449            for (var i = 0; i < hooks.length; i++) {
1450                var hook = hooks[i];
1451                var capitalized = IS;
1452                capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
1453                var key = hook.dataset[NS + "Hook" + capitalized];
1454                if (that._elements[key]) {
1455                    if (!Array.isArray(that._elements[key])) {
1456                        var tmp = that._elements[key];
1457                        that._elements[key] = [tmp];
1458                    }
1459                    that._elements[key].push(hook);
1460                } else {
1461                    that._elements[key] = hook;
1462                }
1463            }
1464        }
1465
1466        /**
1467         * Sets up properties for the Carousel based on the passed options.
1468         *
1469         * @private
1470         * @param {Object} options The Carousel options
1471         */
1472        function setupProperties(options) {
1473            that._properties = {};
1474
1475            for (var key in properties) {
1476                if (Object.prototype.hasOwnProperty.call(properties, key)) {
1477                    var property = properties[key];
1478                    var value = null;
1479
1480                    if (options && options[key] != null) {
1481                        value = options[key];
1482
1483                        // transform the provided option
1484                        if (property && typeof property.transform === "function") {
1485                            value = property.transform(value);
1486                        }
1487                    }
1488
1489                    if (value === null) {
1490                        // value still null, take the property default
1491                        value = properties[key]["default"];
1492                    }
1493
1494                    that._properties[key] = value;
1495                }
1496            }
1497        }
1498
1499        /**
1500         * Binds Carousel event handling
1501         *
1502         * @private
1503         */
1504        function bindEvents() {
1505            window.addEventListener("hashchange", scrollToDeepLinkIdInCarousel, false);
1506            if (that._elements["previous"]) {
1507                that._elements["previous"].addEventListener("click", function() {
1508                    var index = getPreviousIndex();
1509                    navigate(index);
1510                    if (dataLayerEnabled) {
1511                        dataLayer.push({
1512                            event: "cmp:show",
1513                            eventInfo: {
1514                                path: "component." + getDataLayerId(that._elements.item[index])
1515                            }
1516                        });
1517                    }
1518                });
1519            }
1520
1521            if (that._elements["next"]) {
1522                that._elements["next"].addEventListener("click", function() {
1523                    var index = getNextIndex();
1524                    navigate(index);
1525                    if (dataLayerEnabled) {
1526                        dataLayer.push({
1527                            event: "cmp:show",
1528                            eventInfo: {
1529                                path: "component." + getDataLayerId(that._elements.item[index])
1530                            }
1531                        });
1532                    }
1533                });
1534            }
1535
1536            var indicators = that._elements["indicator"];
1537            if (indicators) {
1538                for (var i = 0; i < indicators.length; i++) {
1539                    (function(index) {
1540                        indicators[i].addEventListener("click", function(event) {
1541                            navigateAndFocusIndicator(index);
1542                            // pause the carousel auto-rotation
1543                            pause();
1544                        });
1545                    })(i);
1546                }
1547            }
1548
1549            if (that._elements["pause"]) {
1550                if (that._properties.autoplay) {
1551                    that._elements["pause"].addEventListener("click", onPauseClick);
1552                }
1553            }
1554
1555            if (that._elements["play"]) {
1556                if (that._properties.autoplay) {
1557                    that._elements["play"].addEventListener("click", onPlayClick);
1558                }
1559            }
1560
1561            that._elements.self.addEventListener("keydown", onKeyDown);
1562
1563            if (!that._properties.autopauseDisabled) {
1564                that._elements.self.addEventListener("mouseenter", onMouseEnter);
1565                that._elements.self.addEventListener("mouseleave", onMouseLeave);
1566            }
1567
1568            // for accessibility we pause animation when a element get focused
1569            var items = that._elements["item"];
1570            if (items) {
1571                for (var j = 0; j < items.length; j++) {
1572                    items[j].addEventListener("focusin", onMouseEnter);
1573                    items[j].addEventListener("focusout", onMouseLeave);
1574                }
1575            }
1576        }
1577
1578        /**
1579         * Handles carousel keydown events
1580         *
1581         * @private
1582         * @param {Object} event The keydown event
1583         */
1584        function onKeyDown(event) {
1585            var index = that._active;
1586            var lastIndex = that._elements["indicator"].length - 1;
1587
1588            switch (event.keyCode) {
1589                case keyCodes.ARROW_LEFT:
1590                case keyCodes.ARROW_UP:
1591                    event.preventDefault();
1592                    if (index > 0) {
1593                        navigateAndFocusIndicator(index - 1);
1594                    }
1595                    break;
1596                case keyCodes.ARROW_RIGHT:
1597                case keyCodes.ARROW_DOWN:
1598                    event.preventDefault();
1599                    if (index < lastIndex) {
1600                        navigateAndFocusIndicator(index + 1);
1601                    }
1602                    break;
1603                case keyCodes.HOME:
1604                    event.preventDefault();
1605                    navigateAndFocusIndicator(0);
1606                    break;
1607                case keyCodes.END:
1608                    event.preventDefault();
1609                    navigateAndFocusIndicator(lastIndex);
1610                    break;
1611                case keyCodes.SPACE:
1612                    if (that._properties.autoplay && (event.target !== that._elements["previous"] && event.target !== that._elements["next"])) {
1613                        event.preventDefault();
1614                        if (!that._paused) {
1615                            pause();
1616                        } else {
1617                            play();
1618                        }
1619                    }
1620                    if (event.target === that._elements["pause"]) {
1621                        that._elements["play"].focus();
1622                    }
1623                    if (event.target === that._elements["play"]) {
1624                        that._elements["pause"].focus();
1625                    }
1626                    break;
1627                default:
1628                    return;
1629            }
1630        }
1631
1632        /**
1633         * Handles carousel mouseenter events
1634         *
1635         * @private
1636         * @param {Object} event The mouseenter event
1637         */
1638        function onMouseEnter(event) {
1639            clearAutoplayInterval();
1640        }
1641
1642        /**
1643         * Handles carousel mouseleave events
1644         *
1645         * @private
1646         * @param {Object} event The mouseleave event
1647         */
1648        function onMouseLeave(event) {
1649            resetAutoplayInterval();
1650        }
1651
1652        /**
1653         * Handles pause element click events
1654         *
1655         * @private
1656         * @param {Object} event The click event
1657         */
1658        function onPauseClick(event) {
1659            pause();
1660            that._elements["play"].focus();
1661        }
1662
1663        /**
1664         * Handles play element click events
1665         *
1666         * @private
1667         * @param {Object} event The click event
1668         */
1669        function onPlayClick() {
1670            play();
1671            that._elements["pause"].focus();
1672        }
1673
1674        /**
1675         * Pauses the playing of the Carousel. Sets {@code Carousel#_paused} marker.
1676         * Only relevant when autoplay is enabled
1677         *
1678         * @private
1679         */
1680        function pause() {
1681            that._paused = true;
1682            clearAutoplayInterval();
1683            refreshPlayPauseActions();
1684        }
1685
1686        /**
1687         * Enables the playing of the Carousel. Sets {@code Carousel#_paused} marker.
1688         * Only relevant when autoplay is enabled
1689         *
1690         * @private
1691         */
1692        function play() {
1693            that._paused = false;
1694
1695            // If the Carousel is hovered, don't begin auto transitioning until the next mouse leave event
1696            var hovered = false;
1697            if (that._elements.self.parentElement) {
1698                hovered = that._elements.self.parentElement.querySelector(":hover") === that._elements.self;
1699            }
1700            if (that._properties.autopauseDisabled || !hovered) {
1701                resetAutoplayInterval();
1702            }
1703
1704            refreshPlayPauseActions();
1705        }
1706
1707        /**
1708         * Refreshes the play/pause action markup based on the {@code Carousel#_paused} state
1709         *
1710         * @private
1711         */
1712        function refreshPlayPauseActions() {
1713            setActionDisabled(that._elements["pause"], that._paused);
1714            setActionDisabled(that._elements["play"], !that._paused);
1715        }
1716
1717        /**
1718         * Initialize {@code Carousel#_active} based on the active item of the carousel.
1719         */
1720        function initializeActive() {
1721            var items = that._elements["item"];
1722            if (items && Array.isArray(items)) {
1723                for (var i = 0; i < items.length; i++) {
1724                    if (items[i].classList.contains("cmp-carousel__item--active")) {
1725                        that._active = i;
1726                        break;
1727                    }
1728                }
1729            }
1730        }
1731
1732        /**
1733         * Refreshes the item markup based on the current {@code Carousel#_active} index
1734         *
1735         * @private
1736         */
1737        function refreshActive() {
1738            var items = that._elements["item"];
1739            var indicators = that._elements["indicator"];
1740
1741            if (items) {
1742                if (Array.isArray(items)) {
1743                    for (var i = 0; i < items.length; i++) {
1744                        if (i === parseInt(that._active)) {
1745                            items[i].classList.add("cmp-carousel__item--active");
1746                            items[i].removeAttribute("aria-hidden");
1747                            indicators[i].classList.add("cmp-carousel__indicator--active");
1748                            indicators[i].setAttribute("aria-selected", true);
1749                            indicators[i].setAttribute("tabindex", "0");
1750                        } else {
1751                            items[i].classList.remove("cmp-carousel__item--active");
1752                            items[i].setAttribute("aria-hidden", true);
1753                            indicators[i].classList.remove("cmp-carousel__indicator--active");
1754                            indicators[i].setAttribute("aria-selected", false);
1755                            indicators[i].setAttribute("tabindex", "-1");
1756                        }
1757                    }
1758                } else {
1759                    // only one item
1760                    items.classList.add("cmp-carousel__item--active");
1761                    indicators.classList.add("cmp-carousel__indicator--active");
1762                }
1763            }
1764        }
1765
1766        /**
1767         * Focuses the element and prevents scrolling the element into view
1768         *
1769         * @param {HTMLElement} element Element to focus
1770         */
1771        function focusWithoutScroll(element) {
1772            var x = window.scrollX || window.pageXOffset;
1773            var y = window.scrollY || window.pageYOffset;
1774            element.focus();
1775            window.scrollTo(x, y);
1776        }
1777
1778        /**
1779         * Retrieves the next active index, with looping
1780         *
1781         * @private
1782         * @returns {Number} Index of the next carousel item
1783         */
1784        function getNextIndex() {
1785            return that._active === (that._elements["item"].length - 1) ? 0 : that._active + 1;
1786        }
1787
1788        /**
1789         * Retrieves the previous active index, with looping
1790         *
1791         * @private
1792         * @returns {Number} Index of the previous carousel item
1793         */
1794        function getPreviousIndex() {
1795            return that._active === 0 ? (that._elements["item"].length - 1) : that._active - 1;
1796        }
1797
1798        /**
1799         * Navigates to the item at the provided index
1800         *
1801         * @private
1802         * @param {Number} index The index of the item to navigate to
1803         * @param {Boolean} keepHash true to keep the hash in the URL, false to update it
1804         */
1805        function navigate(index, keepHash) {
1806            if (index < 0 || index > (that._elements["item"].length - 1)) {
1807                return;
1808            }
1809
1810            that._active = index;
1811            refreshActive();
1812
1813            if (!keepHash && containerUtils) {
1814                containerUtils.updateUrlHash(that, "item", index);
1815            }
1816
1817            if (dataLayerEnabled) {
1818                var carouselId = that._elements.self.id;
1819                var activeItem = getDataLayerId(that._elements.item[index]);
1820                var updatePayload = { component: {} };
1821                updatePayload.component[carouselId] = { shownItems: [activeItem] };
1822
1823                var removePayload = { component: {} };
1824                removePayload.component[carouselId] = { shownItems: undefined };
1825
1826                dataLayer.push(removePayload);
1827                dataLayer.push(updatePayload);
1828            }
1829
1830            // reset the autoplay transition interval following navigation, if not already hovering the carousel
1831            if (that._elements.self.parentElement) {
1832                if (that._elements.self.parentElement.querySelector(":hover") !== that._elements.self) {
1833                    resetAutoplayInterval();
1834                }
1835            }
1836        }
1837
1838        /**
1839         * Navigates to the item at the provided index and ensures the active indicator gains focus
1840         *
1841         * @private
1842         * @param {Number} index The index of the item to navigate to
1843         * @param {Boolean} keepHash true to keep the hash in the URL, false to update it
1844         */
1845        function navigateAndFocusIndicator(index, keepHash) {
1846            navigate(index, keepHash);
1847            focusWithoutScroll(that._elements["indicator"][index]);
1848
1849            if (dataLayerEnabled) {
1850                dataLayer.push({
1851                    event: "cmp:show",
1852                    eventInfo: {
1853                        path: "component." + getDataLayerId(that._elements.item[index])
1854                    }
1855                });
1856            }
1857        }
1858
1859        /**
1860         * Starts/resets automatic slide transition interval
1861         *
1862         * @private
1863         */
1864        function resetAutoplayInterval() {
1865            if (that._paused || !that._properties.autoplay) {
1866                return;
1867            }
1868            clearAutoplayInterval();
1869            that._autoplayIntervalId = window.setInterval(function() {
1870                if (document.visibilityState && document.hidden) {
1871                    return;
1872                }
1873                var indicators = that._elements["indicators"];
1874                if (indicators !== document.activeElement && indicators.contains(document.activeElement)) {
1875                    // if an indicator has focus, ensure we switch focus following navigation
1876                    navigateAndFocusIndicator(getNextIndex(), true);
1877                } else {
1878                    navigate(getNextIndex(), true);
1879                }
1880            }, that._properties.delay);
1881        }
1882
1883        /**
1884         * Clears/pauses automatic slide transition interval
1885         *
1886         * @private
1887         */
1888        function clearAutoplayInterval() {
1889            window.clearInterval(that._autoplayIntervalId);
1890            that._autoplayIntervalId = null;
1891        }
1892
1893        /**
1894         * Sets the disabled state for an action and toggles the appropriate CSS classes
1895         *
1896         * @private
1897         * @param {HTMLElement} action Action to disable
1898         * @param {Boolean} [disable] {@code true} to disable, {@code false} to enable
1899         */
1900        function setActionDisabled(action, disable) {
1901            if (!action) {
1902                return;
1903            }
1904            if (disable !== false) {
1905                action.disabled = true;
1906                action.classList.add("cmp-carousel__action--disabled");
1907            } else {
1908                action.disabled = false;
1909                action.classList.remove("cmp-carousel__action--disabled");
1910            }
1911        }
1912    }
1913
1914    /**
1915     * Parses the dataLayer string and returns the ID
1916     *
1917     * @private
1918     * @param {HTMLElement} item the accordion item
1919     * @returns {String} dataLayerId or undefined
1920     */
1921    function getDataLayerId(item) {
1922        if (item) {
1923            if (item.dataset.cmpDataLayer) {
1924                return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0];
1925            } else {
1926                return item.id;
1927            }
1928        }
1929        return null;
1930    }
1931
1932    /**
1933     * Document ready handler and DOM mutation observers. Initializes Carousel components as necessary.
1934     *
1935     * @private
1936     */
1937    function onDocumentReady() {
1938        dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled");
1939        if (dataLayerEnabled) {
1940            dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer";
1941            dataLayer = window[dataLayerName] = window[dataLayerName] || [];
1942        }
1943
1944        var elements = document.querySelectorAll(selectors.self);
1945        for (var i = 0; i < elements.length; i++) {
1946            new Carousel({ element: elements[i], options: CMP.utils.readData(elements[i], IS) });
1947        }
1948
1949        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
1950        var body = document.querySelector("body");
1951        var observer = new MutationObserver(function(mutations) {
1952            mutations.forEach(function(mutation) {
1953                // needed for IE
1954                var nodesArray = [].slice.call(mutation.addedNodes);
1955                if (nodesArray.length > 0) {
1956                    nodesArray.forEach(function(addedNode) {
1957                        if (addedNode.querySelectorAll) {
1958                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
1959                            elementsArray.forEach(function(element) {
1960                                new Carousel({ element: element, options: CMP.utils.readData(element, IS) });
1961                            });
1962                        }
1963                    });
1964                }
1965            });
1966        });
1967
1968        observer.observe(body, {
1969            subtree: true,
1970            childList: true,
1971            characterData: true
1972        });
1973    }
1974
1975    var documentReady = document.readyState !== "loading" ? Promise.resolve() : new Promise(function(resolve) {
1976        document.addEventListener("DOMContentLoaded", resolve);
1977    });
1978    Promise.all([documentReady]).then(onDocumentReady);
1979
1980    if (containerUtils) {
1981        window.addEventListener("load", containerUtils.scrollToAnchor, false);
1982    }
1983
1984}());
1985
1986
1987/*******************************************************************************
1988 * Copyright 2022 Adobe
1989 *
1990 * Licensed under the Apache License, Version 2.0 (the "License");
1991 * you may not use this file except in compliance with the License.
1992 * You may obtain a copy of the License at
1993 *
1994 *     http://www.apache.org/licenses/LICENSE-2.0
1995 *
1996 * Unless required by applicable law or agreed to in writing, software
1997 * distributed under the License is distributed on an "AS IS" BASIS,
1998 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1999 * See the License for the specific language governing permissions and
2000 * limitations under the License.
2001 ******************************************************************************/
2002(function(document) {
2003    "use strict";
2004
2005    window.CMP = window.CMP || {};
2006    window.CMP.utils = (function() {
2007        var NS = "cmp";
2008
2009        /**
2010         * Reads options data from the Component wrapper element, defined via {@code data-cmp-*} data attributes
2011         *
2012         * @param {HTMLElement} element The component element to read options data from
2013         * @param {String} is The component identifier
2014         * @returns {String[]} The options read from the component data attributes
2015         */
2016        var readData = function(element, is) {
2017            var data = element.dataset;
2018            var options = [];
2019            var capitalized = is;
2020            capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
2021            var reserved = ["is", "hook" + capitalized];
2022
2023            for (var key in data) {
2024                if (Object.prototype.hasOwnProperty.call(data, key)) {
2025                    var value = data[key];
2026
2027                    if (key.indexOf(NS) === 0) {
2028                        key = key.slice(NS.length);
2029                        key = key.charAt(0).toLowerCase() + key.substring(1);
2030
2031                        if (reserved.indexOf(key) === -1) {
2032                            options[key] = value;
2033                        }
2034                    }
2035                }
2036            }
2037            return options;
2038        };
2039
2040        /**
2041         * Set up the final properties of a component by evaluating the transform function or fall back to the default value on demand
2042         * @param {String[]} options the options to transform
2043         * @param {Object} properties object of properties of property functions
2044         * @returns {Object} transformed properties
2045         */
2046        var setupProperties = function(options, properties) {
2047            var transformedProperties = {};
2048
2049            for (var key in properties) {
2050                if (Object.prototype.hasOwnProperty.call(properties, key)) {
2051                    var property = properties[key];
2052                    if (options && options[key] != null) {
2053                        if (property && typeof property.transform === "function") {
2054                            transformedProperties[key] = property.transform(options[key]);
2055                        } else {
2056                            transformedProperties[key] = options[key];
2057                        }
2058                    } else {
2059                        transformedProperties[key] = properties[key]["default"];
2060                    }
2061                }
2062            }
2063            return transformedProperties;
2064        };
2065
2066
2067        return {
2068            readData: readData,
2069            setupProperties: setupProperties
2070        };
2071    }());
2072}(window.document));
2073
2074/*******************************************************************************
2075 * Copyright 2022 Adobe
2076 *
2077 * Licensed under the Apache License, Version 2.0 (the "License");
2078 * you may not use this file except in compliance with the License.
2079 * You may obtain a copy of the License at
2080 *
2081 *     http://www.apache.org/licenses/LICENSE-2.0
2082 *
2083 * Unless required by applicable law or agreed to in writing, software
2084 * distributed under the License is distributed on an "AS IS" BASIS,
2085 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2086 * See the License for the specific language governing permissions and
2087 * limitations under the License.
2088 ******************************************************************************/
2089(function(document) {
2090    "use strict";
2091
2092    window.CMP = window.CMP || {};
2093    window.CMP.image = window.CMP.image || {};
2094    window.CMP.image.dynamicMedia = (function() {
2095        var autoSmartCrops = {};
2096        var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}";
2097        var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}";
2098        var SRC_URI_DPR_OFF = "dpr=off";
2099        var SRC_URI_DPR_ON = "dpr=on,{dpr}";
2100        var dpr = window.devicePixelRatio || 1;
2101        var config = {
2102            minWidth: 20
2103        };
2104
2105        /**
2106         * get auto smart crops from dm
2107         * @param {String} src the src uri
2108         * @returns {{}} the smart crop json object
2109         */
2110        var getAutoSmartCrops = function(src) {
2111            var request = new XMLHttpRequest();
2112            var url = src.split(SRC_URI_TEMPLATE_WIDTH_VAR)[0] + "?req=set,json";
2113            request.open("GET", url, false);
2114            request.onload = function() {
2115                if (request.status >= 200 && request.status < 400) {
2116                    // success status
2117                    var responseText = request.responseText;
2118                    var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi);
2119                    var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi);
2120                    var resPayload = rePayload.exec(responseText);
2121                    var payload;
2122                    if (resPayload) {
2123                        var payloadStr = resPayload[2];
2124                        if (rePayloadJSON.test(payloadStr)) {
2125                            payload = JSON.parse(payloadStr);
2126                        }
2127
2128                    }
2129                    // check "relation" - only in case of smartcrop preset
2130                    if (payload && payload.set.relation && payload.set.relation.length > 0) {
2131                        for (var i = 0; i < payload.set.relation.length; i++) {
2132                            autoSmartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] =
2133                                ":" + payload.set.relation[i].userdata.SmartCropDef;
2134                        }
2135                    }
2136                } else {
2137                    // error status
2138                }
2139            };
2140            request.send();
2141            return autoSmartCrops;
2142        };
2143
2144        /**
2145         * Build and return the srcset value based on the available auto smart crops
2146         * @param {String} src the src uri
2147         * @param {Object} smartCrops the smart crops object
2148         * @returns {String} the srcset
2149         */
2150        var getSrcSet = function(src, smartCrops) {
2151            var srcset;
2152            var keys = Object.keys(smartCrops);
2153            if (keys.length > 0) {
2154                srcset = [];
2155                for (var key in autoSmartCrops) {
2156                    srcset.push(src.replace(SRC_URI_TEMPLATE_WIDTH_VAR, smartCrops[key]) + " " + key + "w");
2157                }
2158            }
2159            return  srcset.join(",");
2160        };
2161
2162        /**
2163         * Get the optimal width based on the available sizes
2164         * @param {[Number]} sizes the available sizes
2165         * @param {Number} width the element width
2166         * @returns {String} the optimal width
2167         */
2168        function getOptimalWidth(sizes, width) {
2169            var len = sizes.length;
2170            var key = 0;
2171
2172            while ((key < len - 1) && (sizes[key] < width)) {
2173                key++;
2174            }
2175
2176            return sizes[key] !== undefined ? sizes[key].toString() : width;
2177        }
2178
2179        /**
2180         * Get the width of an element or parent element if the width is smaller than the minimum width
2181         * @param {HTMLElement} component the image component
2182         * @param {HTMLElement | Node} parent the parent element
2183         * @returns {Number} the width of the element
2184         */
2185        var getWidth = function(component, parent) {
2186            var width = component.offsetWidth;
2187            while (width < config.minWidth && parent && !component._autoWidth) {
2188                width =  parent.offsetWidth;
2189                parent = parent.parentNode;
2190            }
2191            return width;
2192        };
2193
2194        /**
2195         * Set the src and srcset attribute for a Dynamic Media Image which auto smart crops enabled.
2196         * @param {HTMLElement} component the image component
2197         * @param {{}} properties the component properties
2198         */
2199        var setDMAttributes = function(component, properties) {
2200            // for v3 we first have to turn the dpr on
2201            var src = properties.src.replace(SRC_URI_DPR_OFF, SRC_URI_DPR_ON);
2202            src = src.replace(SRC_URI_TEMPLATE_DPR_VAR, dpr);
2203            var smartCrops = {};
2204            var width;
2205            if (properties["smartcroprendition"] === "SmartCrop:Auto") {
2206                smartCrops = getAutoSmartCrops(src);
2207            }
2208            var hasWidths = (properties.widths && properties.widths.length > 0) || Object.keys(smartCrops).length > 0;
2209            if (hasWidths) {
2210                var image = component.querySelector("img");
2211                var elemWidth = getWidth(component, component.parentNode);
2212                if (properties["smartcroprendition"] === "SmartCrop:Auto") {
2213                    image.setAttribute("srcset", CMP.image.dynamicMedia.getSrcSet(src, smartCrops));
2214                    width = getOptimalWidth(Object.keys(smartCrops, elemWidth));
2215                    image.setAttribute("src", CMP.image.dynamicMedia.getSrc(src, smartCrops[width]));
2216                } else {
2217                    width = getOptimalWidth(properties.widths, elemWidth);
2218                    image.setAttribute("src", CMP.image.dynamicMedia.getSrc(src, width));
2219                }
2220            }
2221        };
2222
2223        /**
2224         * Get the src attribute based on the optimal width
2225         * @param {String} src the src uri
2226         * @param {String} width the element width
2227         * @returns {String} the final src attribute
2228         */
2229        var getSrc = function(src, width) {
2230            if (src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR) > -1) {
2231                src = src.replace(SRC_URI_TEMPLATE_WIDTH_VAR, width);
2232            }
2233            return src;
2234        };
2235
2236
2237        return {
2238            getAutoSmartCrops: getAutoSmartCrops,
2239            getSrcSet: getSrcSet,
2240            getSrc: getSrc,
2241            setDMAttributes: setDMAttributes,
2242            getWidth: getWidth
2243        };
2244    }());
2245    document.dispatchEvent(new CustomEvent("core.wcm.components.commons.site.image.dynamic-media.loaded"));
2246}(window.document));
2247
2248/*******************************************************************************
2249 * Copyright 2022 Adobe
2250 *
2251 * Licensed under the Apache License, Version 2.0 (the "License");
2252 * you may not use this file except in compliance with the License.
2253 * You may obtain a copy of the License at
2254 *
2255 *     http://www.apache.org/licenses/LICENSE-2.0
2256 *
2257 * Unless required by applicable law or agreed to in writing, software
2258 * distributed under the License is distributed on an "AS IS" BASIS,
2259 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2260 * See the License for the specific language governing permissions and
2261 * limitations under the License.
2262 ******************************************************************************/
2263(function(document) {
2264
2265    "use strict";
2266
2267    window.CMP = window.CMP || {};
2268    window.CMP.image = window.CMP.image || {};
2269    window.CMP.image.v3 = (function() {
2270        var IS = "image";
2271
2272        var selectors = {
2273            self: "[data-cmp-hook-image='imageV3']"
2274        };
2275
2276        var properties = {
2277            "widths": {
2278                "default": [],
2279                "transform": function(value) {
2280                    var widths = [];
2281                    value.split(",").forEach(function(item) {
2282                        item = parseFloat(item);
2283                        if (!isNaN(item)) {
2284                            widths.push(item);
2285                        }
2286                    });
2287                    return widths;
2288                }
2289            },
2290            "dmimage": {
2291                "default": false,
2292                "transform": function(value) {
2293                    return !(value === null || typeof value === "undefined");
2294                }
2295            },
2296            "src": {
2297                "transform": function(value) {
2298                    return decodeURIComponent(value);
2299                }
2300            },
2301            "smartcroprendition": ""
2302        };
2303
2304        function Image(config) {
2305            var that = this;
2306            /**
2307             * Init the image if the image is from dynamic media
2308             * @param {HTMLElement} component the image component
2309             */
2310            that.initImage = function(component) {
2311                var options = CMP.utils.readData(component, IS);
2312                that._properties = CMP.utils.setupProperties(options, properties);
2313                if (that._properties.dmimage) {
2314                    // use encoded src for dynamic media
2315                    that._properties.src = options["src"];
2316                    CMP.image.dynamicMedia.setDMAttributes(component, that._properties);
2317                }
2318            };
2319            that.initImage(config.element);
2320        }
2321
2322        return {
2323            init: function() {
2324                var elements = document.querySelectorAll(selectors.self);
2325                for (var i = 0; i < elements.length; i++) {
2326                    new Image({ element: elements[i], options: CMP.utils.readData(elements[i], IS) });
2327                }
2328
2329                var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
2330                var body             = document.querySelector("body");
2331                var observer         = new MutationObserver(function(mutations) {
2332                    mutations.forEach(function(mutation) {
2333                        // needed for IE
2334                        var nodesArray = [].slice.call(mutation.addedNodes);
2335                        if (nodesArray.length > 0) {
2336                            nodesArray.forEach(function(addedNode) {
2337                                if (addedNode.querySelectorAll) {
2338                                    var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
2339                                    elementsArray.forEach(function(element) {
2340                                        new Image({ element: element, options: CMP.utils.readData(element, IS) });
2341                                    });
2342                                }
2343                            });
2344                        }
2345                    });
2346                });
2347
2348                observer.observe(body, {
2349                    subtree: true,
2350                    childList: true,
2351                    characterData: true
2352                });
2353            }
2354        };
2355    }());
2356
2357    var documentReady = document.readyState !== "loading" ? Promise.resolve() : new Promise(function(resolve) {
2358        document.addEventListener("DOMContentLoaded", resolve);
2359    });
2360    Promise.all([documentReady]).then(window.CMP.image.v3.init);
2361}(window.document));
2362
2363
2364/*******************************************************************************
2365 * Copyright 2022 Adobe
2366 *
2367 * Licensed under the Apache License, Version 2.0 (the "License");
2368 * you may not use this file except in compliance with the License.
2369 * You may obtain a copy of the License at
2370 *
2371 *     http://www.apache.org/licenses/LICENSE-2.0
2372 *
2373 * Unless required by applicable law or agreed to in writing, software
2374 * distributed under the License is distributed on an "AS IS" BASIS,
2375 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2376 * See the License for the specific language governing permissions and
2377 * limitations under the License.
2378 ******************************************************************************/
2379(function() {
2380    "use strict";
2381
2382    var NS = "cmp";
2383    var IS = "search";
2384
2385    var DELAY = 300; // time before fetching new results when the user is typing a search string
2386    var LOADING_DISPLAY_DELAY = 300; // minimum time during which the loading indicator is displayed
2387    var PARAM_RESULTS_OFFSET = "resultsOffset";
2388
2389    var keyCodes = {
2390        TAB: 9,
2391        ENTER: 13,
2392        ESCAPE: 27,
2393        ARROW_UP: 38,
2394        ARROW_DOWN: 40
2395    };
2396
2397    var selectors = {
2398        self: "[data-" + NS + '-is="' + IS + '"]',
2399        item: {
2400            self: "[data-" + NS + "-hook-" + IS + '="item"]',
2401            title: "[data-" + NS + "-hook-" + IS + '="itemTitle"]',
2402            focused: "." + NS + "-search__item--is-focused"
2403        }
2404    };
2405
2406    var properties = {
2407        /**
2408         * The minimum required length of the search term before results are fetched.
2409         *
2410         * @memberof Search
2411         * @type {Number}
2412         * @default 3
2413         */
2414        minLength: {
2415            "default": 3,
2416            transform: function(value) {
2417                value = parseFloat(value);
2418                return isNaN(value) ? null : value;
2419            }
2420        },
2421        /**
2422         * The maximal number of results fetched by a search request.
2423         *
2424         * @memberof Search
2425         * @type {Number}
2426         * @default 10
2427         */
2428        resultsSize: {
2429            "default": 10,
2430            transform: function(value) {
2431                value = parseFloat(value);
2432                return isNaN(value) ? null : value;
2433            }
2434        }
2435    };
2436
2437    var idCount = 0;
2438
2439    function readData(element) {
2440        var data = element.dataset;
2441        var options = [];
2442        var capitalized = IS;
2443        capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
2444        var reserved = ["is", "hook" + capitalized];
2445
2446        for (var key in data) {
2447            if (Object.prototype.hasOwnProperty.call(data, key)) {
2448                var value = data[key];
2449
2450                if (key.indexOf(NS) === 0) {
2451                    key = key.slice(NS.length);
2452                    key = key.charAt(0).toLowerCase() + key.substring(1);
2453
2454                    if (reserved.indexOf(key) === -1) {
2455                        options[key] = value;
2456                    }
2457                }
2458            }
2459        }
2460
2461        return options;
2462    }
2463
2464    function toggleShow(element, show) {
2465        if (element) {
2466            if (show !== false) {
2467                element.style.display = "block";
2468                element.setAttribute("aria-hidden", false);
2469            } else {
2470                element.style.display = "none";
2471                element.setAttribute("aria-hidden", true);
2472            }
2473        }
2474    }
2475
2476    function serialize(form) {
2477        var query = [];
2478        if (form && form.elements) {
2479            for (var i = 0; i < form.elements.length; i++) {
2480                var node = form.elements[i];
2481                if (!node.disabled && node.name) {
2482                    var param = [node.name, encodeURIComponent(node.value)];
2483                    query.push(param.join("="));
2484                }
2485            }
2486        }
2487        return query.join("&");
2488    }
2489
2490    function mark(node, regex) {
2491        if (!node || !regex) {
2492            return;
2493        }
2494
2495        // text nodes
2496        if (node.nodeType === 3) {
2497            var nodeValue = node.nodeValue;
2498            var match = regex.exec(nodeValue);
2499
2500            if (nodeValue && match) {
2501                var element = document.createElement("mark");
2502                element.className = NS + "-search__item-mark";
2503                element.appendChild(document.createTextNode(match[0]));
2504
2505                var after = node.splitText(match.index);
2506                after.nodeValue = after.nodeValue.substring(match[0].length);
2507                node.parentNode.insertBefore(element, after);
2508            }
2509        } else if (node.hasChildNodes()) {
2510            for (var i = 0; i < node.childNodes.length; i++) {
2511                // recurse
2512                mark(node.childNodes[i], regex);
2513            }
2514        }
2515    }
2516
2517    function localizeMessage(searchElementId, message, values = []) {
2518        const i18nMessages = JSON.parse(document.querySelector("#" + searchElementId).getAttribute("data-i18n-messages"));
2519        let translation = i18nMessages[message];
2520        // Insert values
2521        if (values.length > 0) {
2522            translation = translation.replace(/{(\d+)}/g, function(match, index) {
2523                return typeof values[index] !== "undefined" ? values[index] : match;
2524            });
2525        }
2526        return translation;
2527    }
2528
2529    // useful for Accessibility, helping users with low vision and users with cognitive disabilities to identify the change in results
2530    function updateSearchResultsStatusMessageElement(searchElementId, totalResults) {
2531        var searchResultsStatusMessage = document.querySelector("#" + searchElementId + "> .cmp_search__info");
2532        searchResultsStatusMessage.style.visibility = "visible";
2533        var searchResultsFoundMessage = localizeMessage(searchElementId, totalResults === 1 ? "{0} result" : "{0} results", [totalResults]);
2534        var searchResultsNotFoundMessage = localizeMessage(searchElementId, "No results");
2535        searchResultsStatusMessage.innerText = totalResults > 0 ? searchResultsFoundMessage : searchResultsNotFoundMessage;
2536    }
2537
2538    function Search(config) {
2539        if (config.element) {
2540            // prevents multiple initialization
2541            config.element.removeAttribute("data-" + NS + "-is");
2542        }
2543
2544        this._cacheElements(config.element);
2545        this._setupProperties(config.options);
2546
2547        this._action = this._elements.form.getAttribute("action");
2548        this._resultsOffset = 0;
2549        this._hasMoreResults = true;
2550
2551        this._elements.input.addEventListener("input", this._onInput.bind(this));
2552        this._elements.input.addEventListener("focus", this._onInput.bind(this));
2553        this._elements.input.addEventListener("keydown", this._onKeydown.bind(this));
2554        this._elements.clear.addEventListener("click", this._onClearClick.bind(this));
2555        document.addEventListener("click", this._onDocumentClick.bind(this));
2556        this._elements.results.addEventListener("scroll", this._onScroll.bind(this));
2557
2558        this._makeAccessible();
2559    }
2560
2561    Search.prototype._displayResults = function() {
2562        if (this._elements.input.value.length === 0) {
2563            toggleShow(this._elements.clear, false);
2564            this._cancelResults();
2565        } else if (this._elements.input.value.length < this._properties.minLength) {
2566            toggleShow(this._elements.clear, true);
2567        } else {
2568            this._updateResults();
2569            toggleShow(this._elements.clear, true);
2570        }
2571    };
2572
2573    Search.prototype._onScroll = function(event) {
2574        // fetch new results when the results to be scrolled down are less than the visible results
2575        if (this._elements.results.scrollTop + 2 * this._elements.results.clientHeight >= this._elements.results.scrollHeight) {
2576            this._resultsOffset += this._properties.resultsSize;
2577            this._displayResults();
2578        }
2579    };
2580
2581    Search.prototype._onInput = function(event) {
2582        var self = this;
2583        self._cancelResults();
2584        // start searching when the search term reaches the minimum length
2585        this._timeout = setTimeout(function() {
2586            self._displayResults();
2587        }, DELAY);
2588    };
2589
2590    Search.prototype._onKeydown = function(event) {
2591        var self = this;
2592
2593        switch (event.keyCode) {
2594            case keyCodes.TAB:
2595                if (self._resultsOpen()) {
2596                    toggleShow(self._elements.results, false);
2597                    self._elements.input.setAttribute("aria-expanded", "false");
2598                    this._hideSearchResultsStatusMessage();
2599                }
2600                break;
2601            case keyCodes.ENTER:
2602                event.preventDefault();
2603                if (self._resultsOpen()) {
2604                    var focused = self._elements.results.querySelector(selectors.item.focused);
2605                    if (focused) {
2606                        focused.click();
2607                    }
2608                }
2609                break;
2610            case keyCodes.ESCAPE:
2611                self._cancelResults();
2612                break;
2613            case keyCodes.ARROW_UP:
2614                if (self._resultsOpen()) {
2615                    event.preventDefault();
2616                    self._stepResultFocus(true);
2617                }
2618                break;
2619            case keyCodes.ARROW_DOWN:
2620                if (self._resultsOpen()) {
2621                    event.preventDefault();
2622                    self._stepResultFocus();
2623                } else {
2624                    // test the input and if necessary fetch and display the results
2625                    self._onInput();
2626                }
2627                break;
2628            default:
2629                return;
2630        }
2631    };
2632
2633    Search.prototype._onClearClick = function(event) {
2634        event.preventDefault();
2635        this._elements.input.value = "";
2636        toggleShow(this._elements.clear, false);
2637        toggleShow(this._elements.results, false);
2638        this._elements.input.setAttribute("aria-expanded", "false");
2639        this._hideSearchResultsStatusMessage();
2640    };
2641
2642    Search.prototype._onDocumentClick = function(event) {
2643        var inputContainsTarget =  this._elements.input.contains(event.target);
2644        var resultsContainTarget = this._elements.results.contains(event.target);
2645
2646        if (!(inputContainsTarget || resultsContainTarget)) {
2647            toggleShow(this._elements.results, false);
2648            this._elements.input.setAttribute("aria-expanded", "false");
2649            this._hideSearchResultsStatusMessage();
2650        }
2651    };
2652
2653    Search.prototype._resultsOpen = function() {
2654        return this._elements.results.style.display !== "none";
2655    };
2656
2657    Search.prototype._makeAccessible = function() {
2658        var id = NS + "-search-results-" + idCount;
2659        this._elements.input.setAttribute("aria-owns", id);
2660        this._elements.results.id = id;
2661        idCount++;
2662    };
2663
2664    Search.prototype._generateItems = function(data, results) {
2665        var self = this;
2666
2667        data.forEach(function(item) {
2668            var el = document.createElement("span");
2669            el.innerHTML = self._elements.itemTemplate.innerHTML;
2670            el.querySelectorAll(selectors.item.title)[0].appendChild(document.createTextNode(item.title));
2671            el.querySelectorAll(selectors.item.self)[0].setAttribute("href", self._safeHref(item.url));
2672            results.innerHTML += el.innerHTML;
2673        });
2674    };
2675
2676    Search.prototype._safeHref = function(href) {
2677        var a = document.createElement("a");
2678        a.href = href;
2679        return a.pathname;
2680    };
2681
2682    Search.prototype._markResults = function() {
2683        var nodeList = this._elements.results.querySelectorAll(selectors.item.self);
2684        var escapedTerm = this._elements.input.value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
2685        var regex = new RegExp("(" + escapedTerm + ")", "gi");
2686
2687        for (var i = this._resultsOffset - 1; i < nodeList.length; ++i) {
2688            var result = nodeList[i];
2689            mark(result, regex);
2690        }
2691    };
2692
2693    Search.prototype._stepResultFocus = function(reverse) {
2694        var results = this._elements.results.querySelectorAll(selectors.item.self);
2695        var focused = this._elements.results.querySelector(selectors.item.focused);
2696        var newFocused;
2697        var index = Array.prototype.indexOf.call(results, focused);
2698        var focusedCssClass = NS + "-search__item--is-focused";
2699
2700        if (results.length > 0) {
2701
2702            if (!reverse) {
2703                // highlight the next result
2704                if (index < 0) {
2705                    results[0].classList.add(focusedCssClass);
2706                    results[0].setAttribute("aria-selected", "true");
2707                } else if (index + 1 < results.length) {
2708                    results[index].classList.remove(focusedCssClass);
2709                    results[index].setAttribute("aria-selected", "false");
2710                    results[index + 1].classList.add(focusedCssClass);
2711                    results[index + 1].setAttribute("aria-selected", "true");
2712                }
2713
2714                // if the last visible result is partially hidden, scroll up until it's completely visible
2715                newFocused = this._elements.results.querySelector(selectors.item.focused);
2716                if (newFocused) {
2717                    var bottomHiddenHeight = newFocused.offsetTop + newFocused.offsetHeight - this._elements.results.scrollTop - this._elements.results.clientHeight;
2718                    if (bottomHiddenHeight > 0) {
2719                        this._elements.results.scrollTop += bottomHiddenHeight;
2720                    } else {
2721                        this._onScroll();
2722                    }
2723                }
2724
2725            } else {
2726                // highlight the previous result
2727                if (index >= 1) {
2728                    results[index].classList.remove(focusedCssClass);
2729                    results[index].setAttribute("aria-selected", "false");
2730                    results[index - 1].classList.add(focusedCssClass);
2731                    results[index - 1].setAttribute("aria-selected", "true");
2732                }
2733
2734                // if the first visible result is partially hidden, scroll down until it's completely visible
2735                newFocused = this._elements.results.querySelector(selectors.item.focused);
2736                if (newFocused) {
2737                    var topHiddenHeight = this._elements.results.scrollTop - newFocused.offsetTop;
2738                    if (topHiddenHeight > 0) {
2739                        this._elements.results.scrollTop -= topHiddenHeight;
2740                    }
2741                }
2742            }
2743        }
2744    };
2745
2746    Search.prototype._updateResults = function() {
2747        var self = this;
2748        if (self._hasMoreResults) {
2749            var request = new XMLHttpRequest();
2750            var url = self._action + "?" + serialize(self._elements.form) + "&" + PARAM_RESULTS_OFFSET + "=" + self._resultsOffset;
2751
2752            request.open("GET", url, true);
2753            request.onload = function() {
2754                // when the results are loaded: hide the loading indicator and display the search icon after a minimum period
2755                setTimeout(function() {
2756                    toggleShow(self._elements.loadingIndicator, false);
2757                    toggleShow(self._elements.icon, true);
2758                }, LOADING_DISPLAY_DELAY);
2759                if (request.status >= 200 && request.status < 400) {
2760                    // success status
2761                    var data = JSON.parse(request.responseText);
2762                    updateSearchResultsStatusMessageElement(self._elements.self.id, data.length);
2763                    if (data.length > 0) {
2764                        self._generateItems(data, self._elements.results);
2765                        self._markResults();
2766                        toggleShow(self._elements.results, true);
2767                        self._elements.input.setAttribute("aria-expanded", "true");
2768                    } else {
2769                        self._hasMoreResults = false;
2770                    }
2771                    // the total number of results is not a multiple of the fetched results:
2772                    // -> we reached the end of the query
2773                    if (self._elements.results.querySelectorAll(selectors.item.self).length % self._properties.resultsSize > 0) {
2774                        self._hasMoreResults = false;
2775                    }
2776                } else {
2777                    // error status
2778                }
2779            };
2780            // when the results are loading: display the loading indicator and hide the search icon
2781            toggleShow(self._elements.loadingIndicator, true);
2782            toggleShow(self._elements.icon, false);
2783            request.send();
2784        }
2785    };
2786
2787    Search.prototype._cancelResults = function() {
2788        clearTimeout(this._timeout);
2789        this._elements.results.scrollTop = 0;
2790        this._resultsOffset = 0;
2791        this._hasMoreResults = true;
2792        this._elements.results.innerHTML = "";
2793        this._elements.input.setAttribute("aria-expanded", "false");
2794        this._hideSearchResultsStatusMessage();
2795    };
2796
2797    Search.prototype._hideSearchResultsStatusMessage = function() {
2798        var searchResultsStatusMessage = document.querySelector("#" + this._elements.self.id + "> .cmp_search__info");
2799        searchResultsStatusMessage.style.visibility = "hidden";
2800    };
2801
2802    Search.prototype._cacheElements = function(wrapper) {
2803        this._elements = {};
2804        this._elements.self = wrapper;
2805        var hooks = this._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
2806
2807        for (var i = 0; i < hooks.length; i++) {
2808            var hook = hooks[i];
2809            var capitalized = IS;
2810            capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
2811            var key = hook.dataset[NS + "Hook" + capitalized];
2812            this._elements[key] = hook;
2813        }
2814    };
2815
2816    Search.prototype._setupProperties = function(options) {
2817        this._properties = {};
2818
2819        for (var key in properties) {
2820            if (Object.prototype.hasOwnProperty.call(properties, key)) {
2821                var property = properties[key];
2822                if (options && options[key] != null) {
2823                    if (property && typeof property.transform === "function") {
2824                        this._properties[key] = property.transform(options[key]);
2825                    } else {
2826                        this._properties[key] = options[key];
2827                    }
2828                } else {
2829                    this._properties[key] = properties[key]["default"];
2830                }
2831            }
2832        }
2833    };
2834
2835    function onDocumentReady() {
2836        var elements = document.querySelectorAll(selectors.self);
2837        for (var i = 0; i < elements.length; i++) {
2838            new Search({ element: elements[i], options: readData(elements[i]) });
2839        }
2840
2841        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
2842        var body = document.querySelector("body");
2843        var observer = new MutationObserver(function(mutations) {
2844            mutations.forEach(function(mutation) {
2845                // needed for IE
2846                var nodesArray = [].slice.call(mutation.addedNodes);
2847                if (nodesArray.length > 0) {
2848                    nodesArray.forEach(function(addedNode) {
2849                        if (addedNode.querySelectorAll) {
2850                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
2851                            elementsArray.forEach(function(element) {
2852                                new Search({ element: element, options: readData(element) });
2853                            });
2854                        }
2855                    });
2856                }
2857            });
2858        });
2859
2860        observer.observe(body, {
2861            subtree: true,
2862            childList: true,
2863            characterData: true
2864        });
2865    }
2866
2867    if (document.readyState !== "loading") {
2868        onDocumentReady();
2869    } else {
2870        document.addEventListener("DOMContentLoaded", onDocumentReady);
2871    }
2872
2873})();
2874
2875
2876/*******************************************************************************
2877 * Copyright 2016 Adobe
2878 *
2879 * Licensed under the Apache License, Version 2.0 (the "License");
2880 * you may not use this file except in compliance with the License.
2881 * You may obtain a copy of the License at
2882 *
2883 *     http://www.apache.org/licenses/LICENSE-2.0
2884 *
2885 * Unless required by applicable law or agreed to in writing, software
2886 * distributed under the License is distributed on an "AS IS" BASIS,
2887 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2888 * See the License for the specific language governing permissions and
2889 * limitations under the License.
2890 ******************************************************************************/
2891(function() {
2892    "use strict";
2893
2894    var NS = "cmp";
2895    var IS = "formText";
2896    var IS_DASH = "form-text";
2897    var SELF_SELECTOR = "[data-" + NS + '-is="' + IS + '"]';
2898
2899    var selectors = {
2900        self: SELF_SELECTOR,
2901        validationMessage: SELF_SELECTOR + " .cmp-form-text__validation-message"
2902    };
2903
2904    var displayValidationMessage = false;
2905
2906    var properties = {
2907        /**
2908         * A validation message to display if there is a type mismatch between the user input and expected input.
2909         *
2910         * @type {String}
2911         */
2912        constraintMessage: "",
2913        /**
2914         * A validation message to display if no input is supplied, but input is expected for the field.
2915         *
2916         * @type {String}
2917         */
2918        requiredMessage: ""
2919    };
2920
2921    function readData(element) {
2922        var data = element.dataset;
2923        var options = [];
2924        var capitalized = IS;
2925        capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
2926        var reserved = ["is", "hook" + capitalized];
2927
2928        for (var key in data) {
2929            if (Object.prototype.hasOwnProperty.call(data, key)) {
2930                var value = data[key];
2931
2932                if (key.indexOf(NS) === 0) {
2933                    key = key.slice(NS.length);
2934                    key = key.charAt(0).toLowerCase() + key.substring(1);
2935
2936                    if (reserved.indexOf(key) === -1) {
2937                        options[key] = value;
2938                    }
2939                }
2940            }
2941        }
2942
2943        return options;
2944    }
2945
2946    function FormText(config) {
2947        if (config.element) {
2948            // prevents multiple initialization
2949            config.element.removeAttribute("data-" + NS + "-is");
2950        }
2951
2952        this._cacheElements(config.element);
2953        this._setupProperties(config.options);
2954
2955        this._elements.input.addEventListener("invalid", this._onInvalid.bind(this));
2956        this._elements.input.addEventListener("input", this._onInput.bind(this));
2957        if (displayValidationMessage) {
2958            this._elements.input.checkValidity();
2959        }
2960    }
2961
2962    FormText.prototype._onInvalid = function(event) {
2963        event.target.setCustomValidity("");
2964        if (event.target.validity.typeMismatch) {
2965            if (this._properties.constraintMessage) {
2966                event.target.setCustomValidity(this._properties.constraintMessage);
2967            }
2968        } else if (event.target.validity.valueMissing) {
2969            if (this._properties.requiredMessage) {
2970                event.target.setCustomValidity(this._properties.requiredMessage);
2971            }
2972        }
2973        if (displayValidationMessage) {
2974            var validationMessage = event.target.parentElement.querySelector(".cmp-form-text__validation-message");
2975            if (validationMessage) {
2976                validationMessage.innerText = event.target.validationMessage;
2977            }
2978        }
2979    };
2980
2981    FormText.prototype._onInput = function(event) {
2982        event.target.setCustomValidity("");
2983        if (displayValidationMessage) {
2984            event.target.checkValidity();
2985        }
2986    };
2987
2988    FormText.prototype._cacheElements = function(wrapper) {
2989        this._elements = {};
2990        this._elements.self = wrapper;
2991        var hooks = this._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS_DASH + "]");
2992        for (var i = 0; i < hooks.length; i++) {
2993            var hook = hooks[i];
2994            var capitalized = IS;
2995            capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
2996            var key = hook.dataset[NS + "Hook" + capitalized];
2997            this._elements[key] = hook;
2998        }
2999    };
3000
3001    FormText.prototype._setupProperties = function(options) {
3002        this._properties = {};
3003
3004        for (var key in properties) {
3005            if (Object.prototype.hasOwnProperty.call(properties, key)) {
3006                var property = properties[key];
3007                if (options && options[key] != null) {
3008                    if (property && typeof property.transform === "function") {
3009                        this._properties[key] = property.transform(options[key]);
3010                    } else {
3011                        this._properties[key] = options[key];
3012                    }
3013                } else {
3014                    this._properties[key] = properties[key]["default"];
3015                }
3016            }
3017        }
3018    };
3019
3020    function onDocumentReady() {
3021        var validationMessages = document.querySelectorAll(selectors.validationMessage);
3022        if (validationMessages && validationMessages.length > 0) {
3023            displayValidationMessage = true;
3024        }
3025
3026        var elements = document.querySelectorAll(selectors.self);
3027        for (var i = 0; i < elements.length; i++) {
3028            new FormText({ element: elements[i], options: readData(elements[i]) });
3029        }
3030
3031        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
3032        var body = document.querySelector("body");
3033        var observer = new MutationObserver(function(mutations) {
3034            mutations.forEach(function(mutation) {
3035                // needed for IE
3036                var nodesArray = [].slice.call(mutation.addedNodes);
3037                if (nodesArray.length > 0) {
3038                    nodesArray.forEach(function(addedNode) {
3039                        if (addedNode.querySelectorAll) {
3040                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
3041                            elementsArray.forEach(function(element) {
3042                                new FormText({ element: element, options: readData(element) });
3043                            });
3044                        }
3045                    });
3046                }
3047            });
3048        });
3049
3050        observer.observe(body, {
3051            subtree: true,
3052            childList: true,
3053            characterData: true
3054        });
3055    }
3056
3057    if (document.readyState !== "loading") {
3058        onDocumentReady();
3059    } else {
3060        document.addEventListener("DOMContentLoaded", onDocumentReady);
3061    }
3062
3063})();
3064
3065
3066/*******************************************************************************
3067 * Copyright 2020 Adobe
3068 *
3069 * Licensed under the Apache License, Version 2.0 (the "License");
3070 * you may not use this file except in compliance with the License.
3071 * You may obtain a copy of the License at
3072 *
3073 *     http://www.apache.org/licenses/LICENSE-2.0
3074 *
3075 * Unless required by applicable law or agreed to in writing, software
3076 * distributed under the License is distributed on an "AS IS" BASIS,
3077 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3078 * See the License for the specific language governing permissions and
3079 * limitations under the License.
3080 ******************************************************************************/
3081(function() {
3082    "use strict";
3083
3084    var NS = "cmp";
3085    var IS = "pdfviewer";
3086    var SDK_URL = "https://acrobatservices.adobe.com/view-sdk/viewer.js";
3087    var SDK_READY_EVENT = "adobe_dc_view_sdk.ready";
3088
3089    var selectors = {
3090        self: "[data-" + NS + '-is="' + IS + '"]',
3091        sdkScript: 'script[src="' + SDK_URL + '"]'
3092    };
3093
3094    function initSDK() {
3095        var sdkIncluded = document.querySelectorAll(selectors.sdkScript).length > 0;
3096        if (!window.adobe_dc_view_sdk && !sdkIncluded) {
3097            var dcv = document.createElement("script");
3098            dcv.type = "text/javascript";
3099            dcv.src = SDK_URL;
3100            document.body.appendChild(dcv);
3101        }
3102    }
3103
3104    function previewPdf(component) {
3105        // prevents multiple initialization
3106        component.removeAttribute("data-" + NS + "-is");
3107
3108        // add the view sdk to the page
3109        initSDK();
3110
3111        // manage the preview
3112        if (component.dataset && component.id) {
3113            if (window.AdobeDC && window.AdobeDC.View) {
3114                dcView(component);
3115            } else {
3116                document.addEventListener(SDK_READY_EVENT, function() {
3117                    dcView(component);
3118                });
3119            }
3120        }
3121    }
3122
3123    function dcView(component) {
3124        var adobeDCView = new window.AdobeDC.View({
3125            clientId: component.dataset.cmpClientId,
3126            divId: component.id + "-content",
3127            reportSuiteId: component.dataset.cmpReportSuiteId,
3128            locale: typeof Granite !== "undefined" && Granite && Granite.I18n ? Granite.I18n.getLocale() : navigator.language || navigator.userLanguage
3129        });
3130        adobeDCView.previewFile({
3131            content: { location: { url: component.dataset.cmpDocumentPath } },
3132            metaData: { fileName: component.dataset.cmpDocumentFileName }
3133        }, JSON.parse(component.dataset.cmpViewerConfigJson));
3134    }
3135
3136    /**
3137     * Document ready handler and DOM mutation observers. Initializes Accordion components as necessary.
3138     *
3139     * @private
3140     */
3141    function onDocumentReady() {
3142        var elements = document.querySelectorAll(selectors.self);
3143        for (var i = 0; i < elements.length; i++) {
3144            previewPdf(elements[i]);
3145        }
3146
3147        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
3148        var body = document.querySelector("body");
3149        var observer = new MutationObserver(function(mutations) {
3150            mutations.forEach(function(mutation) {
3151                // needed for IE
3152                var nodesArray = [].slice.call(mutation.addedNodes);
3153                if (nodesArray.length > 0) {
3154                    nodesArray.forEach(function(addedNode) {
3155                        if (addedNode.querySelectorAll) {
3156                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
3157                            elementsArray.forEach(function(element) {
3158                                previewPdf(element);
3159                            });
3160                        }
3161                    });
3162                }
3163            });
3164        });
3165
3166        observer.observe(body, {
3167            subtree: true,
3168            childList: true,
3169            characterData: true
3170        });
3171
3172    }
3173
3174    if (document.readyState !== "loading") {
3175        onDocumentReady();
3176    } else {
3177        document.addEventListener("DOMContentLoaded", onDocumentReady);
3178    }
3179}());
3180
3181
3182/*******************************************************************************
3183 * Copyright 2022 Adobe
3184 *
3185 * Licensed under the Apache License, Version 2.0 (the "License");
3186 * you may not use this file except in compliance with the License.
3187 * You may obtain a copy of the License at
3188 *
3189 *     http://www.apache.org/licenses/LICENSE-2.0
3190 *
3191 * Unless required by applicable law or agreed to in writing, software
3192 * distributed under the License is distributed on an "AS IS" BASIS,
3193 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3194 * See the License for the specific language governing permissions and
3195 * limitations under the License.
3196 ******************************************************************************/
3197(function() {
3198    "use strict";
3199
3200    var dataLayerEnabled;
3201    var dataLayer;
3202    var dataLayerName;
3203
3204    /**
3205     * Adds Click Event Listener to the main <div> of the Text Components
3206     */
3207    function addClickEventListenerToTextComponents() {
3208        var componentMainDivs = document.getElementsByClassName("cmp-text");
3209
3210        for (var i = 0; i < componentMainDivs.length; i++) {
3211            componentMainDivs[i].addEventListener("click", addClickedLinkToDataLayer);
3212        }
3213    }
3214
3215    /**
3216     * Adds clicked link contained by the Text Component to Data Layer
3217     *
3218     * @private
3219     * @param {Object} event The Click event
3220     */
3221    function addClickedLinkToDataLayer(event) {
3222        var element = event.currentTarget;
3223        var componentId = getDataLayerId(element);
3224
3225        if (event.target.tagName === "A") {
3226            dataLayer.push({
3227                event: "cmp:click",
3228                eventInfo: {
3229                    path: "component." + componentId,
3230                    link: event.target.getAttribute("href")
3231                }
3232            });
3233        }
3234    }
3235
3236    /**
3237     * Parses the dataLayer string and returns the ID
3238     *
3239     * @private
3240     * @param {HTMLElement} item, the Text item
3241     * @returns {String} dataLayerId or undefined
3242     */
3243    function getDataLayerId(item) {
3244        if (item) {
3245            if (item.dataset.cmpDataLayer) {
3246                return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0];
3247            } else {
3248                return item.id;
3249            }
3250        }
3251        return null;
3252    }
3253
3254    function onDocumentReady() {
3255        dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled");
3256        if (dataLayerEnabled) {
3257            dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer";
3258            dataLayer = window[dataLayerName] = window[dataLayerName] || [];
3259
3260            addClickEventListenerToTextComponents();
3261        }
3262    }
3263
3264    if (document.readyState !== "loading") {
3265        onDocumentReady();
3266    } else {
3267        document.addEventListener("DOMContentLoaded", onDocumentReady);
3268    }
3269})();
3270

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.