nodebb-plugin-ezoic-infinite 1.5.73 → 1.5.75
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 +155 -22
- package/public/style.css +8 -0
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -44,37 +44,100 @@ function isFilledNode(node) {
|
|
|
44
44
|
return !!(node && node.querySelector && node.querySelector('iframe, ins, img, video, [data-google-container-id]'));
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
// Ezoic
|
|
48
|
-
//
|
|
49
|
-
//
|
|
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
50
|
function tightenEzoicMinHeight(wrap) {
|
|
51
51
|
try {
|
|
52
52
|
if (!wrap || !wrap.querySelector) return;
|
|
53
|
-
const outer = wrap.querySelector('.ezoic-ad-adaptive') ||
|
|
54
|
-
wrap.querySelector('.ezoic-ad[style*="min-height"]') ||
|
|
55
|
-
wrap.querySelector('.ezoic-ad');
|
|
56
|
-
if (!outer) return;
|
|
57
53
|
|
|
58
|
-
const iframes =
|
|
54
|
+
const iframes = wrap.querySelectorAll('iframe');
|
|
59
55
|
if (!iframes || !iframes.length) return;
|
|
60
56
|
|
|
61
|
-
|
|
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;
|
|
62
80
|
iframes.forEach((f) => {
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
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);
|
|
66
86
|
});
|
|
67
|
-
if (!h) return;
|
|
68
87
|
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
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
|
+
});
|
|
72
133
|
|
|
73
134
|
// Mobile friendliness: avoid giant fixed widths causing overflow/reflow.
|
|
74
135
|
if (isMobile()) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
+
});
|
|
78
141
|
}
|
|
79
142
|
} catch (e) {}
|
|
80
143
|
}
|
|
@@ -82,19 +145,88 @@ function tightenEzoicMinHeight(wrap) {
|
|
|
82
145
|
function watchWrapForFill(wrap) {
|
|
83
146
|
try {
|
|
84
147
|
if (!wrap || wrap.__ezFillObs) return;
|
|
85
|
-
|
|
148
|
+
|
|
149
|
+
// Ezoic can (re)apply inline styles after fill; keep tightening for a short window.
|
|
150
|
+
const start = now();
|
|
151
|
+
const tightenBurst = () => {
|
|
152
|
+
try { tightenEzoicMinHeight(wrap); } catch (e) {}
|
|
153
|
+
if (now() - start < 6000) {
|
|
154
|
+
setTimeout(tightenBurst, 350);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const obs = new MutationObserver((muts) => {
|
|
159
|
+
// If anything that looks like ad content appears, treat as filled.
|
|
86
160
|
if (isFilledNode(wrap)) {
|
|
87
161
|
wrap.classList.remove('is-empty');
|
|
88
|
-
|
|
162
|
+
tightenBurst();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// If Ezoic changes inline style on descendants (min-height:400!important), tighten again.
|
|
166
|
+
for (const m of muts) {
|
|
167
|
+
if (m.type === 'attributes' && m.attributeName === 'style') {
|
|
168
|
+
try { tightenEzoicMinHeight(wrap); } catch (e) {}
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Disconnect only after the burst window to avoid missing late style rewrites.
|
|
174
|
+
if (now() - start > 7000) {
|
|
89
175
|
try { obs.disconnect(); } catch (e) {}
|
|
90
176
|
wrap.__ezFillObs = null;
|
|
91
177
|
}
|
|
92
178
|
});
|
|
93
|
-
|
|
179
|
+
|
|
180
|
+
obs.observe(wrap, { childList: true, subtree: true, attributes: true, attributeFilter: ['style'] });
|
|
94
181
|
wrap.__ezFillObs = obs;
|
|
95
182
|
} catch (e) {}
|
|
96
183
|
}
|
|
97
184
|
|
|
185
|
+
// Global safety net: sometimes Ezoic swaps nodes in ways that bypass our per-wrap observers.
|
|
186
|
+
// When we see an Ezoic container with min-height:400!important inside posts/topics, shrink it.
|
|
187
|
+
function globalGapFixInit() {
|
|
188
|
+
try {
|
|
189
|
+
if (window.__nodebbEzoicGapFix) return;
|
|
190
|
+
window.__nodebbEzoicGapFix = true;
|
|
191
|
+
|
|
192
|
+
const inPostArea = (el) => {
|
|
193
|
+
try {
|
|
194
|
+
return !!(el && el.closest && el.closest('[component="post"], .topic, .posts, [component="topic"]'));
|
|
195
|
+
} catch (e) { return false; }
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const maybeFix = (root) => {
|
|
199
|
+
if (!root || !root.querySelectorAll) return;
|
|
200
|
+
const nodes = root.querySelectorAll('.ezoic-ad[style*="min-height"], .ezoic-ad-adaptive[style*="min-height"]');
|
|
201
|
+
nodes.forEach((n) => {
|
|
202
|
+
const st = (n.getAttribute('style') || '').toLowerCase();
|
|
203
|
+
if (!st.includes('min-height:400')) return;
|
|
204
|
+
if (!inPostArea(n)) return;
|
|
205
|
+
try {
|
|
206
|
+
const tmpWrap = n.closest('.' + WRAP_CLASS) || n.parentElement;
|
|
207
|
+
tightenEzoicMinHeight(tmpWrap || n);
|
|
208
|
+
} catch (e) {}
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
requestAnimationFrame(() => maybeFix(document));
|
|
213
|
+
|
|
214
|
+
const obs = new MutationObserver((muts) => {
|
|
215
|
+
for (const m of muts) {
|
|
216
|
+
const t = m.target;
|
|
217
|
+
if (m.type === 'attributes') {
|
|
218
|
+
maybeFix(t && t.nodeType === 1 ? t : t && t.parentElement);
|
|
219
|
+
} else if (m.addedNodes && m.addedNodes.length) {
|
|
220
|
+
m.addedNodes.forEach((n) => {
|
|
221
|
+
if (n && n.nodeType === 1) maybeFix(n);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
obs.observe(document.documentElement, { subtree: true, childList: true, attributes: true, attributeFilter: ['style'] });
|
|
227
|
+
} catch (e) {}
|
|
228
|
+
}
|
|
229
|
+
|
|
98
230
|
// ---------------- state ----------------
|
|
99
231
|
|
|
100
232
|
const state = {
|
|
@@ -1024,6 +1156,7 @@ function watchWrapForFill(wrap) {
|
|
|
1024
1156
|
|
|
1025
1157
|
warmUpNetwork();
|
|
1026
1158
|
patchShowAds();
|
|
1159
|
+
globalGapFixInit();
|
|
1027
1160
|
ensurePreloadObserver();
|
|
1028
1161
|
ensureDomObserver();
|
|
1029
1162
|
|
package/public/style.css
CHANGED
|
@@ -71,3 +71,11 @@
|
|
|
71
71
|
|
|
72
72
|
/* Ensure Ezoic reportline doesn't affect layout */
|
|
73
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
|
+
}
|