nodebb-plugin-ezoic-infinite 0.8.2 → 0.8.5

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 +67 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "0.8.2",
3
+ "version": "0.8.5",
4
4
  "description": "Ezoic ads with infinite scroll using a pool of placeholder IDs",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/public/client.js CHANGED
@@ -25,7 +25,8 @@ let fifoCat = []; // [{afterPos, id}]
25
25
  function resetState() {
26
26
  seenAfterPostNo = new Set();
27
27
  seenAfterTopicPos = new Set();
28
- usedIds = new Set();
28
+ usedIdsMsg = new Set();
29
+ usedIdsBetween = new Set();
29
30
  fifo = [];
30
31
  fifoCat = [];
31
32
  }
@@ -108,9 +109,9 @@ function cleanupOnNav() {
108
109
  $('.ezoic-ad-post, .ezoic-ad-topic').remove();
109
110
  }
110
111
 
111
- function pickNextId(pool) {
112
+ function pickNextId(pool, usedSet) {
112
113
  for (const id of pool) {
113
- if (!usedIds.has(id)) return id;
114
+ if (!usedSet.has(id)) return id;
114
115
  }
115
116
  return null;
116
117
  }
@@ -151,7 +152,7 @@ function recycleOldestTopicId($posts) {
151
152
  } catch (e) {}
152
153
 
153
154
  $el.remove();
154
- usedIds.delete(old.id);
155
+ usedIdsMsg.delete(old.id);
155
156
  destroyEzoicId(old.id);
156
157
  return old.id;
157
158
  }
@@ -177,7 +178,7 @@ function recycleOldestCategoryId($items) {
177
178
  } catch (e) {}
178
179
 
179
180
  $el.remove();
180
- usedIds.delete(old.id);
181
+ usedIdsBetween.delete(old.id);
181
182
  destroyEzoicId(old.id);
182
183
  return old.id;
183
184
  }
