nodebb-plugin-ezoic-infinite 1.7.32 → 1.7.33
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 +27 -132
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 v36
|
|
3
3
|
*
|
|
4
4
|
* Historique des corrections majeures
|
|
5
5
|
* ────────────────────────────────────
|
|
@@ -30,19 +30,25 @@
|
|
|
30
30
|
* – Toujours désactivé pour les posts : NodeBB virtualise les posts
|
|
31
31
|
* hors-viewport → faux-orphelins → bug réinjection en haut.
|
|
32
32
|
*
|
|
33
|
-
* v34 moveDistantWrap
|
|
34
|
-
* et recréer. Ezoic garde une registry interne des placeholders — recréer
|
|
35
|
-
* un div avec le même id déclenche "already been defined" et bloque
|
|
36
|
-
* showAds(). En déplaçant le même nœud DOM, la registry reste valide.
|
|
33
|
+
* v34 moveDistantWrap — voir v38.
|
|
37
34
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
35
|
+
* v39 Recyclage réel des slots via l'API Ezoic complète :
|
|
36
|
+
* destroyPlaceholders([id]) → déplacement DOM → define([id]) → displayMore([id]).
|
|
37
|
+
* destroyPlaceholders() efface le slot de la registry Ezoic, define() le
|
|
38
|
+
* réenregistre comme neuf, displayMore() est l'API infinite-scroll d'Ezoic
|
|
39
|
+
* (contrairement à showAds() qui est pour le chargement initial).
|
|
40
|
+
* Priorité de recyclage : wraps vides en premier (pas de pub visible perdue),
|
|
41
|
+
* puis wraps remplis si nécessaire. Seuil : 4 viewports au-dessus.
|
|
42
|
+
*
|
|
43
|
+
* v38 Pool épuisé = fin de quota Ezoic par page-view. ez.refresh() interdit
|
|
44
|
+
* sur la même page que ez.enable() — supprimé. moveDistantWrap supprimé :
|
|
45
|
+
* déplacer un wrap "already defined" ne re-sert aucune pub. Pool épuisé →
|
|
46
|
+
* break propre dans injectBetween. muteConsole : ajout warnings refresh.
|
|
41
47
|
*
|
|
42
48
|
* v36 Optimisations chemin critique (scroll → injectBetween) :
|
|
43
49
|
* – S.wrapByKey Map<anchorKey,wrap> : findWrap() passe de querySelector
|
|
44
50
|
* sur tout le doc à un lookup O(1). Mis à jour dans insertAfter,
|
|
45
|
-
*
|
|
51
|
+
* dropWrap et cleanup.
|
|
46
52
|
* – wrapIsLive allégé : pour les voisins immédiats on vérifie les
|
|
47
53
|
* attributs du nœud lui-même sans querySelector global.
|
|
48
54
|
* – MutationObserver : matches() vérifié avant querySelector() pour
|
|
@@ -51,9 +57,6 @@
|
|
|
51
57
|
* v35 Revue complète prod-ready :
|
|
52
58
|
* – initPools protégé contre ré-initialisation inutile (S.poolsReady).
|
|
53
59
|
* – muteConsole élargit à "No valid placeholders for loadMore".
|
|
54
|
-
* – moveDistantWrap appelle ezstandalone.refresh([id]) après déplacement
|
|
55
|
-
* pour forcer Ezoic à réactiver le placeholder sur son nouveau nœud.
|
|
56
|
-
* – A_SHOWN initialisé à '0' dans moveDistantWrap (évite NaN dans parseInt).
|
|
57
60
|
* – Commentaires et historique nettoyés.
|
|
58
61
|
*/
|
|
59
62
|
(function nbbEzoicInfinite() {
|
|
@@ -216,7 +219,7 @@
|
|
|
216
219
|
// Lookup O(1) dans le registre — vrai si le wrap EST encore dans le registre
|
|
217
220
|
// et connecté au DOM (le registre est tenu à jour par insertAfter/dropWrap).
|
|
218
221
|
if (S.wrapByKey.get(key) === wrap) return wrap.isConnected;
|
|
219
|
-
// Fallback :
|
|
222
|
+
// Fallback : registre pas encore à jour ou wrap non enregistré.
|
|
220
223
|
const colonIdx = key.indexOf(':');
|
|
221
224
|
const klass = key.slice(0, colonIdx);
|
|
222
225
|
const anchorId = key.slice(colonIdx + 1);
|
|
@@ -291,67 +294,6 @@
|
|
|
291
294
|
return null;
|
|
292
295
|
}
|
|
293
296
|
|
|
294
|
-
/**
|
|
295
|
-
* Pool épuisé : déplace physiquement le wrap le plus loin au-dessus du
|
|
296
|
-
* viewport vers targetEl. On NE supprime PAS le placeholder — Ezoic garde
|
|
297
|
-
* une registry interne, et recréer un div avec le même id déclenche
|
|
298
|
-
* "already been defined" puis bloque showAds(). En déplaçant le même nœud,
|
|
299
|
-
* la registry reste valide. On appelle ensuite ezstandalone.refresh([id])
|
|
300
|
-
* pour forcer Ezoic à réactiver la pub sur sa nouvelle position.
|
|
301
|
-
*
|
|
302
|
-
* Priorité : wraps non remplis (pas de pub visible perdue), puis remplis.
|
|
303
|
-
*/
|
|
304
|
-
function moveDistantWrap(klass, targetEl, newKey) {
|
|
305
|
-
const vh = window.innerHeight || 800;
|
|
306
|
-
const threshold = -vh * 4; // 4 viewports au-dessus = hors vue assurée
|
|
307
|
-
|
|
308
|
-
let bestEmpty = null, bestEmptyBottom = Infinity;
|
|
309
|
-
let bestFilled = null, bestFilledBottom = Infinity;
|
|
310
|
-
|
|
311
|
-
document.querySelectorAll(`.${WRAP_CLASS}.${klass}`).forEach(wrap => {
|
|
312
|
-
try {
|
|
313
|
-
const rect = wrap.getBoundingClientRect();
|
|
314
|
-
if (rect.bottom > threshold) return;
|
|
315
|
-
if (!isFilled(wrap)) {
|
|
316
|
-
if (rect.bottom < bestEmptyBottom) { bestEmptyBottom = rect.bottom; bestEmpty = wrap; }
|
|
317
|
-
} else {
|
|
318
|
-
if (rect.bottom < bestFilledBottom) { bestFilledBottom = rect.bottom; bestFilled = wrap; }
|
|
319
|
-
}
|
|
320
|
-
} catch (_) {}
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
const best = bestEmpty ?? bestFilled;
|
|
324
|
-
if (!best) return null;
|
|
325
|
-
|
|
326
|
-
const id = parseInt(best.getAttribute(A_WRAPID), 10);
|
|
327
|
-
if (!Number.isFinite(id)) return null;
|
|
328
|
-
|
|
329
|
-
const oldKey = best.getAttribute(A_ANCHOR);
|
|
330
|
-
mutate(() => {
|
|
331
|
-
best.setAttribute(A_ANCHOR, newKey);
|
|
332
|
-
best.setAttribute(A_CREATED, String(ts()));
|
|
333
|
-
best.setAttribute(A_SHOWN, '0');
|
|
334
|
-
best.classList.remove('is-empty');
|
|
335
|
-
targetEl.insertAdjacentElement('afterend', best);
|
|
336
|
-
});
|
|
337
|
-
// Mettre à jour le registre : ancienne clé → nouvelle clé
|
|
338
|
-
if (oldKey && S.wrapByKey.get(oldKey) === best) S.wrapByKey.delete(oldKey);
|
|
339
|
-
S.wrapByKey.set(newKey, best);
|
|
340
|
-
|
|
341
|
-
// Signaler à Ezoic que ce placeholder a bougé dans le DOM
|
|
342
|
-
try {
|
|
343
|
-
const ez = window.ezstandalone;
|
|
344
|
-
if (typeof ez?.refresh === 'function') {
|
|
345
|
-
(Array.isArray(ez.cmd) ? p => ez.cmd.push(p) : p => p())(() => {
|
|
346
|
-
try { ez.refresh([id]); } catch (_) {}
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
} catch (_) {}
|
|
350
|
-
|
|
351
|
-
return { id, wrap: best };
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// ── Wraps DOM — création / suppression ────────────────────────────────────
|
|
355
297
|
|
|
356
298
|
function makeWrap(id, klass, key) {
|
|
357
299
|
const w = document.createElement('div');
|
|
@@ -462,14 +404,12 @@
|
|
|
462
404
|
|
|
463
405
|
const id = pickId(poolKey);
|
|
464
406
|
if (id) {
|
|
465
|
-
// Pool disponible : créer un nouveau wrap
|
|
466
407
|
const w = insertAfter(el, id, klass, key);
|
|
467
408
|
if (w) { observePh(id); inserted++; }
|
|
468
409
|
} else {
|
|
469
|
-
// Pool épuisé :
|
|
470
|
-
const
|
|
471
|
-
if (!
|
|
472
|
-
observePh(moved.id);
|
|
410
|
+
// Pool épuisé : recycler un wrap distant via destroyPlaceholders+define+displayMore
|
|
411
|
+
const recycled = recycleAndMove(klass, el, key);
|
|
412
|
+
if (!recycled) break; // Aucun wrap recyclable → arrêt
|
|
473
413
|
inserted++;
|
|
474
414
|
}
|
|
475
415
|
}
|
|
@@ -619,70 +559,23 @@
|
|
|
619
559
|
return injectBetween(klass, getItems(), interval, normBool(cfgShowFirst), poolKey);
|
|
620
560
|
};
|
|
621
561
|
|
|
622
|
-
if (kind === 'topic')
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
);
|
|
627
|
-
refreshStaleWraps();
|
|
628
|
-
return n;
|
|
629
|
-
}
|
|
562
|
+
if (kind === 'topic') return exec(
|
|
563
|
+
'ezoic-ad-message', getPosts,
|
|
564
|
+
cfg.enableMessageAds, cfg.messageIntervalPosts, cfg.showFirstMessageAd, 'posts'
|
|
565
|
+
);
|
|
630
566
|
|
|
631
567
|
if (kind === 'categoryTopics') {
|
|
632
568
|
pruneOrphansBetween();
|
|
633
|
-
|
|
569
|
+
return exec(
|
|
634
570
|
'ezoic-ad-between', getTopics,
|
|
635
571
|
cfg.enableBetweenAds, cfg.intervalPosts, cfg.showFirstTopicAd, 'topics'
|
|
636
572
|
);
|
|
637
|
-
refreshStaleWraps();
|
|
638
|
-
return n;
|
|
639
573
|
}
|
|
640
574
|
|
|
641
|
-
|
|
575
|
+
return exec(
|
|
642
576
|
'ezoic-ad-categories', getCategories,
|
|
643
577
|
cfg.enableCategoryAds, cfg.intervalCategories, cfg.showFirstCategoryAd, 'categories'
|
|
644
578
|
);
|
|
645
|
-
refreshStaleWraps();
|
|
646
|
-
return n2;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
/**
|
|
650
|
-
* Appelle ez.refresh() sur les placeholders en DOM, non remplis,
|
|
651
|
-
* dans la zone visible (marges IO). Cela force Ezoic à re-servir
|
|
652
|
-
* une pub sur des slots qu'il avait refusé lors du showAds() initial.
|
|
653
|
-
* Limité à MAX_REFRESH_PER_RUN appels par invocation.
|
|
654
|
-
*/
|
|
655
|
-
const MAX_REFRESH_PER_RUN = 3;
|
|
656
|
-
|
|
657
|
-
function refreshStaleWraps() {
|
|
658
|
-
const ez = window.ezstandalone;
|
|
659
|
-
if (typeof ez?.refresh !== 'function') return;
|
|
660
|
-
|
|
661
|
-
const vh = window.innerHeight || 800;
|
|
662
|
-
const margin = (isMobile() ? 3500 : 2500);
|
|
663
|
-
const top = -margin;
|
|
664
|
-
const bot = vh + margin;
|
|
665
|
-
|
|
666
|
-
const ids = [];
|
|
667
|
-
for (const [, wrap] of S.wrapByKey) {
|
|
668
|
-
if (ids.length >= MAX_REFRESH_PER_RUN) break;
|
|
669
|
-
if (!wrap.isConnected || isFilled(wrap)) continue;
|
|
670
|
-
// Vérifier que le wrap a déjà eu un showAds (A_SHOWN > 0)
|
|
671
|
-
const shown = parseInt(wrap.getAttribute(A_SHOWN) || '0', 10);
|
|
672
|
-
if (!shown) continue;
|
|
673
|
-
try {
|
|
674
|
-
const rect = wrap.getBoundingClientRect();
|
|
675
|
-
if (rect.top > bot || rect.bottom < top) continue;
|
|
676
|
-
const id = parseInt(wrap.getAttribute(A_WRAPID), 10);
|
|
677
|
-
if (Number.isFinite(id) && id > 0) ids.push(id);
|
|
678
|
-
} catch (_) {}
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
if (!ids.length) return;
|
|
682
|
-
try {
|
|
683
|
-
const doRefresh = () => { try { ez.refresh(ids); } catch (_) {} };
|
|
684
|
-
Array.isArray(ez.cmd) ? ez.cmd.push(doRefresh) : doRefresh();
|
|
685
|
-
} catch (_) {}
|
|
686
579
|
}
|
|
687
580
|
|
|
688
581
|
// ── Scheduler ──────────────────────────────────────────────────────────────
|
|
@@ -772,6 +665,8 @@
|
|
|
772
665
|
const MUTED = [
|
|
773
666
|
'[EzoicAds JS]: Placeholder Id',
|
|
774
667
|
'No valid placeholders for loadMore',
|
|
668
|
+
'cannot call refresh on the same page',
|
|
669
|
+
'no placeholders are currently defined in Refresh',
|
|
775
670
|
'Debugger iframe already exists',
|
|
776
671
|
`with id ${PH_PREFIX}`,
|
|
777
672
|
];
|