nodebb-plugin-ezoic-infinite 1.7.87 → 1.7.88

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.7.87",
3
+ "version": "1.7.88",
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
@@ -77,9 +77,7 @@
77
77
  const A_CREATED = 'data-ezoic-created'; // timestamp création ms
78
78
  const A_SHOWN = 'data-ezoic-shown'; // timestamp dernier showAds ms
79
79
 
80
- // anti-race fill async (Ezoic peut remplir bien après showAds)
81
- const EMPTY_CHECK_PASSES = [20_000, 25_000, 35_000];
82
-
80
+ const EMPTY_CHECK_MS = 20_000; // délai avant collapse d'un wrap vide post-show
83
81
  const MIN_PRUNE_AGE_MS = 8_000; // délai de grâce avant pruning (stabilisation DOM)
84
82
  const MAX_INSERTS_RUN = 6; // max insertions par appel runCore
85
83
  const MAX_INFLIGHT = 4; // max showAds() simultanés
@@ -122,8 +120,6 @@
122
120
  cursors: { topics: 0, posts: 0, categories: 0 },
123
121
  mountedIds: new Set(),
124
122
  lastShow: new Map(),
125
- emptyChecks: new Map(), // id -> [timerIds] checks is-empty multi-pass
126
- fillObs: new Map(), // id -> MutationObserver placeholder fill tardif
127
123
  io: null,
128
124
  domObs: null,
129
125
  mutGuard: 0, // >0 : mutations DOM en cours (MutationObserver ignoré)
@@ -146,48 +142,6 @@
146
142
  const normBool = v => v === true || v === 'true' || v === 1 || v === '1' || v === 'on';
147
143
  const isFilled = n => !!(n?.querySelector?.('iframe, ins, img, video, [data-google-container-id]'));
148
144
 
