nodebb-plugin-ezoic-infinite 0.6.4 → 0.6.6

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 +37 -36
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "0.6.4",
3
+ "version": "0.6.6",
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
@@ -14,7 +14,7 @@ let rerunRequested = false;
14
14
  let pageKey = null;
15
15
  let injectedSlots = new Set(); // slot numbers already injected on this page
16
16
  let usedIds = new Set(); // IDs currently present in DOM
17
- let adsFIFO = []; // [{slot, id, selector}] in insertion order (oldest first)
17
+ let adsFIFO = []; // [{slot, id}] oldest first
18
18
 
19
19
  function resetPageState() {
20
20
  injectedSlots = new Set();
@@ -73,14 +73,21 @@ function getCategoryTopicItems() {
73
73
  return $('li[component="category/topic"]').not('.ezoic-ad-topic');
74
74
  }
75
75
 
76
- function tagName($el) {
77
- return ($el && $el.length ? (($el.prop('tagName') || '').toUpperCase()) : '');
76
+ // IMPORTANT: Use the SAME tag type as the surrounding list container.
77
+ // If posts/topics are in a <ul>/<ol>, the wrapper MUST be a <li> or the browser may move it outside the list (often to the top).
78
+ function wrapperTagFor($target) {
79
+ if (!$target || !$target.length) return 'div';
80
+ const parentTag = ($target.parent().prop('tagName') || '').toUpperCase();
81
+ if (parentTag === 'UL' || parentTag === 'OL') return 'li';
82
+ const selfTag = ($target.prop('tagName') || '').toUpperCase();
83
+ if (selfTag === 'LI') return 'li';
84
+ return 'div';
78
85
  }
79
86
 
80
87
  function makeWrapperLike($target, classes, innerHtml, attrs) {
81
- const t = tagName($target);
88
+ const tag = wrapperTagFor($target);
82
89
  const attrStr = attrs ? ' ' + attrs : '';
83
- if (t === 'LI') {
90
+ if (tag === 'li') {
84
91
  return '<li class="' + classes + ' list-unstyled"' + attrStr + '>' + innerHtml + '</li>';
85
92
  }
86
93
  return '<div class="' + classes + '"' + attrStr + '>' + innerHtml + '</div>';
@@ -97,6 +104,19 @@ function pickNextId(pool) {
97
104
  return null;
98
105
  }
99
106
 
107
+ function evictOldestOne() {
108
+ const old = adsFIFO.shift();
109
+ if (!old) return false;
110
+
111
+ const sel = '[data-ezoic-slot="' + old.slot + '"][data-ezoic-id="' + old.id + '"]';
112
+ const $el = $(sel);
113
+ if ($el.length) $el.remove();
114
+
115
+ injectedSlots.delete(old.slot);
116
+ usedIds.delete(old.id);
117
+ return true;
118
+ }
119
+
100
120
  function callEzoic(ids) {
101
121
  if (!ids || !ids.length) return;
102
122
 
@@ -124,21 +144,6 @@ function callEzoic(ids) {
124
144
  }, 800);
125
145
  }
126
146
 
127
- function fifoEvictIfNeeded(poolSize) {
128
- // Keep at most poolSize ads in DOM: remove oldest when we exceed pool capacity.
129
- // This makes ads "follow" the scroll (new ads appear, oldest disappear) without jumping positions.
130
- while (adsFIFO.length > poolSize) {
131
- const old = adsFIFO.shift();
132
- if (!old) break;
133
-
134
- const $el = $(old.selector);
135
- if ($el.length) $el.remove();
136
-
137
- injectedSlots.delete(old.slot);
138
- usedIds.delete(old.id);
139
- }
140
- }
141
-
142
147
  function injectBetweenIncremental($items, pool, interval, wrapperClass) {
143
148
  const total = $items.length;
144
149
  const maxSlot = Math.floor(total / interval);
@@ -153,14 +158,14 @@ function injectBetweenIncremental($items, pool, interval, wrapperClass) {
153
158
  const $target = $items.eq(index);
154
159
  if (!$target.length) continue;
155
160
 
156
- const id = pickNextId(pool);
161
+ let id = pickNextId(pool);
157
162
  if (!id) {
158
- // No free IDs right now; stop. Oldest will be evicted once new ads can be created.
159
- break;
163
+ if (!evictOldestOne()) break;
164
+ id = pickNextId(pool);
165
+ if (!id) break;
160
166
  }
161
167
 
162
168
  const placeholder = '<div id="ezoic-pub-ad-placeholder-' + id + '"></div>';
163
- const selector = '.ezoic-ad-topic[data-ezoic-slot="' + slot + '"][data-ezoic-id="' + id + '"]';
164
169
  const html = makeWrapperLike(
165
170
  $target,
166
171
  wrapperClass,
@@ -172,12 +177,8 @@ function injectBetweenIncremental($items, pool, interval, wrapperClass) {
172
177
 
173
178
  injectedSlots.add(slot);
174
179
  usedIds.add(id);
175
- adsFIFO.push({ slot: slot, id: id, selector: selector });
176
-
180
+ adsFIFO.push({ slot: slot, id: id });
177
181
  newIds.push(id);
178
-
179
- // Enforce capacity immediately (prevents runaway and keeps ads near viewport)
180
- fifoEvictIfNeeded(pool.length);
181
182
  }
182
183
 
183
184
  return newIds;
@@ -197,11 +198,14 @@ function injectMessageIncremental($posts, pool, interval) {
197
198
  const $target = $posts.eq(index);
198
199
  if (!$target.length) continue;
199
200
 
200
- const id = pickNextId(pool);
201
- if (!id) break;
201
+ let id = pickNextId(pool);
202
+ if (!id) {
203
+ if (!evictOldestOne()) break;
204
+ id = pickNextId(pool);
205
+ if (!id) break;
206
+ }
202
207
 
203
208
  const inner = '<div class="content"><div id="ezoic-pub-ad-placeholder-' + id + '"></div></div>';
204
- const selector = '.ezoic-ad-post[data-ezoic-slot="' + slot + '"][data-ezoic-id="' + id + '"]';
205
209
  const html = makeWrapperLike(
206
210
  $target,
207
211
  'post ezoic-ad-post',
@@ -213,11 +217,8 @@ function injectMessageIncremental($posts, pool, interval) {
213
217
 
214
218
  injectedSlots.add(slot);
215
219
  usedIds.add(id);
216
- adsFIFO.push({ slot: slot, id: id, selector: selector });
217
-
220
+ adsFIFO.push({ slot: slot, id: id });
218
221
  newIds.push(id);
219
-
220
- fifoEvictIfNeeded(pool.length);
221
222
  }
222
223
 
223
224
  return newIds;