@@ -214,7 +215,30 @@ function callEzoic(ids) {
214
215
  window.ezstandalone = window.ezstandalone || {};
215
216
  window.ezstandalone.cmd = window.ezstandalone.cmd || [];
216
217
 
217
- // Collect unrendered wrappers (prevents duplicates even if events fire multiple times)
218
+ const markAndFilterByIds = function (list) {
219
+ const out = [];
220
+ list.forEach(function (id) {
221
+ const sel = '.ezoic-ad[data-ezoic-id="' + id + '"]';
222
+ const wraps = document.querySelectorAll(sel);
223
+ let anyUnrendered = false;
224
+ wraps.forEach(function (w) {
225
+ if (w.getAttribute('data-ezoic-rendered') !== '1') {
226
+ anyUnrendered = true;
227
+ }
228
+ });
229
+ if (!wraps.length) {
230
+ // fallback: if wrapper is missing, allow showAds (Ezoic might still handle placeholder)
231
+ out.push(id);
232
+ return;
233
+ }
234
+ if (anyUnrendered) {
235
+ wraps.forEach(function (w) { w.setAttribute('data-ezoic-rendered', '1'); });
236
+ out.push(id);
237
+ }
238
+ });
239
+ return out;
240
+ };
241
+
218
242
  const collect = function () {
219
243
  const list = [];
220
244
  document.querySelectorAll('.ezoic-ad').forEach(function (wrap) {
@@ -224,16 +248,25 @@ function callEzoic(ids) {
224
248
  const idStr = ph.id.replace('ezoic-pub-ad-placeholder-', '');
225
249
  const id = parseInt(idStr, 10);
226
250
  if (!Number.isFinite(id) || id <= 0) return;
227
-
228
251
  wrap.setAttribute('data-ezoic-rendered', '1');
229
252
  list.push(id);
230
253
  });
231
254
  return Array.from(new Set(list));
232
255
  };
233
256
 
234
- const toShow = (ids && ids.length) ? Array.from(new Set(ids)) : collect();
257
+ const input = (ids && ids.length) ? Array.from(new Set(ids)) : null;
258
+ const toShow = input ? markAndFilterByIds(input) : collect();
235
259
  if (!toShow.length) return;
236
260
 
261
+ // De-dupe rapid duplicate calls (observer/poller can fire twice)
262
+ const key = toShow.join(',');
263
+ const now = Date.now();
264
+ if (window.__ezoicLastShowKey === key && (now - (window.__ezoicLastShowAt || 0)) < 1200) {
265
+ return;
266
+ }
267
+ window.__ezoicLastShowKey = key;
268
+ window.__ezoicLastShowAt = now;
269
+
237
270
  const run = function () {
238
271
  try {
239
272
  if (typeof window.ezstandalone.showAds === 'function') {
@@ -247,13 +280,16 @@ function callEzoic(ids) {
247
280
  setupAdAutoHeight();
248
281
  window.ezstandalone.cmd.push(function () { run(); });
249
282
 
250
- // Retry if Ezoic loads late
283
+ // Retry only if showAds isn't available yet
251
284
  let tries = 0;
252
285
  const maxTries = 6;
253
286
  const retry = function () {
254
287
  tries++;
255
288
  const ok = run();
256
289
  if (ok) return;
290
+ try {
291
+ if (typeof window.ezstandalone.showAds === 'function') return;
292
+ } catch (e) {}
257
293
  if (tries < maxTries) setTimeout(retry, 800);
258
294
  };
259
295
 
@@ -301,7 +337,7 @@ function injectTopicMessageAds($posts, pool, interval) {
301
337
  if (postNo % interval !== 0) return;
302
338
  if (seenAfterPostNo.has(postNo)) return;
303
339
 
304
- let id = pickNextId(pool);
340
+ let id = pickNextId(pool, usedIdsMsg);
305
341
  if (!id) {
306
342
  id = recycleOldestTopicId($posts);
307
343
  if (!id) return;
@@ -318,7 +354,7 @@ function injectTopicMessageAds($posts, pool, interval) {
318
354
  $p.after(html);
319
355
 
320
356
  seenAfterPostNo.add(postNo);
321
- usedIds.add(id);
357
+ usedIdsMsg.add(id);
322
358
  fifo.push({ afterPostNo: postNo, id: id });
323
359
  newIds.push(id);
324
360
  });
@@ -340,7 +376,7 @@ function injectCategoryBetweenAds($items, pool, interval) {
340
376
  if (pos % interval !== 0) return;
341
377
  if (seenAfterTopicPos.has(pos)) return;
342
378
 
343
- let id = pickNextId(pool);
379
+ let id = pickNextId(pool, usedIdsBetween);
344
380
  if (!id) {
345
381
  id = recycleOldestCategoryId($items);
346
382
  if (!id) return;
@@ -357,7 +393,7 @@ function injectCategoryBetweenAds($items, pool, interval) {
357
393
  $it.after(html);
358
394
 
359
395
  seenAfterTopicPos.add(pos);
360
- usedIds.add(id);
396
+ usedIdsBetween.add(id);
361
397
  fifoCat.push({ afterPos: pos, id: id });
362
398
  newIds.push(id);
363
399
  });
@@ -410,7 +446,6 @@ async function refreshAds() {
410
446
  newIds.push(...injectTopicMessageAds($posts, messagePool, messageInterval));
411
447
  }
412
448
  callEzoic(newIds);
413
- callEzoic();
414
449
  }
415
450
  } finally {
416
451
  inFlight = false;
@@ -428,6 +463,24 @@ function debounceRefresh() {
428
463
 
429
464
  $(document).ready(function () { setupAdAutoHeight(); debounceRefresh(); });
430
465
 
466
+ $(window).on('action:ajaxify.start', function (ev, data) {
467
+ // IMPORTANT: do not cleanup on infinite scroll loads; only when navigating to a different page.
468
+ try {
469
+ const targetUrl = (data && (data.url || data.href)) ? String(data.url || data.href) : '';
470
+ if (targetUrl) {
471
+ const a = document.createElement('a');
472
+ a.href = targetUrl;
473
+ const targetPath = a.pathname || targetUrl;
474
+ // If we're staying on the same logical page (same path), don't wipe ads/state
475
+ if (targetPath === window.location.pathname) {
476
+ return;
477
+ }
478
+ }
479
+ } catch (e) {}
480
+ pageKey = null;
481
+ resetState();
482
+ cleanupOnNav();
483
+ });
431
484
  $(window).on('action:ajaxify.end action:posts.loaded action:topic.loaded action:topics.loaded action:category.loaded', debounceRefresh);
432
485
 
433
486
  setTimeout(function () { setupAdAutoHeight(); debounceRefresh(); }, 2200);