nodebb-plugin-ezoic-infinite 1.7.2 → 1.7.3
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 +71 -12
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -261,17 +261,45 @@
|
|
|
261
261
|
return w;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Retire proprement un wrap du DOM.
|
|
266
|
+
*
|
|
267
|
+
* Sans précaution, retirer un wrap contenant un player vidéo Ezoic (wyvern.js)
|
|
268
|
+
* déclenche des erreurs async sur des nœuds détachés :
|
|
269
|
+
* "Cannot read properties of null (reading 'paused')"
|
|
270
|
+
* "Cannot read properties of null (reading 'offsetWidth')"
|
|
271
|
+
* "Invalid target for null#trigger / null#on"
|
|
272
|
+
*
|
|
273
|
+
* On pause les media et on tente de notifier l'API wyvern avant remove().
|
|
274
|
+
*/
|
|
264
275
|
function dropWrap(w) {
|
|
265
276
|
try {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
277
|
+
// 1. Pause tous les media actifs avant détachement
|
|
278
|
+
try {
|
|
279
|
+
w.querySelectorAll('video, audio').forEach(m => {
|
|
280
|
+
try { if (!m.paused) m.pause(); } catch (_) {}
|
|
281
|
+
});
|
|
282
|
+
} catch (_) {}
|
|
283
|
+
|
|
284
|
+
// 2. Notifier l'API wyvern si disponible
|
|
285
|
+
try {
|
|
286
|
+
if (window.wyvern && typeof window.wyvern === 'object') {
|
|
287
|
+
w.querySelectorAll('[id^="ezoic-"],[class*="wyvern"],[class*="ezoic-video"]')
|
|
288
|
+
.forEach(n => { try { window.wyvern.destroy?.(n); } catch (_) {} });
|
|
289
|
+
}
|
|
290
|
+
} catch (_) {}
|
|
291
|
+
|
|
292
|
+
// 3. Unobserve (guard instanceof Element — unobserve(null) corrompt l'IO)
|
|
271
293
|
try {
|
|
272
294
|
const ph = w.querySelector(`[id^="${PH_PREFIX}"]`);
|
|
273
295
|
if (ph instanceof Element) S.io?.unobserve(ph);
|
|
274
296
|
} catch (_) {}
|
|
297
|
+
|
|
298
|
+
// 4. Libérer l'id du pool
|
|
299
|
+
const id = parseInt(w.getAttribute(A_WRAPID), 10);
|
|
300
|
+
if (Number.isFinite(id)) S.mountedIds.delete(id);
|
|
301
|
+
|
|
302
|
+
// 5. Retrait DOM
|
|
275
303
|
w.remove();
|
|
276
304
|
} catch (_) {}
|
|
277
305
|
}
|
|
@@ -289,17 +317,31 @@
|
|
|
289
317
|
*
|
|
290
318
|
* On ne prune pas les wraps < MIN_PRUNE_AGE_MS (DOM pas encore stabilisé).
|
|
291
319
|
*/
|
|
320
|
+
/**
|
|
321
|
+
* Supprime les wraps dont l'élément-ancre n'est plus dans le DOM.
|
|
322
|
+
*
|
|
323
|
+
* Règle stricte : on ne supprime JAMAIS un wrap rempli (filled).
|
|
324
|
+
* - Il peut contenir un player wyvern actif → .remove() déclenche des
|
|
325
|
+
* erreurs async ("Cannot read 'paused'", "offsetWidth", "getChild"…).
|
|
326
|
+
* - Le post-ancre peut être temporairement virtualisé par NodeBB puis
|
|
327
|
+
* revenir — dans ce cas le wrap filled doit rester en place.
|
|
328
|
+
*
|
|
329
|
+
* Seuls les wraps VIDES dont l'ancre a disparu sont supprimés.
|
|
330
|
+
*/
|
|
292
331
|
function pruneOrphans(klass) {
|
|
293
332
|
const meta = KIND[klass];
|
|
294
333
|
if (!meta) return;
|
|
295
334
|
|
|
296
|
-
const baseTag = meta.sel.split('[')[0];
|
|
335
|
+
const baseTag = meta.sel.split('[')[0];
|
|
297
336
|
|
|
298
337
|
document.querySelectorAll(`.${WRAP_CLASS}.${klass}`).forEach(w => {
|
|
299
338
|
if (ts() - parseInt(w.getAttribute(A_CREATED) || '0', 10) < MIN_PRUNE_AGE_MS) return;
|
|
300
339
|
|
|
340
|
+
// Ne jamais retirer un wrap qui contient du contenu (player potentiellement actif)
|
|
341
|
+
if (isFilled(w)) return;
|
|
342
|
+
|
|
301
343
|
const key = w.getAttribute(A_ANCHOR) ?? '';
|
|
302
|
-
const sid = key.slice(klass.length + 1);
|
|
344
|
+
const sid = key.slice(klass.length + 1);
|
|
303
345
|
if (!sid) { mutate(() => dropWrap(w)); return; }
|
|
304
346
|
|
|
305
347
|
const anchorEl = document.querySelector(
|
|
@@ -314,11 +356,12 @@
|
|
|
314
356
|
/**
|
|
315
357
|
* Deux wraps adjacents = situation anormale → supprimer le moins prioritaire.
|
|
316
358
|
* Priorité : filled > en grâce (fill en cours) > vide.
|
|
317
|
-
*
|
|
359
|
+
*
|
|
360
|
+
* Règle de sécurité wyvern : on ne supprime JAMAIS un wrap rempli.
|
|
361
|
+
* Si les deux wraps adjacents sont remplis, on laisse en place (edge case rare).
|
|
318
362
|
*/
|
|
319
363
|
function decluster(klass) {
|
|
320
364
|
for (const w of document.querySelectorAll(`.${WRAP_CLASS}.${klass}`)) {
|
|
321
|
-
// Grace sur le wrap courant : on le saute entièrement
|
|
322
365
|
const wShown = parseInt(w.getAttribute(A_SHOWN) || '0', 10);
|
|
323
366
|
if (wShown && ts() - wShown < FILL_GRACE_MS) continue;
|
|
324
367
|
|
|
@@ -327,10 +370,16 @@
|
|
|
327
370
|
if (!prev.classList?.contains(WRAP_CLASS)) { prev = prev.previousElementSibling; continue; }
|
|
328
371
|
|
|
329
372
|
const pShown = parseInt(prev.getAttribute(A_SHOWN) || '0', 10);
|
|
330
|
-
if (pShown && ts() - pShown < FILL_GRACE_MS) break;
|
|
373
|
+
if (pShown && ts() - pShown < FILL_GRACE_MS) break;
|
|
374
|
+
|
|
375
|
+
const wFilled = isFilled(w);
|
|
376
|
+
const pFilled = isFilled(prev);
|
|
331
377
|
|
|
332
|
-
|
|
333
|
-
|
|
378
|
+
// Ne jamais retirer un wrap rempli (player actif potentiel)
|
|
379
|
+
if (!wFilled && !pFilled) mutate(() => dropWrap(w)); // les deux vides → retirer le courant
|
|
380
|
+
else if (!wFilled && pFilled) mutate(() => dropWrap(w)); // courant vide, précédent rempli → retirer le courant
|
|
381
|
+
else if ( wFilled && !pFilled) mutate(() => dropWrap(prev)); // courant rempli, précédent vide → retirer le précédent
|
|
382
|
+
// les deux remplis → rien (on ne touche pas)
|
|
334
383
|
break;
|
|
335
384
|
}
|
|
336
385
|
}
|
|
@@ -592,6 +641,16 @@
|
|
|
592
641
|
|
|
593
642
|
function cleanup() {
|
|
594
643
|
blockedUntil = ts() + 1500;
|
|
644
|
+
|
|
645
|
+
// Pause tous les media dans nos wraps AVANT de les retirer du DOM.
|
|
646
|
+
// Empêche wyvern.js de continuer d'exécuter ses callbacks async sur des
|
|
647
|
+
// nœuds détachés (erreurs "Cannot read 'paused'", "offsetWidth"…).
|
|
648
|
+
try {
|
|
649
|
+
document.querySelectorAll(`.${WRAP_CLASS} video, .${WRAP_CLASS} audio`).forEach(m => {
|
|
650
|
+
try { if (!m.paused) m.pause(); } catch (_) {}
|
|
651
|
+
});
|
|
652
|
+
} catch (_) {}
|
|
653
|
+
|
|
595
654
|
mutate(() => document.querySelectorAll(`.${WRAP_CLASS}`).forEach(dropWrap));
|
|
596
655
|
S.cfg = null;
|
|
597
656
|
S.pools = { topics: [], posts: [], categories: [] };
|