nodebb-plugin-ezoic-infinite 1.1.0 → 1.1.2

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 +78 -32
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
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
@@ -118,33 +118,13 @@
118
118
  function callShowAdsSingle(id) {
119
119
  if (!id) return;
120
120
  const key = String(id);
121
+ const placeholderId = `${PLACEHOLDER_PREFIX}${id}`;
121
122
 
122
- const now = Date.now();
123
- const last = state.lastShowById[key] || 0;
124
- if (now - last < 4000) return;
125
-
126
- // If showAds is ready, call once and return
127
- try {
128
- window.ezstandalone = window.ezstandalone || {};
129
- if (typeof window.ezstandalone.showAds === 'function') {
130
- state.lastShowById[key] = now;
131
- window.ezstandalone.showAds(id);
132
- return;
133
- }
134
- } catch (e) {}
135
-
136
- // Otherwise, queue a single pending attempt (per id)
137
- if (state.pendingById[key]) return;
138
- state.pendingById[key] = true;
139
-
140
- window.ezstandalone = window.ezstandalone || {};
141
- window.ezstandalone.cmd = window.ezstandalone.cmd || [];
142
-
143
- const tryRun = () => {
123
+ const doCall = () => {
144
124
  try {
125
+ window.ezstandalone = window.ezstandalone || {};
145
126
  if (typeof window.ezstandalone.showAds === 'function') {
146
127
  state.lastShowById[key] = Date.now();
147
- delete state.pendingById[key];
148
128
  window.ezstandalone.showAds(id);
149
129
  return true;
150
130
  }
@@ -152,19 +132,56 @@
152
132
  return false;
153
133
  };
154
134
 
155
- window.ezstandalone.cmd.push(() => { tryRun(); });
135
+ // Wait until the placeholder exists in the DOM (critical on ajaxify navigation)
136
+ let attempts = 0;
137
+ (function waitForDom() {
138
+ attempts += 1;
139
+
140
+ const el = document.getElementById(placeholderId);
141
+ if (el && el.isConnected) {
142
+ const now = Date.now();
143
+ const last = state.lastShowById[key] || 0;
144
+ if (now - last < 4000) return;
145
+
146
+ if (doCall()) return;
147
+
148
+ // showAds not ready: queue once per id
149
+ if (state.pendingById[key]) return;
150
+ state.pendingById[key] = true;
151
+
152
+ window.ezstandalone = window.ezstandalone || {};
153
+ window.ezstandalone.cmd = window.ezstandalone.cmd || [];
154
+ window.ezstandalone.cmd.push(() => {
155
+ try {
156
+ if (typeof window.ezstandalone.showAds === 'function') {
157
+ delete state.pendingById[key];
158
+ state.lastShowById[key] = Date.now();
159
+ window.ezstandalone.showAds(id);
160
+ }
161
+ } catch (e) {}
162
+ });
163
+
164
+ // also retry a few times in case cmd is late
165
+ let tries = 0;
166
+ (function tick() {
167
+ tries += 1;
168
+ if (doCall() || tries >= 6) {
169
+ if (tries >= 6) delete state.pendingById[key];
170
+ return;
171
+ }
172
+ setTimeout(tick, 800);
173
+ })();
156
174
 
157
- let tries = 0;
158
- (function tick() {
159
- tries += 1;
160
- if (tryRun() || tries >= 8) {
161
- if (tries >= 8) delete state.pendingById[key];
162
175
  return;
163
176
  }
164
- setTimeout(tick, 800);
177
+
178
+ if (attempts < 40) { // ~2s
179
+ setTimeout(waitForDom, 50);
180
+ }
165
181
  })();
166
182
  }
167
183
 
184
+
168
185
  function recycleIfNeeded(pool, usedSet, fifo, selectorFn) {
169
186
  // only recycle ads far above the viewport, so they don't "disappear" while reading
170
187
  const margin = 1200;
@@ -230,6 +247,7 @@
230
247
  state.observers = {};
231
248
 
232
249
  state.retryCount = {};
250
+
233
251
  }
234
252
 
235
253
  async function fetchConfig() {
@@ -293,6 +311,21 @@
293
311
  state.retryCount[key] += 1;
294
312
  setTimeout(run, 250);
295
313
  }
314
+ } catch (e) {}
315
+ };
316
+
317
+ state.predeclared[kind].add(key);
318
+
319
+ if (window.ezstandalone && typeof window.ezstandalone.showAds === 'function') {
320
+ call();
321
+ return;
322
+ }
323
+
324
+ window.ezstandalone = window.ezstandalone || {};
325
+ window.ezstandalone.cmd = window.ezstandalone.cmd || [];
326
+ window.ezstandalone.cmd.push(call);
327
+ } catch (e) {}
328
+ }
296
329
 
297
330
  function injectBetweenTopics(cfg) {
298
331
  if (!normalizeBool(cfg.enableBetweenAds)) return;
@@ -371,15 +404,28 @@
371
404
  const cfg = await fetchConfig();
372
405
  if (!cfg || cfg.excluded) return;
373
406
 
407
+ // If Ezoic is not ready yet, schedule a single rerun via ezstandalone.cmd
408
+ try {
409
+ window.ezstandalone = window.ezstandalone || {};
410
+ window.ezstandalone.cmd = window.ezstandalone.cmd || [];
411
+ if (typeof window.ezstandalone.showAds !== 'function') {
412
+ const rk = 'ezoicReadyRerun:' + getPageKey();
413
+ if (!state.retryCount[rk]) {
414
+ state.retryCount[rk] = 1;
415
+ window.ezstandalone.cmd.push(() => { setTimeout(run, 0); });
416
+ }
417
+ }
418
+ } catch (e) {}
419
+
374
420
  const kind = getPageKind();
375
421
 
376
422
  if (kind === 'topic') {
377
423
  const hasPosts = document.querySelectorAll(SELECTORS.postItem).length > 0;
378
- if (hasPosts) injectBetweenMessages(cfg);
424
+ if (hasPosts) { injectBetweenMessages(cfg); }
379
425
  else { observeUntilTargets('topic', run); scheduleRetry('topic'); }
380
426
  } else {
381
427
  const hasList = document.querySelectorAll(SELECTORS.topicListItem).length > 0;
382
- if (hasList) injectBetweenTopics(cfg);
428
+ if (hasList) { injectBetweenTopics(cfg); }
383
429
  else { observeUntilTargets('category', run); scheduleRetry('category'); }
384
430
  }
385
431
  } catch (e) {