${config.texts.title.de}
${config.texts.description.de}
${categoriesHTML}
`.trim()
}
// =============================================================================
// JS GENERATION
// =============================================================================
function generateJS(config: CookieBannerConfig): string {
const categoryIds = config.categories.map((c) => c.id)
const requiredCategories = config.categories.filter((c) => c.isRequired).map((c) => c.id)
return `
(function() {
'use strict';
const COOKIE_NAME = 'cookie_consent';
const COOKIE_EXPIRY_DAYS = 365;
const CATEGORIES = ${JSON.stringify(categoryIds)};
const REQUIRED_CATEGORIES = ${JSON.stringify(requiredCategories)};
// Google Consent Mode v2 โ PFLICHT seit Maerz 2024 fuer Google Services in EEA
// Sets default consent state to "denied" BEFORE any Google tags fire
if (typeof gtag === 'function') {
gtag('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
functionality_storage: 'granted',
security_storage: 'granted',
});
}
function updateGoogleConsentMode(consent) {
if (typeof gtag !== 'function') return;
gtag('consent', 'update', {
analytics_storage: consent.statistics ? 'granted' : 'denied',
ad_storage: consent.marketing ? 'granted' : 'denied',
ad_user_data: consent.marketing ? 'granted' : 'denied',
ad_personalization: consent.marketing ? 'granted' : 'denied',
});
}
function getConsent() {
const cookie = document.cookie.split('; ').find(row => row.startsWith(COOKIE_NAME + '='));
if (!cookie) return null;
try {
return JSON.parse(decodeURIComponent(cookie.split('=')[1]));
} catch {
return null;
}
}
function saveConsent(consent) {
const date = new Date();
date.setTime(date.getTime() + (COOKIE_EXPIRY_DAYS * 24 * 60 * 60 * 1000));
document.cookie = COOKIE_NAME + '=' + encodeURIComponent(JSON.stringify(consent)) +
';expires=' + date.toUTCString() +
';path=/;SameSite=Lax';
window.dispatchEvent(new CustomEvent('cookieConsentUpdated', { detail: consent }));
updateGoogleConsentMode(consent);
}
function hasConsent(category) {
const consent = getConsent();
if (!consent) return REQUIRED_CATEGORIES.includes(category);
return consent[category] === true;
}
function initBanner() {
const banner = document.getElementById('cookieBanner');
const overlay = document.getElementById('cookieBannerOverlay');
const details = document.getElementById('cookieBannerDetails');
if (!banner) return;
const consent = getConsent();
if (consent) return;
setTimeout(() => {
banner.classList.add('active');
overlay.classList.add('active');
}, 500);
document.getElementById('cookieBannerAccept')?.addEventListener('click', () => {
const consent = {};
CATEGORIES.forEach(cat => consent[cat] = true);
saveConsent(consent);
closeBanner();
});
document.getElementById('cookieBannerReject')?.addEventListener('click', () => {
const consent = {};
CATEGORIES.forEach(cat => consent[cat] = REQUIRED_CATEGORIES.includes(cat));
saveConsent(consent);
closeBanner();
});
document.getElementById('cookieBannerCustomize')?.addEventListener('click', () => {
details.classList.toggle('active');
});
document.getElementById('cookieBannerSave')?.addEventListener('click', () => {
const consent = {};
CATEGORIES.forEach(cat => {
const toggle = document.querySelector('.cookie-banner-toggle[data-category="' + cat + '"]');
consent[cat] = toggle?.classList.contains('active') || REQUIRED_CATEGORIES.includes(cat);
});
saveConsent(consent);
closeBanner();
});
document.querySelectorAll('.cookie-banner-toggle').forEach(toggle => {
if (toggle.dataset.required === 'true') return;
toggle.addEventListener('click', () => {
toggle.classList.toggle('active');
});
});
overlay?.addEventListener('click', () => {
// Don't close - user must make a choice
});
}
function closeBanner() {
const banner = document.getElementById('cookieBanner');
const overlay = document.getElementById('cookieBannerOverlay');
banner?.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 = {
getConsent,
saveConsent,
hasConsent,
show: () => {
document.getElementById('cookieBanner')?.classList.add('active');
document.getElementById('cookieBannerOverlay')?.classList.add('active');
},
hide: closeBanner,
activateScripts: activateConsentedScripts,
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
initBanner();
activateConsentedScripts();
});
} else {
initBanner();
activateConsentedScripts();
}
})();
/*
* USAGE: Script-Blocking
*
* Instead of:
*
*
* Use:
*
*
* The script will only execute AFTER the user consents to "statistics".
*/
`.trim()
}