nodebb-plugin-ezoic-infinite 1.5.80 → 1.5.81

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 +22 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.5.80",
3
+ "version": "1.5.81",
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
@@ -704,9 +704,10 @@ function globalGapFixInit() {
704
704
  }
705
705
 
706
706
  function pruneOrphanWraps(kindClass, items) {
707
- // Message ads should remain stable (desktop + mobile). Pruning them can make it look like
708
- // ads vanish on scroll and can reduce fill on long topics.
709
- if (kindClass === 'ezoic-ad-message') return 0;
707
+ // Topic pages can be virtualized (posts removed from DOM as you scroll).
708
+ // When that happens, previously-inserted ad wraps may become "orphan" nodes with no
709
+ // nearby post containers, which leads to ads clustering together when scrolling back up.
710
+ // We prune only *true* orphans that are far offscreen to keep the UI stable.
710
711
  if (!items || !items.length) return 0;
711
712
  const itemSet = new Set(items);
712
713
  const wraps = document.querySelectorAll(`.${WRAP_CLASS}.${kindClass}`);
@@ -737,7 +738,10 @@ function globalGapFixInit() {
737
738
  if (wrap.getAttribute('data-ezoic-pin') === '1') return;
738
739
  } catch (e) {}
739
740
 
740
- if (isFilled(wrap)) return; // never prune filled ads
741
+ // For message/topic pages we may prune filled or empty orphans if they are far away,
742
+ // otherwise consecutive "stacks" can appear when posts are virtualized.
743
+ const isMessage = (kindClass === 'ezoic-ad-message');
744
+ if (!isMessage && isFilled(wrap)) return; // never prune filled ads for non-message lists
741
745
 
742
746
  // Never prune a fresh wrap: it may fill late.
743
747
  try {
@@ -747,6 +751,20 @@ function globalGapFixInit() {
747
751
 
748
752
  if (hasNearbyItem(wrap)) return;
749
753
 
754
+ // For message ads: only prune if far offscreen to avoid perceived "vanishing".
755
+ if (isMessage) {
756
+ try {
757
+ const r = wrap.getBoundingClientRect();
758
+ const vh = Math.max(1, window.innerHeight || 1);
759
+ const farAbove = r.bottom < -vh * 2;
760
+ const farBelow = r.top > vh * 4;
761
+ if (!farAbove && !farBelow) return;
762
+ } catch (e) {
763
+ // If we can't measure, be conservative.
764
+ return;
765
+ }
766
+ }
767
+
750
768
  withInternalDomChange(() => releaseWrapNode(wrap));
751
769
  removed++;
752
770
  });