nodebb-plugin-ezoic-infinite 1.0.16 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.0.16",
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;
@@ -237,7 +325,8 @@
237
325
 
238
326
  items.forEach((li, idx) => {
239
327
  const pos = idx + 1;
240
- if (pos % interval !== 0) return;
328
+ const firstEnabled = normalizeBool(cfg.showFirstTopicAd);
329
+ if (!(firstEnabled && pos === 1) && (pos % interval !== 0)) return;
241
330
  if (idx === items.length - 1) return;
242
331
 
243
332
  const next = li.nextElementSibling;
@@ -253,7 +342,7 @@
253
342
  fifoBetween.push({ id, after: pos });
254
343
 
255
344
  const wrap = insertAfter(li, id, 'ezoic-ad-between', pos);
256
- showAdsOnceForElement(wrap, id);
345
+ enqueueShowAds('between', wrap, id);
257
346
  });
258
347
  }
259
348
 
@@ -268,7 +357,8 @@
268
357
 
269
358
  posts.forEach((post, idx) => {
270
359
  const no = idx + 1;
271
- if (no % interval !== 0) return;
360
+ const firstEnabled = normalizeBool(cfg.showFirstMessageAd);
361
+ if (!(firstEnabled && no === 1) && (no % interval !== 0)) return;
272
362
  if (idx === posts.length - 1) return;
273
363
 
274
364
  const next = post.nextElementSibling;
@@ -284,7 +374,7 @@
284
374
  fifoMessage.push({ id, after: no });
285
375
 
286
376
  const wrap = insertAfter(post, id, 'ezoic-ad-message', no);
287
- showAdsOnceForElement(wrap, id);
377
+ enqueueShowAds('between', wrap, id);
288
378
  });
289
379
  }
290
380
 
@@ -7,6 +7,10 @@
7
7
  <div class="form-check mb-3">
8
8
  <input class="form-check-input" type="checkbox" id="enableBetweenAds" name="enableBetweenAds" {enableBetweenAds_checked}>
9
9
  <label class="form-check-label" for="enableBetweenAds">Activer les pubs entre les posts</label>
10
+ <div class="form-check mt-2">
11
+ <input class="form-check-input" type="checkbox" name="showFirstTopicAd" />
12
+ <label class="form-check-label">Afficher une pub après le 1er sujet</label>
13
+ </div>
10
14
  </div>
11
15
 
12
16
  <div class="mb-3">
@@ -28,6 +32,10 @@
28
32
  <div class="form-check mb-3">
29
33
  <input class="form-check-input" type="checkbox" id="enableMessageAds" name="enableMessageAds" {enableMessageAds_checked}>
30
34
  <label class="form-check-label" for="enableMessageAds">Activer les pubs “message”</label>
35
+ <div class="form-check mt-2">
36
+ <input class="form-check-input" type="checkbox" name="showFirstMessageAd" />
37
+ <label class="form-check-label">Afficher une pub après le 1er message</label>
38
+ </div>
31
39
  </div>
32
40
 
33
41
  <div class="mb-3">