nodebb-plugin-ezoic-infinite 1.5.71 → 1.5.72

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/client.js +66 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.5.71",
3
+ "version": "1.5.72",
4
4
  "description": "Production-ready Ezoic infinite ads integration for NodeBB 4.x",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/public/client.js CHANGED
@@ -12,6 +12,10 @@
12
12
  // Smoothness caps
13
13
  const MAX_INSERTS_PER_RUN = 3;
14
14
 
15
+ // Keep empty (unfilled) wraps alive for a while. Topics/messages can fill late (auction/CMP).
16
+ // Pruning too early makes ads look like they "disappear" while scrolling.
17
+ const KEEP_EMPTY_WRAP_MS = 30000;
18
+
15
19
  // Preload margins
16
20
  const PRELOAD_MARGIN_DESKTOP = '2600px 0px 2600px 0px';
17
21
  const PRELOAD_MARGIN_MOBILE = '1500px 0px 1500px 0px';
@@ -207,6 +211,22 @@
207
211
  return el;
208
212
  }
209
213
 
214
+ function primePlaceholderPool(allIds) {
215
+ try {
216
+ if (!Array.isArray(allIds) || !allIds.length) return;
217
+ const pool = getPoolEl();
218
+ for (const id of allIds) {
219
+ if (!id) continue;
220
+ const domId = `${PLACEHOLDER_PREFIX}${id}`;
221
+ if (document.getElementById(domId)) continue;
222
+ const ph = document.createElement('div');
223
+ ph.id = domId;
224
+ ph.setAttribute('data-ezoic-id', String(id));
225
+ pool.appendChild(ph);
226
+ }
227
+ } catch (e) {}
228
+ }
229
+
210
230
  function isInPool(ph) {
211
231
  try { return !!(ph && ph.closest && ph.closest('#' + POOL_ID)); } catch (e) { return false; }
212
232
  }
@@ -319,6 +339,13 @@
319
339
  if (!state.allTopics.length) state.allTopics = parsePool(cfg.placeholderIds);
320
340
  if (!state.allPosts.length) state.allPosts = parsePool(cfg.messagePlaceholderIds);
321
341
  if (!state.allCategories.length) state.allCategories = parsePool(cfg.categoryPlaceholderIds);
342
+
343
+ // Create placeholders up-front in an offscreen pool.
344
+ // Ezoic may attempt to define/show ids during load; if they don't exist yet,
345
+ // it can spam errors and sometimes short-circuit. Pooling keeps ids existing without layout.
346
+ primePlaceholderPool(state.allTopics);
347
+ primePlaceholderPool(state.allPosts);
348
+ primePlaceholderPool(state.allCategories);
322
349
  }
323
350
 
324
351
  // ---------------- insertion primitives ----------------
@@ -328,6 +355,7 @@
328
355
  wrap.className = `${WRAP_CLASS} ${kindClass}`;
329
356
  wrap.setAttribute('data-ezoic-after', String(afterPos));
330
357
  wrap.setAttribute('data-ezoic-wrapid', String(id));
358
+ wrap.setAttribute('data-created', String(now()));
331
359
  wrap.style.width = '100%';
332
360
 
333
361
  if (createPlaceholder) {
@@ -398,12 +426,12 @@
398
426
  const hasNearbyItem = (wrap) => {
399
427
  // NodeBB/skins can inject separators/spacers; be tolerant.
400
428
  let prev = wrap.previousElementSibling;
401
- for (let i = 0; i < 8 && prev; i++) {
429
+ for (let i = 0; i < 14 && prev; i++) {
402
430
  if (itemSet.has(prev)) return true;
403
431
  prev = prev.previousElementSibling;
404
432
  }
405
433
  let next = wrap.nextElementSibling;
406
- for (let i = 0; i < 8 && next; i++) {
434
+ for (let i = 0; i < 14 && next; i++) {
407
435
  if (itemSet.has(next)) return true;
408
436
  next = next.nextElementSibling;
409
437
  }
@@ -412,6 +440,13 @@
412
440
 
413
441
  wraps.forEach((wrap) => {
414
442
  if (isFilled(wrap)) return; // never prune filled ads
443
+
444
+ // Never prune a fresh wrap: it may fill late.
445
+ try {
446
+ const created = parseInt(wrap.getAttribute('data-created') || '0', 10);
447
+ if (created && (now() - created) < KEEP_EMPTY_WRAP_MS) return;
448
+ } catch (e) {}
449
+
415
450
  if (hasNearbyItem(wrap)) return;
416
451
 
417
452
  withInternalDomChange(() => releaseWrapNode(wrap));
@@ -428,13 +463,32 @@
428
463
 
429
464
  const isWrap = (el) => !!(el && el.classList && el.classList.contains(WRAP_CLASS));
430
465
 
466
+ const isFilled = (wrap) => {
467
+ return !!(wrap && wrap.querySelector && wrap.querySelector('iframe, ins, img, video, [data-google-container-id]'));
468
+ };
469
+
470
+ const isFresh = (wrap) => {
471
+ try {
472
+ const created = parseInt(wrap.getAttribute('data-created') || '0', 10);
473
+ return created && (now() - created) < KEEP_EMPTY_WRAP_MS;
474
+ } catch (e) {
475
+ return false;
476
+ }
477
+ };
478
+
431
479
  let removed = 0;
432
480
  for (const w of wraps) {
433
481
  let prev = w.previousElementSibling;
434
482
  for (let i = 0; i < 3 && prev; i++) {
435
483
  if (isWrap(prev)) {
436
- withInternalDomChange(() => releaseWrapNode(w));
437
- removed++;
484
+ // Don't decluster two "fresh" empty wraps — it can reduce fill on slow auctions.
485
+ // Only decluster when at least one is filled, or when the newer one is stale.
486
+ const prevFilled = isFilled(prev);
487
+ const curFilled = isFilled(w);
488
+ if (prevFilled || curFilled || !isFresh(w)) {
489
+ withInternalDomChange(() => releaseWrapNode(w));
490
+ removed++;
491
+ }
438
492
  break;
439
493
  }
440
494
  prev = prev.previousElementSibling;
@@ -545,10 +599,17 @@
545
599
  if (!ph2 || !ph2.isConnected) return;
546
600
  const w2 = ph2.closest ? ph2.closest(`.${WRAP_CLASS}`) : null;
547
601
  if (!w2) return;
602
+
603
+ // Don't collapse "fresh" placements; slow auctions/CMP can fill late.
604
+ try {
605
+ const created = parseInt(w2.getAttribute('data-created') || '0', 10);
606
+ if (created && (now() - created) < KEEP_EMPTY_WRAP_MS) return;
607
+ } catch (e) {}
608
+
548
609
  const hasAd = !!(ph2.querySelector && ph2.querySelector('iframe, ins, img, .ez-ad, .ezoic-ad'));
549
610
  if (!hasAd) w2.classList.add('is-empty');
550
611
  } catch (e) {}
551
- }, 3500);
612
+ }, 15000);
552
613
  } catch (e) {}
553
614
  }
554
615