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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.5.34",
3
+ "version": "1.5.36",
4
4
  "description": "Production-ready Ezoic infinite ads integration for NodeBB 4.x",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
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
- const PRELOAD_MARGIN_DESKTOP = '2600px 0px 2600px 0px';
15
- const PRELOAD_MARGIN_MOBILE = '1500px 0px 1500px 0px';
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 = '4200px 0px 4200px 0px';
20
- const PRELOAD_MARGIN_MOBILE_BOOST = '2500px 0px 2500px 0px';
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
- const MAX_INFLIGHT_DESKTOP = 4;
25
- const MAX_INFLIGHT_MOBILE = 3;
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
- function pruneOrphanWraps(kindClass, items) {
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
- ph.id = `${PLACEHOLDER_PREFIX}${id}`;
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
- const existingPh = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
441
- if (existingPh && existingPh.isConnected) return null;
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
- const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
464
- if (ph && ph.isConnected) continue;
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 ph = victim.querySelector && victim.querySelector(`[id^="${PLACEHOLDER_PREFIX}"]`);
492
- if (ph && state.io) state.io.unobserve(ph);
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-id');
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) enqueueShow(id);
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(`[id^="${PLACEHOLDER_PREFIX}"]`);
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 ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
630
- if (!ph || !ph.isConnected) return;
662
+ const wrap = findWrapById(id);
663
+ if (!wrap || !wrap.isConnected) return;
631
664
  const io = ensurePreloadObserver();
632
- try { io && io.observe(ph); } catch (e) {}
665
+ try { io && io.observe(wrap); } catch (e) {}
633
666
 
634
- // If already above fold, fire immediately
667
+ // If already near the fold, arm & fire immediately
635
668
  try {
636
- const r = ph.getBoundingClientRect();
637
- const screens = isBoosted() ? 5.0 : 3.0;
638
- const minBottom = isBoosted() ? -1500 : -800;
639
- if (r.top < window.innerHeight * screens && r.bottom > minBottom) enqueueShow(id);
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
  }