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 6const docbody = document.querySelector('body'); 7if (window.location.pathname.includes('/includes/plugins/')) { 8 docbody.classList.add('is-preview'); 9} 10 11if (window.self !== window.top) { 12 docbody.classList.add('is-frame'); 13} 14 15require(["jquery", "site_gtm", "sv_load!plugins_dynamic_content", "plugins_common_custom_ui_watcher", "sv_site", "sv_siteFoundation", "domReady!"], function($, gtm, dynamicContent, UIWatcher, site) { 16 17 var publishStart = $("[data-publish-start]").attr("data-publish-start"); 18 var cmsTags = $("[data-cms-tags]").attr("data-cms-tags"); 19 20 if (dynamicContent) { 21 var user = getUserFields(["created", "type", "personas", "page_views"], dynamicContent.getUser()); 22 23 function getUserFields(fields, dcUser){ 24 var user = {}; 25 fields.some(function(field) { 26 if (dcUser !== undefined && dcUser[field] !== undefined) user[field] = dcUser[field]; 27 }); 28 return user; 29 } 30 31 gtm.sendCustomPageview({ tClient_pageview: { dynamic_content: user, publish_start: publishStart, cms_tags: cmsTags }, tCore_pageview : {}}, "shared_footerJs"); 32 } 33 else { 34 gtm.sendCustomPageview({ tClient_pageview: { publish_start: publishStart, cms_tags: cmsTags }, tCore_pageview : {}}, "shared_footerJs"); 35 } 36 37 $(document).foundation(); 38 39 gtm.update(); 40 41 // SEM tracking 42 var uiEvents = new UIWatcher({}, $, document); 43 uiEvents.on("change-page", handlePageChange); 44 uiEvents.on("view-change", handleFilterChange); 45 uiEvents.on("sort-change", handleFilterChange); 46 uiEvents.on("value-change", handleFilterChange); 47 uiEvents.on("toggle-show-more", handleShowMoreToggle); 48 uiEvents.on("scroll-into-view", handleScrollIntoView); 49 uiEvents.on("item-click", handleItemClick); 50 uiEvents.on("map-pin-click", handleMapPinClick); 51 uiEvents.on("tripbuilder", handleTripbuilder); 52 uiEvents.on("qv-tripbuilder", handleTripbuilder); 53 uiEvents.on("quick-view", handleQuickview); 54 55 // tracking handlers 56 function handleTripbuilder(payload){ 57 var event = payload.eventContext, 58 widget = payload.widgetContext; 59 let ga4Data = { 60 eventName: event?.value === "Add" ? "add_to_favorites" : undefined, 61 itemType: event?.itemType ?? (widget?.name === "Coupons" ? 'offers' : !["quickview", "quick view"].includes(widget?.name.toLowerCase()) ? widget?.name.toLowerCase() : undefined), 62 itemName: event.itemName ?? event.refTitle, 63 linkObject: event.linkObject || event.value ==="Add" ? "Add to Favorites" : undefined, 64 itemCategory: event?.crmc, 65 interactionSource: event?.interactionSource, 66 interactionText: event?.interactionText, 67 interactionUrl: event?.interactionUrl, 68 itemCity: event?.itemCity, 69 itemRegion: event?.itemRegion, 70 itemId: event?.itemId, 71 acctId: event?.acctId, 72 itemVariant: event?.itemVariant, 73 price: event?.price, 74 } 75 if (event?.crmsc) 76 ga4Data.itemSubcategory = event?.crmsc; 77 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 78 gtm.sendEvents({ tClient_ga4: ga4Data }); 79 } 80 81 function handleQuickview(payload){ 82 var event = payload.eventContext; 83 let ga4Data = { 84 eventName: event?.eventName, 85 itemType: event.itemType ?? event.detailType, 86 itemName: event?.itemName ?? event?.refTitle, 87 linkObject: event.linkObject ?? event.linkTo, 88 itemCategory: event?.crmc, 89 interactionSource: event?.interactionSource, 90 interactionText: event?.interactionText, 91 interactionUrl: event?.interactionUrl, 92 itemCity: event?.itemCity, 93 itemRegion: event?.itemRegion, 94 itemId: event?.itemId, 95 acctId: event?.acctId, 96 itemVariant: event?.itemVariant, 97 price: event?.price, 98 referralType: event?.referralType, 99 } 100 if (event?.crmsc) 101 ga4Data.itemSubcategory = event?.crmsc; 102 if (event?.eventName === 'partner_referral') 103 ga4Data.value = 5; 104 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 105 gtm.sendEvents({ tClient_ga4: ga4Data }); 106 107 } 108 109 function handleScrollIntoView(payload){ 110 var event = payload.eventContext, 111 widget = payload.widgetContext; 112 } 113 114 function handleShowMoreToggle(payload){ 115 var event = payload.eventContext; 116 let ga4Data = { 117 eventName: "filter", 118 filterType: event.displayText+" | "+event.refTitle, 119 itemType: event.itemType, 120 interactionSource: event?.interactionSource, 121 interactionText: event?.interactionText, 122 } 123 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 124 gtm.sendEvents({tClient_ga4: ga4Data}); 125 } 126 127 function handlePageChange(payload){ 128 var event = payload.eventContext; 129 let ga4Data = { 130 eventName: "filter", 131 filterType: event.refTitle+" | "+event.displayText, 132 itemType: event.itemType, 133 interactionSource: event?.interactionSource, 134 interactionText: event?.interactionText, 135 } 136 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 137 gtm.sendEvents({tClient_ga4: ga4Data}); 138 } 139
140 function handleItemClick(payload){ 141 var event = payload.eventContext; 142 if (event?.name === "Quickview" || event?.name === "Quick View") { 143 var ga4Data = { 144 eventName: "filter", 145 filterType: "Open Quick View", 146 itemType: event?.itemType, 147 itemName: event?.itemName ?? event?.refTitle, 148 interactionSource: event?.interactionSource, 149 interactionText: event?.interactionText, 150 itemCategory: event?.crmc, 151 itemCity: event?.itemCity, 152 itemRegion: event?.itemRegion, 153 itemId: event?.itemId, 154 acctId: event?.acctId, 155 itemVariant: event?.itemVariant, 156 price: event?.price, 157 } 158 if (event?.crmsc) 159 ga4Data.itemSubcategory = event?.crmsc; 160 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 161 gtm.sendEvents({tClient_ga4: ga4Data}); 162 } else { 163 var ga4Data = { 164 eventName: event?.eventName, 165 itemType: event?.itemType, 166 itemName: event?.itemName ?? event?.refTitle, 167 linkObject: event?.linkObject, 168 itemCategory: event?.crmc, 169 interactionSource: event?.interactionSource, 170 interactionText: event?.interactionText, 171 interactionUrl: event?.interactionUrl, 172 itemCity: event?.itemCity, 173 itemRegion: event?.itemRegion, 174 itemId: event?.itemId, 175 acctId: event?.acctId, 176 itemVariant: event?.itemVariant, 177 price: event?.price, 178 referralType: event?.referralType, 179 } 180 if (event?.crmsc) 181 ga4Data.itemSubcategory = event?.crmsc; 182 if (event?.eventName === 'partner_referral') 183 ga4Data.value = 5; 184 if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject) 185 gtm.sendEvents({tClient_ga4: ga4Data}); 186 } 187 } 188 189 function handleMapPinClick(payload){ 190 var event = payload.eventContext, 191 widget = payload.widgetContext; 192 } 193 194 function handleFilterChange (payload) { 195 var event = payload.eventContext; 196 let ga4Data = { 197 eventName: "filter", 198 filterType: event.refTitle+" | "+event.displayText, 199 itemType: event.itemType, 200 interactionSource: event?.interactionSource, 201 interactionText: event?.interactionText, 202 } 203 if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType) 204 gtm.sendEvents({tClient_ga4: ga4Data}); 205 } 206 // end SEM tracking 207 208 if (site.siteConfig.custom[site.site].quickview.active) { 209 const textBoxes = document.querySelectorAll('[data-qv-enabled-textbox]'); 210 211 if (textBoxes.length) { 212 require(['plugins_common_custom_quickview_textbox'], function (qv) { 213 qv.init(); 214 }); 215 } 216 } 217 218 if (site.siteConfig.plugins.maps.active) { 219 // wait for the map iframe to load, then watch for changes on the details panel 220 // info link elements are added to the page dynamically when the details panel is opened 221 // update the info links to open in a new tab 222 223 const watchMap = (map) => { 224 const mapObserver = new MutationObserver((mutationsList, observer) => { 225 for (let mutation of mutationsList) { 226 if (mutation.type === 'childList') { 227 for (let node of mutation.addedNodes) { 228 if (node.classList !== undefined && node.classList.contains('infoTray')) { 229 for (let anchor of node.querySelectorAll('.contentItem > a')) { 230 anchor.setAttribute('target', '_blank'); 231 } 232 } 233 } 234 } 235 } 236 }); 237 238 mapObserver.observe(map.contentDocument, { 239 subtree: true, 240 childList: true, 241 }); 242 }; 243 244 const mapFrame = document.querySelector('.contentRender_name_plugins_maps_embed_widget > iframe'); 245 let checkCount = 0; 246 let waitForMap = setInterval(() => { 247 checkCount++; 248 if (checkCount > 9 || mapFrame !== null) { 249 clearInterval(waitForMap); 250 251 if (mapFrame !== null) { 252 watchMap(mapFrame); 253 } 254 } 255 }, 1000); 256 } 257}); 258 259// Lazy-load FontAwesome 260(function() { 261 var css = document.createElement('link'); 262 css.href = 'https://use.fontawesome.com/releases/v5.15.4/css/all.css'; 263 css.rel = 'stylesheet'; 264 css.type = 'text/css'; 265 document.getElementsByTagName('head')[0].appendChild(css); 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.