nodebb-plugin-ezoic-infinite 1.8.28 → 1.8.29

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 +38 -31
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.8.28",
3
+ "version": "1.8.29",
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
@@ -136,6 +136,7 @@
136
136
  firstShown: false,
137
137
  wrapsByClass: new Map(),
138
138
  kind: null,
139
+ phState: new Map(), // id -> new|show-queued|shown|destroyed
139
140
  };
140
141
 
141
142
  let blockedUntil = 0;
@@ -146,30 +147,19 @@
146
147
  const normBool = v => v === true || v === 'true' || v === 1 || v === '1' || v === 'on';
147
148
  const FILL_SEL = 'iframe, ins, img, video, [data-google-container-id], div[id$="__container__"]';
148
149
  const isFilled = n => !!(n?.querySelector?.(FILL_SEL));
150
+ function placeholderLooksUsed(ph) {
151
+ try {
152
+ if (!ph?.isConnected) return false;
153
+ return !!ph.querySelector('ins.adsbygoogle, iframe, [data-google-container-id], div[id$="__container__"]');
154
+ } catch (_) { return false; }
155
+ }
156
+
149
157
 
150
158
  function mutate(fn) {
151
159
  S.mutGuard++;
152
160
  try { fn(); } finally { S.mutGuard--; }
153
161
  }
154
162
 
155
- function clearEmptyIfFilled(wrap) {
156
- try {
157
- if (!wrap?.isConnected) return false;
158
- const ph = wrap.querySelector(`[id^="${PH_PREFIX}"]`);
159
- if (!ph) return false;
160
- if (!isFilled(ph)) return false;
161
- wrap.classList.remove('is-empty');
162
- return true;
163
- } catch (_) { return false; }
164
- }
165
-
166
- function scheduleUncollapseChecksForWrap(wrap) {
167
- if (!wrap) return;
168
- for (const ms of [500, 1500, 3000, 7000, 15000]) {
169
- setTimeout(() => { try { clearEmptyIfFilled(wrap); } catch (_) {} }, ms);
170
- }
171
- }
172
-
173
163
 
174
164
  function clearEmptyIfFilled(wrap) {
175
165
  try {
@@ -178,6 +168,8 @@ function scheduleUncollapseChecksForWrap(wrap) {
178
168
  if (!ph) return false;
179
169
  if (!isFilled(ph)) return false;
180
170
  wrap.classList.remove('is-empty');
171
+ const id = parseInt(wrap.getAttribute(A_WRAPID) || '0', 10);
172
+ if (Number.isFinite(id) && id > 0) S.phState.set(id, 'shown');
181
173
  return true;
182
174
  } catch (_) { return false; }
183
175
  }
@@ -408,14 +400,12 @@ function scheduleUncollapseChecksForWrap(wrap) {
408
400
  best.setAttribute(A_CREATED, String(ts()));
409
401
  best.setAttribute(A_SHOWN, '0');
410
402
  best.classList.remove('is-empty');
411
- const oldPh = best.querySelector(`#${PH_PREFIX}${id}`);
412
- if (oldPh) {
413
- const fresh = document.createElement('div');
414
- fresh.id = `${PH_PREFIX}${id}`;
415
- fresh.setAttribute('data-ezoic-id', String(id));
416
- fresh.style.minHeight = `${MIN_PLACEHOLDER_HEIGHT}px`;
417
- oldPh.replaceWith(fresh);
418
- }
403
+ best.replaceChildren();
404
+ const fresh = document.createElement('div');
405
+ fresh.id = `${PH_PREFIX}${id}`;
406
+ fresh.setAttribute('data-ezoic-id', String(id));
407
+ fresh.style.minHeight = `${MIN_PLACEHOLDER_HEIGHT}px`;
408
+ best.appendChild(fresh);
419
409
  targetEl.insertAdjacentElement('afterend', best);
420
410
  });
421
411
  if (oldKey && S.wrapByKey.get(oldKey) === best) S.wrapByKey.delete(oldKey);
