1/** 2 * @format 3 * Simple Cookie Banner JavaScript 4 * Version: 1.6.7 5 * Author: MWS (https://mws.co.il) 6 * Includes WordPress Privacy Policy integration 7 */ 8 9// scb-script.js - Vanilla JS cookie consent 10(function () { 11 // Check if jQuery is available, if not, create a simple fallback 12 if (typeof jQuery === 'undefined') { 13 window.jQuery = function(selector) { 14 if (typeof selector === 'string') { 15 const elements = document.querySelectorAll(selector); 16 // Add jQuery-like methods 17 elements.is = function(selector) { 18 if (selector === ':visible') { 19 return this.length > 0 && this[0].offsetWidth > 0 && this[0].offsetHeight > 0; 20 } 21 return false; 22 }; 23 return elements; 24 } 25 return selector; 26 }; 27 window.$ = window.jQuery; 28 } 29 30 const name = (window.scbSettings && scbSettings.cookieName) || "scb_consent"; 31 const expiryDays = (window.scbSettings && scbSettings.expiryDays) || 365; 32 const isPrivacyPage = (window.scbSettings && scbSettings.isPrivacyPage) || false; 33 34 // Prevent multiple initializations 35 if (window.scbInitialized) return; 36 window.scbInitialized = true; 37 38 // === ת×ר×× ×××××× â ×× ×©××ר×× ×××× ××¤× × ××ש×ר === 39 (function(w){ 40 // ת×ר×× ×××××× â ×× ×©××ר×× ×××× ××¤× × ××ש×ר 41 w.dataLayer = Array.isArray(w.dataLayer) ? w.dataLayer : []; 42 w.gtag = w.gtag || function(){ w.dataLayer.push(arguments); }; 43 44 w.ga = w.ga || function(){ (w.ga.q = w.ga.q || []).push(arguments); }; 45 w.fbq = w.fbq || function(){ (w.fbq.q = w.fbq.q || []).push(arguments); }; 46 w._fbq = w._fbq || w.fbq; 47 48 // ×× ×ש ×× PixelYourSite 49 w.dataLayerPYS = Array.isArray(w.dataLayerPYS) ? w.dataLayerPYS : []; 50 })(window); 51 52 // === Domain-based analytics blocker (only until consent) === 53 (function(){ 54 // ×§××ת ×××¦× ×××¢×××× ×©× ×ת×סף 55 function getConsent() { 56 var m = document.cookie.match(/(?:^| )scb_consent=([^;]+)/); 57 if (!m) return null; 58 try { return JSON.parse(decodeURIComponent(m[1])); } catch(e){ return null; } 59 } 60 function analyticsAllowed(){ 61 var c = getConsent(); 62 return !!(c && (c.analytics === true || c.marketing === true || c.all === true)); 63 } 64 65 // ×× ××ס××× - רק ×××××× ×× ×©× ×× ×××××§×ת 66 var ANALYTICS_RE = /(googletagmanager\.com|google-analytics\.com|doubleclick\.net|connect\.facebook\.net|clarity\.ms|bat\.bing\.com|hotjar|tiktok|snap|linkedin|plausible|umami)/i; 67 // ×× ×× ××ס××× (תש××××× ×××× ×××) 68 var PAYMENTS_WHITELIST = /(tranzila|cardcom|pelecard|cgpay|apple-pay|paypal|stripe)/i; 69 70 function isTrackerUrl(u){ 71 if (!u) return false; 72 var url = String(u); 73 if (PAYMENTS_WHITELIST.test(url)) return false; 74 return ANALYTICS_RE.test(url); 75 } 76 77 // ×ס××ת SCRIPT/IFRAME ×§××××× - רק ×ר×ת ××¢×× ×ª ×§×צ×× 78 function blockElement(el){ 79 if (el.dataset.consentProcessed || analyticsAllowed()) return; 80 if (el.tagName === 'SCRIPT') { 81 var src = el.getAttribute('src'); 82 if (isTrackerUrl(src)) { 83 el.setAttribute('data-scb-src', src); 84 el.removeAttribute('src'); 85 el.type = 'text/plain'; 86 el.dataset.consent = 'analytics'; 87 el.dataset.consentBlocked = 'true'; 88 el.dataset.consentProcessed = 'true'; 89 } 90 } else if (el.tagName === 'IFRAME') { 91 var srcI = el.getAttribute('src'); 92 if (isTrackerUrl(srcI)) { 93 el.setAttribute('data-scb-src', srcI); 94 el.removeAttribute('src'); 95 el.style.display = 'none'; 96 el.dataset.consent = 'analytics'; 97 el.dataset.consentBlocked = 'true'; 98 el.dataset.consentProcessed = 'true'; 99 } 100 } 101 } 102 103 // סר××§× ×¨×ש×× ×ת ×××§××ת 104 if (!analyticsAllowed()) { 105 document.querySelectorAll('script[src],iframe[src]').forEach(blockElement); 106 } 107 108 // ××¢×§× ××ר ×××× ××× ××ש×× ×ש×× ×××× ×-src 109 var mo = new MutationObserver(function(records){ 110 if (analyticsAllowed()) return; 111 records.forEach(function(rec){ 112 if (rec.type === 'childList') {
113 rec.addedNodes.forEach(function(n){ 114 if (n.nodeType === 1) { 115 if ((n.tagName === 'SCRIPT' || n.tagName === 'IFRAME')) blockElement(n); 116 // ×× ××××× ××¤× ×× 117 n.querySelectorAll && n.querySelectorAll('script[src],iframe[src]').forEach(blockElement); 118 } 119 }); 120 } 121 }); 122 }); 123 124 // ×ת××ת ×××¢×§× 125 if (document.body) { 126 mo.observe(document.body, { childList: true, subtree: true }); 127 } else { 128 document.addEventListener('DOMContentLoaded', function() { 129 if (document.body) { 130 mo.observe(document.body, { childList: true, subtree: true }); 131 } 132 }); 133 } 134 })(); 135 136 // === Cookie Consent Banner Management === 137 138 // Global functions for external use 139 window.SCB_acceptAllTracking = function() { 140 141 142 const consentData = { 143 essential: true, 144 analytics: true, 145 marketing: true, 146 all: true, 147 timestamp: Date.now() 148 }; 149 150 // Save consent 151 setCookie(consentData); 152 153 // Update Google Consent Mode 154 if (typeof gtag !== 'undefined') { 155 gtag('consent', 'update', { 156 analytics_storage: 'granted', 157 ad_storage: 'granted', 158 ad_user_data: 'granted', 159 ad_personalization: 'granted' 160 }); 161 } 162 163 // Restore blocked elements immediately 164 restoreBlockedElements('marketing'); 165 166 // Also restore elements blocked by the old system 167 restoreOldBlockedElements(); 168 169 // Ensure gtag is available after consent 170 ensureGtagAvailable(); 171 172 // Hide banner 173 hideBanner(); 174 175 // Trigger custom event 176 window.dispatchEvent(new CustomEvent('scb-consent-given', { detail: consentData })); 177 178 179 }; 180 181 window.SCB_acceptAnalytics = function() { 182 const consentData = { 183 essential: true, 184 analytics: true, 185 marketing: false, 186 all: false, 187 timestamp: Date.now() 188 }; 189 190 // Save consent 191 setCookie(consentData); 192 193 // Update Google Consent Mode 194 if (typeof gtag !== 'undefined') { 195 gtag('consent', 'update', { 196 analytics_storage: 'granted', 197 ad_storage: 'denied', 198 ad_user_data: 'denied', 199 ad_personalization: 'denied' 200 }); 201 } 202 203 // Restore blocked elements immediately 204 restoreBlockedElements('analytics'); 205 206 // Also restore elements blocked by the old system 207 restoreOldBlockedElements(); 208 209 // Ensure gtag is available after consent 210 ensureGtagAvailable(); 211 212 // Hide banner 213 hideBanner(); 214 215 // Trigger custom event 216 window.dispatchEvent(new CustomEvent('scb-consent-given', { detail: consentData })); 217 }; 218 219 window.SCB_rejectAll = function() { 220 const consentData = { 221 essential: true, 222 analytics: false, 223 marketing: false, 224 all: false, 225 timestamp: Date.now() 226 }; 227 228 // Save consent 229 setCookie(consentData); 230 231 // Update Google Consent Mode 232 if (typeof gtag !== 'undefined') { 233 gtag('consent', 'update', { 234 analytics_storage: 'denied', 235 ad_storage: 'denied', 236 ad_user_data: 'denied', 237 ad_personalization: 'denied' 238 }); 239 } 240 241 // Hide banner 242 hideBanner(); 243 244 // Trigger custom event 245 window.dispatchEvent(new CustomEvent('scb-consent-rejected', { detail: consentData })); 246 }; 247 248 window.SCB_changeConsent = function() { 249 // Remove existing consent 250 document.cookie = name + '=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT'; 251 try { localStorage.removeItem(name); } catch(e) {} 252 253 // Show banner again 254 showBanner(); 255 256 // Trigger custom event 257 window.dispatchEvent(new CustomEvent('scb-consent-changed')); 258 }; 259 260 // === Immediate release function === 261 window.SCB_releaseBlocked = function() { 262 // This function is for backward compatibility 263 restoreOldBlockedElements(); 264 restoreBlockedElements('marketing'); 265 266 // Also ensure gtag is available 267 ensureGtagAvailable(); 268 }; 269 270 // === Ensure gtag is available === 271 function ensureGtagAvailable() { 272 // Check if gtag is already available 273 if (typeof gtag !== 'undefined') { 274 return; 275 } 276 277 // Look for Google Tag Manager script 278 const gtmScript = document.querySelector('script[src*="googletagmanager.com"]'); 279 if (gtmScript) { 280 // Wait for GTM to load and then check for gtag 281 const checkGtag = setInterval(function() { 282 if (typeof gtag !== 'undefined') { 283 clearInterval(checkGtag); 284 console.log('SCB: gtag is now available'); 285 } 286 }, 100); 287 288 // Timeout after 5 seconds 289 setTimeout(function() { 290 clearInterval(checkGtag); 291 if (typeof gtag === 'undefined') { 292 console.warn('SCB: gtag not available after timeout'); 293 } 294 }, 5000); 295 } 296 } 297 298 // === Fix malformed scripts === 299 function fixMalformedScripts() { 300 // Disabled for performance - causing page loading issues 301 return; 302 } 303 304 // === Remove duplicate tags === 305 function removeDuplicateTags() { 306 // Disabled for performance - causing page loading issues 307 return; 308 } 309 310 // === Global function to ensure gtag is available === 311 window.SCB_ensureGtag = function() { 312 ensureGtagAvailable(); 313 }; 314 315 // === Global function to fix malformed scripts === 316 window.SCB_fixMalformedScripts = function() { 317 fixMalformedScripts(); 318 }; 319 320 // === Accept selected cookies function === 321 window.SCB_acceptSelectedCookies = function() { 322 323 324 // Check if privacy policy is accepted 325 const privacyCheckbox = document.getElementById('scb-privacy-accept'); 326 if (!privacyCheckbox || !privacyCheckbox.checked) { 327 alert('×ש ××שר ×ת ×××× ××ת ×פר×××ת ××¤× × ××ש×ר ××¢××××ת'); 328 if (privacyCheckbox) { 329 privacyCheckbox.focus(); 330 } 331 return; 332 } 333 334 // Get the selected cookie preferences 335 const analyticsToggle = document.getElementById('analytics-toggle'); 336 const marketingToggle = document.getElementById('marketing-toggle'); 337 338 if (!analyticsToggle || !marketingToggle) { 339 340 return; 341 } 342 343 const consentData = { 344 essential: true, 345 analytics: analyticsToggle.checked, 346 marketing: marketingToggle.checked, 347 all: analyticsToggle.checked && marketingToggle.checked, 348 timestamp: Date.now() 349 }; 350 351 352 353 // Save consent
354 setCookie(consentData); 355 356 // Update Google Consent Mode based on selections 357 if (typeof gtag !== 'undefined') { 358 gtag('consent', 'update', { 359 analytics_storage: analyticsToggle.checked ? 'granted' : 'denied', 360 ad_storage: marketingToggle.checked ? 'granted' : 'denied', 361 ad_user_data: marketingToggle.checked ? 'granted' : 'denied', 362 ad_personalization: marketingToggle.checked ? 'granted' : 'denied' 363 }); 364 } 365 366 // Restore blocked elements based on consent 367 if (analyticsToggle.checked || marketingToggle.checked) { 368 const consentType = marketingToggle.checked ? 'marketing' : 'analytics'; 369 restoreBlockedElements(consentType); 370 restoreOldBlockedElements(); 371 372 // Ensure gtag is available after consent 373 ensureGtagAvailable(); 374 } 375 376 // Hide banner 377 hideBanner(); 378 379 // Trigger custom event 380 window.dispatchEvent(new CustomEvent('scb-consent-given', { detail: consentData })); 381 382 383 }; 384 385 // === Advanced automatic script blocking system === 386 function initializeAdvancedBlocking() { 387 // Block all scripts and iframes with data-consent attribute 388 function blockElements() { 389 const scripts = document.querySelectorAll('script[data-consent]:not([data-consent-processed])'); 390 const iframes = document.querySelectorAll('iframe[data-consent]:not([data-consent-processed])'); 391 392 scripts.forEach(script => { 393 if (!script.hasAttribute('data-consent-blocked')) { 394 script.type = 'text/plain'; 395 script.setAttribute('data-consent-blocked', 'true'); 396 script.setAttribute('data-consent-processed', 'true'); 397 } 398 }); 399 400 iframes.forEach(iframe => { 401 if (!iframe.hasAttribute('data-consent-blocked')) { 402 const placeholder = document.createElement('div'); 403 placeholder.className = 'scb-iframe-placeholder'; 404 placeholder.innerHTML = '<div style="padding: 20px; text-align: center; background: #f5f5f5; border: 2px dashed #ccc; color: #666;">ת××× ×× × ××¡× ×¢× ×××ש×ר ×¢××××ת</div>'; 405 406 iframe.parentNode.insertBefore(placeholder, iframe); 407 iframe.style.display = 'none'; 408 iframe.setAttribute('data-consent-blocked', 'true'); 409 iframe.setAttribute('data-consent-processed', 'true'); 410 } 411 }); 412 } 413 414 // Block existing elements 415 blockElements(); 416 417 // Block dynamically added elements 418 const observer = new MutationObserver(function(mutations) { 419 mutations.forEach(function(mutation) { 420 mutation.addedNodes.forEach(function(node) { 421 if (node.nodeType === 1) { // Element node 422 if (node.tagName === 'SCRIPT' && node.getAttribute('data-consent') && !node.getAttribute('data-consent-processed')) { 423 node.type = 'text/plain'; 424 node.setAttribute('data-consent-blocked', 'true'); 425 node.setAttribute('data-consent-processed', 'true'); 426 } else if (node.tagName === 'IFRAME' && node.getAttribute('data-consent') && !node.getAttribute('data-consent-processed')) { 427 const placeholder = document.createElement('div'); 428 placeholder.className = 'scb-iframe-placeholder'; 429 placeholder.innerHTML = '<div style="padding: 20px; text-align: center; background: #f5f5f5; border: 2px dashed #ccc; color: #666;">ת××× ×× × ××¡× ×¢× ×××ש×ר ×¢××××ת</div>'; 430 431 node.parentNode.insertBefore(placeholder, node); 432 node.style.display = 'none'; 433 node.setAttribute('data-consent-blocked', 'true'); 434 node.setAttribute('data-consent-processed', 'true'); 435 } 436 437 // Check child elements 438 const scripts = node.querySelectorAll && node.querySelectorAll('script[data-consent]:not([data-consent-processed])'); 439 const iframes = node.querySelectorAll && node.querySelectorAll('iframe[data-consent]:not([data-consent-processed])'); 440
441 if (scripts) scripts.forEach(script => { 442 script.type = 'text/plain'; 443 script.setAttribute('data-consent-blocked', 'true'); 444 script.setAttribute('data-consent-processed', 'true'); 445 }); 446 447 if (iframes) iframes.forEach(iframe => { 448 const placeholder = document.createElement('div'); 449 placeholder.className = 'scb-iframe-placeholder'; 450 placeholder.innerHTML = '<div style="padding: 20px; text-align: center; background: #f5f5f5; border: 2px dashed #ccc; color: #666;">ת××× ×× × ××¡× ×¢× ×××ש×ר ×¢××××ת</div>'; 451 452 iframe.parentNode.insertBefore(placeholder, iframe); 453 iframe.style.display = 'none'; 454 iframe.setAttribute('data-consent-blocked', 'true'); 455 iframe.setAttribute('data-consent-processed', 'true'); 456 }); 457 } 458 }); 459 }); 460 }); 461 462 // Only observe if document.body exists 463 if (document.body) { 464 observer.observe(document.body, { childList: true, subtree: true }); 465 } else { 466 // Wait for body to be available 467 document.addEventListener('DOMContentLoaded', function() { 468 if (document.body) { 469 observer.observe(document.body, { childList: true, subtree: true }); 470 } 471 }); 472 } 473 } 474 475 // === Restore blocked elements === 476 function restoreBlockedElements(consentType) { 477 // Restore scripts 478 const blockedScripts = document.querySelectorAll('script[data-consent-blocked]'); 479 blockedScripts.forEach(script => { 480 const consentAttr = script.getAttribute('data-consent'); 481 if (shouldRestoreElement(consentAttr, consentType)) { 482 const newScript = document.createElement('script'); 483 484 // Copy all attributes 485 for (let i = 0; i < script.attributes.length; i++) { 486 const attr = script.attributes[i]; 487 if (attr.name !== 'data-consent-blocked') { 488 newScript.setAttribute(attr.name, attr.value); 489 } 490 } 491 492 script.parentNode.replaceChild(newScript, script); 493 } 494 }); 495 496 // Restore iframes 497 const blockedIframes = document.querySelectorAll('iframe[data-consent-blocked]'); 498 blockedIframes.forEach(iframe => { 499 const consentAttr = iframe.getAttribute('data-consent'); 500 if (shouldRestoreElement(consentAttr, consentType)) { 501 iframe.style.display = ''; 502 iframe.removeAttribute('data-consent-blocked'); 503 504 // Remove placeholder 505 const placeholder = iframe.previousElementSibling; 506 if (placeholder && placeholder.classList.contains('scb-iframe-placeholder')) { 507 placeholder.remove(); 508 } 509 } 510 }); 511 512 // Also restore any elements with data-scb-src (old system) 513 restoreOldBlockedElements(); 514 } 515 516 // === Restore old blocked elements (compatibility) === 517 function restoreOldBlockedElements() { 518 try { 519 // Restore scripts blocked by the old system 520 const oldBlockedScripts = document.querySelectorAll('script[type="text/plain"][data-consent="analytics"][data-scb-src]'); 521 522 oldBlockedScripts.forEach(function(oldScript) { 523 try { 524 const src = oldScript.getAttribute('data-scb-src'); 525 526 // Only restore if it's actually a blocked script, not a meta/link wrapper 527 if (src && !oldScript.innerHTML.includes('<meta') && !oldScript.innerHTML.includes('<link')) { 528 const newScript = document.createElement('script'); 529 530 // Copy all attributes 531 for (let i = 0; i < oldScript.attributes.length; i++) { 532 const attr = oldScript.attributes[i]; 533 if (attr.name === 'type' || attr.name === 'data-consent' || attr.name === 'data-scb-src' || attr.name === 'data-consent-blocked') continue; 534 newScript.setAttribute(attr.name, attr.value); 535 } 536 537 if (src) newScript.src = src; 538 if (oldScript.textContent && !src) newScript.text = oldScript.textContent; 539 540 oldScript.parentNode.replaceChild(newScript, oldScript); 541 } else { 542 // This is not a real script, just remove the blocking attributes 543 oldScript.removeAttribute('data-consent'); 544 oldScript.removeAttribute('data-scb-src'); 545 oldScript.removeAttribute('data-consent-blocked'); 546 oldScript.type = 'text/javascript'; 547 } 548 } catch (e) { 549 console.warn('SCB: Error restoring old blocked script:', e); 550 } 551 }); 552 553 // Restore iframes blocked by the old system 554 const oldBlockedIframes = document.querySelectorAll('iframe[data-consent="analytics"][data-scb-src]'); 555
556 oldBlockedIframes.forEach(function(iframe) { 557 try { 558 const src = iframe.getAttribute('data-scb-src'); 559 if (src) { 560 iframe.style.display = ''; 561 iframe.removeAttribute('data-consent-blocked'); 562 iframe.removeAttribute('data-scb-src'); 563 iframe.setAttribute('src', src); 564 } 565 } catch (e) { 566 console.warn('SCB: Error restoring old blocked iframe:', e); 567 } 568 }); 569 } catch (e) { 570 console.warn('SCB: Error in restoreOldBlockedElements:', e); 571 } 572 } 573 574 575 576 // Helper function to determine if element should be restored 577 function shouldRestoreElement(consentAttr, consentType) { 578 if (!consentAttr) return false; 579 580 switch (consentType) { 581 case 'essential': 582 return consentAttr === 'essential'; 583 case 'analytics': 584 return consentAttr === 'analytics' || consentAttr === 'essential'; 585 case 'marketing': 586 return consentAttr === 'marketing' || consentAttr === 'analytics' || consentAttr === 'essential'; 587 default: 588 return false; 589 } 590 } 591 592 // === Banner Management Functions === 593 function showBanner() { 594 const banner = document.getElementById("scb-banner"); 595 596 if (banner) { 597 // Remove hidden classes 598 banner.classList.remove('scb-hidden'); 599 600 // Show banner only (no overlay) 601 banner.style.display = 'block'; 602 603 // Don't prevent scroll (no overlay) 604 // document.body.classList.remove('scb-open'); 605 } else { 606 console.warn('SCB: Banner not found'); 607 } 608 } 609 610 function hideBanner() { 611 const banner = document.getElementById("scb-banner"); 612 const settings = document.getElementById("scb-settings"); 613 614 if (banner) { 615 // Hide banner with multiple methods 616 banner.style.display = 'none'; 617 618 // Also add CSS classes to ensure it stays hidden 619 banner.classList.add('scb-hidden'); 620 621 // Reset settings section 622 if (settings) { 623 settings.style.display = 'none'; 624 } 625 } else { 626 console.warn('SCB: Banner not found in hideBanner'); 627 } 628 } 629 630 function setLoadingState(loading) { 631 const banner = document.getElementById("scb-banner"); 632 if (banner) { 633 if (loading) { 634 banner.classList.add('loading'); 635 } else { 636 banner.classList.remove('loading'); 637 } 638 } 639 } 640 641 // === Initialize the banner === 642 function initBanner() { 643 const banner = document.getElementById("scb-banner"); 644 645 // Check if banner element exists 646 if (!banner) { 647 console.warn('SCB: Banner not found in initBanner'); 648 return; 649 } 650 651 // Check if user already gave consent 652 const stored = getConsent(); 653 654 if (stored && (stored.essential || stored.analytics || stored.marketing || stored.all)) { 655 // User already consented, hide banner permanently 656 hideBanner(); 657 return; 658 } 659 660 // If no consent, show banner after 1 second 661 setTimeout(() => { 662 showBanner(); 663 }, 1000); 664 665 // Initialize banner functionality 666 initBannerFunctionality(); 667 } 668 669 function initBannerFunctionality() { 670 // Custom preferences button - toggle settings visibility 671 const customBtn = document.getElementById('scb-custom-preferences'); 672 const settings = document.getElementById('scb-settings'); 673 674 if (customBtn && settings) { 675 customBtn.addEventListener('click', function() { 676 if (settings.style.display === 'none') { 677 settings.style.display = 'block'; 678 customBtn.textContent = '×סתר ×××ר×ת'; 679 } else { 680 settings.style.display = 'none'; 681 customBtn.textContent = '××ר ס××× ×¢××××ת'; 682 } 683 }); 684 } 685 686 // Initialize settings as hidden by default 687 if (settings) { 688 settings.style.display = 'none'; 689 } 690 691 // Add event listeners to toggle switches using event delegation 692 const analyticsToggle = document.getElementById('analytics-toggle'); 693 const marketingToggle = document.getElementById('marketing-toggle'); 694 695 696 697 // Add direct click listeners to toggle labels 698 const analyticsLabel = document.querySelector('.analytics-toggle'); 699 const marketingLabel = document.querySelector('.marketing-toggle'); 700 701 702 703 if (analyticsLabel) { 704 analyticsLabel.addEventListener('click', function(e) { 705 e.preventDefault(); 706 e.stopPropagation(); 707 708 if (analyticsToggle) { 709 analyticsToggle.checked = !analyticsToggle.checked; 710 711 updateToggleAppearance('analytics-toggle', analyticsToggle.checked); 712 } 713 }); 714 } 715 716 if (marketingLabel) { 717 marketingLabel.addEventListener('click', function(e) { 718 e.preventDefault(); 719 e.stopPropagation(); 720 721 if (marketingToggle) { 722 marketingToggle.checked = !marketingToggle.checked; 723 724 updateToggleAppearance('marketing-toggle', marketingToggle.checked); 725 } 726 }); 727 } 728 729 // Also add direct event listeners as backup 730 if (analyticsToggle) { 731 analyticsToggle.addEventListener('change', function() { 732 733 updateToggleAppearance('analytics-toggle', this.checked); 734 }); 735 736 // Force initial state update 737 updateToggleAppearance('analytics-toggle', analyticsToggle.checked); 738 } 739 740 if (marketingToggle) { 741 marketingToggle.addEventListener('change', function() { 742 743 updateToggleAppearance('marketing-toggle', this.checked); 744 }); 745 746 // Force initial state update 747 updateToggleAppearance('marketing-toggle', marketingToggle.checked); 748 } 749 } 750 751 // Function to update toggle appearance 752 function updateToggleAppearance(toggleClass, isChecked) { 753 754 755 const toggleLabel = document.querySelector('.' + toggleClass); 756 757 758 if (toggleLabel) { 759 if (isChecked) { 760 toggleLabel.style.background = '#3b82f6'; 761 const slider = toggleLabel.querySelector('.scb-toggle-slider'); 762 if (slider) { 763 slider.style.transform = 'translateX(24px)'; 764 765 } 766 // Add active class and data attribute 767 toggleLabel.classList.add('active'); 768 toggleLabel.classList.remove('inactive'); 769 toggleLabel.setAttribute('data-state', 'active'); 770 } else { 771 toggleLabel.style.background = '#cbd5e1'; 772 const slider = toggleLabel.querySelector('.scb-toggle-slider'); 773 if (slider) { 774 slider.style.transform = 'translateX(0)'; 775 776 } 777 // Remove active class and add inactive data attribute 778 toggleLabel.classList.remove('active'); 779 toggleLabel.classList.add('inactive'); 780 toggleLabel.setAttribute('data-state', 'inactive'); 781 } 782 783 // Force CSS update with multiple methods 784 toggleLabel.style.display = 'inline-block'; 785 toggleLabel.offsetHeight; // Force reflow 786 787 // Also try to force a repaint 788 toggleLabel.style.transform = 'translateZ(0)'; 789 790 791 } else { 792 793 } 794 } 795 796 // === Utility Functions === 797 function setCookie(data) { 798 const cookieValue = encodeURIComponent(JSON.stringify(data)); 799 const expires = new Date(); 800 expires.setTime(expires.getTime() + (expiryDays * 24 * 60 * 60 * 1000)); 801 802 // Set cookie with longer expiration 803 document.cookie = `${name}=${cookieValue}; expires=${expires.toUTCString()}; path=/; SameSite=Lax${location.protocol === 'https:' ? '; Secure' : ''}`; 804 805 // Also save to localStorage as backup 806 try { 807 localStorage.setItem(name, JSON.stringify(data)); 808 809 } catch (e) { 810 console.warn('SCB: Local storage not available'); 811 } 812 813 814 } 815 816 function getConsent() { 817 try { 818 const stored = localStorage.getItem(name); 819 if (stored) return JSON.parse(stored); 820 } catch (e) { 821 // Local storage not available 822 } 823 824 const match = document.cookie.match(new RegExp('(?:^| )' + name + '=([^;]+)')); 825 if (match) {
826 try { 827 return JSON.parse(decodeURIComponent(match[1])); 828 } catch (e) { 829 return null; 830 } 831 } 832 833 return null; 834 } 835 836 // === Initialize everything === 837 function initialize() { 838 839 840 // Initialize advanced blocking 841 initializeAdvancedBlocking(); 842 843 // Initialize banner 844 if (document.readyState === 'loading') { 845 846 document.addEventListener('DOMContentLoaded', initBanner); 847 } else { 848 849 initBanner(); 850 } 851 } 852 853 // Start initialization 854 initialize(); 855 856 // Ensure jQuery is available globally 857 if (typeof jQuery === 'undefined') { 858 console.warn('SCB: jQuery not found, using fallback'); 859 } 860 861 // Global function to safely use jQuery 862 window.safeJQuery = function(callback) { 863 if (typeof jQuery !== 'undefined') { 864 callback(jQuery); 865 } else { 866 // Wait for jQuery to load 867 const checkJQuery = setInterval(function() { 868 if (typeof jQuery !== 'undefined') { 869 clearInterval(checkJQuery); 870 callback(jQuery); 871 } 872 }, 100); 873 874 // Timeout after 10 seconds 875 setTimeout(function() { 876 clearInterval(checkJQuery); 877 console.warn('SCB: jQuery timeout, using fallback'); 878 callback(window.jQuery); 879 }, 10000); 880 } 881 }; 882 883 // Global function to wait for jQuery and then execute 884 window.waitForJQuery = function(callback) { 885 if (document.readyState === 'loading') { 886 document.addEventListener('DOMContentLoaded', function() { 887 window.safeJQuery(callback); 888 }); 889 } else { 890 window.safeJQuery(callback); 891 } 892 }; 893 894})(window, document);
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.