/** * Cookie Consent Management System * All sensitive data (tracking IDs, URLs) are loaded from server-side PHP * Includes fallback for local file access (no server) * * @version 2.1.0 */ document.addEventListener('DOMContentLoaded', function() { // ========================================== // CONFIGURATION // ========================================== const cookieCategories = ['necessary', 'analytics', 'marketing']; const API_ENDPOINT = 'scripts/add/send.php'; // Detect if running from file:// protocol (no server) const isLocalFile = window.location.protocol === 'file:'; let consentState = { hasConsented: false, preferences: {} }; let previousPreferences = {}; let trackingScripts = {}; // ========================================== // DATALAYER INTEGRATION // ========================================== window.dataLayer = window.dataLayer || []; function pushConsentToDataLayer(preferences) { window.dataLayer.push({ 'event': 'consent_update', 'consent': { 'analytics_storage': preferences.analytics ? 'granted' : 'denied', 'ad_storage': preferences.marketing ? 'granted' : 'denied', 'functionality_storage': preferences.necessary ? 'granted' : 'denied', 'personalization_storage': preferences.marketing ? 'granted' : 'denied', 'security_storage': 'granted' } }); } function setDefaultConsent() { window.dataLayer.push({ 'event': 'consent_default', 'consent': { 'analytics_storage': 'denied', 'ad_storage': 'denied', 'functionality_storage': 'granted', 'personalization_storage': 'denied', 'security_storage': 'granted', 'wait_for_update': 500 } }); } // ========================================== // STORAGE (API + LOCALSTORAGE FALLBACK) // ========================================== async function saveConsentToStorage(preferences) { // Always save to localStorage as backup const consentData = { hasConsented: true, preferences: preferences, timestamp: new Date().toISOString() }; localStorage.setItem('cookieConsent', JSON.stringify(consentData)); // Try API if not local file if (!isLocalFile) { try { const response = await fetch(API_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'cookie_consent', preferences }) }); const result = await response.json(); if (result.success && result.data && result.data.scripts) { trackingScripts = result.data.scripts; } return result.success; } catch (e) { // API failed, localStorage already saved return false; } } return true; } async function getConsentFromStorage() { // Try localStorage first (faster) const localConsent = localStorage.getItem('cookieConsent'); if (localConsent) { try { return JSON.parse(localConsent); } catch (e) { localStorage.removeItem('cookieConsent'); } } // Try API if not local file if (!isLocalFile) { try { const response = await fetch(API_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'get_cookie_consent' }) }); const result = await response.json(); if (result.success && result.data) { if (result.data.scripts) { trackingScripts = result.data.scripts; } // Cache in localStorage localStorage.setItem('cookieConsent', JSON.stringify(result.data)); return result.data; } } catch (e) { // API unavailable } } return null; } // ========================================== // SCRIPT LOADING // ========================================== function loadTrackingScripts() { if (!trackingScripts || Object.keys(trackingScripts).length === 0) return; if (trackingScripts.ga && consentState.preferences.analytics) { loadGoogleAnalytics(trackingScripts.ga); } if (trackingScripts.gtm && consentState.preferences.analytics) { loadGTM(trackingScripts.gtm); } if (trackingScripts.fb && consentState.preferences.marketing) { loadFacebookPixel(trackingScripts.fb); } if (trackingScripts.gads && consentState.preferences.marketing) { loadGoogleAds(trackingScripts.gads); } if (trackingScripts.linkedin && consentState.preferences.marketing) { loadLinkedIn(trackingScripts.linkedin); } } function loadScript(src, callback) { const script = document.createElement('script'); script.src = src; script.async = true; if (callback) script.onload = callback; document.head.appendChild(script); } function loadGoogleAnalytics(config) { if (!config.src || !config.config || !config.config.id) return; loadScript(config.src, function() { window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} window.gtag = gtag; gtag('js', new Date()); gtag('config', config.config.id); }); } function loadGTM(config) { if (!config.id) return; (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer',config.id); } function loadFacebookPixel(config) { if (!config.id) return; !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod? n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n; n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0; t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window, document,'script','https://connect.facebook.net/en_US/fbevents.js'); fbq('init', config.id); fbq('track', 'PageView'); } function loadGoogleAds(config) { if (!config.id) return; loadScript('https://www.googletagmanager.com/gtag/js?id=' + config.id, function() { window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', config.id); }); } function loadLinkedIn(config) { if (!config.id) return; window._linkedin_partner_id = config.id; window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || []; window._linkedin_data_partner_ids.push(config.id); loadScript('https://snap.licdn.com/li.lms-analytics/insight.min.js'); } // ========================================== // COOKIE DELETION // ========================================== const cookiePatterns = { analytics: ['_ga', '_gid', '_gat', '__utma', '__utmb', '__utmc', '__utmz'], marketing: ['_fbp', '_fbc', 'fr', '_gcl_au', '_gcl_aw', 'IDE', 'DSID', 'NID'] }; function deleteCookie(name) { const paths = ['/', window.location.pathname]; const domains = ['', window.location.hostname, '.' + window.location.hostname]; paths.forEach(path => { domains.forEach(domain => { document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${path}${domain ? '; domain=' + domain : ''}`; }); }); } function deleteCookiesForCategory(category) { const patterns = cookiePatterns[category] || []; const allCookies = document.cookie.split(';'); allCookies.forEach(cookie => { const cookieName = cookie.split('=')[0].trim(); patterns.forEach(pattern => { if (cookieName.startsWith(pattern)) { deleteCookie(cookieName); } }); }); } function handlePreferenceChanges(newPreferences) { Object.keys(cookiePatterns).forEach(category => { if (previousPreferences[category] === true && newPreferences[category] === false) { deleteCookiesForCategory(category); window.dataLayer.push({ 'event': 'consent_revoked', 'consent_category': category }); } }); previousPreferences = { ...newPreferences }; } // ========================================== // DOM ELEMENTS // ========================================== const cookieBanner = document.getElementById('cookieBanner'); const cookieModal = document.getElementById('cookieModal'); const acceptAllBtn = document.getElementById('cookieAcceptAll'); const rejectAllBtn = document.getElementById('cookieRejectAll'); const settingsBtn = document.getElementById('cookieSettings'); const modalCloseBtn = document.getElementById('cookieModalClose'); const savePreferencesBtn = document.getElementById('cookieSavePreferences'); // ========================================== // CORE FUNCTIONS // ========================================== async function initCookieConsent() { setDefaultConsent(); const savedConsent = await getConsentFromStorage(); if (savedConsent && savedConsent.hasConsented) { consentState = { hasConsented: true, preferences: savedConsent.preferences || {} }; previousPreferences = { ...consentState.preferences }; applyConsentPreferences(); return; } // Show banner after short delay setTimeout(() => { if (cookieBanner) cookieBanner.classList.add('show'); }, 500); } function applyConsentPreferences() { pushConsentToDataLayer(consentState.preferences); loadTrackingScripts(); window.dispatchEvent(new CustomEvent('cookieConsentUpdated', { detail: consentState.preferences })); } async function saveConsent(preferences) { handlePreferenceChanges(preferences); await saveConsentToStorage(preferences); consentState = { hasConsented: true, preferences: preferences, timestamp: new Date().toISOString() }; applyConsentPreferences(); } function hideBanner() { if (cookieBanner) cookieBanner.classList.remove('show'); } function showSettingsModal() { if (cookieModal) { cookieModal.classList.add('show'); populateSettingsModal(); } } function hideSettingsModal() { if (cookieModal) cookieModal.classList.remove('show'); } function populateSettingsModal() { cookieCategories.forEach(key => { const toggle = document.getElementById(`cookie-toggle-${key}`); if (!toggle) return; const isEnabled = consentState.preferences[key] || false; const isRequired = key === 'necessary'; if (isRequired) { toggle.classList.add('active', 'disabled'); toggle.setAttribute('aria-checked', 'true'); toggle.setAttribute('aria-disabled', 'true'); } else { toggle.classList.toggle('active', isEnabled); toggle.setAttribute('aria-checked', isEnabled ? 'true' : 'false'); toggle.onclick = () => { toggle.classList.toggle('active'); toggle.setAttribute('aria-checked', toggle.classList.contains('active') ? 'true' : 'false'); }; } }); } function getModalPreferences() { const preferences = {}; cookieCategories.forEach(key => { const toggle = document.getElementById(`cookie-toggle-${key}`); preferences[key] = key === 'necessary' ? true : (toggle ? toggle.classList.contains('active') : false); }); return preferences; } // ========================================== // EVENT LISTENERS // ========================================== if (acceptAllBtn) { acceptAllBtn.addEventListener('click', () => { const preferences = {}; cookieCategories.forEach(key => preferences[key] = true); saveConsent(preferences); hideBanner(); }); } if (rejectAllBtn) { rejectAllBtn.addEventListener('click', () => { saveConsent({ necessary: true, analytics: false, marketing: false }); hideBanner(); }); } if (settingsBtn) { settingsBtn.addEventListener('click', showSettingsModal); } if (modalCloseBtn) { modalCloseBtn.addEventListener('click', hideSettingsModal); } if (savePreferencesBtn) { savePreferencesBtn.addEventListener('click', () => { saveConsent(getModalPreferences()); hideSettingsModal(); hideBanner(); }); } if (cookieModal) { cookieModal.addEventListener('click', (e) => { if (e.target === cookieModal) hideSettingsModal(); }); } document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && cookieModal && cookieModal.classList.contains('show')) { hideSettingsModal(); } }); // ========================================== // PUBLIC API // ========================================== window.CookieConsent = { getConsent: () => consentState, hasConsent: (category) => consentState.preferences[category] === true, updateConsent: saveConsent, showSettings: showSettingsModal }; // ========================================== // INITIALIZE // ========================================== initCookieConsent(); });