nodebb-plugin-ezoic-infinite 1.0.17 → 1.0.18

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 +90 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
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
@@ -21,6 +21,11 @@
21
21
  let usedMessage = new Set(); // between replies
22
22
  let fifoBetween = [];
23
23
  let fifoMessage = [];
24
+ // reset serialized showAds queues
25
+ try {
26
+ if (typeof queues !== 'undefined') { queues.between.length = 0; queues.message.length = 0; }
27
+ if (typeof queueState !== 'undefined') { queueState.between = false; queueState.message = false; }
28
+ } catch (e) {}
24
29
 
25
30
  function getPageKey() {
26
31
  try {
@@ -91,6 +96,11 @@
91
96
  usedMessage = new Set();
92
97
  fifoBetween = [];
93
98
  fifoMessage = [];
99
+ // reset serialized showAds queues
100
+ try {
101
+ if (typeof queues !== 'undefined') { queues.between.length = 0; queues.message.length = 0; }
102
+ if (typeof queueState !== 'undefined') { queueState.between = false; queueState.message = false; }
103
+ } catch (e) {}
94
104
  }
95
105
 
96
106
  function destroyPlaceholder(id) {
@@ -116,6 +126,84 @@
116
126
  destroyPlaceholder(id);
117
127
  }
118
128
 
129
+ // Ensure placeholders are filled in the same order they were inserted.
130
+ // Ezoic can fill asynchronously; we serialize showAds calls per page-type queue.
131
+ const queues = { between: [], message: [] };
132
+ const queueState = { between: false, message: false };
133
+
134
+ function isFilled(placeholderEl) {
135
+ if (!placeholderEl) return false;
136
+ if (placeholderEl.children && placeholderEl.children.length) return true;
137
+ const html = placeholderEl.innerHTML || '';
138
+ if (html.trim().length > 0) return true;
139
+ const r = placeholderEl.getBoundingClientRect ? placeholderEl.getBoundingClientRect() : null;
140
+ if (r && r.height > 10) return true;
141
+ return false;
142
+ }
143
+
144
+ function waitForFilled(placeholderEl, timeoutMs) {
145
+ return new Promise((resolve) => {
146
+ if (!placeholderEl) return resolve(false);
147
+ if (isFilled(placeholderEl)) return resolve(true);
148
+
149
+ let done = false;
150
+ const finish = (ok) => {
151
+ if (done) return;
152
+ done = true;
153
+ try { obs.disconnect(); } catch (e) {}
154
+ resolve(ok);
155
+ };
156
+
157
+ const obs = new MutationObserver(() => {
158
+ if (isFilled(placeholderEl)) finish(true);
159
+ });
160
+
161
+ try {
162
+ obs.observe(placeholderEl, { childList: true, subtree: true, attributes: true });
163
+ } catch (e) {}
164
+
165
+ setTimeout(() => finish(isFilled(placeholderEl)), timeoutMs);
166
+ });
167
+ }
168
+
169
+ async function processQueue(kind) {
170
+ if (queueState[kind]) return;
171
+ queueState[kind] = true;
172
+
173
+ try {
174
+ while (queues[kind].length) {
175
+ const item = queues[kind][0];
176
+ const wrap = item.wrapper;
177
+ const id = item.id;
178
+
179
+ // if removed (recycled) before fill, drop it
180
+ if (!wrap || !wrap.isConnected) {
181
+ queues[kind].shift();
182
+ continue;
183
+ }
184
+
185
+ // call showAds once
186
+ callShowAdsSingle(id);
187
+
188
+ // wait for fill (or timeout) then proceed
189
+ const ph = document.getElementById('ezoic-pub-ad-placeholder-' + id);
190
+ await waitForFilled(ph, 5000);
191
+
192
+ queues[kind].shift();
193
+ }
194
+ } finally {
195
+ queueState[kind] = false;
196
+ }
197
+ }
198
+
199
+ function enqueueShowAds(kind, wrapperEl, id) {
200
+ if (!wrapperEl || !id) return;
201
+ if (wrapperEl.getAttribute('data-ezoic-shown') === '1') return;
202
+ wrapperEl.setAttribute('data-ezoic-shown', '1');
203
+ queues[kind].push({ wrapper: wrapperEl, id });
204
+ processQueue(kind);
205
+ }
206
+
119
207
  function showAdsOnceForElement(wrapperEl, id) {
120
208
  if (!wrapperEl || !id) return;
121
209
  if (wrapperEl.getAttribute('data-ezoic-shown') === '1') return;
@@ -254,7 +342,7 @@
254
342
  fifoBetween.push({ id, after: pos });
255
343
 
256
344
  const wrap = insertAfter(li, id, 'ezoic-ad-between', pos);
257
- showAdsOnceForElement(wrap, id);
345
+ enqueueShowAds('between', wrap, id);
258
346
  });
259
347
  }
260
348
 
@@ -286,7 +374,7 @@
286
374
  fifoMessage.push({ id, after: no });
287
375
 
288
376
  const wrap = insertAfter(post, id, 'ezoic-ad-message', no);
289
- showAdsOnceForElement(wrap, id);
377
+ enqueueShowAds('between', wrap, id);
290
378
  });
291
379
  }
292
380