nodebb-plugin-ezoic-infinite 1.5.76 → 1.5.78
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 +62 -18
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
const POOL_ID = 'nodebb-ezoic-placeholder-pool';
|
|
11
11
|
|
|
12
12
|
// Smoothness caps
|
|
13
|
-
|
|
13
|
+
// Limit how many placements we inject per scan pass.
|
|
14
|
+
// Too low = you end up with only a handful of placeholders after ajaxify.
|
|
15
|
+
// Too high = jank on very long pages.
|
|
16
|
+
const MAX_INSERTS_PER_RUN = 8;
|
|
14
17
|
|
|
15
18
|
// Keep empty (unfilled) wraps alive for a while. Topics/messages can fill late (auction/CMP).
|
|
16
19
|
// Pruning too early makes ads look like they "disappear" while scrolling.
|
|
@@ -135,11 +138,8 @@ function tightenEzoicMinHeight(wrap) {
|
|
|
135
138
|
}
|
|
136
139
|
if (!maxBottom) return;
|
|
137
140
|
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
if (report && report.offsetHeight) {
|
|
141
|
-
maxBottom += report.offsetHeight;
|
|
142
|
-
}
|
|
141
|
+
// NOTE: Do NOT add the Ezoic badge (reportline) height here.
|
|
142
|
+
// It is absolutely positioned and should not reserve layout space.
|
|
143
143
|
|
|
144
144
|
const h = Math.max(1, Math.ceil(maxBottom));
|
|
145
145
|
|
|
@@ -229,6 +229,9 @@ function globalGapFixInit() {
|
|
|
229
229
|
if (window.__nodebbEzoicGapFix) return;
|
|
230
230
|
window.__nodebbEzoicGapFix = true;
|
|
231
231
|
|
|
232
|
+
// Observe only the main content area to minimize overhead.
|
|
233
|
+
const root = document.getElementById('content') || document.querySelector('[component="content"], #panel') || document.body;
|
|
234
|
+
|
|
232
235
|
const inPostArea = (el) => {
|
|
233
236
|
try {
|
|
234
237
|
return !!(el && el.closest && el.closest('[component="post"], .topic, .posts, [component="topic"]'));
|
|
@@ -249,21 +252,37 @@ function globalGapFixInit() {
|
|
|
249
252
|
});
|
|
250
253
|
};
|
|
251
254
|
|
|
252
|
-
requestAnimationFrame(() => maybeFix(
|
|
255
|
+
requestAnimationFrame(() => maybeFix(root));
|
|
256
|
+
|
|
257
|
+
// Batch DOM mutation processing into a single rAF to avoid doing work per mutation.
|
|
258
|
+
const pending = new Set();
|
|
259
|
+
let scheduled = false;
|
|
260
|
+
const scheduleFlush = () => {
|
|
261
|
+
if (scheduled) return;
|
|
262
|
+
scheduled = true;
|
|
263
|
+
requestAnimationFrame(() => {
|
|
264
|
+
scheduled = false;
|
|
265
|
+
pending.forEach((n) => {
|
|
266
|
+
try { maybeFix(n); } catch (e) {}
|
|
267
|
+
});
|
|
268
|
+
pending.clear();
|
|
269
|
+
});
|
|
270
|
+
};
|
|
253
271
|
|
|
254
272
|
const obs = new MutationObserver((muts) => {
|
|
255
273
|
for (const m of muts) {
|
|
256
|
-
const t = m.target;
|
|
257
274
|
if (m.type === 'attributes') {
|
|
258
|
-
|
|
275
|
+
const t = m.target && m.target.nodeType === 1 ? m.target : m.target && m.target.parentElement;
|
|
276
|
+
if (t) pending.add(t);
|
|
259
277
|
} else if (m.addedNodes && m.addedNodes.length) {
|
|
260
278
|
m.addedNodes.forEach((n) => {
|
|
261
|
-
if (n && n.nodeType === 1)
|
|
279
|
+
if (n && n.nodeType === 1) pending.add(n);
|
|
262
280
|
});
|
|
263
281
|
}
|
|
264
282
|
}
|
|
283
|
+
if (pending.size) scheduleFlush();
|
|
265
284
|
});
|
|
266
|
-
obs.observe(
|
|
285
|
+
obs.observe(root, { subtree: true, childList: true, attributes: true, attributeFilter: ['style'] });
|
|
267
286
|
} catch (e) {}
|
|
268
287
|
}
|
|
269
288
|
|
|
@@ -570,12 +589,11 @@ function globalGapFixInit() {
|
|
|
570
589
|
if (!state.allPosts.length) state.allPosts = parsePool(cfg.messagePlaceholderIds);
|
|
571
590
|
if (!state.allCategories.length) state.allCategories = parsePool(cfg.categoryPlaceholderIds);
|
|
572
591
|
|
|
573
|
-
//
|
|
574
|
-
//
|
|
575
|
-
//
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
primePlaceholderPool(state.allCategories);
|
|
592
|
+
// IMPORTANT:
|
|
593
|
+
// We do NOT prime a DOM pool anymore.
|
|
594
|
+
// Keeping placeholders connected (even offscreen) can lead Ezoic/GPT to
|
|
595
|
+
// pre-define slots, which then causes "Placeholder Id X has already been defined".
|
|
596
|
+
// Instead, we create the placeholder element only when we actually inject its wrapper.
|
|
579
597
|
}
|
|
580
598
|
|
|
581
599
|
// ---------------- insertion primitives ----------------
|
|
@@ -892,6 +910,16 @@ function globalGapFixInit() {
|
|
|
892
910
|
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
893
911
|
if (!ph || !ph.isConnected) return;
|
|
894
912
|
|
|
913
|
+
// If the placeholder already has creative, avoid re-showing.
|
|
914
|
+
// Re-showing is a common source of "Placeholder Id X has already been defined".
|
|
915
|
+
try {
|
|
916
|
+
if (ph.querySelector && ph.querySelector('iframe, ins, img, video, [data-google-container-id]')) {
|
|
917
|
+
clearTimeout(hardTimer);
|
|
918
|
+
release();
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
} catch (e) {}
|
|
922
|
+
|
|
895
923
|
const t = now();
|
|
896
924
|
const last = state.lastShowById.get(id) || 0;
|
|
897
925
|
if (t - last < 900) return;
|
|
@@ -1229,13 +1257,29 @@ function globalGapFixInit() {
|
|
|
1229
1257
|
requestBurst();
|
|
1230
1258
|
});
|
|
1231
1259
|
|
|
1260
|
+
// Some setups populate content in multiple phases; ensure we re-scan.
|
|
1261
|
+
$(window).on('action:ajaxify.contentLoaded.ezoicInfinite', () => {
|
|
1262
|
+
if (isBlocked()) return;
|
|
1263
|
+
requestBurst();
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1232
1266
|
$(window).on(
|
|
1233
|
-
'action:posts.loaded.ezoicInfinite action:topics.loaded.ezoicInfinite action:category.loaded.ezoicInfinite action:topic.loaded.ezoicInfinite',
|
|
1267
|
+
'action:posts.loaded.ezoicInfinite action:topics.loaded.ezoicInfinite action:categories.loaded.ezoicInfinite action:category.loaded.ezoicInfinite action:topic.loaded.ezoicInfinite',
|
|
1234
1268
|
() => {
|
|
1235
1269
|
if (isBlocked()) return;
|
|
1236
1270
|
requestBurst();
|
|
1237
1271
|
}
|
|
1238
1272
|
);
|
|
1273
|
+
|
|
1274
|
+
// Also listen through NodeBB's AMD hooks module when available.
|
|
1275
|
+
try {
|
|
1276
|
+
require(['hooks'], (hooks) => {
|
|
1277
|
+
if (!hooks || typeof hooks.on !== 'function') return;
|
|
1278
|
+
['action:ajaxify.end', 'action:ajaxify.contentLoaded', 'action:posts.loaded', 'action:topics.loaded', 'action:categories.loaded', 'action:category.loaded', 'action:topic.loaded'].forEach((ev) => {
|
|
1279
|
+
try { hooks.on(ev, () => { if (!isBlocked()) requestBurst(); }); } catch (e) {}
|
|
1280
|
+
});
|
|
1281
|
+
});
|
|
1282
|
+
} catch (e) {}
|
|
1239
1283
|
}
|
|
1240
1284
|
|
|
1241
1285
|
function bindScroll() {
|