nodebb-plugin-ezoic-infinite 1.2.6 → 1.4.0
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 +15 -1
- package/package.json +1 -1
- package/public/client.js +149 -197
- package/public/templates/admin/plugins/ezoic-infinite.tpl +26 -0
package/library.js
CHANGED
|
@@ -34,13 +34,21 @@ async function getAllGroups() {
|
|
|
34
34
|
async function getSettings() {
|
|
35
35
|
const s = await meta.settings.get(SETTINGS_KEY);
|
|
36
36
|
return {
|
|
37
|
-
// Between-post ads (simple blocks)
|
|
37
|
+
// Between-post ads (simple blocks) in category topic list
|
|
38
38
|
enableBetweenAds: parseBool(s.enableBetweenAds, true),
|
|
39
|
+
showFirstTopicAd: parseBool(s.showFirstTopicAd, false),
|
|
39
40
|
placeholderIds: (s.placeholderIds || '').trim(),
|
|
40
41
|
intervalPosts: Math.max(1, parseInt(s.intervalPosts, 10) || 6),
|
|
41
42
|
|
|
43
|
+
// Home/categories list ads (between categories on / or /categories)
|
|
44
|
+
enableCategoryAds: parseBool(s.enableCategoryAds, false),
|
|
45
|
+
showFirstCategoryAd: parseBool(s.showFirstCategoryAd, false),
|
|
46
|
+
categoryPlaceholderIds: (s.categoryPlaceholderIds || '').trim(),
|
|
47
|
+
intervalCategories: Math.max(1, parseInt(s.intervalCategories, 10) || 4),
|
|
48
|
+
|
|
42
49
|
// "Ad message" between replies (looks like a post)
|
|
43
50
|
enableMessageAds: parseBool(s.enableMessageAds, false),
|
|
51
|
+
showFirstMessageAd: parseBool(s.showFirstMessageAd, false),
|
|
44
52
|
messagePlaceholderIds: (s.messagePlaceholderIds || '').trim(),
|
|
45
53
|
messageIntervalPosts: Math.max(1, parseInt(s.messageIntervalPosts, 10) || 3),
|
|
46
54
|
|
|
@@ -88,9 +96,15 @@ plugin.init = async ({ router, middleware }) => {
|
|
|
88
96
|
res.json({
|
|
89
97
|
excluded,
|
|
90
98
|
enableBetweenAds: settings.enableBetweenAds,
|
|
99
|
+
showFirstTopicAd: settings.showFirstTopicAd,
|
|
91
100
|
placeholderIds: settings.placeholderIds,
|
|
92
101
|
intervalPosts: settings.intervalPosts,
|
|
102
|
+
enableCategoryAds: settings.enableCategoryAds,
|
|
103
|
+
showFirstCategoryAd: settings.showFirstCategoryAd,
|
|
104
|
+
categoryPlaceholderIds: settings.categoryPlaceholderIds,
|
|
105
|
+
intervalCategories: settings.intervalCategories,
|
|
93
106
|
enableMessageAds: settings.enableMessageAds,
|
|
107
|
+
showFirstMessageAd: settings.showFirstMessageAd,
|
|
94
108
|
messagePlaceholderIds: settings.messagePlaceholderIds,
|
|
95
109
|
messageIntervalPosts: settings.messageIntervalPosts,
|
|
96
110
|
});
|
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
1
|
(function () {
|
|
3
2
|
'use strict';
|
|
4
3
|
|
|
5
|
-
// Optional debug switch
|
|
6
|
-
const DEBUG = !!window.__ezoicInfiniteDebug;
|
|
7
|
-
|
|
8
4
|
const $ = (typeof window.jQuery === 'function') ? window.jQuery : null;
|
|
9
5
|
|
|
10
6
|
const SELECTORS = {
|
|
11
7
|
topicItem: 'li[component="category/topic"]',
|
|
12
8
|
postItem: '[component="post"][data-pid]',
|
|
9
|
+
categoryItem: 'li[component="categories/category"]',
|
|
13
10
|
};
|
|
14
11
|
|
|
15
12
|
const WRAP_CLASS = 'ezoic-ad';
|
|
16
13
|
const PLACEHOLDER_PREFIX = 'ezoic-pub-ad-placeholder-';
|
|
17
14
|
|
|
18
|
-
// Prevent “burst” injection: at most N inserts per run per kind
|
|
19
15
|
const MAX_INSERTS_PER_RUN = 2;
|
|
20
16
|
|
|
21
17
|
const state = {
|
|
@@ -23,33 +19,24 @@
|
|
|
23
19
|
cfg: null,
|
|
24
20
|
cfgPromise: null,
|
|
25
21
|
|
|
26
|
-
// Per-page pools (refilled by recycling)
|
|
27
22
|
poolTopics: [],
|
|
28
23
|
poolPosts: [],
|
|
24
|
+
poolCategories: [],
|
|
29
25
|
|
|
30
|
-
// Track inserted ads per page
|
|
31
26
|
usedTopics: new Set(),
|
|
32
27
|
usedPosts: new Set(),
|
|
28
|
+
usedCategories: new Set(),
|
|
33
29
|
|
|
34
|
-
// Track which anchors we already evaluated to avoid reprocessing everything on each event
|
|
35
|
-
seenTopicAnchors: new WeakSet(),
|
|
36
|
-
seenPostAnchors: new WeakSet(),
|
|
37
|
-
|
|
38
|
-
// showAds anti-double
|
|
39
30
|
lastShowById: new Map(),
|
|
40
31
|
pendingById: new Set(),
|
|
41
32
|
|
|
42
|
-
// debounce
|
|
43
33
|
scheduled: false,
|
|
44
34
|
timer: null,
|
|
45
35
|
|
|
46
|
-
// observers
|
|
47
36
|
obs: null,
|
|
37
|
+
attempts: 0,
|
|
48
38
|
};
|
|
49
39
|
|
|
50
|
-
function log(...args) { if (DEBUG) console.log('[ezoic-infinite]', ...args); }
|
|
51
|
-
function warn(...args) { if (DEBUG) console.warn('[ezoic-infinite]', ...args); }
|
|
52
|
-
|
|
53
40
|
function normalizeBool(v) {
|
|
54
41
|
return v === true || v === 'true' || v === 1 || v === '1' || v === 'on';
|
|
55
42
|
}
|
|
@@ -87,89 +74,87 @@
|
|
|
87
74
|
function getKind() {
|
|
88
75
|
const p = window.location.pathname || '';
|
|
89
76
|
if (/^\/topic\//.test(p)) return 'topic';
|
|
90
|
-
if (/^\/category\//.test(p)) return '
|
|
91
|
-
|
|
77
|
+
if (/^\/category\//.test(p)) return 'categoryTopics';
|
|
78
|
+
if (p === '/' || /^\/categories/.test(p)) return 'categories';
|
|
79
|
+
// fallback by DOM
|
|
80
|
+
if (document.querySelector(SELECTORS.categoryItem)) return 'categories';
|
|
92
81
|
if (document.querySelector(SELECTORS.postItem)) return 'topic';
|
|
93
|
-
return '
|
|
82
|
+
if (document.querySelector(SELECTORS.topicItem)) return 'categoryTopics';
|
|
83
|
+
return 'other';
|
|
94
84
|
}
|
|
95
85
|
|
|
96
|
-
|
|
97
86
|
function getTopicItems() {
|
|
98
87
|
return Array.from(document.querySelectorAll(SELECTORS.topicItem));
|
|
99
88
|
}
|
|
100
89
|
|
|
90
|
+
function getCategoryItems() {
|
|
91
|
+
return Array.from(document.querySelectorAll(SELECTORS.categoryItem));
|
|
92
|
+
}
|
|
93
|
+
|
|
101
94
|
function getPostContainers() {
|
|
102
|
-
// Harmony can include multiple [component="post"] blocks (e.g. parent previews, nested structures).
|
|
103
|
-
// We only want top-level post containers that actually contain post content.
|
|
104
95
|
const nodes = Array.from(document.querySelectorAll(SELECTORS.postItem));
|
|
105
96
|
return nodes.filter((el) => {
|
|
106
97
|
if (!el || !el.isConnected) return false;
|
|
107
|
-
|
|
108
|
-
// Must contain post content
|
|
109
98
|
if (!el.querySelector('[component="post/content"]')) return false;
|
|
110
|
-
|
|
111
|
-
// Must not be nested within another post container
|
|
112
99
|
const parentPost = el.parentElement && el.parentElement.closest('[component="post"][data-pid]');
|
|
113
100
|
if (parentPost && parentPost !== el) return false;
|
|
114
|
-
|
|
115
|
-
// Avoid "parent/quote" blocks that use component="post/parent"
|
|
116
101
|
if (el.getAttribute('component') === 'post/parent') return false;
|
|
117
|
-
|
|
118
102
|
return true;
|
|
119
103
|
});
|
|
120
104
|
}
|
|
121
105
|
|
|
122
|
-
function
|
|
123
|
-
const n = el && el.nextElementSibling;
|
|
124
|
-
return !!(n && n.classList && n.classList.contains(WRAP_CLASS));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function enforceNoAdjacentAds() {
|
|
128
|
-
// NodeBB can virtualize (remove) topics/posts from the DOM while keeping our ad wrappers,
|
|
129
|
-
// which can temporarily make two ad wrappers adjacent. Hide the later one to avoid back-to-back ads.
|
|
130
|
-
const ads = Array.from(document.querySelectorAll(`.${WRAP_CLASS}`));
|
|
131
|
-
for (let i = 0; i < ads.length; i++) {
|
|
132
|
-
const ad = ads[i];
|
|
133
|
-
const prev = ad.previousElementSibling;
|
|
134
|
-
if (prev && prev.classList && prev.classList.contains(WRAP_CLASS)) {
|
|
135
|
-
ad.style.display = 'none';
|
|
136
|
-
} else {
|
|
137
|
-
ad.style.display = '';
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const n = el && el.nextElementSibling;
|
|
144
|
-
return !!(n && n.classList && n.classList.contains(WRAP_CLASS));
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function buildWrap(id, kind, afterPos) {
|
|
106
|
+
function buildWrap(id, kindClass, afterPos) {
|
|
148
107
|
const wrap = document.createElement('div');
|
|
149
|
-
wrap.className = `${WRAP_CLASS} ${
|
|
108
|
+
wrap.className = `${WRAP_CLASS} ${kindClass}`;
|
|
150
109
|
wrap.setAttribute('data-ezoic-after', String(afterPos));
|
|
151
110
|
wrap.style.width = '100%';
|
|
111
|
+
|
|
152
112
|
const ph = document.createElement('div');
|
|
153
113
|
ph.id = `${PLACEHOLDER_PREFIX}${id}`;
|
|
154
114
|
wrap.appendChild(ph);
|
|
155
115
|
return wrap;
|
|
156
116
|
}
|
|
157
117
|
|
|
158
|
-
function
|
|
118
|
+
function findWrap(kindClass, afterPos) {
|
|
119
|
+
return document.querySelector(`.${WRAP_CLASS}.${kindClass}[data-ezoic-after="${afterPos}"]`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function insertAfter(target, id, kindClass, afterPos) {
|
|
159
123
|
if (!target || !target.insertAdjacentElement) return null;
|
|
160
|
-
|
|
124
|
+
if (findWrap(kindClass, afterPos)) return null;
|
|
125
|
+
const wrap = buildWrap(id, kindClass, afterPos);
|
|
161
126
|
target.insertAdjacentElement('afterend', wrap);
|
|
162
127
|
return wrap;
|
|
163
128
|
}
|
|
164
129
|
|
|
165
|
-
function
|
|
166
|
-
|
|
167
|
-
|
|
130
|
+
function destroyUsedPlaceholders() {
|
|
131
|
+
const ids = [];
|
|
132
|
+
try {
|
|
133
|
+
state.usedTopics.forEach((id) => ids.push(id));
|
|
134
|
+
state.usedPosts.forEach((id) => ids.push(id));
|
|
135
|
+
state.usedCategories.forEach((id) => ids.push(id));
|
|
136
|
+
} catch (e) {}
|
|
137
|
+
|
|
138
|
+
if (!ids.length) return;
|
|
139
|
+
|
|
140
|
+
const call = () => {
|
|
141
|
+
try {
|
|
142
|
+
if (window.ezstandalone && typeof window.ezstandalone.destroyPlaceholders === 'function') {
|
|
143
|
+
window.ezstandalone.destroyPlaceholders(ids);
|
|
144
|
+
}
|
|
145
|
+
} catch (e) {}
|
|
146
|
+
};
|
|
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);
|
|
168
153
|
} catch (e) {}
|
|
169
154
|
}
|
|
170
155
|
|
|
171
|
-
// Patch ezstandalone.showAds to split batch calls (we NEVER call batch from this plugin)
|
|
172
156
|
function patchShowAds() {
|
|
157
|
+
// Minimal safety net: batch showAds can be triggered by other scripts; split into individual calls.
|
|
173
158
|
try {
|
|
174
159
|
window.ezstandalone = window.ezstandalone || {};
|
|
175
160
|
const ez = window.ezstandalone;
|
|
@@ -179,11 +164,13 @@
|
|
|
179
164
|
ez.__nodebbEzoicPatched = true;
|
|
180
165
|
const orig = ez.showAds;
|
|
181
166
|
|
|
182
|
-
ez.showAds = function
|
|
167
|
+
ez.showAds = function (arg) {
|
|
183
168
|
if (Array.isArray(arg)) {
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
169
|
+
const seen = new Set();
|
|
170
|
+
for (const v of arg) {
|
|
171
|
+
const id = parseInt(v, 10);
|
|
172
|
+
if (!Number.isFinite(id) || id <= 0 || seen.has(id)) continue;
|
|
173
|
+
seen.add(id);
|
|
187
174
|
try { orig.call(ez, id); } catch (e) {}
|
|
188
175
|
}
|
|
189
176
|
return;
|
|
@@ -236,7 +223,6 @@
|
|
|
236
223
|
} catch (e) {}
|
|
237
224
|
});
|
|
238
225
|
|
|
239
|
-
// short retries
|
|
240
226
|
let tries = 0;
|
|
241
227
|
(function tick() {
|
|
242
228
|
tries += 1;
|
|
@@ -249,17 +235,14 @@
|
|
|
249
235
|
return;
|
|
250
236
|
}
|
|
251
237
|
|
|
252
|
-
if (attempts <
|
|
238
|
+
if (attempts < 50) setTimeout(waitForPh, 50);
|
|
253
239
|
})();
|
|
254
240
|
}
|
|
255
|
-
}
|
|
256
|
-
return false;
|
|
257
|
-
}
|
|
258
241
|
|
|
259
242
|
function nextId(kind) {
|
|
260
|
-
const pool = (kind === 'between') ? state.poolTopics : state.poolPosts;
|
|
243
|
+
const pool = (kind === 'between') ? state.poolTopics : (kind === 'message') ? state.poolPosts : state.poolCategories;
|
|
261
244
|
if (pool.length) return pool.shift();
|
|
262
|
-
return null;
|
|
245
|
+
return null;
|
|
263
246
|
}
|
|
264
247
|
|
|
265
248
|
async function fetchConfig() {
|
|
@@ -283,139 +266,80 @@
|
|
|
283
266
|
}
|
|
284
267
|
|
|
285
268
|
function initPools(cfg) {
|
|
286
|
-
// Re-init pools once per page
|
|
287
269
|
if (state.poolTopics.length === 0) state.poolTopics = parsePool(cfg.placeholderIds);
|
|
288
270
|
if (state.poolPosts.length === 0) state.poolPosts = parsePool(cfg.messagePlaceholderIds);
|
|
271
|
+
if (state.poolCategories.length === 0) state.poolCategories = parsePool(cfg.categoryPlaceholderIds);
|
|
289
272
|
}
|
|
290
273
|
|
|
291
|
-
function
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const items = getTopicItems();
|
|
298
|
-
if (!items.length) return 0;
|
|
299
|
-
|
|
300
|
-
let inserted = 0;
|
|
301
|
-
for (let i = 0; i < items.length; i++) {
|
|
302
|
-
const li = items[i];
|
|
303
|
-
if (!li || !li.isConnected) continue;
|
|
304
|
-
|
|
305
|
-
// Avoid re-processing anchors already evaluated
|
|
306
|
-
if (state.seenTopicAnchors.has(li)) continue;
|
|
307
|
-
|
|
308
|
-
const pos = i + 1;
|
|
309
|
-
const ok = (first && pos === 1) || (pos % interval === 0);
|
|
310
|
-
state.seenTopicAnchors.add(li);
|
|
311
|
-
if (!ok) continue;
|
|
312
|
-
|
|
313
|
-
if (hasAdImmediatelyAfter(li)) continue;
|
|
314
|
-
|
|
315
|
-
const id = nextId('between');
|
|
316
|
-
if (!id) break;
|
|
317
|
-
|
|
318
|
-
state.usedTopics.add(id);
|
|
319
|
-
const wrap = insertAfter(li, id, 'ezoic-ad-between', pos);
|
|
320
|
-
if (!wrap) continue;
|
|
321
|
-
|
|
322
|
-
inserted += 1;
|
|
323
|
-
|
|
324
|
-
callShowAdsWhenReady(id);
|
|
325
|
-
|
|
326
|
-
if (inserted >= MAX_INSERTS_PER_RUN) break;
|
|
274
|
+
function computeTargets(count, interval, showFirst) {
|
|
275
|
+
const out = [];
|
|
276
|
+
if (count <= 0) return out;
|
|
277
|
+
if (showFirst) out.push(1);
|
|
278
|
+
for (let i = 1; i <= count; i++) {
|
|
279
|
+
if (i % interval === 0) out.push(i);
|
|
327
280
|
}
|
|
328
|
-
return
|
|
281
|
+
return Array.from(new Set(out)).sort((a, b) => a - b);
|
|
329
282
|
}
|
|
330
283
|
|
|
331
|
-
function
|
|
332
|
-
if (!
|
|
333
|
-
|
|
334
|
-
const interval = Math.max(1, parseInt(cfg.messageIntervalPosts, 10) || 3);
|
|
335
|
-
const first = normalizeBool(cfg.showFirstMessageAd);
|
|
336
|
-
|
|
337
|
-
const posts = getPostContainers();
|
|
338
|
-
if (!posts.length) return 0;
|
|
284
|
+
function injectBetween(kindClass, items, interval, showFirst, kindPool, usedSet) {
|
|
285
|
+
if (!items.length) return 0;
|
|
286
|
+
const targets = computeTargets(items.length, interval, showFirst);
|
|
339
287
|
|
|
340
288
|
let inserted = 0;
|
|
341
|
-
for (
|
|
342
|
-
|
|
343
|
-
if (!post || !post.isConnected) continue;
|
|
289
|
+
for (const afterPos of targets) {
|
|
290
|
+
if (inserted >= MAX_INSERTS_PER_RUN) break;
|
|
344
291
|
|
|
345
|
-
|
|
292
|
+
const el = items[afterPos - 1];
|
|
293
|
+
if (!el || !el.isConnected) continue;
|
|
346
294
|
|
|
347
|
-
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
if (!ok) continue;
|
|
295
|
+
// Prevent back-to-back at load
|
|
296
|
+
const prevWrap = findWrap(kindClass, afterPos - 1);
|
|
297
|
+
if (prevWrap) continue;
|
|
351
298
|
|
|
352
|
-
if (
|
|
299
|
+
if (findWrap(kindClass, afterPos)) continue;
|
|
353
300
|
|
|
354
|
-
const id = nextId(
|
|
301
|
+
const id = nextId(kindPool);
|
|
355
302
|
if (!id) break;
|
|
356
303
|
|
|
357
|
-
|
|
358
|
-
const wrap = insertAfter(
|
|
304
|
+
usedSet.add(id);
|
|
305
|
+
const wrap = insertAfter(el, id, kindClass, afterPos);
|
|
359
306
|
if (!wrap) continue;
|
|
360
307
|
|
|
361
|
-
inserted += 1;
|
|
362
|
-
|
|
363
308
|
callShowAdsWhenReady(id);
|
|
364
|
-
|
|
365
|
-
if (inserted >= MAX_INSERTS_PER_RUN) break;
|
|
309
|
+
inserted += 1;
|
|
366
310
|
}
|
|
367
311
|
return inserted;
|
|
368
312
|
}
|
|
369
313
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
if (!ids.length) return;
|
|
379
|
-
|
|
380
|
-
const call = () => {
|
|
381
|
-
try {
|
|
382
|
-
if (window.ezstandalone && typeof window.ezstandalone.destroyPlaceholders === 'function') {
|
|
383
|
-
window.ezstandalone.destroyPlaceholders(ids);
|
|
384
|
-
}
|
|
385
|
-
} catch (e) {}
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
try {
|
|
389
|
-
window.ezstandalone = window.ezstandalone || {};
|
|
390
|
-
window.ezstandalone.cmd = window.ezstandalone.cmd || [];
|
|
391
|
-
|
|
392
|
-
if (window.ezstandalone && typeof window.ezstandalone.destroyPlaceholders === 'function') {
|
|
393
|
-
call();
|
|
394
|
-
} else {
|
|
395
|
-
// queue for when ezstandalone becomes ready
|
|
396
|
-
window.ezstandalone.cmd.push(call);
|
|
397
|
-
}
|
|
398
|
-
} catch (e) {}
|
|
314
|
+
function enforceNoAdjacentAds() {
|
|
315
|
+
const ads = Array.from(document.querySelectorAll(`.${WRAP_CLASS}`));
|
|
316
|
+
for (let i = 0; i < ads.length; i++) {
|
|
317
|
+
const ad = ads[i];
|
|
318
|
+
const prev = ad.previousElementSibling;
|
|
319
|
+
if (prev && prev.classList && prev.classList.contains(WRAP_CLASS)) ad.style.display = 'none';
|
|
320
|
+
else ad.style.display = '';
|
|
321
|
+
}
|
|
399
322
|
}
|
|
400
323
|
|
|
401
324
|
function cleanup() {
|
|
402
|
-
// Destroy slots for IDs we used on the previous view before we reuse the same IDs on the next page
|
|
403
325
|
destroyUsedPlaceholders();
|
|
326
|
+
|
|
404
327
|
state.pageKey = getPageKey();
|
|
405
328
|
state.cfg = null;
|
|
406
329
|
state.cfgPromise = null;
|
|
407
330
|
|
|
408
331
|
state.poolTopics = [];
|
|
409
332
|
state.poolPosts = [];
|
|
333
|
+
state.poolCategories = [];
|
|
410
334
|
state.usedTopics.clear();
|
|
411
335
|
state.usedPosts.clear();
|
|
412
|
-
|
|
413
|
-
state.seenTopicAnchors = new WeakSet();
|
|
414
|
-
state.seenPostAnchors = new WeakSet();
|
|
336
|
+
state.usedCategories.clear();
|
|
415
337
|
|
|
416
338
|
state.lastShowById = new Map();
|
|
417
339
|
state.pendingById = new Set();
|
|
418
340
|
|
|
341
|
+
state.attempts = 0;
|
|
342
|
+
|
|
419
343
|
document.querySelectorAll(`.${WRAP_CLASS}`).forEach(el => el.remove());
|
|
420
344
|
|
|
421
345
|
if (state.obs) { try { state.obs.disconnect(); } catch (e) {} state.obs = null; }
|
|
@@ -426,14 +350,13 @@
|
|
|
426
350
|
|
|
427
351
|
function ensureObserver() {
|
|
428
352
|
if (state.obs) return;
|
|
429
|
-
state.obs = new MutationObserver(() => scheduleRun('
|
|
353
|
+
state.obs = new MutationObserver(() => scheduleRun('mutation'));
|
|
430
354
|
try { state.obs.observe(document.body, { childList: true, subtree: true }); } catch (e) {}
|
|
431
|
-
setTimeout(() => { if (state.obs) { try { state.obs.disconnect(); } catch (e) {} state.obs = null; } },
|
|
355
|
+
setTimeout(() => { if (state.obs) { try { state.obs.disconnect(); } catch (e) {} state.obs = null; } }, 15000);
|
|
432
356
|
}
|
|
433
357
|
|
|
434
358
|
async function runCore() {
|
|
435
359
|
patchShowAds();
|
|
436
|
-
patchShowAds();
|
|
437
360
|
|
|
438
361
|
const cfg = await fetchConfig();
|
|
439
362
|
if (!cfg || cfg.excluded) return;
|
|
@@ -443,77 +366,106 @@
|
|
|
443
366
|
const kind = getKind();
|
|
444
367
|
let inserted = 0;
|
|
445
368
|
|
|
446
|
-
if (kind === 'topic')
|
|
447
|
-
|
|
369
|
+
if (kind === 'topic') {
|
|
370
|
+
if (normalizeBool(cfg.enableMessageAds)) {
|
|
371
|
+
inserted = injectBetween('ezoic-ad-message', getPostContainers(),
|
|
372
|
+
Math.max(1, parseInt(cfg.messageIntervalPosts, 10) || 3),
|
|
373
|
+
normalizeBool(cfg.showFirstMessageAd),
|
|
374
|
+
'message',
|
|
375
|
+
state.usedPosts);
|
|
376
|
+
}
|
|
377
|
+
} else if (kind === 'categoryTopics') {
|
|
378
|
+
if (normalizeBool(cfg.enableBetweenAds)) {
|
|
379
|
+
inserted = injectBetween('ezoic-ad-between', getTopicItems(),
|
|
380
|
+
Math.max(1, parseInt(cfg.intervalPosts, 10) || 6),
|
|
381
|
+
normalizeBool(cfg.showFirstTopicAd),
|
|
382
|
+
'between',
|
|
383
|
+
state.usedTopics);
|
|
384
|
+
}
|
|
385
|
+
} else if (kind === 'categories') {
|
|
386
|
+
if (normalizeBool(cfg.enableCategoryAds)) {
|
|
387
|
+
inserted = injectBetween('ezoic-ad-categories', getCategoryItems(),
|
|
388
|
+
Math.max(1, parseInt(cfg.intervalCategories, 10) || 4),
|
|
389
|
+
normalizeBool(cfg.showFirstCategoryAd),
|
|
390
|
+
'categories',
|
|
391
|
+
state.usedCategories);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
448
394
|
|
|
449
395
|
enforceNoAdjacentAds();
|
|
450
396
|
|
|
451
|
-
// If
|
|
452
|
-
|
|
453
|
-
|
|
397
|
+
// If nothing inserted and list isn't in DOM yet (first click), retry a bit
|
|
398
|
+
let count = 0;
|
|
399
|
+
if (kind === 'topic') count = getPostContainers().length;
|
|
400
|
+
else if (kind === 'categoryTopics') count = getTopicItems().length;
|
|
401
|
+
else if (kind === 'categories') count = getCategoryItems().length;
|
|
402
|
+
|
|
403
|
+
if (count === 0 && state.attempts < 25) {
|
|
404
|
+
state.attempts += 1;
|
|
405
|
+
setTimeout(() => scheduleRun('await-items'), 120);
|
|
406
|
+
return;
|
|
454
407
|
}
|
|
408
|
+
|
|
409
|
+
if (inserted >= MAX_INSERTS_PER_RUN) setTimeout(() => scheduleRun('continue'), 140);
|
|
455
410
|
}
|
|
456
411
|
|
|
457
|
-
function scheduleRun(
|
|
412
|
+
function scheduleRun() {
|
|
458
413
|
if (state.scheduled) return;
|
|
459
414
|
state.scheduled = true;
|
|
460
415
|
|
|
461
416
|
clearTimeout(state.timer);
|
|
462
417
|
state.timer = setTimeout(() => {
|
|
463
418
|
state.scheduled = false;
|
|
464
|
-
// Ensure we're still on same page
|
|
465
419
|
const pk = getPageKey();
|
|
466
420
|
if (state.pageKey && pk !== state.pageKey) return;
|
|
467
421
|
runCore().catch(() => {});
|
|
468
422
|
}, 80);
|
|
423
|
+
}
|
|
469
424
|
|
|
470
425
|
function bind() {
|
|
471
426
|
if (!$) return;
|
|
472
427
|
|
|
473
428
|
$(window).off('.ezoicInfinite');
|
|
474
429
|
|
|
475
|
-
$(window).on('action:ajaxify.start.ezoicInfinite', () =>
|
|
476
|
-
cleanup();
|
|
477
|
-
});
|
|
430
|
+
$(window).on('action:ajaxify.start.ezoicInfinite', () => cleanup());
|
|
478
431
|
|
|
479
432
|
$(window).on('action:ajaxify.end.ezoicInfinite', () => {
|
|
480
433
|
state.pageKey = getPageKey();
|
|
481
434
|
ensureObserver();
|
|
482
|
-
scheduleRun(
|
|
483
|
-
setTimeout(
|
|
484
|
-
setTimeout(
|
|
435
|
+
scheduleRun();
|
|
436
|
+
setTimeout(scheduleRun, 200);
|
|
437
|
+
setTimeout(scheduleRun, 700);
|
|
485
438
|
});
|
|
486
439
|
|
|
487
440
|
$(window).on('action:category.loaded.ezoicInfinite', () => {
|
|
488
441
|
ensureObserver();
|
|
489
|
-
scheduleRun(
|
|
490
|
-
setTimeout(
|
|
442
|
+
scheduleRun();
|
|
443
|
+
setTimeout(scheduleRun, 250);
|
|
491
444
|
});
|
|
492
445
|
|
|
493
446
|
$(window).on('action:topics.loaded.ezoicInfinite', () => {
|
|
494
447
|
ensureObserver();
|
|
495
|
-
scheduleRun(
|
|
496
|
-
setTimeout(
|
|
448
|
+
scheduleRun();
|
|
449
|
+
setTimeout(scheduleRun, 150);
|
|
497
450
|
});
|
|
498
451
|
|
|
499
452
|
$(window).on('action:topic.loaded.ezoicInfinite', () => {
|
|
500
453
|
ensureObserver();
|
|
501
|
-
scheduleRun(
|
|
502
|
-
setTimeout(
|
|
454
|
+
scheduleRun();
|
|
455
|
+
setTimeout(scheduleRun, 200);
|
|
503
456
|
});
|
|
504
457
|
|
|
505
458
|
$(window).on('action:posts.loaded.ezoicInfinite', () => {
|
|
506
459
|
ensureObserver();
|
|
507
|
-
scheduleRun(
|
|
508
|
-
setTimeout(
|
|
460
|
+
scheduleRun();
|
|
461
|
+
setTimeout(scheduleRun, 150);
|
|
509
462
|
});
|
|
510
463
|
}
|
|
511
464
|
|
|
512
|
-
// Boot
|
|
513
465
|
cleanup();
|
|
514
466
|
bind();
|
|
515
467
|
ensureObserver();
|
|
516
468
|
state.pageKey = getPageKey();
|
|
517
|
-
scheduleRun(
|
|
518
|
-
setTimeout(
|
|
519
|
-
})();
|
|
469
|
+
scheduleRun();
|
|
470
|
+
setTimeout(scheduleRun, 250);
|
|
471
|
+
})();
|
|
@@ -26,6 +26,32 @@
|
|
|
26
26
|
|
|
27
27
|
<hr/>
|
|
28
28
|
|
|
29
|
+
|
|
30
|
+
<hr/>
|
|
31
|
+
|
|
32
|
+
<h4 class="mt-3">Pubs entre les catégories (page d’accueil)</h4>
|
|
33
|
+
<p class="form-text">Insère des pubs entre les catégories sur la page d’accueil (liste des catégories).</p>
|
|
34
|
+
|
|
35
|
+
<div class="form-check mb-3">
|
|
36
|
+
<input class="form-check-input" type="checkbox" id="enableCategoryAds" name="enableCategoryAds">
|
|
37
|
+
<label class="form-check-label" for="enableCategoryAds">Activer les pubs entre les catégories</label>
|
|
38
|
+
<div class="form-check mt-2">
|
|
39
|
+
<input class="form-check-input" type="checkbox" name="showFirstCategoryAd" />
|
|
40
|
+
<label class="form-check-label">Afficher une pub après la 1ère catégorie</label>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="mb-3">
|
|
45
|
+
<label class="form-label" for="categoryPlaceholderIds">Pool d’IDs Ezoic (catégories)</label>
|
|
46
|
+
<textarea id="categoryPlaceholderIds" name="categoryPlaceholderIds" class="form-control" rows="4">{categoryPlaceholderIds}</textarea>
|
|
47
|
+
<p class="form-text">IDs numériques, un par ligne. Utilise un pool dédié (différent des pools topics/messages).</p>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div class="mb-3">
|
|
51
|
+
<label class="form-label" for="intervalCategories">Afficher une pub toutes les N catégories</label>
|
|
52
|
+
<input type="number" id="intervalCategories" name="intervalCategories" class="form-control" value="{intervalCategories}" min="1">
|
|
53
|
+
</div>
|
|
54
|
+
|
|
29
55
|
<h4 class="mt-3">Pubs “message” entre les réponses</h4>
|
|
30
56
|
<p class="form-text">Insère un bloc qui ressemble à un post, toutes les N réponses (dans une page topic).</p>
|
|
31
57
|
|