nodebb-plugin-ezoic-infinite 1.4.7 → 1.4.9
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/library.js +21 -5
- package/package.json +1 -1
- package/plugin.json +4 -0
- package/public/admin.js +2 -3
- package/public/client.js +129 -83
package/library.js
CHANGED
|
@@ -27,13 +27,21 @@ async function getAllGroups() {
|
|
|
27
27
|
}
|
|
28
28
|
const filtered = names.filter(name => !groups.isPrivilegeGroup(name));
|
|
29
29
|
const data = await groups.getGroupsData(filtered);
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
// Filter out nulls (groups deleted between the sorted-set read and getGroupsData)
|
|
31
|
+
const valid = data.filter(g => g && g.name);
|
|
32
|
+
valid.sort((a, b) => String(a.name).localeCompare(String(b.name), undefined, { sensitivity: 'base' }));
|
|
33
|
+
return valid;
|
|
33
34
|
}
|
|
35
|
+
let _settingsCache = null;
|
|
36
|
+
let _settingsCacheAt = 0;
|
|
37
|
+
const SETTINGS_TTL = 30000; // 30s
|
|
38
|
+
|
|
34
39
|
async function getSettings() {
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
if (_settingsCache && (now - _settingsCacheAt) < SETTINGS_TTL) return _settingsCache;
|
|
35
42
|
const s = await meta.settings.get(SETTINGS_KEY);
|
|
36
|
-
|
|
43
|
+
_settingsCacheAt = Date.now();
|
|
44
|
+
_settingsCache = {
|
|
37
45
|
// Between-post ads (simple blocks) in category topic list
|
|
38
46
|
enableBetweenAds: parseBool(s.enableBetweenAds, true),
|
|
39
47
|
showFirstTopicAd: parseBool(s.showFirstTopicAd, false),
|
|
@@ -54,6 +62,7 @@ async function getSettings() {
|
|
|
54
62
|
|
|
55
63
|
excludedGroups: normalizeExcludedGroups(s.excludedGroups),
|
|
56
64
|
};
|
|
65
|
+
return _settingsCache;
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
async function isUserExcluded(uid, excludedGroups) {
|
|
@@ -62,6 +71,13 @@ async function isUserExcluded(uid, excludedGroups) {
|
|
|
62
71
|
return (userGroups[0] || []).some(g => excludedGroups.includes(g.name));
|
|
63
72
|
}
|
|
64
73
|
|
|
74
|
+
plugin.onSettingsSet = function (data) {
|
|
75
|
+
// Invalider le cache dès que les settings de ce plugin sont sauvegardés via l'ACP
|
|
76
|
+
if (data && data.hash === SETTINGS_KEY) {
|
|
77
|
+
_settingsCache = null;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
65
81
|
plugin.addAdminNavigation = async (header) => {
|
|
66
82
|
header.plugins = header.plugins || [];
|
|
67
83
|
header.plugins.push({
|
|
@@ -89,7 +105,7 @@ plugin.init = async ({ router, middleware }) => {
|
|
|
89
105
|
router.get('/admin/plugins/ezoic-infinite', middleware.admin.buildHeader, render);
|
|
90
106
|
router.get('/api/admin/plugins/ezoic-infinite', render);
|
|
91
107
|
|
|
92
|
-
router.get('/api/plugins/ezoic-infinite/config', middleware.
|
|
108
|
+
router.get('/api/plugins/ezoic-infinite/config', middleware.authenticate, async (req, res) => {
|
|
93
109
|
const settings = await getSettings();
|
|
94
110
|
const excluded = await isUserExcluded(req.uid, settings.excludedGroups);
|
|
95
111
|
|
package/package.json
CHANGED
package/plugin.json
CHANGED
package/public/admin.js
CHANGED
|
@@ -13,11 +13,10 @@
|
|
|
13
13
|
e.preventDefault();
|
|
14
14
|
|
|
15
15
|
Settings.save('ezoic-infinite', $form, function () {
|
|
16
|
-
// Toast vert (NodeBB core)
|
|
17
16
|
if (alerts && typeof alerts.success === 'function') {
|
|
18
|
-
alerts.success('
|
|
17
|
+
alerts.success('[[admin/settings:saved]]');
|
|
19
18
|
} else if (window.app && typeof window.app.alertSuccess === 'function') {
|
|
20
|
-
window.app.alertSuccess('
|
|
19
|
+
window.app.alertSuccess('[[admin/settings:saved]]');
|
|
21
20
|
}
|
|
22
21
|
});
|
|
23
22
|
});
|
package/public/client.js
CHANGED
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
liveBetween: [],
|
|
32
32
|
liveMessage: [],
|
|
33
33
|
liveCategory: [],
|
|
34
|
-
usedCategories: new Set(),
|
|
35
34
|
|
|
36
35
|
lastShowById: new Map(),
|
|
37
36
|
pendingById: new Set(),
|
|
@@ -48,6 +47,8 @@
|
|
|
48
47
|
|
|
49
48
|
obs: null,
|
|
50
49
|
attempts: 0,
|
|
50
|
+
poolWaitAttempts: 0,
|
|
51
|
+
__scrollBound: false,
|
|
51
52
|
};
|
|
52
53
|
|
|
53
54
|
function normalizeBool(v) {
|
|
@@ -143,18 +144,9 @@
|
|
|
143
144
|
else window.ezstandalone.cmd.push(call);
|
|
144
145
|
} catch (e) {}
|
|
145
146
|
}
|
|
146
|
-
} catch (e) {}
|
|
147
|
-
};
|
|
148
|
-
try {
|
|
149
|
-
window.ezstandalone = window.ezstandalone || {};
|
|
150
|
-
window.ezstandalone.cmd = window.ezstandalone.cmd || [];
|
|
151
|
-
if (window.ezstandalone && typeof window.ezstandalone.destroyPlaceholders === 'function') call();
|
|
152
|
-
else window.ezstandalone.cmd.push(call);
|
|
153
|
-
} catch (e) {}
|
|
154
|
-
}
|
|
155
147
|
|
|
156
148
|
function getRecyclable(liveArr) {
|
|
157
|
-
const margin =
|
|
149
|
+
const margin = 600;
|
|
158
150
|
for (let i = 0; i < liveArr.length; i++) {
|
|
159
151
|
const entry = liveArr[i];
|
|
160
152
|
if (!entry || !entry.wrap || !entry.wrap.isConnected) { liveArr.splice(i, 1); i--; continue; }
|
|
@@ -167,17 +159,6 @@
|
|
|
167
159
|
return null;
|
|
168
160
|
}
|
|
169
161
|
|
|
170
|
-
function moveWrapAfter(wrap, target, kindClass, afterPos) {
|
|
171
|
-
try {
|
|
172
|
-
wrap.className = `${WRAP_CLASS} ${kindClass}`;
|
|
173
|
-
wrap.setAttribute('data-ezoic-after', String(afterPos));
|
|
174
|
-
target.insertAdjacentElement('afterend', wrap);
|
|
175
|
-
return true;
|
|
176
|
-
} catch (e) {
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
162
|
function pickId(pool, liveArr) {
|
|
182
163
|
if (pool.length) return { id: pool.shift(), recycled: null };
|
|
183
164
|
const recycled = getRecyclable(liveArr);
|
|
@@ -189,6 +170,8 @@
|
|
|
189
170
|
function resetPlaceholderInWrap(wrap, id) {
|
|
190
171
|
try {
|
|
191
172
|
if (!wrap) return;
|
|
173
|
+
try { wrap.removeAttribute('data-ezoic-filled'); } catch (e) {}
|
|
174
|
+
try { if (wrap.__ezoicFillObs) { wrap.__ezoicFillObs.disconnect(); wrap.__ezoicFillObs = null; } } catch (e) {}
|
|
192
175
|
const old = wrap.querySelector && wrap.querySelector(`#${PLACEHOLDER_PREFIX}${id}`);
|
|
193
176
|
if (old) old.remove();
|
|
194
177
|
// Remove any leftover markup inside wrapper
|
|
@@ -234,6 +217,7 @@
|
|
|
234
217
|
if (findWrap(kindClass, afterPos)) return null;
|
|
235
218
|
const wrap = buildWrap(id, kindClass, afterPos);
|
|
236
219
|
target.insertAdjacentElement('afterend', wrap);
|
|
220
|
+
attachFillObserver(wrap, id);
|
|
237
221
|
return wrap;
|
|
238
222
|
}
|
|
239
223
|
|
|
@@ -242,30 +226,20 @@
|
|
|
242
226
|
try {
|
|
243
227
|
state.usedTopics.forEach((id) => ids.push(id));
|
|
244
228
|
state.usedPosts.forEach((id) => ids.push(id));
|
|
245
|
-
state.usedCategories
|
|
229
|
+
state.usedCategories.forEach((id) => ids.push(id));
|
|
246
230
|
} catch (e) {}
|
|
247
231
|
destroyPlaceholderIds(ids);
|
|
248
232
|
}
|
|
249
|
-
} catch (e) {}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
try {
|
|
253
|
-
window.ezstandalone = window.ezstandalone || {};
|
|
254
|
-
window.ezstandalone.cmd = window.ezstandalone.cmd || [];
|
|
255
|
-
if (window.ezstandalone && typeof window.ezstandalone.destroyPlaceholders === 'function') call();
|
|
256
|
-
else window.ezstandalone.cmd.push(call);
|
|
257
|
-
} catch (e) {}
|
|
258
|
-
}
|
|
259
233
|
|
|
260
234
|
function patchShowAds() {
|
|
261
235
|
// Minimal safety net: batch showAds can be triggered by other scripts; split into individual calls.
|
|
262
236
|
try {
|
|
263
237
|
window.ezstandalone = window.ezstandalone || {};
|
|
264
238
|
const ez = window.ezstandalone;
|
|
265
|
-
if (
|
|
239
|
+
if (window.__nodebbEzoicPatched) return;
|
|
266
240
|
if (typeof ez.showAds !== 'function') return;
|
|
267
241
|
|
|
268
|
-
|
|
242
|
+
window.__nodebbEzoicPatched = true;
|
|
269
243
|
const orig = ez.showAds;
|
|
270
244
|
|
|
271
245
|
ez.showAds = function (arg) {
|
|
@@ -285,14 +259,54 @@
|
|
|
285
259
|
}
|
|
286
260
|
|
|
287
261
|
|
|
262
|
+
|
|
263
|
+
function markFilled(wrap) {
|
|
264
|
+
try {
|
|
265
|
+
if (!wrap) return;
|
|
266
|
+
// Disconnect the fill observer first (no need to remove+re-add the attribute)
|
|
267
|
+
try { if (wrap.__ezoicFillObs) { wrap.__ezoicFillObs.disconnect(); wrap.__ezoicFillObs = null; } } catch (e) {}
|
|
268
|
+
wrap.setAttribute('data-ezoic-filled', '1');
|
|
269
|
+
} catch (e) {}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function isWrapMarkedFilled(wrap) {
|
|
273
|
+
try { return wrap && wrap.getAttribute && wrap.getAttribute('data-ezoic-filled') === '1'; } catch (e) { return false; }
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function attachFillObserver(wrap, id) {
|
|
277
|
+
try {
|
|
278
|
+
const ph = wrap && wrap.querySelector && wrap.querySelector(`#${PLACEHOLDER_PREFIX}${id}`);
|
|
279
|
+
if (!ph) return;
|
|
280
|
+
// Already filled?
|
|
281
|
+
if (ph.childNodes && ph.childNodes.length > 0) {
|
|
282
|
+
markFilled(wrap);
|
|
283
|
+
state.definedIds && state.definedIds.add(id);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const obs = new MutationObserver(() => {
|
|
287
|
+
if (ph.childNodes && ph.childNodes.length > 0) {
|
|
288
|
+
markFilled(wrap);
|
|
289
|
+
try { state.definedIds && state.definedIds.add(id); } catch (e) {}
|
|
290
|
+
try { obs.disconnect(); } catch (e) {}
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
obs.observe(ph, { childList: true, subtree: true });
|
|
294
|
+
// Keep a weak reference on the wrapper so we can disconnect on recycle/remove
|
|
295
|
+
wrap.__ezoicFillObs = obs;
|
|
296
|
+
} catch (e) {}
|
|
297
|
+
}
|
|
298
|
+
|
|
288
299
|
function isPlaceholderFilled(id) {
|
|
289
300
|
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
290
301
|
if (!ph || !ph.isConnected) return false;
|
|
291
302
|
|
|
292
|
-
|
|
303
|
+
const wrap = ph.parentElement;
|
|
304
|
+
if (wrap && isWrapMarkedFilled(wrap)) return true;
|
|
305
|
+
|
|
293
306
|
const filled = !!(ph.childNodes && ph.childNodes.length > 0);
|
|
294
307
|
if (filled) {
|
|
295
308
|
try { state.definedIds && state.definedIds.add(id); } catch (e) {}
|
|
309
|
+
try { markFilled(wrap); } catch (e) {}
|
|
296
310
|
}
|
|
297
311
|
return filled;
|
|
298
312
|
}
|
|
@@ -319,24 +333,19 @@
|
|
|
319
333
|
const id = state.retryQueue.shift();
|
|
320
334
|
if (!id) {
|
|
321
335
|
state.retryQueueRunning = false;
|
|
322
|
-
state.badIds = new Set();
|
|
323
|
-
state.definedIds = new Set();
|
|
324
336
|
return;
|
|
325
337
|
}
|
|
326
338
|
state.retryQueueSet.delete(id);
|
|
327
|
-
// If this id was previously attempted and still empty, force a full reset before re-requesting.
|
|
328
339
|
const attempts = (state.retryById.get(id) || 0);
|
|
329
340
|
const phNow = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
330
341
|
const wrapNow = phNow && phNow.parentElement;
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}
|
|
336
|
-
// If this id was previously attempted and still empty, force a full reset before re-requesting.
|
|
337
|
-
if (attempts > 0 && wrapNow && wrapNow.isConnected && !isPlaceholderFilled(id)) {
|
|
342
|
+
// Reset before re-requesting if Ezoic already defined this id but placeholder is now empty,
|
|
343
|
+
// OR if a previous attempt already failed.
|
|
344
|
+
if (wrapNow && wrapNow.isConnected && !isPlaceholderFilled(id) && !isWrapMarkedFilled(wrapNow) &&
|
|
345
|
+
(state.definedIds.has(id) || attempts > 0)) {
|
|
338
346
|
destroyPlaceholderIds([id]);
|
|
339
347
|
resetPlaceholderInWrap(wrapNow, id);
|
|
348
|
+
attachFillObserver(wrapNow, id);
|
|
340
349
|
}
|
|
341
350
|
callShowAdsWhenReady(id);
|
|
342
351
|
setTimeout(step, 1100);
|
|
@@ -360,6 +369,11 @@
|
|
|
360
369
|
state.retryById.delete(id);
|
|
361
370
|
continue;
|
|
362
371
|
}
|
|
372
|
+
// If wrapper was marked filled, don't try to refill even if placeholder temporarily appears empty.
|
|
373
|
+
if (isWrapMarkedFilled(wrap)) {
|
|
374
|
+
state.retryById.delete(id);
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
363
377
|
|
|
364
378
|
const tries = (state.retryById.get(id) || 0);
|
|
365
379
|
if (tries >= 8) { state.badIds && state.badIds.add(id); continue; }
|
|
@@ -396,8 +410,11 @@
|
|
|
396
410
|
return false;
|
|
397
411
|
};
|
|
398
412
|
|
|
413
|
+
const startPageKey = state.pageKey;
|
|
399
414
|
let attempts = 0;
|
|
400
415
|
(function waitForPh() {
|
|
416
|
+
// Abort if the user navigated away since this showAds was scheduled
|
|
417
|
+
if (state.pageKey !== startPageKey) return;
|
|
401
418
|
attempts += 1;
|
|
402
419
|
const el = document.getElementById(phId);
|
|
403
420
|
if (el && el.isConnected) {
|
|
@@ -420,6 +437,7 @@
|
|
|
420
437
|
|
|
421
438
|
let tries = 0;
|
|
422
439
|
(function tick() {
|
|
440
|
+
if (state.pageKey !== startPageKey) { state.pendingById.delete(id); return; }
|
|
423
441
|
tries += 1;
|
|
424
442
|
if (doCall() || tries >= 5) {
|
|
425
443
|
if (tries >= 5) state.pendingById.delete(id);
|
|
@@ -434,30 +452,28 @@
|
|
|
434
452
|
})();
|
|
435
453
|
}
|
|
436
454
|
|
|
437
|
-
function nextId(pool) {
|
|
438
|
-
// backward compatible: the injector passes the pool array
|
|
439
|
-
if (Array.isArray(pool) && pool.length) return pool.shift();
|
|
440
|
-
return null;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
455
|
async function fetchConfig() {
|
|
444
456
|
if (state.cfg) return state.cfg;
|
|
445
457
|
if (state.cfgPromise) return state.cfgPromise;
|
|
446
458
|
|
|
447
459
|
state.cfgPromise = (async () => {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
460
|
+
const MAX_TRIES = 3;
|
|
461
|
+
let delay = 800;
|
|
462
|
+
for (let attempt = 1; attempt <= MAX_TRIES; attempt++) {
|
|
463
|
+
try {
|
|
464
|
+
const res = await fetch('/api/plugins/ezoic-infinite/config', { credentials: 'same-origin' });
|
|
465
|
+
if (res.ok) {
|
|
466
|
+
state.cfg = await res.json();
|
|
467
|
+
return state.cfg;
|
|
468
|
+
}
|
|
469
|
+
} catch (e) {}
|
|
470
|
+
if (attempt < MAX_TRIES) await new Promise(r => setTimeout(r, delay));
|
|
471
|
+
delay *= 2;
|
|
457
472
|
}
|
|
473
|
+
return null;
|
|
458
474
|
})();
|
|
459
475
|
|
|
460
|
-
return state.cfgPromise;
|
|
476
|
+
try { return await state.cfgPromise; } finally { state.cfgPromise = null; }
|
|
461
477
|
}
|
|
462
478
|
|
|
463
479
|
function initPools(cfg) {
|
|
@@ -512,9 +528,12 @@
|
|
|
512
528
|
if (state.definedIds && state.definedIds.has(id)) {
|
|
513
529
|
destroyPlaceholderIds([id]);
|
|
514
530
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
531
|
+
// Remove the old wrapper entirely, then create a fresh wrapper at the new position (same id)
|
|
532
|
+
const oldWrap = pick.recycled.wrap;
|
|
533
|
+
try { if (oldWrap && oldWrap.__ezoicFillObs) { oldWrap.__ezoicFillObs.disconnect(); } } catch (e) {}
|
|
534
|
+
try { oldWrap && oldWrap.remove(); } catch (e) {}
|
|
535
|
+
wrap = insertAfter(el, id, kindClass, afterPos);
|
|
536
|
+
if (!wrap) continue;
|
|
518
537
|
setTimeout(() => { enqueueRetry(id); }, 450);
|
|
519
538
|
} else {
|
|
520
539
|
usedSet.add(id);
|
|
@@ -524,14 +543,16 @@
|
|
|
524
543
|
|
|
525
544
|
liveArr.push({ id, wrap });
|
|
526
545
|
// If adjacency ended up happening (e.g. DOM shifts), rollback this placement.
|
|
527
|
-
if (wrap && (
|
|
546
|
+
if (wrap && (
|
|
547
|
+
(wrap.previousElementSibling && wrap.previousElementSibling.classList && wrap.previousElementSibling.classList.contains(WRAP_CLASS)) ||
|
|
548
|
+
(wrap.nextElementSibling && wrap.nextElementSibling.classList && wrap.nextElementSibling.classList.contains(WRAP_CLASS))
|
|
549
|
+
)) {
|
|
528
550
|
try { wrap.remove(); } catch (e) {}
|
|
529
551
|
// Put id back if it was newly consumed (not recycled)
|
|
530
552
|
if (!(pick.recycled && pick.recycled.wrap)) {
|
|
531
553
|
try { kindPool.unshift(id); } catch (e) {}
|
|
532
554
|
try { usedSet.delete(id); } catch (e) {}
|
|
533
555
|
}
|
|
534
|
-
inserted -= 0; // no-op
|
|
535
556
|
continue;
|
|
536
557
|
}
|
|
537
558
|
if (!(pick.recycled && pick.recycled.wrap)) {
|
|
@@ -562,19 +583,24 @@
|
|
|
562
583
|
state.poolTopics = [];
|
|
563
584
|
state.poolPosts = [];
|
|
564
585
|
state.poolCategories = [];
|
|
565
|
-
state.poolCategories = [];
|
|
566
586
|
state.usedTopics.clear();
|
|
567
587
|
state.usedPosts.clear();
|
|
568
|
-
state.usedCategories
|
|
588
|
+
state.usedCategories.clear();
|
|
569
589
|
state.liveBetween = [];
|
|
570
590
|
state.liveMessage = [];
|
|
571
591
|
state.liveCategory = [];
|
|
572
|
-
state.usedCategories.clear();
|
|
573
592
|
|
|
574
593
|
state.lastShowById = new Map();
|
|
575
594
|
state.pendingById = new Set();
|
|
595
|
+
state.retryById = new Map();
|
|
596
|
+
state.retryQueue = [];
|
|
597
|
+
state.retryQueueSet = new Set();
|
|
598
|
+
state.retryQueueRunning = false;
|
|
599
|
+
state.badIds = new Set();
|
|
600
|
+
state.definedIds = new Set();
|
|
576
601
|
|
|
577
602
|
state.attempts = 0;
|
|
603
|
+
state.poolWaitAttempts = 0;
|
|
578
604
|
|
|
579
605
|
document.querySelectorAll(`.${WRAP_CLASS}`).forEach(el => el.remove());
|
|
580
606
|
|
|
@@ -582,13 +608,14 @@
|
|
|
582
608
|
state.scheduled = false;
|
|
583
609
|
clearTimeout(state.timer);
|
|
584
610
|
state.timer = null;
|
|
611
|
+
clearTimeout(state.retryTimer);
|
|
612
|
+
state.retryTimer = null;
|
|
585
613
|
}
|
|
586
614
|
|
|
587
615
|
function ensureObserver() {
|
|
588
616
|
if (state.obs) return;
|
|
589
617
|
state.obs = new MutationObserver(() => scheduleRun('mutation'));
|
|
590
618
|
try { state.obs.observe(document.body, { childList: true, subtree: true }); } catch (e) {}
|
|
591
|
-
setTimeout(() => { if (state.obs) { try { state.obs.disconnect(); } catch (e) {} state.obs = null; } }, 15000);
|
|
592
619
|
}
|
|
593
620
|
|
|
594
621
|
async function runCore() {
|
|
@@ -607,7 +634,7 @@
|
|
|
607
634
|
inserted = injectBetween('ezoic-ad-message', getPostContainers(),
|
|
608
635
|
Math.max(1, parseInt(cfg.messageIntervalPosts, 10) || 3),
|
|
609
636
|
normalizeBool(cfg.showFirstMessageAd),
|
|
610
|
-
|
|
637
|
+
state.poolPosts,
|
|
611
638
|
state.usedPosts);
|
|
612
639
|
}
|
|
613
640
|
} else if (kind === 'categoryTopics') {
|
|
@@ -615,7 +642,7 @@
|
|
|
615
642
|
inserted = injectBetween('ezoic-ad-between', getTopicItems(),
|
|
616
643
|
Math.max(1, parseInt(cfg.intervalPosts, 10) || 6),
|
|
617
644
|
normalizeBool(cfg.showFirstTopicAd),
|
|
618
|
-
|
|
645
|
+
state.poolTopics,
|
|
619
646
|
state.usedTopics);
|
|
620
647
|
}
|
|
621
648
|
} else if (kind === 'categories') {
|
|
@@ -623,7 +650,7 @@
|
|
|
623
650
|
inserted = injectBetween('ezoic-ad-categories', getCategoryItems(),
|
|
624
651
|
Math.max(1, parseInt(cfg.intervalCategories, 10) || 4),
|
|
625
652
|
normalizeBool(cfg.showFirstCategoryAd),
|
|
626
|
-
|
|
653
|
+
state.poolCategories,
|
|
627
654
|
state.usedCategories);
|
|
628
655
|
}
|
|
629
656
|
}
|
|
@@ -643,7 +670,22 @@
|
|
|
643
670
|
return;
|
|
644
671
|
}
|
|
645
672
|
|
|
646
|
-
if (inserted >= MAX_INSERTS_PER_RUN)
|
|
673
|
+
if (inserted >= MAX_INSERTS_PER_RUN) {
|
|
674
|
+
// Plus d'insertions possibles ce cycle, continuer immédiatement
|
|
675
|
+
setTimeout(() => scheduleRun('continue'), 140);
|
|
676
|
+
} else if (inserted === 0 && count > 0) {
|
|
677
|
+
// Pool épuisé ou recyclage pas encore disponible.
|
|
678
|
+
// Réessayer jusqu'à 8 fois (toutes les 400ms) pour laisser aux anciens wrappers
|
|
679
|
+
// le temps de défiler hors écran et devenir recyclables.
|
|
680
|
+
if (state.poolWaitAttempts < 8) {
|
|
681
|
+
state.poolWaitAttempts += 1;
|
|
682
|
+
setTimeout(() => scheduleRun('pool-wait'), 400);
|
|
683
|
+
} else {
|
|
684
|
+
state.poolWaitAttempts = 0;
|
|
685
|
+
}
|
|
686
|
+
} else if (inserted > 0) {
|
|
687
|
+
state.poolWaitAttempts = 0;
|
|
688
|
+
}
|
|
647
689
|
}
|
|
648
690
|
|
|
649
691
|
function scheduleRun() {
|
|
@@ -699,13 +741,6 @@
|
|
|
699
741
|
});
|
|
700
742
|
}
|
|
701
743
|
|
|
702
|
-
cleanup();
|
|
703
|
-
bind();
|
|
704
|
-
ensureObserver();
|
|
705
|
-
state.pageKey = getPageKey();
|
|
706
|
-
scheduleRun();
|
|
707
|
-
setTimeout(scheduleRun, 250);
|
|
708
|
-
})()
|
|
709
744
|
function bindScroll() {
|
|
710
745
|
if (state.__scrollBound) return;
|
|
711
746
|
state.__scrollBound = true;
|
|
@@ -715,10 +750,21 @@
|
|
|
715
750
|
ticking = true;
|
|
716
751
|
window.requestAnimationFrame(() => {
|
|
717
752
|
ticking = false;
|
|
753
|
+
// Réinitialiser le compteur d'attente de recyclage à chaque reprise de scroll
|
|
754
|
+
state.poolWaitAttempts = 0;
|
|
718
755
|
enforceNoAdjacentAds();
|
|
719
756
|
scheduleRefill(200);
|
|
757
|
+
// Tenter aussi d'insérer de nouvelles pubs si de nouveaux items sont apparus
|
|
758
|
+
scheduleRun();
|
|
720
759
|
});
|
|
721
760
|
}, { passive: true });
|
|
722
761
|
}
|
|
723
762
|
|
|
724
|
-
;
|
|
763
|
+
cleanup();
|
|
764
|
+
bind();
|
|
765
|
+
bindScroll();
|
|
766
|
+
ensureObserver();
|
|
767
|
+
state.pageKey = getPageKey();
|
|
768
|
+
scheduleRun();
|
|
769
|
+
setTimeout(scheduleRun, 250);
|
|
770
|
+
})();
|