PageSourceSearch

https://www.visitchattanooga.com/includes/public/managed/v_c8155e1…/common/virtuals/js/shared_footer.js

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

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.