nodebb-plugin-ezoic-infinite 1.5.75 → 1.5.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 +68 -2
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -38,6 +38,46 @@
|
|
|
38
38
|
// Production build: debug disabled
|
|
39
39
|
function dbg() {}
|
|
40
40
|
|
|
41
|
+
// Ezoic (and some partner scripts) can be very noisy in console on SPA/Ajaxify setups.
|
|
42
|
+
// These warnings are not actionable for end-users and can flood the console.
|
|
43
|
+
// We selectively silence the known spam patterns while keeping other warnings intact.
|
|
44
|
+
function muteNoisyConsole() {
|
|
45
|
+
try {
|
|
46
|
+
if (window.__nodebbEzoicConsoleMuted) return;
|
|
47
|
+
window.__nodebbEzoicConsoleMuted = true;
|
|
48
|
+
|
|
49
|
+
const shouldMute = (args) => {
|
|
50
|
+
try {
|
|
51
|
+
if (!args || !args.length) return false;
|
|
52
|
+
const s0 = typeof args[0] === 'string' ? args[0] : '';
|
|
53
|
+
// Duplicate placeholder definition spam (common when reusing ids in SPA/Ajaxify).
|
|
54
|
+
if (s0.includes('[EzoicAds JS]: Placeholder Id') && s0.includes('has already been defined')) return true;
|
|
55
|
+
// Ezoic debugger iframe spam.
|
|
56
|
+
if (s0.includes('Debugger iframe already exists')) return true;
|
|
57
|
+
// Missing placeholder spam (we already guard showAds; Ezoic still logs sometimes).
|
|
58
|
+
if (s0.includes('HTML element with id ezoic-pub-ad-placeholder-') && s0.includes('does not exist')) return true;
|
|
59
|
+
return false;
|
|
60
|
+
} catch (e) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const wrap = (method) => {
|
|
66
|
+
const orig = console[method];
|
|
67
|
+
if (typeof orig !== 'function') return;
|
|
68
|
+
console[method] = function (...args) {
|
|
69
|
+
if (shouldMute(args)) return;
|
|
70
|
+
return orig.apply(console, args);
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
wrap('log');
|
|
75
|
+
wrap('info');
|
|
76
|
+
wrap('warn');
|
|
77
|
+
wrap('error');
|
|
78
|
+
} catch (e) {}
|
|
79
|
+
}
|
|
80
|
+
|
|
41
81
|
|
|
42
82
|
|
|
43
83
|
function isFilledNode(node) {
|
|
@@ -546,6 +586,10 @@ function globalGapFixInit() {
|
|
|
546
586
|
wrap.setAttribute('data-ezoic-after', String(afterPos));
|
|
547
587
|
wrap.setAttribute('data-ezoic-wrapid', String(id));
|
|
548
588
|
wrap.setAttribute('data-created', String(now()));
|
|
589
|
+
// "Pinned" placements (after the first item) should remain stable.
|
|
590
|
+
if (afterPos === 1) {
|
|
591
|
+
wrap.setAttribute('data-ezoic-pin', '1');
|
|
592
|
+
}
|
|
549
593
|
wrap.style.width = '100%';
|
|
550
594
|
|
|
551
595
|
if (createPlaceholder) {
|
|
@@ -604,8 +648,9 @@ function globalGapFixInit() {
|
|
|
604
648
|
}
|
|
605
649
|
|
|
606
650
|
function pruneOrphanWraps(kindClass, items) {
|
|
607
|
-
//
|
|
608
|
-
|
|
651
|
+
// Message ads should remain stable (desktop + mobile). Pruning them can make it look like
|
|
652
|
+
// ads vanish on scroll and can reduce fill on long topics.
|
|
653
|
+
if (kindClass === 'ezoic-ad-message') return 0;
|
|
609
654
|
if (!items || !items.length) return 0;
|
|
610
655
|
const itemSet = new Set(items);
|
|
611
656
|
const wraps = document.querySelectorAll(`.${WRAP_CLASS}.${kindClass}`);
|
|
@@ -631,6 +676,11 @@ function globalGapFixInit() {
|
|
|
631
676
|
};
|
|
632
677
|
|
|
633
678
|
wraps.forEach((wrap) => {
|
|
679
|
+
// Never prune pinned placements.
|
|
680
|
+
try {
|
|
681
|
+
if (wrap.getAttribute('data-ezoic-pin') === '1') return;
|
|
682
|
+
} catch (e) {}
|
|
683
|
+
|
|
634
684
|
if (isFilled(wrap)) return; // never prune filled ads
|
|
635
685
|
|
|
636
686
|
// Never prune a fresh wrap: it may fill late.
|
|
@@ -670,9 +720,19 @@ function globalGapFixInit() {
|
|
|
670
720
|
|
|
671
721
|
let removed = 0;
|
|
672
722
|
for (const w of wraps) {
|
|
723
|
+
// Never decluster pinned placements.
|
|
724
|
+
try {
|
|
725
|
+
if (w.getAttribute && w.getAttribute('data-ezoic-pin') === '1') continue;
|
|
726
|
+
} catch (e) {}
|
|
727
|
+
|
|
673
728
|
let prev = w.previousElementSibling;
|
|
674
729
|
for (let i = 0; i < 3 && prev; i++) {
|
|
675
730
|
if (isWrap(prev)) {
|
|
731
|
+
// If the previous wrap is pinned, keep this one (spacing is intentional).
|
|
732
|
+
try {
|
|
733
|
+
if (prev.getAttribute && prev.getAttribute('data-ezoic-pin') === '1') break;
|
|
734
|
+
} catch (e) {}
|
|
735
|
+
|
|
676
736
|
// Don't decluster two "fresh" empty wraps — it can reduce fill on slow auctions.
|
|
677
737
|
// Only decluster when at least one is filled, or when the newer one is stale.
|
|
678
738
|
const prevFilled = isFilled(prev);
|
|
@@ -1020,6 +1080,10 @@ function globalGapFixInit() {
|
|
|
1020
1080
|
|
|
1021
1081
|
state.heroDoneForPage = true;
|
|
1022
1082
|
observePlaceholder(id);
|
|
1083
|
+
// Hero placement is expected to be visible right away (after first item),
|
|
1084
|
+
// so kick a fill request immediately instead of waiting only for IO callbacks.
|
|
1085
|
+
enqueueShow(id);
|
|
1086
|
+
startShowQueue();
|
|
1023
1087
|
}
|
|
1024
1088
|
|
|
1025
1089
|
// ---------------- scheduler ----------------
|
|
@@ -1154,6 +1218,7 @@ function globalGapFixInit() {
|
|
|
1154
1218
|
state.pageKey = getPageKey();
|
|
1155
1219
|
blockedUntil = 0;
|
|
1156
1220
|
|
|
1221
|
+
muteNoisyConsole();
|
|
1157
1222
|
warmUpNetwork();
|
|
1158
1223
|
patchShowAds();
|
|
1159
1224
|
globalGapFixInit();
|
|
@@ -1208,6 +1273,7 @@ function globalGapFixInit() {
|
|
|
1208
1273
|
// ---------------- boot ----------------
|
|
1209
1274
|
|
|
1210
1275
|
state.pageKey = getPageKey();
|
|
1276
|
+
muteNoisyConsole();
|
|
1211
1277
|
warmUpNetwork();
|
|
1212
1278
|
patchShowAds();
|
|
1213
1279
|
ensurePreloadObserver();
|