nodebb-plugin-ezoic-infinite 1.5.40 → 1.5.41

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.5.40",
3
+ "version": "1.5.41",
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
@@ -318,6 +318,27 @@ function mutationHasRelevantAddedNodes(mutations) {
318
318
  if (adSpan.tagName !== 'SPAN') return;
319
319
  if (!adSpan.classList || !adSpan.classList.contains('ezoic-ad')) return;
320
320
 
321
+ // Some Ezoic templates apply sticky/fixed positioning inside the ad slot
322
+ // (e.g. .ezads-sticky-intradiv) which can make the creative appear to
323
+ // "slide" within an oversized container. Neutralize it inside the slot.
324
+ try {
325
+ const sticky = adSpan.querySelectorAll('.ezads-sticky-intradiv');
326
+ sticky.forEach((el) => {
327
+ el.style.setProperty('position', 'static', 'important');
328
+ el.style.setProperty('top', 'auto', 'important');
329
+ el.style.setProperty('bottom', 'auto', 'important');
330
+ });
331
+
332
+ // Safety net: any descendant that ends up sticky/fixed via inline style
333
+ // (rare, but causes "floating" creatives).
334
+ const positioned = adSpan.querySelectorAll('[style*="position: sticky"], [style*="position:sticky"], [style*="position: fixed"], [style*="position:fixed"]');
335
+ positioned.forEach((el) => {
336
+ el.style.setProperty('position', 'static', 'important');
337
+ el.style.setProperty('top', 'auto', 'important');
338
+ el.style.setProperty('bottom', 'auto', 'important');
339
+ });
340
+ } catch (e) {}
341
+
321
342
  const mhStr = adSpan.style && adSpan.style.minHeight ? String(adSpan.style.minHeight) : '';
322
343
  const mh = mhStr ? parseInt(mhStr, 10) : 0;
323
344
  if (!mh || mh < 350) return; // only fix the "400px"-style reservations
@@ -1026,9 +1047,27 @@ function startShow(id) {
1026
1047
  ensureTightenObserver();
1027
1048
  ensurePreloadObserver();
1028
1049
  ensureDomObserver();
1029
-
1030
1050
  bindNodeBB();
1031
1051
 
1052
+ // Lightweight scroll kick: NodeBB infinite scroll can keep many nodes and only append occasionally.
1053
+ // Without a scroll trigger, we might not inject new placeholders until another DOM mutation occurs.
1054
+ // This is throttled and only triggers near the bottom to keep CPU usage minimal.
1055
+ state.lastScrollKick = 0;
1056
+ window.addEventListener('scroll', () => {
1057
+ const now = Date.now();
1058
+ if (now - state.lastScrollKick < 250) return;
1059
+ state.lastScrollKick = now;
1060
+
1061
+ // Only kick when user is approaching the end of currently rendered content
1062
+ const doc = document.documentElement;
1063
+ const scrollTop = window.pageYOffset || doc.scrollTop || 0;
1064
+ const viewportH = window.innerHeight || doc.clientHeight || 0;
1065
+ const fullH = Math.max(doc.scrollHeight, document.body ? document.body.scrollHeight : 0);
1066
+ if (scrollTop + viewportH > fullH - 2000) {
1067
+ if (!isBlocked()) scheduleRun();
1068
+ }
1069
+ }, { passive: true });
1070
+
1032
1071
  // First paint: try hero + run
1033
1072
  blockedUntil = 0;
1034
1073
  insertHeroAdEarly().catch(() => {});
package/public/style.css CHANGED
@@ -6,4 +6,6 @@
6
6
  .ezoic-ad {
7
7
  display: block;
8
8
  width: 100%;
9
+ clear: both;
10
+ position: relative;
9
11
  }