nodebb-plugin-ezoic-infinite 1.7.86 → 1.7.87
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 -126
- package/public/style.css +6 -35
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -76,14 +76,10 @@
|
|
|
76
76
|
const A_WRAPID = 'data-ezoic-wrapid'; // id Ezoic
|
|
77
77
|
const A_CREATED = 'data-ezoic-created'; // timestamp création ms
|
|
78
78
|
const A_SHOWN = 'data-ezoic-shown'; // timestamp dernier showAds ms
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const MIN_LIVE_AFTER_SHOW_MS = 15_000;
|
|
84
|
-
const MIN_LIVE_AFTER_FILL_MS = 25_000;
|
|
85
|
-
const KEEP_SHELL_AFTER_UNUSED_MS = 90_000;
|
|
86
|
-
const MIN_SHELL_HEIGHT = 120;
|
|
79
|
+
|
|
80
|
+
// anti-race fill async (Ezoic peut remplir bien après showAds)
|
|
81
|
+
const EMPTY_CHECK_PASSES = [20_000, 25_000, 35_000];
|
|
82
|
+
|
|
87
83
|
const MIN_PRUNE_AGE_MS = 8_000; // délai de grâce avant pruning (stabilisation DOM)
|
|
88
84
|
const MAX_INSERTS_RUN = 6; // max insertions par appel runCore
|
|
89
85
|
const MAX_INFLIGHT = 4; // max showAds() simultanés
|
|
@@ -126,6 +122,8 @@
|
|
|
126
122
|
cursors: { topics: 0, posts: 0, categories: 0 },
|
|
127
123
|
mountedIds: new Set(),
|
|
128
124
|
lastShow: new Map(),
|
|
125
|
+
emptyChecks: new Map(), // id -> [timerIds] checks is-empty multi-pass
|
|
126
|
+
fillObs: new Map(), // id -> MutationObserver placeholder fill tardif
|
|
129
127
|
io: null,
|
|
130
128
|
domObs: null,
|
|
131
129
|
mutGuard: 0, // >0 : mutations DOM en cours (MutationObserver ignoré)
|
|
@@ -133,8 +131,6 @@
|
|
|
133
131
|
pending: [], // ids en attente de slot inflight
|
|
134
132
|
pendingSet: new Set(),
|
|
135
133
|
wrapByKey: new Map(), // anchorKey → wrap DOM node
|
|
136
|
-
emptyChecks: new Map(), // id → [timerIds]
|
|
137
|
-
fillObsById: new Map(), // id → MutationObserver
|
|
138
134
|
runQueued: false,
|
|
139
135
|
burstActive: false,
|
|
140
136
|
burstDeadline: 0,
|
|
@@ -150,85 +146,47 @@
|
|
|
150
146
|
const normBool = v => v === true || v === 'true' || v === 1 || v === '1' || v === 'on';
|
|
151
147
|
const isFilled = n => !!(n?.querySelector?.('iframe, ins, img, video, [data-google-container-id]'));
|
|
152
148
|
|
|
149
|
+
function clearEmptyChecks(id) {
|
|
150
|
+
const arr = S.emptyChecks.get(id);
|
|
151
|
+
if (arr) {
|
|
152
|
+
for (const t of arr) clearTimeout(t);
|
|
153
|
+
S.emptyChecks.delete(id);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
153
156
|
|
|
154
|
-
function
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
function
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
wrap.classList.add('is-unused-shell');
|
|
186
|
-
wrap.style.minHeight = `${h}px`;
|
|
187
|
-
if (ph) ph.style.minHeight = `${h}px`;
|
|
188
|
-
} catch (_) {}
|
|
189
|
-
}
|
|
190
|
-
function clearUnusedShell(wrap, ph) {
|
|
191
|
-
try {
|
|
192
|
-
wrap?.classList?.remove('is-unused-shell');
|
|
193
|
-
wrap?.style?.removeProperty('min-height');
|
|
194
|
-
ph?.style?.removeProperty('min-height');
|
|
195
|
-
} catch (_) {}
|
|
196
|
-
}
|
|
197
|
-
function isProtectedFromDrop(wrap) {
|
|
198
|
-
try {
|
|
199
|
-
const now = ts();
|
|
200
|
-
const shownTs = parseInt(wrap?.getAttribute?.(A_SHOWN) || '0', 10) || 0;
|
|
201
|
-
const filledTs = parseInt(wrap?.getAttribute?.(A_FILLED) || '0', 10) || 0;
|
|
202
|
-
if (shownTs && (now - shownTs) < MIN_LIVE_AFTER_SHOW_MS) return true;
|
|
203
|
-
if (filledTs && (now - filledTs) < MIN_LIVE_AFTER_FILL_MS) return true;
|
|
204
|
-
return false;
|
|
205
|
-
} catch (_) { return false; }
|
|
206
|
-
}
|
|
207
|
-
function uncollapseIfFilled(ph) {
|
|
208
|
-
try {
|
|
209
|
-
const wrap = ph?.closest?.(`.${WRAP_CLASS}`);
|
|
210
|
-
if (!wrap) return;
|
|
211
|
-
if (isFilled(ph)) {
|
|
212
|
-
wrap.classList.remove('is-empty');
|
|
213
|
-
clearUnusedShell(wrap, ph);
|
|
214
|
-
markFilledOnce(ph);
|
|
157
|
+
function queueEmptyCheck(id, timerId) {
|
|
158
|
+
const arr = S.emptyChecks.get(id) || [];
|
|
159
|
+
arr.push(timerId);
|
|
160
|
+
S.emptyChecks.set(id, arr);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function uncollapseIfFilled(ph) {
|
|
164
|
+
try {
|
|
165
|
+
const wrap = ph?.closest?.(`.${WRAP_CLASS}`);
|
|
166
|
+
if (!wrap) return;
|
|
167
|
+
if (isFilled(ph)) wrap.classList.remove('is-empty');
|
|
168
|
+
} catch (_) {}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function watchPlaceholderFill(id) {
|
|
172
|
+
try {
|
|
173
|
+
const ph = document.getElementById(`${PH_PREFIX}${id}`);
|
|
174
|
+
if (!ph?.isConnected) return;
|
|
175
|
+
if (S.fillObs.has(id)) return;
|
|
176
|
+
const obs = new MutationObserver(() => uncollapseIfFilled(ph));
|
|
177
|
+
obs.observe(ph, { childList: true, subtree: true, attributes: true });
|
|
178
|
+
S.fillObs.set(id, obs);
|
|
179
|
+
uncollapseIfFilled(ph);
|
|
180
|
+
} catch (_) {}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function unwatchPlaceholderFill(id) {
|
|
184
|
+
const obs = S.fillObs.get(id);
|
|
185
|
+
if (obs) {
|
|
186
|
+
try { obs.disconnect(); } catch (_) {}
|
|
187
|
+
S.fillObs.delete(id);
|
|
215
188
|
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
function unwatchPlaceholderFill(id) {
|
|
219
|
-
const obs = S.fillObsById.get(id);
|
|
220
|
-
if (obs) { try { obs.disconnect(); } catch (_) {} S.fillObsById.delete(id); }
|
|
221
|
-
}
|
|
222
|
-
function watchPlaceholderFill(id) {
|
|
223
|
-
try {
|
|
224
|
-
const ph = document.getElementById(`${PH_PREFIX}${id}`);
|
|
225
|
-
if (!ph || !ph.isConnected || S.fillObsById.has(id)) return;
|
|
226
|
-
const obs = new MutationObserver(() => uncollapseIfFilled(ph));
|
|
227
|
-
obs.observe(ph, { childList: true, subtree: true, attributes: true });
|
|
228
|
-
S.fillObsById.set(id, obs);
|
|
229
|
-
uncollapseIfFilled(ph);
|
|
230
|
-
} catch (_) {}
|
|
231
|
-
}
|
|
189
|
+
}
|
|
232
190
|
|
|
233
191
|
function mutate(fn) {
|
|
234
192
|
S.mutGuard++;
|
|
@@ -429,20 +387,19 @@ function watchPlaceholderFill(id) {
|
|
|
429
387
|
// Neutraliser l'IO sur ce wrap avant déplacement — évite un showAds
|
|
430
388
|
// parasite si le nœud était encore dans la zone IO_MARGIN.
|
|
431
389
|
try { const ph = best.querySelector(`#${PH_PREFIX}${id}`); if (ph) S.io?.unobserve(ph); } catch (_) {}
|
|
390
|
+
if (Number.isFinite(id)) clearEmptyChecks(id);
|
|
432
391
|
mutate(() => {
|
|
433
392
|
best.setAttribute(A_ANCHOR, newKey);
|
|
434
393
|
best.setAttribute(A_CREATED, String(ts()));
|
|
435
394
|
best.setAttribute(A_SHOWN, '0');
|
|
436
395
|
best.classList.remove('is-empty');
|
|
437
|
-
best.classList.remove('is-unused-shell');
|
|
438
|
-
best.removeAttribute(A_FILLED);
|
|
439
|
-
best.removeAttribute(A_LAST_H);
|
|
440
396
|
const ph = best.querySelector(`#${PH_PREFIX}${id}`);
|
|
441
|
-
if (ph)
|
|
397
|
+
if (ph) ph.innerHTML = '';
|
|
442
398
|
targetEl.insertAdjacentElement('afterend', best);
|
|
443
399
|
});
|
|
444
400
|
if (oldKey && S.wrapByKey.get(oldKey) === best) S.wrapByKey.delete(oldKey);
|
|
445
401
|
S.wrapByKey.set(newKey, best);
|
|
402
|
+
observePh(id);
|
|
446
403
|
|
|
447
404
|
// Délais requis : destroyPlaceholders est asynchrone en interne
|
|
448
405
|
const doDestroy = () => { try { ez.destroyPlaceholders([id]); } catch (_) {} setTimeout(doDefine, 300); };
|
|
@@ -479,24 +436,16 @@ function watchPlaceholderFill(id) {
|
|
|
479
436
|
mutate(() => el.insertAdjacentElement('afterend', w));
|
|
480
437
|
S.mountedIds.add(id);
|
|
481
438
|
S.wrapByKey.set(key, w);
|
|
482
|
-
watchPlaceholderFill(id);
|
|
483
439
|
return w;
|
|
484
440
|
}
|
|
485
441
|
|
|
486
442
|
function dropWrap(w) {
|
|
487
443
|
try {
|
|
488
444
|
const ph = w.querySelector(`[id^="${PH_PREFIX}"]`);
|
|
489
|
-
const id = parseInt(w.getAttribute(A_WRAPID), 10);
|
|
490
|
-
if (isProtectedFromDrop(w) || shouldKeepShellAfterUnused(w)) {
|
|
491
|
-
if (ph) applyUnusedShell(w, ph);
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
445
|
if (ph instanceof Element) S.io?.unobserve(ph);
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
S.mountedIds.delete(id);
|
|
499
|
-
}
|
|
446
|
+
const id = parseInt(w.getAttribute(A_WRAPID), 10);
|
|
447
|
+
if (Number.isFinite(id)) { clearEmptyChecks(id); unwatchPlaceholderFill(id); }
|
|
448
|
+
if (Number.isFinite(id)) S.mountedIds.delete(id);
|
|
500
449
|
const key = w.getAttribute(A_ANCHOR);
|
|
501
450
|
if (key && S.wrapByKey.get(key) === w) S.wrapByKey.delete(key);
|
|
502
451
|
w.remove();
|
|
@@ -604,8 +553,8 @@ function watchPlaceholderFill(id) {
|
|
|
604
553
|
function observePh(id) {
|
|
605
554
|
const ph = document.getElementById(`${PH_PREFIX}${id}`);
|
|
606
555
|
if (ph?.isConnected) {
|
|
607
|
-
watchPlaceholderFill(id);
|
|
608
556
|
try { getIO()?.observe(ph); } catch (_) {}
|
|
557
|
+
watchPlaceholderFill(id);
|
|
609
558
|
}
|
|
610
559
|
}
|
|
611
560
|
|
|
@@ -645,8 +594,9 @@ function watchPlaceholderFill(id) {
|
|
|
645
594
|
if (isBlocked()) { clearTimeout(timer); return release(); }
|
|
646
595
|
const ph = document.getElementById(`${PH_PREFIX}${id}`);
|
|
647
596
|
if (!ph?.isConnected || isFilled(ph)) { clearTimeout(timer); return release(); }
|
|
597
|
+
|
|
648
598
|
clearEmptyChecks(id);
|
|
649
|
-
try {
|
|
599
|
+
try { ph.closest?.(`.${WRAP_CLASS}`)?.classList.remove('is-empty'); } catch (_) {}
|
|
650
600
|
|
|
651
601
|
const t = ts();
|
|
652
602
|
if (t - (S.lastShow.get(id) ?? 0) < SHOW_THROTTLE_MS) { clearTimeout(timer); return release(); }
|
|
@@ -667,35 +617,24 @@ function watchPlaceholderFill(id) {
|
|
|
667
617
|
}
|
|
668
618
|
|
|
669
619
|
function scheduleEmptyCheck(id, showTs) {
|
|
620
|
+
clearEmptyChecks(id);
|
|
621
|
+
|
|
670
622
|
const runCheck = () => {
|
|
671
623
|
try {
|
|
672
624
|
const ph = document.getElementById(`${PH_PREFIX}${id}`);
|
|
673
625
|
const wrap = ph?.closest?.(`.${WRAP_CLASS}`);
|
|
674
626
|
if (!wrap || !ph?.isConnected) return;
|
|
675
627
|
if (parseInt(wrap.getAttribute(A_SHOWN) || '0', 10) > showTs) return;
|
|
676
|
-
|
|
677
|
-
if (
|
|
678
|
-
|
|
679
|
-
clearUnusedShell(wrap, ph);
|
|
680
|
-
markFilledOnce(ph);
|
|
681
|
-
return;
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
if (shouldKeepShellAfterUnused(wrap)) {
|
|
685
|
-
applyUnusedShell(wrap, ph);
|
|
686
|
-
return;
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
clearUnusedShell(wrap, ph);
|
|
690
|
-
wrap.classList.add('is-empty');
|
|
628
|
+
const filled = isFilled(ph);
|
|
629
|
+
if (filled) wrap.classList.remove('is-empty');
|
|
630
|
+
else wrap.classList.add('is-empty');
|
|
691
631
|
} catch (_) {}
|
|
692
632
|
};
|
|
693
633
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
});
|
|
634
|
+
for (const delay of EMPTY_CHECK_PASSES) {
|
|
635
|
+
const tid = setTimeout(runCheck, delay);
|
|
636
|
+
queueEmptyCheck(id, tid);
|
|
637
|
+
}
|
|
699
638
|
}
|
|
700
639
|
|
|
701
640
|
// ── Patch Ezoic showAds ────────────────────────────────────────────────────
|
|
@@ -821,12 +760,14 @@ function watchPlaceholderFill(id) {
|
|
|
821
760
|
S.cursors = { topics: 0, posts: 0, categories: 0 };
|
|
822
761
|
S.mountedIds.clear();
|
|
823
762
|
S.lastShow.clear();
|
|
824
|
-
for (const id of Array.from(S.emptyChecks.keys())) clearEmptyChecks(id);
|
|
825
|
-
for (const id of Array.from(S.fillObsById.keys())) unwatchPlaceholderFill(id);
|
|
826
763
|
S.wrapByKey.clear();
|
|
827
764
|
S.inflight = 0;
|
|
828
765
|
S.pending = [];
|
|
829
766
|
S.pendingSet.clear();
|
|
767
|
+
S.emptyChecks.forEach(arr => { try { arr.forEach(clearTimeout); } catch (_) {} });
|
|
768
|
+
S.emptyChecks.clear();
|
|
769
|
+
S.fillObs.forEach(obs => { try { obs.disconnect(); } catch (_) {} });
|
|
770
|
+
S.fillObs.clear();
|
|
830
771
|
S.burstActive = false;
|
|
831
772
|
S.runQueued = false;
|
|
832
773
|
}
|
package/public/style.css
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
width: 100%;
|
|
9
9
|
margin: 0 !important;
|
|
10
10
|
padding: 0 !important;
|
|
11
|
-
overflow:
|
|
11
|
+
overflow: hidden;
|
|
12
12
|
contain: layout style;
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -71,14 +71,7 @@
|
|
|
71
71
|
overflow: hidden !important;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
/*
|
|
75
|
-
.ezoic-ad {
|
|
76
|
-
margin: 0 !important;
|
|
77
|
-
padding: 0 !important;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
/* Filet de sécurité : si un fill arrive tard alors que .is-empty est resté, ne pas écraser */
|
|
74
|
+
/* Filet de sécurité : si un fill est présent malgré is-empty, on ne collapse pas */
|
|
82
75
|
.nodebb-ezoic-wrap.is-empty:has(iframe, ins, img, video, [data-google-container-id]) {
|
|
83
76
|
height: auto !important;
|
|
84
77
|
min-height: 1px !important;
|
|
@@ -86,30 +79,8 @@
|
|
|
86
79
|
overflow: visible !important;
|
|
87
80
|
}
|
|
88
81
|
|
|
89
|
-
/*
|
|
90
|
-
.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
.nodebb-ezoic-wrap.is-unused-shell > [id^="ezoic-pub-ad-placeholder-"] {
|
|
94
|
-
display: block;
|
|
95
|
-
width: 100%;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/* Responsive hardening conservatif (sans scale JS) */
|
|
99
|
-
.nodebb-ezoic-wrap,
|
|
100
|
-
.nodebb-ezoic-wrap > [id^="ezoic-pub-ad-placeholder-"] {
|
|
101
|
-
max-width: 100%;
|
|
102
|
-
}
|
|
103
|
-
.nodebb-ezoic-wrap .ezoic-ad,
|
|
104
|
-
.nodebb-ezoic-wrap span.ezoic-ad {
|
|
105
|
-
max-width: 100% !important;
|
|
106
|
-
min-width: 0 !important;
|
|
107
|
-
box-sizing: border-box !important;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/* Neutralisation sticky plus défensive dans les wraps du plugin */
|
|
111
|
-
.nodebb-ezoic-wrap .ezads-sticky-intradiv,
|
|
112
|
-
.nodebb-ezoic-wrap [style*="position: sticky"] {
|
|
113
|
-
position: static !important;
|
|
114
|
-
top: auto !important;
|
|
82
|
+
/* ── Ezoic global (hors de nos wraps) ────────────────────────────────────── */
|
|
83
|
+
.ezoic-ad {
|
|
84
|
+
margin: 0 !important;
|
|
85
|
+
padding: 0 !important;
|
|
115
86
|
}
|