nodebb-plugin-ezoic-infinite 1.5.60 → 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 +124 -46
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);
|
|
@@ -469,28 +497,65 @@ function withInternalDomChange(fn) {
|
|
|
469
497
|
}
|
|
470
498
|
|
|
471
499
|
function initPools(cfg) {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
+
|
|
483
532
|
|
|
484
533
|
// ---------- insertion primitives ----------
|
|
485
534
|
|
|
486
535
|
function isAdjacentAd(target) {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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;
|
|
493
555
|
}
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
|
|
494
559
|
|
|
495
560
|
|
|
496
561
|
function getWrapIdFromWrap(wrap) {
|
|
@@ -570,41 +635,54 @@ function withInternalDomChange(fn) {
|
|
|
570
635
|
}, 3500);
|
|
571
636
|
}
|
|
572
637
|
|
|
573
|
-
function buildWrap(id, kindClass, afterPos) {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
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%';
|
|
579
645
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
646
|
+
const ph = acquirePlaceholder(id);
|
|
647
|
+
try { if (ph.dataset) ph.dataset.ezActive = '1'; } catch (e) {}
|
|
648
|
+
wrap.appendChild(ph);
|
|
583
649
|
|
|
584
|
-
|
|
585
|
-
|
|
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
|
+
}
|
|
586
663
|
|
|
587
|
-
function findWrap(kindClass, afterPos) {
|
|
588
|
-
return document.querySelector(`.${WRAP_CLASS}.${kindClass}[data-ezoic-after="${afterPos}"]`);
|
|
589
|
-
}
|
|
590
664
|
|
|
591
665
|
function insertAfter(target, id, kindClass, afterPos) {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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;
|
|
595
670
|
|
|
596
|
-
|
|
597
|
-
|
|
671
|
+
const existingPh = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
672
|
+
if (existingPh && isPlaceholderInUse(existingPh)) return null;
|
|
598
673
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
|
|
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);
|
|
607
683
|
}
|
|
684
|
+
}
|
|
685
|
+
|
|
608
686
|
|
|
609
687
|
function pickIdFromAll(allIds, cursorKey) {
|
|
610
688
|
const n = allIds.length;
|