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.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 viatorEvent: event?.viatorEvent, 43 propertyId: event?.propertyId, 44 propertyType: event?.propertyType, 45 propertyName: event?.propertyName, 46 isFeatured: event?.isFeatured, 47 } 48 if (event?.crmsc) 49 ga4Data.itemSubcategory = event?.crmsc; 50 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 51 gtm.sendEvents({ tClient_ga4: ga4Data }); 52 } 53 54 function handleQuickview(payload){ 55 var event = payload.eventContext; 56 let ga4Data = { 57 eventName: event?.eventName, 58 itemType: event?.itemType, 59 itemName: event?.itemName ?? event?.refTitle, 60 linkObject: event?.linkObject, 61 itemCategory: event?.crmc, 62 interactionSource: event?.interactionSource, 63 interactionText: event?.interactionText, 64 interactionUrl: event?.interactionUrl, 65 itemCity: event?.itemCity, 66 itemRegion: event?.itemRegion, 67 itemId: event?.itemId, 68 acctId: event?.acctId, 69 itemVariant: event?.itemVariant, 70 price: event?.price, 71 referralType: event?.referralType, 72 viatorEvent: event?.viatorEvent, 73 propertyId: event?.propertyId, 74 propertyType: event?.propertyType, 75 propertyName: event?.propertyName, 76 isFeatured: event?.isFeatured, 77 } 78 if (event?.crmsc) 79 ga4Data.itemSubcategory = event?.crmsc; 80 if (event?.eventName === 'partner_referral') 81 ga4Data.value = 5; 82 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 83 gtm.sendEvents({ tClient_ga4: ga4Data }); 84 } 85 86 function handleScrollIntoView(payload){ 87 var event = payload.eventContext, 88 widget = payload.widgetContext; 89 var data = { 90 eventCategory: widget.name, 91 eventAction: event.name, 92 eventLabel: "Widget - "+widget.name, 93 nonInteraction: true 94 } 95 if (data.eventCategory && data.eventAction && data.eventLabel) 96 gtm.sendEvents({tClient: data}); 97 } 98 99 function handleShowMoreToggle(payload){ 100 var event = payload.eventContext; 101 let ga4Data = { 102 eventName: "filter", 103 filterType: `${event?.refTitle} | ${event?.displayText}`, 104 itemType: event?.itemType, 105 interactionSource: event?.interactionSource, 106 interactionText: event?.interactionText, 107 } 108 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 109 gtm.sendEvents({ tClient_ga4: ga4Data }); 110 } 111 112 function handlePageChange(payload){ 113 var event = payload.eventContext; 114 let ga4Data = { 115 eventName: "filter", 116 filterType: `${event?.refTitle} | ${event?.displayText}`, 117 itemType: event?.itemType, 118 interactionSource: event?.interactionSource, 119 interactionText: event?.interactionText, 120 } 121 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 122 gtm.sendEvents({ tClient_ga4: ga4Data }); 123 } 124
125 function handleItemClick(payload){ 126 var event = payload.eventContext; 127 if (event?.name === "Quickview" || event?.name === "Quick View") { 128 var ga4Data = { 129 eventName: "filter", 130 filterType: "Open Quickview", 131 itemType: event?.itemType, 132 itemName: event?.itemName ?? event?.refTitle, 133 interactionSource: event?.interactionSource, 134 interactionText: event?.interactionText, 135 itemCategory: event?.crmc, 136 itemCity: event?.itemCity, 137 itemRegion: event?.itemRegion, 138 itemId: event?.itemId, 139 acctId: event?.acctId, 140 itemVariant: event?.itemVariant, 141 price: event?.price, 142 viatorEvent: event?.viatorEvent, 143 propertyId: event?.propertyId, 144 propertyType: event?.propertyType, 145 propertyName: event?.propertyName, 146 isFeatured: event?.isFeatured, 147 } 148 if (event?.crmsc) 149 ga4Data.itemSubcategory = event?.crmsc; 150 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 151 gtm.sendEvents({tClient_ga4: ga4Data}); 152 } else { 153 var ga4Data = { 154 eventName: event?.eventName, 155 widgetName: event?.widgetName, 156 itemType: event?.itemType, 157 itemName: event?.itemName ?? event?.refTitle, 158 linkObject: event?.linkObject, 159 itemCategory: event?.crmc, 160 interactionSource: event?.interactionSource, 161 interactionText: event?.interactionText, 162 interactionUrl: event?.interactionUrl, 163 itemCity: event?.itemCity, 164 itemRegion: event?.itemRegion, 165 itemId: event?.itemId, 166 acctId: event?.acctId, 167 itemVariant: event?.itemVariant, 168 price: event?.price, 169 referralType: event?.referralType, 170 viatorEvent: event?.viatorEvent, 171 propertyId: event?.propertyId, 172 propertyType: event?.propertyType, 173 propertyName: event?.propertyName, 174 isFeatured: event?.isFeatured, 175 } 176 if (event?.crmsc) 177 ga4Data.itemSubcategory = event?.crmsc; 178 if (event?.eventName === 'partner_referral') 179 ga4Data.value = 5; 180 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 181 gtm.sendEvents({tClient_ga4: ga4Data}); 182 } 183 } 184 185 function handleMapPinClick(payload){ 186 var event = payload.eventContext, 187 widget = payload.widgetContext; 188 var data = { 189 eventCategory: widget.name, 190 eventAction: event.name, 191 eventLabel: event.refTitle, 192 ot: event.type, 193 nonInteraction: false 194 } 195 if (data.eventCategory && data.eventAction && data.eventLabel) 196 gtm.sendEvents({tClient: data}); 197 } 198 199 function handleFilterChange (payload) { 200 var event = payload.eventContext; 201 let ga4Data = { 202 eventName: "filter", 203 filterType: `${event?.refTitle} | ${event?.displayText}`, 204 itemType: event?.itemType, 205 interactionSource: event?.interactionSource, 206 interactionText: event?.interactionText, 207 } 208 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 209 gtm.sendEvents({ tClient_ga4: ga4Data }); 210 } 211 // end SEM tracking 212}); 213 214// Lazy-load FontAwesome 215(function() { 216 var css = document.createElement('link'); 217 css.href = 'https://use.fontawesome.com/releases/v5.14.0/css/all.css'; 218 css.rel = 'stylesheet'; 219 css.type = 'text/css'; 220 document.getElementsByTagName('head')[0].appendChild(css); 221})(); 222 223// Lazy-load js for widgets that have the [data-js] attribute on their root node 224(function() { 225 function initDataJs(searchScope, selector = '[data-js]' ){ 226 require(['plugins_common_custom_lazyload'], function(lazyload) { 227 var widgetsToLoad = []; 228 let scope = searchScope ? searchScope : document; 229 var els = scope.querySelectorAll(selector); 230 231 for (var i = 0; i < els.length; i++) { 232 widgetsToLoad.push(els[i]); 233 } 234 235 lazyload.lazy(widgetsToLoad, function(entry, io) { 236 var target = entry.target; 237 var jsFile = target.dataset.js; 238 var guid = target.dataset.guid; 239 240 require([jsFile], function(widget) { 241 widget.init(guid); 242 io.unobserve(target); 243 }); 244 }); 245 }); 246 }; 247 248 initDataJs(); 249 250 let eventToSelectorMap = { 251 // each event needs a slightly different selector 252 "dynamicContentLoaded": "[data-dynamic-chosen] > .contentRender > [data-js]", 253 "abContentLoaded": "[data-ab-chosen] > .contentRender > [data-js]" 254 } 255
256 Object.entries(eventToSelectorMap).forEach( event => { 257 const [eventName, selector] = event; 258 window.addEventListener(eventName, e => { 259 const collections = document.querySelector(`[data-guid="${e}"]`); 260 initDataJs(collections, selector); 261 }); 262 }); 263})(); 264 265// Remove critical styles from head after all CSS files have loaded 266// This prevents a situation where the critical styles cause an override of the CSS in files 267const criticalStyles = document.querySelector('[data-critical-styles]'); 268if (criticalStyles) { 269 window.addEventListener('load', e => criticalStyles.remove()); 270}
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.