nodebb-plugin-ezoic-infinite 1.5.77 → 1.5.79
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 +65 -16
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
const POOL_ID = 'nodebb-ezoic-placeholder-pool';
|
|
11
11
|
|
|
12
12
|
// Smoothness caps
|
|
13
|
-
|
|
13
|
+
// Limit how many placements we inject per scan pass.
|
|
14
|
+
// Too low = you end up with only a handful of placeholders after ajaxify.
|
|
15
|
+
// Too high = jank on very long pages.
|
|
16
|
+
const MAX_INSERTS_PER_RUN = 8;
|
|
14
17
|
|
|
15
18
|
// Keep empty (unfilled) wraps alive for a while. Topics/messages can fill late (auction/CMP).
|
|
16
19
|
// Pruning too early makes ads look like they "disappear" while scrolling.
|
|
@@ -19,9 +22,11 @@
|
|
|
19
22
|
|
|
20
23
|
// Preload margins
|
|
21
24
|
const PRELOAD_MARGIN_DESKTOP = '2600px 0px 2600px 0px';
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
+
// Mobile: larger preload window so ad fill requests start earlier and
|
|
26
|
+
// users don't scroll past empty placeholders.
|
|
27
|
+
const PRELOAD_MARGIN_MOBILE = '3200px 0px 3200px 0px';
|
|
28
|
+
const PRELOAD_MARGIN_DESKTOP_BOOST = '5200px 0px 5200px 0px';
|
|
29
|
+
const PRELOAD_MARGIN_MOBILE_BOOST = '5200px 0px 5200px 0px';
|
|
25
30
|
|
|
26
31
|
const BOOST_DURATION_MS = 2500;
|
|
27
32
|
const BOOST_SPEED_PX_PER_MS = 2.2; // ~2200px/s
|
|
@@ -586,12 +591,11 @@ function globalGapFixInit() {
|
|
|
586
591
|
if (!state.allPosts.length) state.allPosts = parsePool(cfg.messagePlaceholderIds);
|
|
587
592
|
if (!state.allCategories.length) state.allCategories = parsePool(cfg.categoryPlaceholderIds);
|
|
588
593
|
|
|
589
|
-
//
|
|
590
|
-
//
|
|
591
|
-
//
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
primePlaceholderPool(state.allCategories);
|
|
594
|
+
// IMPORTANT:
|
|
595
|
+
// We do NOT prime a DOM pool anymore.
|
|
596
|
+
// Keeping placeholders connected (even offscreen) can lead Ezoic/GPT to
|
|
597
|
+
// pre-define slots, which then causes "Placeholder Id X has already been defined".
|
|
598
|
+
// Instead, we create the placeholder element only when we actually inject its wrapper.
|
|
595
599
|
}
|
|
596
600
|
|
|
597
601
|
// ---------------- insertion primitives ----------------
|
|
@@ -749,11 +753,24 @@ function globalGapFixInit() {
|
|
|
749
753
|
if (prev.getAttribute && prev.getAttribute('data-ezoic-pin') === '1') break;
|
|
750
754
|
} catch (e) {}
|
|
751
755
|
|
|
752
|
-
//
|
|
753
|
-
//
|
|
756
|
+
// Never remove a wrap that is already filled; otherwise it looks like
|
|
757
|
+
// ads "disappear" while scrolling. Only remove the empty neighbour.
|
|
754
758
|
const prevFilled = isFilled(prev);
|
|
755
759
|
const curFilled = isFilled(w);
|
|
756
|
-
|
|
760
|
+
|
|
761
|
+
if (curFilled) {
|
|
762
|
+
// If the previous one is empty (and not fresh), drop the previous instead.
|
|
763
|
+
if (!prevFilled && !isFresh(prev)) {
|
|
764
|
+
withInternalDomChange(() => releaseWrapNode(prev));
|
|
765
|
+
removed++;
|
|
766
|
+
}
|
|
767
|
+
break;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// Current is empty.
|
|
771
|
+
// Don't decluster two "fresh" empty wraps — it can reduce fill on slow auctions.
|
|
772
|
+
// Only decluster when previous is filled, or when current is stale.
|
|
773
|
+
if (prevFilled || !isFresh(w)) {
|
|
757
774
|
withInternalDomChange(() => releaseWrapNode(w));
|
|
758
775
|
removed++;
|
|
759
776
|
}
|
|
@@ -815,10 +832,16 @@ function globalGapFixInit() {
|
|
|
815
832
|
try { io && io.observe(ph); } catch (e) {}
|
|
816
833
|
|
|
817
834
|
// If already near viewport, fire immediately.
|
|
835
|
+
// Mobile tends to scroll faster + has slower auctions, so we fire earlier.
|
|
818
836
|
try {
|
|
819
837
|
const r = ph.getBoundingClientRect();
|
|
820
|
-
const
|
|
821
|
-
const
|
|
838
|
+
const mobile = isMobile();
|
|
839
|
+
const screens = isBoosted()
|
|
840
|
+
? (mobile ? 9.0 : 5.0)
|
|
841
|
+
: (mobile ? 6.0 : 3.0);
|
|
842
|
+
const minBottom = isBoosted()
|
|
843
|
+
? (mobile ? -2600 : -1500)
|
|
844
|
+
: (mobile ? -1400 : -800);
|
|
822
845
|
if (r.top < window.innerHeight * screens && r.bottom > minBottom) enqueueShow(id);
|
|
823
846
|
} catch (e) {}
|
|
824
847
|
}
|
|
@@ -908,6 +931,16 @@ function globalGapFixInit() {
|
|
|
908
931
|
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
909
932
|
if (!ph || !ph.isConnected) return;
|
|
910
933
|
|
|
934
|
+
// If the placeholder already has creative, avoid re-showing.
|
|
935
|
+
// Re-showing is a common source of "Placeholder Id X has already been defined".
|
|
936
|
+
try {
|
|
937
|
+
if (ph.querySelector && ph.querySelector('iframe, ins, img, video, [data-google-container-id]')) {
|
|
938
|
+
clearTimeout(hardTimer);
|
|
939
|
+
release();
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
} catch (e) {}
|
|
943
|
+
|
|
911
944
|
const t = now();
|
|
912
945
|
const last = state.lastShowById.get(id) || 0;
|
|
913
946
|
if (t - last < 900) return;
|
|
@@ -1245,13 +1278,29 @@ function globalGapFixInit() {
|
|
|
1245
1278
|
requestBurst();
|
|
1246
1279
|
});
|
|
1247
1280
|
|
|
1281
|
+
// Some setups populate content in multiple phases; ensure we re-scan.
|
|
1282
|
+
$(window).on('action:ajaxify.contentLoaded.ezoicInfinite', () => {
|
|
1283
|
+
if (isBlocked()) return;
|
|
1284
|
+
requestBurst();
|
|
1285
|
+
});
|
|
1286
|
+
|
|
1248
1287
|
$(window).on(
|
|
1249
|
-
'action:posts.loaded.ezoicInfinite action:topics.loaded.ezoicInfinite action:category.loaded.ezoicInfinite action:topic.loaded.ezoicInfinite',
|
|
1288
|
+
'action:posts.loaded.ezoicInfinite action:topics.loaded.ezoicInfinite action:categories.loaded.ezoicInfinite action:category.loaded.ezoicInfinite action:topic.loaded.ezoicInfinite',
|
|
1250
1289
|
() => {
|
|
1251
1290
|
if (isBlocked()) return;
|
|
1252
1291
|
requestBurst();
|
|
1253
1292
|
}
|
|
1254
1293
|
);
|
|
1294
|
+
|
|
1295
|
+
// Also listen through NodeBB's AMD hooks module when available.
|
|
1296
|
+
try {
|
|
1297
|
+
require(['hooks'], (hooks) => {
|
|
1298
|
+
if (!hooks || typeof hooks.on !== 'function') return;
|
|
1299
|
+
['action:ajaxify.end', 'action:ajaxify.contentLoaded', 'action:posts.loaded', 'action:topics.loaded', 'action:categories.loaded', 'action:category.loaded', 'action:topic.loaded'].forEach((ev) => {
|
|
1300
|
+
try { hooks.on(ev, () => { if (!isBlocked()) requestBurst(); }); } catch (e) {}
|
|
1301
|
+
});
|
|
1302
|
+
});
|
|
1303
|
+
} catch (e) {}
|
|
1255
1304
|
}
|
|
1256
1305
|
|
|
1257
1306
|
function bindScroll() {
|