1(function () { 2 "use strict"; 3 4 var config = window.CaseFoxConsentConfig || {}; 5 var STORAGE_KEY = 6 typeof config.storageKey === "string" && config.storageKey 7 ? config.storageKey 8 : "casefox_cookie_consent"; 9 var CONSENT_VERSION = 10 parseInt(config.consentVersion, 10) > 0 11 ? parseInt(config.consentVersion, 10) 12 : 1; 13 var COOKIE_MAX_AGE = 60 * 60 * 24 * 365; 14 var FOCUSABLE_SELECTOR = 15 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'; 16 17 var loaded = { 18 googleAnalytics: false, 19 googleTagManager: false, 20 metaPixel: false 21 }; 22 23 var currentConsent = null; 24 var lastFocusedElement = null; 25 26 function isEnabled(value) { 27 return value === true || value === 1 || value === "1"; 28 } 29 30 function analyticsCategoryEnabled() { 31 return isEnabled(config.analyticsEnabled); 32 } 33 34 function marketingCategoryEnabled() { 35 return isEnabled(config.marketingEnabled); 36 } 37 38 function normalizeServiceId(value) { 39 return typeof value === "string" ? value.trim().toUpperCase() : ""; 40 } 41 42 function normalizePixelId(value) { 43 return typeof value === "string" ? value.trim() : ""; 44 } 45 46 function getGaMeasurementId() { 47 var id = normalizeServiceId(config.gaMeasurementId); 48 return /^G-[A-Z0-9]+$/.test(id) ? id : ""; 49 } 50 51 function getGtmContainerId() { 52 var id = normalizeServiceId(config.gtmContainerId); 53 return /^GTM-[A-Z0-9]+$/.test(id) ? id : ""; 54 } 55 56 function getMetaPixelId() { 57 var id = normalizePixelId(config.metaPixelId); 58 return /^[0-9]+$/.test(id) ? id : ""; 59 } 60 61 function normalize(consent) { 62 consent = consent && typeof consent === "object" ? consent : {}; 63 64 return { 65 version: CONSENT_VERSION, 66 essential: true, 67 analytics: 68 analyticsCategoryEnabled() && consent.analytics === true, 69 marketing: 70 marketingCategoryEnabled() && consent.marketing === true, 71 updatedAt: 72 typeof consent.updatedAt === "string" && 73 consent.updatedAt.length <= 40 74 ? consent.updatedAt 75 : "" 76 }; 77 } 78 79 function parseConsent(raw) { 80 if (!raw) { 81 return null; 82 } 83 84 try { 85 var parsed = JSON.parse(raw); 86 87 if (!parsed || typeof parsed !== "object") { 88 return null; 89 } 90 91 if ( 92 parsed.version && 93 parseInt(parsed.version, 10) !== CONSENT_VERSION 94 ) { 95 return null; 96 } 97 98 return normalize(parsed); 99 } catch (error) { 100 return null; 101 } 102 } 103 104 function readLocalStorage() { 105 try { 106 return window.localStorage.getItem(STORAGE_KEY); 107 } catch (error) { 108 return null; 109 } 110 } 111 112 function writeLocalStorage(value) { 113 try { 114 window.localStorage.setItem(STORAGE_KEY, value); 115 } catch (error) { 116 } 117 } 118 119 function removeLocalStorage() { 120 try { 121 window.localStorage.removeItem(STORAGE_KEY); 122 } catch (error) { 123 } 124 } 125 126 function readCookie() { 127 var name = encodeURIComponent(STORAGE_KEY) + "="; 128 var cookies; 129 130 try { 131 cookies = document.cookie ? document.cookie.split(";") : []; 132 } catch (error) { 133 return null; 134 } 135 136 for (var index = 0; index < cookies.length; index += 1) { 137 var cookie = cookies[index].trim(); 138 139 if (cookie.indexOf(name) === 0) { 140 try { 141 return decodeURIComponent(cookie.substring(name.length)); 142 } catch (error) { 143 return null; 144 } 145 } 146 } 147 148 return null; 149 } 150 151 function writeCookie(value) { 152 var cookie = 153 encodeURIComponent(STORAGE_KEY) + 154 "=" + 155 encodeURIComponent(value) + 156 "; Max-Age=" + 157 COOKIE_MAX_AGE + 158 "; Path=/; SameSite=Lax"; 159 160 if (window.location.protocol === "https:") { 161 cookie += "; Secure"; 162 } 163 164 try { 165 document.cookie = cookie; 166 } catch (error) { 167 } 168 } 169 170 function removeCookie() { 171 try { 172 document.cookie = 173 encodeURIComponent(STORAGE_KEY) + 174 "=; Max-Age=0; Path=/; SameSite=Lax"; 175 } catch (error) { 176 } 177 } 178 179 function getConsent() { 180 var stored; 181 182 if (currentConsent !== null) { 183 return normalize(currentConsent); 184 } 185 186 stored = parseConsent(readLocalStorage()) || parseConsent(readCookie()); 187 188 if (stored !== null) { 189 currentConsent = stored; 190 } 191 192 return stored; 193 } 194 195 function dispatchConsentEvent(name, detail) { 196 var event; 197 198 if (typeof window.CustomEvent === "function") { 199 event = new CustomEvent(name, { detail: detail }); 200 } else { 201 event = document.createEvent("CustomEvent"); 202 event.initCustomEvent(name, false, false, detail); 203 } 204 205 document.dispatchEvent(event); 206 } 207 208 function ensureGoogleDataLayer() { 209 window.dataLayer = window.dataLayer || []; 210 211 if (typeof window.gtag !== "function") { 212 window.gtag = function () { 213 window.dataLayer.push(arguments); 214 }; 215 } 216 } 217 218 function applyConsentControls(consent, command) { 219 var gaMeasurementId = getGaMeasurementId();
220 consent = normalize(consent); 221 222 if (gaMeasurementId) { 223 window["ga-disable-" + gaMeasurementId] = 224 consent.analytics !== true; 225 } 226 227 ensureGoogleDataLayer(); 228 window.gtag("consent", command || "update", { 229 analytics_storage: consent.analytics ? "granted" : "denied", 230 ad_storage: consent.marketing ? "granted" : "denied", 231 ad_user_data: consent.marketing ? "granted" : "denied", 232 ad_personalization: consent.marketing ? "granted" : "denied" 233 }); 234 235 if (typeof window.fbq === "function") { 236 window.fbq( 237 "consent", 238 consent.marketing ? "grant" : "revoke" 239 ); 240 } 241 } 242 243 function saveConsent(consent) { 244 var normalized = normalize(consent); 245 var serialized; 246 247 normalized.updatedAt = new Date().toISOString(); 248 currentConsent = normalized; 249 serialized = JSON.stringify(normalized); 250 251 writeLocalStorage(serialized); 252 writeCookie(serialized); 253 applyConsentControls(normalized); 254 255 dispatchConsentEvent("casefox:consentsaved", { 256 consent: normalized 257 }); 258 259 return normalized; 260 } 261 262 function hasAnalyticsConsent() { 263 var consent = getConsent(); 264 return consent !== null && consent.analytics === true; 265 } 266 267 function hasMarketingConsent() { 268 var consent = getConsent(); 269 return consent !== null && consent.marketing === true; 270 } 271 272 function activeConsent(consent) { 273 return consent ? normalize(consent) : normalize(getConsent()); 274 } 275 276 function tagManagerAllowed(consent) { 277 consent = activeConsent(consent); 278 279 if (consent.analytics !== true) { 280 return false; 281 } 282 283 if (!marketingCategoryEnabled()) { 284 return true; 285 } 286 287 return consent.marketing === true; 288 } 289 290 function loadGoogleAnalytics(measurementId) { 291 if (!measurementId || loaded.googleAnalytics) { 292 return; 293 } 294 295 loaded.googleAnalytics = true; 296 window["ga-disable-" + measurementId] = false; 297 ensureGoogleDataLayer(); 298 299 window.gtag("js", new Date()); 300 window.gtag("config", measurementId); 301 302 var script = document.createElement("script"); 303 script.async = true; 304 script.src = 305 "https://www.googletagmanager.com/gtag/js?id=" + 306 encodeURIComponent(measurementId); 307 document.head.appendChild(script); 308 } 309 310 function loadGoogleTagManager(containerId, consent) { 311 if ( 312 !containerId || 313 loaded.googleTagManager || 314 !tagManagerAllowed(consent) 315 ) { 316 return; 317 } 318 319 loaded.googleTagManager = true; 320 window.dataLayer = window.dataLayer || []; 321 window.dataLayer.push({ 322 "gtm.start": new Date().getTime(), 323 event: "gtm.js" 324 }); 325 326 var script = document.createElement("script"); 327 script.async = true; 328 script.src = 329 "https://www.googletagmanager.com/gtm.js?id=" + 330 encodeURIComponent(containerId); 331 document.head.appendChild(script); 332 } 333 334 function installMetaPixelQueue() { 335 var fbq; 336 337 if (typeof window.fbq === "function") { 338 return; 339 } 340 341 fbq = (window.fbq = function () { 342 if (fbq.callMethod) { 343 fbq.callMethod.apply(fbq, arguments); 344 } else { 345 fbq.queue.push(arguments); 346 } 347 }); 348 349 if (!window._fbq) { 350 window._fbq = fbq; 351 } 352 353 fbq.push = fbq; 354 fbq.loaded = true; 355 fbq.version = "2.0"; 356 fbq.queue = []; 357 } 358 359 function loadMetaPixel(pixelId) { 360 var fbqAlreadyLoaded = !!(window.fbq && window.fbq.loaded); 361 362 if (!pixelId || loaded.metaPixel) { 363 return; 364 } 365 366 loaded.metaPixel = true; 367 installMetaPixelQueue(); 368 369 if (!fbqAlreadyLoaded) { 370 var script = document.createElement("script"); 371 script.async = true; 372 script.src = "https://connect.facebook.net/en_US/fbevents.js"; 373 document.head.appendChild(script); 374 } 375 376 window.fbq("consent", "grant"); 377 window.fbq("init", pixelId); 378 window.fbq("track", "PageView"); 379 } 380 381 function loadAnalytics(consent) { 382 consent = activeConsent(consent); 383 384 if (!analyticsCategoryEnabled() || consent.analytics !== true) { 385 return; 386 } 387 388 applyConsentControls(consent); 389 loadGoogleAnalytics(getGaMeasurementId()); 390 loadGoogleTagManager(getGtmContainerId(), consent); 391 } 392 393 function loadMarketing(consent) { 394 consent = activeConsent(consent); 395 396 if (!marketingCategoryEnabled() || consent.marketing !== true) { 397 return; 398 } 399 400 applyConsentControls(consent); 401 loadMetaPixel(getMetaPixelId()); 402 loadGoogleTagManager(getGtmContainerId(), consent); 403 } 404 405 function loadAllowed(consent) { 406 consent = activeConsent(consent); 407 408 if (consent.analytics === true) { 409 loadAnalytics(consent); 410 } 411 412 if (consent.marketing === true) { 413 loadMarketing(consent); 414 } 415 } 416 417 function setElementHidden(element, hidden) { 418 if (!element) { 419 return; 420 } 421 422 element.hidden = hidden; 423 element.setAttribute("aria-hidden", hidden ? "true" : "false"); 424 } 425 426 function showBanner() { 427 setElementHidden( 428 document.getElementById("casefox-cookie-banner"), 429 false 430 ); 431 } 432 433 function hideBanner() { 434 setElementHidden( 435 document.getElementById("casefox-cookie-banner"), 436 true 437 ); 438 } 439 440 function getFocusableElements(container) { 441 var nodes = container.querySelectorAll(FOCUSABLE_SELECTOR); 442 443 return Array.prototype.filter.call(nodes, function (node) { 444 return ( 445 node.offsetParent !== null || 446 node === document.activeElement 447 ); 448 }); 449 } 450 451 function openPreferences(trigger) { 452 var modal = document.getElementById("casefox-cookie-preferences-modal"); 453 var consent; 454 var analyticsInput; 455 var marketingInput; 456 var focusTarget; 457 458 if (!modal) { 459 return; 460 } 461 462 lastFocusedElement = trigger || document.activeElement; 463 consent = getConsent() || normalize({}); 464 analyticsInput = document.getElementById("casefox-analytics"); 465 marketingInput = document.getElementById("casefox-marketing"); 466 467 if (analyticsInput) { 468 analyticsInput.checked = consent.analytics === true; 469 } 470 471 if (marketingInput) { 472 marketingInput.checked = consent.marketing === true; 473 } 474 475 setElementHidden(modal, false); 476 document.documentElement.classList.add( 477 "casefox-cookie-modal-open" 478 ); 479 480 focusTarget = 481 analyticsInput || 482 marketingInput || 483 modal.querySelector("[data-casefox-action='save-preferences']") || 484 modal; 485
486 if (focusTarget && typeof focusTarget.focus === "function") { 487 focusTarget.focus(); 488 } 489 } 490 491 function closePreferences() { 492 var modal = document.getElementById("casefox-cookie-preferences-modal"); 493 494 setElementHidden(modal, true); 495 document.documentElement.classList.remove( 496 "casefox-cookie-modal-open" 497 ); 498 499 if ( 500 lastFocusedElement && 501 document.documentElement.contains(lastFocusedElement) && 502 typeof lastFocusedElement.focus === "function" 503 ) { 504 lastFocusedElement.focus(); 505 } 506 507 lastFocusedElement = null; 508 } 509 510 function preferencesOpen() { 511 var modal = document.getElementById("casefox-cookie-preferences-modal"); 512 return !!modal && modal.hidden === false; 513 } 514 515 function trapModalFocus(event) { 516 var modal = document.getElementById("casefox-cookie-preferences-modal"); 517 var focusable; 518 var first; 519 var last; 520 521 if (!modal || event.key !== "Tab") { 522 return; 523 } 524 525 focusable = getFocusableElements(modal); 526 527 if (!focusable.length) { 528 event.preventDefault(); 529 modal.focus(); 530 return; 531 } 532 533 first = focusable[0]; 534 last = focusable[focusable.length - 1]; 535 536 if (event.shiftKey && document.activeElement === first) { 537 event.preventDefault(); 538 last.focus(); 539 } else if (!event.shiftKey && document.activeElement === last) { 540 event.preventDefault(); 541 first.focus(); 542 } 543 } 544 545 function acceptAll() { 546 var consent = saveConsent({ 547 essential: true, 548 analytics: true, 549 marketing: true 550 }); 551 552 hideBanner(); 553 loadAllowed(consent); 554 555 return consent; 556 } 557 558 function rejectAll() { 559 var consent = saveConsent({ 560 essential: true, 561 analytics: false, 562 marketing: false 563 }); 564 565 hideBanner(); 566 567 return consent; 568 } 569 570 function savePreferences() { 571 var analyticsInput = document.getElementById("casefox-analytics"); 572 var marketingInput = document.getElementById("casefox-marketing"); 573 var consent = saveConsent({ 574 essential: true, 575 analytics: analyticsInput 576 ? analyticsInput.checked === true 577 : false, 578 marketing: marketingInput 579 ? marketingInput.checked === true 580 : false 581 }); 582 583 closePreferences(); 584 hideBanner(); 585 loadAllowed(consent); 586 587 return consent; 588 } 589 590 function resetConsent() { 591 currentConsent = null; 592 removeLocalStorage(); 593 removeCookie(); 594 applyConsentControls(normalize({})); 595 showBanner(); 596 597 dispatchConsentEvent("casefox:consentreset", {}); 598 } 599 600 document.addEventListener("click", function (event) { 601 var target = event.target; 602 var control; 603 var action; 604 605 if (!target || typeof target.closest !== "function") { 606 return; 607 } 608 609 control = target.closest("[data-casefox-action]"); 610 611 if (!control) { 612 return; 613 } 614 615 action = control.getAttribute("data-casefox-action"); 616 617 if (action === "accept") { 618 event.preventDefault(); 619 acceptAll(); 620 } else if (action === "reject") { 621 event.preventDefault(); 622 rejectAll(); 623 } else if (action === "preferences" || action === "open-preferences") { 624 event.preventDefault(); 625 openPreferences(control); 626 } else if (action === "close-preferences") { 627 event.preventDefault(); 628 closePreferences(); 629 } else if (action === "save-preferences") { 630 event.preventDefault(); 631 savePreferences(); 632 } 633 }); 634 635 document.addEventListener("keydown", function (event) { 636 if (!preferencesOpen()) { 637 return; 638 } 639 640 if (event.key === "Escape") { 641 event.preventDefault(); 642 closePreferences(); 643 return; 644 } 645 646 trapModalFocus(event); 647 }); 648 649 function boot() { 650 var consent = getConsent(); 651 652 if (consent === null) { 653 applyConsentControls(normalize({}), "default"); 654 showBanner(); 655 return; 656 } 657 658 applyConsentControls(consent, "default"); 659 loadAllowed(consent); 660 } 661 662 if (document.readyState === "loading") { 663 document.addEventListener("DOMContentLoaded", boot); 664 } else { 665 boot(); 666 } 667 668 window.CaseFoxConsent = { 669 getConsent: getConsent, 670 saveConsent: saveConsent, 671 hasAnalyticsConsent: hasAnalyticsConsent, 672 hasMarketingConsent: hasMarketingConsent, 673 loadAnalytics: loadAnalytics, 674 loadMarketing: loadMarketing, 675 acceptAll: acceptAll, 676 rejectAll: rejectAll, 677 savePreferences: savePreferences, 678 openPreferences: openPreferences, 679 closePreferences: closePreferences, 680 resetConsent: resetConsent 681 }; 682})();
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.