1// This file will be run in the footer on every page. 2// It should be used for content that relates 3// to your site as a whole, it should not be used for 4// plugin-specific js 5 6require(["jquery", "site_gtm", "plugins_common_custom_ui_watcher", "sv_load!plugins_dynamic_content", "sv_site", "domReady!"], function($, gtm, UIWatcher, dynamic, site) { 7 gtm.update(); 8 9 // SEM tracking 10 var uiEvents = new UIWatcher({}, $, document); 11 uiEvents.on("change-page", handlePageChange); 12 uiEvents.on("view-change", handleFilterChange); 13 uiEvents.on("sort-change", handleFilterChange); 14 uiEvents.on("value-change", handleFilterChange); 15 uiEvents.on("toggle-show-more", handleShowMoreToggle); 16 uiEvents.on("item-click", handleItemClick); 17 uiEvents.on("tripbuilder", handleTripbuilder); 18 uiEvents.on("qv-tripbuilder", handleTripbuilder); 19 uiEvents.on("quick-view", handleQuickview); 20 21 // tracking handlers 22 function handleTripbuilder(payload){ 23 var event = payload.eventContext, 24 widget = payload.widgetContext; 25 let ga4Data = { 26 eventName: event?.value === "Add" ? "add_to_favorites" : undefined, 27 itemType: widget?.name === "Coupons" ? 'offers' : widget?.name.toLowerCase() !== "quickview" ? widget?.name.toLowerCase() : event?.itemType, 28 itemName: event?.refTitle, 29 linkObject: event?.linkObject, 30 itemCategory: event?.crmc, 31 interactionSource: event?.interactionSource, 32 interactionText: event?.interactionText, 33 interactionUrl: event?.interactionUrl, 34 itemCity: event?.itemCity, 35 itemRegion: event?.itemRegion, 36 itemId: event?.itemId, 37 acctId: event?.acctId, 38 } 39 if (event?.crmsc) 40 ga4Data.itemSubcategory = event?.crmsc; 41 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 42 gtm.sendEvents({ tClient_ga4: ga4Data }); 43 } 44 45 function handleQuickview(payload){ 46 var event = payload.eventContext; 47 let ga4Data = { 48 eventName: event?.eventName, 49 itemType: event?.itemType, 50 itemName: event?.itemName ?? event?.refTitle, 51 linkObject: event?.linkObject, 52 itemCategory: event?.crmc, 53 interactionSource: event?.interactionSource, 54 interactionText: event?.interactionText, 55 interactionUrl: event?.interactionUrl, 56 itemCity: event?.itemCity, 57 itemRegion: event?.itemRegion, 58 itemId: event?.itemId, 59 acctId: event?.acctId, 60 referralType: event?.referralType, 61 } 62 if (event?.crmsc) 63 ga4Data.itemSubcategory = event?.crmsc; 64 if (event?.eventName === 'partner_referral') 65 ga4Data.value = 5; 66 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 67 gtm.sendEvents({ tClient_ga4: ga4Data }); 68 } 69 70 function handleShowMoreToggle(payload){ 71 var event = payload.eventContext; 72 let ga4Data = { 73 eventName: "filter", 74 filterType: `${event?.refTitle} | ${event?.displayText}`, 75 itemType: event?.itemType, 76 interactionSource: event?.interactionSource, 77 interactionText: event?.interactionText, 78 } 79 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 80 gtm.sendEvents({ tClient_ga4: ga4Data }); 81 } 82 83 function handlePageChange(payload){ 84 var event = payload.eventContext; 85 let ga4Data = { 86 eventName: "filter", 87 filterType: `${event?.refTitle} | ${event?.displayText}`, 88 itemType: event?.itemType, 89 interactionSource: event?.interactionSource, 90 interactionText: event?.interactionText, 91 } 92 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 93 gtm.sendEvents({ tClient_ga4: ga4Data }); 94 } 95 96 function handleItemClick(payload){ 97 var event = payload.eventContext; 98 if (event?.name === "Quickview") { 99 var ga4Data = { 100 eventName: "filter", 101 filterType: "Open Quickview", 102 itemType: event?.itemType, 103 itemName: event?.itemName ?? event?.refTitle, 104 interactionSource: event?.interactionSource, 105 interactionText: event?.interactionText, 106 itemCategory: event?.crmc, 107 itemCity: event?.itemCity, 108 itemRegion: event?.itemRegion, 109 itemId: event?.itemId, 110 acctId: event?.acctId, 111 } 112 if (event?.crmsc) 113 ga4Data.itemSubcategory = event?.crmsc; 114 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 115 gtm.sendEvents({tClient_ga4: ga4Data}); 116 } 117 else { 118 var ga4Data = { 119 eventName: event?.eventName, 120 itemType: event?.itemType, 121 itemName: event?.itemName ?? event?.refTitle, 122 linkObject: event?.linkObject, 123 itemCategory: event?.crmc, 124 interactionSource: event?.interactionSource, 125 interactionText: event?.interactionText, 126 interactionUrl: event?.interactionUrl, 127 itemCity: event?.itemCity, 128 itemRegion: event?.itemRegion, 129 itemId: event?.itemId, 130 acctId: event?.acctId, 131 referralType: event?.referralType, 132 } 133 if (event?.crmsc) 134 ga4Data.itemSubcategory = event?.crmsc; 135 if (event?.eventName === 'partner_referral') 136 ga4Data.value = 5; 137 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 138 gtm.sendEvents({tClient_ga4: ga4Data}); 139 } 140 } 141 142 function handleFilterChange (payload) { 143 var event = payload.eventContext; 144 let ga4Data = { 145 eventName: "filter", 146 filterType: `${event?.refTitle} | ${event?.displayText}`, 147 itemType: event?.itemType, 148 interactionSource: event?.interactionSource, 149 interactionText: event?.interactionText, 150 } 151 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 152 gtm.sendEvents({ tClient_ga4: ga4Data }); 153 } 154 // end SEM tracking 155 156 // Init quickview textboxes 157 if (site.siteConfig.custom[site.site].quickview.active) { 158 const textBoxes = document.querySelectorAll('[data-qv-enabled-textbox]'); 159 160 if (textBoxes.length) { 161 require(['plugins_common_custom_quickview_textbox'], function (qv) {
162 qv.init(); 163 }); 164 } 165 } 166}); 167 168 169// Lazy-load js for widgets that have the [data-js] attribute on their root node 170(function() { 171 function initDataJs(searchScope, selector = '[data-js]' ){ 172 require(['plugins_common_custom_lazyload'], function(lazyload) { 173 var widgetsToLoad = []; 174 let scope = searchScope ? searchScope : document; 175 var els = scope.querySelectorAll(selector); 176 177 for (var i = 0; i < els.length; i++) { 178 widgetsToLoad.push(els[i]); 179 } 180 181 lazyload.lazy(widgetsToLoad, function(entry, io) { 182 var target = entry.target; 183 var jsFile = target.dataset.js; 184 var guid = target.dataset.guid; 185 186 require([jsFile], function(widget) { 187 widget.init(guid); 188 io.unobserve(target); 189 }); 190 }); 191 }); 192 }; 193 194 initDataJs(); 195 196 let eventToSelectorMap = { 197 // each event needs a slightly different selector 198 "dynamicContentLoaded": "[data-dynamic-chosen] [data-js]", 199 "abContentLoaded": "[data-ab-chosen] [data-js]" 200 } 201 202 Object.entries(eventToSelectorMap).forEach( event => { 203 const [eventName, selector] = event; 204 window.addEventListener(eventName, e => { 205 const collections = document.querySelector(`[data-guid="${e}"]`); 206 initDataJs(collections, selector); 207 }); 208 }); 209})(); 210 211// Wrap core_textbox iframes to prevent horizontal overflow 212(function() { 213 const textBoxes = document.querySelectorAll('[data-sv-core-textbox]'); 214 if (textBoxes.length) { 215 require(['plugins_common_custom_utils'], function(utils) { 216 textBoxes.forEach(utils.wrapIframes); 217 }); 218 } 219})(); 220 221// Remove critical styles from head after all CSS files have loaded 222// This prevents a situation where the critical styles cause an override of the CSS in files 223const criticalStyles = document.querySelector('[data-critical-styles]'); 224if (criticalStyles) { 225 window.addEventListener('load', e =>
225 criticalStyles.remove()); 226}
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.