nodebb-plugin-ezoic-infinite 1.5.38 → 1.5.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/public/client.js +140 -216
- package/public/style.css +1 -18
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -8,24 +8,14 @@
|
|
|
8
8
|
const PLACEHOLDER_PREFIX = 'ezoic-pub-ad-placeholder-';
|
|
9
9
|
|
|
10
10
|
// Insert at most N ads per run to keep the UI smooth on infinite scroll
|
|
11
|
-
const MAX_INSERTS_PER_RUN =
|
|
11
|
+
const MAX_INSERTS_PER_RUN = 3;
|
|
12
12
|
|
|
13
13
|
// Preload before viewport (earlier load for smoother scroll)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
// When the user scrolls very fast, temporarily preload more aggressively.
|
|
20
|
-
// This helps ensure ads are already in-flight before the user reaches them.
|
|
21
|
-
const PRELOAD_MARGIN_DESKTOP_BOOST = '8500px 0px 8500px 0px';
|
|
22
|
-
const PRELOAD_MARGIN_MOBILE_BOOST = '5500px 0px 5500px 0px';
|
|
23
|
-
const BOOST_DURATION_MS = 2500;
|
|
24
|
-
const BOOST_SPEED_PX_PER_MS = 2.2; // ~2200px/s
|
|
25
|
-
|
|
26
|
-
// Allow a bit more parallelism; the perf profile can still dial this down on low-end devices.
|
|
27
|
-
const MAX_INFLIGHT_DESKTOP = 8;
|
|
28
|
-
const MAX_INFLIGHT_MOBILE = 6;
|
|
14
|
+
const PRELOAD_MARGIN_DESKTOP = '2600px 0px 2600px 0px';
|
|
15
|
+
const PRELOAD_MARGIN_MOBILE = '1500px 0px 1500px 0px';
|
|
16
|
+
|
|
17
|
+
const MAX_INFLIGHT_DESKTOP = 4;
|
|
18
|
+
const MAX_INFLIGHT_MOBILE = 3;
|
|
29
19
|
|
|
30
20
|
|
|
31
21
|
// Adaptive performance profile (device/network aware)
|
|
@@ -73,23 +63,17 @@ function getPerfProfile() {
|
|
|
73
63
|
return p;
|
|
74
64
|
}
|
|
75
65
|
|
|
76
|
-
function isBoosted() {
|
|
77
|
-
try { return Date.now() < (state.scrollBoostUntil || 0); } catch (e) { return false; }
|
|
78
|
-
}
|
|
79
|
-
|
|
80
66
|
function isMobile() {
|
|
81
67
|
try { return window && window.innerWidth && window.innerWidth < 768; } catch (e) { return false; }
|
|
82
68
|
}
|
|
83
69
|
|
|
84
70
|
function getPreloadRootMargin() {
|
|
85
|
-
|
|
86
|
-
return isBoosted() ? PRELOAD_MARGIN_DESKTOP_BOOST : PRELOAD_MARGIN_DESKTOP;
|
|
71
|
+
return isMobile() ? PRELOAD_MARGIN_MOBILE : PRELOAD_MARGIN_DESKTOP;
|
|
87
72
|
}
|
|
88
73
|
|
|
89
74
|
function getMaxInflight() {
|
|
90
75
|
const perf = getPerfProfile();
|
|
91
|
-
|
|
92
|
-
return base + (isBoosted() ? 1 : 0);
|
|
76
|
+
return isMobile() ? perf.maxInflightMobile : perf.maxInflightDesktop;
|
|
93
77
|
}
|
|
94
78
|
|
|
95
79
|
const SELECTORS = {
|
|
@@ -151,6 +135,7 @@ function mutationHasRelevantAddedNodes(mutations) {
|
|
|
151
135
|
|
|
152
136
|
// observers / schedulers
|
|
153
137
|
domObs: null,
|
|
138
|
+
tightenObs: null,
|
|
154
139
|
io: null,
|
|
155
140
|
runQueued: false,
|
|
156
141
|
|
|
@@ -158,11 +143,6 @@ function mutationHasRelevantAddedNodes(mutations) {
|
|
|
158
143
|
inflight: 0,
|
|
159
144
|
pending: [],
|
|
160
145
|
pendingSet: new Set(),
|
|
161
|
-
|
|
162
|
-
// fast scroll boosting
|
|
163
|
-
scrollBoostUntil: 0,
|
|
164
|
-
lastScrollY: 0,
|
|
165
|
-
lastScrollTs: 0,
|
|
166
146
|
ioMargin: null,
|
|
167
147
|
|
|
168
148
|
// hero)
|
|
@@ -313,6 +293,103 @@ function mutationHasRelevantAddedNodes(mutations) {
|
|
|
313
293
|
}
|
|
314
294
|
}
|
|
315
295
|
|
|
296
|
+
// ---------- Ezoic min-height tightening (lightweight) ----------
|
|
297
|
+
// Some Ezoic placements reserve a large min-height (e.g. 400px) even when
|
|
298
|
+
// the rendered iframe/container is smaller (often 250px). That creates a
|
|
299
|
+
// visible empty gap and can make creatives appear to "slide" inside the slot.
|
|
300
|
+
// We correct ONLY those cases, without scroll listeners or full-page rescans.
|
|
301
|
+
|
|
302
|
+
function getRenderedAdHeight(adSpan) {
|
|
303
|
+
try {
|
|
304
|
+
const c = adSpan.querySelector('div[id$="__container__"]');
|
|
305
|
+
if (c && c.offsetHeight) return c.offsetHeight;
|
|
306
|
+
const f = adSpan.querySelector('iframe');
|
|
307
|
+
if (!f) return 0;
|
|
308
|
+
const attr = parseInt(f.getAttribute('height') || '', 10);
|
|
309
|
+
if (Number.isFinite(attr) && attr > 0) return attr;
|
|
310
|
+
if (f.offsetHeight) return f.offsetHeight;
|
|
311
|
+
} catch (e) {}
|
|
312
|
+
return 0;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function tightenMinHeight(adSpan) {
|
|
316
|
+
try {
|
|
317
|
+
if (!adSpan || adSpan.nodeType !== 1) return;
|
|
318
|
+
if (adSpan.tagName !== 'SPAN') return;
|
|
319
|
+
if (!adSpan.classList || !adSpan.classList.contains('ezoic-ad')) return;
|
|
320
|
+
|
|
321
|
+
const mhStr = adSpan.style && adSpan.style.minHeight ? String(adSpan.style.minHeight) : '';
|
|
322
|
+
const mh = mhStr ? parseInt(mhStr, 10) : 0;
|
|
323
|
+
if (!mh || mh < 350) return; // only fix the "400px"-style reservations
|
|
324
|
+
|
|
325
|
+
const h = getRenderedAdHeight(adSpan);
|
|
326
|
+
if (!h || h <= 0) return;
|
|
327
|
+
if (h >= mh) return;
|
|
328
|
+
|
|
329
|
+
adSpan.style.setProperty('min-height', `${h}px`, 'important');
|
|
330
|
+
} catch (e) {}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function closestEzoicAdSpan(node) {
|
|
334
|
+
try {
|
|
335
|
+
if (!node || node.nodeType !== 1) return null;
|
|
336
|
+
const el = /** @type {Element} */ (node);
|
|
337
|
+
if (el.tagName === 'SPAN' && el.classList && el.classList.contains('ezoic-ad')) return el;
|
|
338
|
+
if (el.closest) return el.closest('span.ezoic-ad');
|
|
339
|
+
} catch (e) {}
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function ensureTightenObserver() {
|
|
344
|
+
if (state.tightenObs) return;
|
|
345
|
+
|
|
346
|
+
let raf = 0;
|
|
347
|
+
const pending = new Set();
|
|
348
|
+
const schedule = (adSpan) => {
|
|
349
|
+
if (!adSpan) return;
|
|
350
|
+
pending.add(adSpan);
|
|
351
|
+
if (raf) return;
|
|
352
|
+
raf = requestAnimationFrame(() => {
|
|
353
|
+
raf = 0;
|
|
354
|
+
for (const el of pending) tightenMinHeight(el);
|
|
355
|
+
pending.clear();
|
|
356
|
+
});
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
state.tightenObs = new MutationObserver((mutations) => {
|
|
360
|
+
try {
|
|
361
|
+
for (const m of mutations) {
|
|
362
|
+
if (m.type === 'attributes') {
|
|
363
|
+
const ad = closestEzoicAdSpan(m.target);
|
|
364
|
+
if (ad) schedule(ad);
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
if (!m.addedNodes || !m.addedNodes.length) continue;
|
|
368
|
+
for (const n of m.addedNodes) {
|
|
369
|
+
const ad = closestEzoicAdSpan(n);
|
|
370
|
+
if (ad) schedule(ad);
|
|
371
|
+
if (n && n.nodeType === 1 && n.querySelectorAll) {
|
|
372
|
+
n.querySelectorAll('span.ezoic-ad').forEach(schedule);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
} catch (e) {}
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
state.tightenObs.observe(document.documentElement, {
|
|
381
|
+
subtree: true,
|
|
382
|
+
childList: true,
|
|
383
|
+
attributes: true,
|
|
384
|
+
attributeFilter: ['style', 'class', 'data-load-complete', 'height'],
|
|
385
|
+
});
|
|
386
|
+
} catch (e) {}
|
|
387
|
+
|
|
388
|
+
try {
|
|
389
|
+
document.querySelectorAll('span.ezoic-ad[style*="min-height"]').forEach(tightenMinHeight);
|
|
390
|
+
} catch (e) {}
|
|
391
|
+
}
|
|
392
|
+
|
|
316
393
|
const RECYCLE_COOLDOWN_MS = 1500;
|
|
317
394
|
|
|
318
395
|
function kindKeyFromClass(kindClass) {
|
|
@@ -575,155 +652,45 @@ function startShow(id) {
|
|
|
575
652
|
drainQueue();
|
|
576
653
|
};
|
|
577
654
|
|
|
578
|
-
// Safety release even if the ad pipeline stalls
|
|
579
655
|
const hardTimer = setTimeout(release, 6500);
|
|
580
656
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
585
|
-
if (!ph || !ph.isConnected) return;
|
|
586
|
-
|
|
587
|
-
// Guard against rapid duplicate calls for the same id
|
|
588
|
-
const now2 = Date.now();
|
|
589
|
-
const last2 = state.lastShowById.get(id) || 0;
|
|
590
|
-
if (now2 - last2 < 250) return;
|
|
591
|
-
state.lastShowById.set(id, now2);
|
|
592
|
-
|
|
593
|
-
window.ezstandalone = window.ezstandalone || {};
|
|
594
|
-
const ez = window.ezstandalone;
|
|
595
|
-
|
|
596
|
-
const doShow = () => {
|
|
597
|
-
try {
|
|
598
|
-
if (state.usedOnce && state.usedOnce.has(id)) {
|
|
599
|
-
safeDestroyById(id);
|
|
600
|
-
}
|
|
601
|
-
} catch (e) {}
|
|
602
|
-
|
|
603
|
-
try { ez.showAds(id); } catch (e) {}
|
|
604
|
-
try { state.usedOnce && state.usedOnce.add(id); } catch (e) {}
|
|
605
|
-
|
|
606
|
-
// Tighten any oversized reserved height once the creative is in the DOM.
|
|
607
|
-
try { scheduleTighten(id); } catch (e) {}
|
|
608
|
-
|
|
609
|
-
// Release budget quickly; the creative can keep loading independently.
|
|
610
|
-
setTimeout(() => { clearTimeout(hardTimer); release(); }, 300);
|
|
611
|
-
};
|
|
612
|
-
|
|
613
|
-
// Use cmd queue if present, but don't delay to next frame.
|
|
614
|
-
if (Array.isArray(ez.cmd)) {
|
|
615
|
-
try { ez.cmd.push(doShow); } catch (e) { doShow(); }
|
|
616
|
-
} else {
|
|
617
|
-
doShow();
|
|
618
|
-
}
|
|
619
|
-
} finally {
|
|
620
|
-
// If we returned early, hardTimer will release.
|
|
621
|
-
}
|
|
622
|
-
}
|
|
657
|
+
requestAnimationFrame(() => {
|
|
658
|
+
try {
|
|
659
|
+
if (isBlocked()) return;
|
|
623
660
|
|
|
661
|
+
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
662
|
+
if (!ph || !ph.isConnected) return;
|
|
624
663
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
664
|
+
const now2 = Date.now();
|
|
665
|
+
const last2 = state.lastShowById.get(id) || 0;
|
|
666
|
+
if (now2 - last2 < 900) return;
|
|
667
|
+
state.lastShowById.set(id, now2);
|
|
629
668
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
633
|
-
if (!ph || !ph.isConnected) return;
|
|
634
|
-
|
|
635
|
-
const ad = ph.querySelector('span.ezoic-ad');
|
|
636
|
-
if (!ad) return;
|
|
637
|
-
|
|
638
|
-
// Prefer the safeframe/container size if present.
|
|
639
|
-
let h = 0;
|
|
640
|
-
const container = ad.querySelector('div[id$="__container__"]');
|
|
641
|
-
if (container) {
|
|
642
|
-
const r = container.getBoundingClientRect();
|
|
643
|
-
if (r && r.height) h = Math.max(h, r.height);
|
|
644
|
-
}
|
|
645
|
-
const iframe = ad.querySelector('iframe');
|
|
646
|
-
if (iframe) {
|
|
647
|
-
const r2 = iframe.getBoundingClientRect();
|
|
648
|
-
if (r2 && r2.height) h = Math.max(h, r2.height);
|
|
649
|
-
const attrH = parseInt(iframe.getAttribute('height') || '', 10);
|
|
650
|
-
if (Number.isFinite(attrH) && attrH > 0) h = Math.max(h, attrH);
|
|
651
|
-
}
|
|
669
|
+
window.ezstandalone = window.ezstandalone || {};
|
|
670
|
+
const ez = window.ezstandalone;
|
|
652
671
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
}
|
|
660
|
-
}
|
|
672
|
+
const doShow = () => {
|
|
673
|
+
try {
|
|
674
|
+
if (state.usedOnce && state.usedOnce.has(id)) {
|
|
675
|
+
safeDestroyById(id);
|
|
676
|
+
}
|
|
677
|
+
} catch (e) {}
|
|
661
678
|
|
|
662
|
-
|
|
663
|
-
|
|
679
|
+
try { ez.showAds(id); } catch (e) {}
|
|
680
|
+
try { state.usedOnce && state.usedOnce.add(id); } catch (e) {}
|
|
664
681
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
// Keep height auto so responsive creatives can expand if needed.
|
|
668
|
-
try { ad.style.setProperty('height', 'auto', 'important'); } catch (e) {}
|
|
669
|
-
} catch (e) {}
|
|
670
|
-
}
|
|
682
|
+
setTimeout(() => { clearTimeout(hardTimer); release(); }, 650);
|
|
683
|
+
};
|
|
671
684
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
if (!ph || !ph.isConnected) return;
|
|
677
|
-
|
|
678
|
-
const ro = (typeof ResizeObserver === 'function') ? new ResizeObserver(() => {
|
|
679
|
-
tightenEzoicHeightFor(id);
|
|
680
|
-
}) : null;
|
|
681
|
-
|
|
682
|
-
// Also watch for Ezoic re-applying an oversized inline min-height (style attribute changes).
|
|
683
|
-
const mo = (typeof MutationObserver === 'function') ? new MutationObserver(() => {
|
|
684
|
-
tightenEzoicHeightFor(id);
|
|
685
|
-
}) : null;
|
|
686
|
-
|
|
687
|
-
const attach = () => {
|
|
688
|
-
const ad = ph.querySelector('span.ezoic-ad[data-ez-name], span.ezoic-ad');
|
|
689
|
-
if (!ad) return false;
|
|
690
|
-
|
|
691
|
-
if (ro) {
|
|
692
|
-
const container = ad.querySelector && ad.querySelector('div[id$="__container__"]');
|
|
693
|
-
const iframe = ad.querySelector && ad.querySelector('iframe');
|
|
694
|
-
try { if (container) ro.observe(container); } catch (e) {}
|
|
695
|
-
try { if (iframe) ro.observe(iframe); } catch (e) {}
|
|
696
|
-
try { ro.observe(ad); } catch (e) {}
|
|
697
|
-
}
|
|
698
|
-
if (mo) {
|
|
699
|
-
try { mo.observe(ad, { attributes: true, attributeFilter: ['style', 'class'] }); } catch (e) {}
|
|
685
|
+
if (Array.isArray(ez.cmd)) {
|
|
686
|
+
try { ez.cmd.push(doShow); } catch (e) { doShow(); }
|
|
687
|
+
} else {
|
|
688
|
+
doShow();
|
|
700
689
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
// If the ad wrapper is injected slightly later, observe the placeholder briefly for children.
|
|
705
|
-
if (!attach() && typeof MutationObserver === 'function') {
|
|
706
|
-
try {
|
|
707
|
-
const tmp = new MutationObserver(() => {
|
|
708
|
-
if (attach()) {
|
|
709
|
-
try { tmp.disconnect(); } catch (e) {}
|
|
710
|
-
tightenEzoicHeightFor(id);
|
|
711
|
-
}
|
|
712
|
-
});
|
|
713
|
-
tmp.observe(ph, { childList: true, subtree: true });
|
|
714
|
-
setTimeout(() => { try { tmp.disconnect(); } catch (e) {} }, 3000);
|
|
715
|
-
} catch (e) {}
|
|
690
|
+
} finally {
|
|
691
|
+
// If we returned early, hardTimer will release.
|
|
716
692
|
}
|
|
717
|
-
|
|
718
|
-
_heightObsByPlaceholder.set(id, { ro: ro || null, mo: mo || null });
|
|
719
|
-
} catch (e) {}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
function scheduleTighten(id) {
|
|
723
|
-
// Run a couple of times (creatives may resize after initial load)
|
|
724
|
-
try { setTimeout(() => tightenEzoicHeightFor(id), 250); } catch (e) {}
|
|
725
|
-
try { setTimeout(() => tightenEzoicHeightFor(id), 1100); } catch (e) {}
|
|
726
|
-
try { ensureHeightObserver(id); } catch (e) {}
|
|
693
|
+
});
|
|
727
694
|
}
|
|
728
695
|
|
|
729
696
|
|
|
@@ -778,9 +745,7 @@ function scheduleTighten(id) {
|
|
|
778
745
|
// If already near the fold, arm & fire immediately
|
|
779
746
|
try {
|
|
780
747
|
const r = wrap.getBoundingClientRect();
|
|
781
|
-
|
|
782
|
-
// During boost (fast scroll), preload even farther.
|
|
783
|
-
const screens = isBoosted() ? 6.0 : 4.0;
|
|
748
|
+
const screens = 3.0;
|
|
784
749
|
const h = (window.innerHeight || 800);
|
|
785
750
|
if (r.top < screens * h && r.bottom > -screens * h) {
|
|
786
751
|
armPlaceholder(wrap, id);
|
|
@@ -807,7 +772,7 @@ function scheduleTighten(id) {
|
|
|
807
772
|
const targets = computeTargets(items.length, interval, showFirst);
|
|
808
773
|
let inserted = 0;
|
|
809
774
|
const perf = getPerfProfile();
|
|
810
|
-
const maxInserts = perf.maxInsertsPerRun
|
|
775
|
+
const maxInserts = perf.maxInsertsPerRun;
|
|
811
776
|
|
|
812
777
|
for (const afterPos of targets) {
|
|
813
778
|
if (inserted >= maxInserts) break;
|
|
@@ -986,15 +951,8 @@ function scheduleTighten(id) {
|
|
|
986
951
|
// reset perf profile cache
|
|
987
952
|
state.perfProfile = null;
|
|
988
953
|
|
|
989
|
-
//
|
|
990
|
-
|
|
991
|
-
for (const v of _heightObsByPlaceholder.values()) {
|
|
992
|
-
try { if (v && v.ro && v.ro.disconnect) v.ro.disconnect(); } catch (e) {}
|
|
993
|
-
try { if (v && v.mo && v.mo.disconnect) v.mo.disconnect(); } catch (e) {}
|
|
994
|
-
try { if (v && v.disconnect) v.disconnect(); } catch (e) {} // backward compat
|
|
995
|
-
}
|
|
996
|
-
_heightObsByPlaceholder.clear();
|
|
997
|
-
} catch (e) {}
|
|
954
|
+
// tighten observer is global; keep it across ajaxify navigation but ensure it exists
|
|
955
|
+
// (do not disconnect here to avoid missing late style rewrites during transitions)
|
|
998
956
|
|
|
999
957
|
// reset state
|
|
1000
958
|
state.cfg = null;
|
|
@@ -1042,6 +1000,7 @@ function scheduleTighten(id) {
|
|
|
1042
1000
|
|
|
1043
1001
|
warmUpNetwork();
|
|
1044
1002
|
patchShowAds();
|
|
1003
|
+
ensureTightenObserver();
|
|
1045
1004
|
ensurePreloadObserver();
|
|
1046
1005
|
ensureDomObserver();
|
|
1047
1006
|
|
|
@@ -1059,51 +1018,16 @@ function scheduleTighten(id) {
|
|
|
1059
1018
|
});
|
|
1060
1019
|
}
|
|
1061
1020
|
|
|
1062
|
-
function bindScroll() {
|
|
1063
|
-
let ticking = false;
|
|
1064
|
-
window.addEventListener('scroll', () => {
|
|
1065
|
-
// Detect very fast scrolling and temporarily boost preload/parallelism.
|
|
1066
|
-
try {
|
|
1067
|
-
const now = Date.now();
|
|
1068
|
-
const y = window.scrollY || window.pageYOffset || 0;
|
|
1069
|
-
if (state.lastScrollTs) {
|
|
1070
|
-
const dt = now - state.lastScrollTs;
|
|
1071
|
-
const dy = Math.abs(y - (state.lastScrollY || 0));
|
|
1072
|
-
if (dt > 0) {
|
|
1073
|
-
const speed = dy / dt; // px/ms
|
|
1074
|
-
if (speed >= BOOST_SPEED_PX_PER_MS) {
|
|
1075
|
-
const wasBoosted = isBoosted();
|
|
1076
|
-
state.scrollBoostUntil = Math.max(state.scrollBoostUntil || 0, now + BOOST_DURATION_MS);
|
|
1077
|
-
if (!wasBoosted) {
|
|
1078
|
-
// margin changed -> rebuild IO so existing placeholders get earlier preload
|
|
1079
|
-
ensurePreloadObserver();
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
state.lastScrollY = y;
|
|
1085
|
-
state.lastScrollTs = now;
|
|
1086
|
-
} catch (e) {}
|
|
1087
|
-
|
|
1088
|
-
if (ticking) return;
|
|
1089
|
-
ticking = true;
|
|
1090
|
-
window.requestAnimationFrame(() => {
|
|
1091
|
-
ticking = false;
|
|
1092
|
-
if (!isBlocked()) scheduleRun();
|
|
1093
|
-
});
|
|
1094
|
-
}, { passive: true });
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
1021
|
// ---------- boot ----------
|
|
1098
1022
|
|
|
1099
1023
|
state.pageKey = getPageKey();
|
|
1100
1024
|
warmUpNetwork();
|
|
1101
1025
|
patchShowAds();
|
|
1026
|
+
ensureTightenObserver();
|
|
1102
1027
|
ensurePreloadObserver();
|
|
1103
1028
|
ensureDomObserver();
|
|
1104
1029
|
|
|
1105
1030
|
bindNodeBB();
|
|
1106
|
-
bindScroll();
|
|
1107
1031
|
|
|
1108
1032
|
// First paint: try hero + run
|
|
1109
1033
|
blockedUntil = 0;
|
package/public/style.css
CHANGED
|
@@ -1,26 +1,9 @@
|
|
|
1
1
|
/* Minimal styling for injected Ezoic wrappers.
|
|
2
2
|
Spacing (margins/padding) is intentionally NOT forced here, because it can be
|
|
3
3
|
configured inside Ezoic and may vary by placement/device.
|
|
4
|
-
|
|
5
|
-
Goals:
|
|
6
|
-
- prevent flex/centering styles from parent lists from affecting ad internals
|
|
7
|
-
- reduce layout jank when iframes resize during scroll
|
|
8
4
|
*/
|
|
9
5
|
|
|
10
6
|
.ezoic-ad {
|
|
11
|
-
display: block
|
|
12
|
-
position: relative;
|
|
7
|
+
display: block;
|
|
13
8
|
width: 100%;
|
|
14
|
-
overflow: hidden;
|
|
15
|
-
|
|
16
|
-
/* limit how far layout/paint changes propagate */
|
|
17
|
-
contain: layout paint style;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/* Keep ad content aligned to the top (avoids the "slides to bottom" look) */
|
|
21
|
-
.ezoic-ad iframe,
|
|
22
|
-
.ezoic-ad ins,
|
|
23
|
-
.ezoic-ad > div {
|
|
24
|
-
display: block !important;
|
|
25
|
-
vertical-align: top !important;
|
|
26
9
|
}
|