PageSourceSearch

https://umbc.edu/wp-content/themes/umbc-theme-2.0/js/umbc-interaction-tracking.js?ver=1790186983

js umbc.edu collected 2026-09-24 07:39:33 UTC 3,275 bytes, 89 lines download raw bytes

1/**
2 * UMBC Interaction Tracking — generic button / CTA click coverage.
3 *
4 * Fires a single `ui_click` dataLayer event for high-signal interactions:
5 *   • every <button> and [role="button"] (real controls — toggles, modals, tabs…)
6 *   • anything explicitly tagged with data-track="Label" (editor opt-in)
7 *   • CTA-styled links (class contains btn / button / cta)
8 *
9 * Deliberately NOT every <a>: plain navigation is already visible via pageviews,
10 * and outbound/download links should come from GA4 Enhanced Measurement (a toggle,
11 * no code). Tracking every click would duplicate data and risk the Stape request
12 * cap — see umbc-sgtm-migration-plan.md §11.6 / §12.5. Add data-track to any link
13 * you want captured; add data-no-track to anything you want suppressed.
14 *
15 * This is a high-volume micro-interaction stream: per §12.5, route `ui_click` to
16 * GA4 directly (not through Stape). Conversions live in umbc-conversion-tracking.js.
17 */
18(function () {
19	'use strict';
20
21	var MAX_LABEL = 100;
22
23	function classStr(el) {
24		return (typeof el.className === 'string' ? el.className : '').toLowerCase();
25	}
26
27	function looksLikeCta(el) {
28		return /(^|[\s_-])(btn|button|cta)([\s_-]|$)/.test(classStr(el));
29	}
30
31	function textLabel(el) {
32		var t = (el.textContent || '').replace(/\s+/g, ' ').trim();
33		return t.length > MAX_LABEL ? t.slice(0, MAX_LABEL) : t;
34	}
35
36	function resolveLabel(el) {
37		return el.getAttribute('data-track')
38			|| el.getAttribute('aria-label')
39			|| textLabel(el)
40			|| el.getAttribute('title')
41			|| el.id
42			|| '';
43	}
44
45	function nearestSection(el) {
46		var s = el.closest('[data-section], section[id], [role="region"][aria-label]');
47		if (!s) return '';
48		return s.getAttribute('data-section') || s.id || s.getAttribute('aria-label') || '';
49	}
50
51	// Capture phase so we still record clicks on controls that stopPropagation.
52	document.addEventListener('click', function (e) {
53		var el = e.target.closest ? e.target.closest('button, [role="button"], [data-track], a') : null;
54		if (!el) return;
55
56		// Owned by other trackers / intentionally excluded.
57		if (el.closest('[data-umbc-register-cta]')) return; // event_register_click
58		if (el.closest('[data-no-track]')) return;          // explicit opt-out
59		if (el.closest('#umbc-cookie-banner')) return;      // consent UI, own semantics
60		if (el.closest('.qs-listbox')) return;              // quick-search, already tracked
61
62		var tag      = el.tagName.toLowerCase();
63		var isButton = tag === 'button' || el.getAttribute('role') === 'button';
64		var isTagged = el.hasAttribute('data-track');
65		var isLink   = tag === 'a';
66
67		// Plain (non-CTA, non-tagged) links: skip — navigation shows up in pageviews.
68		if (isLink && !isButton && !isTagged && !looksLikeCta(el)) return;
69
70		var label = resolveLabel(el);
71		if (!label) return; // nothing meaningful to report
72
73		var payload = {
74			event: 'ui_click',
75			click_text: label,
76			click_type: isTagged ? 'tagged' : (isButton ? 'button' : 'link'),
77			click_id: el.id || '',
78			click_classes: classStr(el),
79			click_section: nearestSection(el)
80		};
81		if (isLink) {
82			var href = el.getAttribute('href');
83			if (href) payload.click_url = href;
84		}
85
86		window.dataLayer = window.dataLayer || [];
87		window.dataLayer.push(payload);
88	}, true);
89})();

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.