149
- function clearEmptyChecks(id) {
150
- const arr = S.emptyChecks.get(id);
151
- if (arr) {
152
- for (const t of arr) clearTimeout(t);
153
- S.emptyChecks.delete(id);
154
- }
155
- }
156
-
157
- function queueEmptyCheck(id, timerId) {
158
- const arr = S.emptyChecks.get(id) || [];
159
- arr.push(timerId);
160
- S.emptyChecks.set(id, arr);
161
- }
162
-
163
- function uncollapseIfFilled(ph) {
164
- try {
165
- const wrap = ph?.closest?.(`.${WRAP_CLASS}`);
166
- if (!wrap) return;
167
- if (isFilled(ph)) wrap.classList.remove('is-empty');
168
- } catch (_) {}
169
- }
170
-
171
- function watchPlaceholderFill(id) {
172
- try {
173
- const ph = document.getElementById(`${PH_PREFIX}${id}`);
174
- if (!ph?.isConnected) return;
175
- if (S.fillObs.has(id)) return;
176
- const obs = new MutationObserver(() => uncollapseIfFilled(ph));
177
- obs.observe(ph, { childList: true, subtree: true, attributes: true });
178
- S.fillObs.set(id, obs);
179
- uncollapseIfFilled(ph);
180
- } catch (_) {}
181
- }
182
-
183
- function unwatchPlaceholderFill(id) {
184
- const obs = S.fillObs.get(id);
185
- if (obs) {
186
- try { obs.disconnect(); } catch (_) {}
187
- S.fillObs.delete(id);
188
- }
189
- }
190
-
191
145
  function mutate(fn) {
192
146
  S.mutGuard++;
193
147
  try { fn(); } finally { S.mutGuard--; }
@@ -387,7 +341,6 @@
387
341
  // Neutraliser l'IO sur ce wrap avant déplacement — évite un showAds
388
342
  // parasite si le nœud était encore dans la zone IO_MARGIN.
389
343
  try { const ph = best.querySelector(`#${PH_PREFIX}${id}`); if (ph) S.io?.unobserve(ph); } catch (_) {}
390
- if (Number.isFinite(id)) clearEmptyChecks(id);
391
344
  mutate(() => {
392
345
  best.setAttribute(A_ANCHOR, newKey);
393
346
  best.setAttribute(A_CREATED, String(ts()));
@@ -399,7 +352,6 @@
399
352
  });
400
353
  if (oldKey && S.wrapByKey.get(oldKey) === best) S.wrapByKey.delete(oldKey);
401
354
  S.wrapByKey.set(newKey, best);
402
- observePh(id);
403
355
 
404
356
  // Délais requis : destroyPlaceholders est asynchrone en interne
405
357
  const doDestroy = () => { try { ez.destroyPlaceholders([id]); } catch (_) {} setTimeout(doDefine, 300); };
@@ -444,7 +396,6 @@
444
396
  const ph = w.querySelector(`[id^="${PH_PREFIX}"]`);
445
397
  if (ph instanceof Element) S.io?.unobserve(ph);
446
398
  const id = parseInt(w.getAttribute(A_WRAPID), 10);
447
- if (Number.isFinite(id)) { clearEmptyChecks(id); unwatchPlaceholderFill(id); }
448
399
  if (Number.isFinite(id)) S.mountedIds.delete(id);
449
400
  const key = w.getAttribute(A_ANCHOR);
450
401
  if (key && S.wrapByKey.get(key) === w) S.wrapByKey.delete(key);
@@ -552,10 +503,7 @@
552
503
 
553
504
  function observePh(id) {
554
505
  const ph = document.getElementById(`${PH_PREFIX}${id}`);
555
- if (ph?.isConnected) {
556
- try { getIO()?.observe(ph); } catch (_) {}
557
- watchPlaceholderFill(id);
558
- }
506
+ if (ph?.isConnected) try { getIO()?.observe(ph); } catch (_) {}
559
507
  }
560
508
 
561
509
  function enqueueShow(id) {
@@ -595,9 +543,6 @@
595
543
  const ph = document.getElementById(`${PH_PREFIX}${id}`);
596
544
  if (!ph?.isConnected || isFilled(ph)) { clearTimeout(timer); return release(); }
597
545
 
598
- clearEmptyChecks(id);
599
- try { ph.closest?.(`.${WRAP_CLASS}`)?.classList.remove('is-empty'); } catch (_) {}
600
-
601
546
  const t = ts();
602
547
  if (t - (S.lastShow.get(id) ?? 0) < SHOW_THROTTLE_MS) { clearTimeout(timer); return release(); }
603
548
  S.lastShow.set(id, t);
@@ -617,24 +562,15 @@
617
562
  }
618
563
 
619
564
  function scheduleEmptyCheck(id, showTs) {
620
- clearEmptyChecks(id);
621
-
622
- const runCheck = () => {
565
+ setTimeout(() => {
623
566
  try {
624
567
  const ph = document.getElementById(`${PH_PREFIX}${id}`);
625
568
  const wrap = ph?.closest?.(`.${WRAP_CLASS}`);
626
569
  if (!wrap || !ph?.isConnected) return;
627
570
  if (parseInt(wrap.getAttribute(A_SHOWN) || '0', 10) > showTs) return;
628
- const filled = isFilled(ph);
629
- if (filled) wrap.classList.remove('is-empty');
630
- else wrap.classList.add('is-empty');
571
+ wrap.classList.toggle('is-empty', !isFilled(ph));
631
572
  } catch (_) {}
632
- };
633
-
634
- for (const delay of EMPTY_CHECK_PASSES) {
635
- const tid = setTimeout(runCheck, delay);
636
- queueEmptyCheck(id, tid);
637
- }
573
+ }, EMPTY_CHECK_MS);
638
574
  }
639
575
 
640
576
  // ── Patch Ezoic showAds ────────────────────────────────────────────────────
@@ -764,10 +700,6 @@
764
700
  S.inflight = 0;
765
701
  S.pending = [];
766
702
  S.pendingSet.clear();
767
- S.emptyChecks.forEach(arr => { try { arr.forEach(clearTimeout); } catch (_) {} });
768
- S.emptyChecks.clear();
769
- S.fillObs.forEach(obs => { try { obs.disconnect(); } catch (_) {} });
770
- S.fillObs.clear();
771
703
  S.burstActive = false;
772
704
  S.runQueued = false;
773
705
  }
package/public/style.css CHANGED
@@ -71,14 +71,6 @@
71
71
  overflow: hidden !important;
72
72
  }
73
73
 
74
- /* Filet de sécurité : si un fill est présent malgré is-empty, on ne collapse pas */
75
- .nodebb-ezoic-wrap.is-empty:has(iframe, ins, img, video, [data-google-container-id]) {
76
- height: auto !important;
77
- min-height: 1px !important;
78
- max-height: none !important;
79
- overflow: visible !important;
80
- }
81
-
82
74
  /* ── Ezoic global (hors de nos wraps) ────────────────────────────────────── */
83
75
  .ezoic-ad {
84
76
  margin: 0 !important;