nodebb-plugin-ezoic-infinite 1.7.95 → 1.7.97

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 +61 -46
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.7.95",
3
+ "version": "1.7.97",
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
@@ -132,8 +132,6 @@
132
132
  burstDeadline: 0,
133
133
  burstCount: 0,
134
134
  lastBurstTs: 0,
135
- lastScrollY: 0,
136
- scrollDir: 1, // 1=down, -1=up
137
135
  };
138
136
 
139
137
  let blockedUntil = 0;
@@ -144,6 +142,34 @@
144
142
  const normBool = v => v === true || v === 'true' || v === 1 || v === '1' || v === 'on';
145
143
  const isFilled = n => !!(n?.querySelector?.('iframe, ins, img, video, [data-google-container-id]'));
146
144
 
145
+ function ezCmd(fn) {
146
+ try {
147
+ window.ezstandalone = window.ezstandalone || {};
148
+ const ez = window.ezstandalone;
149
+ if (Array.isArray(ez.cmd)) ez.cmd.push(fn);
150
+ else fn();
151
+ } catch (_) {}
152
+ }
153
+
154
+ function destroyPlaceholderIds(ids) {
155
+ try {
156
+ const uniq = Array.from(new Set((ids || [])
157
+ .map(v => parseInt(v, 10))
158
+ .filter(v => Number.isFinite(v) && v > 0)));
159
+ if (!uniq.length) return;
160
+ ezCmd(() => {
161
+ try {
162
+ const ez = window.ezstandalone;
163
+ if (typeof ez?.destroyPlaceholders === 'function') ez.destroyPlaceholders(uniq);
164
+ } catch (_) {}
165
+ });
166
+ } catch (_) {}
167
+ }
168
+
169
+ function placeholderCount(id) {
170
+ try { return document.querySelectorAll(`#${PH_PREFIX}${id}`).length; } catch (_) { return 0; }
171
+ }
172
+
147
173
  function mutate(fn) {
148
174
  S.mutGuard++;
149
175
  try { fn(); } finally { S.mutGuard--; }
@@ -315,49 +341,26 @@
315
341
  typeof ez?.define !== 'function' ||
316
342
  typeof ez?.displayMore !== 'function') return null;
317
343
 
318
- const vh = window.innerHeight || 800;
319
- const targetRect = targetEl?.getBoundingClientRect?.() || { top: vh, bottom: vh };
320
-
321
- // Recyclage bidirectionnel :
322
- // - scroll vers le bas -> recycle préférentiellement des wraps loin au-dessus
323
- // - scroll vers le haut -> recycle préférentiellement des wraps loin en-dessous
324
- // Fallback sur l'autre côté si aucun candidat.
325
- const aboveThreshold = -vh; // wrap entièrement/suffisamment au-dessus
326
- const belowThreshold = vh * 2; // wrap loin sous le viewport
327
-
328
- let aboveEmpty = null, aboveEmptyBottom = Infinity;
329
- let aboveFilled = null, aboveFilledBottom = Infinity;
330
- let belowEmpty = null, belowEmptyTop = -Infinity;
331
- let belowFilled = null, belowFilledTop = -Infinity;
344
+ const vh = window.innerHeight || 800;
345
+ // Seuil : -1vh (hors viewport visible). On appelle unobserve(ph) juste
346
+ // après pour neutraliser l'IO — plus de showAds parasite possible.
347
+ const threshold = -vh;
348
+ let bestEmpty = null, bestEmptyBottom = Infinity;
349
+ let bestFilled = null, bestFilledBottom = Infinity;
332
350
 
