PageSourceSearch

https://www.travelandleisureco.com/etc.clientlibs/basecamp-app/com…-af4a3fbee5f84394fba8df3c01538039-lc.min.js

js travelandleisureco.com collected 2026-09-24 10:22:30 UTC 9,799 bytes, 266 lines download raw bytes

1(function() {
2    "use strict";
3
4    const containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined;
5    if (!containerUtils) {
6        // eslint-disable-next-line no-console
7        console.warn("Carousel: 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.");
8    }
9
10    let dataLayerEnabled;
11    let dataLayer;
12    let dataLayerName;
13
14    const NS = "cmp";
15    const IS = "carousel";
16
17    const selectors = {
18        self: "[data-" + NS + '-is="' + IS + '"]',
19    };
20
21    /**
22     * Carousel Configuration
23     *
24     * @typedef {Object} CarouselConfig Represents a Carousel configuration
25     * @property {HTMLElement} element The HTMLElement representing the Carousel
26     * @property {*[]} options The Carousel options
27     */
28
29    /**
30     * Carousel
31     *
32     * @class Carousel
33     * @classdesc An interactive Carousel component for navigating a list of generic items
34     * @param {CarouselConfig} config The Carousel configuration
35     */
36    function Carousel(config) {
37        const that = this;
38
39        if (config && config.element) {
40            init(config);
41        }
42
43        /**
44         * Initializes the Carousel
45         *
46         * @private
47         * @param {CarouselConfig} config The Carousel configuration
48         */
49        function init(config) {
50            that._config = config;
51
52            // prevents multiple initialization
53            config.element.removeAttribute("data-" + NS + "-is");
54
55            cacheElements(config.element);
56
57            that._active = 0;
58            that._paused = false;
59
60            // TODO: This section is only relevant in edit mode and should move to the editor clientLib
61            if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) {
62                /*
63                 * Editor message handling:
64                 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
65                 * - check that the message data panel container type is correct and that the id (path) matches this specific Carousel component
66                 * - if so, route the "navigate" operation to enact a navigation of the Carousel based on index data
67                 */
68                window.CQ = window.CQ || {};
69                window.CQ.CoreComponents = window.CQ.CoreComponents || {};
70                window.CQ.CoreComponents.MESSAGE_CHANNEL = window.CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window);
71                window.CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) {
72                    if (
73                        message?.data.type === "cmp-carousel" 
74                        && message?.data.id === that._elements.self.dataset["cmpPanelcontainerId"] 
75                        && message?.data.operation === "navigate"
76                    ) navigate(message.data.index);
77                });
78            }
79        }
80
81        /**
82         * Caches the Carousel elements as defined via the {@code data-carousel-hook="ELEMENT_NAME"} markup API
83         *
84         * @private
85         * @param {HTMLElement} wrapper The Carousel wrapper element
86         */
87        function cacheElements(wrapper) {
88            that._elements = {};
89            that._elements.self = wrapper;
90            const hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
91
92            for (const hook of hooks) {
93                const capitalized = IS.charAt(0).toUpperCase() + IS.slice(1);
94                const key = hook.dataset[NS + "Hook" + capitalized];
95
96                if (that._elements[key]) {
97
98                    if (!Array.isArray(that._elements[key])) {
99                        const tmp = that._elements[key];
100                        that._elements[key] = [tmp];
101                    }
102                    that._elements[key].push(hook);
103                } else that._elements[key] = hook;
104            }
105        }
106
107        /**
108     * Refreshes the item markup based on the current {@code Carousel#_active} index
109     *
110     * @private
111     */
112    function refreshActive() {
113        const items = that._elements["item"];
114
115
116        if (Array.isArray(items)) {
117            const activeIndex = parseInt(that._active);
118
119            for (let i = 0; i < items.length; i++) {
120
121                if (i === activeIndex) {
122                    items[i].classList.add("cmp-carousel__item--active");
123                    items[i].removeAttribute("aria-hidden");
124                    document.querySelector("zin-carousel").goto(that._active);
125                } else {
126                    items[i].classList.remove("cmp-carousel__item--active");
127                    items[i].setAttribute("aria-hidden", true);
128                }
129            }
130        }
131    }
132    
133    /**
134     * Navigates to the item at the provided index
135     *
136     * @private
137     * @param {Number} index The index of the item to navigate to
138     * @param {Boolean} keepHash true to keep the hash in the URL, false to update it
139     */
140    function navigate(index, keepHash) {
141        if (index < 0 || index > (that._elements["item"].length - 1)) return;
142
143        that._active = index;
144        refreshActive();
145
146        if (!keepHash && containerUtils) containerUtils.updateUrlHash(that, "item", index);
147
148        if (dataLayerEnabled) {
149            const carouselId = that._elements.self.id;
150            const activeItem = getDataLayerId(that._elements.item[index]);
151            const updatePayload = { component: {} };
152            updatePayload.component[carouselId] = { shownItems: [activeItem] };
153
154            const removePayload = { component: {} };
155            removePayload.component[carouselId] = { shownItems: undefined };
156
157            dataLayer.push(removePayload);
158            dataLayer.push(updatePayload);
159        }
160
161    }
162        
163    }
164
165    /**
166   * Reads options data from the Tabs wrapper element, defined via {@code data-cmp-*} data attributes
167   *
168   * @private
169   * @param {HTMLElement} element The Tabs element to read options data from
170   * @returns {Object} The options read from the component data attributes
171   */
172    function readData(element) {
173        const data = element.dataset;
174        const options = [];
175        let capitalized = IS;
176        capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
177        const reserved = ["is", "hook" + capitalized];
178
179        for (let key in data) {
180            if (Object.prototype.hasOwnProperty.call(data, key)) {
181                const value = data[key];
182
183                if (key.indexOf(NS) === 0) {
184                    key = key.slice(NS.length);
185                    key = key.charAt(0).toLowerCase() + key.substring(1);
186
187                    if (reserved.indexOf(key) === -1) {
188                        options[key] = value;
189                    }
190                }
191            }
192        }
193        return options;
194    }
195
196    /**
197     * Parses the dataLayer string and returns the ID
198     *
199     * @private
200     * @param {HTMLElement} item the accordion item
201     * @returns {String} dataLayerId or undefined
202     */
203    function getDataLayerId(item) {
204        let id = null;
205
206        if (item) {
207            if (item.dataset.cmpDataLayer) id = Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0];
208            else id = item.id;
209        }
210        return id;
211    }
212    
213    /**
214     * Document ready handler and DOM mutation observers. Initializes Carousel components as necessary.
215     *
216     * @private
217     */
218    function onDocumentReady() {
219        dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled");
220        if (dataLayerEnabled) {
221            dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer";
222            dataLayer = window[dataLayerName] = window[dataLayerName] || [];
223        }
224
225        const elements = document.querySelectorAll(selectors.self);
226        for (const element of elements) {
227            new Carousel({ element: element, options: readData(element) });
228        }
229
230        const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
231        const body = document.querySelector("body");
232        const observer = new MutationObserver(function(mutations) {
233            mutations.forEach(function(mutation) {
234                // needed for IE
235                const nodesArray = [].slice.call(mutation.addedNodes);
236                if (nodesArray.length > 0) {
237                    nodesArray.forEach(function(addedNode) {
238                        if (addedNode.querySelectorAll) {
239                            const elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
240                            elementsArray.forEach(function(element) {
241                                new Carousel({ element: element, options: readData(element) });
242                            });
243                        }
244                    });
245                }
246            });
247        });
248
249        observer.observe(body, {
250            subtree: true,
251            childList: true,
252            characterData: true
253        });
254    }
255
256    const documentReady = document.readyState !== "loading" ? Promise.resolve() : new Promise(function(resolve) {
257        document.addEventListener("DOMContentLoaded", resolve);
258    });
259    Promise.all([documentReady]).then(onDocumentReady);
260
261    if (containerUtils) {
262        window.addEventListener("load", containerUtils.scrollToAnchor, false);
263    }
264
265    
266})();

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.