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", "domReady!"], function($, gtm, UIWatcher, dynamic) { 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("scroll-into-view", handleScrollIntoView); 17 uiEvents.on("item-click", handleItemClick); 18 uiEvents.on("map-pin-click", handleMapPinClick); 19 uiEvents.on("tripbuilder", handleTripbuilder); 20 uiEvents.on("qv-tripbuilder", handleTripbuilder); 21 uiEvents.on("quick-view", handleQuickview); 22 23 // tracking handlers 24 function handleTripbuilder(payload){ 25 var event = payload.eventContext, 26 widget = payload.widgetContext; 27 let ga4Data = { 28 eventName: event?.value === "Add" ? "add_to_favorites" : undefined, 29 itemType: event?.itemType ?? (widget?.name === "Coupons" ? 'offers' : !["quickview", "quick view"].includes(widget?.name.toLowerCase()) ? widget?.name.toLowerCase() : undefined), 30 itemName: event?.refTitle, 31 linkObject: event?.linkObject, 32 itemCategory: event?.crmc, 33 interactionSource: event?.interactionSource, 34 interactionText: event?.interactionText, 35 interactionUrl: event?.interactionUrl, 36 itemCity: event?.itemCity, 37 itemRegion: event?.itemRegion, 38 itemId: event?.itemId, 39 acctId: event?.acctId, 40 itemVariant: event?.itemVariant, 41 price: event?.price, 42 } 43 if (event?.crmsc) 44 ga4Data.itemSubcategory = event?.crmsc; 45 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 46 gtm.sendEvents({ tClient_ga4: ga4Data }); 47 48 } 49 50 function handleQuickview(payload){ 51 var event = payload.eventContext; 52 let ga4Data = { 53 eventName: event?.eventName, 54 itemType: event?.itemType, 55 itemName: event?.itemName ?? event?.refTitle, 56 linkObject: event?.linkObject, 57 itemCategory: event?.crmc, 58 interactionSource: event?.interactionSource, 59 interactionText: event?.interactionText, 60 interactionUrl: event?.interactionUrl, 61 itemCity: event?.itemCity, 62 itemRegion: event?.itemRegion, 63 itemId: event?.itemId, 64 acctId: event?.acctId, 65 itemVariant: event?.itemVariant, 66 price: event?.price, 67 referralType: event?.referralType, 68 } 69 if (event?.crmsc) 70 ga4Data.itemSubcategory = event?.crmsc; 71 if (event?.eventName === 'partner_referral') 72 ga4Data.value = 5; 73 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 74 gtm.sendEvents({ tClient_ga4: ga4Data }); 75 76 } 77 78 function handleScrollIntoView(payload){ 79 var event = payload.eventContext, 80 widget = payload.widgetContext; 81 } 82 83 function handleShowMoreToggle(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 97 function handlePageChange(payload){ 98 var event = payload.eventContext; 99 let ga4Data = { 100 eventName: "filter", 101 filterType: `${event?.refTitle} | ${event?.displayText}`, 102 itemType: event?.itemType, 103 interactionSource: event?.interactionSource, 104 interactionText: event?.interactionText, 105 } 106 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 107 gtm.sendEvents({ tClient_ga4: ga4Data }); 108 109 } 110 111 function handleItemClick(payload){ 112 var event = payload.eventContext; 113 if (event?.name === "Quickview") { 114 var ga4Data = { 115 eventName: "filter", 116 filterType: "Open Quickview", 117 itemType: event?.itemType, 118 itemName: event?.itemName ?? event?.refTitle, 119 interactionSource: event?.interactionSource, 120 interactionText: event?.interactionText, 121 itemCategory: event?.crmc, 122 itemCity: event?.itemCity, 123 itemRegion: event?.itemRegion, 124 itemId: event?.itemId, 125 acctId: event?.acctId, 126 itemVariant: event?.itemVariant, 127 price: event?.price, 128 } 129 if (event?.crmsc) 130 ga4Data.itemSubcategory = event?.crmsc; 131 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 132 gtm.sendEvents({tClient_ga4: ga4Data}); 133 134 } else { 135 var ga4Data = { 136 eventName: event?.eventName, 137 itemType: event?.itemType, 138 itemName: event?.itemName ?? event?.refTitle, 139 linkObject: event?.linkObject, 140 itemCategory: event?.crmc, 141 interactionSource: event?.interactionSource, 142 interactionText: event?.interactionText, 143 interactionUrl: event?.interactionUrl, 144 itemCity: event?.itemCity, 145 itemRegion: event?.itemRegion, 146 itemId: event?.itemId, 147 acctId: event?.acctId, 148 itemVariant: event?.itemVariant, 149 price: event?.price, 150 referralType: event?.referralType, 151 } 152 if (event?.crmsc) 153 ga4Data.itemSubcategory = event?.crmsc; 154 if (event?.eventName === 'partner_referral') 155 ga4Data.value = 5; 156 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 157 gtm.sendEvents({tClient_ga4: ga4Data}); 158 159 } 160 } 161 162 function handleMapPinClick(payload){ 163 var event = payload.eventContext, 164 widget = payload.widgetContext; 165 } 166
167 function handleFilterChange (payload) { 168 var event = payload.eventContext; 169 let ga4Data = { 170 eventName: "filter", 171 filterType: `${event?.refTitle} | ${event?.displayText}`, 172 itemType: event?.itemType, 173 interactionSource: event?.interactionSource, 174 interactionText: event?.interactionText, 175 } 176 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 177 gtm.sendEvents({ tClient_ga4: ga4Data }); 178 } 179 // end SEM tracking 180}); 181 182// Lazy-load FontAwesome 183(function() { 184 var css = document.createElement('link'); 185 css.href = 'https://use.fontawesome.com/releases/v5.14.0/css/all.css'; 186 css.rel = 'stylesheet'; 187 css.type = 'text/css'; 188 document.getElementsByTagName('head')[0].appendChild(css); 189})(); 190 191// Lazy-load js for widgets that have the [data-js] attribute on their root node 192(function() { 193 function initDataJs(searchScope, selector = '[data-js]' ){ 194 require(['plugins_common_custom_lazyload'], function(lazyload) { 195 var widgetsToLoad = []; 196 let scope = searchScope ? searchScope : document; 197 var els = scope.querySelectorAll(selector); 198 199 for (var i = 0; i < els.length; i++) { 200 widgetsToLoad.push(els[i]); 201 } 202 203 lazyload.lazy(widgetsToLoad, function(entry, io) { 204 var target = entry.target; 205 var jsFile = target.dataset.js; 206 var guid = target.dataset.guid; 207 208 require([jsFile], function(widget) { 209 widget.init(guid); 210 io.unobserve(target); 211 }); 212 }); 213 }); 214 }; 215 216 initDataJs(); 217 218 let eventToSelectorMap = { 219 // each event needs a slightly different selector 220 "dynamicContentLoaded": "[data-dynamic-chosen] [data-js]", 221 "abContentLoaded": "[data-ab-chosen] [data-js]" 222 } 223 224 Object.entries(eventToSelectorMap).forEach( event => { 225 const [eventName, selector] = event; 226 window.addEventListener(eventName, e => { 227 const collections = document.querySelector(`[data-guid="${e}"]`); 228 initDataJs(collections, selector); 229 }); 230 }); 231})(); 232 233// Wrap core_textbox iframes to prevent horizontal overflow 234(function() { 235 const textBoxes = document.querySelectorAll('[data-sv-core-textbox]'); 236 if (textBoxes.length) { 237 require(['plugins_common_custom_utils'], function(utils) { 238 textBoxes.forEach(utils.wrapIframes); 239 }); 240 } 241})(); 242 243// Init quickview textboxes 244(function() { 245 const textBoxes = document.querySelectorAll('[data-qv-enabled-textbox]'); 246 if (textBoxes.length) { 247 require(['plugins_common_custom_quickview_textbox'], function (qv) { 248 qv.init(); 249 }); 250 } 251})(); 252 253// Remove critical styles from head after all CSS files have loaded 254// This prevents a situation where the critical styles cause an override of the CSS in files 255const criticalStyles = document.querySelector('[data-critical-styles]'); 256if (criticalStyles) { 257 window.addEventListener('load', e =>
257 criticalStyles.remove()); 258} 259 260 261require(['jquery'], function($) { 262 if ($('#embedForm').length > 0) { 263 iFrameResize({ log: false }, '#embedForm'); 264 } 265});
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.