nodebb-plugin-ezoic-infinite 1.8.26 → 1.8.27

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.8.26",
3
+ "version": "1.8.27",
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
@@ -83,7 +83,7 @@
83
83
  const MAX_INFLIGHT = 4; // max showAds() simultanés
84
84
  const SHOW_THROTTLE_MS = 900; // anti-spam showAds() par id
85
85
  const BURST_COOLDOWN_MS = 200; // délai min entre deux déclenchements de burst
86
- const MIN_PLACEHOLDER_HEIGHT = 50; // réservation minimale perçue
86
+ const MIN_PLACEHOLDER_HEIGHT = 1; // placeholder minimal (test stabilité scroll)
87
87
 
88
88
  // Marges IO larges et fixes — observer créé une seule fois au boot
89
89
  const IO_MARGIN_DESKTOP = '2500px 0px 2500px 0px';
@@ -370,17 +370,30 @@
370
370
  best.setAttribute(A_CREATED, String(ts()));
371
371
  best.setAttribute(A_SHOWN, '0');
372
372
  best.classList.remove('is-empty');
373
- const ph = best.querySelector(`#${PH_PREFIX}${id}`);
374
- if (ph) ph.innerHTML = '';
373
+ const oldPh = best.querySelector(`#${PH_PREFIX}${id}`);
374
+ if (oldPh) {
375
+ const fresh = document.createElement('div');
376
+ fresh.id = `${PH_PREFIX}${id}`;
377
+ fresh.setAttribute('data-ezoic-id', String(id));
378
+ fresh.style.minHeight = `${MIN_PLACEHOLDER_HEIGHT}px`;
379
+ oldPh.replaceWith(fresh);
380
+ }
375
381
  targetEl.insertAdjacentElement('afterend', best);
376
382
  });
377
383
  if (oldKey && S.wrapByKey.get(oldKey) === best) S.wrapByKey.delete(oldKey);
378
384
  S.wrapByKey.set(newKey, best);
379
385
 
380
- // Délais requis : destroyPlaceholders est asynchrone en interne
381
- const doDestroy = () => { try { ez.destroyPlaceholders([id]); } catch (_) {} setTimeout(doDefine, 300); };
382
- const doDefine = () => { try { ez.define([id]); } catch (_) {} setTimeout(doDisplay, 300); };
383
- const doDisplay = () => { try { ez.displayMore([id]); } catch (_) {} };
386
+ // Recyclage Ezoic : détruire l'ancien placeholder avant de réutiliser le même ID.
387
+ // Puis ré-observer + re-show (batché via patchShowAds) sur le placeholder recréé.
388
+ const doDestroy = () => {
389
+ try { ez.destroyPlaceholders(id); } catch (_) {
390
+ try { ez.destroyPlaceholders([id]); } catch (_) {}
391
+ }
392
+ setTimeout(() => {
393
+ try { observePh(id); } catch (_) {}
394
+ try { enqueueShow(id); } catch (_) {}
395
+ }, 450);
396
+ };
384
397
  try { (typeof ez.cmd?.push === 'function') ? ez.cmd.push(doDestroy) : doDestroy(); } catch (_) {}
385
398
 
386
399
  return { id, wrap: best };
@@ -620,17 +633,34 @@
620
633
  if (window.__nbbEzPatched || typeof ez.showAds !== 'function') return;
621
634
  window.__nbbEzPatched = true;
622
635
  const orig = ez.showAds.bind(ez);
636
+ const q = new Set();
637
+ let flushTimer = null;
638
+ const BATCH_SIZE = 3;
639
+ const FLUSH_MS = 80;
640
+ const flush = () => {
641
+ flushTimer = null;
642
+ if (isBlocked() || !q.size) return;
643
+ const ids = Array.from(q).sort((a, b) => a - b);
644
+ q.clear();
645
+ const valid = ids.filter(id => document.getElementById(`${PH_PREFIX}${id}`)?.isConnected);
646
+ for (let i = 0; i < valid.length; i += BATCH_SIZE) {
647
+ const chunk = valid.slice(i, i + BATCH_SIZE);
648
+ try { orig(...chunk); } catch (_) {
649
+ for (const id of chunk) { try { orig(id); } catch (_) {} }
650
+ }
651
+ }
652
+ };
623
653
  ez.showAds = function (...args) {
624
654
  if (isBlocked()) return;
625
- const ids = args.length === 1 && Array.isArray(args[0]) ? args[0] : args;
626
- const seen = new Set();
655
+ const ids = args.length === 1 && Array.isArray(args[0]) ? args[0] : args;
627
656
  for (const v of ids) {
628
657
  const id = parseInt(v, 10);
629
- if (!Number.isFinite(id) || id <= 0 || seen.has(id)) continue;
658
+ if (!Number.isFinite(id) || id <= 0) continue;
630
659
  if (!document.getElementById(`${PH_PREFIX}${id}`)?.isConnected) continue;
631
- seen.add(id);
632
- try { orig(id); } catch (_) {}
660
+ q.add(id);
633
661
  }
662
+ if (!q.size) return;
663
+ if (!flushTimer) flushTimer = setTimeout(flush, FLUSH_MS);
634
664
  };
635
665
  } catch (_) {}
636
666
  };
package/public/style.css CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * NodeBB Ezoic Infinite Ads — style.css (v20.1)
2
+ * NodeBB Ezoic Infinite Ads — style.css (v20)
3
3
  */
4
4
 
5
5
  /* ── Wrapper ──────────────────────────────────────────────────────────────── */
@@ -39,9 +39,9 @@
39
39
  /* Ne pas écraser la hauteur réelle calculée par Ezoic */
40
40
  .nodebb-ezoic-wrap .ezoic-ad,
41
41
  .nodebb-ezoic-wrap span.ezoic-ad {
42
- display: block !important;
43
42
  margin: 0 !important;
44
43
  padding: 0 !important;
44
+ display: block !important;
45
45
  height: auto !important;
46
46
  min-height: unset !important;
47
47
  max-height: none !important;
@@ -60,8 +60,8 @@
60
60
 
61
61
  /* ── État vide ────────────────────────────────────────────────────────────── */
62
62
  /*
63
- Ajouté après le délai d'empty-check si aucun fill détecté.
64
- Collapse à 1px : réserve minimale, reste observable par l'IO.
63
+ Ajouté 20s après showAds si aucun fill détecté.
64
+ Collapse à 1px : réserve minimale demandée, reste observable par l'IO.
65
65
  */
66
66
  .nodebb-ezoic-wrap.is-empty {
67
67
  display: block !important;
@@ -77,4 +77,4 @@
77
77
  .ezoic-ad {
78
78
  margin: 0 !important;
79
79
  padding: 0 !important;
80
- }
80
+ }