PageSourceSearch

https://www.meetboston.com/includes/public/managed/v_c8155e17_20f3…/common/virtuals/js/shared_footer.js

js meetboston.com collected 2026-09-24 18:31:25 UTC 8,484 bytes, 246 lines download raw bytes

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

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.