nodebb-plugin-ezoic-infinite 0.5.7 → 0.5.8

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 +64 -43
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
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
@@ -7,6 +7,10 @@ let cachedConfig;
7
7
  let lastFetch = 0;
8
8
  let debounceTimer;
9
9
 
10
+ let lastSignature = null;
11
+ let inFlight = false;
12
+ let rerunRequested = false;
13
+
10
14
  async function fetchConfig() {
11
15
  if (cachedConfig && Date.now() - lastFetch < 10000) return cachedConfig;
12
16
  const res = await fetch('/api/plugins/ezoic-infinite/config', { credentials: 'same-origin' });
@@ -40,6 +44,8 @@ function getTopicPosts() {
40
44
  }
41
45
 
42
46
  function getCategoryTopicItems() {
47
+ // Only on category topic list pages
48
+ if (!ajaxify || !ajaxify.data || ajaxify.data.template !== 'category') return $();
43
49
  return $('li[component="category/topic"]').not('.ezoic-ad-topic');
44
50
  }
45
51
 
@@ -47,14 +53,11 @@ function tagName($el) {
47
53
  return ($el && $el.length ? (($el.prop('tagName') || '').toUpperCase()) : '');
48
54
  }
49
55
 
50
- function removePlaceholdersByPool(pool) {
51
- pool.forEach(id => $('[id="ezoic-pub-ad-placeholder-' + id + '"]').remove());
52
- }
53
-
54
- function removeAdWrappers() {
56
+ function removeExistingEzoicNodes() {
55
57
  $('.ezoic-ad-post').remove();
56
58
  $('.ezoic-ad-between').remove();
57
59
  $('.ezoic-ad-topic').remove();
60
+ $('[id^="ezoic-pub-ad-placeholder-"]').remove();
58
61
  }
59
62
 
60
63
  function computeWindowSlots(totalItems, interval, poolSize) {
@@ -130,14 +133,11 @@ function uniqueConcat(a, b) {
130
133
  function ezoicCall(ids) {
131
134
  if (!ids || !ids.length) return;
132
135
 
133
- // Queue calls until Ezoic is ready (recommended pattern)
134
136
  window.ezstandalone = window.ezstandalone || {};
135
137
  window.ezstandalone.cmd = window.ezstandalone.cmd || [];
136
138
 
137
139
  window.ezstandalone.cmd.push(function () {
138
140
  try {
139
- // IMPORTANT: destroy only the placeholders we are about to reuse,
140
- // NOT all placeholders. Destroying too early/all can make ads disappear.
141
141
  if (typeof window.ezstandalone.destroyPlaceholders === 'function') {
142
142
  window.ezstandalone.destroyPlaceholders.apply(window.ezstandalone, ids);
143
143
  }
@@ -151,62 +151,83 @@ function ezoicCall(ids) {
151
151
  });
152
152
  }
153
153
 
154
+ function computeSignature($posts, $topicItems) {
155
+ if ($posts.length) {
156
+ const lastPid = $posts.last().attr('data-pid') || '';
157
+ return 'topic:' + $posts.length + ':' + lastPid;
158
+ }
159
+ if ($topicItems.length) {
160
+ const lastTid = $topicItems.last().attr('data-tid') || '';
161
+ return 'category:' + $topicItems.length + ':' + lastTid;
162
+ }
163
+ return 'none';
164
+ }
165
+
154
166
  async function refreshAds() {
155
- let cfg;
156
- try { cfg = await fetchConfig(); } catch (e) { return; }
157
- if (!cfg || cfg.excluded) return;
167
+ if (inFlight) { rerunRequested = true; return; }
168
+ inFlight = true;
158
169
 
159
- const betweenPool = parsePool(cfg.placeholderIds);
160
- const betweenInterval = Math.max(1, parseInt(cfg.intervalPosts, 10) || 6);
170
+ try {
171
+ const cfg = await fetchConfig();
172
+ if (!cfg || cfg.excluded) return;
161
173
 
162
- const messagePool = parsePool(cfg.messagePlaceholderIds);
163
- const messageInterval = Math.max(1, parseInt(cfg.messageIntervalPosts, 10) || 3);
174
+ const betweenPool = parsePool(cfg.placeholderIds);
175
+ const betweenInterval = Math.max(1, parseInt(cfg.intervalPosts, 10) || 6);
164
176
 
165
- const $posts = getTopicPosts();
166
- const $topicItems = getCategoryTopicItems();
177
+ const messagePool = parsePool(cfg.messagePlaceholderIds);
178
+ const messageInterval = Math.max(1, parseInt(cfg.messageIntervalPosts, 10) || 3);
167
179
 
168
- if (!$posts.length && !$topicItems.length) return;
180
+ const $posts = getTopicPosts();
181
+ const $topicItems = getCategoryTopicItems();
169
182
 
170
- removeAdWrappers();
171
- removePlaceholdersByPool(uniqueConcat(betweenPool, messagePool));
183
+ if (!$posts.length && !$topicItems.length) return;
172
184
 
173
- const combinedUnique = uniqueConcat(betweenPool, messagePool);
185
+ const signature = computeSignature($posts, $topicItems);
186
+ if (signature === lastSignature) return;
187
+ lastSignature = signature;
174
188
 
175
- const activeIds = [];
189
+ removeExistingEzoicNodes();
176
190
 
177
- // Category topic list page
178
- if (!$posts.length && $topicItems.length) {
179
- if (cfg.enableBetweenAds && betweenPool.length) {
180
- activeIds.push(...insertBetweenGeneric($topicItems, combinedUnique.slice(0, betweenPool.length), betweenInterval, 'ezoic-ad-topic'));
191
+ const combinedUnique = uniqueConcat(betweenPool, messagePool);
192
+ const activeIds = [];
193
+
194
+ if (!$posts.length && $topicItems.length) {
195
+ if (cfg.enableBetweenAds && betweenPool.length) {
196
+ activeIds.push(...insertBetweenGeneric($topicItems, combinedUnique.slice(0, betweenPool.length), betweenInterval, 'ezoic-ad-topic'));
197
+ }
181
198
  }
182
- }
183
199
 
184
- // Topic page
185
- if ($posts.length) {
186
- let cursor = 0;
200
+ if ($posts.length) {
201
+ let cursor = 0;
187
202
 
188
- if (cfg.enableBetweenAds && betweenPool.length) {
189
- const idsForBetween = combinedUnique.slice(cursor, cursor + betweenPool.length);
190
- cursor += idsForBetween.length;
191
- activeIds.push(...insertBetweenGeneric($posts, idsForBetween, betweenInterval, 'ezoic-ad-between'));
203
+ if (cfg.enableBetweenAds && betweenPool.length) {
204
+ const idsForBetween = combinedUnique.slice(cursor, cursor + betweenPool.length);
205
+ cursor += idsForBetween.length;
206
+ activeIds.push(...insertBetweenGeneric($posts, idsForBetween, betweenInterval, 'ezoic-ad-between'));
207
+ }
208
+
209
+ if (cfg.enableMessageAds && messagePool.length) {
210
+ const idsForMessage = combinedUnique.slice(cursor, cursor + messagePool.length);
211
+ cursor += idsForMessage.length;
212
+ activeIds.push(...insertAdMessagesBetweenReplies($posts, idsForMessage, messageInterval));
213
+ }
192
214
  }
193
215
 
194
- if (cfg.enableMessageAds && messagePool.length) {
195
- const idsForMessage = combinedUnique.slice(cursor, cursor + messagePool.length);
196
- cursor += idsForMessage.length;
197
- activeIds.push(...insertAdMessagesBetweenReplies($posts, idsForMessage, messageInterval));
216
+ ezoicCall(activeIds);
217
+ } finally {
218
+ inFlight = false;
219
+ if (rerunRequested) {
220
+ rerunRequested = false;
221
+ setTimeout(refreshAds, 50);
198
222
  }
199
223
  }
200
-
201
- // Ask Ezoic to (re)fill ONLY the placeholders we inserted.
202
- ezoicCall(activeIds);
203
224
  }
204
225
 
205
226
  function debounceRefresh() {
206
227
  clearTimeout(debounceTimer);
207
- debounceTimer = setTimeout(refreshAds, 180);
228
+ debounceTimer = setTimeout(refreshAds, 220);
208
229
  }
209
230
 
210
231
  $(document).ready(debounceRefresh);
211
232
  $(window).on('action:ajaxify.end action:posts.loaded action:topic.loaded', debounceRefresh);
212
- setTimeout(debounceRefresh, 1800);
233
+ setTimeout(debounceRefresh, 2200);