PageSourceSearch

https://www.boeing.co.in/etc.clientlibs/theboeingcompany/clientlibs/clientlib-base.min.js

js boeing.co.in collected 2026-10-02 11:05:09 UTC 168,321 bytes, 4,537 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/LICENSE-2.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(function() {
17    "use strict";
18    const version2 = document.querySelector('html').classList.contains('version2');
19
20    var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined;
21    if (!containerUtils) {
22        // eslint-disable-next-line no-console
23        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.");
24    }
25    var dataLayerEnabled;
26    var dataLayer;
27    var dataLayerName;
28    var delay = 100;
29
30    var NS = "cmp";
31    var IS = "accordion";
32
33    var keyCodes = {
34        ENTER: 13,
35        SPACE: 32,
36        END: 35,
37        HOME: 36,
38        ARROW_LEFT: 37,
39        ARROW_UP: 38,
40        ARROW_RIGHT: 39,
41        ARROW_DOWN: 40
42    };
43
44    var selectors = {
45        self: "[data-" + NS + '-is="' + IS + '"]'
46    };
47
48    var cssClasses = {
49        button: {
50            disabled: "cmp-accordion__button--disabled",
51            expanded: "cmp-accordion__button--expanded"
52        },
53        panel: {
54            hidden: (version2) ? "cmp-accordion__panel--collapse" : "cmp-accordion__panel--hidden",
55            expanded: (version2) ? "cmp-accordion__panel--show" : "cmp-accordion__panel--expanded"
56        }
57    };
58
59    var dataAttributes = {
60        item: {
61            expanded: "data-cmp-expanded"
62        }
63    };
64
65    var properties = {
66        /**
67         * Determines whether a single accordion item is forced to be expanded at a time.
68         * Expanding one item will collapse all others.
69         *
70         * @memberof Accordion
71         * @type {Boolean}
72         * @default false
73         */
74        "singleExpansion": {
75            "default": false,
76            "transform": function(value) {
77                return !(value === null || typeof value === "undefined");
78            }
79        }
80    };
81
82    /**
83     * Accordion Configuration.
84     *
85     * @typedef {Object} AccordionConfig Represents an Accordion configuration
86     * @property {HTMLElement} element The HTMLElement representing the Accordion
87     * @property {Object} options The Accordion options
88     */
89
90    /**
91     * Accordion.
92     *
93     * @class Accordion
94     * @classdesc An interactive Accordion component for toggling panels of related content
95     * @param {AccordionConfig} config The Accordion configuration
96     */
97    function Accordion(config) {
98        var that = this;
99
100        if (config && config.element) {
101            init(config);
102        }
103
104        /**
105         * Initializes the Accordion.
106         *
107         * @private
108         * @param {AccordionConfig} config The Accordion configuration
109         */
110        function init(config) {
111            that._config = config;
112
113            // prevents multiple initialization
114            config.element.removeAttribute("data-" + NS + "-is");
115
116            setupProperties(config.options);
117            cacheElements(config.element);
118            if (that._elements["item"]) {
119                // ensures multiple element types are arrays.
120                that._elements["item"] = Array.isArray(that._elements["item"]) ? that._elements["item"] : [that._elements["item"]];
121                that._elements["button"] = Array.isArray(that._elements["button"]) ? that._elements["button"] : [that._elements["button"]];
122                that._elements["panel"] = Array.isArray(that._elements["panel"]) ? that._elements["panel"] : [that._elements["panel"]];
123
124                if (that._properties.singleExpansion) {
125                    var expandedItems = getExpandedItems();
126                    // multiple expanded items annotated, display the last item open.
127                    if (expandedItems.length > 1) {
128                        toggle(expandedItems.length - 1);
129                    }
130                }
131
132                trackInitialView();
133                refreshItems();
134                bindEvents();
135                scrollToDeepLinkIdInAccordion();
136            }
137            if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) {
138                /*
139                 * Editor message handling:
140                 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
141                 * - check that the message data panel container type is correct and that the id (path) matches this specific Accordion component
142                 * - if so, route the "navigate" operation to enact a navigation of the Accordion based on index data
143                 */
144                window.CQ.CoreComponents.MESSAGE_CHANNEL = window.CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window);
145                window.CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) {
146                    if (message.data && message.data.type === "cmp-accordion" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) {
147                        if (message.data.operation === "navigate") {
148                            // switch to single expansion mode when navigating in edit mode.
149                            var singleExpansion = that._properties.singleExpansion;
150                            that._properties.singleExpansion = true;
151                            toggle(message.data.index);
152
153                            // revert to the configured state.
154                            that._properties.singleExpansion = singleExpansion;
155                        }
156                    }
157                });
158            }
159        }
160
161        /**
162         * Displays the panel containing the element that corresponds to the deep link in the URI fragment
163         * and scrolls the browser to this element.
164         */
165        function scrollToDeepLinkIdInAccordion() {
166            if (containerUtils) {
167                var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "item", "item");
168                if (deepLinkItemIdx > -1) {
169                    var deepLinkItem = that._elements["item"][deepLinkItemIdx];
170                    if (deepLinkItem && !deepLinkItem.hasAttribute(dataAttributes.item.expanded)) {
171                        // if single expansion: close all accordion items
172                        if (that._properties.singleExpansion) {
173                            for (var j = 0; j < that._elements["item"].length; j++) {
174                                if (that._elements["item"][j].hasAttribute(dataAttributes.item.expanded)) {
175                                    setItemExpanded(that._elements["item"][j], false, true);
176                                }
177                            }
178                        }
179                        // expand the accordion item containing the deep link
180                        setItemExpanded(deepLinkItem, true, true);
181                    }
182                    var hashId = window.location.hash.substring(1);
183                    if (hashId) {
184                        var hashItem = document.querySelector("[id='" + hashId + "']");
185                        if (hashItem) {
186                            hashItem.scrollIntoView();
187                        }
188                    }
189                }
190            }
191        }
192
193        /**
194         * Caches the Accordion elements as defined via the {@code data-accordion-hook="ELEMENT_NAME"} markup API.
195         *
196         * @private
197         * @param {HTMLElement} wrapper The Accordion wrapper element
198         */
199        function cacheElements(wrapper) {
200            that._elements = {};
201            that._elements.self = wrapper;
202            var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
203
204            for (var i = 0; i < hooks.length; i++) {
205                var hook = hooks[i];
206                if (hook.closest("." + NS + "-" + IS) === that._elements.self) { // only process own accordion elements
207                    var capitalized = IS;
208                    capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
209                    var key = hook.dataset[NS + "Hook" + capitalized];
210                    if (that._elements[key]) {
211                        if (!Array.isArray(that._elements[key])) {
212                            var tmp = that._elements[key];
213                            that._elements[key] = [tmp];
214                        }
215                        that._elements[key].push(hook);
216                    } else {
217                        that._elements[key] = hook;
218                    }
219                }
220            }
221        }
222
223        /**
224         * Sets up properties for the Accordion based on the passed options.
225         *
226         * @private
227         * @param {Object} options The Accordion options
228         */
229        function setupProperties(options) {
230            that._properties = {};
231
232            for (var key in properties) {
233                if (Object.prototype.hasOwnProperty.call(properties, key)) {
234                    var property = properties[key];
235                    var value = null;
236
237                    if (options && options[key] != null) {
238                        value = options[key];
239
240                        // transform the provided option
241                        if (property && typeof property.transform === "function") {
242                            value = property.transform(value);
243                        }
244                    }
245
246                    if (value === null) {
247                        // value still null, take the property default
248                        value = properties[key]["default"];
249                    }
250
251                    that._properties[key] = value;
252                }
253            }
254        }
255
256        /**
257         * Binds Accordion event handling.
258         *
259         * @private
260         */
261        function bindEvents() {
262            window.addEventListener("hashchange", scrollToDeepLinkIdInAccordion, false);
263            var buttons = that._elements["button"];
264            if (buttons) {
265                for (var i = 0; i < buttons.length; i++) {
266                    (function(index) {
267                        buttons[i].addEventListener("click", function(event) {
268                            toggle(index);
269                            focusButton(index);
270                        });
271                        buttons[i].addEventListener("keydown", function(event) {
272                            onButtonKeyDown(event, index);
273                        });
274                    })(i);
275                }
276            }
277        }
278
279        /**
280         * Handles button keydown events.
281         *
282         * @private
283         * @param {Object} event The keydown event
284         * @param {Number} index The index of the button triggering the event
285         */
286        function onButtonKeyDown(event, index) {
287            var lastIndex = that._elements["button"].length - 1;
288
289            switch (event.keyCode) {
290                case keyCodes.ARROW_LEFT:
291                case keyCodes.ARROW_UP:
292                    event.preventDefault();
293                    if (index > 0) {
294                        focusButton(index - 1);
295                    }
296                    break;
297                case keyCodes.ARROW_RIGHT:
298                case keyCodes.ARROW_DOWN:
299                    event.preventDefault();
300                    if (index < lastIndex) {
301                        focusButton(index + 1);
302                    }
303                    break;
304                case keyCodes.HOME:
305                    event.preventDefault();
306                    focusButton(0);
307                    break;
308                case keyCodes.END:
309                    event.preventDefault();
310                    focusButton(lastIndex);
311                    break;
312                case keyCodes.ENTER:
313                case keyCodes.SPACE:
314                    event.preventDefault();
315                    toggle(index);
316                    focusButton(index);
317                    break;
318                default:
319                    return;
320            }
321        }
322
323        /**
324         * General handler for toggle of an item.
325         *
326         * @private
327         * @param {Number} index The index of the item to toggle
328         */
329        function toggle(index) {
330            var item = that._elements["item"][index];
331            if (item) {
332                if (that._properties.singleExpansion) {
333                    // ensure only a single item is expanded if single expansion is enabled.
334                    for (var i = 0; i < that._elements["item"].length; i++) {
335                        if (that._elements["item"][i] !== item) {
336                            var expanded = getItemExpanded(that._elements["item"][i]);
337                            if (expanded) {
338                                setItemExpanded(that._elements["item"][i], false);
339                            }
340                        }
341                    }
342                }
343                setItemExpanded(item, !getItemExpanded(item));
344
345                if (dataLayerEnabled) {
346                    if (window.customTracking && typeof window.customTracking.trackingFlagGetter === 'function') {
347                        if(window.customTracking.trackingFlagGetter()){
348                            var accordionId = that._elements.self.id;
349                            var expandedItems = getExpandedItems()
350                                .map(function(item) {
351                                    return getDataLayerId(item);
352                                });
353
354                            var uploadPayload = { component: {} };
355                            uploadPayload.component[accordionId] = { shownItems: expandedItems };
356
357                            var removePayload = { component: {} };
358                            removePayload.component[accordionId] = { shownItems: undefined };
359
360                            dataLayer.push(removePayload);
361                            dataLayer.push(uploadPayload);
362                        }
363                    }
364                    
365                }
366            }
367        }
368
369        /**
370         * Sets an item's expanded state based on the provided flag and refreshes its internals.
371         *
372         * @private
373         * @param {HTMLElement} item The item to mark as expanded, or not expanded
374         * @param {Boolean} expanded true to mark the item expanded, false otherwise
375         * @param {Boolean} keepHash true to keep the hash in the URL, false to update it
376         */
377        function setItemExpanded(item, expanded, keepHash) {
378            if (expanded) {
379                item.setAttribute(dataAttributes.item.expanded, "");
380                var index = that._elements["item"].indexOf(item);
381                if (!keepHash && containerUtils) {
382                    containerUtils.updateUrlHash(that, "item", index);
383                }
384                if (dataLayerEnabled) {
385                    if (window.customTracking && typeof window.customTracking.trackingFlagGetter === 'function') {
386                        if(window.customTracking.trackingFlagGetter()){
387                            dataLayer.push({
388                                event: "cmp:click",
389                                eventInfo: {
390                                    path: "component." + getDataLayerId(item)
391                                }
392                            });
393                        }
394                    }
395                    
396                }
397
398            } else {
399                item.removeAttribute(dataAttributes.item.expanded);
400                if (!keepHash && containerUtils) {
401                    containerUtils.removeUrlHash();
402                }
403                if (dataLayerEnabled) {
404                    if (window.customTracking && typeof window.customTracking.trackingFlagGetter === 'function') {
405                        if(window.customTracking.trackingFlagGetter()){
406                            dataLayer.push({
407                                event: "cmp:hide",
408                                eventInfo: {
409                                    path: "component." + getDataLayerId(item)
410                                }
411                            });
412                        }
413                    }
414                    
415                }
416            }
417            refreshItem(item);
418        }
419
420        /**
421         * Gets an item's expanded state.
422         *
423         * @private
424         * @param {HTMLElement} item The item for checking its expanded state
425         * @returns {Boolean} true if the item is expanded, false otherwise
426         */
427        function getItemExpanded(item) {
428            return item && item.dataset && item.dataset["cmpExpanded"] !== undefined;
429        }
430
431        /**
432         * Refreshes an item based on its expanded state.
433         *
434         * @private
435         * @param {HTMLElement} item The item to refresh
436         */
437        function refreshItem(item) {
438            var expanded = getItemExpanded(item);
439            if (expanded) {
440                expandItem(item);
441            } else {
442                collapseItem(item);
443            }
444        }
445
446        /**
447         * Refreshes all items based on their expanded state.
448         *
449         * @private
450         */
451        function refreshItems() {
452            for (var i = 0; i < that._elements["item"].length; i++) {
453                refreshItem(that._elements["item"][i]);
454            }
455        }
456
457        /**
458         * Custom tracking function to track initial view of item
459         *
460         * @private
461         */
462        function initialViewItem(item) {
463            var expanded = getItemExpanded(item);
464            if (expanded) {
465                if (dataLayerEnabled) {
466                    dataLayer.push({
467                        event: "cmp:initial",
468                        eventInfo: {
469                            path: "component." + getDataLayerId(item)
470                        }
471                    });
472                    // if (window.customTracking && typeof window.customTracking.trackingFlagGetter === 'function') {
473                    //     if(window.customTracking.trackingFlagGetter()){
474                    //         dataLayer.push({
475                    //             event: "cmp:initial",
476                    //             eventInfo: {
477                    //                 path: "component." + getDataLayerId(item)
478                    //             }
479                    //         });
480                    //     }
481                    // }
482                    
483                }
484            } 
485        }
486
487        function trackInitialView() {
488            for (var i = 0; i < that._elements["item"].length; i++) {
489                initialViewItem(that._elements["item"][i]);
490            }
491        }
492
493        /**
494         * Returns all expanded items.
495         *
496         * @private
497         * @returns {HTMLElement[]} The expanded items
498         */
499        function getExpandedItems() {
500            var expandedItems = [];
501
502            for (var i = 0; i < that._elements["item"].length; i++) {
503                var item = that._elements["item"][i];
504                var expanded = getItemExpanded(item);
505                if (expanded) {
506                    expandedItems.push(item);
507                }
508            }
509
510            return expandedItems;
511        }
512
513        /**
514         * Annotates the item and its internals with
515         * the necessary style and accessibility attributes to indicate it is expanded.
516         *
517         * @private
518         * @param {HTMLElement} item The item to annotate as expanded
519         */
520        function expandItem(item) {
521            var index = that._elements["item"].indexOf(item);
522            if (index > -1) {
523                var button = that._elements["button"][index];
524                var panel = that._elements["panel"][index];
525                button.classList.add(cssClasses.button.expanded);
526                button.classList.remove('collapsed');
527                // used to fix some known screen readers issues in reading the correct state of the 'aria-expanded' attribute
528                // e.g. https://bugs.webkit.org/show_bug.cgi?id=210934
529                setTimeout(function() {
530                    button.setAttribute("aria-expanded", true);
531                }, delay);
532                panel.classList.add(cssClasses.panel.expanded);
533                panel.classList.add('show');
534                panel.classList.remove(cssClasses.panel.hidden);
535                panel.setAttribute("aria-hidden", false);
536            }
537        }
538
539        /**
540         * Annotates the item and its internals with
541         * the necessary style and accessibility attributes to indicate it is not expanded.
542         *
543         * @private
544         * @param {HTMLElement} item The item to annotate as not expanded
545         */
546        function collapseItem(item) {
547            var index = that._elements["item"].indexOf(item);
548            if (index > -1) {
549                var button = that._elements["button"][index];
550                var panel = that._elements["panel"][index];
551                button.classList.remove(cssClasses.button.expanded);
552                button.classList.add('collapsed');
553                // used to fix some known screen readers issues in reading the correct state of the 'aria-expanded' attribute
554                // e.g. https://bugs.webkit.org/show_bug.cgi?id=210934
555                setTimeout(function() {
556                    button.setAttribute("aria-expanded", false);
557                }, delay);
558                panel.classList.add(cssClasses.panel.hidden);
559                panel.classList.remove(cssClasses.panel.expanded);
560                panel.classList.remove('show');
561                panel.setAttribute("aria-hidden", true);
562            }
563        }
564
565        /**
566         * Focuses the button at the provided index.
567         *
568         * @private
569         * @param {Number} index The index of the button to focus
570         */
571        function focusButton(index) {
572            var button = that._elements["button"][index];
573            button.focus();
574        }
575    }
576
577    /**
578     * Reads options data from the Accordion wrapper element, defined via {@code data-cmp-*} data attributes.
579     *
580     * @private
581     * @param {HTMLElement} element The Accordion element to read options data from
582     * @returns {Object} The options read from the component data attributes
583     */
584    function readData(element) {
585        var data = element.dataset;
586        var options = [];
587        var capitalized = IS;
588        capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
589        var reserved = ["is", "hook" + capitalized];
590
591        for (var key in data) {
592            if (Object.prototype.hasOwnProperty.call(data, key)) {
593                var value = data[key];
594
595                if (key.indexOf(NS) === 0) {
596                    key = key.slice(NS.length);
597                    key = key.charAt(0).toLowerCase() + key.substring(1);
598
599                    if (reserved.indexOf(key) === -1) {
600                        options[key] = value;
601                    }
602                }
603            }
604        }
605
606        return options;
607    }
608
609    /**
610     * Parses the dataLayer string and returns the ID
611     *
612     * @private
613     * @param {HTMLElement} item the accordion item
614     * @returns {String} dataLayerId or undefined
615     */
616    function getDataLayerId(item) {
617        if (item) {
618            if (item.dataset.cmpDataLayer) {
619                return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0];
620            } else {
621                return item.id;
622            }
623        }
624        return null;
625    }
626
627    /**
628     * Document ready handler and DOM mutation observers. Initializes Accordion components as necessary.
629     *
630     * @private
631     */
632    function onDocumentReady() {
633        dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled");
634        if (dataLayerEnabled) {
635            dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer";
636            dataLayer = window[dataLayerName] = window[dataLayerName] || [];
637        }
638
639        var elements = document.querySelectorAll(selectors.self);
640        for (var i = 0; i < elements.length; i++) {
641            new Accordion({ element: elements[i], options: readData(elements[i]) });
642        }
643
644        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
645        var body = document.querySelector("body");
646        var observer = new MutationObserver(function(mutations) {
647            mutations.forEach(function(mutation) {
648                // needed for IE
649                var nodesArray = [].slice.call(mutation.addedNodes);
650                if (nodesArray.length > 0) {
651                    nodesArray.forEach(function(addedNode) {
652                        if (addedNode.querySelectorAll) {
653                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
654                            elementsArray.forEach(function(element) {
655                                new Accordion({ element: element, options: readData(element) });
656                            });
657                        }
658                    });
659                }
660            });
661        });
662
663        observer.observe(body, {
664            subtree: true,
665            childList: true,
666            characterData: true
667        });
668    }
669
670    if (document.readyState !== "loading") {
671        onDocumentReady();
672    } else {
673        document.addEventListener("DOMContentLoaded", onDocumentReady);
674    }
675
676    if (containerUtils) {
677        window.addEventListener("load", containerUtils.scrollToAnchor, false);
678    }
679
680}());
681/*******************************************************************************
682 * Copyright 2019 Adobe
683 *
684 * Licensed under the Apache License, Version 2.0 (the "License");
685 * you may not use this file except in compliance with the License.
686 * You may obtain a copy of the License at
687 *
688 *     http://www.apache.org/licenses/LICENSE2.0
689 *
690 * Unless required by applicable law or agreed to in writing, software
691 * distributed under the License is distributed on an "AS IS" BASIS,
692 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
693 * See the License for the specific language governing permissions and
694 * limitations under the License.
695 ******************************************************************************/
696
697/**
698 * Element.matches()
699 * https://developer.mozilla.org/enUS/docs/Web/API/Element/matches#Polyfill
700 */
701if (!Element.prototype.matches) {
702    Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
703}
704
705// eslint-disable-next-line valid-jsdoc
706/**
707 * Element.closest()
708 * https://developer.mozilla.org/enUS/docs/Web/API/Element/closest#Polyfill
709 */
710if (!Element.prototype.closest) {
711    Element.prototype.closest = function(s) {
712        "use strict";
713        var el = this;
714        if (!document.documentElement.contains(el)) {
715            return null;
716        }
717        do {
718            if (el.matches(s)) {
719                return el;
720            }
721            el = el.parentElement || el.parentNode;
722        } while (el !== null && el.nodeType === 1);
723        return null;
724    };
725}
726
727/*******************************************************************************
728 * Copyright 2019 Adobe
729 *
730 * Licensed under the Apache License, Version 2.0 (the "License");
731 * you may not use this file except in compliance with the License.
732 * You may obtain a copy of the License at
733 *
734 *     http://www.apache.org/licenses/LICENSE-2.0
735 *
736 * Unless required by applicable law or agreed to in writing, software
737 * distributed under the License is distributed on an "AS IS" BASIS,
738 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
739 * See the License for the specific language governing permissions and
740 * limitations under the License.
741 ******************************************************************************/
742(function() {
743    "use strict";
744
745    var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined;
746    if (!containerUtils) {
747        // eslint-disable-next-line no-console
748        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.");
749    }
750    var dataLayerEnabled;
751    var dataLayer;
752    var dataLayerName;
753    var delay = 100;
754
755    var NS = "cmp";
756    var IS = "accordion";
757
758    var keyCodes = {
759        ENTER: 13,
760        SPACE: 32,
761        END: 35,
762        HOME: 36,
763        ARROW_LEFT: 37,
764        ARROW_UP: 38,
765        ARROW_RIGHT: 39,
766        ARROW_DOWN: 40
767    };
768
769    var selectors = {
770        self: "[data-" + NS + '-is="' + IS + '"]'
771    };
772
773    var cssClasses = {
774        button: {
775            disabled: "cmp-accordion__button--disabled",
776            expanded: "cmp-accordion__button--expanded"
777        },
778        panel: {
779            hidden: "cmp-accordion__panel--hidden",
780            expanded: "cmp-accordion__panel--expanded"
781        }
782    };
783
784    var dataAttributes = {
785        item: {
786            expanded: "data-cmp-expanded"
787        }
788    };
789
790    var properties = {
791        /**
792         * Determines whether a single accordion item is forced to be expanded at a time.
793         * Expanding one item will collapse all others.
794         *
795         * @memberof Accordion
796         * @type {Boolean}
797         * @default false
798         */
799        "singleExpansion": {
800            "default": false,
801            "transform": function(value) {
802                return !(value === null || typeof value === "undefined");
803            }
804        }
805    };
806
807    /**
808     * Accordion Configuration.
809     *
810     * @typedef {Object} AccordionConfig Represents an Accordion configuration
811     * @property {HTMLElement} element The HTMLElement representing the Accordion
812     * @property {Object} options The Accordion options
813     */
814
815    /**
816     * Accordion.
817     *
818     * @class Accordion
819     * @classdesc An interactive Accordion component for toggling panels of related content
820     * @param {AccordionConfig} config The Accordion configuration
821     */
822    function Accordion(config) {
823        var that = this;
824
825        if (config && config.element) {
826            init(config);
827        }
828
829        /**
830         * Initializes the Accordion.
831         *
832         * @private
833         * @param {AccordionConfig} config The Accordion configuration
834         */
835        function init(config) {
836            that._config = config;
837
838            // prevents multiple initialization
839            config.element.removeAttribute("data-" + NS + "-is");
840
841            setupProperties(config.options);
842            cacheElements(config.element);
843
844            if (that._elements["item"]) {
845                // ensures multiple element types are arrays.
846                that._elements["item"] = Array.isArray(that._elements["item"]) ? that._elements["item"] : [that._elements["item"]];
847                that._elements["button"] = Array.isArray(that._elements["button"]) ? that._elements["button"] : [that._elements["button"]];
848                that._elements["panel"] = Array.isArray(that._elements["panel"]) ? that._elements["panel"] : [that._elements["panel"]];
849
850                if (that._properties.singleExpansion) {
851                    var expandedItems = getExpandedItems();
852                    // multiple expanded items annotated, display the last item open.
853                    if (expandedItems.length > 1) {
854                        toggle(expandedItems.length - 1);
855                    }
856                }
857
858                refreshItems();
859                bindEvents();
860                scrollToDeepLinkIdInAccordion();
861            }
862            if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) {
863                /*
864                 * Editor message handling:
865                 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
866                 * - check that the message data panel container type is correct and that the id (path) matches this specific Accordion component
867                 * - if so, route the "navigate" operation to enact a navigation of the Accordion based on index data
868                 */
869                window.CQ.CoreComponents.MESSAGE_CHANNEL = window.CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window);
870                window.CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) {
871                    if (message.data && message.data.type === "cmp-accordion" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) {
872                        if (message.data.operation === "navigate") {
873                            // switch to single expansion mode when navigating in edit mode.
874                            var singleExpansion = that._properties.singleExpansion;
875                            that._properties.singleExpansion = true;
876                            toggle(message.data.index);
877
878                            // revert to the configured state.
879                            that._properties.singleExpansion = singleExpansion;
880                        }
881                    }
882                });
883            }
884        }
885
886        /**
887         * Displays the panel containing the element that corresponds to the deep link in the URI fragment
888         * and scrolls the browser to this element.
889         */
890        function scrollToDeepLinkIdInAccordion() {
891            if (containerUtils) {
892                var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "item", "item");
893                if (deepLinkItemIdx > -1) {
894                    var deepLinkItem = that._elements["item"][deepLinkItemIdx];
895                    if (deepLinkItem && !deepLinkItem.hasAttribute(dataAttributes.item.expanded)) {
896                        // if single expansion: close all accordion items
897                        if (that._properties.singleExpansion) {
898                            for (var j = 0; j < that._elements["item"].length; j++) {
899                                if (that._elements["item"][j].hasAttribute(dataAttributes.item.expanded)) {
900                                    setItemExpanded(that._elements["item"][j], false, true);
901                                }
902                            }
903                        }
904                        // expand the accordion item containing the deep link
905                        setItemExpanded(deepLinkItem, true, true);
906                    }
907                    var hashId = window.location.hash.substring(1);
908                    if (hashId) {
909                        var hashItem = document.querySelector("[id='" + hashId + "']");
910                        if (hashItem) {
911                            hashItem.scrollIntoView();
912                        }
913                    }
914                }
915            }
916        }
917
918        /**
919         * Caches the Accordion elements as defined via the {@code data-accordion-hook="ELEMENT_NAME"} markup API.
920         *
921         * @private
922         * @param {HTMLElement} wrapper The Accordion wrapper element
923         */
924        function cacheElements(wrapper) {
925            that._elements = {};
926            that._elements.self = wrapper;
927            var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
928
929            for (var i = 0; i < hooks.length; i++) {
930                var hook = hooks[i];
931                if (hook.closest("." + NS + "-" + IS) === that._elements.self) { // only process own accordion elements
932                    var capitalized = IS;
933                    capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
934                    var key = hook.dataset[NS + "Hook" + capitalized];
935                    if (that._elements[key]) {
936                        if (!Array.isArray(that._elements[key])) {
937                            var tmp = that._elements[key];
938                            that._elements[key] = [tmp];
939                        }
940                        that._elements[key].push(hook);
941                    } else {
942                        that._elements[key] = hook;
943                    }
944                }
945            }
946        }
947
948        /**
949         * Sets up properties for the Accordion based on the passed options.
950         *
951         * @private
952         * @param {Object} options The Accordion options
953         */
954        function setupProperties(options) {
955            that._properties = {};
956
957            for (var key in properties) {
958                if (Object.prototype.hasOwnProperty.call(properties, key)) {
959                    var property = properties[key];
960                    var value = null;
961
962                    if (options && options[key] != null) {
963                        value = options[key];
964
965                        // transform the provided option
966                        if (property && typeof property.transform === "function") {
967                            value = property.transform(value);
968                        }
969                    }
970
971                    if (value === null) {
972                        // value still null, take the property default
973                        value = properties[key]["default"];
974                    }
975
976                    that._properties[key] = value;
977                }
978            }
979        }
980
981        /**
982         * Binds Accordion event handling.
983         *
984         * @private
985         */
986        function bindEvents() {
987            window.addEventListener("hashchange", scrollToDeepLinkIdInAccordion, false);
988            var buttons = that._elements["button"];
989            if (buttons) {
990                for (var i = 0; i < buttons.length; i++) {
991                    (function(index) {
992                        buttons[i].addEventListener("click", function(event) {
993                            toggle(index);
994                            focusButton(index);
995                        });
996                        buttons[i].addEventListener("keydown", function(event) {
997                            onButtonKeyDown(event, index);
998                        });
999                    })(i);
1000                }
1001            }
1002        }
1003
1004        /**
1005         * Handles button keydown events.
1006         *
1007         * @private
1008         * @param {Object} event The keydown event
1009         * @param {Number} index The index of the button triggering the event
1010         */
1011        function onButtonKeyDown(event, index) {
1012            var lastIndex = that._elements["button"].length - 1;
1013
1014            switch (event.keyCode) {
1015                case keyCodes.ARROW_LEFT:
1016                case keyCodes.ARROW_UP:
1017                    event.preventDefault();
1018                    if (index > 0) {
1019                        focusButton(index - 1);
1020                    }
1021                    break;
1022                case keyCodes.ARROW_RIGHT:
1023                case keyCodes.ARROW_DOWN:
1024                    event.preventDefault();
1025                    if (index < lastIndex) {
1026                        focusButton(index + 1);
1027                    }
1028                    break;
1029                case keyCodes.HOME:
1030                    event.preventDefault();
1031                    focusButton(0);
1032                    break;
1033                case keyCodes.END:
1034                    event.preventDefault();
1035                    focusButton(lastIndex);
1036                    break;
1037                case keyCodes.ENTER:
1038                case keyCodes.SPACE:
1039                    event.preventDefault();
1040                    toggle(index);
1041                    focusButton(index);
1042                    break;
1043                default:
1044                    return;
1045            }
1046        }
1047
1048        /**
1049         * General handler for toggle of an item.
1050         *
1051         * @private
1052         * @param {Number} index The index of the item to toggle
1053         */
1054        function toggle(index) {
1055            var item = that._elements["item"][index];
1056            if (item) {
1057                if (that._properties.singleExpansion) {
1058                    // ensure only a single item is expanded if single expansion is enabled.
1059                    for (var i = 0; i < that._elements["item"].length; i++) {
1060                        if (that._elements["item"][i] !== item) {
1061                            var expanded = getItemExpanded(that._elements["item"][i]);
1062                            if (expanded) {
1063                                setItemExpanded(that._elements["item"][i], false);
1064                            }
1065                        }
1066                    }
1067                }
1068                setItemExpanded(item, !getItemExpanded(item));
1069
1070                if (dataLayerEnabled) {
1071                    var accordionId = that._elements.self.id;
1072                    var expandedItems = getExpandedItems()
1073                        .map(function(item) {
1074                            return getDataLayerId(item);
1075                        });
1076
1077                    var uploadPayload = { component: {} };
1078                    uploadPayload.component[accordionId] = { shownItems: expandedItems };
1079
1080                    var removePayload = { component: {} };
1081                    removePayload.component[accordionId] = { shownItems: undefined };
1082
1083                    dataLayer.push(removePayload);
1084                    dataLayer.push(uploadPayload);
1085                }
1086            }
1087        }
1088
1089        /**
1090         * Sets an item's expanded state based on the provided flag and refreshes its internals.
1091         *
1092         * @private
1093         * @param {HTMLElement} item The item to mark as expanded, or not expanded
1094         * @param {Boolean} expanded true to mark the item expanded, false otherwise
1095         * @param {Boolean} keepHash true to keep the hash in the URL, false to update it
1096         */
1097        function setItemExpanded(item, expanded, keepHash) {
1098            if (expanded) {
1099                item.setAttribute(dataAttributes.item.expanded, "");
1100                var index = that._elements["item"].indexOf(item);
1101                if (!keepHash && containerUtils) {
1102                    containerUtils.updateUrlHash(that, "item", index);
1103                }
1104                if (dataLayerEnabled) {
1105                    dataLayer.push({
1106                        event: "cmp:show",
1107                        eventInfo: {
1108                            path: "component." + getDataLayerId(item)
1109                        }
1110                    });
1111                }
1112
1113            } else {
1114                item.removeAttribute(dataAttributes.item.expanded);
1115                if (!keepHash && containerUtils) {
1116                    containerUtils.removeUrlHash();
1117                }
1118                if (dataLayerEnabled) {
1119                    dataLayer.push({
1120                        event: "cmp:hide",
1121                        eventInfo: {
1122                            path: "component." + getDataLayerId(item)
1123                        }
1124                    });
1125                }
1126            }
1127            refreshItem(item);
1128        }
1129
1130        /**
1131         * Gets an item's expanded state.
1132         *
1133         * @private
1134         * @param {HTMLElement} item The item for checking its expanded state
1135         * @returns {Boolean} true if the item is expanded, false otherwise
1136         */
1137        function getItemExpanded(item) {
1138            return item && item.dataset && item.dataset["cmpExpanded"] !== undefined;
1139        }
1140
1141        /**
1142         * Refreshes an item based on its expanded state.
1143         *
1144         * @private
1145         * @param {HTMLElement} item The item to refresh
1146         */
1147        function refreshItem(item) {
1148            var expanded = getItemExpanded(item);
1149            if (expanded) {
1150                expandItem(item);
1151            } else {
1152                collapseItem(item);
1153            }
1154        }
1155
1156        /**
1157         * Refreshes all items based on their expanded state.
1158         *
1159         * @private
1160         */
1161        function refreshItems() {
1162            for (var i = 0; i < that._elements["item"].length; i++) {
1163                refreshItem(that._elements["item"][i]);
1164            }
1165        }
1166
1167        /**
1168         * Returns all expanded items.
1169         *
1170         * @private
1171         * @returns {HTMLElement[]} The expanded items
1172         */
1173        function getExpandedItems() {
1174            var expandedItems = [];
1175
1176            for (var i = 0; i < that._elements["item"].length; i++) {
1177                var item = that._elements["item"][i];
1178                var expanded = getItemExpanded(item);
1179                if (expanded) {
1180                    expandedItems.push(item);
1181                }
1182            }
1183
1184            return expandedItems;
1185        }
1186
1187        /**
1188         * Annotates the item and its internals with
1189         * the necessary style and accessibility attributes to indicate it is expanded.
1190         *
1191         * @private
1192         * @param {HTMLElement} item The item to annotate as expanded
1193         */
1194        function expandItem(item) {
1195            var index = that._elements["item"].indexOf(item);
1196            if (index > -1) {
1197                var button = that._elements["button"][index];
1198                var panel = that._elements["panel"][index];
1199                button.classList.add(cssClasses.button.expanded);
1200                // used to fix some known screen readers issues in reading the correct state of the 'aria-expanded' attribute
1201                // e.g. https://bugs.webkit.org/show_bug.cgi?id=210934
1202                setTimeout(function() {
1203                    button.setAttribute("aria-expanded", true);
1204                }, delay);
1205                panel.classList.add(cssClasses.panel.expanded);
1206                panel.classList.remove(cssClasses.panel.hidden);
1207                panel.setAttribute("aria-hidden", false);
1208            }
1209        }
1210
1211        /**
1212         * Annotates the item and its internals with
1213         * the necessary style and accessibility attributes to indicate it is not expanded.
1214         *
1215         * @private
1216         * @param {HTMLElement} item The item to annotate as not expanded
1217         */
1218        function collapseItem(item) {
1219            var index = that._elements["item"].indexOf(item);
1220            if (index > -1) {
1221                var button = that._elements["button"][index];
1222                var panel = that._elements["panel"][index];
1223                button.classList.remove(cssClasses.button.expanded);
1224                // used to fix some known screen readers issues in reading the correct state of the 'aria-expanded' attribute
1225                // e.g. https://bugs.webkit.org/show_bug.cgi?id=210934
1226                setTimeout(function() {
1227                    button.setAttribute("aria-expanded", false);
1228                }, delay);
1229                panel.classList.add(cssClasses.panel.hidden);
1230                panel.classList.remove(cssClasses.panel.expanded);
1231                panel.setAttribute("aria-hidden", true);
1232            }
1233        }
1234
1235        /**
1236         * Focuses the button at the provided index.
1237         *
1238         * @private
1239         * @param {Number} index The index of the button to focus
1240         */
1241        function focusButton(index) {
1242            var button = that._elements["button"][index];
1243            button.focus();
1244        }
1245    }
1246
1247    /**
1248     * Reads options data from the Accordion wrapper element, defined via {@code data-cmp-*} data attributes.
1249     *
1250     * @private
1251     * @param {HTMLElement} element The Accordion element to read options data from
1252     * @returns {Object} The options read from the component data attributes
1253     */
1254    function readData(element) {
1255        var data = element.dataset;
1256        var options = [];
1257        var capitalized = IS;
1258        capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
1259        var reserved = ["is", "hook" + capitalized];
1260
1261        for (var key in data) {
1262            if (Object.prototype.hasOwnProperty.call(data, key)) {
1263                var value = data[key];
1264
1265                if (key.indexOf(NS) === 0) {
1266                    key = key.slice(NS.length);
1267                    key = key.charAt(0).toLowerCase() + key.substring(1);
1268
1269                    if (reserved.indexOf(key) === -1) {
1270                        options[key] = value;
1271                    }
1272                }
1273            }
1274        }
1275
1276        return options;
1277    }
1278
1279    /**
1280     * Parses the dataLayer string and returns the ID
1281     *
1282     * @private
1283     * @param {HTMLElement} item the accordion item
1284     * @returns {String} dataLayerId or undefined
1285     */
1286    function getDataLayerId(item) {
1287        if (item) {
1288            if (item.dataset.cmpDataLayer) {
1289                return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0];
1290            } else {
1291                return item.id;
1292            }
1293        }
1294        return null;
1295    }
1296
1297    /**
1298     * Document ready handler and DOM mutation observers. Initializes Accordion components as necessary.
1299     *
1300     * @private
1301     */
1302    function onDocumentReady() {
1303        dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled");
1304        if (dataLayerEnabled) {
1305            dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer";
1306            dataLayer = window[dataLayerName] = window[dataLayerName] || [];
1307        }
1308
1309        var elements = document.querySelectorAll(selectors.self);
1310        for (var i = 0; i < elements.length; i++) {
1311            new Accordion({ element: elements[i], options: readData(elements[i]) });
1312        }
1313
1314        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
1315        var body = document.querySelector("body");
1316        var observer = new MutationObserver(function(mutations) {
1317            mutations.forEach(function(mutation) {
1318                // needed for IE
1319                var nodesArray = [].slice.call(mutation.addedNodes);
1320                if (nodesArray.length > 0) {
1321                    nodesArray.forEach(function(addedNode) {
1322                        if (addedNode.querySelectorAll) {
1323                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
1324                            elementsArray.forEach(function(element) {
1325                                new Accordion({ element: element, options: readData(element) });
1326                            });
1327                        }
1328                    });
1329                }
1330            });
1331        });
1332
1333        observer.observe(body, {
1334            subtree: true,
1335            childList: true,
1336            characterData: true
1337        });
1338    }
1339
1340    if (document.readyState !== "loading") {
1341        onDocumentReady();
1342    } else {
1343        document.addEventListener("DOMContentLoaded", onDocumentReady);
1344    }
1345
1346    if (containerUtils) {
1347        window.addEventListener("load", containerUtils.scrollToAnchor, false);
1348    }
1349
1350}());
1351
1352/*******************************************************************************
1353 * Copyright 2018 Adobe
1354 *
1355 * Licensed under the Apache License, Version 2.0 (the "License");
1356 * you may not use this file except in compliance with the License.
1357 * You may obtain a copy of the License at
1358 *
1359 *     http://www.apache.org/licenses/LICENSE2.0
1360 *
1361 * Unless required by applicable law or agreed to in writing, software
1362 * distributed under the License is distributed on an "AS IS" BASIS,
1363 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1364 * See the License for the specific language governing permissions and
1365 * limitations under the License.
1366 ******************************************************************************/
1367
1368/**
1369 * Element.matches()
1370 * https://developer.mozilla.org/enUS/docs/Web/API/Element/matches#Polyfill
1371 */
1372if (!Element.prototype.matches) {
1373    Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
1374}
1375
1376// eslint-disable-next-line valid-jsdoc
1377/**
1378 * Element.closest()
1379 * https://developer.mozilla.org/enUS/docs/Web/API/Element/closest#Polyfill
1380 */
1381if (!Element.prototype.closest) {
1382    Element.prototype.closest = function(s) {
1383        "use strict";
1384        var el = this;
1385        if (!document.documentElement.contains(el)) {
1386            return null;
1387        }
1388        do {
1389            if (el.matches(s)) {
1390                return el;
1391            }
1392            el = el.parentElement || el.parentNode;
1393        } while (el !== null && el.nodeType === 1);
1394        return null;
1395    };
1396}
1397/*******************************************************************************
1398 * Copyright 2018 Adobe
1399 *
1400 * Licensed under the Apache License, Version 2.0 (the "License");
1401 * you may not use this file except in compliance with the License.
1402 * You may obtain a copy of the License at
1403 *
1404 *     http://www.apache.org/licenses/LICENSE-2.0
1405 *
1406 * Unless required by applicable law or agreed to in writing, software
1407 * distributed under the License is distributed on an "AS IS" BASIS,
1408 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1409 * See the License for the specific language governing permissions and
1410 * limitations under the License.
1411 ******************************************************************************/
1412/* global
1413    CQ
1414 */
1415	(function() {
1416		"use strict";
1417
1418    	const version2 = document.querySelector('html').classList.contains('version2');
1419	
1420		var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined;
1421		if (!containerUtils) {
1422			// eslint-disable-next-line no-console
1423			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.");
1424		}
1425		var dataLayerEnabled;
1426		var dataLayer;
1427		var dataLayerName;
1428	
1429		var NS = "cmp";
1430		var IS = "tabs";
1431	
1432		var keyCodes = {
1433			END: 35,
1434			HOME: 36,
1435			ARROW_LEFT: 37,
1436			ARROW_UP: 38,
1437			ARROW_RIGHT: 39,
1438			ARROW_DOWN: 40
1439		};
1440	
1441		var selectors = {
1442			self: "[data-" + NS + '-is="' + IS + '"]',
1443			active: {
1444				tab: (version2) ? "active" : "cmp-tabs__tab--active",
1445            	tabpanel: (version2) ? "active" : "cmp-tabs__tabpanel--active"
1446			}
1447		};
1448
1449		/**
1450		 * Tabs Configuration
1451		 *
1452		 * @typedef {Object} TabsConfig Represents a Tabs configuration
1453		 * @property {HTMLElement} element The HTMLElement representing the Tabs
1454		 * @property {Object} options The Tabs options
1455		 */
1456	
1457		/**
1458		 * Tabs
1459		 *
1460		 * @class Tabs
1461		 * @classdesc An interactive Tabs component for navigating a list of tabs
1462		 * @param {TabsConfig} config The Tabs configuration
1463		 */
1464		function Tabs(config) {
1465			var that = this;
1466	
1467			if (config && config.element) {
1468				init(config);
1469			}
1470	
1471			/**
1472			 * Initializes the Tabs
1473			 *
1474			 * @private
1475			 * @param {TabsConfig} config The Tabs configuration
1476			 */
1477			function init(config) {
1478				that._config = config;
1479	
1480				// prevents multiple initialization
1481				config.element.removeAttribute("data-" + NS + "-is");
1482	
1483				cacheElements(config.element);
1484				that._active = getActiveIndex(that._elements["tab"]);
1485	
1486				if (that._elements.tabpanel) {
1487					refreshActive();
1488					bindEvents();
1489					scrollToDeepLinkIdInTabs();
1490				}
1491	
1492				if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) {
1493					/*
1494					 * Editor message handling:
1495					 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
1496					 * - check that the message data panel container type is correct and that the id (path) matches this specific Tabs component
1497					 * - if so, route the "navigate" operation to enact a navigation of the Tabs based on index data
1498					 */
1499					CQ.CoreComponents.MESSAGE_CHANNEL = CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window);
1500					CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) {
1501						if (message.data && message.data.type === "cmp-tabs" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) {
1502							if (message.data.operation === "navigate") {
1503								navigate(message.data.index);
1504							}
1505						}
1506					});
1507				}
1508			}
1509	
1510			/**
1511			 * Displays the panel containing the element that corresponds to the deep link in the URI fragment
1512			 * and scrolls the browser to this element.
1513			 */
1514			function scrollToDeepLinkIdInTabs() {
1515				if (containerUtils) {
1516					var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "tab", "tabpanel");
1517					if (deepLinkItemIdx > -1) {
1518						var deepLinkItem = that._elements["tab"][deepLinkItemIdx];
1519						if (deepLinkItem && that._elements["tab"][that._active].id !== deepLinkItem.id) {
1520							navigateAndFocusTab(deepLinkItemIdx, true);
1521						}
1522						var hashId = window.location.hash.substring(1);
1523						if (hashId) {
1524							var hashItem = document.querySelector("[id='" + hashId + "']");
1525							if (hashItem) {
1526								hashItem.scrollIntoView();
1527							}
1528						}
1529					}
1530				}
1531			}
1532	
1533			/**
1534			 * Returns the index of the active tab, if no tab is active returns 0
1535			 *
1536			 * @param {Array} tabs Tab elements
1537			 * @returns {Number} Index of the active tab, 0 if none is active
1538			 */
1539			function getActiveIndex(tabs) {
1540				if (tabs) {
1541					for (var i = 0; i < tabs.length; i++) {
1542						if (tabs[i].classList.contains(selectors.active.tab)) {
1543							return i;
1544						}
1545					}
1546				}
1547				return 0;
1548			}
1549	
1550			/**
1551			 * Caches the Tabs elements as defined via the {@code data-tabs-hook="ELEMENT_NAME"} markup API
1552			 *
1553			 * @private
1554			 * @param {HTMLElement} wrapper The Tabs wrapper element
1555			 */
1556			function cacheElements(wrapper) {
1557				that._elements = {};
1558				that._elements.self = wrapper;
1559				var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
1560	
1561				for (var i = 0; i < hooks.length; i++) {
1562					var hook = hooks[i];
1563					if (hook.closest("." + NS + "-" + IS) === that._elements.self) { // only process own tab elements
1564						var capitalized = IS;
1565						capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
1566						var key = hook.dataset[NS + "Hook" + capitalized];
1567						if (that._elements[key]) {
1568							if (!Array.isArray(that._elements[key])) {
1569								var tmp = that._elements[key];
1570								that._elements[key] = [tmp];
1571							}
1572							that._elements[key].push(hook);
1573						} else {
1574							that._elements[key] = hook;
1575						}
1576					}
1577				}
1578			}
1579	
1580			/**
1581			 * Binds Tabs event handling
1582			 *
1583			 * @private
1584			 */
1585			function bindEvents() {
1586				if(version2) { return; }
1587				
1588				window.addEventListener("hashchange", scrollToDeepLinkIdInTabs, false);
1589				var tabs = that._elements["tab"];
1590				if (tabs) {
1591					for (var i = 0; i < tabs.length; i++) {
1592						(function(index) {
1593							tabs[i].addEventListener("click", function(event) {
1594								navigateAndFocusTab(index);
1595							});
1596							tabs[i].addEventListener("keydown", function(event) {
1597								onKeyDown(event);
1598							});
1599						})(i);
1600					}
1601				}
1602			}
1603	
1604			/**
1605			 * Handles tab keydown events
1606			 *
1607			 * @private
1608			 * @param {Object} event The keydown event
1609			 */
1610			function onKeyDown(event) {
1611				var index = that._active;
1612				var lastIndex = that._elements["tab"].length - 1;
1613				if(version2){
1614					switch (event.keyCode) {
1615						case keyCodes.ARROW_LEFT:
1616						case keyCodes.ARROW_UP:
1617						case keyCodes.ARROW_RIGHT:
1618						case keyCodes.ARROW_DOWN:
1619						case keyCodes.HOME:
1620						case keyCodes.END:
1621							event.preventDefault();
1622							removeActive();
1623							break;
1624						default:
1625							return;
1626					}
1627				} else {
1628					switch (event.keyCode) {
1629						case keyCodes.ARROW_LEFT:
1630						case keyCodes.ARROW_UP:
1631							event.preventDefault();
1632							if (index > 0) {
1633								navigateAndFocusTab(index - 1);
1634							}
1635							break;
1636						case keyCodes.ARROW_RIGHT:
1637						case keyCodes.ARROW_DOWN:
1638							event.preventDefault();
1639							if (index < lastIndex) {
1640								navigateAndFocusTab(index + 1);
1641							}
1642							break;
1643						case keyCodes.HOME:
1644							event.preventDefault();
1645							navigateAndFocusTab(0);
1646							break;
1647						case keyCodes.END:
1648							event.preventDefault();
1649							navigateAndFocusTab(lastIndex);
1650							break;
1651						default:
1652							return;
1653					}
1654				}
1655			}
1656	
1657			/**
1658			 * Refreshes the tab markup based on the current {@code Tabs#_active} index
1659			 *
1660			 * @private
1661			 */
1662			function refreshActive() {
1663				var tabpanels = that._elements["tabpanel"];
1664				var tabs = that._elements["tab"];
1665				var dropdown = that._elements["dropdown"];
1666				if(dropdown){
1667					var dropdownText = dropdown.querySelector('.dropdown-text');
1668				}
1669
1670				if (tabpanels) {
1671					if (Array.isArray(tabpanels)) {
1672						for (var i = 0; i < tabpanels.length; i++) {
1673							if (i === parseInt(that._active)) {
1674								tabpanels[i].classList.add(selectors.active.tabpanel);
1675								tabpanels[i].classList.add('show');
1676								tabpanels[i].removeAttribute("aria-hidden");
1677								tabs[i].classList.add(selectors.active.tab);
1678								tabs[i].setAttribute("aria-selected", true);
1679								tabs[i].setAttribute("tabindex", "0");
1680								if(dropdown && dropdownText){
1681									dropdownText.innerText = tabs[i].innerText.trim();
1682								}
1683							} else {
1684								tabpanels[i].classList.remove(selectors.active.tabpanel);
1685								tabpanels[i].setAttribute("aria-hidden", true);
1686								tabs[i].classList.remove(selectors.active.tab);
1687								tabs[i].setAttribute("aria-selected", false);
1688								tabs[i].setAttribute("tabindex", "-1");
1689							}
1690						}
1691					} else {
1692						// only one tab
1693						tabpanels.classList.add(selectors.active.tabpanel);
1694						tabs.classList.add(selectors.active.tab);
1695						if(dropdown && dropdownText){
1696							dropdownText.innerText = tabs.innerText.trim();
1697						}
1698					}
1699				}
1700			}
1701	
1702			function removeActive() {
1703				var tabpanels = that._elements["tabpanel"];
1704				var tabs = that._elements["tab"];
1705
1706				if (tabpanels) {
1707					if (Array.isArray(tabpanels)) {
1708						for (var i = 0; i < tabpanels.length; i++) {
1709							
1710								tabpanels[i].classList.remove(selectors.active.tabpanel);
1711								tabpanels[i].setAttribute("aria-hidden", true);
1712								tabs[i].classList.remove(selectors.active.tab);
1713								tabs[i].setAttribute("aria-selected", false);
1714								tabs[i].setAttribute("tabindex", "-1");
1715							
1716						}
1717					} else {
1718						// only one tab
1719						tabpanels.classList.remove(selectors.active.tabpanel);
1720						tabs.classList.remove(selectors.active.tab);
1721					}
1722				}
1723			}
1724
1725			/**
1726			 * Focuses the element and prevents scrolling the element into view
1727			 *
1728			 * @param {HTMLElement} element Element to focus
1729			 */
1730			function focusWithoutScroll(element) {
1731				var x = window.scrollX || window.pageXOffset;
1732				var y = window.scrollY || window.pageYOffset;
1733				element.focus();
1734				window.scrollTo(x, y);
1735			}
1736	
1737			/**
1738			 * Navigates to the tab at the provided index
1739			 *
1740			 * @private
1741			 * @param {Number} index The index of the tab to navigate to
1742			 */
1743			function navigate(index) {
1744				that._active = index;
1745				refreshActive();
1746			}
1747	
1748			/**
1749			 * Navigates to the item at the provided index and ensures the active tab gains focus
1750			 *
1751			 * @private
1752			 * @param {Number} index The index of the item to navigate to
1753			 * @param {Boolean} keepHash true to keep the hash in the URL, false to update it
1754			 */
1755			function navigateAndFocusTab(index, keepHash) {
1756				var exActive = that._active;
1757				if (!keepHash && containerUtils) {
1758					containerUtils.updateUrlHash(that, "tab", index);
1759				}
1760				navigate(index);
1761				focusWithoutScroll(that._elements["tab"][index]);
1762	
1763				if (dataLayerEnabled) {
1764					if (window.customTracking && typeof window.customTracking.trackingFlagGetter === 'function') {
1765						if(window.customTracking.trackingFlagGetter()){
1766							var activeItem = getDataLayerId(that._elements.tabpanel[index]);
1767							var exActiveItem = getDataLayerId(that._elements.tabpanel[exActive]);
1768			
1769							dataLayer.push({
1770								event: "cmp:show",
1771								eventInfo: {
1772									path: "component." + activeItem
1773								}
1774							});
1775			
1776							dataLayer.push({
1777								event: "cmp:hide",
1778								eventInfo: {
1779									path: "component." + exActiveItem
1780								}
1781							});
1782			
1783							var tabsId = that._elements.self.id;
1784							var uploadPayload = { component: {} };
1785							uploadPayload.component[tabsId] = { shownItems: [activeItem] };
1786			
1787							var removePayload = { component: {} };
1788							removePayload.component[tabsId] = { shownItems: undefined };
1789			
1790							dataLayer.push(removePayload);
1791							dataLayer.push(uploadPayload);
1792						}
1793					}
1794				}
1795			}
1796		}
1797	
1798		/**
1799		 * Reads options data from the Tabs wrapper element, defined via {@code data-cmp-*} data attributes
1800		 *
1801		 * @private
1802		 * @param {HTMLElement} element The Tabs element to read options data from
1803		 * @returns {Object} The options read from the component data attributes
1804		 */
1805		function readData(element) {
1806			var data = element.dataset;
1807			var options = [];
1808			var capitalized = IS;
1809			capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
1810			var reserved = ["is", "hook" + capitalized];
1811	
1812			for (var key in data) {
1813				if (Object.prototype.hasOwnProperty.call(data, key)) {
1814					var value = data[key];
1815	
1816					if (key.indexOf(NS) === 0) {
1817						key = key.slice(NS.length);
1818						key = key.charAt(0).toLowerCase() + key.substring(1);
1819	
1820						if (reserved.indexOf(key) === -1) {
1821							options[key] = value;
1822						}
1823					}
1824				}
1825			}
1826	
1827			return options;
1828		}
1829	
1830		/**
1831		 * Parses the dataLayer string and returns the ID
1832		 *
1833		 * @private
1834		 * @param {HTMLElement} item the accordion item
1835		 * @returns {String} dataLayerId or undefined
1836		 */
1837		function getDataLayerId(item) {
1838			if (item) {
1839				if (item.dataset.cmpDataLayer) {
1840					return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0];
1841				} else {
1842					return item.id;
1843				}
1844			}
1845			return null;
1846		}
1847	
1848		/**
1849		 * Document ready handler and DOM mutation observers. Initializes Tabs components as necessary.
1850		 *
1851		 * @private
1852		 */
1853		function onDocumentReady() {
1854			dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled");
1855			if (dataLayerEnabled) {
1856				dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer";
1857				dataLayer = window[dataLayerName] = window[dataLayerName] || [];
1858			}
1859	
1860			var elements = document.querySelectorAll(selectors.self);
1861			for (var i = 0; i < elements.length; i++) {
1862				new Tabs({ element: elements[i], options: readData(elements[i]) });
1863			}
1864	
1865			var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
1866			var body = document.querySelector("body");
1867			var observer = new MutationObserver(function(mutations) {
1868				mutations.forEach(function(mutation) {
1869					// needed for IE
1870					var nodesArray = [].slice.call(mutation.addedNodes);
1871					if (nodesArray.length > 0) {
1872						nodesArray.forEach(function(addedNode) {
1873							if (addedNode.querySelectorAll) {
1874								var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
1875								elementsArray.forEach(function(element) {
1876									new Tabs({ element: element, options: readData(element) });
1877								});
1878							}
1879						});
1880					}
1881				});
1882			});
1883	
1884			observer.observe(body, {
1885				subtree: true,
1886				childList: true,
1887				characterData: true
1888			});
1889		}
1890	
1891		if (document.readyState !== "loading") {
1892			onDocumentReady();
1893		} else {
1894			document.addEventListener("DOMContentLoaded", onDocumentReady);
1895		}
1896	
1897		if (containerUtils) {
1898			window.addEventListener("load", containerUtils.scrollToAnchor, false);
1899		}
1900	
1901	}());
1902/*******************************************************************************
1903 * Copyright 2018 Adobe
1904 *
1905 * Licensed under the Apache License, Version 2.0 (the "License");
1906 * you may not use this file except in compliance with the License.
1907 * You may obtain a copy of the License at
1908 *
1909 *     http://www.apache.org/licenses/LICENSE2.0
1910 *
1911 * Unless required by applicable law or agreed to in writing, software
1912 * distributed under the License is distributed on an "AS IS" BASIS,
1913 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1914 * See the License for the specific language governing permissions and
1915 * limitations under the License.
1916 ******************************************************************************/
1917
1918/**
1919 * Element.matches()
1920 * https://developer.mozilla.org/enUS/docs/Web/API/Element/matches#Polyfill
1921 */
1922if (!Element.prototype.matches) {
1923    Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
1924}
1925
1926// eslint-disable-next-line valid-jsdoc
1927/**
1928 * Element.closest()
1929 * https://developer.mozilla.org/enUS/docs/Web/API/Element/closest#Polyfill
1930 */
1931if (!Element.prototype.closest) {
1932    Element.prototype.closest = function(s) {
1933        "use strict";
1934        var el = this;
1935        if (!document.documentElement.contains(el)) {
1936            return null;
1937        }
1938        do {
1939            if (el.matches(s)) {
1940                return el;
1941            }
1942            el = el.parentElement || el.parentNode;
1943        } while (el !== null && el.nodeType === 1);
1944        return null;
1945    };
1946}
1947
1948/*******************************************************************************
1949 * Copyright 2018 Adobe
1950 *
1951 * Licensed under the Apache License, Version 2.0 (the "License");
1952 * you may not use this file except in compliance with the License.
1953 * You may obtain a copy of the License at
1954 *
1955 *     http://www.apache.org/licenses/LICENSE-2.0
1956 *
1957 * Unless required by applicable law or agreed to in writing, software
1958 * distributed under the License is distributed on an "AS IS" BASIS,
1959 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1960 * See the License for the specific language governing permissions and
1961 * limitations under the License.
1962 ******************************************************************************/
1963/* global
1964    CQ
1965 */
1966(function() {
1967    "use strict";
1968
1969    var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined;
1970    if (!containerUtils) {
1971        // eslint-disable-next-line no-console
1972        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.");
1973    }
1974    var dataLayerEnabled;
1975    var dataLayer;
1976    var dataLayerName;
1977
1978    var NS = "cmp";
1979    var IS = "tabs";
1980
1981    var keyCodes = {
1982        END: 35,
1983        HOME: 36,
1984        ARROW_LEFT: 37,
1985        ARROW_UP: 38,
1986        ARROW_RIGHT: 39,
1987        ARROW_DOWN: 40
1988    };
1989
1990    var selectors = {
1991        self: "[data-" + NS + '-is="' + IS + '"]',
1992        active: {
1993            tab: "cmp-tabs__tab--active",
1994            tabpanel: "cmp-tabs__tabpanel--active"
1995        }
1996    };
1997
1998    /**
1999     * Tabs Configuration
2000     *
2001     * @typedef {Object} TabsConfig Represents a Tabs configuration
2002     * @property {HTMLElement} element The HTMLElement representing the Tabs
2003     * @property {Object} options The Tabs options
2004     */
2005
2006    /**
2007     * Tabs
2008     *
2009     * @class Tabs
2010     * @classdesc An interactive Tabs component for navigating a list of tabs
2011     * @param {TabsConfig} config The Tabs configuration
2012     */
2013    function Tabs(config) {
2014        var that = this;
2015
2016        if (config && config.element) {
2017            init(config);
2018        }
2019
2020        /**
2021         * Initializes the Tabs
2022         *
2023         * @private
2024         * @param {TabsConfig} config The Tabs configuration
2025         */
2026        function init(config) {
2027            that._config = config;
2028
2029            // prevents multiple initialization
2030            config.element.removeAttribute("data-" + NS + "-is");
2031
2032            cacheElements(config.element);
2033            that._active = getActiveIndex(that._elements["tab"]);
2034
2035            if (that._elements.tabpanel) {
2036                refreshActive();
2037                bindEvents();
2038                scrollToDeepLinkIdInTabs();
2039            }
2040
2041            if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) {
2042                /*
2043                 * Editor message handling:
2044                 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
2045                 * - check that the message data panel container type is correct and that the id (path) matches this specific Tabs component
2046                 * - if so, route the "navigate" operation to enact a navigation of the Tabs based on index data
2047                 */
2048                CQ.CoreComponents.MESSAGE_CHANNEL = CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window);
2049                CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) {
2050                    if (message.data && message.data.type === "cmp-tabs" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) {
2051                        if (message.data.operation === "navigate") {
2052                            navigate(message.data.index);
2053                        }
2054                    }
2055                });
2056            }
2057        }
2058
2059        /**
2060         * Displays the panel containing the element that corresponds to the deep link in the URI fragment
2061         * and scrolls the browser to this element.
2062         */
2063        function scrollToDeepLinkIdInTabs() {
2064            if (containerUtils) {
2065                var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "tab", "tabpanel");
2066                if (deepLinkItemIdx > -1) {
2067                    var deepLinkItem = that._elements["tab"][deepLinkItemIdx];
2068                    if (deepLinkItem && that._elements["tab"][that._active].id !== deepLinkItem.id) {
2069                        navigateAndFocusTab(deepLinkItemIdx, true);
2070                    }
2071                    var hashId = window.location.hash.substring(1);
2072                    if (hashId) {
2073                        var hashItem = document.querySelector("[id='" + hashId + "']");
2074                        if (hashItem) {
2075                            hashItem.scrollIntoView();
2076                        }
2077                    }
2078                }
2079            }
2080        }
2081
2082        /**
2083         * Returns the index of the active tab, if no tab is active returns 0
2084         *
2085         * @param {Array} tabs Tab elements
2086         * @returns {Number} Index of the active tab, 0 if none is active
2087         */
2088        function getActiveIndex(tabs) {
2089            if (tabs) {
2090                for (var i = 0; i < tabs.length; i++) {
2091                    if (tabs[i].classList.contains(selectors.active.tab)) {
2092                        return i;
2093                    }
2094                }
2095            }
2096            return 0;
2097        }
2098
2099        /**
2100         * Caches the Tabs elements as defined via the {@code data-tabs-hook="ELEMENT_NAME"} markup API
2101         *
2102         * @private
2103         * @param {HTMLElement} wrapper The Tabs wrapper element
2104         */
2105        function cacheElements(wrapper) {
2106            that._elements = {};
2107            that._elements.self = wrapper;
2108            var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
2109
2110            for (var i = 0; i < hooks.length; i++) {
2111                var hook = hooks[i];
2112                if (hook.closest("." + NS + "-" + IS) === that._elements.self) { // only process own tab elements
2113                    var capitalized = IS;
2114                    capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
2115                    var key = hook.dataset[NS + "Hook" + capitalized];
2116                    if (that._elements[key]) {
2117                        if (!Array.isArray(that._elements[key])) {
2118                            var tmp = that._elements[key];
2119                            that._elements[key] = [tmp];
2120                        }
2121                        that._elements[key].push(hook);
2122                    } else {
2123                        that._elements[key] = hook;
2124                    }
2125                }
2126            }
2127        }
2128
2129        /**
2130         * Binds Tabs event handling
2131         *
2132         * @private
2133         */
2134        function bindEvents() {
2135            window.addEventListener("hashchange", scrollToDeepLinkIdInTabs, false);
2136            var tabs = that._elements["tab"];
2137            if (tabs) {
2138                for (var i = 0; i < tabs.length; i++) {
2139                    (function(index) {
2140                        tabs[i].addEventListener("click", function(event) {
2141                            navigateAndFocusTab(index);
2142                        });
2143                        tabs[i].addEventListener("keydown", function(event) {
2144                            onKeyDown(event);
2145                        });
2146                    })(i);
2147                }
2148            }
2149        }
2150
2151        /**
2152         * Handles tab keydown events
2153         *
2154         * @private
2155         * @param {Object} event The keydown event
2156         */
2157        function onKeyDown(event) {
2158            var index = that._active;
2159            var lastIndex = that._elements["tab"].length - 1;
2160
2161            switch (event.keyCode) {
2162                case keyCodes.ARROW_LEFT:
2163                case keyCodes.ARROW_UP:
2164                    event.preventDefault();
2165                    if (index > 0) {
2166                        navigateAndFocusTab(index - 1);
2167                    }
2168                    break;
2169                case keyCodes.ARROW_RIGHT:
2170                case keyCodes.ARROW_DOWN:
2171                    event.preventDefault();
2172                    if (index < lastIndex) {
2173                        navigateAndFocusTab(index + 1);
2174                    }
2175                    break;
2176                case keyCodes.HOME:
2177                    event.preventDefault();
2178                    navigateAndFocusTab(0);
2179                    break;
2180                case keyCodes.END:
2181                    event.preventDefault();
2182                    navigateAndFocusTab(lastIndex);
2183                    break;
2184                default:
2185                    return;
2186            }
2187        }
2188
2189        /**
2190         * Refreshes the tab markup based on the current {@code Tabs#_active} index
2191         *
2192         * @private
2193         */
2194        function refreshActive() {
2195            var tabpanels = that._elements["tabpanel"];
2196            var tabs = that._elements["tab"];
2197
2198            if (tabpanels) {
2199                if (Array.isArray(tabpanels)) {
2200                    for (var i = 0; i < tabpanels.length; i++) {
2201                        if (i === parseInt(that._active)) {
2202                            tabpanels[i].classList.add(selectors.active.tabpanel);
2203                            tabpanels[i].removeAttribute("aria-hidden");
2204                            tabs[i].classList.add(selectors.active.tab);
2205                            tabs[i].setAttribute("aria-selected", true);
2206                            tabs[i].setAttribute("tabindex", "0");
2207                        } else {
2208                            tabpanels[i].classList.remove(selectors.active.tabpanel);
2209                            tabpanels[i].setAttribute("aria-hidden", true);
2210                            tabs[i].classList.remove(selectors.active.tab);
2211                            tabs[i].setAttribute("aria-selected", false);
2212                            tabs[i].setAttribute("tabindex", "-1");
2213                        }
2214                    }
2215                } else {
2216                    // only one tab
2217                    tabpanels.classList.add(selectors.active.tabpanel);
2218                    tabs.classList.add(selectors.active.tab);
2219                }
2220            }
2221        }
2222
2223        /**
2224         * Focuses the element and prevents scrolling the element into view
2225         *
2226         * @param {HTMLElement} element Element to focus
2227         */
2228        function focusWithoutScroll(element) {
2229            var x = window.scrollX || window.pageXOffset;
2230            var y = window.scrollY || window.pageYOffset;
2231            element.focus();
2232            window.scrollTo(x, y);
2233        }
2234
2235        /**
2236         * Navigates to the tab at the provided index
2237         *
2238         * @private
2239         * @param {Number} index The index of the tab to navigate to
2240         */
2241        function navigate(index) {
2242            that._active = index;
2243            refreshActive();
2244        }
2245
2246        /**
2247         * Navigates to the item at the provided index and ensures the active tab gains focus
2248         *
2249         * @private
2250         * @param {Number} index The index of the item to navigate to
2251         * @param {Boolean} keepHash true to keep the hash in the URL, false to update it
2252         */
2253        function navigateAndFocusTab(index, keepHash) {
2254            var exActive = that._active;
2255            if (!keepHash && containerUtils) {
2256                containerUtils.updateUrlHash(that, "tab", index);
2257            }
2258            navigate(index);
2259            focusWithoutScroll(that._elements["tab"][index]);
2260
2261            if (dataLayerEnabled) {
2262
2263                var activeItem = getDataLayerId(that._elements.tabpanel[index]);
2264                var exActiveItem = getDataLayerId(that._elements.tabpanel[exActive]);
2265
2266                dataLayer.push({
2267                    event: "cmp:show",
2268                    eventInfo: {
2269                        path: "component." + activeItem
2270                    }
2271                });
2272
2273                dataLayer.push({
2274                    event: "cmp:hide",
2275                    eventInfo: {
2276                        path: "component." + exActiveItem
2277                    }
2278                });
2279
2280                var tabsId = that._elements.self.id;
2281                var uploadPayload = { component: {} };
2282                uploadPayload.component[tabsId] = { shownItems: [activeItem] };
2283
2284                var removePayload = { component: {} };
2285                removePayload.component[tabsId] = { shownItems: undefined };
2286
2287                dataLayer.push(removePayload);
2288                dataLayer.push(uploadPayload);
2289            }
2290        }
2291    }
2292
2293    /**
2294     * Reads options data from the Tabs wrapper element, defined via {@code data-cmp-*} data attributes
2295     *
2296     * @private
2297     * @param {HTMLElement} element The Tabs element to read options data from
2298     * @returns {Object} The options read from the component data attributes
2299     */
2300    function readData(element) {
2301        var data = element.dataset;
2302        var options = [];
2303        var capitalized = IS;
2304        capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
2305        var reserved = ["is", "hook" + capitalized];
2306
2307        for (var key in data) {
2308            if (Object.prototype.hasOwnProperty.call(data, key)) {
2309                var value = data[key];
2310
2311                if (key.indexOf(NS) === 0) {
2312                    key = key.slice(NS.length);
2313                    key = key.charAt(0).toLowerCase() + key.substring(1);
2314
2315                    if (reserved.indexOf(key) === -1) {
2316                        options[key] = value;
2317                    }
2318                }
2319            }
2320        }
2321
2322        return options;
2323    }
2324
2325    /**
2326     * Parses the dataLayer string and returns the ID
2327     *
2328     * @private
2329     * @param {HTMLElement} item the accordion item
2330     * @returns {String} dataLayerId or undefined
2331     */
2332    function getDataLayerId(item) {
2333        if (item) {
2334            if (item.dataset.cmpDataLayer) {
2335                return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0];
2336            } else {
2337                return item.id;
2338            }
2339        }
2340        return null;
2341    }
2342
2343    /**
2344     * Document ready handler and DOM mutation observers. Initializes Tabs components as necessary.
2345     *
2346     * @private
2347     */
2348    function onDocumentReady() {
2349        dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled");
2350        if (dataLayerEnabled) {
2351            dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer";
2352            dataLayer = window[dataLayerName] = window[dataLayerName] || [];
2353        }
2354
2355        var elements = document.querySelectorAll(selectors.self);
2356        for (var i = 0; i < elements.length; i++) {
2357            new Tabs({ element: elements[i], options: readData(elements[i]) });
2358        }
2359
2360        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
2361        var body = document.querySelector("body");
2362        var observer = new MutationObserver(function(mutations) {
2363            mutations.forEach(function(mutation) {
2364                // needed for IE
2365                var nodesArray = [].slice.call(mutation.addedNodes);
2366                if (nodesArray.length > 0) {
2367                    nodesArray.forEach(function(addedNode) {
2368                        if (addedNode.querySelectorAll) {
2369                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
2370                            elementsArray.forEach(function(element) {
2371                                new Tabs({ element: element, options: readData(element) });
2372                            });
2373                        }
2374                    });
2375                }
2376            });
2377        });
2378
2379        observer.observe(body, {
2380            subtree: true,
2381            childList: true,
2382            characterData: true
2383        });
2384    }
2385
2386    if (document.readyState !== "loading") {
2387        onDocumentReady();
2388    } else {
2389        document.addEventListener("DOMContentLoaded", onDocumentReady);
2390    }
2391
2392    if (containerUtils) {
2393        window.addEventListener("load", containerUtils.scrollToAnchor, false);
2394    }
2395
2396}());
2397
2398/*******************************************************************************
2399 * Copyright 2022 Adobe
2400 *
2401 * Licensed under the Apache License, Version 2.0 (the "License");
2402 * you may not use this file except in compliance with the License.
2403 * You may obtain a copy of the License at
2404 *
2405 *     http://www.apache.org/licenses/LICENSE-2.0
2406 *
2407 * Unless required by applicable law or agreed to in writing, software
2408 * distributed under the License is distributed on an "AS IS" BASIS,
2409 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2410 * See the License for the specific language governing permissions and
2411 * limitations under the License.
2412 ******************************************************************************/
2413(function(document) {
2414    "use strict";
2415
2416    window.CMP = window.CMP || {};
2417    window.CMP.utils = (function() {
2418        var NS = "cmp";
2419
2420        /**
2421         * Reads options data from the Component wrapper element, defined via {@code data-cmp-*} data attributes
2422         *
2423         * @param {HTMLElement} element The component element to read options data from
2424         * @param {String} is The component identifier
2425         * @returns {String[]} The options read from the component data attributes
2426         */
2427        var readData = function(element, is) {
2428            var data = element.dataset;
2429            var options = [];
2430            var capitalized = is;
2431            capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
2432            var reserved = ["is", "hook" + capitalized];
2433
2434            for (var key in data) {
2435                if (Object.prototype.hasOwnProperty.call(data, key)) {
2436                    var value = data[key];
2437
2438                    if (key.indexOf(NS) === 0) {
2439                        key = key.slice(NS.length);
2440                        key = key.charAt(0).toLowerCase() + key.substring(1);
2441
2442                        if (reserved.indexOf(key) === -1) {
2443                            options[key] = value;
2444                        }
2445                    }
2446                }
2447            }
2448            return options;
2449        };
2450
2451        /**
2452         * Set up the final properties of a component by evaluating the transform function or fall back to the default value on demand
2453         * @param {String[]} options the options to transform
2454         * @param {Object} properties object of properties of property functions
2455         * @returns {Object} transformed properties
2456         */
2457        var setupProperties = function(options, properties) {
2458            var transformedProperties = {};
2459
2460            for (var key in properties) {
2461                if (Object.prototype.hasOwnProperty.call(properties, key)) {
2462                    var property = properties[key];
2463                    if (options && options[key] != null) {
2464                        if (property && typeof property.transform === "function") {
2465                            transformedProperties[key] = property.transform(options[key]);
2466                        } else {
2467                            transformedProperties[key] = options[key];
2468                        }
2469                    } else {
2470                        transformedProperties[key] = properties[key]["default"];
2471                    }
2472                }
2473            }
2474            return transformedProperties;
2475        };
2476
2477
2478        return {
2479            readData: readData,
2480            setupProperties: setupProperties
2481        };
2482    }());
2483}(window.document));
2484
2485/*******************************************************************************
2486 * Copyright 2018 Adobe
2487 *
2488 * Licensed under the Apache License, Version 2.0 (the "License");
2489 * you may not use this file except in compliance with the License.
2490 * You may obtain a copy of the License at
2491 *
2492 *     http://www.apache.org/licenses/LICENSE-2.0
2493 *
2494 * Unless required by applicable law or agreed to in writing, software
2495 * distributed under the License is distributed on an "AS IS" BASIS,
2496 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2497 * See the License for the specific language governing permissions and
2498 * limitations under the License.
2499 ******************************************************************************/
2500(function() {
2501    "use strict";
2502
2503    var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined;
2504    if (!containerUtils) {
2505        // eslint-disable-next-line no-console
2506        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.");
2507    }
2508    var dataLayerEnabled;
2509    var dataLayer;
2510    var dataLayerName;
2511
2512    var NS = "cmp";
2513    var IS = "carousel";
2514
2515    var keyCodes = {
2516        SPACE: 32,
2517        END: 35,
2518        HOME: 36,
2519        ARROW_LEFT: 37,
2520        ARROW_UP: 38,
2521        ARROW_RIGHT: 39,
2522        ARROW_DOWN: 40
2523    };
2524
2525    var selectors = {
2526        self: "[data-" + NS + '-is="' + IS + '"]'
2527    };
2528
2529    var properties = {
2530        /**
2531         * Determines whether the Carousel will automatically transition between slides
2532         *
2533         * @memberof Carousel
2534         * @type {Boolean}
2535         * @default false
2536         */
2537        "autoplay": {
2538            "default": false,
2539            "transform": function(value) {
2540                return !(value === null || typeof value === "undefined");
2541            }
2542        },
2543        /**
2544         * Duration (in milliseconds) before automatically transitioning to the next slide
2545         *
2546         * @memberof Carousel
2547         * @type {Number}
2548         * @default 5000
2549         */
2550        "delay": {
2551            "default": 5000,
2552            "transform": function(value) {
2553                value = parseFloat(value);
2554                return !isNaN(value) ? value : null;
2555            }
2556        },
2557        /**
2558         * Determines whether automatic pause on hovering the carousel is disabled
2559         *
2560         * @memberof Carousel
2561         * @type {Boolean}
2562         * @default false
2563         */
2564        "autopauseDisabled": {
2565            "default": false,
2566            "transform": function(value) {
2567                return !(value === null || typeof value === "undefined");
2568            }
2569        }
2570    };
2571
2572    /**
2573     * Carousel Configuration
2574     *
2575     * @typedef {Object} CarouselConfig Represents a Carousel configuration
2576     * @property {HTMLElement} element The HTMLElement representing the Carousel
2577     * @property {*[]} options The Carousel options
2578     */
2579
2580    /**
2581     * Carousel
2582     *
2583     * @class Carousel
2584     * @classdesc An interactive Carousel component for navigating a list of generic items
2585     * @param {CarouselConfig} config The Carousel configuration
2586     */
2587    function Carousel(config) {
2588        var that = this;
2589
2590        if (config && config.element) {
2591            init(config);
2592        }
2593
2594        /**
2595         * Initializes the Carousel
2596         *
2597         * @private
2598         * @param {CarouselConfig} config The Carousel configuration
2599         */
2600        function init(config) {
2601            that._config = config;
2602
2603            // prevents multiple initialization
2604            config.element.removeAttribute("data-" + NS + "-is");
2605
2606            setupProperties(config.options);
2607            cacheElements(config.element);
2608
2609            that._active = 0;
2610            that._paused = false;
2611
2612            if (that._elements.item) {
2613                initializeActive();
2614                bindEvents();
2615                resetAutoplayInterval();
2616                refreshPlayPauseActions();
2617                scrollToDeepLinkIdInCarousel();
2618            }
2619
2620            // TODO: This section is only relevant in edit mode and should move to the editor clientLib
2621            if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) {
2622                /*
2623                 * Editor message handling:
2624                 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
2625                 * - check that the message data panel container type is correct and that the id (path) matches this specific Carousel component
2626                 * - if so, route the "navigate" operation to enact a navigation of the Carousel based on index data
2627                 */
2628                window.CQ = window.CQ || {};
2629                window.CQ.CoreComponents = window.CQ.CoreComponents || {};
2630                window.CQ.CoreComponents.MESSAGE_CHANNEL = window.CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window);
2631                window.CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) {
2632                    if (message.data && message.data.type === "cmp-carousel" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) {
2633                        if (message.data.operation === "navigate") {
2634                            navigate(message.data.index);
2635                        }
2636                    }
2637                });
2638            }
2639        }
2640
2641        /**
2642         * Displays the slide containing the element that corresponds to the deep link in the URI fragment
2643         * and scrolls the browser to this element.
2644         */
2645        function scrollToDeepLinkIdInCarousel() {
2646            if (containerUtils) {
2647                var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "item", "item");
2648                if (deepLinkItemIdx > -1) {
2649                    var deepLinkItem = that._elements["item"][deepLinkItemIdx];
2650                    if (deepLinkItem && that._elements["item"][that._active].id !== deepLinkItem.id) {
2651                        navigateAndFocusIndicator(deepLinkItemIdx, true);
2652                        // pause the carousel auto-rotation
2653                        pause();
2654                    }
2655                    var hashId = window.location.hash.substring(1);
2656                    if (hashId) {
2657                        var hashItem = document.querySelector("[id='" + hashId + "']");
2658                        if (hashItem) {
2659                            hashItem.scrollIntoView();
2660                        }
2661                    }
2662                }
2663            }
2664        }
2665
2666        /**
2667         * Caches the Carousel elements as defined via the {@code data-carousel-hook="ELEMENT_NAME"} markup API
2668         *
2669         * @private
2670         * @param {HTMLElement} wrapper The Carousel wrapper element
2671         */
2672        function cacheElements(wrapper) {
2673            that._elements = {};
2674            that._elements.self = wrapper;
2675            var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
2676
2677            for (var i = 0; i < hooks.length; i++) {
2678                var hook = hooks[i];
2679                var capitalized = IS;
2680                capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
2681                var key = hook.dataset[NS + "Hook" + capitalized];
2682                if (that._elements[key]) {
2683                    if (!Array.isArray(that._elements[key])) {
2684                        var tmp = that._elements[key];
2685                        that._elements[key] = [tmp];
2686                    }
2687                    that._elements[key].push(hook);
2688                } else {
2689                    that._elements[key] = hook;
2690                }
2691            }
2692        }
2693
2694        /**
2695         * Sets up properties for the Carousel based on the passed options.
2696         *
2697         * @private
2698         * @param {Object} options The Carousel options
2699         */
2700        function setupProperties(options) {
2701            that._properties = {};
2702
2703            for (var key in properties) {
2704                if (Object.prototype.hasOwnProperty.call(properties, key)) {
2705                    var property = properties[key];
2706                    var value = null;
2707
2708                    if (options && options[key] != null) {
2709                        value = options[key];
2710
2711                        // transform the provided option
2712                        if (property && typeof property.transform === "function") {
2713                            value = property.transform(value);
2714                        }
2715                    }
2716
2717                    if (value === null) {
2718                        // value still null, take the property default
2719                        value = properties[key]["default"];
2720                    }
2721
2722                    that._properties[key] = value;
2723                }
2724            }
2725        }
2726
2727        /**
2728         * Binds Carousel event handling
2729         *
2730         * @private
2731         */
2732        function bindEvents() {
2733            window.addEventListener("hashchange", scrollToDeepLinkIdInCarousel, false);
2734            if (that._elements["previous"]) {
2735                that._elements["previous"].addEventListener("click", function() {
2736                    var index = getPreviousIndex();
2737                    navigate(index);
2738                    if (dataLayerEnabled) {
2739                        dataLayer.push({
2740                            event: "cmp:show",
2741                            eventInfo: {
2742                                path: "component." + getDataLayerId(that._elements.item[index])
2743                            }
2744                        });
2745                    }
2746                });
2747            }
2748
2749            if (that._elements["next"]) {
2750                that._elements["next"].addEventListener("click", function() {
2751                    var index = getNextIndex();
2752                    navigate(index);
2753                    if (dataLayerEnabled) {
2754                        dataLayer.push({
2755                            event: "cmp:show",
2756                            eventInfo: {
2757                                path: "component." + getDataLayerId(that._elements.item[index])
2758                            }
2759                        });
2760                    }
2761                });
2762            }
2763
2764            var indicators = that._elements["indicator"];
2765            if (indicators) {
2766                for (var i = 0; i < indicators.length; i++) {
2767                    (function(index) {
2768                        indicators[i].addEventListener("click", function(event) {
2769                            navigateAndFocusIndicator(index);
2770                            // pause the carousel auto-rotation
2771                            pause();
2772                        });
2773                    })(i);
2774                }
2775            }
2776
2777            if (that._elements["pause"]) {
2778                if (that._properties.autoplay) {
2779                    that._elements["pause"].addEventListener("click", onPauseClick);
2780                }
2781            }
2782
2783            if (that._elements["play"]) {
2784                if (that._properties.autoplay) {
2785                    that._elements["play"].addEventListener("click", onPlayClick);
2786                }
2787            }
2788
2789            that._elements.self.addEventListener("keydown", onKeyDown);
2790
2791            if (!that._properties.autopauseDisabled) {
2792                that._elements.self.addEventListener("mouseenter", onMouseEnter);
2793                that._elements.self.addEventListener("mouseleave", onMouseLeave);
2794            }
2795
2796            // for accessibility we pause animation when a element get focused
2797            var items = that._elements["item"];
2798            if (items) {
2799                for (var j = 0; j < items.length; j++) {
2800                    items[j].addEventListener("focusin", onMouseEnter);
2801                    items[j].addEventListener("focusout", onMouseLeave);
2802                }
2803            }
2804        }
2805
2806        /**
2807         * Handles carousel keydown events
2808         *
2809         * @private
2810         * @param {Object} event The keydown event
2811         */
2812        function onKeyDown(event) {
2813            var index = that._active;
2814            var lastIndex = that._elements["indicator"].length - 1;
2815
2816            switch (event.keyCode) {
2817                case keyCodes.ARROW_LEFT:
2818                case keyCodes.ARROW_UP:
2819                    event.preventDefault();
2820                    if (index > 0) {
2821                        navigateAndFocusIndicator(index - 1);
2822                    }
2823                    break;
2824                case keyCodes.ARROW_RIGHT:
2825                case keyCodes.ARROW_DOWN:
2826                    event.preventDefault();
2827                    if (index < lastIndex) {
2828                        navigateAndFocusIndicator(index + 1);
2829                    }
2830                    break;
2831                case keyCodes.HOME:
2832                    event.preventDefault();
2833                    navigateAndFocusIndicator(0);
2834                    break;
2835                case keyCodes.END:
2836                    event.preventDefault();
2837                    navigateAndFocusIndicator(lastIndex);
2838                    break;
2839                case keyCodes.SPACE:
2840                    if (that._properties.autoplay && (event.target !== that._elements["previous"] && event.target !== that._elements["next"])) {
2841                        event.preventDefault();
2842                        if (!that._paused) {
2843                            pause();
2844                        } else {
2845                            play();
2846                        }
2847                    }
2848                    if (event.target === that._elements["pause"]) {
2849                        that._elements["play"].focus();
2850                    }
2851                    if (event.target === that._elements["play"]) {
2852                        that._elements["pause"].focus();
2853                    }
2854                    break;
2855                default:
2856                    return;
2857            }
2858        }
2859
2860        /**
2861         * Handles carousel mouseenter events
2862         *
2863         * @private
2864         * @param {Object} event The mouseenter event
2865         */
2866        function onMouseEnter(event) {
2867            clearAutoplayInterval();
2868        }
2869
2870        /**
2871         * Handles carousel mouseleave events
2872         *
2873         * @private
2874         * @param {Object} event The mouseleave event
2875         */
2876        function onMouseLeave(event) {
2877            resetAutoplayInterval();
2878        }
2879
2880        /**
2881         * Handles pause element click events
2882         *
2883         * @private
2884         * @param {Object} event The click event
2885         */
2886        function onPauseClick(event) {
2887            pause();
2888            that._elements["play"].focus();
2889        }
2890
2891        /**
2892         * Handles play element click events
2893         *
2894         * @private
2895         * @param {Object} event The click event
2896         */
2897        function onPlayClick() {
2898            play();
2899            that._elements["pause"].focus();
2900        }
2901
2902        /**
2903         * Pauses the playing of the Carousel. Sets {@code Carousel#_paused} marker.
2904         * Only relevant when autoplay is enabled
2905         *
2906         * @private
2907         */
2908        function pause() {
2909            that._paused = true;
2910            clearAutoplayInterval();
2911            refreshPlayPauseActions();
2912        }
2913
2914        /**
2915         * Enables the playing of the Carousel. Sets {@code Carousel#_paused} marker.
2916         * Only relevant when autoplay is enabled
2917         *
2918         * @private
2919         */
2920        function play() {
2921            that._paused = false;
2922
2923            // If the Carousel is hovered, don't begin auto transitioning until the next mouse leave event
2924            var hovered = false;
2925            if (that._elements.self.parentElement) {
2926                hovered = that._elements.self.parentElement.querySelector(":hover") === that._elements.self;
2927            }
2928            if (that._properties.autopauseDisabled || !hovered) {
2929                resetAutoplayInterval();
2930            }
2931
2932            refreshPlayPauseActions();
2933        }
2934
2935        /**
2936         * Refreshes the play/pause action markup based on the {@code Carousel#_paused} state
2937         *
2938         * @private
2939         */
2940        function refreshPlayPauseActions() {
2941            setActionDisabled(that._elements["pause"], that._paused);
2942            setActionDisabled(that._elements["play"], !that._paused);
2943        }
2944
2945        /**
2946         * Initialize {@code Carousel#_active} based on the active item of the carousel.
2947         */
2948        function initializeActive() {
2949            var items = that._elements["item"];
2950            if (items && Array.isArray(items)) {
2951                for (var i = 0; i < items.length; i++) {
2952                    if (items[i].classList.contains("cmp-carousel__item--active")) {
2953                        that._active = i;
2954                        break;
2955                    }
2956                }
2957            }
2958        }
2959
2960        /**
2961         * Refreshes the item markup based on the current {@code Carousel#_active} index
2962         *
2963         * @private
2964         */
2965        function refreshActive() {
2966            var items = that._elements["item"];
2967            var indicators = that._elements["indicator"];
2968
2969            if (items) {
2970                if (Array.isArray(items)) {
2971                    for (var i = 0; i < items.length; i++) {
2972                        if (i === parseInt(that._active)) {
2973                            items[i].classList.add("cmp-carousel__item--active");
2974                            items[i].removeAttribute("aria-hidden");
2975                            indicators[i].classList.add("cmp-carousel__indicator--active");
2976                            indicators[i].setAttribute("aria-selected", true);
2977                            indicators[i].setAttribute("tabindex", "0");
2978                        } else {
2979                            items[i].classList.remove("cmp-carousel__item--active");
2980                            items[i].setAttribute("aria-hidden", true);
2981                            indicators[i].classList.remove("cmp-carousel__indicator--active");
2982                            indicators[i].setAttribute("aria-selected", false);
2983                            indicators[i].setAttribute("tabindex", "-1");
2984                        }
2985                    }
2986                } else {
2987                    // only one item
2988                    items.classList.add("cmp-carousel__item--active");
2989                    indicators.classList.add("cmp-carousel__indicator--active");
2990                }
2991            }
2992        }
2993
2994        /**
2995         * Focuses the element and prevents scrolling the element into view
2996         *
2997         * @param {HTMLElement} element Element to focus
2998         */
2999        function focusWithoutScroll(element) {
3000            var x = window.scrollX || window.pageXOffset;
3001            var y = window.scrollY || window.pageYOffset;
3002            element.focus();
3003            window.scrollTo(x, y);
3004        }
3005
3006        /**
3007         * Retrieves the next active index, with looping
3008         *
3009         * @private
3010         * @returns {Number} Index of the next carousel item
3011         */
3012        function getNextIndex() {
3013            return that._active === (that._elements["item"].length - 1) ? 0 : that._active + 1;
3014        }
3015
3016        /**
3017         * Retrieves the previous active index, with looping
3018         *
3019         * @private
3020         * @returns {Number} Index of the previous carousel item
3021         */
3022        function getPreviousIndex() {
3023            return that._active === 0 ? (that._elements["item"].length - 1) : that._active - 1;
3024        }
3025
3026        /**
3027         * Navigates to the item at the provided index
3028         *
3029         * @private
3030         * @param {Number} index The index of the item to navigate to
3031         * @param {Boolean} keepHash true to keep the hash in the URL, false to update it
3032         */
3033        function navigate(index, keepHash) {
3034            if (index < 0 || index > (that._elements["item"].length - 1)) {
3035                return;
3036            }
3037
3038            that._active = index;
3039            refreshActive();
3040
3041            if (!keepHash && containerUtils) {
3042                containerUtils.updateUrlHash(that, "item", index);
3043            }
3044
3045            if (dataLayerEnabled) {
3046                var carouselId = that._elements.self.id;
3047                var activeItem = getDataLayerId(that._elements.item[index]);
3048                var updatePayload = { component: {} };
3049                updatePayload.component[carouselId] = { shownItems: [activeItem] };
3050
3051                var removePayload = { component: {} };
3052                removePayload.component[carouselId] = { shownItems: undefined };
3053
3054                dataLayer.push(removePayload);
3055                dataLayer.push(updatePayload);
3056            }
3057
3058            // reset the autoplay transition interval following navigation, if not already hovering the carousel
3059            if (that._elements.self.parentElement) {
3060                if (that._elements.self.parentElement.querySelector(":hover") !== that._elements.self) {
3061                    resetAutoplayInterval();
3062                }
3063            }
3064        }
3065
3066        /**
3067         * Navigates to the item at the provided index and ensures the active indicator gains focus
3068         *
3069         * @private
3070         * @param {Number} index The index of the item to navigate to
3071         * @param {Boolean} keepHash true to keep the hash in the URL, false to update it
3072         */
3073        function navigateAndFocusIndicator(index, keepHash) {
3074            navigate(index, keepHash);
3075            focusWithoutScroll(that._elements["indicator"][index]);
3076
3077            if (dataLayerEnabled) {
3078                dataLayer.push({
3079                    event: "cmp:show",
3080                    eventInfo: {
3081                        path: "component." + getDataLayerId(that._elements.item[index])
3082                    }
3083                });
3084            }
3085        }
3086
3087        /**
3088         * Starts/resets automatic slide transition interval
3089         *
3090         * @private
3091         */
3092        function resetAutoplayInterval() {
3093            if (that._paused || !that._properties.autoplay) {
3094                return;
3095            }
3096            clearAutoplayInterval();
3097            that._autoplayIntervalId = window.setInterval(function() {
3098                if (document.visibilityState && document.hidden) {
3099                    return;
3100                }
3101                var indicators = that._elements["indicators"];
3102                if (indicators !== document.activeElement && indicators.contains(document.activeElement)) {
3103                    // if an indicator has focus, ensure we switch focus following navigation
3104                    navigateAndFocusIndicator(getNextIndex(), true);
3105                } else {
3106                    navigate(getNextIndex(), true);
3107                }
3108            }, that._properties.delay);
3109        }
3110
3111        /**
3112         * Clears/pauses automatic slide transition interval
3113         *
3114         * @private
3115         */
3116        function clearAutoplayInterval() {
3117            window.clearInterval(that._autoplayIntervalId);
3118            that._autoplayIntervalId = null;
3119        }
3120
3121        /**
3122         * Sets the disabled state for an action and toggles the appropriate CSS classes
3123         *
3124         * @private
3125         * @param {HTMLElement} action Action to disable
3126         * @param {Boolean} [disable] {@code true} to disable, {@code false} to enable
3127         */
3128        function setActionDisabled(action, disable) {
3129            if (!action) {
3130                return;
3131            }
3132            if (disable !== false) {
3133                action.disabled = true;
3134                action.classList.add("cmp-carousel__action--disabled");
3135            } else {
3136                action.disabled = false;
3137                action.classList.remove("cmp-carousel__action--disabled");
3138            }
3139        }
3140    }
3141
3142    /**
3143     * Parses the dataLayer string and returns the ID
3144     *
3145     * @private
3146     * @param {HTMLElement} item the accordion item
3147     * @returns {String} dataLayerId or undefined
3148     */
3149    function getDataLayerId(item) {
3150        if (item) {
3151            if (item.dataset.cmpDataLayer) {
3152                return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0];
3153            } else {
3154                return item.id;
3155            }
3156        }
3157        return null;
3158    }
3159
3160    /**
3161     * Document ready handler and DOM mutation observers. Initializes Carousel components as necessary.
3162     *
3163     * @private
3164     */
3165    function onDocumentReady() {
3166        dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled");
3167        if (dataLayerEnabled) {
3168            dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer";
3169            dataLayer = window[dataLayerName] = window[dataLayerName] || [];
3170        }
3171
3172        var elements = document.querySelectorAll(selectors.self);
3173        for (var i = 0; i < elements.length; i++) {
3174            new Carousel({ element: elements[i], options: CMP.utils.readData(elements[i], IS) });
3175        }
3176
3177        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
3178        var body = document.querySelector("body");
3179        var observer = new MutationObserver(function(mutations) {
3180            mutations.forEach(function(mutation) {
3181                // needed for IE
3182                var nodesArray = [].slice.call(mutation.addedNodes);
3183                if (nodesArray.length > 0) {
3184                    nodesArray.forEach(function(addedNode) {
3185                        if (addedNode.querySelectorAll) {
3186                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
3187                            elementsArray.forEach(function(element) {
3188                                new Carousel({ element: element, options: CMP.utils.readData(element, IS) });
3189                            });
3190                        }
3191                    });
3192                }
3193            });
3194        });
3195
3196        observer.observe(body, {
3197            subtree: true,
3198            childList: true,
3199            characterData: true
3200        });
3201    }
3202
3203    var documentReady = document.readyState !== "loading" ? Promise.resolve() : new Promise(function(resolve) {
3204        document.addEventListener("DOMContentLoaded", resolve);
3205    });
3206    Promise.all([documentReady]).then(onDocumentReady);
3207
3208    if (containerUtils) {
3209        window.addEventListener("load", containerUtils.scrollToAnchor, false);
3210    }
3211
3212}());
3213
3214/*******************************************************************************
3215 * Copyright 2022 Adobe
3216 *
3217 * Licensed under the Apache License, Version 2.0 (the "License");
3218 * you may not use this file except in compliance with the License.
3219 * You may obtain a copy of the License at
3220 *
3221 *     http://www.apache.org/licenses/LICENSE-2.0
3222 *
3223 * Unless required by applicable law or agreed to in writing, software
3224 * distributed under the License is distributed on an "AS IS" BASIS,
3225 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3226 * See the License for the specific language governing permissions and
3227 * limitations under the License.
3228 ******************************************************************************/
3229(function(document) {
3230    "use strict";
3231
3232    window.CMP = window.CMP || {};
3233    window.CMP.utils = (function() {
3234        var NS = "cmp";
3235
3236        /**
3237         * Reads options data from the Component wrapper element, defined via {@code data-cmp-*} data attributes
3238         *
3239         * @param {HTMLElement} element The component element to read options data from
3240         * @param {String} is The component identifier
3241         * @returns {String[]} The options read from the component data attributes
3242         */
3243        var readData = function(element, is) {
3244            var data = element.dataset;
3245            var options = [];
3246            var capitalized = is;
3247            capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
3248            var reserved = ["is", "hook" + capitalized];
3249
3250            for (var key in data) {
3251                if (Object.prototype.hasOwnProperty.call(data, key)) {
3252                    var value = data[key];
3253
3254                    if (key.indexOf(NS) === 0) {
3255                        key = key.slice(NS.length);
3256                        key = key.charAt(0).toLowerCase() + key.substring(1);
3257
3258                        if (reserved.indexOf(key) === -1) {
3259                            options[key] = value;
3260                        }
3261                    }
3262                }
3263            }
3264            return options;
3265        };
3266
3267        /**
3268         * Set up the final properties of a component by evaluating the transform function or fall back to the default value on demand
3269         * @param {String[]} options the options to transform
3270         * @param {Object} properties object of properties of property functions
3271         * @returns {Object} transformed properties
3272         */
3273        var setupProperties = function(options, properties) {
3274            var transformedProperties = {};
3275
3276            for (var key in properties) {
3277                if (Object.prototype.hasOwnProperty.call(properties, key)) {
3278                    var property = properties[key];
3279                    if (options && options[key] != null) {
3280                        if (property && typeof property.transform === "function") {
3281                            transformedProperties[key] = property.transform(options[key]);
3282                        } else {
3283                            transformedProperties[key] = options[key];
3284                        }
3285                    } else {
3286                        transformedProperties[key] = properties[key]["default"];
3287                    }
3288                }
3289            }
3290            return transformedProperties;
3291        };
3292
3293
3294        return {
3295            readData: readData,
3296            setupProperties: setupProperties
3297        };
3298    }());
3299}(window.document));
3300
3301/*******************************************************************************
3302 * Copyright 2022 Adobe
3303 *
3304 * Licensed under the Apache License, Version 2.0 (the "License");
3305 * you may not use this file except in compliance with the License.
3306 * You may obtain a copy of the License at
3307 *
3308 *     http://www.apache.org/licenses/LICENSE-2.0
3309 *
3310 * Unless required by applicable law or agreed to in writing, software
3311 * distributed under the License is distributed on an "AS IS" BASIS,
3312 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3313 * See the License for the specific language governing permissions and
3314 * limitations under the License.
3315 ******************************************************************************/
3316(function(document) {
3317    "use strict";
3318
3319    window.CMP = window.CMP || {};
3320    window.CMP.image = window.CMP.image || {};
3321    window.CMP.image.dynamicMedia = (function() {
3322        var autoSmartCrops = {};
3323        var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}";
3324        var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}";
3325        var SRC_URI_DPR_OFF = "dpr=off";
3326        var SRC_URI_DPR_ON = "dpr=on,{dpr}";
3327        var dpr = window.devicePixelRatio || 1;
3328        var config = {
3329            minWidth: 20
3330        };
3331
3332        /**
3333         * get auto smart crops from dm
3334         * @param {String} src the src uri
3335         * @returns {{}} the smart crop json object
3336         */
3337        var getAutoSmartCrops = function(src) {
3338            var request = new XMLHttpRequest();
3339            var url = src.split(SRC_URI_TEMPLATE_WIDTH_VAR)[0] + "?req=set,json";
3340            request.open("GET", url, false);
3341            request.onload = function() {
3342                if (request.status >= 200 && request.status < 400) {
3343                    // success status
3344                    var responseText = request.responseText;
3345                    var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi);
3346                    var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi);
3347                    var resPayload = rePayload.exec(responseText);
3348                    var payload;
3349                    if (resPayload) {
3350                        var payloadStr = resPayload[2];
3351                        if (rePayloadJSON.test(payloadStr)) {
3352                            payload = JSON.parse(payloadStr);
3353                        }
3354
3355                    }
3356                    // check "relation" - only in case of smartcrop preset
3357                    if (payload && payload.set.relation && payload.set.relation.length > 0) {
3358                        for (var i = 0; i < payload.set.relation.length; i++) {
3359                            autoSmartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] =
3360                                ":" + payload.set.relation[i].userdata.SmartCropDef;
3361                        }
3362                    }
3363                } else {
3364                    // error status
3365                }
3366            };
3367            request.send();
3368            return autoSmartCrops;
3369        };
3370
3371        /**
3372         * Build and return the srcset value based on the available auto smart crops
3373         * @param {String} src the src uri
3374         * @param {Object} smartCrops the smart crops object
3375         * @returns {String} the srcset
3376         */
3377        var getSrcSet = function(src, smartCrops) {
3378            var srcset;
3379            var keys = Object.keys(smartCrops);
3380            if (keys.length > 0) {
3381                srcset = [];
3382                for (var key in autoSmartCrops) {
3383                    srcset.push(src.replace(SRC_URI_TEMPLATE_WIDTH_VAR, smartCrops[key]) + " " + key + "w");
3384                }
3385            }
3386            return  srcset.join(",");
3387        };
3388
3389        /**
3390         * Get the optimal width based on the available sizes
3391         * @param {[Number]} sizes the available sizes
3392         * @param {Number} width the element width
3393         * @returns {String} the optimal width
3394         */
3395        function getOptimalWidth(sizes, width) {
3396            var len = sizes.length;
3397            var key = 0;
3398
3399            while ((key < len - 1) && (sizes[key] < width)) {
3400                key++;
3401            }
3402
3403            return sizes[key] !== undefined ? sizes[key].toString() : width;
3404        }
3405
3406        /**
3407         * Get the width of an element or parent element if the width is smaller than the minimum width
3408         * @param {HTMLElement} component the image component
3409         * @param {HTMLElement | Node} parent the parent element
3410         * @returns {Number} the width of the element
3411         */
3412        var getWidth = function(component, parent) {
3413            var width = component.offsetWidth;
3414            while (width < config.minWidth && parent && !component._autoWidth) {
3415                width =  parent.offsetWidth;
3416                parent = parent.parentNode;
3417            }
3418            return width;
3419        };
3420
3421        /**
3422         * Set the src and srcset attribute for a Dynamic Media Image which auto smart crops enabled.
3423         * @param {HTMLElement} component the image component
3424         * @param {{}} properties the component properties
3425         */
3426        var setDMAttributes = function(component, properties) {
3427            // for v3 we first have to turn the dpr on
3428            var src = properties.src.replace(SRC_URI_DPR_OFF, SRC_URI_DPR_ON);
3429            src = src.replace(SRC_URI_TEMPLATE_DPR_VAR, dpr);
3430            var smartCrops = {};
3431            var width;
3432            if (properties["smartcroprendition"] === "SmartCrop:Auto") {
3433                smartCrops = getAutoSmartCrops(src);
3434            }
3435            var hasWidths = (properties.widths && properties.widths.length > 0) || Object.keys(smartCrops).length > 0;
3436            if (hasWidths) {
3437                var image = component.querySelector("img");
3438                var elemWidth = getWidth(component, component.parentNode);
3439                if (properties["smartcroprendition"] === "SmartCrop:Auto") {
3440                    image.setAttribute("srcset", CMP.image.dynamicMedia.getSrcSet(src, smartCrops));
3441                    width = getOptimalWidth(Object.keys(smartCrops, elemWidth));
3442                    image.setAttribute("src", CMP.image.dynamicMedia.getSrc(src, smartCrops[width]));
3443                } else {
3444                    width = getOptimalWidth(properties.widths, elemWidth);
3445                    image.setAttribute("src", CMP.image.dynamicMedia.getSrc(src, width));
3446                }
3447            }
3448        };
3449
3450        /**
3451         * Get the src attribute based on the optimal width
3452         * @param {String} src the src uri
3453         * @param {String} width the element width
3454         * @returns {String} the final src attribute
3455         */
3456        var getSrc = function(src, width) {
3457            if (src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR) > -1) {
3458                src = src.replace(SRC_URI_TEMPLATE_WIDTH_VAR, width);
3459            }
3460            return src;
3461        };
3462
3463
3464        return {
3465            getAutoSmartCrops: getAutoSmartCrops,
3466            getSrcSet: getSrcSet,
3467            getSrc: getSrc,
3468            setDMAttributes: setDMAttributes,
3469            getWidth: getWidth
3470        };
3471    }());
3472    document.dispatchEvent(new CustomEvent("core.wcm.components.commons.site.image.dynamic-media.loaded"));
3473}(window.document));
3474
3475/*******************************************************************************
3476 * Copyright 2022 Adobe
3477 *
3478 * Licensed under the Apache License, Version 2.0 (the "License");
3479 * you may not use this file except in compliance with the License.
3480 * You may obtain a copy of the License at
3481 *
3482 *     http://www.apache.org/licenses/LICENSE-2.0
3483 *
3484 * Unless required by applicable law or agreed to in writing, software
3485 * distributed under the License is distributed on an "AS IS" BASIS,
3486 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3487 * See the License for the specific language governing permissions and
3488 * limitations under the License.
3489 ******************************************************************************/
3490(function(document) {
3491
3492    "use strict";
3493
3494    window.CMP = window.CMP || {};
3495    window.CMP.image = window.CMP.image || {};
3496    window.CMP.image.v3 = (function() {
3497        var IS = "image";
3498
3499        var selectors = {
3500            self: "[data-cmp-hook-image='imageV3']"
3501        };
3502
3503        var properties = {
3504            "widths": {
3505                "default": [],
3506                "transform": function(value) {
3507                    var widths = [];
3508                    value.split(",").forEach(function(item) {
3509                        item = parseFloat(item);
3510                        if (!isNaN(item)) {
3511                            widths.push(item);
3512                        }
3513                    });
3514                    return widths;
3515                }
3516            },
3517            "dmimage": {
3518                "default": false,
3519                "transform": function(value) {
3520                    return !(value === null || typeof value === "undefined");
3521                }
3522            },
3523            "src": {
3524                "transform": function(value) {
3525                    return decodeURIComponent(value);
3526                }
3527            },
3528            "smartcroprendition": ""
3529        };
3530
3531        function Image(config) {
3532            var that = this;
3533            /**
3534             * Init the image if the image is from dynamic media
3535             * @param {HTMLElement} component the image component
3536             */
3537            that.initImage = function(component) {
3538                var options = CMP.utils.readData(component, IS);
3539                that._properties = CMP.utils.setupProperties(options, properties);
3540                if (that._properties.dmimage) {
3541                    CMP.image.dynamicMedia.setDMAttributes(component, that._properties);
3542                }
3543            };
3544            that.initImage(config.element);
3545        }
3546
3547        return {
3548            init: function() {
3549                var elements = document.querySelectorAll(selectors.self);
3550                for (var i = 0; i < elements.length; i++) {
3551                    new Image({ element: elements[i], options: CMP.utils.readData(elements[i], IS) });
3552                }
3553
3554                var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
3555                var body             = document.querySelector("body");
3556                var observer         = new MutationObserver(function(mutations) {
3557                    mutations.forEach(function(mutation) {
3558                        // needed for IE
3559                        var nodesArray = [].slice.call(mutation.addedNodes);
3560                        if (nodesArray.length > 0) {
3561                            nodesArray.forEach(function(addedNode) {
3562                                if (addedNode.querySelectorAll) {
3563                                    var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
3564                                    elementsArray.forEach(function(element) {
3565                                        new Image({ element: element, options: CMP.utils.readData(element, IS) });
3566                                    });
3567                                }
3568                            });
3569                        }
3570                    });
3571                });
3572
3573                observer.observe(body, {
3574                    subtree: true,
3575                    childList: true,
3576                    characterData: true
3577                });
3578            }
3579        };
3580    }());
3581
3582    var documentReady = document.readyState !== "loading" ? Promise.resolve() : new Promise(function(resolve) {
3583        document.addEventListener("DOMContentLoaded", resolve);
3584    });
3585    Promise.all([documentReady]).then(window.CMP.image.v3.init);
3586}(window.document));
3587
3588/*******************************************************************************
3589 * Copyright 2022 Adobe
3590 *
3591 * Licensed under the Apache License, Version 2.0 (the "License");
3592 * you may not use this file except in compliance with the License.
3593 * You may obtain a copy of the License at
3594 *
3595 *     http://www.apache.org/licenses/LICENSE-2.0
3596 *
3597 * Unless required by applicable law or agreed to in writing, software
3598 * distributed under the License is distributed on an "AS IS" BASIS,
3599 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3600 * See the License for the specific language governing permissions and
3601 * limitations under the License.
3602 ******************************************************************************/
3603(function() {
3604    "use strict";
3605
3606    var NS = "cmp";
3607    var IS = "search";
3608
3609    var DELAY = 300; // time before fetching new results when the user is typing a search string
3610    var LOADING_DISPLAY_DELAY = 300; // minimum time during which the loading indicator is displayed
3611    var PARAM_RESULTS_OFFSET = "resultsOffset";
3612
3613    var keyCodes = {
3614        TAB: 9,
3615        ENTER: 13,
3616        ESCAPE: 27,
3617        ARROW_UP: 38,
3618        ARROW_DOWN: 40
3619    };
3620
3621    var selectors = {
3622        self: "[data-" + NS + '-is="' + IS + '"]',
3623        item: {
3624            self: "[data-" + NS + "-hook-" + IS + '="item"]',
3625            title: "[data-" + NS + "-hook-" + IS + '="itemTitle"]',
3626            focused: "." + NS + "-search__item--is-focused"
3627        }
3628    };
3629
3630    var properties = {
3631        /**
3632         * The minimum required length of the search term before results are fetched.
3633         *
3634         * @memberof Search
3635         * @type {Number}
3636         * @default 3
3637         */
3638        minLength: {
3639            "default": 3,
3640            transform: function(value) {
3641                value = parseFloat(value);
3642                return isNaN(value) ? null : value;
3643            }
3644        },
3645        /**
3646         * The maximal number of results fetched by a search request.
3647         *
3648         * @memberof Search
3649         * @type {Number}
3650         * @default 10
3651         */
3652        resultsSize: {
3653            "default": 10,
3654            transform: function(value) {
3655                value = parseFloat(value);
3656                return isNaN(value) ? null : value;
3657            }
3658        }
3659    };
3660
3661    var idCount = 0;
3662
3663    function readData(element) {
3664        var data = element.dataset;
3665        var options = [];
3666        var capitalized = IS;
3667        capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
3668        var reserved = ["is", "hook" + capitalized];
3669
3670        for (var key in data) {
3671            if (Object.prototype.hasOwnProperty.call(data, key)) {
3672                var value = data[key];
3673
3674                if (key.indexOf(NS) === 0) {
3675                    key = key.slice(NS.length);
3676                    key = key.charAt(0).toLowerCase() + key.substring(1);
3677
3678                    if (reserved.indexOf(key) === -1) {
3679                        options[key] = value;
3680                    }
3681                }
3682            }
3683        }
3684
3685        return options;
3686    }
3687
3688    function toggleShow(element, show) {
3689        if (element) {
3690            if (show !== false) {
3691                element.style.display = "block";
3692                element.setAttribute("aria-hidden", false);
3693            } else {
3694                element.style.display = "none";
3695                element.setAttribute("aria-hidden", true);
3696            }
3697        }
3698    }
3699
3700    function serialize(form) {
3701        var query = [];
3702        if (form && form.elements) {
3703            for (var i = 0; i < form.elements.length; i++) {
3704                var node = form.elements[i];
3705                if (!node.disabled && node.name) {
3706                    var param = [node.name, encodeURIComponent(node.value)];
3707                    query.push(param.join("="));
3708                }
3709            }
3710        }
3711        return query.join("&");
3712    }
3713
3714    function mark(node, regex) {
3715        if (!node || !regex) {
3716            return;
3717        }
3718
3719        // text nodes
3720        if (node.nodeType === 3) {
3721            var nodeValue = node.nodeValue;
3722            var match = regex.exec(nodeValue);
3723
3724            if (nodeValue && match) {
3725                var element = document.createElement("mark");
3726                element.className = NS + "-search__item-mark";
3727                element.appendChild(document.createTextNode(match[0]));
3728
3729                var after = node.splitText(match.index);
3730                after.nodeValue = after.nodeValue.substring(match[0].length);
3731                node.parentNode.insertBefore(element, after);
3732            }
3733        } else if (node.hasChildNodes()) {
3734            for (var i = 0; i < node.childNodes.length; i++) {
3735                // recurse
3736                mark(node.childNodes[i], regex);
3737            }
3738        }
3739    }
3740
3741    // useful for Accessibility, helping users with low vision and users with cognitive disabilities to identify the change in results
3742    function updateSearchResultsStatusMessageElement(searchElementId, totalResults) {
3743        var searchResultsStatusMessage = document.querySelector("#" + searchElementId + "> .cmp_search__info");
3744        searchResultsStatusMessage.style.visibility = "visible";
3745        var searchResultsFoundMessage = totalResults === 1 ? totalResults + " result" : totalResults + " results";
3746        var searchResultsNotFoundMessage = "No results";
3747        searchResultsStatusMessage.innerText = totalResults > 0 ? searchResultsFoundMessage : searchResultsNotFoundMessage;
3748    }
3749
3750    function Search(config) {
3751        if (config.element) {
3752            // prevents multiple initialization
3753            config.element.removeAttribute("data-" + NS + "-is");
3754        }
3755
3756        this._cacheElements(config.element);
3757        this._setupProperties(config.options);
3758
3759        this._action = this._elements.form.getAttribute("action");
3760        this._resultsOffset = 0;
3761        this._hasMoreResults = true;
3762
3763        this._elements.input.addEventListener("input", this._onInput.bind(this));
3764        this._elements.input.addEventListener("focus", this._onInput.bind(this));
3765        this._elements.input.addEventListener("keydown", this._onKeydown.bind(this));
3766        this._elements.clear.addEventListener("click", this._onClearClick.bind(this));
3767        document.addEventListener("click", this._onDocumentClick.bind(this));
3768        this._elements.results.addEventListener("scroll", this._onScroll.bind(this));
3769
3770        this._makeAccessible();
3771    }
3772
3773    Search.prototype._displayResults = function() {
3774        if (this._elements.input.value.length === 0) {
3775            toggleShow(this._elements.clear, false);
3776            this._cancelResults();
3777        } else if (this._elements.input.value.length < this._properties.minLength) {
3778            toggleShow(this._elements.clear, true);
3779        } else {
3780            this._updateResults();
3781            toggleShow(this._elements.clear, true);
3782        }
3783    };
3784
3785    Search.prototype._onScroll = function(event) {
3786        // fetch new results when the results to be scrolled down are less than the visible results
3787        if (this._elements.results.scrollTop + 2 * this._elements.results.clientHeight >= this._elements.results.scrollHeight) {
3788            this._resultsOffset += this._properties.resultsSize;
3789            this._displayResults();
3790        }
3791    };
3792
3793    Search.prototype._onInput = function(event) {
3794        var self = this;
3795        self._cancelResults();
3796        // start searching when the search term reaches the minimum length
3797        this._timeout = setTimeout(function() {
3798            self._displayResults();
3799        }, DELAY);
3800    };
3801
3802    Search.prototype._onKeydown = function(event) {
3803        var self = this;
3804
3805        switch (event.keyCode) {
3806            case keyCodes.TAB:
3807                if (self._resultsOpen()) {
3808                    toggleShow(self._elements.results, false);
3809                    self._elements.input.setAttribute("aria-expanded", "false");
3810                    this._hideSearchResultsStatusMessage();
3811                }
3812                break;
3813            case keyCodes.ENTER:
3814                event.preventDefault();
3815                if (self._resultsOpen()) {
3816                    var focused = self._elements.results.querySelector(selectors.item.focused);
3817                    if (focused) {
3818                        focused.click();
3819                    }
3820                }
3821                break;
3822            case keyCodes.ESCAPE:
3823                self._cancelResults();
3824                break;
3825            case keyCodes.ARROW_UP:
3826                if (self._resultsOpen()) {
3827                    event.preventDefault();
3828                    self._stepResultFocus(true);
3829                }
3830                break;
3831            case keyCodes.ARROW_DOWN:
3832                if (self._resultsOpen()) {
3833                    event.preventDefault();
3834                    self._stepResultFocus();
3835                } else {
3836                    // test the input and if necessary fetch and display the results
3837                    self._onInput();
3838                }
3839                break;
3840            default:
3841                return;
3842        }
3843    };
3844
3845    Search.prototype._onClearClick = function(event) {
3846        event.preventDefault();
3847        this._elements.input.value = "";
3848        toggleShow(this._elements.clear, false);
3849        toggleShow(this._elements.results, false);
3850        this._elements.input.setAttribute("aria-expanded", "false");
3851        this._hideSearchResultsStatusMessage();
3852    };
3853
3854    Search.prototype._onDocumentClick = function(event) {
3855        var inputContainsTarget =  this._elements.input.contains(event.target);
3856        var resultsContainTarget = this._elements.results.contains(event.target);
3857
3858        if (!(inputContainsTarget || resultsContainTarget)) {
3859            toggleShow(this._elements.results, false);
3860            this._elements.input.setAttribute("aria-expanded", "false");
3861            this._hideSearchResultsStatusMessage();
3862        }
3863    };
3864
3865    Search.prototype._resultsOpen = function() {
3866        return this._elements.results.style.display !== "none";
3867    };
3868
3869    Search.prototype._makeAccessible = function() {
3870        var id = NS + "-search-results-" + idCount;
3871        this._elements.input.setAttribute("aria-owns", id);
3872        this._elements.results.id = id;
3873        idCount++;
3874    };
3875
3876    Search.prototype._generateItems = function(data, results) {
3877        var self = this;
3878
3879        data.forEach(function(item) {
3880            var el = document.createElement("span");
3881            el.innerHTML = self._elements.itemTemplate.innerHTML;
3882            el.querySelectorAll(selectors.item.title)[0].appendChild(document.createTextNode(item.title));
3883            el.querySelectorAll(selectors.item.self)[0].setAttribute("href", self._safeHref(item.url));
3884            results.innerHTML += el.innerHTML;
3885        });
3886    };
3887
3888    Search.prototype._safeHref = function(href) {
3889        var a = document.createElement("a");
3890        a.href = href;
3891        return a.pathname;
3892    };
3893
3894    Search.prototype._markResults = function() {
3895        var nodeList = this._elements.results.querySelectorAll(selectors.item.self);
3896        var escapedTerm = this._elements.input.value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
3897        var regex = new RegExp("(" + escapedTerm + ")", "gi");
3898
3899        for (var i = this._resultsOffset - 1; i < nodeList.length; ++i) {
3900            var result = nodeList[i];
3901            mark(result, regex);
3902        }
3903    };
3904
3905    Search.prototype._stepResultFocus = function(reverse) {
3906        var results = this._elements.results.querySelectorAll(selectors.item.self);
3907        var focused = this._elements.results.querySelector(selectors.item.focused);
3908        var newFocused;
3909        var index = Array.prototype.indexOf.call(results, focused);
3910        var focusedCssClass = NS + "-search__item--is-focused";
3911
3912        if (results.length > 0) {
3913
3914            if (!reverse) {
3915                // highlight the next result
3916                if (index < 0) {
3917                    results[0].classList.add(focusedCssClass);
3918                    results[0].setAttribute("aria-selected", "true");
3919                } else if (index + 1 < results.length) {
3920                    results[index].classList.remove(focusedCssClass);
3921                    results[index].setAttribute("aria-selected", "false");
3922                    results[index + 1].classList.add(focusedCssClass);
3923                    results[index + 1].setAttribute("aria-selected", "true");
3924                }
3925
3926                // if the last visible result is partially hidden, scroll up until it's completely visible
3927                newFocused = this._elements.results.querySelector(selectors.item.focused);
3928                if (newFocused) {
3929                    var bottomHiddenHeight = newFocused.offsetTop + newFocused.offsetHeight - this._elements.results.scrollTop - this._elements.results.clientHeight;
3930                    if (bottomHiddenHeight > 0) {
3931                        this._elements.results.scrollTop += bottomHiddenHeight;
3932                    } else {
3933                        this._onScroll();
3934                    }
3935                }
3936
3937            } else {
3938                // highlight the previous result
3939                if (index >= 1) {
3940                    results[index].classList.remove(focusedCssClass);
3941                    results[index].setAttribute("aria-selected", "false");
3942                    results[index - 1].classList.add(focusedCssClass);
3943                    results[index - 1].setAttribute("aria-selected", "true");
3944                }
3945
3946                // if the first visible result is partially hidden, scroll down until it's completely visible
3947                newFocused = this._elements.results.querySelector(selectors.item.focused);
3948                if (newFocused) {
3949                    var topHiddenHeight = this._elements.results.scrollTop - newFocused.offsetTop;
3950                    if (topHiddenHeight > 0) {
3951                        this._elements.results.scrollTop -= topHiddenHeight;
3952                    }
3953                }
3954            }
3955        }
3956    };
3957
3958    Search.prototype._updateResults = function() {
3959        var self = this;
3960        if (self._hasMoreResults) {
3961            var request = new XMLHttpRequest();
3962            var url = self._action + "?" + serialize(self._elements.form) + "&" + PARAM_RESULTS_OFFSET + "=" + self._resultsOffset;
3963
3964            request.open("GET", url, true);
3965            request.onload = function() {
3966                // when the results are loaded: hide the loading indicator and display the search icon after a minimum period
3967                setTimeout(function() {
3968                    toggleShow(self._elements.loadingIndicator, false);
3969                    toggleShow(self._elements.icon, true);
3970                }, LOADING_DISPLAY_DELAY);
3971                if (request.status >= 200 && request.status < 400) {
3972                    // success status
3973                    var data = JSON.parse(request.responseText);
3974                    updateSearchResultsStatusMessageElement(self._elements.self.id, data.length);
3975                    if (data.length > 0) {
3976                        self._generateItems(data, self._elements.results);
3977                        self._markResults();
3978                        toggleShow(self._elements.results, true);
3979                        self._elements.input.setAttribute("aria-expanded", "true");
3980                    } else {
3981                        self._hasMoreResults = false;
3982                    }
3983                    // the total number of results is not a multiple of the fetched results:
3984                    // -> we reached the end of the query
3985                    if (self._elements.results.querySelectorAll(selectors.item.self).length % self._properties.resultsSize > 0) {
3986                        self._hasMoreResults = false;
3987                    }
3988                } else {
3989                    // error status
3990                }
3991            };
3992            // when the results are loading: display the loading indicator and hide the search icon
3993            toggleShow(self._elements.loadingIndicator, true);
3994            toggleShow(self._elements.icon, false);
3995            request.send();
3996        }
3997    };
3998
3999    Search.prototype._cancelResults = function() {
4000        clearTimeout(this._timeout);
4001        this._elements.results.scrollTop = 0;
4002        this._resultsOffset = 0;
4003        this._hasMoreResults = true;
4004        this._elements.results.innerHTML = "";
4005        this._elements.input.setAttribute("aria-expanded", "false");
4006        this._hideSearchResultsStatusMessage();
4007    };
4008
4009    Search.prototype._hideSearchResultsStatusMessage = function() {
4010        var searchResultsStatusMessage = document.querySelector("#" + this._elements.self.id + "> .cmp_search__info");
4011        searchResultsStatusMessage.style.visibility = "hidden";
4012    };
4013
4014    Search.prototype._cacheElements = function(wrapper) {
4015        this._elements = {};
4016        this._elements.self = wrapper;
4017        var hooks = this._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
4018
4019        for (var i = 0; i < hooks.length; i++) {
4020            var hook = hooks[i];
4021            var capitalized = IS;
4022            capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
4023            var key = hook.dataset[NS + "Hook" + capitalized];
4024            this._elements[key] = hook;
4025        }
4026    };
4027
4028    Search.prototype._setupProperties = function(options) {
4029        this._properties = {};
4030
4031        for (var key in properties) {
4032            if (Object.prototype.hasOwnProperty.call(properties, key)) {
4033                var property = properties[key];
4034                if (options && options[key] != null) {
4035                    if (property && typeof property.transform === "function") {
4036                        this._properties[key] = property.transform(options[key]);
4037                    } else {
4038                        this._properties[key] = options[key];
4039                    }
4040                } else {
4041                    this._properties[key] = properties[key]["default"];
4042                }
4043            }
4044        }
4045    };
4046
4047    function onDocumentReady() {
4048        var elements = document.querySelectorAll(selectors.self);
4049        for (var i = 0; i < elements.length; i++) {
4050            new Search({ element: elements[i], options: readData(elements[i]) });
4051        }
4052
4053        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
4054        var body = document.querySelector("body");
4055        var observer = new MutationObserver(function(mutations) {
4056            mutations.forEach(function(mutation) {
4057                // needed for IE
4058                var nodesArray = [].slice.call(mutation.addedNodes);
4059                if (nodesArray.length > 0) {
4060                    nodesArray.forEach(function(addedNode) {
4061                        if (addedNode.querySelectorAll) {
4062                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
4063                            elementsArray.forEach(function(element) {
4064                                new Search({ element: element, options: readData(element) });
4065                            });
4066                        }
4067                    });
4068                }
4069            });
4070        });
4071
4072        observer.observe(body, {
4073            subtree: true,
4074            childList: true,
4075            characterData: true
4076        });
4077    }
4078
4079    if (document.readyState !== "loading") {
4080        onDocumentReady();
4081    } else {
4082        document.addEventListener("DOMContentLoaded", onDocumentReady);
4083    }
4084
4085})();
4086
4087/*******************************************************************************
4088 * Copyright 2016 Adobe
4089 *
4090 * Licensed under the Apache License, Version 2.0 (the "License");
4091 * you may not use this file except in compliance with the License.
4092 * You may obtain a copy of the License at
4093 *
4094 *     http://www.apache.org/licenses/LICENSE-2.0
4095 *
4096 * Unless required by applicable law or agreed to in writing, software
4097 * distributed under the License is distributed on an "AS IS" BASIS,
4098 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4099 * See the License for the specific language governing permissions and
4100 * limitations under the License.
4101 ******************************************************************************/
4102(function() {
4103    "use strict";
4104
4105    var NS = "cmp";
4106    var IS = "formText";
4107    var IS_DASH = "form-text";
4108    var SELF_SELECTOR = "[data-" + NS + '-is="' + IS + '"]';
4109
4110    var selectors = {
4111        self: SELF_SELECTOR,
4112        validationMessage: SELF_SELECTOR + " .cmp-form-text__validation-message"
4113    };
4114
4115    var displayValidationMessage = false;
4116
4117    var properties = {
4118        /**
4119         * A validation message to display if there is a type mismatch between the user input and expected input.
4120         *
4121         * @type {String}
4122         */
4123        constraintMessage: "",
4124        /**
4125         * A validation message to display if no input is supplied, but input is expected for the field.
4126         *
4127         * @type {String}
4128         */
4129        requiredMessage: ""
4130    };
4131
4132    function readData(element) {
4133        var data = element.dataset;
4134        var options = [];
4135        var capitalized = IS;
4136        capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
4137        var reserved = ["is", "hook" + capitalized];
4138
4139        for (var key in data) {
4140            if (Object.prototype.hasOwnProperty.call(data, key)) {
4141                var value = data[key];
4142
4143                if (key.indexOf(NS) === 0) {
4144                    key = key.slice(NS.length);
4145                    key = key.charAt(0).toLowerCase() + key.substring(1);
4146
4147                    if (reserved.indexOf(key) === -1) {
4148                        options[key] = value;
4149                    }
4150                }
4151            }
4152        }
4153
4154        return options;
4155    }
4156
4157    function FormText(config) {
4158        if (config.element) {
4159            // prevents multiple initialization
4160            config.element.removeAttribute("data-" + NS + "-is");
4161        }
4162
4163        this._cacheElements(config.element);
4164        this._setupProperties(config.options);
4165
4166        this._elements.input.addEventListener("invalid", this._onInvalid.bind(this));
4167        this._elements.input.addEventListener("input", this._onInput.bind(this));
4168        if (displayValidationMessage) {
4169            this._elements.input.checkValidity();
4170        }
4171    }
4172
4173    FormText.prototype._onInvalid = function(event) {
4174        event.target.setCustomValidity("");
4175        if (event.target.validity.typeMismatch) {
4176            if (this._properties.constraintMessage) {
4177                event.target.setCustomValidity(this._properties.constraintMessage);
4178            }
4179        } else if (event.target.validity.valueMissing) {
4180            if (this._properties.requiredMessage) {
4181                event.target.setCustomValidity(this._properties.requiredMessage);
4182            }
4183        }
4184        if (displayValidationMessage) {
4185            var validationMessage = event.target.parentElement.querySelector(".cmp-form-text__validation-message");
4186            if (validationMessage) {
4187                validationMessage.innerText = event.target.validationMessage;
4188            }
4189        }
4190    };
4191
4192    FormText.prototype._onInput = function(event) {
4193        event.target.setCustomValidity("");
4194        if (displayValidationMessage) {
4195            event.target.checkValidity();
4196        }
4197    };
4198
4199    FormText.prototype._cacheElements = function(wrapper) {
4200        this._elements = {};
4201        this._elements.self = wrapper;
4202        var hooks = this._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS_DASH + "]");
4203        for (var i = 0; i < hooks.length; i++) {
4204            var hook = hooks[i];
4205            var capitalized = IS;
4206            capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
4207            var key = hook.dataset[NS + "Hook" + capitalized];
4208            this._elements[key] = hook;
4209        }
4210    };
4211
4212    FormText.prototype._setupProperties = function(options) {
4213        this._properties = {};
4214
4215        for (var key in properties) {
4216            if (Object.prototype.hasOwnProperty.call(properties, key)) {
4217                var property = properties[key];
4218                if (options && options[key] != null) {
4219                    if (property && typeof property.transform === "function") {
4220                        this._properties[key] = property.transform(options[key]);
4221                    } else {
4222                        this._properties[key] = options[key];
4223                    }
4224                } else {
4225                    this._properties[key] = properties[key]["default"];
4226                }
4227            }
4228        }
4229    };
4230
4231    function onDocumentReady() {
4232        var validationMessages = document.querySelectorAll(selectors.validationMessage);
4233        if (validationMessages && validationMessages.length > 0) {
4234            displayValidationMessage = true;
4235        }
4236
4237        var elements = document.querySelectorAll(selectors.self);
4238        for (var i = 0; i < elements.length; i++) {
4239            new FormText({ element: elements[i], options: readData(elements[i]) });
4240        }
4241
4242        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
4243        var body = document.querySelector("body");
4244        var observer = new MutationObserver(function(mutations) {
4245            mutations.forEach(function(mutation) {
4246                // needed for IE
4247                var nodesArray = [].slice.call(mutation.addedNodes);
4248                if (nodesArray.length > 0) {
4249                    nodesArray.forEach(function(addedNode) {
4250                        if (addedNode.querySelectorAll) {
4251                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
4252                            elementsArray.forEach(function(element) {
4253                                new FormText({ element: element, options: readData(element) });
4254                            });
4255                        }
4256                    });
4257                }
4258            });
4259        });
4260
4261        observer.observe(body, {
4262            subtree: true,
4263            childList: true,
4264            characterData: true
4265        });
4266    }
4267
4268    if (document.readyState !== "loading") {
4269        onDocumentReady();
4270    } else {
4271        document.addEventListener("DOMContentLoaded", onDocumentReady);
4272    }
4273
4274})();
4275
4276/*******************************************************************************
4277 * Copyright 2020 Adobe
4278 *
4279 * Licensed under the Apache License, Version 2.0 (the "License");
4280 * you may not use this file except in compliance with the License.
4281 * You may obtain a copy of the License at
4282 *
4283 *     http://www.apache.org/licenses/LICENSE-2.0
4284 *
4285 * Unless required by applicable law or agreed to in writing, software
4286 * distributed under the License is distributed on an "AS IS" BASIS,
4287 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4288 * See the License for the specific language governing permissions and
4289 * limitations under the License.
4290 ******************************************************************************/
4291(function() {
4292    "use strict";
4293
4294    var NS = "cmp";
4295    var IS = "pdfviewer";
4296    var SDK_URL = "https://acrobatservices.adobe.com/view-sdk/viewer.js";
4297    var SDK_READY_EVENT = "adobe_dc_view_sdk.ready";
4298
4299    var selectors = {
4300        self: "[data-" + NS + '-is="' + IS + '"]',
4301        sdkScript: 'script[src="' + SDK_URL + '"]'
4302    };
4303
4304    function initSDK() {
4305        var sdkIncluded = document.querySelectorAll(selectors.sdkScript).length > 0;
4306        if (!window.adobe_dc_view_sdk && !sdkIncluded) {
4307            var dcv = document.createElement("script");
4308            dcv.type = "text/javascript";
4309            dcv.src = SDK_URL;
4310            document.body.appendChild(dcv);
4311        }
4312    }
4313
4314    function previewPdf(component) {
4315        // prevents multiple initialization
4316        component.removeAttribute("data-" + NS + "-is");
4317
4318        // add the view sdk to the page
4319        initSDK();
4320
4321        // manage the preview
4322        if (component.dataset && component.id) {
4323            if (window.AdobeDC && window.AdobeDC.View) {
4324                dcView(component);
4325            } else {
4326                document.addEventListener(SDK_READY_EVENT, function() {
4327                    dcView(component);
4328                });
4329            }
4330        }
4331    }
4332
4333    function dcView(component) {
4334        var adobeDCView = new window.AdobeDC.View({
4335            clientId: component.dataset.cmpClientId,
4336            divId: component.id + "-content",
4337            reportSuiteId: component.dataset.cmpReportSuiteId
4338        });
4339        adobeDCView.previewFile({
4340            content: { location: { url: component.dataset.cmpDocumentPath } },
4341            metaData: { fileName: component.dataset.cmpDocumentFileName }
4342        }, JSON.parse(component.dataset.cmpViewerConfigJson));
4343    }
4344
4345    /**
4346     * Document ready handler and DOM mutation observers. Initializes Accordion components as necessary.
4347     *
4348     * @private
4349     */
4350    function onDocumentReady() {
4351        var elements = document.querySelectorAll(selectors.self);
4352        for (var i = 0; i < elements.length; i++) {
4353            previewPdf(elements[i]);
4354        }
4355
4356        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
4357        var body = document.querySelector("body");
4358        var observer = new MutationObserver(function(mutations) {
4359            mutations.forEach(function(mutation) {
4360                // needed for IE
4361                var nodesArray = [].slice.call(mutation.addedNodes);
4362                if (nodesArray.length > 0) {
4363                    nodesArray.forEach(function(addedNode) {
4364                        if (addedNode.querySelectorAll) {
4365                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
4366                            elementsArray.forEach(function(element) {
4367                                previewPdf(element);
4368                            });
4369                        }
4370                    });
4371                }
4372            });
4373        });
4374
4375        observer.observe(body, {
4376            subtree: true,
4377            childList: true,
4378            characterData: true
4379        });
4380
4381    }
4382
4383    if (document.readyState !== "loading") {
4384        onDocumentReady();
4385    } else {
4386        document.addEventListener("DOMContentLoaded", onDocumentReady);
4387    }
4388}());
4389
4390/*******************************************************************************
4391 * Copyright 2022 Adobe
4392 *
4393 * Licensed under the Apache License, Version 2.0 (the "License");
4394 * you may not use this file except in compliance with the License.
4395 * You may obtain a copy of the License at
4396 *
4397 *     http://www.apache.org/licenses/LICENSE-2.0
4398 *
4399 * Unless required by applicable law or agreed to in writing, software
4400 * distributed under the License is distributed on an "AS IS" BASIS,
4401 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4402 * See the License for the specific language governing permissions and
4403 * limitations under the License.
4404 ******************************************************************************/
4405(function() {
4406    "use strict";
4407
4408    var dataLayerEnabled;
4409    var dataLayer;
4410    var dataLayerName;
4411
4412    /**
4413     * Adds Click Event Listener to the main <div> of the Text Components
4414     */
4415    function addClickEventListenerToTextComponents() {
4416        var componentMainDivs = document.getElementsByClassName("cmp-text");
4417
4418        for (var i = 0; i < componentMainDivs.length; i++) {
4419            componentMainDivs[i].addEventListener("click", addClickedLinkToDataLayer);
4420        }
4421    }
4422
4423    /**
4424     * Adds clicked link contained by the Text Component to Data Layer
4425     *
4426     * @private
4427     * @param {Object} event The Click event
4428     */
4429    function addClickedLinkToDataLayer(event) {
4430        var element = event.currentTarget;
4431        var componentId = getDataLayerId(element);
4432
4433        if (event.target.tagName === "A") {
4434            dataLayer.push({
4435                event: "cmp:click",
4436                eventInfo: {
4437                    path: "component." + componentId,
4438                    link: event.target.getAttribute("href")
4439                }
4440            });
4441        }
4442    }
4443
4444    /**
4445     * Parses the dataLayer string and returns the ID
4446     *
4447     * @private
4448     * @param {HTMLElement} item, the Text item
4449     * @returns {String} dataLayerId or undefined
4450     */
4451    function getDataLayerId(item) {
4452        if (item) {
4453            if (item.dataset.cmpDataLayer) {
4454                return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0];
4455            } else {
4456                return item.id;
4457            }
4458        }
4459        return null;
4460    }
4461
4462    function onDocumentReady() {
4463        dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled");
4464        if (dataLayerEnabled) {
4465            dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer";
4466            dataLayer = window[dataLayerName] = window[dataLayerName] || [];
4467
4468            addClickEventListenerToTextComponents();
4469        }
4470    }
4471
4472    if (document.readyState !== "loading") {
4473        onDocumentReady();
4474    } else {
4475        document.addEventListener("DOMContentLoaded", onDocumentReady);
4476    }
4477})();
4478
4479/*******************************************************************************
4480 * Copyright 2022 Adobe
4481 *
4482 * Licensed under the Apache License, Version 2.0 (the "License");
4483 * you may not use this file except in compliance with the License.
4484 * You may obtain a copy of the License at
4485 *
4486 *     http://www.apache.org/licenses/LICENSE-2.0
4487 *
4488 * Unless required by applicable law or agreed to in writing, software
4489 * distributed under the License is distributed on an "AS IS" BASIS,
4490 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4491 * See the License for the specific language governing permissions and
4492 * limitations under the License.
4493 ******************************************************************************/
4494(function() {
4495    "use strict";
4496
4497    var linkAccessibilityClass = "cmp-link__screen-reader-only";
4498    var selectors = {
4499        linkAccessibility: "." + linkAccessibilityClass,
4500        linkAccessibilityEnabled: "[data-cmp-link-accessibility-enabled]",
4501        linkAccessibilityText: "[data-cmp-link-accessibility-text]"
4502    };
4503
4504    function getLinkAccessibilityText() {
4505        var linkAccessibilityEnabled = document.querySelectorAll(selectors.linkAccessibilityEnabled);
4506        if (!linkAccessibilityEnabled[0]) {
4507            return;
4508        }
4509        var linkAccessibilityTextElements = document.querySelectorAll(selectors.linkAccessibilityText);
4510        if (!linkAccessibilityTextElements[0]) {
4511            return;
4512        }
4513        return linkAccessibilityTextElements[0].dataset.cmpLinkAccessibilityText;
4514    }
4515
4516    function onDocumentReady() {
4517        var linkAccessibilityText = getLinkAccessibilityText();
4518        if (linkAccessibilityText) {
4519            document.querySelectorAll("a[target='_blank']").forEach(function(link) {
4520                if (!link.querySelector(selectors.linkAccessibility)) {
4521                    var linkAccessibilityElement = document.createElement("span");
4522                    linkAccessibilityElement.classList.add(linkAccessibilityClass);
4523                    linkAccessibilityElement.innerText = linkAccessibilityText;
4524                    link.insertAdjacentElement("beforeend", linkAccessibilityElement);
4525                }
4526            });
4527        }
4528    }
4529
4530    if (document.readyState !== "loading") {
4531        onDocumentReady();
4532    } else {
4533        document.addEventListener("DOMContentLoaded", onDocumentReady);
4534    }
4535
4536}());
4537

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.