nodebb-plugin-ezoic-infinite 1.6.75 → 1.6.76
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 +67 -76
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -133,7 +133,29 @@ function tightenEzoicMinHeight(wrap) {
|
|
|
133
133
|
if (!wrap || !wrap.querySelector) return;
|
|
134
134
|
|
|
135
135
|
const iframes = wrap.querySelectorAll('iframe');
|
|
136
|
-
|
|
136
|
+
|
|
137
|
+
// If the wrap is still empty, Ezoic often leaves inline `min-height:400px !important` on
|
|
138
|
+
// nested `.ezoic-ad` containers, which creates large blank gaps. We can't remove it with CSS.
|
|
139
|
+
// We collapse those gaps after a short grace period, while still allowing late fill.
|
|
140
|
+
if (!iframes || !iframes.length) {
|
|
141
|
+
try {
|
|
142
|
+
const created = parseInt(wrap.getAttribute('data-created') || '0', 10);
|
|
143
|
+
const age = created ? (now() - created) : 0;
|
|
144
|
+
// Give auctions/CMP a bit of time; then collapse the notorious 400px gap.
|
|
145
|
+
if (age >= 12000) {
|
|
146
|
+
const nodes = wrap.querySelectorAll('.ezoic-ad, .ezoic-ad-adaptive');
|
|
147
|
+
nodes.forEach((n) => {
|
|
148
|
+
const st = (n.getAttribute('style') || '').toLowerCase();
|
|
149
|
+
if (st.includes('min-height:400') || st.includes('min-height: 400') || st.includes('min-height:400px')) {
|
|
150
|
+
try { n.style.setProperty('min-height', '1px', 'important'); } catch (e) { n.style.minHeight = '1px'; }
|
|
151
|
+
try { n.style.setProperty('height', 'auto', 'important'); } catch (e) {}
|
|
152
|
+
try { n.style.setProperty('line-height', '0', 'important'); } catch (e) {}
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
} catch (e) {}
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
137
159
|
|
|
138
160
|
// Find the closest "big" ezoic container that carries the 400px min-height.
|
|
139
161
|
const firstIframe = iframes[0];
|
|
@@ -220,42 +242,6 @@ function tightenEzoicMinHeight(wrap) {
|
|
|
220
242
|
} catch (e) {}
|
|
221
243
|
}
|
|
222
244
|
|
|
223
|
-
// If a placement never fills, Ezoic may still leave an inline `min-height:400px !important`
|
|
224
|
-
// on nested containers, creating large "blank" blocks. On SPA/infinite scroll, some
|
|
225
|
-
// auctions can fail (network/CMP/adblock). We collapse those gaps after a grace period.
|
|
226
|
-
function collapseEmptyGap(wrap) {
|
|
227
|
-
try {
|
|
228
|
-
if (!wrap || !wrap.isConnected) return;
|
|
229
|
-
if (isFilledNode(wrap)) return;
|
|
230
|
-
|
|
231
|
-
const created = parseInt(wrap.getAttribute('data-created') || '0', 10);
|
|
232
|
-
if (!created) return;
|
|
233
|
-
// Give plenty of time for late fill (CMP / header bidding).
|
|
234
|
-
if ((now() - created) < 12000) return;
|
|
235
|
-
|
|
236
|
-
// Find the nested node that carries the 400px min-height.
|
|
237
|
-
const nodes = wrap.querySelectorAll('.ezoic-ad, .ezoic-ad-adaptive');
|
|
238
|
-
nodes.forEach((n) => {
|
|
239
|
-
const st = (n.getAttribute('style') || '').toLowerCase();
|
|
240
|
-
if (st.includes('min-height:400')) {
|
|
241
|
-
try { n.style.setProperty('min-height', '1px', 'important'); } catch (e) { n.style.minHeight = '1px'; }
|
|
242
|
-
try { n.style.setProperty('height', 'auto', 'important'); } catch (e) {}
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
// Also collapse our wrapper's reserved height.
|
|
247
|
-
try { wrap.style.setProperty('min-height', '1px', 'important'); } catch (e) { wrap.style.minHeight = '1px'; }
|
|
248
|
-
try { wrap.style.setProperty('height', 'auto', 'important'); } catch (e) {}
|
|
249
|
-
} catch (e) {}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function collapseEmptyGaps(kindClass) {
|
|
253
|
-
try {
|
|
254
|
-
const wraps = document.querySelectorAll(`.${WRAP_CLASS}.${kindClass}`);
|
|
255
|
-
wraps.forEach((w) => collapseEmptyGap(w));
|
|
256
|
-
} catch (e) {}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
245
|
function watchWrapForFill(wrap) {
|
|
260
246
|
try {
|
|
261
247
|
if (!wrap || wrap.__ezFillObs) return;
|
|
@@ -774,47 +760,48 @@ function globalGapFixInit() {
|
|
|
774
760
|
if (wrap.getAttribute('data-ezoic-pin') === '1') return;
|
|
775
761
|
} catch (e) {}
|
|
776
762
|
|
|
777
|
-
//
|
|
778
|
-
//
|
|
779
|
-
// "stack" (back-to-back) when the user scrolls back up.
|
|
780
|
-
//
|
|
781
|
-
// Topic list pages (categoryTopics) are also virtualized in some themes/plugins,
|
|
782
|
-
// so we must treat between-ads similarly to message-ads.
|
|
763
|
+
// For message/topic pages we may prune filled or empty orphans if they are far away,
|
|
764
|
+
// otherwise consecutive "stacks" can appear when posts are virtualized.
|
|
783
765
|
const isMessage = (kindClass === 'ezoic-ad-message');
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
//
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
} catch (e) {}
|
|
793
|
-
|
|
766
|
+
// IMPORTANT:
|
|
767
|
+
// On category/topic lists, NodeBB can virtualize/recycle list items while scrolling.
|
|
768
|
+
// If we keep *filled* wraps when their anchor items are gone, they can visually
|
|
769
|
+
// "stack" together on upward scroll. We therefore allow filled wraps to be hidden
|
|
770
|
+
// when orphaned, but we still avoid fully releasing them (so they can come back
|
|
771
|
+
// when anchors reappear).
|
|
772
|
+
|
|
773
|
+
// If the wrap is anchored to current items, ensure it is visible.
|
|
794
774
|
if (hasNearbyItem(wrap)) {
|
|
795
|
-
try {
|
|
796
|
-
wrap.classList && wrap.classList.remove('ez-orphan-hidden');
|
|
797
|
-
wrap.style && (wrap.style.display = '');
|
|
798
|
-
} catch (e) {}
|
|
775
|
+
try { wrap.classList && wrap.classList.remove('ez-orphan-hidden'); wrap.style && (wrap.style.display = ''); } catch (e) {}
|
|
799
776
|
return;
|
|
800
777
|
}
|
|
801
778
|
|
|
802
|
-
// If the anchor item is no longer in the DOM (virtualized), hide the wrap so ads never
|
|
803
|
-
// back-to-back while scrolling.
|
|
779
|
+
// If the anchor item is no longer in the DOM (virtualized), hide the wrap so ads never 'stack'
|
|
780
|
+
// back-to-back while scrolling. We'll restore it when its anchor comes back.
|
|
781
|
+
try { wrap.classList && wrap.classList.add('ez-orphan-hidden'); wrap.style && (wrap.style.display = 'none'); } catch (e) {}
|
|
782
|
+
|
|
783
|
+
// On topic/category lists, never release orphan wraps. Releasing moves placeholders around and makes
|
|
784
|
+
// ads appear to 'travel' from top to bottom as you scroll. Parking (hiding) keeps DOM order stable.
|
|
785
|
+
const isList = (kindClass === 'ezoic-ad-between' || kindClass === 'ezoic-ad-categories');
|
|
786
|
+
if (isList) return;
|
|
787
|
+
|
|
788
|
+
// Never release a fresh wrap: it may fill late (auction/CMP). Keep it hidden for a while.
|
|
804
789
|
try {
|
|
805
|
-
|
|
806
|
-
|
|
790
|
+
const created = parseInt(wrap.getAttribute('data-created') || '0', 10);
|
|
791
|
+
if (created && (now() - created) < keepEmptyWrapMs()) return;
|
|
807
792
|
} catch (e) {}
|
|
808
793
|
|
|
809
|
-
//
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
794
|
+
// For message ads: only release if far offscreen to avoid perceived 'vanishing' during fast scroll.
|
|
795
|
+
if (isMessage) {
|
|
796
|
+
try {
|
|
797
|
+
const r = wrap.getBoundingClientRect();
|
|
798
|
+
const vh = Math.max(1, window.innerHeight || 1);
|
|
799
|
+
const farAbove = r.bottom < -vh * 2;
|
|
800
|
+
const farBelow = r.top > vh * 4;
|
|
801
|
+
if (!farAbove && !farBelow) return;
|
|
802
|
+
} catch (e) {
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
818
805
|
}
|
|
819
806
|
|
|
820
807
|
withInternalDomChange(() => releaseWrapNode(wrap));
|
|
@@ -844,7 +831,6 @@ function globalGapFixInit() {
|
|
|
844
831
|
}
|
|
845
832
|
};
|
|
846
833
|
|
|
847
|
-
const lookback = (kindClass === 'ezoic-ad-between') ? 12 : 3;
|
|
848
834
|
let removed = 0;
|
|
849
835
|
for (const w of wraps) {
|
|
850
836
|
// Never decluster pinned placements.
|
|
@@ -853,7 +839,7 @@ function globalGapFixInit() {
|
|
|
853
839
|
} catch (e) {}
|
|
854
840
|
|
|
855
841
|
let prev = w.previousElementSibling;
|
|
856
|
-
for (let i = 0; i <
|
|
842
|
+
for (let i = 0; i < 3 && prev; i++) {
|
|
857
843
|
if (isWrap(prev)) {
|
|
858
844
|
// If the previous wrap is pinned, keep this one (spacing is intentional).
|
|
859
845
|
try {
|
|
@@ -865,6 +851,12 @@ function globalGapFixInit() {
|
|
|
865
851
|
const prevFilled = isFilled(prev);
|
|
866
852
|
const curFilled = isFilled(w);
|
|
867
853
|
|
|
854
|
+
// On topic/category lists, prevent visible stacking by hiding the later wrap immediately.
|
|
855
|
+
if ((kindClass === 'ezoic-ad-between' || kindClass === 'ezoic-ad-categories') && prevFilled && curFilled) {
|
|
856
|
+
try { w.classList && w.classList.add('ez-stack-hidden'); w.style && (w.style.display = 'none'); } catch (e) {}
|
|
857
|
+
break;
|
|
858
|
+
}
|
|
859
|
+
|
|
868
860
|
if (curFilled) {
|
|
869
861
|
// If the previous one is empty (and not fresh), drop the previous instead.
|
|
870
862
|
if (!prevFilled && !isFresh(prev)) {
|
|
@@ -1066,6 +1058,8 @@ function globalGapFixInit() {
|
|
|
1066
1058
|
watchWrapForFill(ww);
|
|
1067
1059
|
setTimeout(() => { try { tightenEzoicMinHeight(ww); } catch (e) {} }, 900);
|
|
1068
1060
|
setTimeout(() => { try { tightenEzoicMinHeight(ww); } catch (e) {} }, 2200);
|
|
1061
|
+
// Collapse the notorious 400px inline min-height if the slot stays empty.
|
|
1062
|
+
setTimeout(() => { try { tightenEzoicMinHeight(ww); } catch (e) {} }, 12500);
|
|
1069
1063
|
}
|
|
1070
1064
|
} catch (e) {}
|
|
1071
1065
|
setTimeout(() => { clearTimeout(hardTimer); release(); }, 650);
|
|
@@ -1151,7 +1145,7 @@ function buildOrdinalMap(items) {
|
|
|
1151
1145
|
if (!id) {
|
|
1152
1146
|
// Safe mode: disable recycling for topic message ads to prevent visual "jumping"
|
|
1153
1147
|
// (ads seemingly moving back under the first post during virtualized scroll).
|
|
1154
|
-
const allowRecycle = kindClass !== 'ezoic-ad-message';
|
|
1148
|
+
const allowRecycle = kindClass !== 'ezoic-ad-message' && kindClass !== 'ezoic-ad-between' && kindClass !== 'ezoic-ad-categories';
|
|
1155
1149
|
recycledWrap = (allowRecycle && scrollDir > 0) ? pickRecyclableWrap(kindClass) : null;
|
|
1156
1150
|
if (recycledWrap) {
|
|
1157
1151
|
id = recycledWrap.getAttribute('data-ezoic-wrapid') || '';
|
|
@@ -1243,7 +1237,6 @@ function buildOrdinalMap(items) {
|
|
|
1243
1237
|
'curPosts'
|
|
1244
1238
|
);
|
|
1245
1239
|
decluster('ezoic-ad-message');
|
|
1246
|
-
collapseEmptyGaps('ezoic-ad-message');
|
|
1247
1240
|
}
|
|
1248
1241
|
} else if (kind === 'categoryTopics') {
|
|
1249
1242
|
if (normalizeBool(cfg.enableBetweenAds)) {
|
|
@@ -1258,7 +1251,6 @@ function buildOrdinalMap(items) {
|
|
|
1258
1251
|
'curTopics'
|
|
1259
1252
|
);
|
|
1260
1253
|
decluster('ezoic-ad-between');
|
|
1261
|
-
collapseEmptyGaps('ezoic-ad-between');
|
|
1262
1254
|
}
|
|
1263
1255
|
} else if (kind === 'categories') {
|
|
1264
1256
|
if (normalizeBool(cfg.enableCategoryAds)) {
|
|
@@ -1273,7 +1265,6 @@ function buildOrdinalMap(items) {
|
|
|
1273
1265
|
'curCategories'
|
|
1274
1266
|
);
|
|
1275
1267
|
decluster('ezoic-ad-categories');
|
|
1276
|
-
collapseEmptyGaps('ezoic-ad-categories');
|
|
1277
1268
|
}
|
|
1278
1269
|
}
|
|
1279
1270
|
|