nodebb-plugin-ezoic-infinite 1.7.20 → 1.7.21
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 +1 -1
- package/public/client.js +21 -69
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* NodeBB Ezoic Infinite Ads — client.js
|
|
2
|
+
* NodeBB Ezoic Infinite Ads — client.js v28
|
|
3
3
|
*
|
|
4
4
|
* Historique des corrections majeures
|
|
5
5
|
* ────────────────────────────────────
|
|
@@ -18,15 +18,21 @@
|
|
|
18
18
|
*
|
|
19
19
|
* v25 Table KIND unifiée avec baseTag + ordinalAttr.
|
|
20
20
|
* Fix scroll-up / virtualisation NodeBB :
|
|
21
|
-
* – pruneOrphans : PRUNE_STABLE_MS = 45 s, isFilled guard en premier.
|
|
22
21
|
* – decluster : isFilled en premier, A_CREATED grace period (FILL_GRACE_MS).
|
|
23
22
|
* Tentative recyclage d'id (v25) → cause exactement le même bug (wraps
|
|
24
23
|
* déplacés laissent les positions originales libres → réinjection en haut).
|
|
25
24
|
*
|
|
26
25
|
* v26 Suppression définitive du recyclage d'id.
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
26
|
+
* KIND simplifié.
|
|
27
|
+
*
|
|
28
|
+
* v27 pruneOrphans supprimé (faux-orphelins sur virtualisation NodeBB).
|
|
29
|
+
*
|
|
30
|
+
* v28 decluster supprimé.
|
|
31
|
+
* Analyse : decluster appelait dropWrap() qui faisait S.mountedIds.delete(id).
|
|
32
|
+
* Un wrap vide adjacent à un autre wrap → supprimé → id libéré → réinjecté
|
|
33
|
+
* en haut au prochain scroll. Exactement le bug observé.
|
|
34
|
+
* Les deux mécanismes de nettoyage actif (pruneOrphans + decluster) sont
|
|
35
|
+
* maintenant retirés. Seul cleanup() à la navigation peut supprimer des wraps.
|
|
30
36
|
*/
|
|
31
37
|
(function () {
|
|
32
38
|
'use strict';
|
|
@@ -40,8 +46,6 @@
|
|
|
40
46
|
const A_CREATED = 'data-ezoic-created'; // timestamp création ms
|
|
41
47
|
const A_SHOWN = 'data-ezoic-shown'; // timestamp dernier showAds ms
|
|
42
48
|
|
|
43
|
-
const PRUNE_STABLE_MS = 45_000; // délai avant pruning (évite faux-orphelins scroll-up)
|
|
44
|
-
const FILL_GRACE_MS = 25_000; // fenêtre fill async Ezoic (SSP auction)
|
|
45
49
|
const EMPTY_CHECK_MS = 20_000; // délai collapse wrap vide post-show
|
|
46
50
|
const MAX_INSERTS_RUN = 6;
|
|
47
51
|
const MAX_INFLIGHT = 4;
|
|
@@ -255,66 +259,16 @@
|
|
|
255
259
|
} catch (_) {}
|
|
256
260
|
}
|
|
257
261
|
|
|
258
|
-
// ── Prune
|
|
262
|
+
// ── Prune : désactivé ─────────────────────────────────────────────────────
|
|
263
|
+
//
|
|
264
|
+
// pruneOrphans() a été supprimé car il causait le bug "pubs en haut".
|
|
265
|
+
// NodeBB virtualise les posts hors viewport → les ancres disparaissent du DOM
|
|
266
|
+
// temporairement → pruneOrphans supprimait les wraps → scroll retour → les
|
|
267
|
+
// ancres revenaient → injectBetween réinjectait tout en haut.
|
|
268
|
+
//
|
|
269
|
+
// Les wraps ne sont supprimés que par cleanup() à chaque navigation ajaxify.
|
|
270
|
+
// decluster() et pruneOrphans() sont désactivés — voir v28.
|
|
259
271
|
|
|
260
|
-
/**
|
|
261
|
-
* Supprime les wraps VIDES dont l'ancre a disparu du DOM.
|
|
262
|
-
*
|
|
263
|
-
* isFilled en premier : un wrap rempli n'est JAMAIS supprimé.
|
|
264
|
-
* PRUNE_STABLE_MS (45 s) : pendant cette fenêtre une ancre absente est
|
|
265
|
-
* considérée comme virtualisée par NodeBB (scroll up), pas comme orphelin réel.
|
|
266
|
-
*/
|
|
267
|
-
function pruneOrphans(klass) {
|
|
268
|
-
const meta = KIND[klass];
|
|
269
|
-
if (!meta) return;
|
|
270
|
-
|
|
271
|
-
for (const w of document.querySelectorAll(`.${WRAP_CLASS}.${klass}`)) {
|
|
272
|
-
if (isFilled(w)) continue;
|
|
273
|
-
if (ts() - parseInt(w.getAttribute(A_CREATED) || '0', 10) < PRUNE_STABLE_MS) continue;
|
|
274
|
-
|
|
275
|
-
const key = w.getAttribute(A_ANCHOR) ?? '';
|
|
276
|
-
const sid = key.slice(klass.length + 1);
|
|
277
|
-
if (!sid) { mutate(() => dropWrap(w)); continue; }
|
|
278
|
-
|
|
279
|
-
const sel = `${meta.baseTag}[${meta.anchorAttr}="${sid.replace(/"/g, '\\"')}"]`;
|
|
280
|
-
const anchorEl = document.querySelector(sel);
|
|
281
|
-
if (!anchorEl || !anchorEl.isConnected) mutate(() => dropWrap(w));
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// ── Decluster ──────────────────────────────────────────────────────────────
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Deux wraps adjacents → supprimer le courant s'il est vide et hors grâce.
|
|
289
|
-
* Guards dans l'ordre :
|
|
290
|
-
* 1. isFilled(w) → jamais toucher un wrap rempli
|
|
291
|
-
* 2. A_CREATED < FILL_GRACE → wrap trop récent (pas encore showAds'd)
|
|
292
|
-
* 3. A_SHOWN grace → fill en cours
|
|
293
|
-
* 4. isFilled(prev) → voisin rempli, intouchable → break
|
|
294
|
-
* 5. A_CREATED prev grace → voisin trop récent → break
|
|
295
|
-
* 6. A_SHOWN prev grace → break
|
|
296
|
-
* → les deux vides et hors grâce : supprimer le courant
|
|
297
|
-
*/
|
|
298
|
-
function decluster(klass) {
|
|
299
|
-
for (const w of document.querySelectorAll(`.${WRAP_CLASS}.${klass}`)) {
|
|
300
|
-
if (isFilled(w)) continue;
|
|
301
|
-
if (ts() - parseInt(w.getAttribute(A_CREATED) || '0', 10) < FILL_GRACE_MS) continue;
|
|
302
|
-
const wShown = parseInt(w.getAttribute(A_SHOWN) || '0', 10);
|
|
303
|
-
if (wShown && ts() - wShown < FILL_GRACE_MS) continue;
|
|
304
|
-
|
|
305
|
-
let prev = w.previousElementSibling, steps = 0;
|
|
306
|
-
while (prev && steps++ < 3) {
|
|
307
|
-
if (!prev.classList?.contains(WRAP_CLASS)) { prev = prev.previousElementSibling; continue; }
|
|
308
|
-
if (isFilled(prev)) break;
|
|
309
|
-
if (ts() - parseInt(prev.getAttribute(A_CREATED) || '0', 10) < FILL_GRACE_MS) break;
|
|
310
|
-
const pShown = parseInt(prev.getAttribute(A_SHOWN) || '0', 10);
|
|
311
|
-
if (pShown && ts() - pShown < FILL_GRACE_MS) break;
|
|
312
|
-
|
|
313
|
-
mutate(() => dropWrap(w));
|
|
314
|
-
break;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
272
|
|
|
319
273
|
// ── Injection ──────────────────────────────────────────────────────────────
|
|
320
274
|
|
|
@@ -354,7 +308,7 @@
|
|
|
354
308
|
if (findWrap(key)) continue;
|
|
355
309
|
|
|
356
310
|
const id = pickId(poolKey);
|
|
357
|
-
if (!id) continue; // pool épuisé :
|
|
311
|
+
if (!id) continue; // pool épuisé : tous les ids sont montés, on passe au suivant
|
|
358
312
|
|
|
359
313
|
const w = insertAfter(el, id, klass, key);
|
|
360
314
|
if (w) { observePh(id); inserted++; }
|
|
@@ -498,9 +452,7 @@
|
|
|
498
452
|
const exec = (klass, getItems, cfgEnable, cfgInterval, cfgShowFirst, poolKey) => {
|
|
499
453
|
if (!normBool(cfgEnable)) return 0;
|
|
500
454
|
const interval = Math.max(1, parseInt(cfgInterval, 10) || 3);
|
|
501
|
-
pruneOrphans(klass);
|
|
502
455
|
const n = injectBetween(klass, getItems(), interval, normBool(cfgShowFirst), poolKey);
|
|
503
|
-
if (n) decluster(klass);
|
|
504
456
|
return n;
|
|
505
457
|
};
|
|
506
458
|
|