PageSourceSearch

https://mightygreen.com/wp-content/plugins/tmb-site-manager-client…/tracking/tracking-consent.js?ver=1.149.0

js mightygreen.com collected 2026-10-04 18:57:56 UTC 4,981 bytes, 143 lines download raw bytes

1/**
2 * Nexus Client — Consent Banner
3 *
4 * Reads cached consent decision from localStorage, renders the sticky consent
5 * banner if no decision exists, wires accept / decline buttons, persists the
6 * choice to localStorage + POSTs to /tmb-client/v1/tracking/consent, and
7 * updates window.TMBClientBeacon.consent so the beacon starts/stops flushing.
8 */
9(function () {
10	'use strict';
11
12	if (typeof document === 'undefined') return;
13
14	var cfg = window.TMBClientBeacon || {};
15	var i18n = cfg.i18n || {};
16	var STORAGE_KEY = 'tmb_consent_state';
17	var CONSENT_URL = (cfg.restRoot || '').replace(/\/+$/, '') + '/tracking/consent';
18
19	function readStored() {
20		try { return localStorage.getItem(STORAGE_KEY) || ''; }
21		catch (e) { return ''; }
22	}
23
24	function writeStored(state) {
25		try { localStorage.setItem(STORAGE_KEY, state); } catch (e) {}
26	}
27
28	function ensureBannerMarkup() {
29		var existing = document.getElementById('tmb-consent-banner');
30		if (existing) return existing;
31
32		// Build banner programmatically if the template wasn't injected
33		// server-side. Mirrors templates/tracking/tracking-consent-banner.php.
34		var banner = document.createElement('div');
35		banner.id = 'tmb-consent-banner';
36		banner.className = 'tmb-consent-banner';
37		banner.setAttribute('role', 'dialog');
38		banner.setAttribute('aria-labelledby', 'tmb-consent-banner-title');
39		banner.setAttribute('aria-describedby', 'tmb-consent-banner-text');
40		banner.hidden = true;
41		banner.innerHTML = ''
42			+ '<div class="tmb-consent-banner-inner">'
43			+   '<div class="tmb-consent-banner-body">'
44			+     '<h2 id="tmb-consent-banner-title" class="tmb-consent-banner-title"></h2>'
45			+     '<p id="tmb-consent-banner-text" class="tmb-consent-banner-text"></p>'
46			+   '</div>'
47			+   '<div class="tmb-consent-banner-actions">'
48			+     '<button type="button" class="tmb-consent-btn tmb-consent-btn--decline" id="tmb-consent-decline"></button>'
49			+     '<button type="button" class="tmb-consent-btn tmb-consent-btn--accept"  id="tmb-consent-accept"></button>'
50			+   '</div>'
51			+   '<button type="button" class="tmb-consent-banner-dismiss" id="tmb-consent-dismiss" aria-label="Dismiss">&times;</button>'
52			+ '</div>';
53		document.body.appendChild(banner);
54		return banner;
55	}
56
57	function applyI18n(banner) {
58		var titleNode   = banner.querySelector('#tmb-consent-banner-title');
59		var textNode    = banner.querySelector('#tmb-consent-banner-text');
60		var acceptBtn   = banner.querySelector('#tmb-consent-accept');
61		var declineBtn  = banner.querySelector('#tmb-consent-decline');
62		if (titleNode  && !titleNode.textContent.trim())  titleNode.textContent  = i18n.consentTitle || 'We value your privacy';
63		if (textNode   && !textNode.textContent.trim())   textNode.textContent   = i18n.consentText  || 'We use cookies to improve your experience and analyze site traffic.';
64		if (acceptBtn  && !acceptBtn.textContent.trim())  acceptBtn.textContent  = i18n.accept       || 'Accept';
65		if (declineBtn && !declineBtn.textContent.trim()) declineBtn.textContent = i18n.decline      || 'Decline';
66	}
67
68	function showBanner(banner) {
69		banner.hidden = false;
70		banner.removeAttribute('hidden');
71	}
72
73	function hideBanner(banner) {
74		banner.hidden = true;
75		banner.setAttribute('hidden', 'hidden');
76	}
77
78	function postConsent(state) {
79		try {
80			fetch(CONSENT_URL, {
81				method: 'POST',
82				credentials: 'same-origin',
83				headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
84				body: JSON.stringify({ state: state, visitor_id: cfg.visitorId || '' })
85			}).catch(function () {});
86		} catch (e) {}
87	}
88
89	function applyDecision(state) {
90		writeStored(state);
91		cfg.consent = state;
92		if (typeof cfg._setConsent === 'function') {
93			cfg._setConsent(state);
94		}
95		if (typeof cfg.track === 'function') {
96			try { cfg.track('visitor.consent_' + state, {}, {}); } catch (e) {}
97		}
98		postConsent(state);
99	}
100
101	function boot() {
102		var existing = readStored();
103		if (existing === 'granted' || existing === 'denied') {
104			cfg.consent = existing;
105			if (typeof cfg._setConsent === 'function') cfg._setConsent(existing);
106			return;
107		}
108
109		var banner = ensureBannerMarkup();
110		applyI18n(banner);
111
112		var acceptBtn  = banner.querySelector('#tmb-consent-accept');
113		var declineBtn = banner.querySelector('#tmb-consent-decline');
114		var dismissBtn = banner.querySelector('#tmb-consent-dismiss');
115
116		if (acceptBtn) {
117			acceptBtn.addEventListener('click', function () {
118				applyDecision('granted');
119				hideBanner(banner);
120			});
121		}
122		if (declineBtn) {
123			declineBtn.addEventListener('click', function () {
124				applyDecision('denied');
125				hideBanner(banner);
126			});
127		}
128		if (dismissBtn) {
129			dismissBtn.addEventListener('click', function () {
130				// Dismiss without a decision — leave state unknown for this session
131				hideBanner(banner);
132			});
133		}
134
135		showBanner(banner);
136	}
137
138	if (document.readyState === 'loading') {
139		document.addEventListener('DOMContentLoaded', boot, { once: true });
140	} else {
141		boot();
142	}
143})();

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.