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.