nodebb-plugin-ezoic-infinite 1.4.95 → 1.4.96
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 +172 -59
- package/public/style.css +7 -3
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -7,8 +7,12 @@
|
|
|
7
7
|
categoryItem: 'li[component="categories/category"]',
|
|
8
8
|
}, WRAP_CLASS = 'ezoic-ad';
|
|
9
9
|
const PLACEHOLDER_PREFIX = 'ezoic-pub-ad-placeholder-', MAX_INSERTS_PER_RUN = 3;
|
|
10
|
+
|
|
11
|
+
// FLAG GLOBAL: Bloquer Ezoic pendant navigation
|
|
12
|
+
let EZOIC_BLOCKED = false;
|
|
13
|
+
|
|
14
|
+
// DEBUG: Vérifier que le plugin charge
|
|
10
15
|
|
|
11
|
-
// Nécessaire pour savoir si on doit appeler destroyPlaceholders avant recyclage.
|
|
12
16
|
const sessionDefinedIds = new Set();
|
|
13
17
|
|
|
14
18
|
const insertingIds = new Set(), state = {
|
|
@@ -106,9 +110,7 @@
|
|
|
106
110
|
|
|
107
111
|
function destroyPlaceholderIds(ids) {
|
|
108
112
|
if (!ids || !ids.length) return;
|
|
109
|
-
// Only destroy ids that were actually "defined" (filled at least once) to avoid Ezoic warnings.
|
|
110
113
|
const filtered = ids.filter((id) => {
|
|
111
|
-
// Utiliser sessionDefinedIds (survit aux navigations) plutôt que state.definedIds
|
|
112
114
|
try { return sessionDefinedIds.has(id); } catch (e) { return true; }
|
|
113
115
|
});
|
|
114
116
|
if (!filtered.length) return;
|
|
@@ -119,6 +121,11 @@
|
|
|
119
121
|
window.ezstandalone.destroyPlaceholders(filtered);
|
|
120
122
|
}
|
|
121
123
|
} catch (e) {}
|
|
124
|
+
|
|
125
|
+
// Recyclage: libérer IDs après 100ms
|
|
126
|
+
setTimeout(() => {
|
|
127
|
+
filtered.forEach(id => sessionDefinedIds.delete(id));
|
|
128
|
+
}, 100);
|
|
122
129
|
};
|
|
123
130
|
try {
|
|
124
131
|
window.ezstandalone = window.ezstandalone || {};
|
|
@@ -126,10 +133,63 @@
|
|
|
126
133
|
if (window.ezstandalone && typeof window.ezstandalone.destroyPlaceholders === 'function') call();
|
|
127
134
|
else window.ezstandalone.cmd.push(call);
|
|
128
135
|
} catch (e) {}
|
|
136
|
+
|
|
137
|
+
// Recyclage: libérer IDs après 100ms
|
|
138
|
+
setTimeout(() => {
|
|
139
|
+
filtered.forEach(id => sessionDefinedIds.delete(id));
|
|
140
|
+
}, 100);
|
|
129
141
|
}
|
|
130
142
|
|
|
143
|
+
// Nettoyer éléments Ezoic invisibles qui créent espace vertical
|
|
144
|
+
function cleanupInvisibleEzoicElements() {
|
|
145
|
+
try {
|
|
146
|
+
document.querySelectorAll('.ezoic-ad').forEach(wrapper => {
|
|
147
|
+
const ph = wrapper.querySelector('[id^="ezoic-pub-ad-placeholder-"]');
|
|
148
|
+
if (!ph) return;
|
|
149
|
+
|
|
150
|
+
// ULTRA-AGRESSIF: Supprimer TOUT sauf placeholder
|
|
151
|
+
Array.from(wrapper.children).forEach(child => {
|
|
152
|
+
if (child === ph || child.contains(ph)) return;
|
|
153
|
+
if (child.id && child.id.startsWith('ezoic-pub-ad-placeholder-')) return;
|
|
154
|
+
child.remove();
|
|
155
|
+
});
|
|
131
156
|
|
|
132
|
-
//
|
|
157
|
+
// Forcer wrapper collé
|
|
158
|
+
wrapper.style.height = 'auto';
|
|
159
|
+
wrapper.style.overflow = 'hidden';
|
|
160
|
+
wrapper.style.lineHeight = '0';
|
|
161
|
+
wrapper.style.fontSize = '0';
|
|
162
|
+
wrapper.style.margin = '0';
|
|
163
|
+
wrapper.style.padding = '0';
|
|
164
|
+
|
|
165
|
+
// CRITIQUE: Forcer suppression margin sur TOUS les .ezoic-ad enfants
|
|
166
|
+
// Pour overrider les margin-top/bottom:15px !important d'Ezoic
|
|
167
|
+
wrapper.querySelectorAll('.ezoic-ad, span.ezoic-ad').forEach(ezSpan => {
|
|
168
|
+
ezSpan.style.setProperty('margin-top', '0', 'important');
|
|
169
|
+
ezSpan.style.setProperty('margin-bottom', '0', 'important');
|
|
170
|
+
ezSpan.style.setProperty('margin-left', '0', 'important');
|
|
171
|
+
ezSpan.style.setProperty('margin-right', '0', 'important');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Nettoyer aussi DANS le placeholder
|
|
175
|
+
if (ph) {
|
|
176
|
+
Array.from(ph.children).forEach(child => {
|
|
177
|
+
// Garder seulement iframe, ins, img
|
|
178
|
+
const tag = child.tagName;
|
|
179
|
+
if (tag !== 'IFRAME' && tag !== 'INS' && tag !== 'IMG' && tag !== 'DIV') {
|
|
180
|
+
child.remove();
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
} catch (e) {}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Lancer cleanup périodique toutes les 2s
|
|
189
|
+
setInterval(() => {
|
|
190
|
+
try { cleanupInvisibleEzoicElements(); } catch (e) {}
|
|
191
|
+
}, 2000);
|
|
192
|
+
|
|
133
193
|
function cleanupEmptyWrappers() {
|
|
134
194
|
try {
|
|
135
195
|
document.querySelectorAll('.ezoic-ad').forEach(wrapper => {
|
|
@@ -140,7 +200,7 @@
|
|
|
140
200
|
if (ph.children.length === 0) {
|
|
141
201
|
wrapper.remove();
|
|
142
202
|
}
|
|
143
|
-
},
|
|
203
|
+
}, 1500);
|
|
144
204
|
}
|
|
145
205
|
});
|
|
146
206
|
} catch (e) {}
|
|
@@ -217,10 +277,8 @@
|
|
|
217
277
|
if (findWrap(kindClass, afterPos)) return null;
|
|
218
278
|
|
|
219
279
|
// CRITICAL: Double-lock pour éviter race conditions sur les doublons
|
|
220
|
-
// 1. Vérifier qu'aucun autre thread n'est en train d'insérer cet ID
|
|
221
280
|
if (insertingIds.has(id)) return null;
|
|
222
281
|
|
|
223
|
-
// 2. Vérifier qu'aucun placeholder avec cet ID n'existe déjà dans le DOM
|
|
224
282
|
const existingPh = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
225
283
|
if (existingPh && existingPh.isConnected) return null;
|
|
226
284
|
|
|
@@ -233,7 +291,6 @@
|
|
|
233
291
|
attachFillObserver(wrap, id);
|
|
234
292
|
return wrap;
|
|
235
293
|
} finally {
|
|
236
|
-
// Libérer le lock après 100ms (le temps que le DOM soit stable)
|
|
237
294
|
setTimeout(() => insertingIds.delete(id), 50);
|
|
238
295
|
}
|
|
239
296
|
}
|
|
@@ -244,8 +301,6 @@
|
|
|
244
301
|
}
|
|
245
302
|
|
|
246
303
|
function patchShowAds() {
|
|
247
|
-
// Minimal safety net: batch showAds can be triggered by other scripts; split into individual calls.
|
|
248
|
-
// Also ensures the patch is applied even if Ezoic loads after our script.
|
|
249
304
|
const applyPatch = () => {
|
|
250
305
|
try {
|
|
251
306
|
window.ezstandalone = window.ezstandalone || {}, ez = window.ezstandalone;
|
|
@@ -256,23 +311,50 @@
|
|
|
256
311
|
const orig = ez.showAds;
|
|
257
312
|
|
|
258
313
|
ez.showAds = function (arg) {
|
|
314
|
+
// CRITIQUE: Bloquer TOUS appels si navigation en cours
|
|
315
|
+
if (EZOIC_BLOCKED) {
|
|
316
|
+
return; // Ignorer complètement
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Filtrer IDs dont placeholders n'existent pas
|
|
320
|
+
const filterValidIds = (ids) => {
|
|
321
|
+
return ids.filter(id => {
|
|
322
|
+
const phId = `ezoic-pub-ad-placeholder-${id}`;
|
|
323
|
+
const ph = document.getElementById(phId);
|
|
324
|
+
return ph && ph.isConnected;
|
|
325
|
+
});
|
|
326
|
+
};
|
|
327
|
+
|
|
259
328
|
if (Array.isArray(arg)) {
|
|
260
329
|
const seen = new Set();
|
|
261
330
|
for (const v of arg) {
|
|
262
331
|
const id = parseInt(v, 10);
|
|
263
332
|
if (!Number.isFinite(id) || id <= 0 || seen.has(id)) continue;
|
|
333
|
+
|
|
334
|
+
// Vérifier existence avant appel
|
|
335
|
+
const phId = `ezoic-pub-ad-placeholder-${id}`;
|
|
336
|
+
const ph = document.getElementById(phId);
|
|
337
|
+
if (!ph || !ph.isConnected) continue;
|
|
338
|
+
|
|
264
339
|
seen.add(id);
|
|
265
340
|
try { orig.call(ez, id); } catch (e) {}
|
|
266
341
|
}
|
|
267
342
|
return;
|
|
268
343
|
}
|
|
344
|
+
|
|
345
|
+
// Pour appels simples, vérifier aussi
|
|
346
|
+
if (typeof arg === 'number') {
|
|
347
|
+
const phId = `ezoic-pub-ad-placeholder-${arg}`;
|
|
348
|
+
const ph = document.getElementById(phId);
|
|
349
|
+
if (!ph || !ph.isConnected) return;
|
|
350
|
+
}
|
|
351
|
+
|
|
269
352
|
return orig.apply(ez, arguments);
|
|
270
353
|
};
|
|
271
354
|
} catch (e) {}
|
|
272
355
|
};
|
|
273
356
|
|
|
274
357
|
applyPatch();
|
|
275
|
-
// Si Ezoic n'est pas encore chargé, appliquer le patch via sa cmd queue
|
|
276
358
|
if (!window.__nodebbEzoicPatched) {
|
|
277
359
|
try {
|
|
278
360
|
window.ezstandalone = window.ezstandalone || {};
|
|
@@ -285,7 +367,6 @@
|
|
|
285
367
|
function markFilled(wrap) {
|
|
286
368
|
try {
|
|
287
369
|
if (!wrap) return;
|
|
288
|
-
// Disconnect the fill observer first (no need to remove+re-add the attribute)
|
|
289
370
|
if (wrap.__ezoicFillObs) { wrap.__ezoicFillObs.disconnect(); wrap.__ezoicFillObs = null; }
|
|
290
371
|
wrap.setAttribute('data-ezoic-filled', '1');
|
|
291
372
|
} catch (e) {}
|
|
@@ -301,19 +382,18 @@
|
|
|
301
382
|
if (!ph) return;
|
|
302
383
|
// Already filled?
|
|
303
384
|
if (ph.childNodes && ph.childNodes.length > 0) {
|
|
304
|
-
markFilled(wrap);
|
|
305
|
-
|
|
385
|
+
markFilled(wrap); // Afficher wrapper
|
|
386
|
+
sessionDefinedIds.add(id);
|
|
306
387
|
return;
|
|
307
388
|
}
|
|
308
389
|
const obs = new MutationObserver(() => {
|
|
309
390
|
if (ph.childNodes && ph.childNodes.length > 0) {
|
|
310
|
-
markFilled(wrap);
|
|
311
|
-
try {
|
|
391
|
+
markFilled(wrap); // CRITIQUE: Afficher wrapper maintenant
|
|
392
|
+
try { sessionDefinedIds.add(id); } catch (e) {}
|
|
312
393
|
try { obs.disconnect(); } catch (e) {}
|
|
313
394
|
}
|
|
314
395
|
});
|
|
315
396
|
obs.observe(ph, { childList: true, subtree: true });
|
|
316
|
-
// Keep a weak reference on the wrapper so we can disconnect on recycle/remove
|
|
317
397
|
wrap.__ezoicFillObs = obs;
|
|
318
398
|
} catch (e) {}
|
|
319
399
|
}
|
|
@@ -333,15 +413,12 @@
|
|
|
333
413
|
return filled;
|
|
334
414
|
}
|
|
335
415
|
|
|
336
|
-
// Appeler showAds() en batch selon recommandations Ezoic
|
|
337
|
-
// Au lieu de showAds(id1), showAds(id2)... faire showAds(id1, id2, id3...)
|
|
338
416
|
let batchShowAdsTimer = null;
|
|
339
417
|
const pendingShowAdsIds = new Set();
|
|
340
418
|
|
|
341
419
|
function scheduleShowAdsBatch(id) {
|
|
342
420
|
if (!id) return;
|
|
343
421
|
|
|
344
|
-
// CRITIQUE: Si cet ID a déjà été défini (sessionDefinedIds), le détruire d'abord
|
|
345
422
|
if (sessionDefinedIds.has(id)) {
|
|
346
423
|
try {
|
|
347
424
|
destroyPlaceholderIds([id]);
|
|
@@ -356,30 +433,52 @@
|
|
|
356
433
|
// Ajouter à la batch
|
|
357
434
|
pendingShowAdsIds.add(id);
|
|
358
435
|
|
|
359
|
-
// Debounce: attendre 100ms pour collecter tous les IDs
|
|
360
436
|
clearTimeout(batchShowAdsTimer);
|
|
361
437
|
batchShowAdsTimer = setTimeout(() => {
|
|
438
|
+
// CRITIQUE: Vérifier que nous sommes toujours sur la même page
|
|
439
|
+
const currentPageKey = getPageKey();
|
|
440
|
+
if (state.pageKey && currentPageKey !== state.pageKey) {
|
|
441
|
+
pendingShowAdsIds.clear();
|
|
442
|
+
return; // Page a changé, annuler
|
|
443
|
+
}
|
|
444
|
+
|
|
362
445
|
if (pendingShowAdsIds.size === 0) return;
|
|
363
446
|
|
|
364
447
|
const idsArray = Array.from(pendingShowAdsIds);
|
|
365
448
|
pendingShowAdsIds.clear();
|
|
366
449
|
|
|
450
|
+
// CRITIQUE: Vérifier que placeholders existent encore
|
|
451
|
+
const validIds = idsArray.filter(id => {
|
|
452
|
+
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
453
|
+
return ph && ph.isConnected;
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
if (validIds.length === 0) return;
|
|
457
|
+
|
|
367
458
|
// Appeler showAds avec TOUS les IDs en une fois
|
|
368
459
|
try {
|
|
460
|
+
// CRITIQUE: Re-patcher AVANT chaque appel pour être sûr
|
|
461
|
+
patchShowAds();
|
|
462
|
+
|
|
369
463
|
window.ezstandalone = window.ezstandalone || {};
|
|
370
464
|
window.ezstandalone.cmd = window.ezstandalone.cmd || [];
|
|
371
465
|
window.ezstandalone.cmd.push(function() {
|
|
372
466
|
if (typeof window.ezstandalone.showAds === 'function') {
|
|
373
467
|
// Appel batch: showAds(id1, id2, id3...)
|
|
374
|
-
window.ezstandalone.showAds(...
|
|
468
|
+
window.ezstandalone.showAds(...validIds);
|
|
375
469
|
// Tracker tous les IDs
|
|
376
|
-
|
|
470
|
+
validIds.forEach(id => {
|
|
377
471
|
state.lastShowById.set(id, Date.now());
|
|
378
472
|
sessionDefinedIds.add(id);
|
|
379
473
|
});
|
|
380
474
|
}
|
|
381
475
|
});
|
|
382
476
|
} catch (e) {}
|
|
477
|
+
|
|
478
|
+
// CRITIQUE: Nettoyer éléments invisibles APRÈS que pubs soient chargées
|
|
479
|
+
setTimeout(() => {
|
|
480
|
+
cleanupInvisibleEzoicElements();
|
|
481
|
+
}, 1500); // 1.5s pour laisser Ezoic charger
|
|
383
482
|
}, 100);
|
|
384
483
|
}
|
|
385
484
|
|
|
@@ -406,19 +505,15 @@
|
|
|
406
505
|
const startPageKey = state.pageKey;
|
|
407
506
|
let attempts = 0;
|
|
408
507
|
(function waitForPh() {
|
|
409
|
-
// Abort if the user navigated away since this showAds was scheduled
|
|
410
508
|
if (state.pageKey !== startPageKey) return;
|
|
411
|
-
// Abort if another concurrent call is already handling this id
|
|
412
509
|
if (state.pendingById.has(id)) return;
|
|
413
510
|
|
|
414
511
|
attempts += 1;
|
|
415
512
|
const el = document.getElementById(phId);
|
|
416
513
|
if (el && el.isConnected) {
|
|
417
|
-
// CRITIQUE: Vérifier que le placeholder est VISIBLE
|
|
418
514
|
|
|
419
515
|
// Si on arrive ici, soit visible, soit timeout
|
|
420
516
|
|
|
421
|
-
// Si doCall() réussit, Ezoic est chargé et showAds a été appelé → sortir
|
|
422
517
|
if (doCall()) {
|
|
423
518
|
state.pendingById.delete(id);
|
|
424
519
|
return;
|
|
@@ -484,7 +579,6 @@
|
|
|
484
579
|
const el = items[afterPos - 1];
|
|
485
580
|
if (!el || !el.isConnected) continue;
|
|
486
581
|
|
|
487
|
-
// Prevent adjacent ads (DOM-based, robust against virtualization)
|
|
488
582
|
if (isAdjacentAd(el) || isPrevAd(el)) {
|
|
489
583
|
continue;
|
|
490
584
|
}
|
|
@@ -501,17 +595,14 @@
|
|
|
501
595
|
|
|
502
596
|
let wrap = null;
|
|
503
597
|
if (pick.recycled && pick.recycled.wrap) {
|
|
504
|
-
// Only destroy if Ezoic has actually defined this placeholder before
|
|
505
598
|
if (sessionDefinedIds.has(id)) {
|
|
506
599
|
destroyPlaceholderIds([id]);
|
|
507
600
|
}
|
|
508
|
-
// Remove the old wrapper entirely, then create a fresh wrapper at the new position (same id)
|
|
509
601
|
const oldWrap = pick.recycled.wrap;
|
|
510
602
|
try { if (oldWrap && oldWrap.__ezoicFillObs) { oldWrap.__ezoicFillObs.disconnect(); } } catch (e) {}
|
|
511
603
|
try { oldWrap && oldWrap.remove(); } catch (e) {}
|
|
512
604
|
wrap = insertAfter(el, id, kindClass, afterPos);
|
|
513
605
|
if (!wrap) continue;
|
|
514
|
-
// Attendre que le wrapper soit dans le DOM puis appeler showAds
|
|
515
606
|
setTimeout(() => {
|
|
516
607
|
callShowAdsWhenReady(id);
|
|
517
608
|
}, 50);
|
|
@@ -525,12 +616,10 @@
|
|
|
525
616
|
}
|
|
526
617
|
|
|
527
618
|
liveArr.push({ id, wrap });
|
|
528
|
-
// If adjacency ended up happening (e.g. DOM shifts), rollback this placement.
|
|
529
619
|
if (wrap && (
|
|
530
620
|
(wrap.previousElementSibling && wrap.previousElementSibling.classList && wrap.previousElementSibling.classList.contains(WRAP_CLASS)) || (wrap.nextElementSibling && wrap.nextElementSibling.classList && wrap.nextElementSibling.classList.contains(WRAP_CLASS))
|
|
531
621
|
)) {
|
|
532
622
|
try { wrap.remove(); } catch (e) {}
|
|
533
|
-
// Put id back if it was newly consumed (not recycled)
|
|
534
623
|
if (!(pick.recycled && pick.recycled.wrap)) {
|
|
535
624
|
try { kindPool.unshift(id); } catch (e) {}
|
|
536
625
|
usedSet.delete(id);
|
|
@@ -547,7 +636,6 @@
|
|
|
547
636
|
for (let i = 0; i < ads.length; i++) {
|
|
548
637
|
const ad = ads[i], prev = ad.previousElementSibling;
|
|
549
638
|
if (prev && prev.classList && prev.classList.contains(WRAP_CLASS)) {
|
|
550
|
-
// Supprimer le wrapper adjacent au lieu de le cacher
|
|
551
639
|
try {
|
|
552
640
|
const ph = ad.querySelector && ad.querySelector(`[id^="${PLACEHOLDER_PREFIX}"]`);
|
|
553
641
|
if (ph) {
|
|
@@ -566,11 +654,45 @@
|
|
|
566
654
|
}
|
|
567
655
|
|
|
568
656
|
function cleanup() {
|
|
569
|
-
|
|
657
|
+
// DEBUG: Vérifier que cleanup est appelé
|
|
658
|
+
// CRITIQUE: BLOQUER Ezoic immédiatement
|
|
659
|
+
EZOIC_BLOCKED = true;
|
|
660
|
+
|
|
661
|
+
// Détruire TOUS les placeholders Ezoic AVANT de supprimer DOM
|
|
662
|
+
const allWrappers = document.querySelectorAll('.ezoic-ad');
|
|
663
|
+
const allIds = [];
|
|
664
|
+
allWrappers.forEach(wrapper => {
|
|
665
|
+
const ph = wrapper.querySelector('[id^="ezoic-pub-ad-placeholder-"]');
|
|
666
|
+
if (ph) {
|
|
667
|
+
const match = ph.id.match(/\d+/);
|
|
668
|
+
if (match) allIds.push(parseInt(match[0]));
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
// CRITIQUE: Vider COMPLÈTEMENT sessionDefinedIds
|
|
673
|
+
// Pour éviter que d'anciens IDs soient encore en mémoire
|
|
674
|
+
|
|
675
|
+
// CRITIQUE: Détruire AUSSI tous les IDs tracés dans state
|
|
676
|
+
// Pour annuler les anciens IDs qu'Ezoic a en mémoire
|
|
677
|
+
const trackedIds = [
|
|
678
|
+
...Array.from(state.usedTopics),
|
|
679
|
+
...Array.from(state.usedPosts),
|
|
680
|
+
...Array.from(state.usedCategories)
|
|
681
|
+
];
|
|
682
|
+
|
|
683
|
+
const allIdsToDestroy = [...new Set([...allIds, ...trackedIds, ...Array.from(sessionDefinedIds)])];
|
|
684
|
+
sessionDefinedIds.clear(); // ✅ VIDER TOUT
|
|
685
|
+
|
|
686
|
+
if (allIdsToDestroy.length > 0) {
|
|
687
|
+
destroyPlaceholderIds(allIdsToDestroy);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Annuler batch showAds en attente
|
|
691
|
+
pendingShowAdsIds.clear();
|
|
692
|
+
clearTimeout(batchShowAdsTimer);
|
|
570
693
|
|
|
571
|
-
//
|
|
572
|
-
|
|
573
|
-
document.querySelectorAll('.ezoic-ad').forEach(el => {
|
|
694
|
+
// Maintenant supprimer DOM
|
|
695
|
+
allWrappers.forEach(el => {
|
|
574
696
|
try { el.remove(); } catch (e) {}
|
|
575
697
|
});
|
|
576
698
|
|
|
@@ -585,23 +707,14 @@
|
|
|
585
707
|
state.usedPosts.clear();
|
|
586
708
|
state.usedCategories.clear();
|
|
587
709
|
state.lastShowById.clear();
|
|
588
|
-
// CRITIQUE: Vider pendingById pour annuler tous les showAds en cours
|
|
589
|
-
// Sinon Ezoic essaie d'accéder aux placeholders pendant que NodeBB vide le DOM
|
|
590
710
|
state.pendingById.clear();
|
|
591
711
|
state.definedIds.clear();
|
|
592
712
|
|
|
593
|
-
// NE PAS supprimer les wrappers Ezoic ici - ils seront supprimés naturellement
|
|
594
|
-
// quand NodeBB vide le DOM lors de la navigation ajaxify
|
|
595
|
-
// Les supprimer manuellement cause des problèmes avec l'état interne d'Ezoic
|
|
596
|
-
|
|
597
|
-
// CRITIQUE: Annuler TOUS les timeouts en cours pour éviter que les anciens
|
|
598
|
-
// showAds() continuent à s'exécuter après la navigation
|
|
599
713
|
state.activeTimeouts.forEach(id => {
|
|
600
714
|
try { clearTimeout(id); } catch (e) {}
|
|
601
715
|
});
|
|
602
716
|
state.activeTimeouts.clear();
|
|
603
717
|
|
|
604
|
-
// Vider aussi pendingById pour annuler les showAds en attente
|
|
605
718
|
state.pendingById.clear();
|
|
606
719
|
|
|
607
720
|
if (state.obs) { state.obs.disconnect(); state.obs = null; }
|
|
@@ -618,7 +731,11 @@
|
|
|
618
731
|
}
|
|
619
732
|
|
|
620
733
|
async function runCore() {
|
|
621
|
-
//
|
|
734
|
+
// CRITIQUE: Ne rien insérer si navigation en cours
|
|
735
|
+
if (EZOIC_BLOCKED) {
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
|
|
622
739
|
if (!state.canShowAds) {
|
|
623
740
|
return;
|
|
624
741
|
}
|
|
@@ -661,7 +778,6 @@
|
|
|
661
778
|
|
|
662
779
|
enforceNoAdjacentAds();
|
|
663
780
|
|
|
664
|
-
// If nothing inserted and list isn't in DOM yet (first click), retry a bit
|
|
665
781
|
let count = 0;
|
|
666
782
|
if (kind === 'topic') count = getPostContainers().length;
|
|
667
783
|
else if (kind === 'categoryTopics') count = getTopicItems().length;
|
|
@@ -673,12 +789,9 @@
|
|
|
673
789
|
}
|
|
674
790
|
|
|
675
791
|
if (inserted >= MAX_INSERTS_PER_RUN) {
|
|
676
|
-
// Plus d'insertions possibles ce cycle, continuer immédiatement
|
|
677
792
|
setTimeout(arguments[0], 50);
|
|
678
793
|
} else if (inserted === 0 && count > 0) {
|
|
679
794
|
// Pool épuisé ou recyclage pas encore disponible.
|
|
680
|
-
// Réessayer jusqu'à 8 fois (toutes les 400ms) pour laisser aux anciens wrappers
|
|
681
|
-
// le temps de défiler hors écran et devenir recyclables.
|
|
682
795
|
if (state.poolWaitAttempts < 8) {
|
|
683
796
|
state.poolWaitAttempts += 1;
|
|
684
797
|
setTimeout(arguments[0], 50);
|
|
@@ -710,17 +823,20 @@
|
|
|
710
823
|
|
|
711
824
|
$(window).on('action:ajaxify.end.ezoicInfinite', () => {
|
|
712
825
|
state.pageKey = getPageKey();
|
|
826
|
+
|
|
827
|
+
// Débloquer Ezoic IMMÉDIATEMENT pour la nouvelle page
|
|
828
|
+
EZOIC_BLOCKED = false;
|
|
829
|
+
|
|
713
830
|
ensureObserver();
|
|
714
831
|
|
|
715
|
-
// CRITIQUE: Attendre 300ms avant de permettre l'insertion de nouveaux placeholders
|
|
716
|
-
// pour laisser les anciens showAds() (en cours) se terminer ou échouer proprement
|
|
717
|
-
// Sinon race condition: NodeBB vide le DOM pendant que Ezoic essaie d'accéder aux placeholders
|
|
718
832
|
state.canShowAds = true;
|
|
833
|
+
|
|
834
|
+
// CRITIQUE: Relancer insertion maintenant que navigation est terminée
|
|
835
|
+
scheduleRun();
|
|
719
836
|
});
|
|
720
837
|
|
|
721
838
|
$(window).on('action:category.loaded.ezoicInfinite', () => {
|
|
722
839
|
ensureObserver();
|
|
723
|
-
// category.loaded = infinite scroll, Ezoic déjà chargé normalement
|
|
724
840
|
waitForContentThenRun();
|
|
725
841
|
});
|
|
726
842
|
$(window).on('action:topics.loaded.ezoicInfinite', () => {
|
|
@@ -750,7 +866,6 @@
|
|
|
750
866
|
window.requestAnimationFrame(() => {
|
|
751
867
|
ticking = false;
|
|
752
868
|
enforceNoAdjacentAds();
|
|
753
|
-
// Debounce scheduleRun - une fois toutes les 2 secondes max au scroll
|
|
754
869
|
const now = Date.now();
|
|
755
870
|
if (!state.lastScrollRun || now - state.lastScrollRun > 2000) {
|
|
756
871
|
state.lastScrollRun = now;
|
|
@@ -760,7 +875,6 @@
|
|
|
760
875
|
}, { passive: true });
|
|
761
876
|
}
|
|
762
877
|
|
|
763
|
-
// Fonction qui attend que la page ait assez de contenu avant d'insérer les pubs
|
|
764
878
|
function waitForContentThenRun() {
|
|
765
879
|
const MIN_WORDS = 250;
|
|
766
880
|
let attempts = 0;
|
|
@@ -791,7 +905,6 @@
|
|
|
791
905
|
})();
|
|
792
906
|
}
|
|
793
907
|
|
|
794
|
-
// Fonction qui attend que Ezoic soit vraiment chargé
|
|
795
908
|
function waitForEzoicThenRun() {
|
|
796
909
|
let attempts = 0;
|
|
797
910
|
const maxAttempts = 50; // 50 × 200ms = 10s max
|
package/public/style.css
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
.ezoic-ad
|
|
2
|
-
.ezoic-ad
|
|
3
|
-
.ezoic-ad
|
|
1
|
+
.ezoic-ad,
|
|
2
|
+
.ezoic-ad *,
|
|
3
|
+
span.ezoic-ad,
|
|
4
|
+
span[class*="ezoic"] {
|
|
5
|
+
min-height: 0 !important;
|
|
6
|
+
min-width: 0 !important;
|
|
7
|
+
}
|