PageSourceSearch

https://www.boeingcentertechport.com/includes/public/managed/v_c81…/virtuals/js/custom_asm/shared_footer.js

js boeingcentertechport.com collected 2026-09-25 04:47:33 UTC 9,087 bytes, 274 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("scroll-into-view", handleScrollIntoView);
17	uiEvents.on("item-click", handleItemClick);
18
19
20	function handleScrollIntoView(payload){
21		var event = payload.eventContext,
22			widget = payload.widgetContext;
23	}
24
25	function handleShowMoreToggle(payload){
26		var event = payload.eventContext;
27		let ga4Data = {
28			eventName: "filter",
29			filterType: `${event?.refTitle} | ${event?.displayText}`,
30			itemType: event?.itemType,
31			interactionSource: event?.interactionSource,
32			interactionText: event?.interactionText,
33		}
34		if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType)
35			gtm.sendEvents({ tClient_ga4: ga4Data });
36	}
37
38	function handlePageChange(payload){
39		var event = payload.eventContext;
40		let ga4Data = {
41			eventName: "filter",
42			filterType: `${event?.refTitle} | ${event?.displayText}`,
43			itemType: event?.itemType,
44			interactionSource: event?.interactionSource,
45			interactionText: event?.interactionText,
46		}
47		if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType)
48			gtm.sendEvents({ tClient_ga4: ga4Data });
49	}
50
51	function handleItemClick(payload){
52		var event = payload.eventContext;
53		if (event?.name === "Quickview") {
54			var ga4Data = {
55				eventName: "filter",
56				filterType: "Open Quickview",
57				itemType: event?.itemType,
58				itemName: event?.itemName ?? event?.refTitle,
59				interactionSource: event?.interactionSource,
60				interactionText: event?.interactionText,
61			}
62			if (ga4Data.eventName && ga4Data.filterType && ga4Data.itemType)
63				gtm.sendEvents({tClient_ga4: ga4Data});
64		}
65		else {
66			var ga4Data = {
67				eventName: event?.eventName,
68				itemType: event?.itemType,
69				itemName: event?.itemName ?? event?.refTitle,
70				linkObject: event?.linkObject,
71				itemCategory: event?.crmc,
72				interactionSource: event?.interactionSource,
73				interactionText: event?.interactionText,
74				interactionUrl: event?.interactionUrl,
75				itemCity: event?.itemCity,
76				itemRegion: event?.itemRegion,
77				itemId: event?.itemId,
78				acctId: event?.acctId,
79			}
80			if (event?.crmsc)
81				ga4Data.itemSubcategory = event?.crmsc;
82			if (event?.eventName === 'partner_referral') {
83				ga4Data.value = 5;
84				ga4Data.referralType = event?.referralType;
85			}
86			if (ga4Data.eventName && ga4Data.itemType && ga4Data.itemName && ga4Data.linkObject)
87				gtm.sendEvents({tClient_ga4: ga4Data});
88		}
89	}
90
91	function handleMapPinClick(payload){
92		var event = payload.eventContext,
93			widget = payload.widgetContext;
94	}
95
96	function handleFilterChange (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	// end SEM tracking
109});
110
111// Lazy-load js for widgets that have the [data-js] attribute on their root node
112(function() {
113	function initDataJs(searchScope, selector = '[data-js]' ){
114		require(['plugins_common_custom_lazyload'], function(lazyload) {
115			var widgetsToLoad = [];
116			let scope = searchScope ? searchScope : document;
117			var els = scope.querySelectorAll(selector);
118
119			for (var i = 0; i < els.length; i++) {
120				widgetsToLoad.push(els[i]);
121			}
122			
123			lazyload.lazy(widgetsToLoad, function(entry, io) {
124				var target = entry.target;
125				var jsFile = target.dataset.js;
126				var guid = target.dataset.guid;
127
128				require([jsFile], function(widget) {
129					widget.init(guid);
130					io.unobserve(target);
131				});
132			});
133		});
134	};
135
136	initDataJs();
137
138	let eventToSelectorMap = {
139		// each event needs a slightly different selector
140		"dynamicContentLoaded": "[data-dynamic-chosen] [data-js]",
141		"abContentLoaded": "[data-ab-chosen] [data-js]"
142	}
143	
144	Object.entries(eventToSelectorMap).forEach( event => {
145		const [eventName, selector] = event;
146		window.addEventListener(eventName, e => {
147			const collections = document.querySelector(`[data-guid="${e}"]`);
148			initDataJs(collections, selector);
149		});
150	});
151})();
152
153// Wrap core_textbox iframes to prevent horizontal overflow
154(function() {
155	const textBoxes = document.querySelectorAll('[data-sv-core-textbox]');
156	if (textBoxes.length) {
157		require(['plugins_common_custom_utils'], function(utils) {
158			textBoxes.forEach(utils.wrapIframes);
159		});
160	}
161})();
162
163// Remove critical styles from head after all CSS files have loaded
164// This prevents a situation where the critical styles cause an override of the CSS in files
165const criticalStyles = document.querySelectorAll('[data-critical-styles]');
166if (criticalStyles) {
167	window.addEventListener('load', e => {
168		criticalStyles.forEach(element => {
169			element.remove()
170		});
171	});
172}
173
174require(["plugins_core", "sv_site", "domReady!"], function (core, site) {
175	(async function () {
176		if (!(site?.siteConfig?.plugins?.events?.active)) { return; }
177
178		// Gets all recId elements on page that are not in Detail or Events Layout List widget, as those are handled separately.
179		const recIdElements = document.querySelectorAll('[data-recid]:not(.layoutjs [data-recid]):not(.shared-detail)');
180		const recIdsArray = Array.from(recIdElements).map(element => element.getAttribute('data-recid'));
181		if (recIdsArray.length === 0) { return; }
182
183		async function fetchItems(matchCondition) {
184			const aggregateQuery = [
185				{
186					$match: matchCondition
187				},
188				{
189					$sort: {
190						_updated: -1
191					}
192				},
193				{
194					$group: {
195						_id: "$event",
196						mostRecentDocument: { $first: "$$ROOT" }
197					}
198				},
199				{
200					$replaceRoot: {
201						newRoot: "$mostRecentDocument"
202					}
203				}
204			];
205			
206			const params = new URLSearchParams({ 'token': core.simpleToken, 'json': JSON.stringify({ pipeline: aggregateQuery }) });
207			const resource = "plugins_collections_type_custom_premium_link_override";
208			const aggregateEndpoint = `/includes/rest_v2/${resource}/aggregate/?` + params;
209
210			try {
211				const response = await fetch(aggregateEndpoint);
212				
213				if (!response.ok) {
214					console.warn(`Error: Failed to fetch data from the endpoint. Status: ${response.status}`);
215					return;
216				}
217			} catch (error) {
218				console.error("An error occurred during the fetch request:", error);
219			}
220
221			const aggregateResponse = await fetch(aggregateEndpoint);
222			const aggregateResultData = await aggregateResponse.json();
223
224			if (aggregateResultData.docs.length > 0) {
225				const findQuery = {
226					filter: {
227						_id: {
228							$in: aggregateResultData.docs.map(doc => ({ $oid: doc._id }) )
229						},
230					},
231					options: {
232						castDocs: false,
233					},
234				};
235
236				const findParams = new URLSearchParams({ 'token': core.simpleToken, 'json': JSON.stringify(findQuery) });
237				const findEndpoint = `/includes/rest_v2/${resource}/find/?` + findParams;
238				const findResponse = await fetch(findEndpoint);
239				const findResultData = await findResponse.json();
240
241				return findResultData.docs || [];
242			} else {
243				return [];
244			}
245		}
246
247		const matchCondition = { event: { $in: recIdsArray } };
248		const premiumLinks = await fetchItems(matchCondition);
249		if (premiumLinks.length > 0) {
250			const eventMap = new Map();
251			premiumLinks.forEach(premiumLink => {
252				eventMap.set(premiumLink.event, premiumLink.button_link.url);
253			})
254			recIdElements.forEach(element => {
255				// Check if the element itself or any of its descendants have a data-premium-link attribute
256				const link = element.querySelector('[data-premium-link]') || (element.hasAttribute('data-premium-link') ? element : null);
257				if (link === null) return;
258				const recId = element.getAttribute('data-recid');
259				if (eventMap.has(recId)) {
260					let linkToUse = eventMap.get(recId);
261					link.setAttribute('href', linkToUse);
262					let gtmVars = link.getAttribute('data-gtm-vars');
263					let gtmVarsObj = JSON.parse(gtmVars);
264					gtmVarsObj.tClient_ga4.interactionUrl = encodeURIComponent(linkToUse);
265					let updatedGtmVars = JSON.stringify(gtmVarsObj);
266					link.setAttribute('data-gtm-vars', updatedGtmVars);
267				}
268				else if (link.getAttribute('href').includes("javascript:void(0)")) {
269					link.remove();
270				}
271			});
272		}
273	})();
274});

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.