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