PageSourceSearch

https://www.destinationtoronto.com/includes/public/managed/v_a2e6a…/common/virtuals/js/shared_footer.js

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

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.