PageSourceSearch

https://scplumber.co.il/wp-content/plugins/cookie-consent-banner/assets/js/atr-scb.js?ver=1.6.7

js scplumber.co.il collected 2026-09-24 13:50:58 UTC 29,196 bytes, 894 lines download raw bytes

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.