nodebb-plugin-ezoic-infinite 1.7.25 → 1.7.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/client.js +25 -21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.7.25",
3
+ "version": "1.7.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
@@ -1,5 +1,5 @@
1
1
  /**
2
- * NodeBB Ezoic Infinite Ads — client.js v31
2
+ * NodeBB Ezoic Infinite Ads — client.js v33
3
3
  *
4
4
  * Historique des corrections majeures
5
5
  * ────────────────────────────────────
@@ -31,6 +31,11 @@
31
31
  *
32
32
  * v29 Fix ancrage topics : data-index → data-tid.
33
33
  *
34
+ * v32 Retour anchorAttr = data-index pour ezoic-ad-between (comme v20.1).
35
+ * data-tid peut être absent sur li[component="category/topic"] → clés
36
+ * invalides → wraps empilés sur pos0. data-index est toujours présent.
37
+ * pruneOrphansBetween cherche li[data-index="N"] — cohérent avec v20.1.
38
+ *
34
39
  * v31 pruneOrphans réactivé UNIQUEMENT pour ezoic-ad-between (topics de catégorie).
35
40
  * NodeBB NE virtualise PAS les topics dans une liste de catégorie — les ancres
36
41
  * restent dans le DOM entre les scrolls. pruneOrphans est donc safe ici et
@@ -98,7 +103,7 @@
98
103
  */
99
104
  const KIND = {
100
105
  'ezoic-ad-message': { sel: SEL.post, baseTag: '', anchorAttr: 'data-pid', ordinalAttr: 'data-index' },
101
- 'ezoic-ad-between': { sel: SEL.topic, baseTag: 'li', anchorAttr: 'data-tid', ordinalAttr: 'data-index' },
106
+ 'ezoic-ad-between': { sel: SEL.topic, baseTag: 'li', anchorAttr: 'data-index', ordinalAttr: 'data-index' },
102
107
  'ezoic-ad-categories': { sel: SEL.category, baseTag: 'li', anchorAttr: 'data-cid', ordinalAttr: null },
103
108
  };
104
109
 
@@ -257,31 +262,30 @@
257
262
  return null;
258
263
  }
259
264
 
260
- function recycleOrphanId(klass) {
261
- // Quand le pool est épuisé : cherche un wrap orphelin (ancre hors DOM, non rempli)
262
- // loin au-dessus du viewport et libère son ID.
265
+ function recycleDistantWrap(klass) {
266
+ // Quand le pool est épuisé : récupère le wrap le plus loin au-dessus du
267
+ // viewport (qu'il soit orphelin ou non) pour libérer son ID.
268
+ // Les topics/pubs à 4+ viewports au-dessus ne sont plus visibles — on peut
269
+ // recycler leur slot. Non-remplis en priorité, remplis si rien d'autre.
263
270
  const vh = window.innerHeight || 800;
264
- const threshold = -vh * 3;
265
- let best = null, bestBottom = Infinity;
271
+ const threshold = -vh * 4;
272
+
273
+ let bestEmpty = null, bestEmptyBottom = Infinity;
274
+ let bestFilled = null, bestFilledBottom = Infinity;
275
+
266
276
  document.querySelectorAll(`.${WRAP_CLASS}.${klass}`).forEach(wrap => {
267
- if (wrap.getAttribute(A_CREATED) === null) return;
268
- if (isFilled(wrap)) return;
269
- const key = wrap.getAttribute(A_ANCHOR);
270
- if (!key) return;
271
- const colonIdx = key.indexOf(':');
272
- const anchorId = key.slice(colonIdx + 1);
273
- const cfg = KIND[klass];
274
- if (!cfg) return;
275
- try {
276
- const found = document.querySelector(`${cfg.sel}[${cfg.anchorAttr}="${anchorId}"]`);
277
- if (found?.isConnected) return; // ancre encore dans le DOM, pas orphelin
278
- } catch (_) { return; }
279
277
  try {
280
278
  const rect = wrap.getBoundingClientRect();
281
279
  if (rect.bottom > threshold) return;
282
- if (rect.bottom < bestBottom) { bestBottom = rect.bottom; best = wrap; }
280
+ if (!isFilled(wrap)) {
281
+ if (rect.bottom < bestEmptyBottom) { bestEmptyBottom = rect.bottom; bestEmpty = wrap; }
282
+ } else {
283
+ if (rect.bottom < bestFilledBottom) { bestFilledBottom = rect.bottom; bestFilled = wrap; }
284
+ }
283
285
  } catch (_) {}
284
286
  });
287
+
288
+ const best = bestEmpty ?? bestFilled;
285
289
  if (!best) return null;
286
290
  const id = parseInt(best.getAttribute(A_WRAPID), 10);
287
291
  if (!Number.isFinite(id)) return null;
@@ -405,7 +409,7 @@
405
409
  if (findWrap(key)) continue;
406
410
 
407
411
  let id = pickId(poolKey);
408
- if (!id) { id = recycleOrphanId(klass); if (!id) continue; }
412
+ if (!id) { id = recycleDistantWrap(klass); if (!id) continue; }
409
413
 
410
414
  const w = insertAfter(el, id, klass, key);
411
415
  if (w) { observePh(id); inserted++; }