PageSourceSearch

https://www.holahouston.com/includes/public/managed/v_a2e6ae52_ff2…/common/virtuals/js/shared_footer.js

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

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.