PageSourceSearch

https://www.visitjamaica.com/includes/public/managed/v_c8155e17_96…/common/virtuals/js/shared_footer.js

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

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.