@@ -424,11 +414,13 @@ function scheduleUncollapseChecksForWrap(wrap) {
424
414
  // Recyclage Ezoic : détruire l'ancien placeholder avant de réutiliser le même ID.
425
415
  // Puis ré-observer + re-show (batché via patchShowAds) sur le placeholder recréé.
426
416
  const doDestroy = () => {
417
+ S.phState.set(id, 'destroyed');
427
418
  try { ez.destroyPlaceholders(id); } catch (_) {
428
419
  try { ez.destroyPlaceholders([id]); } catch (_) {}
429
420
  }
430
421
  setTimeout(() => {
431
422
  try { observePh(id); } catch (_) {}
423
+ S.phState.set(id, 'new');
432
424
  try { enqueueShow(id); } catch (_) {}
433
425
  }, 450);
434
426
  };
@@ -463,6 +455,7 @@ function scheduleUncollapseChecksForWrap(wrap) {
463
455
  const w = makeWrap(id, klass, key);
464
456
  mutate(() => el.insertAdjacentElement('afterend', w));
465
457
  S.mountedIds.add(id);
458
+ S.phState.set(id, 'new');
466
459
  S.wrapByKey.set(key, w);
467
460
  registerWrap(klass, w);
468
461
  return w;
@@ -473,7 +466,7 @@ function scheduleUncollapseChecksForWrap(wrap) {
473
466
  const ph = w.querySelector(`[id^="${PH_PREFIX}"]`);
474
467
  if (ph instanceof Element) S.io?.unobserve(ph);
475
468
  const id = parseInt(w.getAttribute(A_WRAPID), 10);
476
- if (Number.isFinite(id)) S.mountedIds.delete(id);
469
+ if (Number.isFinite(id)) { S.mountedIds.delete(id); S.phState.delete(id); }
477
470
  const key = w.getAttribute(A_ANCHOR);
478
471
  if (key && S.wrapByKey.get(key) === w) S.wrapByKey.delete(key);
479
472
  const klass = Array.from(w.classList || []).find(c => c !== WRAP_CLASS && c.startsWith('ezoic-ad-'));
@@ -592,11 +585,14 @@ function scheduleUncollapseChecksForWrap(wrap) {
592
585
 
593
586
  function enqueueShow(id) {
594
587
  if (!id || isBlocked()) return;
588
+ const st = S.phState.get(id);
589
+ if (st === 'show-queued' || st === 'shown') return;
595
590
  if (ts() - (S.lastShow.get(id) ?? 0) < SHOW_THROTTLE_MS) return;
596
591
  if (S.inflight >= MAX_INFLIGHT) {
597
- if (!S.pendingSet.has(id)) { S.pending.push(id); S.pendingSet.add(id); }
592
+ if (!S.pendingSet.has(id)) { S.pending.push(id); S.pendingSet.add(id); S.phState.set(id, 'show-queued'); }
598
593
  return;
599
594
  }
595
+ S.phState.set(id, 'show-queued');
600
596
  startShow(id);
601
597
  }
602
598
 
@@ -625,13 +621,15 @@ function scheduleUncollapseChecksForWrap(wrap) {
625
621
  try {
626
622
  if (isBlocked()) { clearTimeout(timer); return release(); }
627
623
  const ph = document.getElementById(`${PH_PREFIX}${id}`);
628
- if (!ph?.isConnected || isFilled(ph)) { clearTimeout(timer); return release(); }
624
+ if (!ph?.isConnected) { S.phState.delete(id); clearTimeout(timer); return release(); }
625
+ if (isFilled(ph) || placeholderLooksUsed(ph)) { S.phState.set(id, 'shown'); clearTimeout(timer); return release(); }
629
626
 
630
627
  const t = ts();
631
628
  if (t - (S.lastShow.get(id) ?? 0) < SHOW_THROTTLE_MS) { clearTimeout(timer); return release(); }
632
629
  S.lastShow.set(id, t);
633
630
 
634
631
  try { ph.closest?.(`.${WRAP_CLASS}`)?.setAttribute(A_SHOWN, String(t)); } catch (_) {}
632
+ S.phState.set(id, 'shown');
635
633
 
636
634
  window.ezstandalone = window.ezstandalone || {};
637
635
  const ez = window.ezstandalone;
@@ -684,7 +682,12 @@ function scheduleUncollapseChecksForWrap(wrap) {
684
682
  if (isBlocked() || !q.size) return;
685
683
  const ids = Array.from(q).sort((a, b) => a - b);
686
684
  q.clear();
687
- const valid = ids.filter(id => document.getElementById(`${PH_PREFIX}${id}`)?.isConnected);
685
+ const valid = ids.filter(id => {
686
+ const ph = document.getElementById(`${PH_PREFIX}${id}`);
687
+ if (!ph?.isConnected) { S.phState.delete(id); return false; }
688
+ if (placeholderLooksUsed(ph)) { S.phState.set(id, 'shown'); return false; }
689
+ return true;
690
+ });
688
691
  for (let i = 0; i < valid.length; i += BATCH_SIZE) {
689
692
  const chunk = valid.slice(i, i + BATCH_SIZE);
690
693
  try { orig(...chunk); } catch (_) {
@@ -698,7 +701,10 @@ function scheduleUncollapseChecksForWrap(wrap) {
698
701
  for (const v of ids) {
699
702
  const id = parseInt(v, 10);
700
703
  if (!Number.isFinite(id) || id <= 0) continue;
701
- if (!document.getElementById(`${PH_PREFIX}${id}`)?.isConnected) continue;
704
+ const ph = document.getElementById(`${PH_PREFIX}${id}`);
705
+ if (!ph?.isConnected) continue;
706
+ if (placeholderLooksUsed(ph)) { S.phState.set(id, 'shown'); continue; }
707
+ S.phState.set(id, 'show-queued');
702
708
  q.add(id);
703
709
  }
704
710
  if (!q.size) return;
@@ -804,6 +810,7 @@ function scheduleUncollapseChecksForWrap(wrap) {
804
810
  S.wrapByKey.clear();
805
811
  S.wrapsByClass.clear();
806
812
  S.kind = null;
813
+ S.phState.clear();
807
814
  S.inflight = 0;
808
815
  S.pending = [];
809
816
  S.pendingSet.clear();