nodebb-plugin-ezoic-infinite 0.5.5 → 0.5.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/client.js +60 -32
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "0.5.5",
3
+ "version": "0.5.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/public/client.js CHANGED
@@ -39,11 +39,14 @@ function getTopicPosts() {
39
39
  return $('.posts .post').not('.ezoic-ad-post');
40
40
  }
41
41
 
42
+ function getCategoryTopicItems() {
43
+ return $('li[component="category/topic"]').not('.ezoic-ad-topic');
44
+ }
45
+
42
46
  function tagName($el) {
43
47
  return ($el && $el.length ? (($el.prop('tagName') || '').toUpperCase()) : '');
44
48
  }
45
49
 
46
- // Remove *all* nodes with a given id (duplicates are possible if misconfigured)
47
50
  function removePlaceholdersByPool(pool) {
48
51
  pool.forEach(id => $('[id="ezoic-pub-ad-placeholder-' + id + '"]').remove());
49
52
  }
@@ -51,6 +54,7 @@ function removePlaceholdersByPool(pool) {
51
54
  function removeAdWrappers() {
52
55
  $('.ezoic-ad-post').remove();
53
56
  $('.ezoic-ad-between').remove();
57
+ $('.ezoic-ad-topic').remove();
54
58
  }
55
59
 
56
60
  function computeWindowSlots(totalItems, interval, poolSize) {
@@ -70,8 +74,8 @@ function makeWrapperLike($target, classes, innerHtml) {
70
74
  return '<div class="' + classes + '" data-ezoic-ad="1">' + innerHtml + '</div>';
71
75
  }
72
76
 
73
- function insertBetweenPosts($posts, ids, interval) {
74
- const total = $posts.length;
77
+ function insertBetweenGeneric($items, ids, interval, wrapperClass) {
78
+ const total = $items.length;
75
79
  const slotsToRender = computeWindowSlots(total, interval, ids.length);
76
80
  if (!slotsToRender.length) return [];
77
81
 
@@ -80,10 +84,10 @@ function insertBetweenPosts($posts, ids, interval) {
80
84
  const slotNumber = slotsToRender[i];
81
85
  const id = ids[i];
82
86
  const index = slotNumber * interval - 1;
83
- const $target = $posts.eq(index);
87
+ const $target = $items.eq(index);
84
88
  if (!$target.length) continue;
85
89
 
86
- const html = makeWrapperLike($target, 'ezoic-ad-between', '<div id="ezoic-pub-ad-placeholder-' + id + '"></div>');
90
+ const html = makeWrapperLike($target, wrapperClass, '<div id="ezoic-pub-ad-placeholder-' + id + '"></div>');
87
91
  $target.after(html);
88
92
  activeIds.push(id);
89
93
  }
@@ -123,6 +127,30 @@ function uniqueConcat(a, b) {
123
127
  return out;
124
128
  }
125
129
 
130
+ function ezoicCall(ids) {
131
+ if (!ids || !ids.length) return;
132
+
133
+ // Queue calls until Ezoic is ready (recommended pattern)
134
+ window.ezstandalone = window.ezstandalone || {};
135
+ window.ezstandalone.cmd = window.ezstandalone.cmd || [];
136
+
137
+ window.ezstandalone.cmd.push(function () {
138
+ 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
+ if (typeof window.ezstandalone.destroyPlaceholders === 'function') {
142
+ window.ezstandalone.destroyPlaceholders.apply(window.ezstandalone, ids);
143
+ }
144
+ } catch (e) {}
145
+
146
+ try {
147
+ if (typeof window.ezstandalone.showAds === 'function') {
148
+ window.ezstandalone.showAds.apply(window.ezstandalone, ids);
149
+ }
150
+ } catch (e) {}
151
+ });
152
+ }
153
+
126
154
  async function refreshAds() {
127
155
  let cfg;
128
156
  try { cfg = await fetchConfig(); } catch (e) { return; }
@@ -135,50 +163,50 @@ async function refreshAds() {
135
163
  const messageInterval = Math.max(1, parseInt(cfg.messageIntervalPosts, 10) || 3);
136
164
 
137
165
  const $posts = getTopicPosts();
138
- if (!$posts.length) return;
166
+ const $topicItems = getCategoryTopicItems();
167
+
168
+ if (!$posts.length && !$topicItems.length) return;
139
169
 
140
- // Clean first (remove wrappers + any placeholders, even duplicates)
141
170
  removeAdWrappers();
142
171
  removePlaceholdersByPool(uniqueConcat(betweenPool, messagePool));
143
172
 
144
- // IMPORTANT:
145
- // IDs must be UNIQUE on the page. If admin reuses the same IDs for both pools,
146
- // we allocate unique IDs across "between posts" and "message ads" to avoid duplicates.
147
173
  const combinedUnique = uniqueConcat(betweenPool, messagePool);
148
174
 
149
175
  const activeIds = [];
150
- let cursor = 0;
151
176
 
152
- if (cfg.enableBetweenAds && betweenPool.length) {
153
- const idsForBetween = combinedUnique.slice(cursor, cursor + betweenPool.length);
154
- cursor += idsForBetween.length;
155
- activeIds.push(...insertBetweenPosts($posts, idsForBetween, betweenInterval));
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'));
181
+ }
156
182
  }
157
183
 
158
- if (cfg.enableMessageAds && messagePool.length) {
159
- const idsForMessage = combinedUnique.slice(cursor, cursor + messagePool.length);
160
- cursor += idsForMessage.length;
161
- activeIds.push(...insertAdMessagesBetweenReplies($posts, idsForMessage, messageInterval));
162
- }
184
+ // Topic page
185
+ if ($posts.length) {
186
+ let cursor = 0;
187
+
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'));
192
+ }
163
193
 
164
- // Ezoic render
165
- if (activeIds.length && window.ezstandalone && typeof window.ezstandalone.destroyPlaceholders === 'function') {
166
- try { window.ezstandalone.destroyPlaceholders(); } catch (e) {}
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));
198
+ }
167
199
  }
168
- activeIds.forEach(id => {
169
- try {
170
- if (window.ezstandalone && typeof window.ezstandalone.showAds === 'function') {
171
- window.ezstandalone.showAds(id);
172
- }
173
- } catch (e) {}
174
- });
200
+
201
+ // Ask Ezoic to (re)fill ONLY the placeholders we inserted.
202
+ ezoicCall(activeIds);
175
203
  }
176
204
 
177
205
  function debounceRefresh() {
178
206
  clearTimeout(debounceTimer);
179
- debounceTimer = setTimeout(refreshAds, 150);
207
+ debounceTimer = setTimeout(refreshAds, 180);
180
208
  }
181
209
 
182
210
  $(document).ready(debounceRefresh);
183
211
  $(window).on('action:ajaxify.end action:posts.loaded action:topic.loaded', debounceRefresh);
184
- setTimeout(debounceRefresh, 1500);
212
+ setTimeout(debounceRefresh, 1800);