feat: Implement cookie consent management and improve navigation functionality
This commit is contained in:
+134
-163
@@ -754,6 +754,110 @@
|
|||||||
(function () {
|
(function () {
|
||||||
var menuToggle = document.getElementById('mobileMenuToggle');
|
var menuToggle = document.getElementById('mobileMenuToggle');
|
||||||
var navLinks = document.getElementById('mainNav');
|
var navLinks = document.getElementById('mainNav');
|
||||||
|
var consentKey = 'cookie_consent_v1';
|
||||||
|
var banner = document.getElementById('cookieBanner');
|
||||||
|
var acceptBtn = document.getElementById('cookieAcceptBtn');
|
||||||
|
var prefsBtn = document.getElementById('cookiePrefsBtn');
|
||||||
|
var prefsModal = document.getElementById('cookiePrefsModal');
|
||||||
|
var analyticsCheckbox = document.getElementById('cookie_analytics');
|
||||||
|
var marketingCheckbox = document.getElementById('cookie_marketing');
|
||||||
|
var prefsSave = document.getElementById('cookiePrefsSave');
|
||||||
|
var prefsAcceptAll = document.getElementById('cookiePrefsAcceptAll');
|
||||||
|
var prefsOnlyNecessary = document.getElementById('cookiePrefsOnlyNecessary');
|
||||||
|
|
||||||
|
function getConsent() {
|
||||||
|
try {
|
||||||
|
var raw = window.localStorage.getItem(consentKey);
|
||||||
|
return raw ? JSON.parse(raw) : null;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyConsent() {
|
||||||
|
try {
|
||||||
|
var c = getConsent() || {};
|
||||||
|
var analyticsAllowed = !!c.analytics;
|
||||||
|
var marketingAllowed = !!c.marketing;
|
||||||
|
|
||||||
|
document.querySelectorAll('script[type="text/plain"]').forEach(function (node) {
|
||||||
|
var required = node.getAttribute('data-consent') || 'analytics';
|
||||||
|
var allowed = (required === 'analytics' && analyticsAllowed) || (required === 'marketing' && marketingAllowed) || required === 'necessary';
|
||||||
|
if (!allowed) return;
|
||||||
|
|
||||||
|
if (node.getAttribute('data-consent-applied') === '1') return;
|
||||||
|
|
||||||
|
var script = document.createElement('script');
|
||||||
|
if (node.src) script.src = node.src;
|
||||||
|
else script.text = node.textContent || node.innerText || '';
|
||||||
|
|
||||||
|
var type = node.getAttribute('data-script-type');
|
||||||
|
if (type) script.type = type;
|
||||||
|
|
||||||
|
node.parentNode.insertBefore(script, node);
|
||||||
|
node.setAttribute('data-consent-applied', '1');
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('applyConsent error', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveConsent(obj) {
|
||||||
|
try {
|
||||||
|
window.localStorage.setItem(consentKey, JSON.stringify(obj));
|
||||||
|
document.cookie = 'cookie_consent=' + encodeURIComponent(JSON.stringify(obj)) + '; Max-Age=' + (60 * 60 * 24 * 365) + '; Path=/; SameSite=Strict';
|
||||||
|
applyConsent();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('saveConsent error', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showBannerIfNeeded() {
|
||||||
|
if (banner && !getConsent()) banner.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
function openPrefs() {
|
||||||
|
var consent = getConsent() || {};
|
||||||
|
if (analyticsCheckbox) analyticsCheckbox.checked = !!consent.analytics;
|
||||||
|
if (marketingCheckbox) marketingCheckbox.checked = !!consent.marketing;
|
||||||
|
if (prefsModal) prefsModal.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closePrefs() {
|
||||||
|
if (prefsModal) prefsModal.classList.add('hidden');
|
||||||
|
if (banner) banner.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
window.printDocument = function () {
|
||||||
|
try { window.print(); } catch (e) { console.error('print error', e); }
|
||||||
|
};
|
||||||
|
|
||||||
|
window.printPdf = function (url) {
|
||||||
|
try {
|
||||||
|
var popup = window.open(url, '_blank');
|
||||||
|
if (!popup) return;
|
||||||
|
var attempts = 0;
|
||||||
|
var timer = setInterval(function () {
|
||||||
|
attempts += 1;
|
||||||
|
try {
|
||||||
|
if (popup.document && (popup.document.readyState === 'complete' || popup.document.readyState === 'interactive')) {
|
||||||
|
popup.focus();
|
||||||
|
popup.print();
|
||||||
|
clearInterval(timer);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (attempts > 8) {
|
||||||
|
clearInterval(timer);
|
||||||
|
try { popup.focus(); } catch (focusError) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attempts > 30) clearInterval(timer);
|
||||||
|
}, 300);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('printPdf error', e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (menuToggle && navLinks) {
|
if (menuToggle && navLinks) {
|
||||||
menuToggle.addEventListener('click', function () {
|
menuToggle.addEventListener('click', function () {
|
||||||
var isExpanded = this.getAttribute('aria-expanded') === 'true';
|
var isExpanded = this.getAttribute('aria-expanded') === 'true';
|
||||||
@@ -764,11 +868,10 @@
|
|||||||
|
|
||||||
navLinks.querySelectorAll('a').forEach(function (link) {
|
navLinks.querySelectorAll('a').forEach(function (link) {
|
||||||
link.addEventListener('click', function () {
|
link.addEventListener('click', function () {
|
||||||
if (navLinks.classList.contains('open')) {
|
if (!navLinks.classList.contains('open')) return;
|
||||||
menuToggle.setAttribute('aria-expanded', 'false');
|
menuToggle.setAttribute('aria-expanded', 'false');
|
||||||
navLinks.classList.remove('open');
|
navLinks.classList.remove('open');
|
||||||
navLinks.setAttribute('aria-hidden', 'true');
|
navLinks.setAttribute('aria-hidden', 'true');
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -780,16 +883,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
navLinks.querySelectorAll('a').forEach(function (link) {
|
|
||||||
link.addEventListener('click', function () {
|
|
||||||
if (navLinks.classList.contains('open')) {
|
|
||||||
menuToggle.setAttribute('aria-expanded', 'false');
|
|
||||||
navLinks.classList.remove('open');
|
|
||||||
navLinks.setAttribute('aria-hidden', 'true');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener('resize', function () {
|
window.addEventListener('resize', function () {
|
||||||
if (window.innerWidth > 820 && navLinks.classList.contains('open')) {
|
if (window.innerWidth > 820 && navLinks.classList.contains('open')) {
|
||||||
menuToggle.setAttribute('aria-expanded', 'false');
|
menuToggle.setAttribute('aria-expanded', 'false');
|
||||||
@@ -799,161 +892,39 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var banner = document.getElementById("cookieBanner");
|
if (banner && acceptBtn) {
|
||||||
var acceptBtn = document.getElementById("cookieAcceptBtn");
|
showBannerIfNeeded();
|
||||||
var declineBtn = document.getElementById("cookieDeclineBtn");
|
|
||||||
if (!banner || !acceptBtn || !declineBtn) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var consentKey = "cookie_consent_v1";
|
acceptBtn.addEventListener('click', function () {
|
||||||
|
saveConsent({ status: 'accepted', necessary: true, analytics: true, marketing: true, saved_at: Date.now() });
|
||||||
|
banner.classList.add('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
function getConsent() {
|
if (prefsBtn) prefsBtn.addEventListener('click', openPrefs);
|
||||||
try {
|
|
||||||
var raw = window.localStorage.getItem(consentKey);
|
|
||||||
if (!raw) return null;
|
|
||||||
return JSON.parse(raw);
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveConsent(obj) {
|
if (prefsSave) prefsSave.addEventListener('click', function () {
|
||||||
try {
|
saveConsent({
|
||||||
window.localStorage.setItem(consentKey, JSON.stringify(obj));
|
status: 'custom',
|
||||||
var cookieVal = obj.status || (obj.accepted ? 'accepted' : 'custom');
|
necessary: true,
|
||||||
document.cookie = "cookie_consent=" + encodeURIComponent(JSON.stringify(obj)) + "; Max-Age=" + (60 * 60 * 24 * 365) + "; Path=/; SameSite=Strict";
|
analytics: !!(analyticsCheckbox && analyticsCheckbox.checked),
|
||||||
// Apply consent immediately: enable any scripts gated by consent
|
marketing: !!(marketingCheckbox && marketingCheckbox.checked),
|
||||||
applyConsent();
|
saved_at: Date.now()
|
||||||
} catch (e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showBannerIfNeeded() {
|
|
||||||
var c = getConsent();
|
|
||||||
if (!c) {
|
|
||||||
banner.classList.remove("hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showBannerIfNeeded();
|
|
||||||
|
|
||||||
acceptBtn.addEventListener("click", function () {
|
|
||||||
var obj = { status: 'accepted', necessary: true, analytics: true, marketing: true, saved_at: Date.now() };
|
|
||||||
saveConsent(obj);
|
|
||||||
banner.classList.add("hidden");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Preferences modal handling
|
|
||||||
var prefsBtn = document.getElementById('cookiePrefsBtn');
|
|
||||||
var prefsModal = document.getElementById('cookiePrefsModal');
|
|
||||||
var analyticsCheckbox = document.getElementById('cookie_analytics');
|
|
||||||
var marketingCheckbox = document.getElementById('cookie_marketing');
|
|
||||||
var prefsSave = document.getElementById('cookiePrefsSave');
|
|
||||||
var prefsAcceptAll = document.getElementById('cookiePrefsAcceptAll');
|
|
||||||
var prefsOnlyNecessary = document.getElementById('cookiePrefsOnlyNecessary');
|
|
||||||
|
|
||||||
function openPrefs() {
|
|
||||||
// initialize from existing consent if present
|
|
||||||
var c = getConsent() || {};
|
|
||||||
analyticsCheckbox.checked = !!c.analytics;
|
|
||||||
marketingCheckbox.checked = !!c.marketing;
|
|
||||||
prefsModal.classList.remove('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
function closePrefs() {
|
|
||||||
prefsModal.classList.add('hidden');
|
|
||||||
banner.classList.add('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prefsBtn) prefsBtn.addEventListener('click', openPrefs);
|
|
||||||
|
|
||||||
prefsSave.addEventListener('click', function () {
|
|
||||||
var obj = { status: 'custom', necessary: true, analytics: !!analyticsCheckbox.checked, marketing: !!marketingCheckbox.checked, saved_at: Date.now() };
|
|
||||||
saveConsent(obj);
|
|
||||||
closePrefs();
|
|
||||||
});
|
|
||||||
|
|
||||||
prefsAcceptAll.addEventListener('click', function () {
|
|
||||||
var obj = { status: 'accepted', necessary: true, analytics: true, marketing: true, saved_at: Date.now() };
|
|
||||||
saveConsent(obj);
|
|
||||||
closePrefs();
|
|
||||||
});
|
|
||||||
|
|
||||||
prefsOnlyNecessary.addEventListener('click', function () {
|
|
||||||
var obj = { status: 'necessary', necessary: true, analytics: false, marketing: false, saved_at: Date.now() };
|
|
||||||
saveConsent(obj);
|
|
||||||
closePrefs();
|
|
||||||
});
|
|
||||||
|
|
||||||
// --- Consent-based script loader -------------------------------------------------
|
|
||||||
// Usage: include scripts that require consent like this in templates:
|
|
||||||
// <script type="text/plain" data-consent="analytics" src="https://www.googletagmanager.com/gtag/js?id=XXX"></script>
|
|
||||||
// or for inline scripts:
|
|
||||||
// <script type="text/plain" data-consent="marketing"> /* fbq or other init code */ </script>
|
|
||||||
function applyConsent() {
|
|
||||||
try {
|
|
||||||
var c = getConsent() || {};
|
|
||||||
var analyticsAllowed = !!c.analytics;
|
|
||||||
var marketingAllowed = !!c.marketing;
|
|
||||||
|
|
||||||
// Find all scripts that were intentionally disabled by using type="text/plain"
|
|
||||||
document.querySelectorAll('script[type="text/plain"]').forEach(function (node) {
|
|
||||||
var required = node.getAttribute('data-consent') || 'analytics';
|
|
||||||
if ((required === 'analytics' && analyticsAllowed) || (required === 'marketing' && marketingAllowed) || required === 'necessary') {
|
|
||||||
var s = document.createElement('script');
|
|
||||||
// copy src or inline content
|
|
||||||
if (node.src) s.src = node.src;
|
|
||||||
else s.text = node.textContent || node.innerText || '';
|
|
||||||
// copy attributes that are safe/needed
|
|
||||||
var type = node.getAttribute('data-script-type');
|
|
||||||
if (type) s.type = type;
|
|
||||||
// append to same parent
|
|
||||||
node.parentNode.insertBefore(s, node);
|
|
||||||
// mark original as applied to avoid double-inserting
|
|
||||||
node.setAttribute('data-consent-applied', '1');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (e) {
|
closePrefs();
|
||||||
console.error('applyConsent error', e);
|
});
|
||||||
}
|
|
||||||
|
if (prefsAcceptAll) prefsAcceptAll.addEventListener('click', function () {
|
||||||
|
saveConsent({ status: 'accepted', necessary: true, analytics: true, marketing: true, saved_at: Date.now() });
|
||||||
|
closePrefs();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (prefsOnlyNecessary) prefsOnlyNecessary.addEventListener('click', function () {
|
||||||
|
saveConsent({ status: 'necessary', necessary: true, analytics: false, marketing: false, saved_at: Date.now() });
|
||||||
|
closePrefs();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run once on load in case user already saved consent
|
|
||||||
applyConsent();
|
applyConsent();
|
||||||
// Global print helpers
|
|
||||||
window.printDocument = function () {
|
|
||||||
try { window.print(); } catch (e) { console.error('print error', e); }
|
|
||||||
};
|
|
||||||
|
|
||||||
window.printPdf = function (url) {
|
|
||||||
try {
|
|
||||||
var w = window.open(url, '_blank');
|
|
||||||
if (!w) return;
|
|
||||||
// Attempt to print after load; poll for readyState
|
|
||||||
var attempts = 0;
|
|
||||||
var t = setInterval(function () {
|
|
||||||
attempts++;
|
|
||||||
try {
|
|
||||||
if (w.document && (w.document.readyState === 'complete' || w.document.readyState === 'interactive')) {
|
|
||||||
w.focus();
|
|
||||||
w.print();
|
|
||||||
clearInterval(t);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// cross-domain or plugin viewer may block access; fallback: focus window and leave to user
|
|
||||||
if (attempts > 8) {
|
|
||||||
clearInterval(t);
|
|
||||||
try { w.focus(); } catch (e) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (attempts > 30) clearInterval(t);
|
|
||||||
}, 300);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('printPdf error', e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user