nodebb-plugin-ezoic-infinite 1.5.23 → 1.5.25
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 +103 -50
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
pageKey: null,
|
|
27
27
|
cfg: null,
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
// Full lists (never consumed) + cursors for round-robin reuse
|
|
30
|
+
allTopics: [],
|
|
31
|
+
allPosts: [],
|
|
32
|
+
allCategories: [],
|
|
33
|
+
curTopics: 0,
|
|
34
|
+
curPosts: 0,
|
|
35
|
+
curCategories: 0,
|
|
36
36
|
|
|
37
37
|
// throttle per placeholder id
|
|
38
38
|
lastShowById: new Map(),
|
|
@@ -46,9 +46,18 @@
|
|
|
46
46
|
heroDoneForPage: false,
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
const sessionDefinedIds = new Set();
|
|
50
49
|
const insertingIds = new Set();
|
|
51
50
|
|
|
51
|
+
// Debug logs (enable with localStorage.ezoicInfiniteDebug = "1")
|
|
52
|
+
function dbg(...args) {
|
|
53
|
+
try {
|
|
54
|
+
if (window && window.localStorage && window.localStorage.getItem('ezoicInfiniteDebug') === '1') {
|
|
55
|
+
// eslint-disable-next-line no-console
|
|
56
|
+
console.log('[ezoicInfinite]', ...args);
|
|
57
|
+
}
|
|
58
|
+
} catch (e) {}
|
|
59
|
+
}
|
|
60
|
+
|
|
52
61
|
// ---------- small utils ----------
|
|
53
62
|
|
|
54
63
|
function normalizeBool(v) {
|
|
@@ -205,9 +214,9 @@
|
|
|
205
214
|
|
|
206
215
|
function initPools(cfg) {
|
|
207
216
|
if (!cfg) return;
|
|
208
|
-
if (state.
|
|
209
|
-
if (state.
|
|
210
|
-
if (state.
|
|
217
|
+
if (state.allTopics.length === 0) state.allTopics = parsePool(cfg.placeholderIds);
|
|
218
|
+
if (state.allPosts.length === 0) state.allPosts = parsePool(cfg.messagePlaceholderIds);
|
|
219
|
+
if (state.allCategories.length === 0) state.allCategories = parsePool(cfg.categoryPlaceholderIds);
|
|
211
220
|
}
|
|
212
221
|
|
|
213
222
|
// ---------- insertion primitives ----------
|
|
@@ -257,8 +266,50 @@
|
|
|
257
266
|
}
|
|
258
267
|
}
|
|
259
268
|
|
|
260
|
-
function
|
|
261
|
-
|
|
269
|
+
function pickIdFromAll(allIds, cursorKey) {
|
|
270
|
+
const n = allIds.length;
|
|
271
|
+
if (!n) return null;
|
|
272
|
+
|
|
273
|
+
// Try at most n ids to find one that's not already in the DOM
|
|
274
|
+
for (let tries = 0; tries < n; tries++) {
|
|
275
|
+
const idx = state[cursorKey] % n;
|
|
276
|
+
state[cursorKey] = (state[cursorKey] + 1) % n;
|
|
277
|
+
|
|
278
|
+
const id = allIds[idx];
|
|
279
|
+
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
280
|
+
if (ph && ph.isConnected) continue;
|
|
281
|
+
|
|
282
|
+
return id;
|
|
283
|
+
}
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
function removeOneOldWrap(kindClass) {
|
|
289
|
+
try {
|
|
290
|
+
const wraps = Array.from(document.querySelectorAll(`.${WRAP_CLASS}.${kindClass}`));
|
|
291
|
+
if (!wraps.length) return false;
|
|
292
|
+
|
|
293
|
+
// Prefer a wrap far above the viewport
|
|
294
|
+
let victim = null;
|
|
295
|
+
for (const w of wraps) {
|
|
296
|
+
const r = w.getBoundingClientRect();
|
|
297
|
+
if (r.bottom < -2000) { victim = w; break; }
|
|
298
|
+
}
|
|
299
|
+
// Otherwise remove the earliest one in the document
|
|
300
|
+
if (!victim) victim = wraps[0];
|
|
301
|
+
|
|
302
|
+
// Unobserve placeholder if still observed
|
|
303
|
+
try {
|
|
304
|
+
const ph = victim.querySelector && victim.querySelector(`[id^="${PLACEHOLDER_PREFIX}"]`);
|
|
305
|
+
if (ph && state.io) state.io.unobserve(ph);
|
|
306
|
+
} catch (e) {}
|
|
307
|
+
|
|
308
|
+
victim.remove();
|
|
309
|
+
return true;
|
|
310
|
+
} catch (e) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
262
313
|
}
|
|
263
314
|
|
|
264
315
|
function showAd(id) {
|
|
@@ -280,7 +331,6 @@
|
|
|
280
331
|
// Fast path
|
|
281
332
|
if (typeof ez.showAds === 'function') {
|
|
282
333
|
ez.showAds(id);
|
|
283
|
-
sessionDefinedIds.add(id);
|
|
284
334
|
return;
|
|
285
335
|
}
|
|
286
336
|
|
|
@@ -294,7 +344,6 @@
|
|
|
294
344
|
const el = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
295
345
|
if (!el || !el.isConnected) return;
|
|
296
346
|
window.ezstandalone.showAds(id);
|
|
297
|
-
sessionDefinedIds.add(id);
|
|
298
347
|
} catch (e) {}
|
|
299
348
|
});
|
|
300
349
|
}
|
|
@@ -348,7 +397,7 @@
|
|
|
348
397
|
return Array.from(new Set(out)).sort((a, b) => a - b);
|
|
349
398
|
}
|
|
350
399
|
|
|
351
|
-
function injectBetween(kindClass, items, interval, showFirst,
|
|
400
|
+
function injectBetween(kindClass, items, interval, showFirst, allIds, cursorKey) {
|
|
352
401
|
if (!items.length) return 0;
|
|
353
402
|
|
|
354
403
|
const targets = computeTargets(items.length, interval, showFirst);
|
|
@@ -362,14 +411,16 @@
|
|
|
362
411
|
if (isAdjacentAd(el)) continue;
|
|
363
412
|
if (findWrap(kindClass, afterPos)) continue;
|
|
364
413
|
|
|
365
|
-
|
|
414
|
+
let id = pickIdFromAll(allIds, cursorKey);
|
|
415
|
+
if (!id) {
|
|
416
|
+
// No free ids: recycle an old ad wrapper so we can reuse its placeholder id
|
|
417
|
+
const recycled = removeOneOldWrap(kindClass);
|
|
418
|
+
dbg('recycle-needed', kindClass, { recycled, ids: allIds.length });
|
|
419
|
+
id = pickIdFromAll(allIds, cursorKey);
|
|
420
|
+
}
|
|
366
421
|
if (!id) break;
|
|
367
|
-
|
|
368
|
-
usedSet.add(id);
|
|
369
422
|
const wrap = insertAfter(el, id, kindClass, afterPos);
|
|
370
423
|
if (!wrap) {
|
|
371
|
-
usedSet.delete(id);
|
|
372
|
-
pool.unshift(id);
|
|
373
424
|
continue;
|
|
374
425
|
}
|
|
375
426
|
|
|
@@ -383,36 +434,42 @@
|
|
|
383
434
|
async function insertHeroAdEarly() {
|
|
384
435
|
if (state.heroDoneForPage) return;
|
|
385
436
|
const cfg = await fetchConfigOnce();
|
|
386
|
-
if (!cfg
|
|
437
|
+
if (!cfg) { dbg('no-config'); return; }
|
|
438
|
+
if (cfg.excluded) { dbg('excluded'); return; }
|
|
387
439
|
|
|
388
440
|
initPools(cfg);
|
|
389
441
|
|
|
390
442
|
const kind = getKind();
|
|
391
443
|
let items = [];
|
|
392
|
-
let
|
|
393
|
-
let
|
|
444
|
+
let allIds = [];
|
|
445
|
+
let cursorKey = '';
|
|
394
446
|
let kindClass = '';
|
|
447
|
+
let showFirst = false;
|
|
395
448
|
|
|
396
449
|
if (kind === 'topic' && normalizeBool(cfg.enableMessageAds)) {
|
|
397
450
|
items = getPostContainers();
|
|
398
|
-
|
|
399
|
-
|
|
451
|
+
allIds = state.allPosts;
|
|
452
|
+
cursorKey = 'curPosts';
|
|
400
453
|
kindClass = 'ezoic-ad-message';
|
|
454
|
+
showFirst = normalizeBool(cfg.showFirstMessageAd);
|
|
401
455
|
} else if (kind === 'categoryTopics' && normalizeBool(cfg.enableBetweenAds)) {
|
|
402
456
|
items = getTopicItems();
|
|
403
|
-
|
|
404
|
-
|
|
457
|
+
allIds = state.allTopics;
|
|
458
|
+
cursorKey = 'curTopics';
|
|
405
459
|
kindClass = 'ezoic-ad-between';
|
|
460
|
+
showFirst = normalizeBool(cfg.showFirstTopicAd);
|
|
406
461
|
} else if (kind === 'categories' && normalizeBool(cfg.enableCategoryAds)) {
|
|
407
462
|
items = getCategoryItems();
|
|
408
|
-
|
|
409
|
-
|
|
463
|
+
allIds = state.allCategories;
|
|
464
|
+
cursorKey = 'curCategories';
|
|
410
465
|
kindClass = 'ezoic-ad-categories';
|
|
466
|
+
showFirst = normalizeBool(cfg.showFirstCategoryAd);
|
|
411
467
|
} else {
|
|
412
468
|
return;
|
|
413
469
|
}
|
|
414
470
|
|
|
415
471
|
if (!items.length) return;
|
|
472
|
+
if (!showFirst) { state.heroDoneForPage = true; return; }
|
|
416
473
|
|
|
417
474
|
// Insert after the very first item (above-the-fold)
|
|
418
475
|
const afterPos = 1;
|
|
@@ -421,14 +478,11 @@
|
|
|
421
478
|
if (isAdjacentAd(el)) return;
|
|
422
479
|
if (findWrap(kindClass, afterPos)) { state.heroDoneForPage = true; return; }
|
|
423
480
|
|
|
424
|
-
const id =
|
|
481
|
+
const id = pickIdFromAll(allIds, cursorKey);
|
|
425
482
|
if (!id) return;
|
|
426
483
|
|
|
427
|
-
usedSet.add(id);
|
|
428
484
|
const wrap = insertAfter(el, id, kindClass, afterPos);
|
|
429
485
|
if (!wrap) {
|
|
430
|
-
usedSet.delete(id);
|
|
431
|
-
pool.unshift(id);
|
|
432
486
|
return;
|
|
433
487
|
}
|
|
434
488
|
|
|
@@ -437,12 +491,13 @@
|
|
|
437
491
|
}
|
|
438
492
|
|
|
439
493
|
async function runCore() {
|
|
440
|
-
if (EZOIC_BLOCKED) return;
|
|
494
|
+
if (EZOIC_BLOCKED) { dbg('blocked'); return; }
|
|
441
495
|
|
|
442
496
|
patchShowAds();
|
|
443
497
|
|
|
444
498
|
const cfg = await fetchConfigOnce();
|
|
445
|
-
if (!cfg
|
|
499
|
+
if (!cfg) { dbg('no-config'); return; }
|
|
500
|
+
if (cfg.excluded) { dbg('excluded'); return; }
|
|
446
501
|
initPools(cfg);
|
|
447
502
|
|
|
448
503
|
const kind = getKind();
|
|
@@ -454,8 +509,8 @@
|
|
|
454
509
|
getPostContainers(),
|
|
455
510
|
Math.max(1, parseInt(cfg.messageIntervalPosts, 10) || 3),
|
|
456
511
|
normalizeBool(cfg.showFirstMessageAd),
|
|
457
|
-
state.
|
|
458
|
-
|
|
512
|
+
state.allPosts,
|
|
513
|
+
'curPosts'
|
|
459
514
|
);
|
|
460
515
|
}
|
|
461
516
|
} else if (kind === 'categoryTopics') {
|
|
@@ -465,8 +520,8 @@
|
|
|
465
520
|
getTopicItems(),
|
|
466
521
|
Math.max(1, parseInt(cfg.intervalPosts, 10) || 6),
|
|
467
522
|
normalizeBool(cfg.showFirstTopicAd),
|
|
468
|
-
state.
|
|
469
|
-
|
|
523
|
+
state.allTopics,
|
|
524
|
+
'curTopics'
|
|
470
525
|
);
|
|
471
526
|
}
|
|
472
527
|
} else if (kind === 'categories') {
|
|
@@ -476,8 +531,8 @@
|
|
|
476
531
|
getCategoryItems(),
|
|
477
532
|
Math.max(1, parseInt(cfg.intervalCategories, 10) || 4),
|
|
478
533
|
normalizeBool(cfg.showFirstCategoryAd),
|
|
479
|
-
state.
|
|
480
|
-
|
|
534
|
+
state.allCategories,
|
|
535
|
+
'curCategories'
|
|
481
536
|
);
|
|
482
537
|
}
|
|
483
538
|
}
|
|
@@ -508,17 +563,15 @@
|
|
|
508
563
|
|
|
509
564
|
// reset state
|
|
510
565
|
state.cfg = null;
|
|
511
|
-
state.
|
|
512
|
-
state.
|
|
513
|
-
state.
|
|
514
|
-
state.
|
|
515
|
-
state.
|
|
516
|
-
state.
|
|
566
|
+
state.allTopics = [];
|
|
567
|
+
state.allPosts = [];
|
|
568
|
+
state.allCategories = [];
|
|
569
|
+
state.curTopics = 0;
|
|
570
|
+
state.curPosts = 0;
|
|
571
|
+
state.curCategories = 0;
|
|
517
572
|
state.lastShowById.clear();
|
|
518
573
|
state.heroDoneForPage = false;
|
|
519
574
|
|
|
520
|
-
sessionDefinedIds.clear();
|
|
521
|
-
|
|
522
575
|
// keep observers alive (MutationObserver will re-trigger after navigation)
|
|
523
576
|
}
|
|
524
577
|
|