333
351
  document.querySelectorAll(`.${WRAP_CLASS}.${klass}`).forEach(wrap => {
334
352
  try {
335
- if (!wrap?.isConnected) return;
336
353
  const rect = wrap.getBoundingClientRect();
337
-
338
- if (rect.bottom < aboveThreshold) {
339
- if (!isFilled(wrap)) {
340
- if (rect.bottom < aboveEmptyBottom) { aboveEmptyBottom = rect.bottom; aboveEmpty = wrap; }
341
- } else {
342
- if (rect.bottom < aboveFilledBottom) { aboveFilledBottom = rect.bottom; aboveFilled = wrap; }
343
- }
344
- return;
345
- }
346
-
347
- if (rect.top > belowThreshold) {
348
- if (!isFilled(wrap)) {
349
- if (rect.top > belowEmptyTop) { belowEmptyTop = rect.top; belowEmpty = wrap; }
350
- } else {
351
- if (rect.top > belowFilledTop) { belowFilledTop = rect.top; belowFilled = wrap; }
352
- }
354
+ if (rect.bottom > threshold) return;
355
+ if (!isFilled(wrap)) {
356
+ if (rect.bottom < bestEmptyBottom) { bestEmptyBottom = rect.bottom; bestEmpty = wrap; }
357
+ } else {
358
+ if (rect.bottom < bestFilledBottom) { bestFilledBottom = rect.bottom; bestFilled = wrap; }
353
359
  }
354
360
  } catch (_) {}
355
361
  });
356
362
 
357
- const preferBelow = (S.scrollDir < 0) || (targetRect.top < vh * 0.5);
358
- const pickAbove = () => aboveEmpty ?? aboveFilled;
359
- const pickBelow = () => belowEmpty ?? belowFilled;
360
- const best = preferBelow ? (pickBelow() ?? pickAbove()) : (pickAbove() ?? pickBelow());
363
+ const best = bestEmpty ?? bestFilled;
361
364
  if (!best) return null;
362
365
  const id = parseInt(best.getAttribute(A_WRAPID), 10);
363
366
  if (!Number.isFinite(id)) return null;
@@ -421,7 +424,10 @@
421
424
  const ph = w.querySelector(`[id^="${PH_PREFIX}"]`);
422
425
  if (ph instanceof Element) S.io?.unobserve(ph);
423
426
  const id = parseInt(w.getAttribute(A_WRAPID), 10);
424
- if (Number.isFinite(id)) S.mountedIds.delete(id);
427
+ if (Number.isFinite(id)) {
428
+ destroyPlaceholderIds([id]);
429
+ S.mountedIds.delete(id);
430
+ }
425
431
  const key = w.getAttribute(A_ANCHOR);
426
432
  if (key && S.wrapByKey.get(key) === w) S.wrapByKey.delete(key);
427
433
  w.remove();
@@ -567,6 +573,7 @@
567
573
  if (isBlocked()) { clearTimeout(timer); return release(); }
568
574
  const ph = document.getElementById(`${PH_PREFIX}${id}`);
569
575
  if (!ph?.isConnected || isFilled(ph)) { clearTimeout(timer); return release(); }
576
+ if (placeholderCount(id) !== 1) { clearTimeout(timer); return release(); }
570
577
 
571
578
  const t = ts();
572
579
  if (t - (S.lastShow.get(id) ?? 0) < SHOW_THROTTLE_MS) { clearTimeout(timer); return release(); }
@@ -620,6 +627,7 @@
620
627
  const id = parseInt(v, 10);
621
628
  if (!Number.isFinite(id) || id <= 0 || seen.has(id)) continue;
622
629
  if (!document.getElementById(`${PH_PREFIX}${id}`)?.isConnected) continue;
630
+ if (placeholderCount(id) !== 1) continue;
623
631
  seen.add(id);
624
632
  try { orig(id); } catch (_) {}
625
633
  }
@@ -714,6 +722,18 @@
714
722
 
715
723
  function cleanup() {
716
724
  blockedUntil = ts() + 1500;
725
+ try {
726
+ const ids = Array.from(document.querySelectorAll(`.${WRAP_CLASS}[${A_WRAPID}]`))
727
+ .map(w => parseInt(w.getAttribute(A_WRAPID), 10))
728
+ .filter(v => Number.isFinite(v) && v > 0);
729
+ destroyPlaceholderIds(ids);
730
+ ezCmd(() => {
731
+ try {
732
+ const ez = window.ezstandalone;
733
+ if (typeof ez?.destroyAll === 'function') ez.destroyAll();
734
+ } catch (_) {}
735
+ });
736
+ } catch (_) {}
717
737
  mutate(() => document.querySelectorAll(`.${WRAP_CLASS}`).forEach(dropWrap));
718
738
  S.cfg = null;
719
739
  S.poolsReady = false;
@@ -824,7 +844,9 @@
824
844
  S.pageKey = pageKey();
825
845
  blockedUntil = 0;
826
846
  muteConsole(); ensureTcfLocator(); warmNetwork();
827
- patchShowAds(); getIO(); ensureDomObserver(); requestBurst();
847
+ patchShowAds(); getIO(); ensureDomObserver();
848
+ ezCmd(() => { try { window.ezstandalone?.showAds?.(); } catch (_) {} });
849
+ requestBurst();
828
850
  });
829
851
 
830
852
  const burstEvts = [
@@ -847,12 +869,6 @@
847
869
  function bindScroll() {
848
870
  let ticking = false;
849
871
  window.addEventListener('scroll', () => {
850
- try {
851
- const y = window.scrollY || window.pageYOffset || 0;
852
- const dy = y - (S.lastScrollY || 0);
853
- if (Math.abs(dy) > 2) S.scrollDir = dy > 0 ? 1 : -1;
854
- S.lastScrollY = y;
855
- } catch (_) {}
856
872
  if (ticking) return;
857
873
  ticking = true;
858
874
  requestAnimationFrame(() => { ticking = false; requestBurst(); });
@@ -862,7 +878,6 @@
862
878
  // ── Boot ───────────────────────────────────────────────────────────────────
863
879
 
864
880
  S.pageKey = pageKey();
865
- try { S.lastScrollY = window.scrollY || window.pageYOffset || 0; } catch (_) { S.lastScrollY = 0; }
866
881
  muteConsole();
867
882
  ensureTcfLocator();
868
883
  warmNetwork();