PageSourceSearch

https://www.jayjeffers.com/dyad/wp-content/mu-plugins/dyad-compliance/assets/compliance.js?ver=0.1.0

js jayjeffers.com collected 2026-09-26 10:25:30 UTC 20,228 bytes, 778 lines download raw bytes

1(function () {
2	"use strict";
3
4	var config = window.DyadComplianceConfig || {};
5	var loadedGa = false;
6	var NOTICE_CLOSE_MS = 350;
7	var consentLevel = String(config.consentLevel || "us_opt_out");
8	var footerMode = false;
9	var footerSelector = "footer, #colophon, [role='contentinfo'], .site-footer, .footer";
10	var footerPositionWasOverridden = false;
11	var footerPositionElement = null;
12	var footerPositionOriginalValue = "";
13
14	function getFooterElement() {
15		return document.querySelector(footerSelector);
16	}
17
18	function getActivePageContainer(preferredContainer) {
19		if (preferredContainer && preferredContainer.nodeType === 1) {
20			return preferredContainer;
21		}
22
23		var visibleBarbaContainer = document.querySelector("[data-barba='container']:not(.hidden)");
24		if (visibleBarbaContainer) {
25			return visibleBarbaContainer;
26		}
27
28		return document.getElementById("primary-container");
29	}
30
31	function normalizePageTitle(title) {
32		var rawTitle = String(title || "");
33		var firstSegment = rawTitle.split("|")[0].split("-")[0].split("—")[0].trim();
34
35		return firstSegment.toLowerCase();
36	}
37
38	function getCurrentPageTitle(preferredContainer) {
39		var container = getActivePageContainer(preferredContainer);
40		if (container) {
41			var containerTitle = String(container.getAttribute("data-title") || "").trim();
42			if (containerTitle) {
43				return containerTitle;
44			}
45		}
46
47		return String(document.title || "").trim();
48	}
49
50	function shouldStayFixedForCurrentPage(preferredContainer) {
51		var container = getActivePageContainer(preferredContainer);
52		var hasBarba = !!window.barba;
53
54		if (hasBarba && container) {
55			var namespace = String(container.getAttribute("data-barba-namespace") || "").toLowerCase();
56			if (namespace === "home-page") {
57				return true;
58			}
59
60			var title = normalizePageTitle(getCurrentPageTitle(container));
61			if (title === "contact" || title === "inquire") {
62				return true;
63			}
64
65			return false;
66		}
67
68		if (document.body.classList.contains("home") || document.body.classList.contains("front-page")) {
69			return true;
70		}
71
72		if (document.body.classList.contains("contact") || document.body.classList.contains("inquire")) {
73			return true;
74		}
75
76		return false;
77	}
78
79	function setFooterPositioning(footer, enabled) {
80		if (enabled) {
81			if (!footer) {
82				return;
83			}
84
85			if (footerPositionWasOverridden && footerPositionElement && footerPositionElement !== footer) {
86				footerPositionElement.style.position = footerPositionOriginalValue;
87				footerPositionOriginalValue = "";
88				footerPositionWasOverridden = false;
89				footerPositionElement = null;
90			}
91
92			var computedPosition = window.getComputedStyle(footer).position;
93			if (computedPosition === "static" && !footerPositionWasOverridden) {
94				footerPositionOriginalValue = footer.style.position || "";
95				footer.style.position = "relative";
96				footerPositionWasOverridden = true;
97				footerPositionElement = footer;
98			}
99			return;
100		}
101
102		if (footerPositionWasOverridden) {
103			if (footerPositionElement) {
104				footerPositionElement.style.position = footerPositionOriginalValue;
105			}
106			footerPositionOriginalValue = "";
107			footerPositionWasOverridden = false;
108			footerPositionElement = null;
109		}
110	}
111
112	function moveRootToFooter(root, footer) {
113		if (!root || !footer) {
114			return;
115		}
116
117		if (root.parentNode !== footer) {
118			footer.appendChild(root);
119		}
120		root.classList.add("dyad-compliance-root--footer");
121	}
122
123	function moveRootToBody(root) {
124		if (!root) {
125			return;
126		}
127
128		if (root.parentNode !== document.body) {
129			document.body.appendChild(root);
130		}
131		root.style.removeProperty("--dyad-footer-toggle-color");
132		root.classList.remove("dyad-compliance-root--footer");
133	}
134
135	function syncFooterToggleColor(preferredContainer) {
136		var root = document.getElementById("dyad-compliance-root");
137		if (!root || !root.classList.contains("dyad-compliance-root--footer")) {
138			return;
139		}
140
141		var footer = getFooterElement();
142		if (!footer) {
143			root.style.removeProperty("--dyad-footer-toggle-color");
144			return;
145		}
146
147		var footerColor = window.getComputedStyle(footer).color || "";
148		if (footerColor) {
149			root.style.setProperty("--dyad-footer-toggle-color", footerColor);
150		} else {
151			root.style.removeProperty("--dyad-footer-toggle-color");
152		}
153	}
154
155	function updateFooterPlacement(preferredContainer) {
156		var root = document.getElementById("dyad-compliance-root");
157		if (!root) {
158			return;
159		}
160
161		var footer = getFooterElement();
162		var useFixedMode = shouldStayFixedForCurrentPage(preferredContainer) || !footer;
163
164		if (useFixedMode) {
165			setFooterPositioning(null, false);
166			moveRootToBody(root);
167			footerMode = false;
168			return;
169		}
170
171		setFooterPositioning(footer, true);
172		moveRootToFooter(root, footer);
173		footerMode = true;
174	}
175
176	function registerPageChangeListener() {
177		if (window.DyadCompliancePageChangeListenerRegistered) {
178			return;
179		}
180
181		window.DyadCompliancePageChangeListenerRegistered = true;
182
183		window.addEventListener("dyad:page-change", function (event) {
184			var pageContainer = event && event.detail ? event.detail.newContainer : null;
185			if (window.barba) {
186				closePopupOnPageChange();
187			}
188			updateFooterPlacement(pageContainer);
189		});
190	}
191
192	function shouldKeepPopupOpenOnPageChange() {
193		return consentLevel === "gdpr_opt_in" && String(window.DyadComplianceState || "unknown") === "unknown";
194	}
195
196	function closePopupOnPageChange() {
197		if (shouldKeepPopupOpenOnPageChange()) {
198			return;
199		}
200
201		var popup = document.getElementById("dyad-compliance-popup");
202		if (popup) {
203			popup.hidden = true;
204		}
205	}
206
207	function registerBarbaPageChangeHook() {
208		if (window.DyadComplianceBarbaHookRegistered) {
209			return;
210		}
211
212		if (!window.barba || !window.barba.hooks) {
213			return;
214		}
215
216		var hook = null;
217		if (typeof window.barba.hooks.afterEnter === "function") {
218			hook = window.barba.hooks.afterEnter;
219		} else if (typeof window.barba.hooks.after === "function") {
220			hook = window.barba.hooks.after;
221		}
222
223		if (!hook) {
224			return;
225		}
226
227		window.DyadComplianceBarbaHookRegistered = true;
228		hook(function (data) {
229			var pageContainer = data && data.next ? data.next.container : null;
230			closePopupOnPageChange();
231			updateFooterPlacement(pageContainer);
232			window.requestAnimationFrame(function () {
233				syncFooterToggleColor(pageContainer);
234			});
235		});
236	}
237
238	function setNoticeExpanded(expanded, isClosing) {
239		var notice = document.getElementById("dyad-compliance-notice");
240		if (!notice) {
241			return;
242		}
243
244		var toggle = notice.querySelector(".dyad-consent-toggle");
245		if (toggle) {
246			toggle.setAttribute("aria-expanded", expanded ? "true" : "false");
247		}
248
249		if (expanded) {
250			notice.classList.remove("is-collapsing");
251			notice.classList.add("is-expanded");
252			updateNoticeDetailHeight();
253			return;
254		}
255
256		if (isClosing) {
257			notice.classList.add("is-collapsing");
258		}
259		notice.classList.remove("is-expanded");
260
261		if (isClosing) {
262			window.setTimeout(function () {
263				notice.classList.remove("is-collapsing");
264			}, NOTICE_CLOSE_MS);
265		}
266	}
267
268	function updateNoticeDetailHeight() {
269		var notice = document.getElementById("dyad-compliance-notice");
270		if (!notice) {
271			return;
272		}
273
274		var details = notice.querySelector(".dyad-consent-details");
275		if (!details) {
276			return;
277		}
278
279		// Measure actual scrollHeight and apply via CSS custom property for dynamic animation
280		var height = Math.ceil(details.scrollHeight);
281		notice.style.setProperty("--dyad-detail-max-height", height + "px");
282	}
283
284	function registerNoticeResizeObserver() {
285		var notice = document.getElementById("dyad-compliance-notice");
286		if (!notice) {
287			return;
288		}
289
290		if (!window.ResizeObserver) {
291			return;
292		}
293
294		var details = notice.querySelector(".dyad-consent-details");
295		if (!details) {
296			return;
297		}
298
299		var observer = new window.ResizeObserver(function () {
300			if (notice.classList.contains("is-expanded")) {
301				updateNoticeDetailHeight();
302			}
303		});
304		observer.observe(details);
305	}
306
307	function getUsNoticeCopyForState(state, defaultCopy) {
308		if (state === "denied" || state === "gpc_denied") {
309			if (defaultCopy) {
310				return "You are no longer being tracked. " + defaultCopy;
311			}
312			return "You are no longer being tracked.";
313		}
314		return defaultCopy;
315	}
316
317	function getGdprNoticeCopyForState(state, defaultCopy) {
318		if (state === "denied" || state === "gpc_denied") {
319			if (defaultCopy) {
320				return "You have declined analytics cookies. " + defaultCopy;
321			}
322			return "You have declined analytics cookies.";
323		}
324
325		if (state === "granted") {
326			if (defaultCopy) {
327				return "You have accepted analytics cookies. " + defaultCopy;
328			}
329			return "You have accepted analytics cookies.";
330		}
331
332		return defaultCopy;
333	}
334
335	function log() {
336		if (!config.diagnosticsMode) {
337			return;
338		}
339		if (window.console && typeof window.console.log === "function") {
340			window.console.log.apply(window.console, arguments);
341		}
342	}
343
344	function getCookie(name) {
345		var escaped = name.replace(/[-.+*]/g, "\\$&");
346		var match = document.cookie.match(new RegExp("(?:^|; )" + escaped + "=([^;]*)"));
347		return match ? decodeURIComponent(match[1]) : "";
348	}
349
350	function setCookie(name, value, days) {
351		var maxAge = Math.max(1, Number(days || 365)) * 24 * 60 * 60;
352		var secure = window.location.protocol === "https:" ? "; Secure" : "";
353		document.cookie = name + "=" + encodeURIComponent(value) + "; path=/; max-age=" + maxAge + "; SameSite=Lax" + secure;
354	}
355
356	function getLocal(name) {
357		try {
358			return window.localStorage.getItem(name) || "";
359		} catch (error) {
360			return "";
361		}
362	}
363
364	function setLocal(name, value) {
365		try {
366			window.localStorage.setItem(name, value);
367		} catch (error) {
368			// no-op
369		}
370	}
371
372	function shouldUseCookie() {
373		return config.consentStateStorageMode === "cookie_only" || config.consentStateStorageMode === "cookie_and_local_storage";
374	}
375
376	function shouldUseLocalStorage() {
377		return config.consentStateStorageMode === "local_storage_only" || config.consentStateStorageMode === "cookie_and_local_storage";
378	}
379
380	function readStoredState() {
381		var cookieName = config.consentCookieName || "site_consent_pref";
382		var state = "";
383
384		if (shouldUseCookie()) {
385			state = getCookie(cookieName);
386		}
387		if (!state && shouldUseLocalStorage()) {
388			state = getLocal(cookieName);
389		}
390		if (state === "granted" || state === "denied" || state === "gpc_denied") {
391			return state;
392		}
393		return "unknown";
394	}
395
396	function persistState(state) {
397		var cookieName = config.consentCookieName || "site_consent_pref";
398		if (shouldUseCookie()) {
399			setCookie(cookieName, state, Number(config.cookieTtlDays || 365));
400		}
401		if (shouldUseLocalStorage()) {
402			setLocal(cookieName, state);
403		}
404	}
405
406	function gpcEnabled() {
407		if (config.gpcServerDetected) {
408			return true;
409		}
410		return navigator.globalPrivacyControl === true || navigator.globalPrivacyControl === 1 || navigator.globalPrivacyControl === "1";
411	}
412
413	function ensureGtagBase() {
414		window.dataLayer = window.dataLayer || [];
415		if (typeof window.gtag !== "function") {
416			window.gtag = function () {
417				window.dataLayer.push(arguments);
418			};
419		}
420	}
421
422	function setGaDisable(denied) {
423		var id = String(config.ga4MeasurementId || "").trim();
424		if (!id) {
425			return;
426		}
427		window["ga-disable-" + id] = !!denied;
428	}
429
430	function applyConsentMode(state) {
431		ensureGtagBase();
432		var analyticsStorage = state === "granted" ? "granted" : "denied";
433		window.gtag("consent", "default", {
434			analytics_storage: analyticsStorage,
435			ad_storage: "denied",
436			ad_user_data: "denied",
437			ad_personalization: "denied",
438			security_storage: "granted",
439		});
440		window.gtag("consent", "update", {
441			analytics_storage: analyticsStorage,
442			ad_storage: "denied",
443			ad_user_data: "denied",
444			ad_personalization: "denied",
445		});
446	}
447
448	function maybeLoadGa4(state) {
449		if (config.useSiteKit) {
450			return;
451		}
452		var gaId = String(config.ga4MeasurementId || "").trim();
453		if (!gaId || loadedGa || state !== "granted") {
454			return;
455		}
456
457		var script = document.createElement("script");
458		script.async = true;
459		script.src = "https://www.googletagmanager.com/gtag/js?id=" + encodeURIComponent(gaId);
460		document.head.appendChild(script);
461
462		ensureGtagBase();
463		window.gtag("js", new Date());
464		var gaConfig = {
465			send_page_view: true,
466			allow_google_signals: false,
467			allow_ad_personalization_signals: false,
468		};
469		if (config.enableGa4IpRandomization) {
470			// Best-effort browser-side privacy flag; strict proxy randomization is server-side work.
471			gaConfig.anonymize_ip = true;
472		}
473		window.gtag("config", gaId, gaConfig);
474		loadedGa = true;
475		log("[Dyad Compliance] GA4 loaded in manual mode");
476	}
477
478	function computeInitialState() {
479		if (consentLevel === "disabled") {
480			return "granted";
481		}
482
483		if (gpcEnabled()) {
484			return "gpc_denied";
485		}
486
487		var stored = readStoredState();
488		if (stored !== "unknown") {
489			return stored;
490		}
491
492		if (consentLevel === "gdpr_opt_in") {
493			return "unknown";
494		}
495
496		return "granted";
497	}
498
499	function updateUsNoticeState(state) {
500		var notice = document.getElementById("dyad-compliance-notice");
501		if (!notice) {
502			return;
503		}
504
505		var copy = notice.querySelector(".dyad-consent-copy");
506		var optOutButton = document.getElementById("dyad-consent-opt-out");
507		var reEnableButton = document.getElementById("dyad-consent-re-enable");
508		var gdprAcceptInlineButton = document.getElementById("dyad-consent-accept-inline");
509		var gdprDenyInlineButton = document.getElementById("dyad-consent-deny-inline");
510		var defaultCopy = copy ? String(copy.getAttribute("data-us-copy") || copy.getAttribute("data-default-copy") || "") : "";
511
512		if (copy) {
513			copy.textContent = getUsNoticeCopyForState(state, defaultCopy);
514		}
515
516		if (gdprAcceptInlineButton) {
517			gdprAcceptInlineButton.hidden = true;
518		}
519		if (gdprDenyInlineButton) {
520			gdprDenyInlineButton.hidden = true;
521		}
522
523		if (state === "denied") {
524			if (optOutButton) {
525				optOutButton.hidden = true;
526			}
527			if (reEnableButton) {
528				reEnableButton.hidden = false;
529			}
530			setNoticeExpanded(true, false);
531			return;
532		}
533
534		if (state === "gpc_denied") {
535			if (optOutButton) {
536				optOutButton.hidden = true;
537			}
538			if (reEnableButton) {
539				reEnableButton.hidden = true;
540			}
541			setNoticeExpanded(true, false);
542			return;
543		}
544
545		if (optOutButton) {
546			optOutButton.hidden = false;
547		}
548		if (reEnableButton) {
549			reEnableButton.hidden = true;
550		}
551		setNoticeExpanded(false, false);
552	}
553
554	function updateGdprNoticeState(state) {
555		var notice = document.getElementById("dyad-compliance-notice");
556		if (!notice) {
557			return;
558		}
559
560		var copy = notice.querySelector(".dyad-consent-copy");
561		var optOutButton = document.getElementById("dyad-consent-opt-out");
562		var reEnableButton = document.getElementById("dyad-consent-re-enable");
563		var acceptInlineButton = document.getElementById("dyad-consent-accept-inline");
564		var denyInlineButton = document.getElementById("dyad-consent-deny-inline");
565		var defaultCopy = copy ? String(copy.getAttribute("data-gdpr-copy") || copy.getAttribute("data-default-copy") || "") : "";
566
567		if (copy) {
568			copy.textContent = getGdprNoticeCopyForState(state, defaultCopy);
569		}
570
571		if (optOutButton) {
572			optOutButton.hidden = true;
573		}
574		if (reEnableButton) {
575			reEnableButton.hidden = true;
576		}
577
578		if (state === "gpc_denied") {
579			if (acceptInlineButton) {
580				acceptInlineButton.hidden = true;
581			}
582			if (denyInlineButton) {
583				denyInlineButton.hidden = true;
584			}
585		} else {
586			if (acceptInlineButton) {
587				acceptInlineButton.hidden = false;
588			}
589			if (denyInlineButton) {
590				denyInlineButton.hidden = false;
591			}
592		}
593
594		setNoticeExpanded(false, false);
595	}
596
597	function openManager() {
598		var notice = document.getElementById("dyad-compliance-notice");
599		var popup = document.getElementById("dyad-compliance-popup");
600		if (consentLevel === "disabled") {
601			return;
602		}
603
604		if (consentLevel === "gdpr_opt_in") {
605			var currentState = String(window.DyadComplianceState || "unknown");
606			if (currentState === "unknown") {
607				if (popup) {
608					popup.hidden = false;
609				}
610				if (notice) {
611					notice.hidden = true;
612				}
613			} else if (notice) {
614				notice.hidden = false;
615				setNoticeExpanded(true, false);
616				if (popup) {
617					popup.hidden = true;
618				}
619			}
620		} else if (notice) {
621			notice.hidden = false;
622			setNoticeExpanded(true, false);
623		}
624	}
625
626	function closeManager() {
627		var notice = document.getElementById("dyad-compliance-notice");
628		var popup = document.getElementById("dyad-compliance-popup");
629		if (notice) {
630			notice.hidden = true;
631		}
632		if (popup) {
633			popup.hidden = true;
634		}
635	}
636
637	function updateUiForState(state) {
638		var notice = document.getElementById("dyad-compliance-notice");
639		var popup = document.getElementById("dyad-compliance-popup");
640		var root = document.getElementById("dyad-compliance-root");
641
642		if (consentLevel === "disabled") {
643			if (notice) {
644				notice.hidden = true;
645			}
646			if (popup) {
647				popup.hidden = true;
648			}
649			if (root) {
650				root.hidden = true;
651			}
652			return;
653		}
654
655		if (root) {
656			root.hidden = false;
657		}
658
659		if (consentLevel === "gdpr_opt_in") {
660			if (popup) {
661				popup.hidden = state !== "unknown";
662			}
663			if (notice) {
664				notice.hidden = state === "unknown";
665				if (state !== "unknown") {
666					updateGdprNoticeState(state);
667				}
668			}
669		} else {
670			if (notice) {
671				notice.hidden = false;
672				updateUsNoticeState(state);
673			}
674			if (popup) {
675				popup.hidden = true;
676			}
677		}
678	}
679
680	function applyState(state, persist) {
681		var finalState = state;
682		if (consentLevel !== "disabled" && gpcEnabled()) {
683			finalState = "gpc_denied";
684		}
685
686		if (persist) {
687			persistState(finalState);
688		}
689
690		setGaDisable(finalState !== "granted");
691		applyConsentMode(finalState);
692		maybeLoadGa4(finalState);
693		updateUiForState(finalState);
694		log("[Dyad Compliance] state:", finalState);
695		window.DyadComplianceState = finalState;
696	}
697
698	function bindUi() {
699		var denyButton = document.getElementById("dyad-consent-deny");
700		var acceptButton = document.getElementById("dyad-consent-accept");
701		var inlineDenyButton = document.getElementById("dyad-consent-deny-inline");
702		var inlineAcceptButton = document.getElementById("dyad-consent-accept-inline");
703		var ccpaOptOutButton = document.getElementById("dyad-consent-opt-out");
704		var reEnableButton = document.getElementById("dyad-consent-re-enable");
705		var ccpaCloseButton = document.querySelector("#dyad-compliance-notice .ccpa-close");
706		var ccpaTitleToggle = document.querySelector("#dyad-compliance-notice .dyad-consent-toggle");
707
708		if (denyButton) {
709			denyButton.addEventListener("click", function () {
710				applyState("denied", true);
711			});
712		}
713		if (acceptButton) {
714			acceptButton.addEventListener("click", function () {
715				applyState("granted", true);
716			});
717		}
718		if (inlineDenyButton) {
719			inlineDenyButton.addEventListener("click", function () {
720				applyState("denied", true);
721			});
722		}
723		if (inlineAcceptButton) {
724			inlineAcceptButton.addEventListener("click", function () {
725				applyState("granted", true);
726			});
727		}
728		if (ccpaOptOutButton) {
729			ccpaOptOutButton.addEventListener("click", function () {
730				applyState("denied", true);
731			});
732		}
733		if (reEnableButton) {
734			reEnableButton.addEventListener("click", function () {
735				applyState("granted", true);
736			});
737		}
738		if (ccpaTitleToggle) {
739			ccpaTitleToggle.addEventListener("click", function () {
740				var notice = document.getElementById("dyad-compliance-notice");
741				var isExpanded = !!(notice && notice.classList.contains("is-expanded"));
742				setNoticeExpanded(!isExpanded, false);
743			});
744		}
745		if (ccpaCloseButton) {
746			ccpaCloseButton.addEventListener("click", function () {
747				setNoticeExpanded(false, true);
748			});
749		}
750	}
751
752	function init() {
753		bindUi();
754		var initial = computeInitialState();
755		applyState(initial, consentLevel !== "disabled" && initial !== "unknown");
756		window.DyadComplianceLevel = consentLevel;
757		registerPageChangeListener();
758		registerBarbaPageChangeHook();
759		registerNoticeResizeObserver();
760		updateFooterPlacement();
761		syncFooterToggleColor();
762		window.addEventListener("load", function () {
763			registerBarbaPageChangeHook();
764			updateFooterPlacement();
765			syncFooterToggleColor();
766		});
767
768		window.addEventListener("dyad:open-privacy-settings", function () {
769			openManager();
770		});
771	}
772
773	if (document.readyState === "loading") {
774		document.addEventListener("DOMContentLoaded", init);
775	} else {
776		init();
777	}
778})();

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.