nodebb-plugin-ezoic-infinite 1.5.72 → 1.5.74
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 +144 -6
- package/public/style.css +11 -0
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
// Keep empty (unfilled) wraps alive for a while. Topics/messages can fill late (auction/CMP).
|
|
16
16
|
// Pruning too early makes ads look like they "disappear" while scrolling.
|
|
17
|
-
|
|
17
|
+
// Keep empty wraps alive; mobile fills can be slow.
|
|
18
|
+
function keepEmptyWrapMs() { return isMobile() ? 120000 : 60000; }
|
|
18
19
|
|
|
19
20
|
// Preload margins
|
|
20
21
|
const PRELOAD_MARGIN_DESKTOP = '2600px 0px 2600px 0px';
|
|
@@ -37,7 +38,127 @@
|
|
|
37
38
|
// Production build: debug disabled
|
|
38
39
|
function dbg() {}
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
function isFilledNode(node) {
|
|
44
|
+
return !!(node && node.querySelector && node.querySelector('iframe, ins, img, video, [data-google-container-id]'));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Ezoic injects inline `min-height:400px !important` on one or more nested wrappers.
|
|
48
|
+
// If the creative is 250px, this leaves ~150px empty space. Because it's inline+important,
|
|
49
|
+
// CSS alone cannot fix it reliably — we must rewrite the inline style.
|
|
50
|
+
function tightenEzoicMinHeight(wrap) {
|
|
51
|
+
try {
|
|
52
|
+
if (!wrap || !wrap.querySelector) return;
|
|
53
|
+
|
|
54
|
+
const iframes = wrap.querySelectorAll('iframe');
|
|
55
|
+
if (!iframes || !iframes.length) return;
|
|
56
|
+
|
|
57
|
+
// Find the closest "big" ezoic container that carries the 400px min-height.
|
|
58
|
+
const firstIframe = iframes[0];
|
|
59
|
+
let refNode = null;
|
|
60
|
+
let p = firstIframe && firstIframe.parentElement;
|
|
61
|
+
while (p && p !== wrap) {
|
|
62
|
+
if (p.classList && p.classList.contains('ezoic-ad')) {
|
|
63
|
+
const st = (p.getAttribute('style') || '').toLowerCase();
|
|
64
|
+
if (st.includes('min-height:400') || st.includes('min-height: 400') || st.includes('min-height:400px')) {
|
|
65
|
+
refNode = p;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
p = p.parentElement;
|
|
70
|
+
}
|
|
71
|
+
if (!refNode) {
|
|
72
|
+
refNode = wrap.querySelector('.ezoic-ad-adaptive') || wrap.querySelector('.ezoic-ad') || wrap;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let refTop = 0;
|
|
76
|
+
try { refTop = refNode.getBoundingClientRect().top; } catch (e) { refTop = 0; }
|
|
77
|
+
|
|
78
|
+
// Compute the rendered height needed inside refNode (visible iframes only).
|
|
79
|
+
let maxBottom = 0;
|
|
80
|
+
iframes.forEach((f) => {
|
|
81
|
+
if (!f || !f.getBoundingClientRect) return;
|
|
82
|
+
const rect = f.getBoundingClientRect();
|
|
83
|
+
if (rect.width <= 1 || rect.height <= 1) return;
|
|
84
|
+
const bottom = rect.bottom - refTop;
|
|
85
|
+
maxBottom = Math.max(maxBottom, bottom);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Fallback to attr/offset if layout metrics are not available.
|
|
89
|
+
if (!maxBottom) {
|
|
90
|
+
iframes.forEach((f) => {
|
|
91
|
+
const ah = parseInt(f.getAttribute('height') || '0', 10);
|
|
92
|
+
const oh = f.offsetHeight || 0;
|
|
93
|
+
maxBottom = Math.max(maxBottom, ah, oh);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (!maxBottom) return;
|
|
97
|
+
|
|
98
|
+
// Account for the Ezoic badge (reportline) which is absolutely positioned.
|
|
99
|
+
const report = refNode.querySelector('.reportline');
|
|
100
|
+
if (report && report.offsetHeight) {
|
|
101
|
+
maxBottom += report.offsetHeight;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const h = Math.max(1, Math.ceil(maxBottom));
|
|
105
|
+
|
|
106
|
+
const tightenNode = (node) => {
|
|
107
|
+
if (!node || !node.style) return;
|
|
108
|
+
try { node.style.setProperty('min-height', h + 'px', 'important'); } catch (e) { node.style.minHeight = h + 'px'; }
|
|
109
|
+
try { node.style.setProperty('height', 'auto', 'important'); } catch (e) {}
|
|
110
|
+
try { node.style.setProperty('line-height', '0', 'important'); } catch (e) {}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Tighten refNode and any ancestor ezoic-ad nodes with the problematic min-height.
|
|
114
|
+
let cur = refNode;
|
|
115
|
+
while (cur && cur !== wrap) {
|
|
116
|
+
if (cur.classList && cur.classList.contains('ezoic-ad')) {
|
|
117
|
+
const st = (cur.getAttribute('style') || '').toLowerCase();
|
|
118
|
+
if (st.includes('min-height:400') || st.includes('min-height: 400') || st.includes('min-height:400px')) {
|
|
119
|
+
tightenNode(cur);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
cur = cur.parentElement;
|
|
123
|
+
}
|
|
124
|
+
tightenNode(refNode);
|
|
125
|
+
|
|
126
|
+
// Tighten any nested wrappers that also have the 400px min-height inline.
|
|
127
|
+
refNode.querySelectorAll('.ezoic-ad[style*="min-height"], .ezoic-ad-adaptive').forEach((n) => {
|
|
128
|
+
const st = (n.getAttribute('style') || '').toLowerCase();
|
|
129
|
+
if (st.includes('min-height:400') || st.includes('min-height: 400') || st.includes('min-height:400px')) {
|
|
130
|
+
tightenNode(n);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Mobile friendliness: avoid giant fixed widths causing overflow/reflow.
|
|
135
|
+
if (isMobile()) {
|
|
136
|
+
[refNode].forEach((n) => {
|
|
137
|
+
try { n.style.setProperty('width', '100%', 'important'); } catch (e) {}
|
|
138
|
+
try { n.style.setProperty('max-width', '100%', 'important'); } catch (e) {}
|
|
139
|
+
try { n.style.setProperty('min-width', '0', 'important'); } catch (e) {}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
} catch (e) {}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function watchWrapForFill(wrap) {
|
|
146
|
+
try {
|
|
147
|
+
if (!wrap || wrap.__ezFillObs) return;
|
|
148
|
+
const obs = new MutationObserver(() => {
|
|
149
|
+
if (isFilledNode(wrap)) {
|
|
150
|
+
wrap.classList.remove('is-empty');
|
|
151
|
+
tightenEzoicMinHeight(wrap);
|
|
152
|
+
try { obs.disconnect(); } catch (e) {}
|
|
153
|
+
wrap.__ezFillObs = null;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
obs.observe(wrap, { childList: true, subtree: true });
|
|
157
|
+
wrap.__ezFillObs = obs;
|
|
158
|
+
} catch (e) {}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ---------------- state ----------------
|
|
41
162
|
|
|
42
163
|
const state = {
|
|
43
164
|
pageKey: null,
|
|
@@ -414,6 +535,8 @@
|
|
|
414
535
|
}
|
|
415
536
|
|
|
416
537
|
function pruneOrphanWraps(kindClass, items) {
|
|
538
|
+
// On mobile topics/messages, keep wraps alive longer to avoid 'disappearing' ads.
|
|
539
|
+
if (kindClass === 'ezoic-ad-message' && isMobile()) return 0;
|
|
417
540
|
if (!items || !items.length) return 0;
|
|
418
541
|
const itemSet = new Set(items);
|
|
419
542
|
const wraps = document.querySelectorAll(`.${WRAP_CLASS}.${kindClass}`);
|
|
@@ -444,7 +567,7 @@
|
|
|
444
567
|
// Never prune a fresh wrap: it may fill late.
|
|
445
568
|
try {
|
|
446
569
|
const created = parseInt(wrap.getAttribute('data-created') || '0', 10);
|
|
447
|
-
if (created && (now() - created) <
|
|
570
|
+
if (created && (now() - created) < keepEmptyWrapMs()) return;
|
|
448
571
|
} catch (e) {}
|
|
449
572
|
|
|
450
573
|
if (hasNearbyItem(wrap)) return;
|
|
@@ -470,7 +593,7 @@
|
|
|
470
593
|
const isFresh = (wrap) => {
|
|
471
594
|
try {
|
|
472
595
|
const created = parseInt(wrap.getAttribute('data-created') || '0', 10);
|
|
473
|
-
return created && (now() - created) <
|
|
596
|
+
return created && (now() - created) < keepEmptyWrapMs();
|
|
474
597
|
} catch (e) {
|
|
475
598
|
return false;
|
|
476
599
|
}
|
|
@@ -603,11 +726,17 @@
|
|
|
603
726
|
// Don't collapse "fresh" placements; slow auctions/CMP can fill late.
|
|
604
727
|
try {
|
|
605
728
|
const created = parseInt(w2.getAttribute('data-created') || '0', 10);
|
|
606
|
-
if (created && (now() - created) <
|
|
729
|
+
if (created && (now() - created) < keepEmptyWrapMs()) return;
|
|
607
730
|
} catch (e) {}
|
|
608
731
|
|
|
609
732
|
const hasAd = !!(ph2.querySelector && ph2.querySelector('iframe, ins, img, .ez-ad, .ezoic-ad'));
|
|
610
|
-
if (!hasAd)
|
|
733
|
+
if (!hasAd) {
|
|
734
|
+
w2.classList.add('is-empty');
|
|
735
|
+
watchWrapForFill(w2);
|
|
736
|
+
} else {
|
|
737
|
+
w2.classList.remove('is-empty');
|
|
738
|
+
tightenEzoicMinHeight(w2);
|
|
739
|
+
}
|
|
611
740
|
} catch (e) {}
|
|
612
741
|
}, 15000);
|
|
613
742
|
} catch (e) {}
|
|
@@ -645,6 +774,15 @@
|
|
|
645
774
|
const doShow = () => {
|
|
646
775
|
try { ez.showAds(id); } catch (e) {}
|
|
647
776
|
try { markEmptyWrapper(id); } catch (e) {}
|
|
777
|
+
try {
|
|
778
|
+
const phw = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
779
|
+
const ww = phw && phw.closest ? phw.closest(`.${WRAP_CLASS}`) : null;
|
|
780
|
+
if (ww) {
|
|
781
|
+
watchWrapForFill(ww);
|
|
782
|
+
setTimeout(() => { try { tightenEzoicMinHeight(ww); } catch (e) {} }, 900);
|
|
783
|
+
setTimeout(() => { try { tightenEzoicMinHeight(ww); } catch (e) {} }, 2200);
|
|
784
|
+
}
|
|
785
|
+
} catch (e) {}
|
|
648
786
|
setTimeout(() => { clearTimeout(hardTimer); release(); }, 650);
|
|
649
787
|
};
|
|
650
788
|
|
package/public/style.css
CHANGED
|
@@ -68,3 +68,14 @@
|
|
|
68
68
|
min-height: 1px !important; /* kill 400px gaps */
|
|
69
69
|
height: auto !important;
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
/* Ensure Ezoic reportline doesn't affect layout */
|
|
73
|
+
.nodebb-ezoic-wrap .reportline{position:absolute!important;}
|
|
74
|
+
|
|
75
|
+
/* Ezoic sometimes injects `position: sticky` inside placements. In long NodeBB topics,
|
|
76
|
+
this can create "gliding" and sudden disappear/reappear effects while scrolling.
|
|
77
|
+
We neutralize sticky positioning *inside our injected wrappers* only. */
|
|
78
|
+
.nodebb-ezoic-wrap .ezads-sticky-intradiv {
|
|
79
|
+
position: static !important;
|
|
80
|
+
top: auto !important;
|
|
81
|
+
}
|