1(function () { 2 'use strict'; 3 4 // Pick once per page so all placements stay synchronized, even with page caching. 5 const rotations = document.querySelectorAll('[data-eb-campaign-rotation]'); 6 if (rotations.length) { 7 const campaigns = Array.from(rotations[0].querySelectorAll('template[data-eb-campaign]')).map((template) => template.dataset.ebCampaign); 8 let previous = ''; 9 try { 10 previous = sessionStorage.getItem('eb-ad-last-campaign') || ''; 11 } catch (_) {} 12 const choices = campaigns.length > 1 ? campaigns.filter((name) => name !== previous) : campaigns; 13 const campaign = choices[Math.floor(Math.random() * choices.length)]; 14 try { sessionStorage.setItem('eb-ad-last-campaign', campaign); } catch (_) {} 15 rotations.forEach((rotation) => { 16 const template = rotation.querySelector('template[data-eb-campaign="' + campaign + '"]'); 17 if (!template) return; 18 rotation.querySelector('[data-eb-campaign-active]').replaceChildren(template.content.cloneNode(true)); 19 }); 20 } 21 22 // Hosts may override redirect cache headers; each navigation needs a fresh URL. 23 function freshCampaignLink(event) { 24 const link = event.target.closest && event.target.closest('a[href*="eb_ad_click="]'); 25 if (!link) return; 26 const url = new URL(link.href); 27 if (url.origin !== window.location.origin) return; 28 url.searchParams.set('click_ref', window.crypto.randomUUID()); 29 link.href = url.href; 30 } 31 document.addEventListener('click', freshCampaignLink, true); 32 document.addEventListener('auxclick', freshCampaignLink, true); 33 document.addEventListener('contextmenu', freshCampaignLink, true); 34 35 const desktopQuery = window.matchMedia('(min-width: 1440px)'); 36 const root = document.documentElement; 37 const rails = Array.from(document.querySelectorAll('[data-eb-side-ad-rail]')); 38 const units = Array.from(document.querySelectorAll('[data-eb-ad-unit]')); 39 const content = document.querySelector('.page-box'); 40 const minWidth = 120; 41 const maxWidth = 160; 42 const preferredGap = 12; 43 let libraryRequested = false; 44 let libraryLoaded = false; 45 let initialisationFrame = 0; 46 let frame = 0; 47 48 const takeover = rails.some((rail) => rail.querySelector('[data-eb-takeover]')); 49 if ((units.length === 0 && rails.length === 0 && !document.querySelector('.eb-header-ad')) || !content) return; 50 51 function isVisible(element) { 52 if (!element) return false; 53 const style = window.getComputedStyle(element); 54 const rect = element.getBoundingClientRect(); 55 return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0; 56 } 57 58 function hasBlockingOverlay(top, height) { 59 const search = document.querySelector('.search-overlay.open, .search-overlay[aria-hidden="false"]'); 60 if (isVisible(search)) return true; 61 62 const blockers = document.querySelectorAll([ 63 '#cookie-notice', 64 '.cookie-notice-container', 65 '.cky-consent-container', 66 '.cc-window', 67 '.cmplz-cookiebanner', 68 '#cmplz-cookiebanner-container', 69 '[class*="cookie-banner"]', 70 '[id*="cookie-banner"]' 71 ].join(',')); 72 73 for (const blocker of blockers) { 74 if (!isVisible(blocker)) continue; 75 const rect = blocker.getBoundingClientRect(); 76 if (rect.top < top + height && rect.bottom > top) return true; 77 } 78 79 const footer = document.querySelector('.elementor-location-footer, footer.site-footer, footer[role="contentinfo"]'); 80 if (!takeover && footer && footer.getBoundingClientRect().top < top + height + 16) return true; 81 82 return false; 83 } 84 85 function initialiseVisibleUnits() { 86 window.adsbygoogle = window.adsbygoogle || []; 87 units.forEach((unit) => { 88 if (!isVisible(unit) || unit.dataset.ebAdInitialised === '1') return; 89 unit.dataset.ebAdInitialised = '1'; 90 try { 91 window.adsbygoogle.push({}); 92 } catch (error) { 93 unit.dataset.ebAdStatus = 'error'; 94 } 95 }); 96 } 97 98 function scheduleUnitInitialisation() { 99 if (initialisationFrame) return; 100 initialisationFrame = window.requestAnimationFrame(() => { 101 initialisationFrame = window.requestAnimationFrame(() => { 102 initialisationFrame = 0; 103 initialiseVisibleUnits(); 104 }); 105 }); 106 } 107 108 function markLibraryLoaded() { 109 libraryLoaded = true; 110 scheduleUnitInitialisation(); 111 } 112 113 function requestLibrary() { 114 if (window.ebSideAdConfig && !window.ebSideAdConfig.loadLibrary) return; 115 if (!libraryRequested) { 116 libraryRequested = true;
117 const publisher = units.map((unit) => unit.dataset.adClient || '').find(Boolean); 118 if (!publisher) return; 119 const source = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=' + encodeURIComponent(publisher); 120 let script = document.querySelector('script[src*="pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"]'); 121 if (!script) { 122 script = document.createElement('script'); 123 script.async = true; 124 script.src = source; 125 script.crossOrigin = 'anonymous'; 126 script.addEventListener('load', markLibraryLoaded, { once: true }); 127 document.head.appendChild(script); 128 } else if (window.adsbygoogle && window.adsbygoogle.loaded) { 129 libraryLoaded = true; 130 } else { 131 script.addEventListener('load', markLibraryLoaded, { once: true }); 132 } 133 } 134 if (libraryLoaded) scheduleUnitInitialisation(); 135 } 136 137 function updateLayout() { 138 frame = 0; 139 if (rails.length === 0) { 140 root.classList.remove('eb-side-ads-enabled', 'eb-side-ads-obscured'); 141 requestLibrary(); 142 return; 143 } 144 if (!desktopQuery.matches) { 145 root.classList.remove('eb-side-ads-enabled', 'eb-side-ads-obscured'); 146 requestLibrary(); 147 return; 148 } 149 150 const viewportWidth = document.documentElement.clientWidth; 151 const contentRect = content.getBoundingClientRect(); 152 const leftSpace = Math.max(0, contentRect.left); 153 const rightSpace = Math.max(0, viewportWidth - contentRect.right); 154 const railSpaces = rails.map((rail) => rail.dataset.ebSideAdRail === 'left' ? leftSpace : rightSpace); 155 const available = Math.floor(Math.min(...railSpaces)); 156 if (available < minWidth) { 157 root.classList.remove('eb-side-ads-enabled', 'eb-side-ads-obscured'); 158 requestLibrary(); 159 return; 160 } 161 162 const gap = takeover ? 0 : Math.max(0, Math.min(preferredGap, available - minWidth)); 163 const width = takeover ? available : Math.min(maxWidth, available - gap); 164 const left = Math.max(0, Math.round(contentRect.left - gap - width)); 165 const right = Math.max(0, Math.round(viewportWidth - contentRect.right - gap - width)); 166 const top = 0; 167 const height = window.innerHeight; 168 169 root.style.setProperty('--eb-side-ad-width', width + 'px'); 170 root.style.setProperty('--eb-side-ad-left', left + 'px'); 171 root.style.setProperty('--eb-side-ad-right', right + 'px'); 172 root.classList.add('eb-side-ads-enabled'); 173 root.classList.toggle('eb-side-ads-obscured', hasBlockingOverlay(top, height)); 174 requestLibrary(); 175 } 176 177 function scheduleLayout() { 178 if (frame) return; 179 frame = window.requestAnimationFrame(updateLayout); 180 } 181 182 desktopQuery.addEventListener('change', scheduleLayout); 183 window.addEventListener('resize', scheduleLayout, { passive: true }); 184 window.addEventListener('scroll', scheduleLayout, { passive: true }); 185 document.addEventListener('visibilitychange', scheduleLayout); 186 187 const searchOverlay = document.querySelector('.search-overlay'); 188 if (window.MutationObserver && searchOverlay) { 189 new MutationObserver(scheduleLayout).observe(searchOverlay, { 190 attributes: true, 191 attributeFilter: ['class', 'aria-hidden'] 192 }); 193 } 194 195 scheduleLayout(); 196})();
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.