1/** 2 * Keeper Cookie Consent 3 * 4 * Handles GDPR-compliant cookie consent with: 5 * - Banner (desktop) and popup/modal (mobile) display 6 * - localStorage-based consent state 7 * - Google Consent Mode v2 integration 8 * - Body class state management 9 */ 10 11(function() { 12 'use strict'; 13 14 var KeeperCookieConsent = { 15 popup: true, // true = "Cookie Preferences" state, false = "Withdraw" state 16 17 /** 18 * Initialize the cookie consent system 19 */ 20 init: function() { 21 this.registerEventListeners(); 22 this.handleConsentUI(); 23 }, 24 25 /** 26 * Check if device is mobile (viewport < 768px) 27 */ 28 isMobile: function() { 29 return !window.matchMedia('(min-width: 768px)').matches; 30 }, 31 32 /** 33 * Check if user has given consent 34 */ 35 hasConsent: function() { 36 return localStorage.getItem('keeper_cookie_consent') === 'true'; 37 }, 38 39 /** 40 * Set consent state and update UI/analytics accordingly 41 */ 42 setConsent: function(consent) { 43 var body = document.body; 44 45 if (consent === null || consent === undefined) { 46 body.classList.remove('user-cookie-consent'); 47 body.classList.remove('no-cookie-consent'); 48 body.classList.remove('cookie-consent'); 49 return; 50 } 51 52 localStorage.setItem('keeper_cookie_consent', consent); 53 54 if (consent === 'true' || consent === true) { 55 body.classList.add('user-cookie-consent'); 56 body.classList.remove('no-cookie-consent'); 57 body.classList.remove('cookie-consent'); 58 59 // Update Google Consent Mode v2 60 if (typeof gtag === 'function') { 61 gtag('consent', 'update', { 62 ad_storage: 'granted', 63 ad_user_data: 'granted', 64 ad_personalization: 'granted', 65 analytics_storage: 'granted' 66 }); 67 } 68 69 // Update Bing UET consent 70 window.uetq = window.uetq || []; 71 window.uetq.push('consent', 'update', { 72 ad_storage: 'granted' 73 }); 74 75 // Push to dataLayer 76 window.dataLayer = window.dataLayer || []; 77 window.dataLayer.push({event: 'keeper_cookie_consent'}); 78 } 79 80 if (consent === 'false' || consent === false) { 81 body.classList.add('no-cookie-consent'); 82 body.classList.remove('user-cookie-consent'); 83 body.classList.remove('cookie-consent'); 84 85 // Update Google Consent Mode v2 86 if (typeof gtag === 'function') { 87 gtag('consent', 'update', { 88 ad_storage: 'denied', 89 ad_user_data: 'denied', 90 ad_personalization: 'denied', 91 analytics_storage: 'denied' 92 }); 93 } 94 95 // Update Bing UET consent 96 window.uetq = window.uetq || []; 97 window.uetq.push('consent', 'update', { 98 ad_storage: 'denied' 99 }); 100 101 // Push to dataLayer 102 window.dataLayer = window.dataLayer || []; 103 window.dataLayer.push({event: 'no_keeper_cookie_consent'}); 104 } 105 }, 106 107 /** 108 * Register all event listeners 109 */ 110 registerEventListeners: function() { 111 var self = this; 112 113 // Accept button click 114 document.addEventListener('click', function(event) { 115 if (event.target.classList.contains('cookie_accept')) { 116 event.preventDefault(); 117 self.setConsent('true'); 118 119 // Check if this is from banner or popup 120 var giveConsent = event.target.getAttribute('data-give-consent'); 121 if (giveConsent === 'popup') { 122 self.disablePopup(); 123 } else if (giveConsent === 'banner') { 124 self.popup = false;
125 } 126 127 self.updatePopupVisibility(); 128 } 129 }); 130 131 // Decline button click 132 document.addEventListener('click', function(event) { 133 if (event.target.classList.contains('cookie_decline')) { 134 event.preventDefault(); 135 self.setConsent('false'); 136 self.triggerResize(); 137 } 138 }); 139 140 // Withdraw button click 141 document.addEventListener('click', function(event) { 142 if (event.target.classList.contains('cookie_withdraw')) { 143 event.preventDefault(); 144 self.setConsent('false'); 145 self.disablePopup(); 146 147 // Reload page to apply changes 148 window.location.reload(); 149 } 150 }); 151 152 // Cancel button click (close popup without action) 153 document.addEventListener('click', function(event) { 154 if (event.target.classList.contains('cookie_cancel')) { 155 event.preventDefault(); 156 self.disablePopup(); 157 158 // If it also has cookie_cancel_consent, decline consent 159 if (event.target.classList.contains('cookie_cancel_consent')) { 160 self.setConsent('false'); 161 } 162 } 163 }); 164 165 // Close popup via overlay click 166 document.addEventListener('click', function(event) { 167 if (event.target.matches('#cookie-consent-popup .overlay')) { 168 self.disablePopup(); 169 } 170 }); 171 172 // Close popup via close button 173 document.addEventListener('click', function(event) { 174 if (event.target.matches('[data-close="cookie-consent-popup"]') || 175 event.target.closest('[data-close="cookie-consent-popup"]')) { 176 self.disablePopup(); 177 } 178 }); 179 180 // Mobile popup trigger 181 document.addEventListener('click', function(event) { 182 if (event.target.matches('#cookie_onload_popup')) { 183 event.preventDefault(); 184 self.enablePopup(); 185 } 186 }); 187 188 // Show consent popup trigger (for footer link) 189 document.addEventListener('click', function(event) { 190 if (event.target.classList.contains('show_consent_popup') || 191 event.target.closest('.show_consent_popup')) { 192 event.preventDefault(); 193 self.enablePopup(); 194 // Show withdraw options 195 self.showElements('[data-show-on-popup="false"]'); 196 } 197 }); 198
199 // Check for cookie-consent-popup URL parameter 200 if (this.getUrlParam('cookie-consent-popup')) { 201 this.enablePopup(); 202 } 203 }, 204 205 /** 206 * Handle initial consent UI state 207 */ 208 handleConsentUI: function() { 209 var consentStatus = localStorage.getItem('keeper_cookie_consent'); 210 211 if (consentStatus === undefined || consentStatus === null || 212 consentStatus === 'false' || consentStatus === false) { 213 214 if (this.isMobile()) { 215 // Mobile: show popup instead of banner 216 this.popup = true; 217 var trigger = document.getElementById('cookie_onload_popup'); 218 if (trigger) { 219 trigger.click(); 220 } 221 } else { 222 // Desktop: show banner 223 this.setConsent(null); 224 this.triggerResize(); 225 } 226 } else if (consentStatus === 'true' || consentStatus === true) { 227 this.setConsent('true'); 228 this.popup = false; 229 } 230 231 this.updatePopupVisibility(); 232 }, 233 234 /** 235 * Enable/show the popup modal 236 */ 237 enablePopup: function() { 238 var body = document.body; 239 var popup = document.getElementById('cookie-consent-popup'); 240 var overlay = popup ? popup.querySelector('.overlay') : null; 241 242 body.classList.add('no-scroll'); 243 244 // Add blur effect to main content 245 var blurElements = document.querySelectorAll('.header, .main, .footer'); 246 blurElements.forEach(function(el) { 247 el.classList.add('blurForModal'); 248 }); 249 250 if (popup) { 251 popup.classList.add('moduleVisible'); 252 } 253 if (overlay) { 254 overlay.classList.add('overlayVisible'); 255 } 256 }, 257 258 /** 259 * Disable/hide the popup modal 260 */ 261 disablePopup: function() { 262 var body = document.body; 263 var popup = document.getElementById('cookie-consent-popup'); 264 var overlay = popup ? popup.querySelector('.overlay') : null; 265 266 body.classList.remove('no-scroll'); 267 268 // Remove blur effect 269 var blurElements = document.querySelectorAll('.header, .main, .footer'); 270 blurElements.forEach(function(el) { 271 el.classList.remove('blurForModal'); 272 }); 273 274 if (popup) { 275 popup.classList.remove('moduleVisible'); 276 } 277 if (overlay) { 278 overlay.classList.remove('overlayVisible'); 279 } 280 281 this.popup = false; 282 }, 283 284 /** 285 * Update popup visibility based on consent state 286 */ 287 updatePopupVisibility: function() { 288 var showOnPopupTrue = document.querySelectorAll('[data-show-on-popup="true"]'); 289 var showOnPopupFalse = document.querySelectorAll('[data-show-on-popup="false"]'); 290 291 // Hide all first 292 showOnPopupTrue.forEach(function(el) { el.style.display = 'none'; }); 293 showOnPopupFalse.forEach(function(el) { el.style.display = 'none'; }); 294 295 // Show appropriate elements 296 var selector = this.popup ? '[data-show-on-popup="true"]' : '[data-show-on-popup="false"]'; 297 document.querySelectorAll(selector).forEach(function(el) { 298 el.style.display = ''; 299 }); 300 301 // If consent is false, hide the withdraw options 302 var consentStatus = localStorage.getItem('keeper_cookie_consent'); 303 if (consentStatus === 'false' || consentStatus === false) { 304 showOnPopupFalse.forEach(function(el) { el.style.display = 'none'; }); 305 } 306 }, 307 308 /** 309 * Show elements by selector 310 */ 311 showElements: function(selector) { 312 document.querySelectorAll(selector).forEach(function(el) { 313 el.style.display = ''; 314 }); 315 }, 316 317 /** 318 * Trigger window resize event 319 */ 320 triggerResize: function() { 321 window.dispatchEvent(new Event('resize')); 322 }, 323 324 /** 325 * Get URL parameter value 326 */ 327 getUrlParam: function(name) {
328 var urlParams = new URLSearchParams(window.location.search); 329 return urlParams.get(name); 330 } 331 }; 332 333 // Initialize when DOM is ready 334 if (document.readyState === 'loading') { 335 document.addEventListener('DOMContentLoaded', function() { 336 KeeperCookieConsent.init(); 337 }); 338 } else { 339 KeeperCookieConsent.init(); 340 } 341 342 // Expose to global scope for external access if needed 343 window.KeeperCookieConsent = KeeperCookieConsent; 344 345})();
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.