nodebb-plugin-ezoic-infinite 0.6.5 → 0.6.7

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": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "Ezoic ads with infinite scroll using a pool of placeholder IDs",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/plugin.json CHANGED
@@ -22,5 +22,8 @@
22
22
  "scripts": [
23
23
  "public/client.js"
24
24
  ],
25
- "templates": "public/templates"
25
+ "templates": "public/templates",
26
+ "css": [
27
+ "public/style.css"
28
+ ]
26
29
  }
package/public/client.js CHANGED
@@ -12,12 +12,12 @@ let rerunRequested = false;
12
12
 
13
13
  // Per-page incremental state
14
14
  let pageKey = null;
15
- let injectedSlots = new Set(); // slot numbers already injected on this page
15
+ let seenSlots = new Set(); // slots already processed (never cleared on eviction)
16
16
  let usedIds = new Set(); // IDs currently present in DOM
17
- let adsFIFO = []; // [{type, slot, id}] oldest first
17
+ let adsFIFO = []; // [{slot, id}] oldest first
18
18
 
19
19
  function resetPageState() {
20
- injectedSlots = new Set();
20
+ seenSlots = new Set();
21
21
  usedIds = new Set();
22
22
  adsFIFO = [];
23
23
  }
@@ -58,36 +58,44 @@ function isCategoryTopicListPage() {
58
58
  }
59
59
 
60
60
  function getTopicPosts() {
61
+ // Only real posts
61
62
  const $primary = $('[component="post"][data-pid]');
62
- if ($primary.length) return $primary.not('.ezoic-ad-post');
63
+ if ($primary.length) return $primary;
63
64
 
65
+ // Fallback: top-level with post/content
64
66
  return $('[data-pid]').filter(function () {
65
67
  const $el = $(this);
66
68
  const hasContent = $el.find('[component="post/content"]').length > 0;
67
69
  const nested = $el.parents('[data-pid]').length > 0;
68
70
  return hasContent && !nested;
69
- }).not('.ezoic-ad-post');
71
+ });
70
72
  }
71
73
 
72
74
  function getCategoryTopicItems() {
73
- return $('li[component="category/topic"]').not('.ezoic-ad-topic');
75
+ return $('li[component="category/topic"]');
74
76
  }
75
77
 
