nodebb-plugin-ezoic-infinite 0.6.3 → 0.6.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 +50 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "0.6.3",
3
+ "version": "0.6.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
@@ -10,23 +10,23 @@ let debounceTimer;
10
10
  let inFlight = false;
11
11
  let rerunRequested = false;
12
12
 
13
- // Incremental state (prevents ads "jumping to the top")
13
+ // Per-page incremental state
14
14
  let pageKey = null;
15
- let injectedSlots = new Set(); // slotNumber per page
16
- let usedIds = new Set(); // ids currently injected per page
15
+ let injectedSlots = new Set(); // slot numbers already injected on this page
16
+ let usedIds = new Set(); // IDs currently present in DOM
17
+ let adsFIFO = []; // [{type, slot, id}] oldest first
17
18
 
18
19
  function resetPageState() {
19
20
  injectedSlots = new Set();
20
21
  usedIds = new Set();
22
+ adsFIFO = [];
21
23
  }
22
24
 
23
25
  function currentPageKey() {
24
- // Stable key per ajaxified page
25
26
  try {
26
27
  if (ajaxify && ajaxify.data) {
27
28
  if (ajaxify.data.tid) return 'topic:' + ajaxify.data.tid;
28
29
  if (ajaxify.data.cid) return 'category:' + ajaxify.data.cid;
29
- if (ajaxify.data.template) return 'tpl:' + ajaxify.data.template + ':' + (ajaxify.data.url || window.location.pathname);
30
30
  }
31
31
  } catch (e) {}
32
32
  return window.location.pathname;
@@ -86,6 +86,10 @@ function makeWrapperLike($target, classes, innerHtml, attrs) {
86
86
  return '<div class="' + classes + '"' + attrStr + '>' + innerHtml + '</div>';
87
87
  }
88
88
 
89
+ function cleanupWrappersOnNav() {
90
+ $('.ezoic-ad-post, .ezoic-ad-between, .ezoic-ad-topic').remove();
91
+ }
92
+
89
93
  function pickNextId(pool) {
90
94
  for (const id of pool) {
91
95
  if (!usedIds.has(id)) return id;
@@ -93,6 +97,19 @@ function pickNextId(pool) {
93
97
  return null;
94
98
  }
95
99
 
100
+ function evictOldestOne() {
101
+ const old = adsFIFO.shift();
102
+ if (!old) return false;
103
+
104
+ const sel = '[data-ezoic-slot="' + old.slot + '"][data-ezoic-id="' + old.id + '"]';
105
+ const $el = $(sel);
106
+ if ($el.length) $el.remove();
107
+
108
+ injectedSlots.delete(old.slot);
109
+ usedIds.delete(old.id);
110
+ return true;
111
+ }
112
+
96
113
  function callEzoic(ids) {
97
114
  if (!ids || !ids.length) return;
98
115
 
@@ -111,7 +128,7 @@ function callEzoic(ids) {
111
128
 
112
129
  window.ezstandalone.cmd.push(function () { run(); });
113
130
 
114
- // retry a few times (Ezoic can load late)
131
+ // Retry (Ezoic can load late)
115
132
  let tries = 0;
116
133
  const maxTries = 6;
117
134
  const timer = setInterval(function () {
@@ -134,19 +151,27 @@ function injectBetweenIncremental($items, pool, interval, wrapperClass) {
134
151
  const $target = $items.eq(index);
135
152
  if (!$target.length) continue;
136
153
 
137
- const id = pickNextId(pool);
154
+ let id = pickNextId(pool);
138
155
  if (!id) {
139
- // pool exhausted: stop injecting further to avoid reusing ids and "jumping"
140
- break;
156
+ // Pool full: evict oldest, then reuse freed ID
157
+ if (!evictOldestOne()) break;
158
+ id = pickNextId(pool);
159
+ if (!id) break;
141
160
  }
142
161
 
143
162
  const placeholder = '<div id="ezoic-pub-ad-placeholder-' + id + '"></div>';
144
- const html = makeWrapperLike($target, wrapperClass, placeholder, 'data-ezoic-slot="' + slot + '" data-ezoic-id="' + id + '"');
163
+ const html = makeWrapperLike(
164
+ $target,
165
+ wrapperClass,
166
+ placeholder,
167
+ 'data-ezoic-slot="' + slot + '" data-ezoic-id="' + id + '"'
168
+ );
145
169
 
146
170
  $target.after(html);
147
171
 
148
172
  injectedSlots.add(slot);
149
173
  usedIds.add(id);
174
+ adsFIFO.push({ type: 'between', slot: slot, id: id });
150
175
  newIds.push(id);
151
176
  }
152
177
 
@@ -167,16 +192,26 @@ function injectMessageIncremental($posts, pool, interval) {
167
192
  const $target = $posts.eq(index);
168
193
  if (!$target.length) continue;
169
194
 
170
- const id = pickNextId(pool);
171
- if (!id) break;
195
+ let id = pickNextId(pool);
196
+ if (!id) {
197
+ if (!evictOldestOne()) break;
198
+ id = pickNextId(pool);
199
+ if (!id) break;
200
+ }
172
201
 
173
202
  const inner = '<div class="content"><div id="ezoic-pub-ad-placeholder-' + id + '"></div></div>';
174
- const html = makeWrapperLike($target, 'post ezoic-ad-post', inner, 'data-ezoic-slot="' + slot + '" data-ezoic-id="' + id + '"');
203
+ const html = makeWrapperLike(
204
+ $target,
205
+ 'post ezoic-ad-post',
206
+ inner,
207
+ 'data-ezoic-slot="' + slot + '" data-ezoic-id="' + id + '"'
208
+ );
175
209
 
176
210
  $target.after(html);
177
211
 
178
212
  injectedSlots.add(slot);
179
213
  usedIds.add(id);
214
+ adsFIFO.push({ type: 'message', slot: slot, id: id });
180
215
  newIds.push(id);
181
216
  }
182
217
 
@@ -184,13 +219,12 @@ function injectMessageIncremental($posts, pool, interval) {
184
219
  }
185
220
 
186
221
  async function refreshAds() {
187
- // reset state when navigating (ajaxify)
222
+ // Reset state on navigation
188
223
  const key = currentPageKey();
189
224
  if (pageKey !== key) {
190
225
  pageKey = key;
191
226
  resetPageState();
192
- // also cleanup any injected wrappers that may have been left by browser bfcache
193
- $('.ezoic-ad-post, .ezoic-ad-between, .ezoic-ad-topic').remove();
227
+ cleanupWrappersOnNav();
194
228
  }
195
229
 
196
230
  if (inFlight) { rerunRequested = true; return; }