feat: cookie banner compliance hardening — 5 legal requirements
1. Impressum link mandatory in banner (§5 TMG) 2. Pre-ticked prevention: only "required" categories pre-enabled (Planet49) 3. Cookie-Settings reopen link (§7(3) DSGVO — revocation as easy as consent) 4. Script-Blocking: data-cookie-category + type="text/plain" pattern Scripts only execute AFTER user consents to that category 5. Buttons already equal size (flex:1) — verified correct Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -245,13 +245,16 @@ function generateHTML(config: CookieBannerConfig, privacyPolicyUrl: string): str
|
|||||||
const categoriesHTML = config.categories
|
const categoriesHTML = config.categories
|
||||||
.map((cat) => {
|
.map((cat) => {
|
||||||
const isRequired = cat.isRequired
|
const isRequired = cat.isRequired
|
||||||
|
// COMPLIANCE: Only "required" categories may be pre-enabled (EuGH Planet49)
|
||||||
|
// Non-required categories must NEVER be defaultEnabled
|
||||||
|
const isEnabled = isRequired ? true : false
|
||||||
return `
|
return `
|
||||||
<div class="cookie-banner-category" data-category="${cat.id}">
|
<div class="cookie-banner-category" data-category="${cat.id}">
|
||||||
<div class="cookie-banner-category-info">
|
<div class="cookie-banner-category-info">
|
||||||
<div class="cookie-banner-category-name">${cat.name.de}</div>
|
<div class="cookie-banner-category-name">${cat.name.de}</div>
|
||||||
<div class="cookie-banner-category-desc">${cat.description.de}</div>
|
<div class="cookie-banner-category-desc">${cat.description.de}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cookie-banner-toggle ${cat.defaultEnabled ? 'active' : ''} ${isRequired ? 'disabled' : ''}"
|
<div class="cookie-banner-toggle ${isEnabled ? 'active' : ''} ${isRequired ? 'disabled' : ''}"
|
||||||
data-category="${cat.id}"
|
data-category="${cat.id}"
|
||||||
data-required="${isRequired}"></div>
|
data-required="${isRequired}"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -286,10 +289,22 @@ function generateHTML(config: CookieBannerConfig, privacyPolicyUrl: string): str
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="${privacyPolicyUrl}" class="cookie-banner-link" target="_blank">
|
<div class="cookie-banner-links">
|
||||||
${config.texts.privacyPolicyLink.de}
|
<a href="${privacyPolicyUrl}" class="cookie-banner-link" target="_blank">
|
||||||
</a>
|
${config.texts.privacyPolicyLink.de}
|
||||||
|
</a>
|
||||||
|
<a href="${config.impressumUrl || '/impressum'}" class="cookie-banner-link" target="_blank">
|
||||||
|
Impressum
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Cookie Settings Re-Open (§7(3) DSGVO — Widerruf so einfach wie Einwilligung) -->
|
||||||
|
<a href="#" id="cookieBannerReopen" class="cookie-settings-footer-link"
|
||||||
|
onclick="document.getElementById('cookieBanner').style.display='block';document.getElementById('cookieBannerOverlay').classList.add('active');return false;"
|
||||||
|
style="position:fixed;bottom:8px;left:8px;z-index:9990;font-size:11px;color:#6b7280;text-decoration:none;background:rgba(255,255,255,0.9);padding:4px 8px;border-radius:4px;border:1px solid #e5e7eb;">
|
||||||
|
Cookie-Einstellungen
|
||||||
|
</a>
|
||||||
`.trim()
|
`.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,6 +412,31 @@ function generateJS(config: CookieBannerConfig): string {
|
|||||||
overlay?.classList.remove('active');
|
overlay?.classList.remove('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Script-Blocking: activate scripts with data-cookie-category ONLY after consent
|
||||||
|
function activateConsentedScripts() {
|
||||||
|
const consent = getConsent();
|
||||||
|
if (!consent) return;
|
||||||
|
|
||||||
|
// Find all blocked scripts (type="text/plain" with data-cookie-category)
|
||||||
|
document.querySelectorAll('script[data-cookie-category][type="text/plain"]').forEach(script => {
|
||||||
|
const category = script.getAttribute('data-cookie-category');
|
||||||
|
if (consent[category] === true) {
|
||||||
|
// Replace type to activate the script
|
||||||
|
const newScript = document.createElement('script');
|
||||||
|
if (script.src) newScript.src = script.src;
|
||||||
|
else newScript.textContent = script.textContent;
|
||||||
|
newScript.type = 'text/javascript';
|
||||||
|
script.parentNode.replaceChild(newScript, script);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also fire custom event for programmatic listeners
|
||||||
|
window.dispatchEvent(new CustomEvent('cookieConsentActivated', { detail: consent }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run script activation after consent is saved
|
||||||
|
window.addEventListener('cookieConsentUpdated', activateConsentedScripts);
|
||||||
|
|
||||||
window.CookieConsent = {
|
window.CookieConsent = {
|
||||||
getConsent,
|
getConsent,
|
||||||
saveConsent,
|
saveConsent,
|
||||||
@@ -405,14 +445,32 @@ function generateJS(config: CookieBannerConfig): string {
|
|||||||
document.getElementById('cookieBanner')?.classList.add('active');
|
document.getElementById('cookieBanner')?.classList.add('active');
|
||||||
document.getElementById('cookieBannerOverlay')?.classList.add('active');
|
document.getElementById('cookieBannerOverlay')?.classList.add('active');
|
||||||
},
|
},
|
||||||
hide: closeBanner
|
hide: closeBanner,
|
||||||
|
activateScripts: activateConsentedScripts,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', initBanner);
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
initBanner();
|
||||||
|
activateConsentedScripts();
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
initBanner();
|
initBanner();
|
||||||
|
activateConsentedScripts();
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* USAGE: Script-Blocking
|
||||||
|
*
|
||||||
|
* Instead of:
|
||||||
|
* <script src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXX"></script>
|
||||||
|
*
|
||||||
|
* Use:
|
||||||
|
* <script type="text/plain" data-cookie-category="statistics"
|
||||||
|
* src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXX"></script>
|
||||||
|
*
|
||||||
|
* The script will only execute AFTER the user consents to "statistics".
|
||||||
|
*/
|
||||||
`.trim()
|
`.trim()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user