76
- function tagName($el) {
77
- return ($el && $el.length ? (($el.prop('tagName') || '').toUpperCase()) : '');
78
+ // If target's parent is UL/OL, wrapper MUST be LI (otherwise browser may move it to top)
79
+ function wrapperTagFor($target) {
80
+ if (!$target || !$target.length) return 'div';
81
+ const parentTag = ($target.parent().prop('tagName') || '').toUpperCase();
82
+ if (parentTag === 'UL' || parentTag === 'OL') return 'li';
83
+ const selfTag = ($target.prop('tagName') || '').toUpperCase();
84
+ if (selfTag === 'LI') return 'li';
85
+ return 'div';
78
86
  }
79
87
 
80
88
  function makeWrapperLike($target, classes, innerHtml, attrs) {
81
- const t = tagName($target);
89
+ const tag = wrapperTagFor($target);
82
90
  const attrStr = attrs ? ' ' + attrs : '';
83
- if (t === 'LI') {
91
+ if (tag === 'li') {
84
92
  return '<li class="' + classes + ' list-unstyled"' + attrStr + '>' + innerHtml + '</li>';
85
93
  }
86
94
  return '<div class="' + classes + '"' + attrStr + '>' + innerHtml + '</div>';
87
95
  }
88
96
 
89
97
  function cleanupWrappersOnNav() {
90
- $('.ezoic-ad-post, .ezoic-ad-between, .ezoic-ad-topic').remove();
98
+ $('.ezoic-ad-post, .ezoic-ad-topic, .ezoic-ad-between').remove();
91
99
  }
92
100
 
93
101
  function pickNextId(pool) {
@@ -105,7 +113,6 @@ function evictOldestOne() {
105
113
  const $el = $(sel);
106
114
  if ($el.length) $el.remove();
107
115
 
108
- injectedSlots.delete(old.slot);
109
116
  usedIds.delete(old.id);
110
117
  return true;
111
118
  }
@@ -145,7 +152,7 @@ function injectBetweenIncremental($items, pool, interval, wrapperClass) {
145
152
  const newIds = [];
146
153
 
147
154
  for (let slot = 1; slot <= maxSlot; slot++) {
148
- if (injectedSlots.has(slot)) continue;
155
+ if (seenSlots.has(slot)) continue;
149
156
 
150
157
  const index = slot * interval - 1;
151
158
  const $target = $items.eq(index);
@@ -153,7 +160,6 @@ function injectBetweenIncremental($items, pool, interval, wrapperClass) {
153
160
 
154
161
  let id = pickNextId(pool);
155
162
  if (!id) {
156
- // Pool full: evict oldest, then reuse freed ID
157
163
  if (!evictOldestOne()) break;
158
164
  id = pickNextId(pool);
159
165
  if (!id) break;
@@ -162,16 +168,16 @@ function injectBetweenIncremental($items, pool, interval, wrapperClass) {
162
168
  const placeholder = '<div id="ezoic-pub-ad-placeholder-' + id + '"></div>';
163
169
  const html = makeWrapperLike(
164
170
  $target,
165
- wrapperClass,
171
+ wrapperClass + ' ezoic-ad',
166
172
  placeholder,
167
173
  'data-ezoic-slot="' + slot + '" data-ezoic-id="' + id + '"'
168
174
  );
169
175
 
170
176
  $target.after(html);
171
177
 
172
- injectedSlots.add(slot);
178
+ seenSlots.add(slot);
173
179
  usedIds.add(id);
174
- adsFIFO.push({ type: 'between', slot: slot, id: id });
180
+ adsFIFO.push({ slot: slot, id: id });
175
181
  newIds.push(id);
176
182
  }
177
183
 
@@ -186,7 +192,7 @@ function injectMessageIncremental($posts, pool, interval) {
186
192
  const newIds = [];
187
193
 
188
194
  for (let slot = 1; slot <= maxSlot; slot++) {
189
- if (injectedSlots.has(slot)) continue;
195
+ if (seenSlots.has(slot)) continue;
190
196
 
191
197
  const index = slot * interval - 1;
192
198
  const $target = $posts.eq(index);
@@ -199,19 +205,20 @@ function injectMessageIncremental($posts, pool, interval) {
199
205
  if (!id) break;
200
206
  }
201
207
 
202
- const inner = '<div class="content"><div id="ezoic-pub-ad-placeholder-' + id + '"></div></div>';
208
+ // Do NOT use class "post" nor component="post" for ads: can break NodeBB infinite scroll.
209
+ const inner = '<div class="ezoic-ad-message-inner"><div id="ezoic-pub-ad-placeholder-' + id + '"></div></div>';
203
210
  const html = makeWrapperLike(
204
211
  $target,
205
- 'post ezoic-ad-post',
212
+ 'ezoic-ad-post ezoic-ad',
206
213
  inner,
207
214
  'data-ezoic-slot="' + slot + '" data-ezoic-id="' + id + '"'
208
215
  );
209
216
 
210
217
  $target.after(html);
211
218
 
212
- injectedSlots.add(slot);
219
+ seenSlots.add(slot);
213
220
  usedIds.add(id);
214
- adsFIFO.push({ type: 'message', slot: slot, id: id });
221
+ adsFIFO.push({ slot: slot, id: id });
215
222
  newIds.push(id);
216
223
  }
217
224
 
@@ -219,7 +226,6 @@ function injectMessageIncremental($posts, pool, interval) {
219
226
  }
220
227
 
221
228
  async function refreshAds() {
222
- // Reset state on navigation
223
229
  const key = currentPageKey();
224
230
  if (pageKey !== key) {
225
231
  pageKey = key;
@@ -250,9 +256,6 @@ async function refreshAds() {
250
256
 
251
257
  const newIds = [];
252
258
 
253
- // Your rule:
254
- // - Category topic list: BETWEEN only
255
- // - Topic page: MESSAGE only
256
259
  if ($topicItems.length) {
257
260
  if (cfg.enableBetweenAds && betweenPool.length) {
258
261
  newIds.push(...injectBetweenIncremental($topicItems, betweenPool, betweenInterval, 'ezoic-ad-topic'));
@@ -278,7 +281,7 @@ async function refreshAds() {
278
281
 
279
282
  function debounceRefresh() {
280
283
  clearTimeout(debounceTimer);
281
- debounceTimer = setTimeout(refreshAds, 180);
284
+ debounceTimer = setTimeout(refreshAds, 200);
282
285
  }
283
286
 
284
287
  $(document).ready(debounceRefresh);
@@ -0,0 +1,2 @@
1
+ .ezoic-ad-post{margin:0.75rem 0;}
2
+ .ezoic-ad-message-inner{padding:0.75rem 0;}