nodebb-plugin-ezoic-infinite 1.5.67 → 1.5.68
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 +52 -29
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -100,6 +100,36 @@
|
|
|
100
100
|
|
|
101
101
|
const insertingIds = new Set();
|
|
102
102
|
|
|
103
|
+
// Hidden pool where we keep placeholder DIVs when they are not currently
|
|
104
|
+
// mounted in the content flow. This avoids:
|
|
105
|
+
// - Ezoic trying to act on ids that were removed from the DOM ("does not exist")
|
|
106
|
+
// - re-defining placeholders (we re-use the same node)
|
|
107
|
+
const POOL_ID = 'nodebb-ezoic-placeholder-pool';
|
|
108
|
+
function getPoolEl() {
|
|
109
|
+
let el = document.getElementById(POOL_ID);
|
|
110
|
+
if (el) return el;
|
|
111
|
+
el = document.createElement('div');
|
|
112
|
+
el.id = POOL_ID;
|
|
113
|
+
el.style.cssText = 'position:fixed;left:-99999px;top:-99999px;width:1px;height:1px;overflow:hidden;opacity:0;pointer-events:none;';
|
|
114
|
+
(document.body || document.documentElement).appendChild(el);
|
|
115
|
+
return el;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function isInPool(ph) {
|
|
119
|
+
try { return !!(ph && ph.closest && ph.closest('#' + POOL_ID)); } catch (e) { return false; }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function releaseWrapNode(wrap) {
|
|
123
|
+
try {
|
|
124
|
+
const ph = wrap && wrap.querySelector && wrap.querySelector(`[id^="${PLACEHOLDER_PREFIX}"]`);
|
|
125
|
+
if (ph) {
|
|
126
|
+
try { getPoolEl().appendChild(ph); } catch (e) {}
|
|
127
|
+
try { if (state.io) state.io.unobserve(ph); } catch (e) {}
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {}
|
|
130
|
+
try { wrap && wrap.remove && wrap.remove(); } catch (e) {}
|
|
131
|
+
}
|
|
132
|
+
|
|
103
133
|
|
|
104
134
|
function markEmptyWrapper(id) {
|
|
105
135
|
try {
|
|
@@ -354,11 +384,11 @@ function withInternalDomChange(fn) {
|
|
|
354
384
|
}
|
|
355
385
|
|
|
356
386
|
if (!ok) {
|
|
357
|
-
const id = getWrapIdFromWrap(wrap);
|
|
358
387
|
withInternalDomChange(() => {
|
|
359
388
|
try {
|
|
360
|
-
|
|
361
|
-
|
|
389
|
+
// Do not destroy placeholders; move them back to the pool so
|
|
390
|
+
// Ezoic won't log "does not exist" and we can reuse them later.
|
|
391
|
+
releaseWrapNode(wrap);
|
|
362
392
|
} catch (e) {}
|
|
363
393
|
});
|
|
364
394
|
removed++;
|
|
@@ -384,17 +414,19 @@ function withInternalDomChange(fn) {
|
|
|
384
414
|
}, 3500);
|
|
385
415
|
}
|
|
386
416
|
|
|
387
|
-
function buildWrap(id, kindClass, afterPos) {
|
|
417
|
+
function buildWrap(id, kindClass, afterPos, createPlaceholder) {
|
|
388
418
|
const wrap = document.createElement('div');
|
|
389
419
|
wrap.className = `${WRAP_CLASS} ${kindClass}`;
|
|
390
420
|
wrap.setAttribute('data-ezoic-after', String(afterPos));
|
|
391
421
|
wrap.setAttribute('data-ezoic-wrapid', String(id));
|
|
392
422
|
wrap.style.width = '100%';
|
|
393
423
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
424
|
+
if (createPlaceholder) {
|
|
425
|
+
const ph = document.createElement('div');
|
|
426
|
+
ph.id = `${PLACEHOLDER_PREFIX}${id}`;
|
|
427
|
+
ph.setAttribute('data-ezoic-id', String(id));
|
|
428
|
+
wrap.appendChild(ph);
|
|
429
|
+
}
|
|
398
430
|
|
|
399
431
|
return wrap;
|
|
400
432
|
}
|
|
@@ -412,16 +444,20 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
412
444
|
|
|
413
445
|
insertingIds.add(id);
|
|
414
446
|
try {
|
|
415
|
-
|
|
447
|
+
// If a placeholder already exists (either in content or in our pool),
|
|
448
|
+
// do NOT create a new DOM node with the same id even temporarily.
|
|
449
|
+
const wrap = buildWrap(id, kindClass, afterPos, !existingPh);
|
|
416
450
|
target.insertAdjacentElement('afterend', wrap);
|
|
417
451
|
|
|
418
452
|
// If a placeholder with this id already exists elsewhere (some Ezoic flows
|
|
419
453
|
// pre-create placeholders), move it into our wrapper instead of aborting.
|
|
420
454
|
// replaceChild moves the node atomically (no detach window).
|
|
421
|
-
if (existingPh
|
|
455
|
+
if (existingPh) {
|
|
422
456
|
try {
|
|
423
457
|
existingPh.setAttribute('data-ezoic-id', String(id));
|
|
424
|
-
|
|
458
|
+
// If we didn't create a placeholder, just append.
|
|
459
|
+
if (!wrap.firstElementChild) wrap.appendChild(existingPh);
|
|
460
|
+
else wrap.replaceChild(existingPh, wrap.firstElementChild);
|
|
425
461
|
} catch (e) {
|
|
426
462
|
// Keep the new placeholder if replace fails.
|
|
427
463
|
}
|
|
@@ -443,7 +479,9 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
443
479
|
|
|
444
480
|
const id = allIds[idx];
|
|
445
481
|
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
446
|
-
|
|
482
|
+
// If placeholder is currently mounted in the content flow, skip.
|
|
483
|
+
// If it's in our hidden pool, it's available for reuse.
|
|
484
|
+
if (ph && ph.isConnected && !isInPool(ph)) continue;
|
|
447
485
|
|
|
448
486
|
return id;
|
|
449
487
|
}
|
|
@@ -465,13 +503,7 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
465
503
|
// Otherwise remove the earliest one in the document
|
|
466
504
|
if (!victim) victim = wraps[0];
|
|
467
505
|
|
|
468
|
-
|
|
469
|
-
try {
|
|
470
|
-
const ph = victim.querySelector && victim.querySelector(`[id^="${PLACEHOLDER_PREFIX}"]`);
|
|
471
|
-
if (ph && state.io) state.io.unobserve(ph);
|
|
472
|
-
} catch (e) {}
|
|
473
|
-
|
|
474
|
-
victim.remove();
|
|
506
|
+
releaseWrapNode(victim);
|
|
475
507
|
return true;
|
|
476
508
|
} catch (e) {
|
|
477
509
|
return false;
|
|
@@ -625,15 +657,6 @@ function startShow(id) {
|
|
|
625
657
|
if (i % interval === 0) out.push(i);
|
|
626
658
|
}
|
|
627
659
|
return Array.from(new Set(out)).sort((a, b) => a - b);
|
|
628
|
-
// If we inserted the maximum batch, likely there are more targets.
|
|
629
|
-
// Schedule a follow-up pass (bounded via scheduleRun coalescing).
|
|
630
|
-
const maxInserts = MAX_INSERTS_PER_RUN + (isBoosted() ? 1 : 0);
|
|
631
|
-
if (insertedThisRun >= maxInserts) {
|
|
632
|
-
scheduleRun(120);
|
|
633
|
-
scheduleRun(420);
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
|
|
637
660
|
}
|
|
638
661
|
|
|
639
662
|
function injectBetween(kindClass, items, interval, showFirst, allIds, cursorKey) {
|
|
@@ -838,7 +861,7 @@ function startShow(id) {
|
|
|
838
861
|
// remove all wrappers
|
|
839
862
|
try {
|
|
840
863
|
document.querySelectorAll(`.${WRAP_CLASS}`).forEach((el) => {
|
|
841
|
-
|
|
864
|
+
releaseWrapNode(el);
|
|
842
865
|
});
|
|
843
866
|
} catch (e) {}
|
|
844
867
|
|