1// The server emits this initializer only on eligible production pages. 2// Watch streamed article HTML without polling, database reads, or repeated ad refreshes. 3(() => { 4 const loader = document.getElementById('tep-adsense-loader'); 5 if (!loader || window.tepAdSenseStarted) return; 6 window.tepAdSenseStarted = true; 7 8 const client = new URL(loader.src).searchParams.get('client'); 9 const selector = 'ins.adsbygoogle[data-ad-client][data-ad-slot]'; 10 const requested = new WeakSet(); 11 const pending = new Set(); 12 let frame = 0; 13 let stopped = false; 14 const resize = typeof ResizeObserver === 'function' ? new ResizeObserver(schedule) : null; 15 16 function forget(slot) { 17 pending.delete(slot); 18 resize?.unobserve(slot); 19 } 20 21 function schedule() { 22 if (!stopped && !frame) frame = requestAnimationFrame(flush); 23 } 24 25 function flush() { 26 frame = 0; 27 for (const slot of pending) { 28 if (!slot.isConnected || requested.has(slot) || slot.hasAttribute('data-adsbygoogle-status')) { 29 forget(slot); 30 continue; 31 } 32 // Responsive units cannot be requested until their container has a real width. 33 if (slot.getBoundingClientRect().width <= 0) continue; 34 requested.add(slot); 35 forget(slot);
36 try { 37 (window.adsbygoogle = window.adsbygoogle || []).push({}); 38 } catch (error) { 39 // A blocked/failed ad must never interfere with reading the article. 40 // Do not repeatedly retry a slot: that can generate duplicate impressions. 41 console.warn('An advertisement could not be initialized.', error); 42 } 43 } 44 } 45 46 function collect(root) { 47 if (root.nodeType !== 1) return; 48 const slots = root.matches(selector) ? [root] : root.querySelectorAll(selector); 49 for (const slot of slots) { 50 if (slot.getAttribute('data-ad-client') !== client || requested.has(slot) || 51 slot.hasAttribute('data-adsbygoogle-status') || pending.has(slot) || 52 slot.closest('[contenteditable], [data-ads-disabled]')) continue; 53 pending.add(slot); 54 resize?.observe(slot); 55 } 56 if (pending.size) schedule(); 57 } 58 59 const observer = new MutationObserver(records => { 60 for (const record of records) { 61 for (const node of record.addedNodes) collect(node); 62 } 63 // Release removed, not-yet-visible slots as well. 64 if (pending.size) schedule(); 65 }); 66 67 function start() { 68 stopped = false; 69 observer.observe(document.body, { childList: true, subtree: true }); 70 collect(document.body); 71 } 72 73 window.addEventListener('resize', schedule, { passive: true }); 74 window.addEventListener('pagehide', () => { 75 stopped = true; 76 observer.disconnect(); 77 resize?.disconnect(); 78 if (frame) cancelAnimationFrame(frame); 79 frame = 0; 80 pending.clear(); 81 }); 82 // Back/forward cache restores reuse existing filled units, without requesting them again. 83 window.addEventListener('pageshow', event => { if (event.persisted) start(); }); 84 start(); 85})();
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.