nodebb-plugin-ezoic-infinite 1.5.31 → 1.5.32

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/client.js +71 -94
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.5.31",
3
+ "version": "1.5.32",
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,11 +11,11 @@
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 = '1600px 0px 1600px 0px';
15
- const PRELOAD_MARGIN_MOBILE = '900px 0px 900px 0px';
14
+ const PRELOAD_MARGIN_DESKTOP = '2600px 0px 2600px 0px';
15
+ const PRELOAD_MARGIN_MOBILE = '1500px 0px 1500px 0px';
16
16
 
17
- const MAX_INFLIGHT_DESKTOP = 3;
18
- const MAX_INFLIGHT_MOBILE = 2;
17
+ const MAX_INFLIGHT_DESKTOP = 4;
18
+ const MAX_INFLIGHT_MOBILE = 3;
19
19
 
20
20
  function isMobile() {
21
21
  try { return window && window.innerWidth && window.innerWidth < 768; } catch (e) { return false; }
@@ -77,28 +77,7 @@
77
77
 
78
78
  const insertingIds = new Set();
79
79
 
80
- function enqueueShow(id) {
81
- if (!id || isBlocked()) return;
82
- const max = getMaxInflight();
83
- if (state.inflight >= max) {
84
- if (!state.pendingSet.has(id)) {
85
- state.pending.push(id);
86
- state.pendingSet.add(id);
87
- }
88
- return;
89
80
  }
90
- startShow(id);
91
- }
92
-
93
- function drainQueue() {
94
- if (isBlocked()) return;
95
- const max = getMaxInflight();
96
- while (state.inflight < max && state.pending.length) {
97
- const id = state.pending.shift();
98
- state.pendingSet.delete(id);
99
- startShow(id);
100
- }
101
- }
102
81
 
103
82
  function markEmptyWrapper(id) {
104
83
  try {
@@ -467,29 +446,50 @@ function buildWrap(id, kindClass, afterPos) {
467
446
  }
468
447
 
469
448
  function enqueueShow(id) {
470
- if (!id || isBlocked()) return;
449
+ if (!id || isBlocked()) return;
450
+
451
+ // Basic per-id throttle (prevents rapid re-requests when DOM churns)
452
+ const now = Date.now();
453
+ const last = state.lastShowById.get(id) || 0;
454
+ if (now - last < 900) return;
455
+
456
+ const max = getMaxInflight();
457
+ if (state.inflight >= max) {
458
+ if (!state.pendingSet.has(id)) {
459
+ state.pending.push(id);
460
+ state.pendingSet.add(id);
461
+ }
462
+ return;
463
+ }
464
+ startShow(id);
465
+ }
471
466
 
472
- const now = Date.now();
473
- const last = state.lastShowById.get(id) || 0;
474
- if (now - last < 1500) return; // basic throttle
475
-
476
- // Defer one frame
477
-
478
- // Budget concurrent loads
479
- state.inflight++;
480
- let released = false;
481
- const release = () => {
482
- if (released) return;
483
- released = true;
484
- state.inflight = Math.max(0, state.inflight - 1);
485
- drainQueue();
486
- };
467
+ function drainQueue() {
468
+ if (isBlocked()) return;
469
+ const max = getMaxInflight();
470
+ while (state.inflight < max && state.pending.length) {
471
+ const id = state.pending.shift();
472
+ state.pendingSet.delete(id);
473
+ startShow(id);
474
+ }
475
+ }
487
476
 
488
- // Safety release in case Ezoic never fills
489
- const hardTimer = setTimeout(release, 6500);
477
+ function startShow(id) {
478
+ if (!id || isBlocked()) return;
490
479
 
491
- // Defer one frame so the placeholder is definitely in DOM after insertion/recycle
492
- requestAnimationFrame(() => {
480
+ state.inflight++;
481
+ let released = false;
482
+ const release = () => {
483
+ if (released) return;
484
+ released = true;
485
+ state.inflight = Math.max(0, state.inflight - 1);
486
+ drainQueue();
487
+ };
488
+
489
+ const hardTimer = setTimeout(release, 6500);
490
+
491
+ requestAnimationFrame(() => {
492
+ try {
493
493
  if (isBlocked()) return;
494
494
 
495
495
  const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
@@ -497,59 +497,36 @@ function buildWrap(id, kindClass, afterPos) {
497
497
 
498
498
  const now2 = Date.now();
499
499
  const last2 = state.lastShowById.get(id) || 0;
500
- if (now2 - last2 < 1200) return;
500
+ if (now2 - last2 < 900) return;
501
501
  state.lastShowById.set(id, now2);
502
502
 
503
- try {
504
- window.ezstandalone = window.ezstandalone || {};
505
- const ez = window.ezstandalone;
503
+ window.ezstandalone = window.ezstandalone || {};
504
+ const ez = window.ezstandalone;
506
505
 
507
- const doShow = () => {
508
- try {
509
- if (state.usedOnce && state.usedOnce.has(id) && typeof ez.destroyPlaceholders === 'function') {
510
- // Avoid Ezoic caching state for reused placeholders
511
- ez.destroyPlaceholders(id);
512
- }
513
- } catch (e) {}
514
- try { ez.showAds(id); } catch (e) {}
515
- try { state.usedOnce && state.usedOnce.add(id); } catch (e) {}
516
- try { markEmptyWrapper(id); } catch (e) {}
517
- // allow a short time for DOM fill; then release budget
518
- setTimeout(() => { clearTimeout(hardTimer); release(); }, 700);
519
- };
506
+ const doShow = () => {
507
+ try {
508
+ if (state.usedOnce && state.usedOnce.has(id) && typeof ez.destroyPlaceholders === 'function') {
509
+ try { ez.destroyPlaceholders(id); } catch (e) {}
510
+ }
511
+ } catch (e) {}
520
512
 
521
- // Fast path
522
- if (typeof ez.showAds === 'function') {
523
- doShow();
524
- return;
525
- }
513
+ try { ez.showAds(id); } catch (e) {}
514
+ try { state.usedOnce && state.usedOnce.add(id); } catch (e) {}
515
+ try { markEmptyWrapper(id); } catch (e) {}
526
516
 
527
- // Queue once for when Ezoic is ready
528
- ez.cmd = ez.cmd || [];
529
- if (!ph.__ezoicQueued) {
530
- ph.__ezoicQueued = true;
531
- ez.cmd.push(() => {
532
- try {
533
- if (isBlocked()) return;
534
- const el = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
535
- if (!el || !el.isConnected) return;
536
- const ez2 = window.ezstandalone;
537
- if (!ez2 || typeof ez2.showAds !== 'function') return;
538
- try {
539
- if (state.usedOnce && state.usedOnce.has(id) && typeof ez2.destroyPlaceholders === 'function') {
540
- ez2.destroyPlaceholders(id);
541
- }
542
- } catch (e) {}
543
- try { ez2.showAds(id); } catch (e) {}
544
- try { state.usedOnce && state.usedOnce.add(id); } catch (e) {}
545
- try { markEmptyWrapper(id); } catch (e) {}
546
- setTimeout(() => { clearTimeout(hardTimer); release(); }, 700);
547
- } catch (e) {}
548
- });
549
- }
550
- } catch (e) { try { clearTimeout(hardTimer); release(); } catch (e2) {} }
551
- });
552
- }
517
+ setTimeout(() => { clearTimeout(hardTimer); release(); }, 650);
518
+ };
519
+
520
+ if (Array.isArray(ez.cmd)) {
521
+ try { ez.cmd.push(doShow); } catch (e) { doShow(); }
522
+ } else {
523
+ doShow();
524
+ }
525
+ } finally {
526
+ // If we returned early, hardTimer will release.
527
+ }
528
+ });
529
+ }
553
530
 
554
531
 
555
532
  // ---------- preload / above-the-fold ----------
@@ -583,7 +560,7 @@ function buildWrap(id, kindClass, afterPos) {
583
560
  // If already above fold, fire immediately
584
561
  try {
585
562
  const r = ph.getBoundingClientRect();
586
- if (r.top < window.innerHeight * 1.5 && r.bottom > -200) enqueueShow(id);
563
+ if (r.top < window.innerHeight * 3.0 && r.bottom > -800) enqueueShow(id);
587
564
  } catch (e) {}
588
565
  }
589
566