nodebb-plugin-ezoic-infinite 1.7.84 → 1.7.85
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 +148 -113
- package/public/style.css +8 -6
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -76,16 +76,22 @@
|
|
|
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
|
-
const A_FILLED = 'data-ezoic-filled';
|
|
79
|
+
const A_FILLED = 'data-ezoic-filled'; // timestamp premier fill réel ms
|
|
80
|
+
const A_LAST_W = 'data-ezoic-lastw'; // dernière largeur pub connue
|
|
81
|
+
const A_LAST_H = 'data-ezoic-lasth'; // dernière hauteur pub connue
|
|
80
82
|
|
|
81
83
|
const EMPTY_CHECK_MS = 20_000; // délai avant collapse d'un wrap vide post-show
|
|
84
|
+
const EMPTY_RECHECK_2_MS = EMPTY_CHECK_MS + 5_000;
|
|
85
|
+
const EMPTY_RECHECK_3_MS = EMPTY_CHECK_MS + 15_000;
|
|
86
|
+
const MIN_LIVE_AFTER_SHOW_MS = 15_000;
|
|
87
|
+
const MIN_LIVE_AFTER_FILL_MS = 25_000;
|
|
88
|
+
const KEEP_SHELL_AFTER_UNUSED_MS = 90_000;
|
|
89
|
+
const MIN_SHELL_HEIGHT = 120;
|
|
82
90
|
const MIN_PRUNE_AGE_MS = 8_000; // délai de grâce avant pruning (stabilisation DOM)
|
|
83
91
|
const MAX_INSERTS_RUN = 6; // max insertions par appel runCore
|
|
84
92
|
const MAX_INFLIGHT = 4; // max showAds() simultanés
|
|
85
93
|
const SHOW_THROTTLE_MS = 900; // anti-spam showAds() par id
|
|
86
94
|
const BURST_COOLDOWN_MS = 200; // délai min entre deux déclenchements de burst
|
|
87
|
-
const MIN_LIVE_AFTER_SHOW_MS = 15_000; // grâce post-show avant drop/recycle
|
|
88
|
-
const MIN_LIVE_AFTER_FILL_MS = 25_000; // grâce post-fill réel avant drop/recycle
|
|
89
95
|
|
|
90
96
|
// Marges IO larges et fixes — observer créé une seule fois au boot
|
|
91
97
|
const IO_MARGIN_DESKTOP = '2500px 0px 2500px 0px';
|
|
@@ -130,8 +136,7 @@
|
|
|
130
136
|
pending: [], // ids en attente de slot inflight
|
|
131
137
|
pendingSet: new Set(),
|
|
132
138
|
wrapByKey: new Map(), // anchorKey → wrap DOM node
|
|
133
|
-
emptyChecks:
|
|
134
|
-
fillObs: new Map(), // id -> MutationObserver (late fill uncollapse + responsive fit)
|
|
139
|
+
emptyChecks: new Map(), // id -> timeout ids
|
|
135
140
|
runQueued: false,
|
|
136
141
|
burstActive: false,
|
|
137
142
|
burstDeadline: 0,
|
|
@@ -147,12 +152,16 @@
|
|
|
147
152
|
const normBool = v => v === true || v === 'true' || v === 1 || v === '1' || v === 'on';
|
|
148
153
|
const isFilled = n => !!(n?.querySelector?.('iframe, ins, img, video, [data-google-container-id]'));
|
|
149
154
|
|
|
155
|
+
function mutate(fn) {
|
|
156
|
+
S.mutGuard++;
|
|
157
|
+
try { fn(); } finally { S.mutGuard--; }
|
|
158
|
+
}
|
|
159
|
+
|
|
150
160
|
function clearEmptyChecks(id) {
|
|
151
161
|
const timers = S.emptyChecks.get(id);
|
|
152
|
-
if (timers)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
162
|
+
if (!timers) return;
|
|
163
|
+
for (const t of timers) clearTimeout(t);
|
|
164
|
+
S.emptyChecks.delete(id);
|
|
156
165
|
}
|
|
157
166
|
|
|
158
167
|
function queueEmptyCheck(id, timerId) {
|
|
@@ -160,28 +169,28 @@
|
|
|
160
169
|
S.emptyChecks.get(id).push(timerId);
|
|
161
170
|
}
|
|
162
171
|
|
|
172
|
+
function hasEverFilled(wrap) { return !!wrap?.getAttribute?.(A_FILLED); }
|
|
173
|
+
function getFilledTs(wrap) { return parseInt(wrap?.getAttribute?.(A_FILLED) || '0', 10) || 0; }
|
|
174
|
+
function shouldKeepShellAfterUnused(wrap) {
|
|
175
|
+
const t = getFilledTs(wrap);
|
|
176
|
+
return !!t && (Date.now() - t) < KEEP_SHELL_AFTER_UNUSED_MS;
|
|
177
|
+
}
|
|
163
178
|
function markFilledOnce(ph) {
|
|
164
179
|
try {
|
|
165
180
|
const wrap = ph?.closest?.(`.${WRAP_CLASS}`);
|
|
166
181
|
if (!wrap) return;
|
|
167
|
-
if (!wrap.getAttribute(A_FILLED) && isFilled(ph))
|
|
168
|
-
wrap.setAttribute(A_FILLED, String(ts()));
|
|
169
|
-
}
|
|
182
|
+
if (!wrap.getAttribute(A_FILLED) && isFilled(ph)) wrap.setAttribute(A_FILLED, String(Date.now()));
|
|
170
183
|
} catch (_) {}
|
|
171
184
|
}
|
|
172
|
-
|
|
173
|
-
function isProtectedFromDrop(wrap) {
|
|
185
|
+
function rememberAdSize(ph, w, h) {
|
|
174
186
|
try {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
if (
|
|
180
|
-
|
|
181
|
-
return false;
|
|
182
|
-
} catch (_) { return false; }
|
|
187
|
+
const wrap = ph?.closest?.(`.${WRAP_CLASS}`);
|
|
188
|
+
if (!wrap) return;
|
|
189
|
+
const ww = Math.round(w || 0), hh = Math.round(h || 0);
|
|
190
|
+
if (ww > 0) wrap.setAttribute(A_LAST_W, String(ww));
|
|
191
|
+
if (hh > 0) wrap.setAttribute(A_LAST_H, String(hh));
|
|
192
|
+
} catch (_) {}
|
|
183
193
|
}
|
|
184
|
-
|
|
185
194
|
function getAdIntrinsicSize(ph) {
|
|
186
195
|
if (!ph) return null;
|
|
187
196
|
const iframe = ph.querySelector('iframe');
|
|
@@ -189,45 +198,42 @@
|
|
|
189
198
|
const wAttr = parseInt(iframe.getAttribute('width') || iframe.getAttribute('ezaw') || '0', 10);
|
|
190
199
|
const hAttr = parseInt(iframe.getAttribute('height') || iframe.getAttribute('ezah') || '0', 10);
|
|
191
200
|
const cs = window.getComputedStyle(iframe);
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
const w = wAttr || Math.round(wCss);
|
|
195
|
-
const h = hAttr || Math.round(hCss);
|
|
201
|
+
const w = wAttr || Math.round(parseFloat(cs.width) || iframe.offsetWidth || 0);
|
|
202
|
+
const h = hAttr || Math.round(parseFloat(cs.height) || iframe.offsetHeight || 0);
|
|
196
203
|
if (w > 0 && h > 0) return { w, h };
|
|
197
204
|
}
|
|
198
|
-
const
|
|
199
|
-
if (
|
|
200
|
-
const cs = window.getComputedStyle(
|
|
201
|
-
const w = Math.round(parseFloat(cs.width) ||
|
|
202
|
-
const h = Math.round(parseFloat(cs.height) ||
|
|
203
|
-
if (w > 0 && h > 0) return { w, h };
|
|
204
|
-
}
|
|
205
|
-
const ez = ph.querySelector('.ezoic-ad');
|
|
206
|
-
if (ez) {
|
|
207
|
-
const cs = window.getComputedStyle(ez);
|
|
208
|
-
const w = Math.round(parseFloat(cs.width) || ez.offsetWidth || 0);
|
|
209
|
-
const h = Math.round(parseFloat(cs.height) || ez.offsetHeight || 0);
|
|
205
|
+
const c = ph.querySelector('[id$="__container__"]') || ph.querySelector('.ezoic-ad');
|
|
206
|
+
if (c) {
|
|
207
|
+
const cs = window.getComputedStyle(c);
|
|
208
|
+
const w = Math.round(parseFloat(cs.width) || c.offsetWidth || 0);
|
|
209
|
+
const h = Math.round(parseFloat(cs.height) || c.offsetHeight || 0);
|
|
210
210
|
if (w > 0 && h > 0) return { w, h };
|
|
211
211
|
}
|
|
212
212
|
return null;
|
|
213
213
|
}
|
|
214
|
-
|
|
214
|
+
function rememberCurrentAdSize(ph) {
|
|
215
|
+
try {
|
|
216
|
+
const size = getAdIntrinsicSize(ph);
|
|
217
|
+
if (size?.w > 0 && size?.h > 0) return rememberAdSize(ph, size.w, size.h);
|
|
218
|
+
const r = ph.getBoundingClientRect?.();
|
|
219
|
+
if (r && (r.width > 0 || r.height > 0)) rememberAdSize(ph, r.width, r.height);
|
|
220
|
+
} catch (_) {}
|
|
221
|
+
}
|
|
215
222
|
function ensureScaleBox(ph) {
|
|
216
223
|
let box = ph.querySelector(':scope > .nbb-ez-scale-box');
|
|
217
224
|
if (box) return box;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (n.nodeType ===
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
if (!
|
|
225
|
+
let hasChild = false;
|
|
226
|
+
for (const n of Array.from(ph.childNodes)) {
|
|
227
|
+
if (n.nodeType === 1) { hasChild = true; break; }
|
|
228
|
+
if (n.nodeType === 3 && (n.textContent || '').trim()) { hasChild = true; break; }
|
|
229
|
+
}
|
|
230
|
+
if (!hasChild) return null;
|
|
224
231
|
box = document.createElement('div');
|
|
225
232
|
box.className = 'nbb-ez-scale-box';
|
|
226
233
|
while (ph.firstChild) box.appendChild(ph.firstChild);
|
|
227
234
|
ph.appendChild(box);
|
|
228
235
|
return box;
|
|
229
236
|
}
|
|
230
|
-
|
|
231
237
|
function clearAdScale(ph) {
|
|
232
238
|
const wrap = ph?.closest?.(`.${WRAP_CLASS}`);
|
|
233
239
|
if (!wrap) return;
|
|
@@ -241,18 +247,18 @@
|
|
|
241
247
|
}
|
|
242
248
|
ph.style.removeProperty('height');
|
|
243
249
|
}
|
|
244
|
-
|
|
245
250
|
function fitWideAd(ph) {
|
|
246
251
|
try {
|
|
247
252
|
if (!ph?.isConnected) return;
|
|
248
253
|
const wrap = ph.closest?.(`.${WRAP_CLASS}`);
|
|
249
254
|
if (!wrap) return;
|
|
250
|
-
if (!isFilled(ph))
|
|
255
|
+
if (!isFilled(ph)) return clearAdScale(ph);
|
|
251
256
|
const size = getAdIntrinsicSize(ph);
|
|
252
257
|
if (!size?.w || !size?.h) return;
|
|
258
|
+
rememberAdSize(ph, size.w, size.h);
|
|
253
259
|
const wrapWidth = Math.max(0, Math.floor(wrap.clientWidth || wrap.getBoundingClientRect().width || 0));
|
|
254
260
|
if (!wrapWidth) return;
|
|
255
|
-
if (size.w <= wrapWidth + 2)
|
|
261
|
+
if (size.w <= wrapWidth + 2) return clearAdScale(ph);
|
|
256
262
|
const scale = Math.max(0.1, Math.min(1, wrapWidth / size.w));
|
|
257
263
|
const scaledH = Math.ceil(size.h * scale);
|
|
258
264
|
const box = ensureScaleBox(ph);
|
|
@@ -265,39 +271,66 @@
|
|
|
265
271
|
wrap.style.height = `${scaledH}px`;
|
|
266
272
|
} catch (_) {}
|
|
267
273
|
}
|
|
268
|
-
|
|
274
|
+
function applyUnusedShell(wrap, ph) {
|
|
275
|
+
try {
|
|
276
|
+
if (!wrap) return;
|
|
277
|
+
const lastH = parseInt(wrap.getAttribute(A_LAST_H) || '0', 10) || 0;
|
|
278
|
+
const h = Math.max(MIN_SHELL_HEIGHT, lastH || 0);
|
|
279
|
+
wrap.classList.remove('is-empty');
|
|
280
|
+
wrap.classList.add('is-unused-shell');
|
|
281
|
+
wrap.style.minHeight = `${h}px`;
|
|
282
|
+
if (ph) ph.style.minHeight = `${h}px`;
|
|
283
|
+
} catch (_) {}
|
|
284
|
+
}
|
|
285
|
+
function clearUnusedShell(wrap, ph) {
|
|
286
|
+
try {
|
|
287
|
+
wrap?.classList?.remove('is-unused-shell');
|
|
288
|
+
wrap?.style?.removeProperty('min-height');
|
|
289
|
+
ph?.style?.removeProperty('min-height');
|
|
290
|
+
} catch (_) {}
|
|
291
|
+
}
|
|
292
|
+
function isProtectedFromDrop(wrap) {
|
|
293
|
+
try {
|
|
294
|
+
const now = Date.now();
|
|
295
|
+
const shownTs = parseInt(wrap?.getAttribute?.(A_SHOWN) || '0', 10) || 0;
|
|
296
|
+
const filledTs = parseInt(wrap?.getAttribute?.(A_FILLED) || '0', 10) || 0;
|
|
297
|
+
if (shownTs && (now - shownTs) < MIN_LIVE_AFTER_SHOW_MS) return true;
|
|
298
|
+
if (filledTs && (now - filledTs) < MIN_LIVE_AFTER_FILL_MS) return true;
|
|
299
|
+
if (shouldKeepShellAfterUnused(wrap)) return true;
|
|
300
|
+
} catch (_) {}
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
269
303
|
function uncollapseIfFilled(ph) {
|
|
270
304
|
try {
|
|
271
305
|
const wrap = ph?.closest?.(`.${WRAP_CLASS}`);
|
|
272
306
|
if (!wrap) return;
|
|
273
307
|
if (isFilled(ph)) {
|
|
274
308
|
wrap.classList.remove('is-empty');
|
|
309
|
+
clearUnusedShell(wrap, ph);
|
|
275
310
|
markFilledOnce(ph);
|
|
311
|
+
rememberCurrentAdSize(ph);
|
|
276
312
|
fitWideAd(ph);
|
|
277
313
|
}
|
|
278
314
|
} catch (_) {}
|
|
279
315
|
}
|
|
280
|
-
|
|
281
|
-
function unwatchPlaceholderFill(phOrId) {
|
|
282
|
-
const id = typeof phOrId === 'number' ? phOrId : parseInt(phOrId?.getAttribute?.('data-ezoic-id'), 10);
|
|
283
|
-
if (!Number.isFinite(id)) return;
|
|
284
|
-
const obs = S.fillObs.get(id);
|
|
285
|
-
if (obs) { try { obs.disconnect(); } catch (_) {} S.fillObs.delete(id); }
|
|
286
|
-
}
|
|
287
|
-
|
|
288
316
|
function watchPlaceholderFill(ph) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const obs = new MutationObserver(() => { uncollapseIfFilled(ph); try { fitWideAd(ph); } catch (_) {} });
|
|
317
|
+
if (!ph || ph.__nbbEzFillObs) return;
|
|
318
|
+
const obs = new MutationObserver(() => { uncollapseIfFilled(ph); });
|
|
292
319
|
try { obs.observe(ph, { childList: true, subtree: true, attributes: true }); } catch (_) { return; }
|
|
293
|
-
|
|
320
|
+
ph.__nbbEzFillObs = obs;
|
|
294
321
|
uncollapseIfFilled(ph);
|
|
295
|
-
try { fitWideAd(ph); } catch (_) {}
|
|
296
322
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
323
|
+
function unwatchPlaceholderFill(ph) {
|
|
324
|
+
try { ph?.__nbbEzFillObs?.disconnect?.(); } catch (_) {}
|
|
325
|
+
try { delete ph.__nbbEzFillObs; } catch (_) {}
|
|
326
|
+
}
|
|
327
|
+
let fitRaf = 0;
|
|
328
|
+
function scheduleRefitAll() {
|
|
329
|
+
if (fitRaf) return;
|
|
330
|
+
fitRaf = requestAnimationFrame(() => {
|
|
331
|
+
fitRaf = 0;
|
|
332
|
+
document.querySelectorAll(`[id^="${PH_PREFIX}"]`).forEach(ph => { try { fitWideAd(ph); } catch (_) {} });
|
|
333
|
+
});
|
|
301
334
|
}
|
|
302
335
|
|
|
303
336
|
// ── Config ─────────────────────────────────────────────────────────────────
|
|
@@ -475,7 +508,6 @@
|
|
|
475
508
|
|
|
476
509
|
document.querySelectorAll(`.${WRAP_CLASS}.${klass}`).forEach(wrap => {
|
|
477
510
|
try {
|
|
478
|
-
if (isProtectedFromDrop(wrap)) return;
|
|
479
511
|
const rect = wrap.getBoundingClientRect();
|
|
480
512
|
if (rect.bottom > threshold) return;
|
|
481
513
|
if (!isFilled(wrap)) {
|
|
@@ -488,26 +520,27 @@
|
|
|
488
520
|
|
|
489
521
|
const best = bestEmpty ?? bestFilled;
|
|
490
522
|
if (!best) return null;
|
|
523
|
+
if (isProtectedFromDrop(best)) return null;
|
|
491
524
|
const id = parseInt(best.getAttribute(A_WRAPID), 10);
|
|
492
525
|
if (!Number.isFinite(id)) return null;
|
|
493
526
|
|
|
494
527
|
const oldKey = best.getAttribute(A_ANCHOR);
|
|
495
528
|
// Neutraliser l'IO sur ce wrap avant déplacement — évite un showAds
|
|
496
529
|
// parasite si le nœud était encore dans la zone IO_MARGIN.
|
|
497
|
-
try { const ph = best.querySelector(`#${PH_PREFIX}${id}`); if (ph) { S.io?.unobserve(ph); clearAdScale(ph);
|
|
498
|
-
clearEmptyChecks(id);
|
|
530
|
+
try { const ph = best.querySelector(`#${PH_PREFIX}${id}`); if (ph) { S.io?.unobserve(ph); unwatchPlaceholderFill(ph); clearAdScale(ph); clearUnusedShell(best, ph); } } catch (_) {}
|
|
499
531
|
mutate(() => {
|
|
500
532
|
best.setAttribute(A_ANCHOR, newKey);
|
|
501
533
|
best.setAttribute(A_CREATED, String(ts()));
|
|
502
534
|
best.setAttribute(A_SHOWN, '0');
|
|
503
|
-
best.
|
|
504
|
-
best.classList.remove('is-empty');
|
|
535
|
+
best.classList.remove('is-empty', 'is-unused-shell');
|
|
505
536
|
const ph = best.querySelector(`#${PH_PREFIX}${id}`);
|
|
506
|
-
if (ph) { ph.innerHTML = ''; ph.style.removeProperty('height'); }
|
|
537
|
+
if (ph) { ph.innerHTML = ''; ph.style.removeProperty('min-height'); ph.style.removeProperty('height'); }
|
|
538
|
+
best.removeAttribute(A_FILLED); best.removeAttribute(A_LAST_W); best.removeAttribute(A_LAST_H);
|
|
507
539
|
targetEl.insertAdjacentElement('afterend', best);
|
|
508
540
|
});
|
|
509
541
|
if (oldKey && S.wrapByKey.get(oldKey) === best) S.wrapByKey.delete(oldKey);
|
|
510
542
|
S.wrapByKey.set(newKey, best);
|
|
543
|
+
try { const ph2 = best.querySelector(`#${PH_PREFIX}${id}`); if (ph2) watchPlaceholderFill(ph2); } catch (_) {}
|
|
511
544
|
|
|
512
545
|
// Délais requis : destroyPlaceholders est asynchrone en interne
|
|
513
546
|
const doDestroy = () => { try { ez.destroyPlaceholders([id]); } catch (_) {} setTimeout(doDefine, 300); };
|
|
@@ -515,7 +548,6 @@
|
|
|
515
548
|
const doDisplay = () => { try { ez.displayMore([id]); } catch (_) {} };
|
|
516
549
|
try { (typeof ez.cmd?.push === 'function') ? ez.cmd.push(doDestroy) : doDestroy(); } catch (_) {}
|
|
517
550
|
|
|
518
|
-
try { const ph = best.querySelector(`#${PH_PREFIX}${id}`); if (ph) { observePh(id); watchPlaceholderFill(ph); } } catch (_) {}
|
|
519
551
|
return { id, wrap: best };
|
|
520
552
|
}
|
|
521
553
|
|
|
@@ -528,7 +560,6 @@
|
|
|
528
560
|
w.setAttribute(A_WRAPID, String(id));
|
|
529
561
|
w.setAttribute(A_CREATED, String(ts()));
|
|
530
562
|
w.setAttribute(A_SHOWN, '0');
|
|
531
|
-
w.setAttribute(A_FILLED, '0');
|
|
532
563
|
w.style.cssText = 'width:100%;display:block;';
|
|
533
564
|
const ph = document.createElement('div');
|
|
534
565
|
ph.id = `${PH_PREFIX}${id}`;
|
|
@@ -546,21 +577,26 @@
|
|
|
546
577
|
mutate(() => el.insertAdjacentElement('afterend', w));
|
|
547
578
|
S.mountedIds.add(id);
|
|
548
579
|
S.wrapByKey.set(key, w);
|
|
549
|
-
try { const ph = w.querySelector(`#${PH_PREFIX}${id}`); if (ph) watchPlaceholderFill(ph); } catch (_) {}
|
|
550
580
|
return w;
|
|
551
581
|
}
|
|
552
582
|
|
|
553
583
|
function dropWrap(w) {
|
|
554
584
|
try {
|
|
555
|
-
if (isProtectedFromDrop(w))
|
|
585
|
+
if (isProtectedFromDrop(w)) {
|
|
586
|
+
const keepPh = w.querySelector(`[id^="${PH_PREFIX}"]`);
|
|
587
|
+
if (shouldKeepShellAfterUnused(w)) applyUnusedShell(w, keepPh);
|
|
588
|
+
return false;
|
|
589
|
+
}
|
|
556
590
|
const ph = w.querySelector(`[id^="${PH_PREFIX}"]`);
|
|
557
|
-
if (ph instanceof Element) { S.io?.unobserve(ph); clearAdScale(ph);
|
|
591
|
+
if (ph instanceof Element) { S.io?.unobserve(ph); unwatchPlaceholderFill(ph); clearAdScale(ph); clearUnusedShell(w, ph); }
|
|
558
592
|
const id = parseInt(w.getAttribute(A_WRAPID), 10);
|
|
559
593
|
if (Number.isFinite(id)) { S.mountedIds.delete(id); clearEmptyChecks(id); }
|
|
560
594
|
const key = w.getAttribute(A_ANCHOR);
|
|
561
595
|
if (key && S.wrapByKey.get(key) === w) S.wrapByKey.delete(key);
|
|
562
596
|
w.remove();
|
|
597
|
+
return true;
|
|
563
598
|
} catch (_) {}
|
|
599
|
+
return false;
|
|
564
600
|
}
|
|
565
601
|
|
|
566
602
|
// ── Prune (topics de catégorie uniquement) ────────────────────────────────
|
|
@@ -663,10 +699,9 @@
|
|
|
663
699
|
|
|
664
700
|
function observePh(id) {
|
|
665
701
|
const ph = document.getElementById(`${PH_PREFIX}${id}`);
|
|
666
|
-
if (ph?.isConnected)
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
}
|
|
702
|
+
if (!ph?.isConnected) return;
|
|
703
|
+
try { watchPlaceholderFill(ph); } catch (_) {}
|
|
704
|
+
try { getIO()?.observe(ph); } catch (_) {}
|
|
670
705
|
}
|
|
671
706
|
|
|
672
707
|
function enqueueShow(id) {
|
|
@@ -704,7 +739,7 @@
|
|
|
704
739
|
try {
|
|
705
740
|
if (isBlocked()) { clearTimeout(timer); return release(); }
|
|
706
741
|
const ph = document.getElementById(`${PH_PREFIX}${id}`);
|
|
707
|
-
if (!ph?.isConnected || isFilled(ph)) { try { if (ph
|
|
742
|
+
if (!ph?.isConnected || isFilled(ph)) { try { if (ph) uncollapseIfFilled(ph); } catch (_) {} clearTimeout(timer); return release(); }
|
|
708
743
|
|
|
709
744
|
const t = ts();
|
|
710
745
|
if (t - (S.lastShow.get(id) ?? 0) < SHOW_THROTTLE_MS) { clearTimeout(timer); return release(); }
|
|
@@ -713,12 +748,10 @@
|
|
|
713
748
|
try {
|
|
714
749
|
const wrap = ph.closest?.(`.${WRAP_CLASS}`);
|
|
715
750
|
wrap?.setAttribute(A_SHOWN, String(t));
|
|
716
|
-
wrap?.
|
|
717
|
-
wrap
|
|
718
|
-
|
|
719
|
-
ph.style.removeProperty('height');
|
|
751
|
+
wrap?.classList?.remove('is-empty');
|
|
752
|
+
clearUnusedShell(wrap, ph);
|
|
753
|
+
clearEmptyChecks(id);
|
|
720
754
|
} catch (_) {}
|
|
721
|
-
clearEmptyChecks(id);
|
|
722
755
|
|
|
723
756
|
window.ezstandalone = window.ezstandalone || {};
|
|
724
757
|
const ez = window.ezstandalone;
|
|
@@ -736,25 +769,37 @@
|
|
|
736
769
|
|
|
737
770
|
function scheduleEmptyCheck(id, showTs) {
|
|
738
771
|
clearEmptyChecks(id);
|
|
772
|
+
|
|
739
773
|
const runCheck = () => {
|
|
740
774
|
try {
|
|
741
775
|
const ph = document.getElementById(`${PH_PREFIX}${id}`);
|
|
742
776
|
const wrap = ph?.closest?.(`.${WRAP_CLASS}`);
|
|
743
777
|
if (!wrap || !ph?.isConnected) return;
|
|
744
778
|
if (parseInt(wrap.getAttribute(A_SHOWN) || '0', 10) > showTs) return;
|
|
745
|
-
|
|
779
|
+
|
|
780
|
+
if (isFilled(ph)) {
|
|
746
781
|
wrap.classList.remove('is-empty');
|
|
747
|
-
|
|
782
|
+
clearUnusedShell(wrap, ph);
|
|
783
|
+
markFilledOnce(ph);
|
|
784
|
+
rememberCurrentAdSize(ph);
|
|
785
|
+
fitWideAd(ph);
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
if (hasEverFilled(wrap) || shouldKeepShellAfterUnused(wrap)) {
|
|
790
|
+
applyUnusedShell(wrap, ph);
|
|
748
791
|
return;
|
|
749
792
|
}
|
|
750
|
-
|
|
751
|
-
|
|
793
|
+
|
|
794
|
+
clearUnusedShell(wrap, ph);
|
|
795
|
+
clearAdScale(ph);
|
|
796
|
+
wrap.classList.add('is-empty');
|
|
752
797
|
} catch (_) {}
|
|
753
798
|
};
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
799
|
+
|
|
800
|
+
queueEmptyCheck(id, setTimeout(runCheck, EMPTY_CHECK_MS));
|
|
801
|
+
queueEmptyCheck(id, setTimeout(runCheck, EMPTY_RECHECK_2_MS));
|
|
802
|
+
queueEmptyCheck(id, setTimeout(runCheck, EMPTY_RECHECK_3_MS));
|
|
758
803
|
}
|
|
759
804
|
|
|
760
805
|
// ── Patch Ezoic showAds ────────────────────────────────────────────────────
|
|
@@ -869,17 +914,6 @@
|
|
|
869
914
|
step();
|
|
870
915
|
}
|
|
871
916
|
|
|
872
|
-
let fitRaf = 0;
|
|
873
|
-
function scheduleRefitAll() {
|
|
874
|
-
if (fitRaf) return;
|
|
875
|
-
fitRaf = requestAnimationFrame(() => {
|
|
876
|
-
fitRaf = 0;
|
|
877
|
-
document.querySelectorAll(`[id^="${PH_PREFIX}"]`).forEach(ph => {
|
|
878
|
-
try { fitWideAd(ph); } catch (_) {}
|
|
879
|
-
});
|
|
880
|
-
});
|
|
881
|
-
}
|
|
882
|
-
|
|
883
917
|
// ── Cleanup navigation ─────────────────────────────────────────────────────
|
|
884
918
|
|
|
885
919
|
function cleanup() {
|
|
@@ -892,16 +926,13 @@
|
|
|
892
926
|
S.mountedIds.clear();
|
|
893
927
|
S.lastShow.clear();
|
|
894
928
|
S.wrapByKey.clear();
|
|
895
|
-
for (const
|
|
929
|
+
for (const timers of S.emptyChecks.values()) for (const t of timers) clearTimeout(t);
|
|
896
930
|
S.emptyChecks.clear();
|
|
897
|
-
for (const [, obs] of S.fillObs) { try { obs.disconnect(); } catch (_) {} }
|
|
898
|
-
S.fillObs.clear();
|
|
899
931
|
S.inflight = 0;
|
|
900
932
|
S.pending = [];
|
|
901
933
|
S.pendingSet.clear();
|
|
902
934
|
S.burstActive = false;
|
|
903
935
|
S.runQueued = false;
|
|
904
|
-
if (fitRaf) { try { cancelAnimationFrame(fitRaf); } catch (_) {} fitRaf = 0; }
|
|
905
936
|
}
|
|
906
937
|
|
|
907
938
|
// ── MutationObserver ───────────────────────────────────────────────────────
|
|
@@ -1028,6 +1059,10 @@
|
|
|
1028
1059
|
}, { passive: true });
|
|
1029
1060
|
}
|
|
1030
1061
|
|
|
1062
|
+
function bindResize() {
|
|
1063
|
+
window.addEventListener('resize', scheduleRefitAll, { passive: true });
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1031
1066
|
// ── Boot ───────────────────────────────────────────────────────────────────
|
|
1032
1067
|
|
|
1033
1068
|
S.pageKey = pageKey();
|
|
@@ -1039,7 +1074,7 @@
|
|
|
1039
1074
|
ensureDomObserver();
|
|
1040
1075
|
bindNodeBB();
|
|
1041
1076
|
bindScroll();
|
|
1042
|
-
|
|
1077
|
+
bindResize();
|
|
1043
1078
|
blockedUntil = 0;
|
|
1044
1079
|
requestBurst();
|
|
1045
1080
|
|
package/public/style.css
CHANGED
|
@@ -77,8 +77,7 @@
|
|
|
77
77
|
padding: 0 !important;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
/* Si le wrap contient une pub, ne jamais le laisser en mode vide */
|
|
80
|
+
/* ── Hardening async fill + responsive creatives ───────────────────────── */
|
|
82
81
|
.nodebb-ezoic-wrap.is-empty:has(iframe, ins, img, video, [data-google-container-id]) {
|
|
83
82
|
height: auto !important;
|
|
84
83
|
min-height: 1px !important;
|
|
@@ -86,7 +85,6 @@
|
|
|
86
85
|
overflow: visible !important;
|
|
87
86
|
}
|
|
88
87
|
|
|
89
|
-
/* ── Responsive hardening Ezoic ─────────────────────────────────────────── */
|
|
90
88
|
.nodebb-ezoic-wrap {
|
|
91
89
|
max-width: 100%;
|
|
92
90
|
overflow-x: clip;
|
|
@@ -113,7 +111,6 @@
|
|
|
113
111
|
}
|
|
114
112
|
|
|
115
113
|
.nodebb-ezoic-wrap iframe {
|
|
116
|
-
display: block !important;
|
|
117
114
|
margin-left: auto !important;
|
|
118
115
|
margin-right: auto !important;
|
|
119
116
|
max-width: none !important;
|
|
@@ -128,6 +125,11 @@
|
|
|
128
125
|
will-change: transform;
|
|
129
126
|
}
|
|
130
127
|
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
.nodebb-ezoic-wrap.is-unused-shell {
|
|
129
|
+
overflow: hidden !important;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.nodebb-ezoic-wrap.is-unused-shell > [id^="ezoic-pub-ad-placeholder-"] {
|
|
133
|
+
display: block;
|
|
134
|
+
width: 100%;
|
|
133
135
|
}
|