1(function () { 2 function detectDevice() { 3 return (window.matchMedia && window.matchMedia("(max-width: 991px)").matches) 4 ? "phone" 5 : "computer"; 6 } 7 8 function normalizePagePath(path) { 9 try { 10 let p = String(path || "").trim(); 11 if (!p) return "/"; 12 13 if (/^[a-z][a-z0-9+.-]*:\/\//i.test(p) || p.indexOf("//") === 0) { 14 try { 15 p = new URL(p, (window.location && window.location.origin) ? window.location.origin : undefined).pathname || "/"; 16 } catch (e) {} 17 } 18 19 const hashIdx = p.indexOf("#"); 20 if (hashIdx >= 0) p = p.slice(0, hashIdx); 21 const queryIdx = p.indexOf("?"); 22 if (queryIdx >= 0) p = p.slice(0, queryIdx); 23 24 p = p.replace(/\\/g, "/").replace(/\/{2,}/g, "/"); 25 if (!p) p = "/"; 26 if (p.charAt(0) !== "/") p = "/" + p; 27 if (p.length > 1) p = p.replace(/\/+$/, ""); 28 return p || "/"; 29 } catch (e) { 30 return "/"; 31 } 32 } 33 34 function shuffle(arr) { 35 for (let i = arr.length - 1; i > 0; i--) { 36 const j = Math.floor(Math.random() * (i + 1)); 37 const tmp = arr[i]; 38 arr[i] = arr[j]; 39 arr[j] = tmp; 40 } 41 return arr; 42 } 43 44 function buildAdSlide(ad, block) { 45 // Source-of-truth slide node is the legacy wrapper itself 46 // (.adr.ad_###) directly under .adblock_carousel 47 const wrap = document.createElement("div"); 48 wrap.className = "adr ad_" + ad.id; 49 50 // IMPORTANT: Impression tracking must be enforced at render time. 51 // Only mark the ad as trackable when the server says tracking is enabled. 52 // impressions-beacon observes `[data-ad-id]` elements. 53 if (ad.track) { 54 wrap.setAttribute("data-ad-id", String(ad.id)); 55 } 56 57 // Keep the configured block dimensions as the maximum size, 58 // but allow the slide to shrink responsively with its container. 59 const bw = parseInt(block.width, 10); 60 const bh = parseInt(block.height, 10); 61 if (Number.isFinite(bw) && bw > 0) { 62 wrap.style.maxWidth = bw + "px"; 63 wrap.style.width = "100%"; 64 } 65 if (Number.isFinite(bh) && bh > 0) { 66 if (Number.isFinite(bw) && bw > 0) { 67 // Allows the height to scale with the width while preserving ratio. 68 wrap.style.aspectRatio = bw + " / " + bh; 69 wrap.style.height = "auto"; 70 } else { 71 // Without a width, we can't safely scale; reserve height only. 72 wrap.style.height = bh + "px"; 73 } 74 } 75 wrap.style.margin = "0 auto"; // Center within container when maxWidth is set 76 wrap.style.padding = "0"; 77 wrap.style.overflow = "hidden"; 78 79 // Image ad 80 if (ad.type === "image_ad") { 81 const imgUrl = 82 (block._device === "phone" && ad.mobile_img_url) 83 ? ad.mobile_img_url 84 : ad.img_url; 85 86 const img = document.createElement("img"); 87 img.src = imgUrl || ""; 88 img.alt = ad.title || "Advertisement"; 89 img.className = "adimage ultra-trackable" + (ad.track ? " impressionAdEnabled" : ""); 90 img.style.display = "block"; 91 // FIX: Ensure image scales responsively within its container 92 img.style.width = "100%"; 93 img.style.maxWidth = "100%"; 94 img.style.height = "auto"; 95 // For carousel slides (absolute positioned), use object-fit to maintain aspect ratio 96 img.style.objectFit = "contain"; 97 98 if (ad.link) { 99 const a = document.createElement("a"); 100 a.href = ad.link; 101 a.target = ad.target || "_self"; 102 a.rel = "nofollow noopener"; 103 a.setAttribute("aria-label", ad.title || "Advertisement"); 104 a.className = "adlink ad_" + ad.id + (ad.track ? " impressionAdEnabled" : ""); 105 // FIX: Ensure link wrapper doesn't constrain image responsiveness 106 a.style.display = "block"; 107 a.style.width = "100%"; 108 a.style.height = "100%"; 109 // NOTE: impressions-beacon needs to find data-ad-id; it's on <img> already 110 a.appendChild(img); 111 wrap.appendChild(a); 112 } else { 113 wrap.appendChild(img); 114 } 115 116 return wrap; 117 } 118 119 // Non-image ad 120 const inner = document.createElement("div"); 121 inner.innerHTML = ad.content_html || ""; 122 try { 123 const scripts = inner.querySelectorAll ? inner.querySelectorAll('script') : []; 124 if (scripts && scripts.length) {
125 scripts.forEach(function(oldScript){ 126 try { 127 const s = document.createElement('script'); 128 try { 129 if (oldScript.attributes && oldScript.attributes.length) { 130 for (let i = 0; i < oldScript.attributes.length; i++) { 131 const a = oldScript.attributes[i]; 132 if (a && a.name) s.setAttribute(a.name, a.value || ''); 133 } 134 } 135 } catch (e) {} 136 const code = oldScript.text || oldScript.textContent || ''; 137 if (code && !s.src) { 138 s.text = code; 139 } 140 if (oldScript.parentNode) { 141 oldScript.parentNode.replaceChild(s, oldScript); 142 } 143 } catch (e) {} 144 }); 145 } 146 } catch (e) {} 147 wrap.appendChild(inner); 148 149 return wrap; 150 } 151 152 153 /** 154 * Ad Rotation: the payload carries every eligible variant, and the browser 155 * picks one per page view. This has to happen here rather than on the server, 156 * because the payload is cached and shared â a server-side pick would show the 157 * same variant to everyone in that cache window and skew the A/B split. 158 * 159 * Even split: start at a random offset per browser, then step through the list 160 * on each following view. Starting everyone at index 0 would hand the first 161 * variant nearly every first impression. 162 */ 163 function pickRotationVariant(ad) { 164 if (!ad || !Array.isArray(ad.variants) || ad.variants.length === 0) return ad; 165 const variants = ad.variants; 166 if (variants.length === 1) return variants[0]; 167 168 const key = "srrAds:rot:" + (ad.rotation_parent || ad.id || "x"); 169 let i; 170 try { 171 const stored = window.sessionStorage.getItem(key); 172 i = stored === null ? Math.floor(Math.random() * variants.length) : (parseInt(stored, 10) || 0); 173 window.sessionStorage.setItem(key, String((i + 1) % variants.length)); 174 } catch (e) { 175 i = Math.floor(Math.random() * variants.length); 176 } 177 return variants[((i % variants.length) + variants.length) % variants.length]; 178 } 179 180 function renderBlock(container, payload) { 181 if (!payload || !payload.block) return; 182 183 // If the server explicitly said this block has no ads, hide the placeholder 184 if (payload.success === false || (Array.isArray(payload.ads) && payload.ads.length === 0)) { 185 container.innerHTML = ""; 186 container.style.display = "none"; 187 container.classList.add("srr-adblock-empty"); 188 return; 189 } 190 191 const block = payload.block || {}; 192 block._device = detectDevice(); 193 194 let ads = Array.isArray(payload.ads) ? payload.ads.slice() : []; 195 196 // Swap each Ad Rotation entry for one of its variants before anything else 197 // looks at the list, so ordering, dedupe and markup all use the real ad. 198 ads = ads.map(function (ad) { 199 return (ad && Array.isArray(ad.variants) && ad.variants.length) ? pickRotationVariant(ad) : ad; 200 }).filter(Boolean); 201 202 if (!ads.length) { 203 container.innerHTML = ""; 204 container.style.display = "none"; 205 container.classList.add("srr-adblock-empty"); 206 return; 207 } 208 209 // Normalize order (support old values) 210 const rawOrder = String(block.order || "").toLowerCase(); 211 const order = 212 (rawOrder === "rand" || rawOrder === "random") ? "random" : 213 (rawOrder === "menu_order" || rawOrder === "menuorder") ? "menu_order" : 214 (rawOrder === "date" || rawOrder.includes("date") || rawOrder.includes("sequential")) ? "menu_order" : 215 "random"; 216 217 const intervalSecRaw = parseInt(block.interval, 10); 218 const intSec = (Number.isFinite(intervalSecRaw) && intervalSecRaw > 0) ? intervalSecRaw : 7; 219 const timerMs = intSec * 1000; 220 const anim = String(block.anim || "opacity"); 221 222 // Outer wrapper 223 const outer = document.createElement("div"); 224 outer.className = "singlead"; 225 // FIX: Ensure outer wrapper is responsive 226 outer.style.width = "100%"; 227 outer.style.maxWidth = "100%"; 228 229 const blockEl = document.createElement("div"); 230 blockEl.id = "adblock_" + payload.id; 231 blockEl.className = "adblock"; 232 blockEl.setAttribute("data-block-id", String(payload.id)); 233 // FIX: Ensure block element is responsive 234 blockEl.style.width = "100%"; 235 blockEl.style.maxWidth = "100%"; 236 237 const blockType = String(block.type || "slider").toLowerCase(); 238 239 if (blockType === "single") { 240 // "Single Rotator" means: show ONE ad per instance of the block on the page, 241 // with NO animation/rotation. 242 // When the same block appears multiple times on the page, pick the next ad 243 // so each occurrence displays a different one.
244 const key = String(payload.id); 245 246 const rawAds = Array.isArray(payload.ads) ? payload.ads.slice() : []; 247 if (!rawAds.length) { 248 container.innerHTML = ""; 249 return; 250 } 251 252 // Sort ads deterministically by menu_order (if present) then by ID. 253 // Used both as the ordering for menu_order blocks and as a stable signature 254 // for cache-invalidation comparison when the ad set changes. 255 const sortedAds = rawAds.slice().sort(function(a, b) { 256 const orderA = parseInt(a.menu_order, 10) || 0; 257 const orderB = parseInt(b.menu_order, 10) || 0; 258 if (orderA !== orderB) return orderA - orderB; 259 const idA = parseInt(a.id, 10) || 0; 260 const idB = parseInt(b.id, 10) || 0; 261 return idA - idB; 262 }); 263 264 // Respect the block's configured order. For random blocks, shuffle once per 265 // page load so repeater copies cycle through a fresh random sequence. 266 const iterationOrder = (order === "random") ? shuffle(rawAds.slice()) : sortedAds; 267 268 // Signature from sorted ad IDs (order-independent) so random shuffles don't 269 // look like a changed ad set. 270 const sig = sortedAds.map((a) => String(a && a.id ? a.id : '')).join(','); 271 window.__srrSingleRotatorState = window.__srrSingleRotatorState || {}; 272 const state = window.__srrSingleRotatorState[key] || { idx: 0, sig: '', order: [] }; 273 274 if (!state.order || !state.order.length || state.sig !== sig) { 275 state.order = iterationOrder; 276 state.idx = 0; 277 state.sig = sig; 278 } 279 280 const picked = state.order[state.idx % state.order.length]; 281 state.idx = state.idx + 1; 282 window.__srrSingleRotatorState[key] = state; 283 284 // FIX: Use mobile dimensions when on phone and mobile ads exist 285 const mobileBw = parseInt(block.mobile_width, 10); 286 const mobileBh = parseInt(block.mobile_height, 10); 287 const useMobileDims = (block._device === "phone" && Number.isFinite(mobileBw) && mobileBw > 0 && Number.isFinite(mobileBh) && mobileBh > 0); 288 289 // Create modified block with effective dimensions for buildAdSlide 290 const effectiveBlock = useMobileDims 291 ? Object.assign({}, block, { width: mobileBw, height: mobileBh }) 292 : block; 293 294 const slide = buildAdSlide(picked, effectiveBlock); 295 slide.style.position = "relative"; 296 slide.style.display = "block"; 297 298 blockEl.appendChild(slide); 299 outer.appendChild(blockEl); 300 301 container.innerHTML = ""; 302 container.appendChild(outer); 303 // FIX: Clear placeholder's inline styles that could conflict with ad sizing 304 container.style.height = "auto"; 305 container.style.aspectRatio = ""; 306 container.style.maxWidth = ""; 307 308 if (window.dispatchEvent) { 309 try { 310 window.dispatchEvent(new CustomEvent("srr_ads:block_rendered", { detail: { id: payload.id } })); 311 } catch (e) {} 312 } 313 return; 314 } 315 316 if (order === "random") shuffle(ads); 317 318 if (blockType === "vertical") { 319 const widthPx = parseInt(block.width, 10); 320 const heightPx = parseInt(block.height, 10); 321 const verthPx = parseInt(block.verth, 10); 322 const verts = parseInt(block.verts, 10); 323 324 const vertical = document.createElement("div"); 325 vertical.id = "vertical-container_" + payload.id; 326 vertical.setAttribute("data-block-id", String(payload.id)); 327 if (Number.isFinite(widthPx) && widthPx > 0) vertical.setAttribute("data-width", String(widthPx)); 328 if (Number.isFinite(heightPx) && heightPx > 0) vertical.setAttribute("data-height", String(heightPx)); 329 if (Number.isFinite(verthPx) && verthPx > 0) vertical.setAttribute("data-verth", String(verthPx)); 330 if (Number.isFinite(verts) && verts > 0) vertical.setAttribute("data-verts", String(verts)); 331 // FIX: Ensure vertical container is responsive 332 vertical.style.width = "100%"; 333 vertical.style.maxWidth = "100%"; 334 335 const rotator = document.createElement("div"); 336 rotator.className = "adrotate_" + payload.id; 337 // FIX: Ensure rotator is responsive 338 rotator.style.width = "100%"; 339 rotator.style.maxWidth = "100%"; 340 341 // Vertical blocks are continuous scroll: stack ads naturally (no absolute positioning) 342 ads.forEach(function (ad) { 343 const node = buildAdSlide(ad, block); 344 node.style.position = "relative"; 345 node.style.display = "block"; 346 if (Number.isFinite(widthPx) && widthPx > 0) { 347 node.style.maxWidth = widthPx + "px"; 348 node.style.width = "100%"; 349 } 350 if (Number.isFinite(heightPx) && heightPx > 0) { 351 if (Number.isFinite(widthPx) && widthPx > 0) { 352 node.style.aspectRatio = widthPx + " / " + heightPx; 353 node.style.height = "auto"; 354 } else { 355 node.style.height = heightPx + "px"; 356 } 357 } 358 rotator.appendChild(node); 359 }); 360 361 vertical.appendChild(rotator); 362 blockEl.appendChild(vertical); 363 outer.appendChild(blockEl); 364 365 container.innerHTML = ""; 366 container.appendChild(outer); 367 368 // The placeholder shortcode reserves height using ad-block-verth. 369 // The runtime vertical slider clamps verth to the total slide height. 370 // Clear the placeholder's inline styles so vertical container controls sizing. 371 container.style.height = "auto"; 372 container.style.aspectRatio = ""; 373 container.style.maxWidth = ""; 374 375 if (window.SRRAdsRuntime && typeof window.SRRAdsRuntime.initAll === "function") { 376 window.__srrAdsRuntimeKick && clearTimeout(window.__srrAdsRuntimeKick); 377 window.__srrAdsRuntimeKick = setTimeout(function () { 378 try { window.SRRAdsRuntime.initAll(document); } catch(e) {} 379 }, 50); 380 } 381 382 if (window.dispatchEvent) { 383 try { 384 window.dispatchEvent(new CustomEvent("srr_ads:block_rendered", { detail: { id: payload.id } })); 385 } catch (e) {} 386 } 387 return; 388 } 389 390 // Carousel container (this is what SRRAdsRuntime should initialize) 391 const carousel = document.createElement("div"); 392 carousel.className = "adblock_carousel"; 393 carousel.id = "seq_" + payload.id; 394 395 carousel.setAttribute("data-timer", String(timerMs)); 396 carousel.setAttribute("data-interval", String(timerMs)); 397 carousel.setAttribute("data-anim", anim); 398 carousel.setAttribute("data-animation", anim); 399 400 // IMPORTANT for animation stacking 401 carousel.style.position = "relative"; 402 carousel.style.overflow = "hidden"; 403 // FIX: Ensure carousel fills its container width for responsive scaling 404 carousel.style.width = "100%"; 405 406 // Determine effective dimensions: use mobile dimensions if on phone and mobile ads exist 407 const rawBw = parseInt(block.width, 10); 408 const rawBh = parseInt(block.height, 10); 409 const mobileBw = parseInt(block.mobile_width, 10); 410 const mobileBh = parseInt(block.mobile_height, 10); 411 const useMobileDims = (block._device === "phone" && Number.isFinite(mobileBw) && mobileBw > 0 && Number.isFinite(mobileBh) && mobileBh > 0); 412 const bw = useMobileDims ? mobileBw : rawBw; 413 const bh = useMobileDims ? mobileBh : rawBh; 414 415 // Set max dimensions from block config so carousel doesn't exceed intended size 416 if (Number.isFinite(bw) && bw > 0) { 417 carousel.style.maxWidth = bw + "px"; 418 carousel.style.margin = "0 auto"; // Center the carousel
419 } 420 // Use aspect-ratio on carousel to maintain proportions and give it intrinsic height 421 if (Number.isFinite(bw) && bw > 0 && Number.isFinite(bh) && bh > 0) { 422 carousel.style.aspectRatio = bw + " / " + bh; 423 // FIX: Mark carousel as using responsive aspect-ratio so runtime doesn't override with fixed height 424 carousel.setAttribute("data-responsive-ar", "1"); 425 } 426 427 // Slides: source-of-truth `.adr` elements directly under `.adblock_carousel` 428 ads.forEach(function (ad) { 429 const slide = buildAdSlide(ad, block); 430 slide.style.position = "absolute"; 431 slide.style.inset = "0"; 432 slide.style.display = "none"; 433 slide.style.opacity = "1"; 434 slide.style.transform = "translate3d(0,0,0) scale(1)"; 435 slide.style.willChange = "opacity, transform"; 436 // FIX: Override wrapper maxWidth for carousel slides - let carousel control dimensions 437 slide.style.maxWidth = "100%"; 438 slide.style.width = "100%"; 439 slide.style.height = "100%"; 440 carousel.appendChild(slide); 441 }); 442 443 // Show only the first slide initially 444 const slides = carousel.querySelectorAll(":scope > .adr"); 445 if (slides.length) { 446 slides.forEach((s, i) => { s.style.display = (i === 0 ? "block" : "none"); }); 447 } 448 449 blockEl.appendChild(carousel); 450 outer.appendChild(blockEl); 451 452 container.innerHTML = ""; 453 container.appendChild(outer); 454 455 // FIX: Clear placeholder's inline styles that could conflict with carousel sizing 456 // The placeholder had aspect-ratio based on block dimensions (e.g., 728/90) 457 // but mobile ads may have different dimensions (e.g., 300/250) 458 container.style.height = "auto"; 459 container.style.aspectRatio = ""; 460 container.style.maxWidth = ""; 461 462 // Kick the new runtime (NOT legacy) 463 if (window.SRRAdsRuntime && typeof window.SRRAdsRuntime.initAll === "function") { 464 // debounce so 5 blocks don't create 5 init storms 465 window.__srrAdsRuntimeKick && clearTimeout(window.__srrAdsRuntimeKick); 466 window.__srrAdsRuntimeKick = setTimeout(function () { 467 try { window.SRRAdsRuntime.initAll(document); } catch(e) {} 468 }, 50); 469 } 470 471 // Optional hook 472 if (window.dispatchEvent) { 473 try { 474 window.dispatchEvent(new CustomEvent("srr_ads:block_rendered", { detail: { id: payload.id } })); 475 } catch (e) {} 476 } 477 } 478 479 function loadOne(el) { 480 if (el.__srrLoaded) return; 481 482 // IMPORTANT: 483 // Read ID from all known placeholder attributes 484 const id = 485 el.getAttribute("data-srr-adblock-id") || 486 el.getAttribute("data-ad-block-id") || // <-- your placeholder_func 487 el.getAttribute("data-block-id") || 488 el.getAttribute("data-id"); 489 490 if (!id) return; 491 492 const device = detectDevice(); 493 494 const pagePath = normalizePagePath((window.location && window.location.pathname) ? window.location.pathname : "/"); 495 496 const base = 497 (window.srrAdsLazyload && window.srrAdsLazyload.restBase) 498 ? window.srrAdsLazyload.restBase 499 : null; 500 501 // Cache revision stamped on the placeholder by PHP ("{global}.{block}"), falling 502 // back to the site-wide revision. The coordinator keys its browser-side payload 503 // cache on this, so an ad or ad-block save retires cached copies immediately 504 // rather than after the payload timeout. 505 const rev = 506 el.getAttribute("data-srr-rev") || 507 ((window.srrAdsLazyload && window.srrAdsLazyload.rev != null) ? String(window.srrAdsLazyload.rev) : "0"); 508 509 if (!base) { 510 // No REST base configured = no fetch possible 511 // Keep placeholder visible. 512 return; 513 } 514 515 // Use shared coordinator to prevent duplicate REST calls (lazyload + SPA re-init). 516 // This reduces PHP concurrency by enforcing one network call per block/device. 517 el.__srrLoaded = true; 518 const coord = window.SRRAdsPayloadCoordinator; 519 const getter = coord && typeof coord.getPayload === "function" 520 ? coord.getPayload 521 : null; 522 523 const p = getter 524 ? getter(id, device, base, rev) 525 : fetch( 526 base.replace(/\/$/, "") + "/" + encodeURIComponent(id) + "?device=" + encodeURIComponent(device) + "&page_path=" + encodeURIComponent(pagePath), 527 { credentials: "same-origin" } 528 ) 529 .then(function (r) { return r.json(); }); 530 531 p.then(function (payload) { 532 try { 533 renderBlock(el, payload); 534 } catch (e) { 535 // allow retry if render threw 536 el.__srrLoaded = false;
537 return; 538 } 539 540 // If renderBlock no-ops (invalid/empty payload), the placeholder text can remain 541 // while __srrLoaded stays true, which prevents future retries and can strand SPA pages. 542 // Only mark as truly loaded if real ad markup exists. 543 try { 544 if (!(el.querySelector && el.querySelector(".adblock, .adblock_carousel, .adr"))) { 545 el.__srrLoaded = false; 546 } 547 } catch (e) { 548 // On any unexpected DOM exception, allow retry. 549 el.__srrLoaded = false; 550 } 551 }) 552 .catch(function () { 553 // allow retry if it failed 554 el.__srrLoaded = false; 555 }); 556 } 557 558 function observeLazyBlocks() { 559 // IMPORTANT: 560 // Support ALL placeholder attribute variants: 561 // - data-srr-adblock-id (new) 562 // - data-ad-block-id (your placeholder_func) 563 // - .srr-adblock-placeholder (your placeholder class) 564 // - .srr-adblock-lazy (older) 565 // - data-block-id / data-id (misc) 566 const blocks = document.querySelectorAll( 567 "[data-srr-adblock-id], [data-ad-block-id], .srr-adblock-placeholder, .srr-adblock-lazy, [data-block-id].srr-adblock-lazy" 568 ); 569 570 if (!blocks.length) return; 571 572 // IntersectionObserver: load when near viewport 573 if ("IntersectionObserver" in window) { 574 const io = new IntersectionObserver(function (entries) { 575 entries.forEach(function (entry) { 576 if (entry.isIntersecting) { 577 loadOne(entry.target); 578 io.unobserve(entry.target); 579 } 580 }); 581 }, { root: null, rootMargin: "1200px 0px", threshold: 0.01 }); 582 583 blocks.forEach(function (el) { 584 // If already contains real ads, skip 585 if (el.querySelector && el.querySelector(".adblock, .adblock_carousel, .adr")) return; 586 io.observe(el); 587 }); 588 589 return; 590 } 591 592 // Fallback: no IO -> immediate load 593 blocks.forEach(function (el) { loadOne(el); }); 594 } 595 596 // Avoid runaway loops: re-scan a few times after page changes, then stop 597 let scanBurstTimer = null; 598 function scanBurst() { 599 let runs = 0; 600 clearInterval(scanBurstTimer); 601 scanBurstTimer = setInterval(function () { 602 runs++; 603 observeLazyBlocks(); 604 if (runs >= 6) { // ~6 * 1500ms = 9 seconds then stop 605 clearInterval(scanBurstTimer); 606 scanBurstTimer = null; 607 } 608 }, 1500); 609 } 610 611 function init() { 612 observeLazyBlocks(); 613 } 614 615 function onPageChangeLikeEvent() { 616 // StreamPlayer/SPA may reuse DOM nodes. If a placeholder node was previously loaded, 617 // it can retain the in-memory `__srrLoaded` flag and never re-hydrate, leaving 618 // the user stuck on the placeholder text (e.g. "Loading advertisement"). 619 // Reset the flag for placeholders that do not currently contain rendered ad markup. 620 try { 621 const blocks = document.querySelectorAll( 622 "[data-srr-adblock-id], [data-ad-block-id], .srr-adblock-placeholder, .srr-adblock-lazy, [data-block-id].srr-adblock-lazy" 623 ); 624 blocks.forEach(function(el){ 625 if (!el) return; 626 el.__srrLoaded = false; 627 }); 628 } catch (e) {} 629 scanBurst(); 630 } 631 632 if (document.readyState === "loading") { 633 document.addEventListener("DOMContentLoaded", function () { 634 init(); 635 scanBurst(); 636 }); 637 } else { 638 init(); 639 scanBurst(); 640 } 641 642 // StreamPlayer / SPA hooks. 643 // "pageContentLoaded" (on window) is what srr-streamplayer really dispatches; 644 // the "streamplayer:*" names are legacy and never fired by anything. 645 window.addEventListener("pageContentLoaded", onPageChangeLikeEvent); 646 document.addEventListener("pageContentLoaded", onPageChangeLikeEvent); 647 document.addEventListener("streamplayer:contentreplaced", onPageChangeLikeEvent); 648 document.addEventListener("streamplayer:pagechange", onPageChangeLikeEvent); 649 document.addEventListener("srr_ads:page_change", onPageChangeLikeEvent); 650 window.addEventListener("popstate", onPageChangeLikeEvent); 651 652 // If you use Barba, hook it too (wonât throw if Barba is missing) 653 try { 654 if (typeof Barba !== "undefined" && Barba.Dispatcher && Barba.Dispatcher.on) { 655 Barba.Dispatcher.on("newPageReady", onPageChangeLikeEvent); 656 } 657 } catch (e) {} 658 659 // MutationObserver: catch placeholders inserted after the initial scan burst. 660 // StreamPlayer, deferred widgets, or other plugins may inject ad placeholders 661 // after the 9-second scanBurst window closes. Without this, those placeholders
662 // would stay stuck on "Loading advertisement" forever. 663 var moDebounce = null; 664 var PLACEHOLDER_SELECTOR = "[data-srr-adblock-id], [data-ad-block-id], .srr-adblock-placeholder, .srr-adblock-lazy"; 665 try { 666 if ("MutationObserver" in window) { 667 var mo = new MutationObserver(function () { 668 if (moDebounce) clearTimeout(moDebounce); 669 moDebounce = setTimeout(function () { 670 var blocks = document.querySelectorAll(PLACEHOLDER_SELECTOR); 671 if (!blocks || !blocks.length) return; 672 blocks.forEach(function (el) { 673 if (el.__srrLoaded) return; 674 if (el.querySelector && el.querySelector(".adblock, .adblock_carousel, .adr")) return; 675 loadOne(el); 676 }); 677 }, 200); 678 }); 679 // Start observing once the body is available 680 function startMutationObserver() { 681 if (document.body) { 682 mo.observe(document.body, { childList: true, subtree: true }); 683 } else { 684 setTimeout(startMutationObserver, 50); 685 } 686 } 687 startMutationObserver(); 688 } 689 } catch (e) {} 690})();
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.