nodebb-plugin-ezoic-infinite 1.7.88 → 1.7.89
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 +41 -2
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -282,6 +282,28 @@
|
|
|
282
282
|
return (w?.isConnected) ? w : null;
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
/**
|
|
286
|
+
* Libère les ids de wraps supprimés du DOM (virtualisation NodeBB / rerender).
|
|
287
|
+
* Sans ce sweep, mountedIds peut conserver des ids fantômes → pool épuisé
|
|
288
|
+
* après long scroll alors qu'aucun wrap recyclable n'existe encore en DOM.
|
|
289
|
+
*/
|
|
290
|
+
function sweepDeadWraps() {
|
|
291
|
+
for (const [key, w] of S.wrapByKey.entries()) {
|
|
292
|
+
if (w?.isConnected) continue;
|
|
293
|
+
const id = parseInt(w?.getAttribute?.(A_WRAPID), 10);
|
|
294
|
+
if (Number.isFinite(id)) {
|
|
295
|
+
S.mountedIds.delete(id);
|
|
296
|
+
S.lastShow.delete(id);
|
|
297
|
+
S.pendingSet.delete(id);
|
|
298
|
+
}
|
|
299
|
+
S.wrapByKey.delete(key);
|
|
300
|
+
}
|
|
301
|
+
if (S.pending.length) {
|
|
302
|
+
S.pending = S.pending.filter(id => !S.pendingSet.has(id) || document.getElementById(`${PH_PREFIX}${id}`)?.isConnected);
|
|
303
|
+
S.pendingSet = new Set(S.pending);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
285
307
|
// ── Pool ───────────────────────────────────────────────────────────────────
|
|
286
308
|
|
|
287
309
|
/**
|
|
@@ -471,7 +493,13 @@
|
|
|
471
493
|
const key = anchorKey(klass, el);
|
|
472
494
|
if (findWrap(key)) continue;
|
|
473
495
|
|
|
474
|
-
|
|
496
|
+
let id = pickId(poolKey);
|
|
497
|
+
if (!id) {
|
|
498
|
+
// Réessaie après sweep : des wraps ont pu être retirés du DOM (virtualisation)
|
|
499
|
+
// sans passer par dropWrap, laissant des ids fantômes dans mountedIds.
|
|
500
|
+
sweepDeadWraps();
|
|
501
|
+
id = pickId(poolKey);
|
|
502
|
+
}
|
|
475
503
|
if (id) {
|
|
476
504
|
const w = insertAfter(el, id, klass, key);
|
|
477
505
|
if (w) { observePh(id); inserted++; }
|
|
@@ -613,6 +641,7 @@
|
|
|
613
641
|
async function runCore() {
|
|
614
642
|
if (isBlocked()) return 0;
|
|
615
643
|
patchShowAds();
|
|
644
|
+
sweepDeadWraps();
|
|
616
645
|
|
|
617
646
|
const cfg = await fetchConfig();
|
|
618
647
|
if (!cfg || cfg.excluded) return 0;
|
|
@@ -711,16 +740,26 @@
|
|
|
711
740
|
const allSel = [SEL.post, SEL.topic, SEL.category];
|
|
712
741
|
S.domObs = new MutationObserver(muts => {
|
|
713
742
|
if (S.mutGuard > 0 || isBlocked()) return;
|
|
743
|
+
let sawRelevantAdd = false;
|
|
744
|
+
let sawWrapRemoval = false;
|
|
714
745
|
for (const m of muts) {
|
|
746
|
+
for (const n of m.removedNodes) {
|
|
747
|
+
if (n.nodeType !== 1) continue;
|
|
748
|
+
if ((n.matches && n.matches(`.${WRAP_CLASS}`)) || n.querySelector?.(`.${WRAP_CLASS}`)) {
|
|
749
|
+
sawWrapRemoval = true;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
715
752
|
for (const n of m.addedNodes) {
|
|
716
753
|
if (n.nodeType !== 1) continue;
|
|
717
754
|
// matches() d'abord (O(1)), querySelector() seulement si nécessaire
|
|
718
755
|
if (allSel.some(s => { try { return n.matches(s); } catch(_){return false;} }) ||
|
|
719
756
|
allSel.some(s => { try { return !!n.querySelector(s); } catch(_){return false;} })) {
|
|
720
|
-
|
|
757
|
+
sawRelevantAdd = true;
|
|
721
758
|
}
|
|
722
759
|
}
|
|
723
760
|
}
|
|
761
|
+
if (sawWrapRemoval) sweepDeadWraps();
|
|
762
|
+
if (sawRelevantAdd) requestBurst();
|
|
724
763
|
});
|
|
725
764
|
try { S.domObs.observe(document.body, { childList: true, subtree: true }); } catch (_) {}
|
|
726
765
|
}
|