PageSourceSearch

https://www.superdry.fr/on/demandware.static/Sites-sd-europe-Site/-/fr_FR/v1790402188748/js/carouselEvents.js

js superdry.fr collected 2026-09-26 06:13:13 UTC 20,439 bytes, 646 lines download raw bytes

1/******/ (function() { // webpackBootstrap
2/******/ 	"use strict";
3/******/ 	var __webpack_modules__ = ({
4
5/***/ "./cartridges/app_superdry/cartridge/client/default/js/components/carouselEvents.js":
6/*!******************************************************************************************!*\
7  !*** ./cartridges/app_superdry/cartridge/client/default/js/components/carouselEvents.js ***!
8  \******************************************************************************************/
9/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
10
11
12
13const gtmHelpers = __webpack_require__(/*! ../helpers/gtmHelpers */ "./cartridges/app_superdry/cartridge/client/default/js/helpers/gtmHelpers.js");
14/**
15 * Events of the component
16 **/
17const bindEvents = () => {
18    const parentElements = document.querySelectorAll(".product-tile-carousel-wrapper");
19    const initializedCarousels = document.querySelectorAll(".product-tile-carousel-wrapper .slick-slider:not(.einstein-carousel)");
20
21    parentElements.forEach(parentElement => {
22        parentElement.addEventListener("click", (event) => {
23            if (event.target.closest(".product-tile-pd")) {
24                gtmHelpers.selectItemEvent(event.target.closest(".product-tile-pd"));
25
26                if ($(".pdp-container").length) {
27                    const recommenderType = event.target.closest(".product-tile-carousel-wrapper").dataset.recommenderType;
28                    gtmHelpers.recommendationClickEvent(recommenderType, event.target.closest(".product-tile-pd"));
29                }
30            }
31        });
32    });
33
34    const observer = new IntersectionObserver((entries) => {
35        entries.forEach((entry) => {
36            if (entry.isIntersecting) {
37                gtmHelpers.viewItemListEvent(undefined, entry.target);
38                gtmHelpers.promotionEvents("view_promotion", entry.target.parentElement);
39                observer.unobserve(entry.target);
40            }
41        });
42    });
43
44    initializedCarousels.forEach((carousel) => {
45        observer.observe(carousel);
46    });
47};
48
49module.exports = {
50    bindEvents
51};
52
53
54/***/ }),
55
56/***/ "./cartridges/app_superdry/cartridge/client/default/js/helpers/gtmHelpers.js":
57/*!***********************************************************************************!*\
58  !*** ./cartridges/app_superdry/cartridge/client/default/js/helpers/gtmHelpers.js ***!
59  \***********************************************************************************/
60/***/ (function(module) {
61
62
63
64/**
65 * Sends a page view event to Google Tag Manager
66 * @param {string} pageType - the type of the page being viewed
67 * @returns {void}
68 */
69const pageViewEvent = (pageType) => {
70    const event = new CustomEvent("pageViewPushed");
71    const pageData = document.querySelector(".gtm-page-view-data");
72    const userData = document.querySelector(".gtm-user-data");
73
74    if (!pageData || !userData) {
75        return;
76    }
77
78    const pageDataObject = safeParseJSON(pageData.getAttribute("data-gtm"));
79    const userDataObject = safeParseJSON(userData.getAttribute("data-gtm"));
80
81    if (!pageDataObject || !userDataObject) {
82        return;
83    }
84
85    const object = {
86        event: "page_view",
87        page_type: pageType,
88        ...pageDataObject,
89        ...userDataObject
90    };
91
92    window.dataLayer = window.dataLayer || [];
93    window.dataLayer.push(object);
94
95    document.dispatchEvent(event);
96};
97
98/**
99* Sends product data to the data layer for Google Tag Manager events. Used for add_to_cart and remove_from_cart events
100* @param {string} productData - JSON string representing product data
101* @returns {void}
102*/
103const cartEvents = (productData) => {
104    if (!productData) {
105        return;
106    }
107
108    const productDataObject = safeParseJSON(productData);
109
110    if (!productDataObject) {
111        return;
112    }
113
114    window.dataLayer = window.dataLayer || [];
115    window.dataLayer.push({"ecommerce": null});
116    window.dataLayer.push(productDataObject);
117};
118
119/**
120* Represents the view cart event and pushes the view cart object to the data layer
121*/
122const viewCartEvent = () => {
123    const cartPageWrapper = document.querySelector(".cart-page");
124
125    if (!cartPageWrapper) {
126        return;
127    }
128
129    let viewCartObject = safeParseJSON(cartPageWrapper.getAttribute("data-gtm"));
130
131    if (!viewCartObject) {
132        return;
133    }
134
135    updateItemIndexes(viewCartObject.ecommerce.items);
136
137    window.dataLayer = window.dataLayer || [];
138    window.dataLayer.push({"ecommerce": null});
139    window.dataLayer.push(viewCartObject);
140};
141
142/**
143* Handles the view item event for Google Tag Manager
144*/
145const viewItemEvent = () => {
146    const pdpWrapper = document.querySelector(".product-detail");
147    const viewItemObject = safeParseJSON(pdpWrapper.getAttribute("data-gtm"));
148
149    if (!viewItemObject) {
150        return;
151    }
152
153    window.dataLayer = window.dataLayer || [];
154    window.dataLayer.push({"ecommerce": null});
155    window.dataLayer.push(viewItemObject);
156};
157
158/**
159* Handles the select item event for Google Tag Manager
160*/
161const selectItemEvent = (wrapper) => {
162    if (!wrapper) {
163        return;
164    }
165
166    const selectItemObject = safeParseJSON(wrapper.getAttribute("data-gtm"));
167
168    if (!selectItemObject) {
169        return;
170    }
171
172    let eventLocation = "Cart Page";
173    if (document.querySelector(".storepage")?.id === "homepage") {
174        eventLocation = "Homepage";
175    }
176
177    if (document.querySelector(".search-result-count-wrapper")) {
178        eventLocation = "Search Results";
179    }
180
181    if (document.querySelector(".pdp-container")) {
182        eventLocation = "PDP";
183    }
184
185    if (wrapper.parentNode.classList.contains("item")) {
186        eventLocation = "Search Suggestions";
187    }
188
189    if (document.querySelector(".plp-title")) {
190        eventLocation = "PLP";
191    }
192
193    let objectValue;
194    selectItemObject.ecommerce.items.forEach((item) => {
195        objectValue = item.price;
196        item.item_list_name = eventLocation;
197    });
198
199    selectItemObject.event = "select_item";
200    selectItemObject.ecommerce.value = objectValue;
201
202    window.dataLayer = window.dataLayer || [];
203    window.dataLayer.push({"ecommerce": null});
204    window.dataLayer.push(selectItemObject);
205};
206
207const recommendationClickEvent = (title, element) => {
208    if (!element) {
209        return;
210    }
211
212    window.dataLayer = window.dataLayer || [];
213    window.dataLayer.push({
214        "event": "pdp_recommendation_click",
215        "reco_type": title || "",
216        "reco_product_id": element.getAttribute("data-gtm-product-id"),
217        "reco_product_name": element.getAttribute("data-gtm-product-name"),
218    });
219};
220
221/**
222 * Safely parses a JSON string and returns the parsed JSON object or null if parsing fails
223 * @param {string} str - The JSON string to be parsed
224 * @returns {Object | null} The parsed JSON object or null if parsing fails
225 */
226const safeParseJSON = (str) => {
227    try {
228        return JSON.parse(str);
229    } catch (error) {
230        return null;
231    }
232};
233
234/**
235* Handles the order confirmation event for Google Tag Manager
236* @param {HTMLElement} wrapper - the HTML element containing the data for the event
237* @returns {void}
238*/
239const purchaseEvent = (orderId) => {
240    const orderConfirmationWrapper = document.querySelector(".order-confirmation-wrapper");
241    const orderConfirmationObject = safeParseJSON(orderConfirmationWrapper.getAttribute("data-gtm"));
242
243    if (!orderConfirmationObject) {
244        return;
245    }
246
247    const purchesEventFromDataLayer = window.dataLayer.find(event => event.event === "purchase");
248
249    if (purchesEventFromDataLayer?.ecommerce?.transaction_id === orderId) {
250        return false;
251
252    } else {
253        updateItemIndexes(orderConfirmationObject.ecommerce.items);
254
255        window.dataLayer = window.dataLayer || [];
256        window.dataLayer.push({"ecommerce": null});
257        window.dataLayer.push(orderConfirmationObject);
258    }
259};
260
261/**
262* Parses and pushes the page data object to the data layer
263* @param {string} data - the page data to be parsed and pushed
264* @returns {void}
265*/
266const checkoutEvents = (data) => {
267    if (!data) {
268        return;
269    }
270
271    const checkoutDataObject = safeParseJSON(data) ? safeParseJSON(data) : data;
272
273    updateItemIndexes(checkoutDataObject.ecommerce.items);
274
275    window.dataLayer = window.dataLayer || [];
276    window.dataLayer.push({"ecommerce": null});
277    window.dataLayer.push(checkoutDataObject);
278};
279
280/**
281 * Sorts the interaction event and pushes the data to the data layer
282 * @returns {void}
283 */
284const sortInteractionEvent = () => {
285    const gridWrapper = document.querySelector(".product-grid");
286    const sortInteractionObject = safeParseJSON(gridWrapper.getAttribute("data-gtm"));
287
288    if (!sortInteractionObject) {
289        return;
290    }
291
292    window.dataLayer = window.dataLayer || [];
293    window.dataLayer.push(sortInteractionObject);
294};
295
296/**
297* Updates the indexes of items in the given array
298* @param {Array} items - the array of items to be updated
299* @returns {void}
300*/
301const updateItemIndexes = (items) => {
302    items.forEach((item, idx) => {
303        item.index = idx;
304    });
305};
306
307/**
308* Handles the search event and pushes the search term to the data layer
309* @returns {void}
310*/
311const searchEvent = () => {
312    const searchInput = document.querySelector(".search-input").value;
313
314    const searchObject = {
315        "event": "user_search",
316        "search_term": searchInput
317    };
318
319    window.dataLayer = window.dataLayer || [];
320    window.dataLayer.push(searchObject);
321};
322
323/**
324 * Authenticates customer events and pushes data to the data layer
325 * @param {string} data - the customer data to be authenticated
326 * @param {string} loginType - the type of login (e.g. social, email)
327 * @param {string} isLogin - type of action (login, create)
328 * @returns {void}
329 */
330const authenticateCustomerEvents = (data, loginType, label, isLogin) => {
331    if (!data) {
332        return;
333    }
334
335    const userDataObject = safeParseJSON(data);
336
337    if (!userDataObject) {
338        return;
339    }
340
341    const object = {
342        event: label,
343        [isLogin ? "login_type" : "create_type"]: loginType,
344        ...userDataObject
345    };
346
347    window.dataLayer = window.dataLayer || [];
348    window.dataLayer.push(object);
349};
350
351/**
352 * Handles form submit events and pushes data to the data layer
353 * @param {string} formClass - the class name of the form
354 * @param {string} email - submited email address
355 * @returns {void}
356 */
357const formSubmitEvents = (formName, email) => {
358    if (!formName) {
359        return;
360    }
361
362    const object = {
363        event: "form_submit",
364        form_type: formName
365    };
366
367    if (email) {
368        object.user = {
369            user_em: email
370        };
371    }
372
373    window.dataLayer = window.dataLayer || [];
374    window.dataLayer.push({"ecommerce": null});
375    window.dataLayer.push(object);
376};
377
378/**
379 * Logs a featured tile click event to the data layer
380 * @param {string} tileName - the name of the featured tile being clicked
381 * @returns {void}
382 */
383const featuredTileClick = (tileName) => {
384    const dataLayerObject = {
385        "event": "featured_tile_click",
386        "featured_tile_name": tileName || ""
387    };
388
389    window.dataLayer = window.dataLayer || [];
390    window.dataLayer.push(dataLayerObject);
391};
392
393/**
394 * Initializes and triggers an IntersectionObserver to observe elements with the class "last-tracked".
395 * When an observed element intersects with the viewport, it triggers the `viewItemListEvent` function
396 * and then stops observing that element.
397 */
398function triggerItemListObserver(pageType) {
399    const observer = new IntersectionObserver((entries) => {
400        entries.forEach((entry) => {
401            if (entry.isIntersecting) {
402                viewItemListEvent(pageType);
403                observer.unobserve(entry.target);
404            }
405        });
406    });
407    const lastTrackedElements = document.querySelectorAll(".last-tracked");
408    const lastTrackedElement = lastTrackedElements[lastTrackedElements.length - 1];
409    observer.observe(lastTrackedElement);
410}
411
412/**
413 * Tracks the view item list event for Google Tag Manager
414 * @param {string} pageType - the type of page where the event is triggered
415 * @param {HTMLElement} targetCarousel - the target carousel element
416 */
417const viewItemListEvent = (pageType, targetCarousel) => {
418    const productGrids = targetCarousel ? targetCarousel : document.querySelectorAll(".product-grid");
419    const gridWrapper = productGrids.length > 1 ? productGrids[productGrids.length - 1] : productGrids[0];
420    const lastTrackedElements = gridWrapper ? gridWrapper.querySelectorAll(".last-tracked") : false;
421    const lastTrackedElement = lastTrackedElements ? lastTrackedElements[lastTrackedElements.length - 1] : false;
422    const indexToSlice = lastTrackedElement ? Array.from(gridWrapper.querySelectorAll(".product-tile")).indexOf(lastTrackedElement) + 1 : 0;
423    const isOutOfBounds = indexToSlice ? indexToSlice >= gridWrapper.querySelectorAll(".product-tile").length : false;
424
425    if (isOutOfBounds) {
426        return;
427    }
428
429    const tiles = targetCarousel ?
430        targetCarousel.querySelectorAll(".product-tile-pd") :
431        Array.from(gridWrapper.querySelectorAll(".product-tile")).slice(indexToSlice, indexToSlice + 10);
432    const eventLocation = pageType ? pageType : document.querySelector(".storepage")?.id === "homepage" ? "Homepage" : document.querySelector(".no-results-wrapper") ? "Search Results" : document.querySelector(".pdp-container") ? "PDP" : "Cart Page";
433
434    if (eventLocation === "Cart Page") {
435        return;
436    }
437
438    let currency = "";
439    const dataLayerObject = {
440        "event": "view_item_list",
441        "ecommerce": {
442            "currency": "",
443            "items": []
444        }
445    };
446
447    tiles.forEach((tile, index) => {
448        const viewItemObject = safeParseJSON(tile.getAttribute("data-gtm"));
449        viewItemObject.ecommerce.items[0].item_list_name = eventLocation;
450        dataLayerObject.ecommerce.items.push(viewItemObject.ecommerce.items[0]);
451        currency = viewItemObject.ecommerce.currency;
452        if (!targetCarousel && index === tiles.length - 1) {
453            tile.classList.add("last-tracked");
454            triggerItemListObserver(pageType);
455        }
456    });
457
458    dataLayerObject.ecommerce.currency = currency;
459    updateItemIndexes(dataLayerObject.ecommerce.items);
460
461    window.dataLayer = window.dataLayer || [];
462    window.dataLayer.push({"ecommerce": null});
463    window.dataLayer.push(dataLayerObject);
464
465    $("body").trigger("viewItemListEventComplete");
466};
467
468/**
469* View promotion event for Google Tag Manager
470* @param {HTMLElement} component - the component to trigger the view promotion event
471* @returns {void}
472*/
473const promotionEvents = (type, component) => {
474    if (!component) {
475        return;
476    }
477
478    const isPromotion = component.getAttribute("data-ispromotion");
479
480    if (isPromotion === "false") {
481        return;
482    }
483
484    const creative_name = component.getAttribute("data-creative-name");
485    const creative_slot = component.getAttribute("data-creative-slot");
486    const promotion_id = component.getAttribute("data-promotion-id");
487    const promotion_name = component.getAttribute("data-promotion-name");
488
489    const dataLayerObject = {
490        "event": type,
491        "ecommerce": {
492            "creative_name": creative_name || "",
493            "creative_slot": creative_slot || "",
494            "promotion_id": promotion_id || "",
495            "promotion_name": promotion_name || "",
496            "items": []
497        }
498    };
499
500    if (component.classList.contains("product-tile-carousel-wrapper")) {
501        const eventLocation = document.querySelector(".storepage")?.id === "homepage" ? "Homepage" : document.querySelector(".no-results-wrapper") ? "Search Results" : document.querySelector(".pdp-container") ? "PDP" : "Cart Page";
502        const productTiles = component.querySelectorAll(".product-tile-pd");
503
504        productTiles.forEach((tile) => {
505            const viewItemObject = safeParseJSON(tile.getAttribute("data-gtm"));
506            viewItemObject.ecommerce.items[0].item_list_name = eventLocation;
507            dataLayerObject.ecommerce.items.push(viewItemObject.ecommerce.items[0]);
508        });
509    }
510
511    window.dataLayer = window.dataLayer || [];
512    window.dataLayer.push({"ecommerce": null});
513    window.dataLayer.push(dataLayerObject);
514};
515
516/**
517 * Logs a filter interaction event to the data layer
518 * @param {string} filterName - the name of the filter being interacted with
519 * @param {string} filterValue - the value of the filter being interacted with
520 * @returns {void}
521 */
522const filterInteractionEvent = (filterName, filterValue) => {
523    window.dataLayer = window.dataLayer || [];
524    window.dataLayer.push({
525        "event": "filter_interaction",
526        "filter_name": filterName || "",
527        "filter_value": filterValue || ""
528    });
529};
530
531/**
532* Pushes wishlist view event data to the Google Tag Manager dataLayer.
533*
534* This function checks for the presence of a wishlist page wrapper element with the class
535* ".gtm-page-wish-list". If found, it retrieves and parses the GTM-related JSON data from its
536* "data-gtm" attribute. If the data is valid, it pushes a reset event and the wishlist event
537* object to the global dataLayer array for GTM tracking.
538*
539* @function
540* @returns {void}
541*/
542const wishlistViewEvent = () => {
543    const wishListPageWrapper = document.querySelector(".gtm-page-wish-list");
544
545    if (!wishListPageWrapper) {
546        return;
547    }
548
549    let viewWishListObject = safeParseJSON(wishListPageWrapper.getAttribute("data-gtm"));
550
551    if (!viewWishListObject) {
552        return;
553    }
554
555    window.dataLayer = window.dataLayer || [];
556    window.dataLayer.push({"ecommerce": null});
557    window.dataLayer.push(viewWishListObject);
558};
559
560module.exports  = {
561    pageViewEvent,
562    cartEvents,
563    checkoutEvents,
564    viewCartEvent,
565    viewItemEvent,
566    selectItemEvent,
567    purchaseEvent,
568    searchEvent,
569    authenticateCustomerEvents,
570    sortInteractionEvent,
571    viewItemListEvent,
572    promotionEvents,
573    featuredTileClick,
574    formSubmitEvents,
575    recommendationClickEvent,
576    filterInteractionEvent,
577    wishlistViewEvent
578};
579
580
581/***/ }),
582
583/***/ "./cartridges/app_superdry/cartridge/client/default/js/util.js":
584/*!*********************************************************************!*\
585  !*** ./cartridges/app_superdry/cartridge/client/default/js/util.js ***!
586  \*********************************************************************/
587/***/ (function(module) {
588
589
590
591module.exports = function (include) {
592    if (typeof include === "function") {
593        include();
594    } else if (typeof include === "object") {
595        Object.keys(include).forEach(function (key) {
596            if (typeof include[key] === "function") {
597                include[key]();
598            }
599        });
600    }
601};
602
603
604/***/ })
604
605
606/******/ 	});
607/************************************************************************/
608/******/ 	// The module cache
609/******/ 	var __webpack_module_cache__ = {};
610/******/ 	
611/******/ 	// The require function
612/******/ 	function __webpack_require__(moduleId) {
613/******/ 		// Check if module is in cache
614/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
615/******/ 		if (cachedModule !== undefined) {
616/******/ 			return cachedModule.exports;
617/******/ 		}
618/******/ 		// Create a new module (and put it into the cache)
619/******/ 		var module = __webpack_module_cache__[moduleId] = {
620/******/ 			// no module.id needed
621/******/ 			// no module.loaded needed
622/******/ 			exports: {}
623/******/ 		};
624/******/ 	
625/******/ 		// Execute the module function
626/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
627/******/ 	
628/******/ 		// Return the exports of the module
629/******/ 		return module.exports;
630/******/ 	}
631/******/ 	
632/************************************************************************/
633/*!*******************************************************************************!*\
634  !*** ./cartridges/app_superdry/cartridge/client/default/js/carouselEvents.js ***!
635  \*******************************************************************************/
636
637
638var processInclude = __webpack_require__(/*! ./util */ "./cartridges/app_superdry/cartridge/client/default/js/util.js");
639
640$(document).ready(function () {
641    processInclude(__webpack_require__(/*! ./components/carouselEvents */ "./cartridges/app_superdry/cartridge/client/default/js/components/carouselEvents.js"));
642});
643
644/******/ })()
645;
646//# sourceMappingURL=./carouselEvents.js.map

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.