nodebb-plugin-ezoic-infinite 1.8.11 → 1.8.13
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 +18 -26
- package/package.json +2 -2
- package/public/client.js +56 -166
- package/public/style.css +8 -5
package/library.js
CHANGED
|
@@ -71,9 +71,8 @@ async function getSettings() {
|
|
|
71
71
|
|
|
72
72
|
async function isUserExcluded(uid, excludedGroups) {
|
|
73
73
|
if (!uid || !excludedGroups.length) return false;
|
|
74
|
-
const excluded = new Set((excludedGroups || []).map(String));
|
|
75
74
|
const userGroups = await groups.getUserGroups([uid]);
|
|
76
|
-
return (userGroups[0] || []).some(g =>
|
|
75
|
+
return (userGroups[0] || []).some(g => excludedGroups.includes(g.name));
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
// ── Scripts Ezoic ──────────────────────────────────────────────────────────
|
|
@@ -114,34 +113,13 @@ plugin.injectEzoicHead = async (data) => {
|
|
|
114
113
|
const uid = data.req?.uid ?? 0;
|
|
115
114
|
const excluded = await isUserExcluded(uid, settings.excludedGroups);
|
|
116
115
|
if (!excluded) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
data.templateData.customHTML = `<meta data-nbb-ezoic-head="1">` + EZOIC_SCRIPTS + html;
|
|
120
|
-
}
|
|
116
|
+
// Préfixer : nos scripts d'abord, puis le customHTML existant de l'admin
|
|
117
|
+
data.templateData.customHTML = EZOIC_SCRIPTS + (data.templateData.customHTML || '');
|
|
121
118
|
}
|
|
122
119
|
} catch (_) {}
|
|
123
120
|
return data;
|
|
124
121
|
};
|
|
125
122
|
|
|
126
|
-
|
|
127
|
-
function publicConfigPayload(settings, excluded) {
|
|
128
|
-
return {
|
|
129
|
-
excluded,
|
|
130
|
-
enableBetweenAds: settings.enableBetweenAds,
|
|
131
|
-
showFirstTopicAd: settings.showFirstTopicAd,
|
|
132
|
-
placeholderIds: settings.placeholderIds,
|
|
133
|
-
intervalPosts: settings.intervalPosts,
|
|
134
|
-
enableCategoryAds: settings.enableCategoryAds,
|
|
135
|
-
showFirstCategoryAd: settings.showFirstCategoryAd,
|
|
136
|
-
categoryPlaceholderIds: settings.categoryPlaceholderIds,
|
|
137
|
-
intervalCategories: settings.intervalCategories,
|
|
138
|
-
enableMessageAds: settings.enableMessageAds,
|
|
139
|
-
showFirstMessageAd: settings.showFirstMessageAd,
|
|
140
|
-
messagePlaceholderIds: settings.messagePlaceholderIds,
|
|
141
|
-
messageIntervalPosts: settings.messageIntervalPosts,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
123
|
plugin.init = async ({ router, middleware }) => {
|
|
146
124
|
async function render(req, res) {
|
|
147
125
|
const settings = await getSettings();
|
|
@@ -161,7 +139,21 @@ plugin.init = async ({ router, middleware }) => {
|
|
|
161
139
|
router.get('/api/plugins/ezoic-infinite/config', async (req, res) => {
|
|
162
140
|
const settings = await getSettings();
|
|
163
141
|
const excluded = await isUserExcluded(req.uid, settings.excludedGroups);
|
|
164
|
-
res.json(
|
|
142
|
+
res.json({
|
|
143
|
+
excluded,
|
|
144
|
+
enableBetweenAds: settings.enableBetweenAds,
|
|
145
|
+
showFirstTopicAd: settings.showFirstTopicAd,
|
|
146
|
+
placeholderIds: settings.placeholderIds,
|
|
147
|
+
intervalPosts: settings.intervalPosts,
|
|
148
|
+
enableCategoryAds: settings.enableCategoryAds,
|
|
149
|
+
showFirstCategoryAd: settings.showFirstCategoryAd,
|
|
150
|
+
categoryPlaceholderIds: settings.categoryPlaceholderIds,
|
|
151
|
+
intervalCategories: settings.intervalCategories,
|
|
152
|
+
enableMessageAds: settings.enableMessageAds,
|
|
153
|
+
showFirstMessageAd: settings.showFirstMessageAd,
|
|
154
|
+
messagePlaceholderIds: settings.messagePlaceholderIds,
|
|
155
|
+
messageIntervalPosts: settings.messageIntervalPosts,
|
|
156
|
+
});
|
|
165
157
|
});
|
|
166
158
|
};
|
|
167
159
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodebb-plugin-ezoic-infinite",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.13",
|
|
4
4
|
"description": "Production-ready Ezoic infinite ads integration for NodeBB 4.x",
|
|
5
5
|
"main": "library.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,4 +18,4 @@
|
|
|
18
18
|
"compatibility": "^4.0.0"
|
|
19
19
|
},
|
|
20
20
|
"private": false
|
|
21
|
-
}
|
|
21
|
+
}
|
package/public/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* NodeBB Ezoic Infinite Ads — client.js
|
|
2
|
+
* NodeBB Ezoic Infinite Ads — client.js v36
|
|
3
3
|
*
|
|
4
4
|
* Historique des corrections majeures
|
|
5
5
|
* ────────────────────────────────────
|
|
@@ -32,8 +32,6 @@
|
|
|
32
32
|
*
|
|
33
33
|
* v34 moveDistantWrap — voir v38.
|
|
34
34
|
*
|
|
35
|
-
* v52 Clean architecture interne (modules logiques, cache DOM, bridge Ezoic).
|
|
36
|
-
*
|
|
37
35
|
* v50 Suppression de bindLoginCheck() : NodeBB fait un rechargement complet
|
|
38
36
|
* après login — filter:middleware.renderHeader re-évalue l'exclusion au
|
|
39
37
|
* rechargement. Redondant depuis le fix normalizeExcludedGroups (v49).
|
|
@@ -151,9 +149,6 @@
|
|
|
151
149
|
burstDeadline: 0,
|
|
152
150
|
burstCount: 0,
|
|
153
151
|
lastBurstTs: 0,
|
|
154
|
-
ioViewportMode: isMobile() ? 'm' : 'd',
|
|
155
|
-
domRev: 0,
|
|
156
|
-
domCache: new Map(),
|
|
157
152
|
};
|
|
158
153
|
|
|
159
154
|
let blockedUntil = 0;
|
|
@@ -162,61 +157,7 @@
|
|
|
162
157
|
const isBlocked = () => ts() < blockedUntil;
|
|
163
158
|
const isMobile = () => { try { return window.innerWidth < 768; } catch (_) { return false; } };
|
|
164
159
|
const normBool = v => v === true || v === 'true' || v === 1 || v === '1' || v === 'on';
|
|
165
|
-
const
|
|
166
|
-
const dbg = (...a) => { if (DEBUG) { try { console.debug('[nbb-ezoic]', ...a); } catch (_) {} } };
|
|
167
|
-
const isFilled = n => {
|
|
168
|
-
try {
|
|
169
|
-
if (!n?.querySelector) return false;
|
|
170
|
-
if (n.querySelector('iframe, ins, img, video, [data-google-container-id], .ezoic-ad, [id$="__container__"]')) return true;
|
|
171
|
-
const r = n.getBoundingClientRect?.();
|
|
172
|
-
return !!(r && r.height > 8);
|
|
173
|
-
} catch (_) { return false; }
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
const Arch = {
|
|
177
|
-
cache: {
|
|
178
|
-
invalidate(reason) {
|
|
179
|
-
S.domRev++;
|
|
180
|
-
S.domCache.clear();
|
|
181
|
-
dbg('dom-cache.invalidate', reason || '');
|
|
182
|
-
},
|
|
183
|
-
queryAll(key, selector, mapFn) {
|
|
184
|
-
const cacheKey = `${S.domRev}:${key}`;
|
|
185
|
-
if (S.domCache.has(cacheKey)) return S.domCache.get(cacheKey);
|
|
186
|
-
const arr = Array.from(document.querySelectorAll(selector));
|
|
187
|
-
const out = typeof mapFn === 'function' ? arr.filter(Boolean).filter(mapFn) : arr;
|
|
188
|
-
S.domCache.set(cacheKey, out);
|
|
189
|
-
return out;
|
|
190
|
-
},
|
|
191
|
-
get(key, buildFn) {
|
|
192
|
-
const cacheKey = `${S.domRev}:${key}`;
|
|
193
|
-
if (S.domCache.has(cacheKey)) return S.domCache.get(cacheKey);
|
|
194
|
-
const v = buildFn();
|
|
195
|
-
S.domCache.set(cacheKey, v);
|
|
196
|
-
return v;
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
ezoic: {
|
|
200
|
-
ensure() {
|
|
201
|
-
window.ezstandalone = window.ezstandalone || {};
|
|
202
|
-
return window.ezstandalone;
|
|
203
|
-
},
|
|
204
|
-
run(fn) {
|
|
205
|
-
const ez = this.ensure();
|
|
206
|
-
try { return (typeof ez?.cmd?.push === 'function') ? ez.cmd.push(fn) : fn(); } catch (_) {}
|
|
207
|
-
},
|
|
208
|
-
call(method, ...args) {
|
|
209
|
-
const ez = this.ensure();
|
|
210
|
-
const fn = ez?.[method];
|
|
211
|
-
if (typeof fn !== 'function') return;
|
|
212
|
-
try { return fn.apply(ez, args); } catch (_) {}
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
page: {
|
|
216
|
-
kind() { return getKind(); },
|
|
217
|
-
key() { return pageKey(); },
|
|
218
|
-
},
|
|
219
|
-
};
|
|
160
|
+
const isFilled = n => !!(n?.querySelector?.('iframe, ins, img, video, [data-google-container-id]'));
|
|
220
161
|
|
|
221
162
|
function healFalseEmpty(root = document) {
|
|
222
163
|
try {
|
|
@@ -274,8 +215,7 @@
|
|
|
274
215
|
|
|
275
216
|
function mutate(fn) {
|
|
276
217
|
S.mutGuard++;
|
|
277
|
-
try { fn(); }
|
|
278
|
-
finally { S.mutGuard--; Arch.cache.invalidate('mutate'); }
|
|
218
|
+
try { fn(); } finally { S.mutGuard--; }
|
|
279
219
|
}
|
|
280
220
|
function scheduleDestroyFlush() {
|
|
281
221
|
if (S.destroyBatchTimer) return;
|
|
@@ -295,7 +235,11 @@ function flushDestroyBatch() {
|
|
|
295
235
|
ids.push(id);
|
|
296
236
|
}
|
|
297
237
|
if (ids.length) {
|
|
298
|
-
try {
|
|
238
|
+
try {
|
|
239
|
+
const ez = window.ezstandalone;
|
|
240
|
+
const run = () => { try { ez?.destroyPlaceholders?.(ids); } catch (_) {} };
|
|
241
|
+
try { (typeof ez?.cmd?.push === 'function') ? ez.cmd.push(run) : run(); } catch (_) {}
|
|
242
|
+
} catch (_) {}
|
|
299
243
|
}
|
|
300
244
|
if (S.destroyPending.length) scheduleDestroyFlush();
|
|
301
245
|
}
|
|
@@ -311,28 +255,20 @@ function destroyEzoicId(id) {
|
|
|
311
255
|
scheduleDestroyFlush();
|
|
312
256
|
}
|
|
313
257
|
|
|
314
|
-
function
|
|
315
|
-
for (const raw of (ids || [])) {
|
|
316
|
-
const id = parseInt(raw, 10);
|
|
317
|
-
if (!Number.isFinite(id) || id <= 0) continue;
|
|
318
|
-
if (!S.ezActiveIds.has(id) && !S.ezShownSinceDestroy.has(id)) continue;
|
|
319
|
-
if (S.destroyPendingSet.has(id)) continue;
|
|
320
|
-
S.destroyPending.push(id);
|
|
321
|
-
S.destroyPendingSet.add(id);
|
|
322
|
-
S.ezActiveIds.delete(id);
|
|
323
|
-
S.ezShownSinceDestroy.delete(id);
|
|
324
|
-
}
|
|
325
|
-
if (S.destroyPending.length) scheduleDestroyFlush();
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
function prepareIdsForShow(ids) {
|
|
258
|
+
function destroyBeforeReuse(ids) {
|
|
329
259
|
const out = [];
|
|
260
|
+
const toDestroy = [];
|
|
330
261
|
const seen = new Set();
|
|
331
262
|
for (const raw of (ids || [])) {
|
|
332
263
|
const id = parseInt(raw, 10);
|
|
333
264
|
if (!Number.isFinite(id) || id <= 0 || seen.has(id)) continue;
|
|
334
265
|
seen.add(id);
|
|
335
266
|
out.push(id);
|
|
267
|
+
if (S.ezShownSinceDestroy.has(id)) toDestroy.push(id);
|
|
268
|
+
}
|
|
269
|
+
if (toDestroy.length) {
|
|
270
|
+
try { window.ezstandalone?.destroyPlaceholders?.(toDestroy); } catch (_) {}
|
|
271
|
+
for (const id of toDestroy) S.ezShownSinceDestroy.delete(id);
|
|
336
272
|
}
|
|
337
273
|
return out;
|
|
338
274
|
}
|
|
@@ -378,7 +314,6 @@ function prepareIdsForShow(ids) {
|
|
|
378
314
|
}
|
|
379
315
|
|
|
380
316
|
function getKind() {
|
|
381
|
-
return Arch.cache.get('kind', () => {
|
|
382
317
|
const p = location.pathname;
|
|
383
318
|
if (/^\/topic\//.test(p)) return 'topic';
|
|
384
319
|
if (/^\/category\//.test(p)) return 'categoryTopics';
|
|
@@ -387,13 +322,12 @@ function prepareIdsForShow(ids) {
|
|
|
387
322
|
if (document.querySelector(SEL.post)) return 'topic';
|
|
388
323
|
if (document.querySelector(SEL.topic)) return 'categoryTopics';
|
|
389
324
|
return 'other';
|
|
390
|
-
});
|
|
391
325
|
}
|
|
392
326
|
|
|
393
327
|
// ── Items DOM ──────────────────────────────────────────────────────────────
|
|
394
328
|
|
|
395
329
|
function getPosts() {
|
|
396
|
-
return
|
|
330
|
+
return Array.from(document.querySelectorAll(SEL.post)).filter(el => {
|
|
397
331
|
if (!el.isConnected) return false;
|
|
398
332
|
if (!el.querySelector('[component="post/content"]')) return false;
|
|
399
333
|
const p = el.parentElement?.closest(SEL.post);
|
|
@@ -402,8 +336,8 @@ function prepareIdsForShow(ids) {
|
|
|
402
336
|
});
|
|
403
337
|
}
|
|
404
338
|
|
|
405
|
-
const getTopics = () =>
|
|
406
|
-
const getCategories = () =>
|
|
339
|
+
const getTopics = () => Array.from(document.querySelectorAll(SEL.topic));
|
|
340
|
+
const getCategories = () => Array.from(document.querySelectorAll(SEL.category));
|
|
407
341
|
|
|
408
342
|
// ── Wraps — détection ──────────────────────────────────────────────────────
|
|
409
343
|
|
|
@@ -504,7 +438,6 @@ function prepareIdsForShow(ids) {
|
|
|
504
438
|
S.mountedIds.delete(id);
|
|
505
439
|
S.pendingSet.delete(id);
|
|
506
440
|
S.lastShow.delete(id);
|
|
507
|
-
queueDestroyIds([id]);
|
|
508
441
|
S.ezActiveIds.delete(id);
|
|
509
442
|
}
|
|
510
443
|
}
|
|
@@ -521,7 +454,7 @@ function prepareIdsForShow(ids) {
|
|
|
521
454
|
* Priorité : wraps vides d'abord, remplis si nécessaire.
|
|
522
455
|
*/
|
|
523
456
|
function recycleAndMove(klass, targetEl, newKey) {
|
|
524
|
-
const ez =
|
|
457
|
+
const ez = window.ezstandalone;
|
|
525
458
|
if (typeof ez?.destroyPlaceholders !== 'function' ||
|
|
526
459
|
typeof ez?.define !== 'function' ||
|
|
527
460
|
typeof ez?.displayMore !== 'function') return null;
|
|
@@ -593,7 +526,7 @@ function recycleAndMove(klass, targetEl, newKey) {
|
|
|
593
526
|
};
|
|
594
527
|
const doDefine = () => { try { ez.define([id]); } catch (_) {} setTimeout(doDisplay, 300); };
|
|
595
528
|
const doDisplay = () => { try { ez.displayMore([id]); S.ezActiveIds.add(id); S.ezShownSinceDestroy.add(id); } catch (_) {} };
|
|
596
|
-
try {
|
|
529
|
+
try { (typeof ez.cmd?.push === 'function') ? ez.cmd.push(doDestroy) : doDestroy(); } catch (_) {}
|
|
597
530
|
|
|
598
531
|
return { id, wrap: best };
|
|
599
532
|
}
|
|
@@ -633,7 +566,7 @@ function recycleAndMove(klass, targetEl, newKey) {
|
|
|
633
566
|
const ph = w.querySelector(`[id^="${PH_PREFIX}"]`);
|
|
634
567
|
if (ph instanceof Element) S.io?.unobserve(ph);
|
|
635
568
|
const id = parseInt(w.getAttribute(A_WRAPID), 10);
|
|
636
|
-
if (Number.isFinite(id)) {
|
|
569
|
+
if (Number.isFinite(id)) { S.ezActiveIds.delete(id); S.mountedIds.delete(id); }
|
|
637
570
|
const key = w.getAttribute(A_ANCHOR);
|
|
638
571
|
if (key && S.wrapByKey.get(key) === w) S.wrapByKey.delete(key);
|
|
639
572
|
w.remove();
|
|
@@ -656,18 +589,19 @@ function recycleAndMove(klass, targetEl, newKey) {
|
|
|
656
589
|
// supprimerait les wraps, et provoquerait une réinjection en haut.
|
|
657
590
|
|
|
658
591
|
function pruneOrphansBetween() {
|
|
659
|
-
if (S.burstActive || (S.scrollSpeed || 0) > 1800) return;
|
|
660
592
|
const klass = 'ezoic-ad-between';
|
|
661
593
|
const cfg = KIND[klass];
|
|
662
|
-
const liveAnchors = new Set(Arch.cache.queryAll('prune-between-anchors', cfg.sel).map(el => el.getAttribute(cfg.anchorAttr)).filter(Boolean));
|
|
663
594
|
|
|
664
595
|
document.querySelectorAll(`.${WRAP_CLASS}.${klass}`).forEach(w => {
|
|
665
596
|
const created = parseInt(w.getAttribute(A_CREATED) || '0', 10);
|
|
666
|
-
if (ts() - created < MIN_PRUNE_AGE_MS) return;
|
|
597
|
+
if (ts() - created < MIN_PRUNE_AGE_MS) return; // grâce post-création
|
|
598
|
+
|
|
667
599
|
const key = w.getAttribute(A_ANCHOR) ?? '';
|
|
668
|
-
const sid = key.slice(klass.length + 1);
|
|
600
|
+
const sid = key.slice(klass.length + 1); // après "ezoic-ad-between:"
|
|
669
601
|
if (!sid) { mutate(() => dropWrap(w)); return; }
|
|
670
|
-
|
|
602
|
+
|
|
603
|
+
const anchorEl = document.querySelector(`${cfg.baseTag}[${cfg.anchorAttr}="${sid}"]`);
|
|
604
|
+
if (!anchorEl?.isConnected) mutate(() => dropWrap(w));
|
|
671
605
|
});
|
|
672
606
|
}
|
|
673
607
|
|
|
@@ -713,8 +647,6 @@ function recycleAndMove(klass, targetEl, newKey) {
|
|
|
713
647
|
const w = insertAfter(el, id, klass, key);
|
|
714
648
|
if (w) { observePh(id); inserted++; }
|
|
715
649
|
} else {
|
|
716
|
-
// Recyclage agressif = source fréquente de churn visuel (surtout sticky/fixed)
|
|
717
|
-
if (klass === 'ezoic-ad-message') break;
|
|
718
650
|
const recycled = recycleAndMove(klass, el, key);
|
|
719
651
|
if (!recycled) break;
|
|
720
652
|
inserted++;
|
|
@@ -725,31 +657,15 @@ function recycleAndMove(klass, targetEl, newKey) {
|
|
|
725
657
|
|
|
726
658
|
// ── IntersectionObserver & Show ────────────────────────────────────────────
|
|
727
659
|
|
|
728
|
-
function ensureIOViewportMode() {
|
|
729
|
-
const mode = isMobile() ? 'm' : 'd';
|
|
730
|
-
if (S.io && S.ioViewportMode !== mode) {
|
|
731
|
-
try { S.io.disconnect(); } catch (_) {}
|
|
732
|
-
S.io = null;
|
|
733
|
-
}
|
|
734
|
-
S.ioViewportMode = mode;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
660
|
function getIO() {
|
|
738
|
-
ensureIOViewportMode();
|
|
739
661
|
if (S.io) return S.io;
|
|
740
662
|
try {
|
|
741
663
|
S.io = new IntersectionObserver(entries => {
|
|
742
664
|
for (const e of entries) {
|
|
743
665
|
if (!e.isIntersecting) continue;
|
|
744
|
-
|
|
745
|
-
const id = parseInt(target
|
|
746
|
-
if (
|
|
747
|
-
const accepted = enqueueShow(id);
|
|
748
|
-
if (accepted) {
|
|
749
|
-
try { S.io?.unobserve(target); } catch (_) {}
|
|
750
|
-
} else if (target?.isConnected) {
|
|
751
|
-
setTimeout(() => { try { if (target.isConnected) S.io?.observe(target); } catch (_) {} }, 300);
|
|
752
|
-
}
|
|
666
|
+
if (e.target instanceof Element) S.io?.unobserve(e.target);
|
|
667
|
+
const id = parseInt(e.target.getAttribute('data-ezoic-id'), 10);
|
|
668
|
+
if (Number.isFinite(id) && id > 0) enqueueShow(id);
|
|
753
669
|
}
|
|
754
670
|
}, { root: null, rootMargin: isMobile() ? IO_MARGIN_MOBILE : IO_MARGIN_DESKTOP, threshold: 0 });
|
|
755
671
|
} catch (_) { S.io = null; }
|
|
@@ -770,15 +686,12 @@ function recycleAndMove(klass, targetEl, newKey) {
|
|
|
770
686
|
}
|
|
771
687
|
|
|
772
688
|
function enqueueShow(id) {
|
|
773
|
-
if (!id || isBlocked()) return
|
|
689
|
+
if (!id || isBlocked()) return;
|
|
774
690
|
const n = parseInt(id, 10);
|
|
775
|
-
if (!Number.isFinite(n) || n <= 0) return
|
|
776
|
-
if (ts() - (S.lastShow.get(n) ?? 0) < SHOW_THROTTLE_MS) return
|
|
777
|
-
const ph = phEl(n);
|
|
778
|
-
if (!ph?.isConnected || isFilled(ph) || !hasSinglePlaceholder(n)) return false;
|
|
691
|
+
if (!Number.isFinite(n) || n <= 0) return;
|
|
692
|
+
if (ts() - (S.lastShow.get(n) ?? 0) < SHOW_THROTTLE_MS) return;
|
|
779
693
|
if (!S.pendingSet.has(n)) { S.pending.push(n); S.pendingSet.add(n); }
|
|
780
694
|
scheduleDrainQueue();
|
|
781
|
-
return true;
|
|
782
695
|
}
|
|
783
696
|
|
|
784
697
|
function scheduleDrainQueue() {
|
|
@@ -844,18 +757,19 @@ function startShowBatch(ids) {
|
|
|
844
757
|
|
|
845
758
|
if (!valid.length) { clearTimeout(timer); return release(); }
|
|
846
759
|
|
|
847
|
-
|
|
760
|
+
window.ezstandalone = window.ezstandalone || {};
|
|
761
|
+
const ez = window.ezstandalone;
|
|
848
762
|
const doShow = () => {
|
|
849
|
-
const prepared =
|
|
763
|
+
const prepared = destroyBeforeReuse(valid);
|
|
850
764
|
if (!prepared.length) { setTimeout(() => { clearTimeout(timer); release(); }, SHOW_RELEASE_MS); return; }
|
|
851
|
-
try { ez.showAds(...prepared); } catch (_) {
|
|
765
|
+
try { ez.showAds(...prepared); } catch (_) {}
|
|
852
766
|
for (const id of prepared) {
|
|
853
767
|
S.ezActiveIds.add(id);
|
|
854
768
|
S.ezShownSinceDestroy.add(id);
|
|
855
769
|
}
|
|
856
770
|
setTimeout(() => { clearTimeout(timer); release(); }, SHOW_RELEASE_MS);
|
|
857
771
|
};
|
|
858
|
-
|
|
772
|
+
Array.isArray(ez.cmd) ? ez.cmd.push(doShow) : doShow();
|
|
859
773
|
} catch (_) { clearTimeout(timer); release(); }
|
|
860
774
|
});
|
|
861
775
|
}
|
|
@@ -870,7 +784,8 @@ function startShowBatch(ids) {
|
|
|
870
784
|
function patchShowAds() {
|
|
871
785
|
const apply = () => {
|
|
872
786
|
try {
|
|
873
|
-
|
|
787
|
+
window.ezstandalone = window.ezstandalone || {};
|
|
788
|
+
const ez = window.ezstandalone;
|
|
874
789
|
if (window.__nbbEzPatched || typeof ez.showAds !== 'function') return;
|
|
875
790
|
window.__nbbEzPatched = true;
|
|
876
791
|
const orig = ez.showAds.bind(ez);
|
|
@@ -897,7 +812,8 @@ function startShowBatch(ids) {
|
|
|
897
812
|
};
|
|
898
813
|
apply();
|
|
899
814
|
if (!window.__nbbEzPatched) {
|
|
900
|
-
|
|
815
|
+
window.ezstandalone = window.ezstandalone || {};
|
|
816
|
+
(window.ezstandalone.cmd = window.ezstandalone.cmd || []).push(apply);
|
|
901
817
|
}
|
|
902
818
|
}
|
|
903
819
|
|
|
@@ -1006,7 +922,6 @@ function startShowBatch(ids) {
|
|
|
1006
922
|
S.scrollSpeed = 0;
|
|
1007
923
|
S.lastScrollY = 0;
|
|
1008
924
|
S.lastScrollTs = 0;
|
|
1009
|
-
Arch.cache.invalidate('cleanup');
|
|
1010
925
|
}
|
|
1011
926
|
|
|
1012
927
|
// ── MutationObserver ───────────────────────────────────────────────────────
|
|
@@ -1024,14 +939,14 @@ function startShowBatch(ids) {
|
|
|
1024
939
|
sawWrapRemoval = true;
|
|
1025
940
|
}
|
|
1026
941
|
}
|
|
1027
|
-
if (sawWrapRemoval)
|
|
942
|
+
if (sawWrapRemoval) queueSweepDeadWraps();
|
|
1028
943
|
for (const n of m.addedNodes) {
|
|
1029
944
|
if (n.nodeType !== 1) continue;
|
|
1030
945
|
try { healFalseEmpty(n); } catch (_) {}
|
|
1031
946
|
// matches() d'abord (O(1)), querySelector() seulement si nécessaire
|
|
1032
947
|
if (allSel.some(s => { try { return n.matches(s); } catch(_){return false;} }) ||
|
|
1033
948
|
allSel.some(s => { try { return !!n.querySelector(s); } catch(_){return false;} })) {
|
|
1034
|
-
|
|
949
|
+
requestBurst(); return;
|
|
1035
950
|
}
|
|
1036
951
|
}
|
|
1037
952
|
}
|
|
@@ -1110,8 +1025,7 @@ function startShowBatch(ids) {
|
|
|
1110
1025
|
$(window).off('.nbbEzoic');
|
|
1111
1026
|
$(window).on('action:ajaxify.start.nbbEzoic', cleanup);
|
|
1112
1027
|
$(window).on('action:ajaxify.end.nbbEzoic', () => {
|
|
1113
|
-
S.pageKey =
|
|
1114
|
-
Arch.cache.invalidate('ajaxify.end');
|
|
1028
|
+
S.pageKey = pageKey();
|
|
1115
1029
|
blockedUntil = 0;
|
|
1116
1030
|
muteConsole(); ensureTcfLocator(); warmNetwork();
|
|
1117
1031
|
patchShowAds(); getIO(); ensureDomObserver(); sweepDeadWraps(); requestBurst();
|
|
@@ -1134,17 +1048,6 @@ function startShowBatch(ids) {
|
|
|
1134
1048
|
} catch (_) {}
|
|
1135
1049
|
}
|
|
1136
1050
|
|
|
1137
|
-
function bindResize() {
|
|
1138
|
-
let rT = 0;
|
|
1139
|
-
window.addEventListener('resize', () => {
|
|
1140
|
-
if (rT) clearTimeout(rT);
|
|
1141
|
-
rT = setTimeout(() => {
|
|
1142
|
-
ensureIOViewportMode();
|
|
1143
|
-
requestBurst();
|
|
1144
|
-
}, 120);
|
|
1145
|
-
}, { passive: true });
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
1051
|
function bindScroll() {
|
|
1149
1052
|
let ticking = false;
|
|
1150
1053
|
try {
|
|
@@ -1171,29 +1074,16 @@ function startShowBatch(ids) {
|
|
|
1171
1074
|
|
|
1172
1075
|
// ── Boot ───────────────────────────────────────────────────────────────────
|
|
1173
1076
|
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
this.modules.infra.patchShowAds();
|
|
1186
|
-
this.modules.viewport.getIO();
|
|
1187
|
-
this.modules.lifecycle.ensureDomObserver();
|
|
1188
|
-
this.modules.lifecycle.bindNodeBB();
|
|
1189
|
-
this.modules.viewport.bindResize();
|
|
1190
|
-
this.modules.viewport.bindScroll();
|
|
1191
|
-
blockedUntil = 0;
|
|
1192
|
-
this.modules.scheduler.requestBurst();
|
|
1193
|
-
},
|
|
1194
|
-
};
|
|
1195
|
-
|
|
1196
|
-
S.pageKey = Arch.page.key();
|
|
1197
|
-
App.boot();
|
|
1077
|
+
S.pageKey = pageKey();
|
|
1078
|
+
muteConsole();
|
|
1079
|
+
ensureTcfLocator();
|
|
1080
|
+
warmNetwork();
|
|
1081
|
+
patchShowAds();
|
|
1082
|
+
getIO();
|
|
1083
|
+
ensureDomObserver();
|
|
1084
|
+
bindNodeBB();
|
|
1085
|
+
bindScroll();
|
|
1086
|
+
blockedUntil = 0;
|
|
1087
|
+
requestBurst();
|
|
1198
1088
|
|
|
1199
1089
|
})();
|
package/public/style.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* NodeBB Ezoic Infinite Ads — style.css (
|
|
2
|
+
* NodeBB Ezoic Infinite Ads — style.css (v20)
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* ── Wrapper ──────────────────────────────────────────────────────────────── */
|
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
width: 100%;
|
|
9
9
|
margin: 0 !important;
|
|
10
10
|
padding: 0 !important;
|
|
11
|
-
overflow:
|
|
12
|
-
contain:
|
|
13
|
-
position: relative;
|
|
11
|
+
overflow: hidden;
|
|
12
|
+
contain: layout style;
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
/* Placeholder : 1px minimum pour rester visible par l'IntersectionObserver */
|
|
@@ -51,7 +50,11 @@
|
|
|
51
50
|
position: absolute !important;
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
/*
|
|
53
|
+
/* Neutralise sticky dans nos wraps (évite l'effet "gliding") */
|
|
54
|
+
.nodebb-ezoic-wrap .ezads-sticky-intradiv {
|
|
55
|
+
position: static !important;
|
|
56
|
+
top: auto !important;
|
|
57
|
+
}
|
|
55
58
|
|
|
56
59
|
/* ── Ezoic global (hors de nos wraps) ────────────────────────────────────── */
|
|
57
60
|
.ezoic-ad {
|