nodebb-plugin-ezoic-infinite 1.5.59 → 1.5.61
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 +126 -49
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -27,7 +27,7 @@ function ensurePool() {
|
|
|
27
27
|
if (pool) {
|
|
28
28
|
// In rare cases (aggressive SPA navigation), the pool may get detached.
|
|
29
29
|
if (!pool.isConnected) {
|
|
30
|
-
try {
|
|
30
|
+
try { document.body.appendChild(pool); } catch (e) {}
|
|
31
31
|
}
|
|
32
32
|
return pool;
|
|
33
33
|
}
|
|
@@ -41,7 +41,7 @@ function ensurePool() {
|
|
|
41
41
|
pool.style.overflow = 'hidden';
|
|
42
42
|
pool.setAttribute('aria-hidden', 'true');
|
|
43
43
|
// Attach early (documentElement exists before body), so placeholders are always connected.
|
|
44
|
-
try {
|
|
44
|
+
try { document.body.appendChild(pool); } catch (e) {}
|
|
45
45
|
// If body exists later, move it under body (purely cosmetic).
|
|
46
46
|
try {
|
|
47
47
|
if (document.body && pool.parentNode !== document.body) {
|
|
@@ -76,6 +76,34 @@ function primePool(ids) {
|
|
|
76
76
|
} catch (e) {}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
|
|
80
|
+
// Prime a continuous id range (inclusive) into the offscreen pool.
|
|
81
|
+
// Ezoic sometimes references ids outside our configured list (e.g. +N); a small buffer prevents "does not exist" spam.
|
|
82
|
+
function primePoolRange(minId, maxId) {
|
|
83
|
+
try {
|
|
84
|
+
minId = parseInt(minId, 10);
|
|
85
|
+
maxId = parseInt(maxId, 10);
|
|
86
|
+
if (!Number.isFinite(minId) || !Number.isFinite(maxId)) return;
|
|
87
|
+
if (minId <= 0 || maxId <= 0) return;
|
|
88
|
+
if (maxId < minId) { const t = minId; minId = maxId; maxId = t; }
|
|
89
|
+
const span = Math.min(400, Math.max(0, maxId - minId)); // cap
|
|
90
|
+
const pool = ensurePool();
|
|
91
|
+
for (let id = minId; id <= minId + span; id += 1) {
|
|
92
|
+
const domId = `${PLACEHOLDER_PREFIX}${id}`;
|
|
93
|
+
let ph = document.getElementById(domId);
|
|
94
|
+
if (!ph) {
|
|
95
|
+
ph = document.createElement('div');
|
|
96
|
+
ph.id = domId;
|
|
97
|
+
ph.setAttribute('data-ezoic-id', String(id));
|
|
98
|
+
pool.appendChild(ph);
|
|
99
|
+
} else if (!ph.isConnected) {
|
|
100
|
+
pool.appendChild(ph);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} catch (e) {}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
79
107
|
function acquirePlaceholder(id) {
|
|
80
108
|
const domId = `${PLACEHOLDER_PREFIX}${id}`;
|
|
81
109
|
let ph = document.getElementById(domId);
|
|
@@ -84,9 +112,8 @@ function acquirePlaceholder(id) {
|
|
|
84
112
|
ph.id = domId;
|
|
85
113
|
ph.setAttribute('data-ezoic-id', String(id));
|
|
86
114
|
ensurePool().appendChild(ph);
|
|
87
|
-
}
|
|
88
|
-
//
|
|
89
|
-
try { if (ph.parentNode) ph.parentNode.removeChild(ph); } catch (e) {}
|
|
115
|
+
}
|
|
116
|
+
// Note: appendChild will automatically move the node, no manual detach (avoids race gaps).
|
|
90
117
|
// Clear request/defined flags when reusing
|
|
91
118
|
try {
|
|
92
119
|
if (ph.dataset) {
|
|
@@ -470,28 +497,65 @@ function withInternalDomChange(fn) {
|
|
|
470
497
|
}
|
|
471
498
|
|
|
472
499
|
function initPools(cfg) {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
500
|
+
if (!cfg) return;
|
|
501
|
+
if (state.allTopics.length === 0) state.allTopics = parsePool(cfg.placeholderIds);
|
|
502
|
+
if (state.allPosts.length === 0) state.allPosts = parsePool(cfg.messagePlaceholderIds);
|
|
503
|
+
if (state.allCategories.length === 0) state.allCategories = parsePool(cfg.categoryPlaceholderIds);
|
|
504
|
+
|
|
505
|
+
// Keep placeholders alive even before they're injected.
|
|
506
|
+
// Ezoic can reference ids slightly outside our configured lists (often sequential),
|
|
507
|
+
// so we prime a small buffered range to prevent "does not exist" spam.
|
|
508
|
+
const primeBuffered = (ids) => {
|
|
509
|
+
try {
|
|
510
|
+
if (!ids || !ids.length) return;
|
|
511
|
+
primePool(ids);
|
|
512
|
+
|
|
513
|
+
let min = Infinity, max = -Infinity;
|
|
514
|
+
for (const v of ids) {
|
|
515
|
+
const n = parseInt(v, 10);
|
|
516
|
+
if (!Number.isFinite(n) || n <= 0) continue;
|
|
517
|
+
if (n < min) min = n;
|
|
518
|
+
if (n > max) max = n;
|
|
519
|
+
}
|
|
520
|
+
if (!Number.isFinite(min) || !Number.isFinite(max)) return;
|
|
521
|
+
|
|
522
|
+
// small buffer in both directions; range prime is capped internally
|
|
523
|
+
primePoolRange(Math.max(1, min - 5), max + 120);
|
|
524
|
+
} catch (e) {}
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
primeBuffered(state.allTopics);
|
|
528
|
+
primeBuffered(state.allPosts);
|
|
529
|
+
primeBuffered(state.allCategories);
|
|
530
|
+
}
|
|
531
|
+
|
|
484
532
|
|
|
485
533
|
// ---------- insertion primitives ----------
|
|
486
534
|
|
|
487
535
|
function isAdjacentAd(target) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
536
|
+
if (!target) return false;
|
|
537
|
+
const isAdEl = (el) => !!(el && el.classList && el.classList.contains(WRAP_CLASS));
|
|
538
|
+
// Look a few siblings away, skipping spacer elements inserted by NodeBB/themes
|
|
539
|
+
let el = target;
|
|
540
|
+
for (let i = 0; i < 3; i += 1) {
|
|
541
|
+
el = el.nextElementSibling;
|
|
542
|
+
if (!el) break;
|
|
543
|
+
if (isAdEl(el)) return true;
|
|
544
|
+
// Skip elements that are effectively spacers/dividers
|
|
545
|
+
const h = el.getBoundingClientRect ? el.getBoundingClientRect().height : 0;
|
|
546
|
+
if (h > 8) break;
|
|
547
|
+
}
|
|
548
|
+
el = target;
|
|
549
|
+
for (let i = 0; i < 3; i += 1) {
|
|
550
|
+
el = el.previousElementSibling;
|
|
551
|
+
if (!el) break;
|
|
552
|
+
if (isAdEl(el)) return true;
|
|
553
|
+
const h = el.getBoundingClientRect ? el.getBoundingClientRect().height : 0;
|
|
554
|
+
if (h > 8) break;
|
|
494
555
|
}
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
|
|
495
559
|
|
|
496
560
|
|
|
497
561
|
function getWrapIdFromWrap(wrap) {
|
|
@@ -571,41 +635,54 @@ function withInternalDomChange(fn) {
|
|
|
571
635
|
}, 3500);
|
|
572
636
|
}
|
|
573
637
|
|
|
574
|
-
function buildWrap(id, kindClass, afterPos) {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
638
|
+
function buildWrap(id, kindClass, afterPos, afterPid) {
|
|
639
|
+
const wrap = document.createElement('div');
|
|
640
|
+
wrap.className = `${WRAP_CLASS} ${kindClass}`;
|
|
641
|
+
wrap.setAttribute('data-ezoic-after', String(afterPos));
|
|
642
|
+
if (afterPid) wrap.setAttribute('data-ezoic-after-pid', String(afterPid));
|
|
643
|
+
wrap.setAttribute('data-ezoic-wrapid', String(id));
|
|
644
|
+
wrap.style.width = '100%';
|
|
580
645
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
646
|
+
const ph = acquirePlaceholder(id);
|
|
647
|
+
try { if (ph.dataset) ph.dataset.ezActive = '1'; } catch (e) {}
|
|
648
|
+
wrap.appendChild(ph);
|
|
584
649
|
|
|
585
|
-
|
|
586
|
-
|
|
650
|
+
return wrap;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
function findWrap(kindClass, afterPos, afterPid) {
|
|
655
|
+
try {
|
|
656
|
+
if (afterPid) {
|
|
657
|
+
const w = document.querySelector(`.${WRAP_CLASS}.${kindClass}[data-ezoic-after-pid="${afterPid}"]`);
|
|
658
|
+
if (w) return w;
|
|
659
|
+
}
|
|
660
|
+
} catch (e) {}
|
|
661
|
+
return document.querySelector(`.${WRAP_CLASS}.${kindClass}[data-ezoic-after="${afterPos}"]`);
|
|
662
|
+
}
|
|
587
663
|
|
|
588
|
-
function findWrap(kindClass, afterPos) {
|
|
589
|
-
return document.querySelector(`.${WRAP_CLASS}.${kindClass}[data-ezoic-after="${afterPos}"]`);
|
|
590
|
-
}
|
|
591
664
|
|
|
592
665
|
function insertAfter(target, id, kindClass, afterPos) {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
666
|
+
if (!target || !target.insertAdjacentElement) return null;
|
|
667
|
+
const afterPid = target.getAttribute ? target.getAttribute('data-pid') : null;
|
|
668
|
+
if (findWrap(kindClass, afterPos, afterPid)) return null;
|
|
669
|
+
if (insertingIds.has(id)) return null;
|
|
596
670
|
|
|
597
|
-
|
|
598
|
-
|
|
671
|
+
const existingPh = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
672
|
+
if (existingPh && isPlaceholderInUse(existingPh)) return null;
|
|
599
673
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
|
|
674
|
+
insertingIds.add(id);
|
|
675
|
+
try {
|
|
676
|
+
const wrap = buildWrap(id, kindClass, afterPos, afterPid);
|
|
677
|
+
target.insertAdjacentElement('afterend', wrap);
|
|
678
|
+
// Mark post as processed anchor to stabilize 1/X across infinite scroll reflows
|
|
679
|
+
try { if (afterPid) target.setAttribute('data-ezoic-anchored', '1'); } catch (e) {}
|
|
680
|
+
return wrap;
|
|
681
|
+
} finally {
|
|
682
|
+
insertingIds.delete(id);
|
|
608
683
|
}
|
|
684
|
+
}
|
|
685
|
+
|
|
609
686
|
|
|
610
687
|
function pickIdFromAll(allIds, cursorKey) {
|
|
611
688
|
const n = allIds.length;
|