nodebb-plugin-ezoic-infinite 1.5.34 → 1.5.36
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 +63 -25
- package/public/style.css +18 -1
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -11,18 +11,20 @@
|
|
|
11
11
|
const MAX_INSERTS_PER_RUN = 3;
|
|
12
12
|
|
|
13
13
|
// Preload before viewport (earlier load for smoother scroll)
|
|
14
|
-
|
|
15
|
-
const
|
|
14
|
+
// Preload far enough ahead that fast scroll doesn't outrun ad loading.
|
|
15
|
+
const PRELOAD_MARGIN_DESKTOP = '3200px 0px 3200px 0px';
|
|
16
|
+
const PRELOAD_MARGIN_MOBILE = '1800px 0px 1800px 0px';
|
|
16
17
|
|
|
17
18
|
// When the user scrolls very fast, temporarily preload more aggressively.
|
|
18
19
|
// This helps ensure ads are already in-flight before the user reaches them.
|
|
19
|
-
const PRELOAD_MARGIN_DESKTOP_BOOST = '
|
|
20
|
-
const PRELOAD_MARGIN_MOBILE_BOOST = '
|
|
20
|
+
const PRELOAD_MARGIN_DESKTOP_BOOST = '5200px 0px 5200px 0px';
|
|
21
|
+
const PRELOAD_MARGIN_MOBILE_BOOST = '3200px 0px 3200px 0px';
|
|
21
22
|
const BOOST_DURATION_MS = 2500;
|
|
22
23
|
const BOOST_SPEED_PX_PER_MS = 2.2; // ~2200px/s
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
const
|
|
25
|
+
// Allow a bit more parallelism; the perf profile can still dial this down on low-end devices.
|
|
26
|
+
const MAX_INFLIGHT_DESKTOP = 5;
|
|
27
|
+
const MAX_INFLIGHT_MOBILE = 4;
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
// Adaptive performance profile (device/network aware)
|
|
@@ -383,7 +385,33 @@ function withInternalDomChange(fn) {
|
|
|
383
385
|
} catch (e) {}
|
|
384
386
|
}
|
|
385
387
|
|
|
386
|
-
|
|
388
|
+
|
|
389
|
+
function findWrapById(id) {
|
|
390
|
+
try {
|
|
391
|
+
return document.querySelector(`.${WRAP_CLASS}[data-ezoic-wrapid="${id}"]`);
|
|
392
|
+
} catch (e) {}
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function armPlaceholder(wrap, id) {
|
|
397
|
+
try {
|
|
398
|
+
if (!wrap || !wrap.isConnected) return null;
|
|
399
|
+
const domId = `${PLACEHOLDER_PREFIX}${id}`;
|
|
400
|
+
|
|
401
|
+
// If the id is already present somewhere, do not reassign it.
|
|
402
|
+
const existing = document.getElementById(domId);
|
|
403
|
+
if (existing && existing.isConnected) return existing;
|
|
404
|
+
|
|
405
|
+
const ph = wrap.querySelector('[data-ezoic-ph="1"]');
|
|
406
|
+
if (!ph) return null;
|
|
407
|
+
|
|
408
|
+
if (!ph.id) ph.id = domId;
|
|
409
|
+
return ph;
|
|
410
|
+
} catch (e) {}
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function pruneOrphanWraps(kindClass, items) {
|
|
387
415
|
if (!items || !items.length) return 0;
|
|
388
416
|
const itemSet = new Set(items);
|
|
389
417
|
const wraps = document.querySelectorAll(`.${WRAP_CLASS}.${kindClass}`);
|
|
@@ -421,8 +449,10 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
421
449
|
wrap.style.width = '100%';
|
|
422
450
|
|
|
423
451
|
const ph = document.createElement('div');
|
|
424
|
-
|
|
452
|
+
// Do not assign the Ezoic placeholder id until we actually want to load the ad.
|
|
453
|
+
// This avoids Ezoic defining placeholders too early during DOM churn/infinite scroll.
|
|
425
454
|
ph.setAttribute('data-ezoic-id', String(id));
|
|
455
|
+
ph.setAttribute('data-ezoic-ph', '1');
|
|
426
456
|
wrap.appendChild(ph);
|
|
427
457
|
|
|
428
458
|
return wrap;
|
|
@@ -437,8 +467,8 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
437
467
|
if (findWrap(kindClass, afterPos)) return null;
|
|
438
468
|
if (insertingIds.has(id)) return null;
|
|
439
469
|
|
|
440
|
-
|
|
441
|
-
if (
|
|
470
|
+
const existingWrap = findWrapById(id);
|
|
471
|
+
if (existingWrap && existingWrap.isConnected) return null;
|
|
442
472
|
|
|
443
473
|
insertingIds.add(id);
|
|
444
474
|
try {
|
|
@@ -460,8 +490,8 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
460
490
|
state[cursorKey] = (state[cursorKey] + 1) % n;
|
|
461
491
|
|
|
462
492
|
const id = allIds[idx];
|
|
463
|
-
|
|
464
|
-
if (
|
|
493
|
+
const w = findWrapById(id);
|
|
494
|
+
if (w && w.isConnected) continue;
|
|
465
495
|
|
|
466
496
|
return id;
|
|
467
497
|
}
|
|
@@ -488,8 +518,8 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
488
518
|
withInternalDomChange(() => {
|
|
489
519
|
// Unobserve placeholder if still observed
|
|
490
520
|
try {
|
|
491
|
-
const
|
|
492
|
-
if (
|
|
521
|
+
const t = victim;
|
|
522
|
+
if (t && state.io) state.io.unobserve(t);
|
|
493
523
|
} catch (e) {}
|
|
494
524
|
|
|
495
525
|
try { if (id) safeDestroyById(id); } catch (e) {}
|
|
@@ -604,9 +634,12 @@ function startShow(id) {
|
|
|
604
634
|
const el = ent.target;
|
|
605
635
|
try { state.io && state.io.unobserve(el); } catch (e) {}
|
|
606
636
|
|
|
607
|
-
const idAttr = el && el.getAttribute && el.getAttribute('data-ezoic-
|
|
637
|
+
const idAttr = el && el.getAttribute && el.getAttribute('data-ezoic-wrapid');
|
|
608
638
|
const id = parseInt(idAttr, 10);
|
|
609
|
-
if (Number.isFinite(id) && id > 0)
|
|
639
|
+
if (Number.isFinite(id) && id > 0) {
|
|
640
|
+
armPlaceholder(el, id);
|
|
641
|
+
enqueueShow(id);
|
|
642
|
+
}
|
|
610
643
|
}
|
|
611
644
|
}, { root: null, rootMargin: desiredMargin, threshold: 0 });
|
|
612
645
|
state.ioMargin = desiredMargin;
|
|
@@ -618,7 +651,7 @@ function startShow(id) {
|
|
|
618
651
|
// If we rebuilt the observer, re-observe existing placeholders so we don't miss them.
|
|
619
652
|
try {
|
|
620
653
|
if (state.io) {
|
|
621
|
-
const nodes = document.querySelectorAll(
|
|
654
|
+
const nodes = document.querySelectorAll(`.${WRAP_CLASS}[data-ezoic-wrapid]`);
|
|
622
655
|
nodes.forEach((n) => { try { state.io.observe(n); } catch (e) {} });
|
|
623
656
|
}
|
|
624
657
|
} catch (e) {}
|
|
@@ -626,17 +659,22 @@ function startShow(id) {
|
|
|
626
659
|
}
|
|
627
660
|
|
|
628
661
|
function observePlaceholder(id) {
|
|
629
|
-
const
|
|
630
|
-
if (!
|
|
662
|
+
const wrap = findWrapById(id);
|
|
663
|
+
if (!wrap || !wrap.isConnected) return;
|
|
631
664
|
const io = ensurePreloadObserver();
|
|
632
|
-
try { io && io.observe(
|
|
665
|
+
try { io && io.observe(wrap); } catch (e) {}
|
|
633
666
|
|
|
634
|
-
// If already
|
|
667
|
+
// If already near the fold, arm & fire immediately
|
|
635
668
|
try {
|
|
636
|
-
const r =
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
669
|
+
const r = wrap.getBoundingClientRect();
|
|
670
|
+
// Fire early enough that the ad is likely ready when the user reaches it.
|
|
671
|
+
// During boost (fast scroll), preload even farther.
|
|
672
|
+
const screens = isBoosted() ? 6.0 : 4.0;
|
|
673
|
+
const h = (window.innerHeight || 800);
|
|
674
|
+
if (r.top < screens * h && r.bottom > -screens * h) {
|
|
675
|
+
armPlaceholder(wrap, id);
|
|
676
|
+
enqueueShow(id);
|
|
677
|
+
}
|
|
640
678
|
} catch (e) {}
|
|
641
679
|
}
|
|
642
680
|
|
package/public/style.css
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
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
|
|
4
8
|
*/
|
|
5
9
|
|
|
6
10
|
.ezoic-ad {
|
|
7
|
-
display: block;
|
|
11
|
+
display: block !important;
|
|
12
|
+
position: relative;
|
|
8
13
|
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;
|
|
9
26
|
}
|