nodebb-plugin-ezoic-infinite 1.5.80 → 1.5.82
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 +65 -10
- package/public/test.txt +1 -0
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -704,9 +704,10 @@ function globalGapFixInit() {
|
|
|
704
704
|
}
|
|
705
705
|
|
|
706
706
|
function pruneOrphanWraps(kindClass, items) {
|
|
707
|
-
//
|
|
708
|
-
//
|
|
709
|
-
|
|
707
|
+
// Topic pages can be virtualized (posts removed from DOM as you scroll).
|
|
708
|
+
// When that happens, previously-inserted ad wraps may become "orphan" nodes with no
|
|
709
|
+
// nearby post containers, which leads to ads clustering together when scrolling back up.
|
|
710
|
+
// We prune only *true* orphans that are far offscreen to keep the UI stable.
|
|
710
711
|
if (!items || !items.length) return 0;
|
|
711
712
|
const itemSet = new Set(items);
|
|
712
713
|
const wraps = document.querySelectorAll(`.${WRAP_CLASS}.${kindClass}`);
|
|
@@ -737,7 +738,10 @@ function globalGapFixInit() {
|
|
|
737
738
|
if (wrap.getAttribute('data-ezoic-pin') === '1') return;
|
|
738
739
|
} catch (e) {}
|
|
739
740
|
|
|
740
|
-
|
|
741
|
+
// For message/topic pages we may prune filled or empty orphans if they are far away,
|
|
742
|
+
// otherwise consecutive "stacks" can appear when posts are virtualized.
|
|
743
|
+
const isMessage = (kindClass === 'ezoic-ad-message');
|
|
744
|
+
if (!isMessage && isFilled(wrap)) return; // never prune filled ads for non-message lists
|
|
741
745
|
|
|
742
746
|
// Never prune a fresh wrap: it may fill late.
|
|
743
747
|
try {
|
|
@@ -745,10 +749,30 @@ function globalGapFixInit() {
|
|
|
745
749
|
if (created && (now() - created) < keepEmptyWrapMs()) return;
|
|
746
750
|
} catch (e) {}
|
|
747
751
|
|
|
748
|
-
|
|
752
|
+
if (hasNearbyItem(wrap)) {
|
|
753
|
+
try { wrap.classList && wrap.classList.remove('ez-orphan-hidden'); wrap.style && (wrap.style.display = ''); } catch (e) {}
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// If the anchor item is no longer in the DOM (virtualized), hide the wrap so ads never "stack"
|
|
758
|
+
// back-to-back while scrolling. We'll recycle it when its anchor comes back.
|
|
759
|
+
try { wrap.classList && wrap.classList.add('ez-orphan-hidden'); wrap.style && (wrap.style.display = 'none'); } catch (e) {}
|
|
749
760
|
|
|
750
|
-
|
|
751
|
-
|
|
761
|
+
// For message ads: only release if far offscreen to avoid perceived "vanishing" during fast scroll.
|
|
762
|
+
if (isMessage) {
|
|
763
|
+
try {
|
|
764
|
+
const r = wrap.getBoundingClientRect();
|
|
765
|
+
const vh = Math.max(1, window.innerHeight || 1);
|
|
766
|
+
const farAbove = r.bottom < -vh * 2;
|
|
767
|
+
const farBelow = r.top > vh * 4;
|
|
768
|
+
if (!farAbove && !farBelow) return;
|
|
769
|
+
} catch (e) {
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
withInternalDomChange(() => releaseWrapNode(wrap));
|
|
775
|
+
removed++;
|
|
752
776
|
});
|
|
753
777
|
|
|
754
778
|
return removed;
|
|
@@ -1013,6 +1037,36 @@ function globalGapFixInit() {
|
|
|
1013
1037
|
|
|
1014
1038
|
// ---------------- core injection ----------------
|
|
1015
1039
|
|
|
1040
|
+
function getItemOrdinal(el, fallbackIndex) {
|
|
1041
|
+
try {
|
|
1042
|
+
if (!el) return fallbackIndex + 1;
|
|
1043
|
+
const di = el.getAttribute('data-index') || (el.dataset && (el.dataset.index || el.dataset.postIndex));
|
|
1044
|
+
if (di !== null && di !== undefined && di !== '' && !isNaN(di)) {
|
|
1045
|
+
const n = parseInt(di, 10);
|
|
1046
|
+
if (Number.isFinite(n) && n >= 0) return n + 1;
|
|
1047
|
+
}
|
|
1048
|
+
const d1 = el.getAttribute('data-idx') || el.getAttribute('data-position') || (el.dataset && (el.dataset.idx || el.dataset.position));
|
|
1049
|
+
if (d1 !== null && d1 !== undefined && d1 !== '' && !isNaN(d1)) {
|
|
1050
|
+
const n = parseInt(d1, 10);
|
|
1051
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
1052
|
+
}
|
|
1053
|
+
} catch (e) {}
|
|
1054
|
+
return fallbackIndex + 1;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
function buildOrdinalMap(items) {
|
|
1058
|
+
const map = new Map();
|
|
1059
|
+
let max = 0;
|
|
1060
|
+
for (let i = 0; i < items.length; i++) {
|
|
1061
|
+
const el = items[i];
|
|
1062
|
+
const ord = getItemOrdinal(el, i);
|
|
1063
|
+
map.set(ord, el);
|
|
1064
|
+
if (ord > max) max = ord;
|
|
1065
|
+
}
|
|
1066
|
+
return { map, max };
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
|
|
1016
1070
|
function computeTargets(count, interval, showFirst) {
|
|
1017
1071
|
const out = [];
|
|
1018
1072
|
if (count <= 0) return out;
|
|
@@ -1027,14 +1081,15 @@ function globalGapFixInit() {
|
|
|
1027
1081
|
function injectBetween(kindClass, items, interval, showFirst, allIds, cursorKey) {
|
|
1028
1082
|
if (!items.length) return 0;
|
|
1029
1083
|
|
|
1030
|
-
const
|
|
1084
|
+
const { map: ordinalMap, max: maxOrdinal } = buildOrdinalMap(items);
|
|
1085
|
+
const targets = computeTargets(maxOrdinal, interval, showFirst);
|
|
1031
1086
|
let inserted = 0;
|
|
1032
1087
|
const maxInserts = MAX_INSERTS_PER_RUN + (isBoosted() ? 1 : 0);
|
|
1033
1088
|
|
|
1034
1089
|
for (const afterPos of targets) {
|
|
1035
1090
|
if (inserted >= maxInserts) break;
|
|
1036
|
-
|
|
1037
|
-
|
|
1091
|
+
const el = ordinalMap.get(afterPos);
|
|
1092
|
+
if (!el) continue;
|
|
1038
1093
|
if (!el || !el.isConnected) continue;
|
|
1039
1094
|
if (isAdjacentAd(el)) continue;
|
|
1040
1095
|
if (findWrap(kindClass, afterPos)) continue;
|
package/public/test.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hi
|