nodebb-plugin-ezoic-infinite 1.5.83 → 1.5.85

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 +8 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.5.83",
3
+ "version": "1.5.85",
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
@@ -1102,9 +1102,10 @@ function buildOrdinalMap(items) {
1102
1102
  // This avoids "Placeholder Id X has already been defined" and also ensures ads keep
1103
1103
  // appearing on very long infinite scroll sessions.
1104
1104
  if (!id) {
1105
- // Only recycle while scrolling down. Recycling while scrolling up tends to
1106
- // cause perceived instability (ads bunching/disappearing).
1107
- recycledWrap = scrollDir > 0 ? pickRecyclableWrap(kindClass) : null;
1105
+ // Safe mode: disable recycling for topic message ads to prevent visual "jumping"
1106
+ // (ads seemingly moving back under the first post during virtualized scroll).
1107
+ const allowRecycle = false; // hard-disable recycling to prevent wrappers jumping to top on virtualized/infinite scroll
1108
+ recycledWrap = (allowRecycle && scrollDir > 0) ? pickRecyclableWrap(kindClass) : null;
1108
1109
  if (recycledWrap) {
1109
1110
  id = recycledWrap.getAttribute('data-ezoic-wrapid') || '';
1110
1111
  }
@@ -1142,6 +1143,7 @@ function buildOrdinalMap(items) {
1142
1143
  let bestBottom = Infinity;
1143
1144
  for (const w of wraps) {
1144
1145
  if (!w || !w.isConnected) continue;
1146
+ if (w.getAttribute && w.getAttribute('data-ezoic-pin') === '1') continue;
1145
1147
  const rect = w.getBoundingClientRect();
1146
1148
  if (rect.bottom < threshold) {
1147
1149
  if (rect.bottom < bestBottom) {
@@ -1163,17 +1165,6 @@ function buildOrdinalMap(items) {
1163
1165
  // Ensure minimal layout impact.
1164
1166
  try { wrap.style.contain = 'layout style paint'; } catch (e) {}
1165
1167
  try { tightenStickyIn(wrap); } catch (e) {}
1166
-
1167
- const id = wrap.getAttribute('data-ezoic-wrapid');
1168
- if (id) {
1169
- setTimeout(() => {
1170
- try {
1171
- if (window.ezstandalone && typeof window.ezstandalone.showAds === 'function') {
1172
- window.ezstandalone.showAds(id);
1173
- }
1174
- } catch (e) {}
1175
- }, 0);
1176
- }
1177
1168
  return wrap;
1178
1169
  } catch (e) {
1179
1170
  return null;
@@ -1204,7 +1195,7 @@ function buildOrdinalMap(items) {
1204
1195
  state.allPosts,
1205
1196
  'curPosts'
1206
1197
  );
1207
- decluster('ezoic-ad-message');
1198
+ // decluster disabled for stability on virtualized lists
1208
1199
  }
1209
1200
  } else if (kind === 'categoryTopics') {
1210
1201
  if (normalizeBool(cfg.enableBetweenAds)) {
@@ -1218,7 +1209,7 @@ function buildOrdinalMap(items) {
1218
1209
  state.allTopics,
1219
1210
  'curTopics'
1220
1211
  );
1221
- decluster('ezoic-ad-between');
1212
+ // decluster disabled for stability on virtualized lists
1222
1213
  }
1223
1214
  } else if (kind === 'categories') {
1224
1215
  if (normalizeBool(cfg.enableCategoryAds)) {
@@ -1232,7 +1223,7 @@ function buildOrdinalMap(items) {
1232
1223
  state.allCategories,
1233
1224
  'curCategories'
1234
1225
  );
1235
- decluster('ezoic-ad-categories');
1226
+ // decluster disabled for stability on virtualized lists
1236
1227
  }
1237
1228
  }
1238
1229