nodebb-plugin-ezoic-infinite 0.6.7 → 0.6.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.
- package/package.json +1 -1
- package/public/client.js +104 -74
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -10,19 +10,27 @@ let debounceTimer;
|
|
|
10
10
|
let inFlight = false;
|
|
11
11
|
let rerunRequested = false;
|
|
12
12
|
|
|
13
|
-
// Per-page
|
|
13
|
+
// Per-page state (keyed by tid/cid)
|
|
14
14
|
let pageKey = null;
|
|
15
|
-
let seenSlots = new Set(); // slots already processed (never cleared on eviction)
|
|
16
|
-
let usedIds = new Set(); // IDs currently present in DOM
|
|
17
|
-
let adsFIFO = []; // [{slot, id}] oldest first
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
// Topic page state: anchor ads to absolute post number (not DOM index)
|
|
17
|
+
let seenAfterPostNo = new Set(); // post numbers we've already inserted an ad after
|
|
18
|
+
let usedIds = new Set(); // ids currently in DOM
|
|
19
|
+
let fifo = []; // [{afterPostNo, id}]
|
|
20
|
+
|
|
21
|
+
// Category page state: anchor to absolute topic position if available
|
|
22
|
+
let seenAfterTopicPos = new Set(); // topic positions we've inserted after
|
|
23
|
+
let fifoCat = []; // [{afterPos, id}]
|
|
24
|
+
|
|
25
|
+
function resetState() {
|
|
26
|
+
seenAfterPostNo = new Set();
|
|
27
|
+
seenAfterTopicPos = new Set();
|
|
21
28
|
usedIds = new Set();
|
|
22
|
-
|
|
29
|
+
fifo = [];
|
|
30
|
+
fifoCat = [];
|
|
23
31
|
}
|
|
24
32
|
|
|
25
|
-
function
|
|
33
|
+
function getPageKey() {
|
|
26
34
|
try {
|
|
27
35
|
if (ajaxify && ajaxify.data) {
|
|
28
36
|
if (ajaxify.data.tid) return 'topic:' + ajaxify.data.tid;
|
|
@@ -58,11 +66,10 @@ function isCategoryTopicListPage() {
|
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
function getTopicPosts() {
|
|
61
|
-
// Only real posts
|
|
62
69
|
const $primary = $('[component="post"][data-pid]');
|
|
63
70
|
if ($primary.length) return $primary;
|
|
64
71
|
|
|
65
|
-
//
|
|
72
|
+
// fallback: top-level with post/content
|
|
66
73
|
return $('[data-pid]').filter(function () {
|
|
67
74
|
const $el = $(this);
|
|
68
75
|
const hasContent = $el.find('[component="post/content"]').length > 0;
|
|
@@ -94,7 +101,7 @@ function makeWrapperLike($target, classes, innerHtml, attrs) {
|
|
|
94
101
|
return '<div class="' + classes + '"' + attrStr + '>' + innerHtml + '</div>';
|
|
95
102
|
}
|
|
96
103
|
|
|
97
|
-
function
|
|
104
|
+
function cleanupOnNav() {
|
|
98
105
|
$('.ezoic-ad-post, .ezoic-ad-topic, .ezoic-ad-between').remove();
|
|
99
106
|
}
|
|
100
107
|
|
|
@@ -105,11 +112,26 @@ function pickNextId(pool) {
|
|
|
105
112
|
return null;
|
|
106
113
|
}
|
|
107
114
|
|
|
108
|
-
function
|
|
109
|
-
|
|
115
|
+
function removeOldestTopicAd() {
|
|
116
|
+
fifo.sort((a, b) => a.afterPostNo - b.afterPostNo);
|
|
117
|
+
const old = fifo.shift();
|
|
110
118
|
if (!old) return false;
|
|
111
119
|
|
|
112
|
-
const sel = '[data-ezoic-
|
|
120
|
+
const sel = '.ezoic-ad-post[data-ezoic-after="' + old.afterPostNo + '"][data-ezoic-id="' + old.id + '"]';
|
|
121
|
+
const $el = $(sel);
|
|
122
|
+
if ($el.length) $el.remove();
|
|
123
|
+
|
|
124
|
+
usedIds.delete(old.id);
|
|
125
|
+
// DO NOT delete seenAfterPostNo to prevent re-insertion in the top area
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function removeOldestCategoryAd() {
|
|
130
|
+
fifoCat.sort((a, b) => a.afterPos - b.afterPos);
|
|
131
|
+
const old = fifoCat.shift();
|
|
132
|
+
if (!old) return false;
|
|
133
|
+
|
|
134
|
+
const sel = '.ezoic-ad-topic[data-ezoic-after="' + old.afterPos + '"][data-ezoic-id="' + old.id + '"]';
|
|
113
135
|
const $el = $(sel);
|
|
114
136
|
if ($el.length) $el.remove();
|
|
115
137
|
|
|
@@ -135,7 +157,6 @@ function callEzoic(ids) {
|
|
|
135
157
|
|
|
136
158
|
window.ezstandalone.cmd.push(function () { run(); });
|
|
137
159
|
|
|
138
|
-
// Retry (Ezoic can load late)
|
|
139
160
|
let tries = 0;
|
|
140
161
|
const maxTries = 6;
|
|
141
162
|
const timer = setInterval(function () {
|
|
@@ -144,93 +165,105 @@ function callEzoic(ids) {
|
|
|
144
165
|
}, 800);
|
|
145
166
|
}
|
|
146
167
|
|
|
147
|
-
function
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
168
|
+
function getPostNumber($post) {
|
|
169
|
+
const di = parseInt($post.attr('data-index'), 10);
|
|
170
|
+
if (Number.isFinite(di) && di > 0) return di;
|
|
171
|
+
|
|
172
|
+
const txt = ($post.find('a.post-index').first().text() || '').trim();
|
|
173
|
+
const m = txt.match(/#\s*(\d+)/);
|
|
174
|
+
if (m) return parseInt(m[1], 10);
|
|
175
|
+
|
|
176
|
+
return NaN;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function getTopicPos($item) {
|
|
180
|
+
const pos = parseInt($item.attr('data-index'), 10);
|
|
181
|
+
if (Number.isFinite(pos) && pos >= 0) return pos + 1;
|
|
182
|
+
const schemaPos = parseInt($item.find('meta[itemprop="position"]').attr('content'), 10);
|
|
183
|
+
if (Number.isFinite(schemaPos) && schemaPos > 0) return schemaPos;
|
|
184
|
+
return NaN;
|
|
185
|
+
}
|
|
151
186
|
|
|
187
|
+
function injectTopicMessageAds($posts, pool, interval) {
|
|
152
188
|
const newIds = [];
|
|
153
189
|
|
|
154
|
-
|
|
155
|
-
|
|
190
|
+
$posts.each(function () {
|
|
191
|
+
const $p = $(this);
|
|
192
|
+
const postNo = getPostNumber($p);
|
|
193
|
+
if (!Number.isFinite(postNo) || postNo <= 0) return;
|
|
156
194
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (!$target.length) continue;
|
|
195
|
+
if (postNo % interval !== 0) return;
|
|
196
|
+
if (seenAfterPostNo.has(postNo)) return;
|
|
160
197
|
|
|
161
198
|
let id = pickNextId(pool);
|
|
162
199
|
if (!id) {
|
|
163
|
-
if (!
|
|
200
|
+
if (!removeOldestTopicAd()) return;
|
|
164
201
|
id = pickNextId(pool);
|
|
165
|
-
if (!id)
|
|
202
|
+
if (!id) return;
|
|
166
203
|
}
|
|
167
204
|
|
|
168
|
-
const
|
|
205
|
+
const inner = '<div class="ezoic-ad-message-inner"><div id="ezoic-pub-ad-placeholder-' + id + '"></div></div>';
|
|
169
206
|
const html = makeWrapperLike(
|
|
170
|
-
$
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
'data-ezoic-
|
|
207
|
+
$p,
|
|
208
|
+
'ezoic-ad-post ezoic-ad',
|
|
209
|
+
inner,
|
|
210
|
+
'data-ezoic-after="' + postNo + '" data-ezoic-id="' + id + '"'
|
|
174
211
|
);
|
|
175
212
|
|
|
176
|
-
$
|
|
213
|
+
$p.after(html);
|
|
177
214
|
|
|
178
|
-
|
|
215
|
+
seenAfterPostNo.add(postNo);
|
|
179
216
|
usedIds.add(id);
|
|
180
|
-
|
|
217
|
+
fifo.push({ afterPostNo: postNo, id: id });
|
|
181
218
|
newIds.push(id);
|
|
182
|
-
}
|
|
219
|
+
});
|
|
183
220
|
|
|
184
221
|
return newIds;
|
|
185
222
|
}
|
|
186
223
|
|
|
187
|
-
function
|
|
188
|
-
const total = $posts.length;
|
|
189
|
-
const maxSlot = Math.floor(total / interval);
|
|
190
|
-
if (maxSlot <= 0) return [];
|
|
191
|
-
|
|
224
|
+
function injectCategoryBetweenAds($items, pool, interval) {
|
|
192
225
|
const newIds = [];
|
|
193
226
|
|
|
194
|
-
|
|
195
|
-
|
|
227
|
+
$items.each(function () {
|
|
228
|
+
const $it = $(this);
|
|
229
|
+
const pos = getTopicPos($it);
|
|
230
|
+
if (!Number.isFinite(pos) || pos <= 0) return;
|
|
196
231
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (!$target.length) continue;
|
|
232
|
+
if (pos % interval !== 0) return;
|
|
233
|
+
if (seenAfterTopicPos.has(pos)) return;
|
|
200
234
|
|
|
201
235
|
let id = pickNextId(pool);
|
|
202
236
|
if (!id) {
|
|
203
|
-
if (!
|
|
237
|
+
if (!removeOldestCategoryAd()) return;
|
|
204
238
|
id = pickNextId(pool);
|
|
205
|
-
if (!id)
|
|
239
|
+
if (!id) return;
|
|
206
240
|
}
|
|
207
241
|
|
|
208
|
-
|
|
209
|
-
const inner = '<div class="ezoic-ad-message-inner"><div id="ezoic-pub-ad-placeholder-' + id + '"></div></div>';
|
|
242
|
+
const placeholder = '<div id="ezoic-pub-ad-placeholder-' + id + '"></div>';
|
|
210
243
|
const html = makeWrapperLike(
|
|
211
|
-
$
|
|
212
|
-
'ezoic-ad-
|
|
213
|
-
|
|
214
|
-
'data-ezoic-
|
|
244
|
+
$it,
|
|
245
|
+
'ezoic-ad-topic ezoic-ad',
|
|
246
|
+
placeholder,
|
|
247
|
+
'data-ezoic-after="' + pos + '" data-ezoic-id="' + id + '"'
|
|
215
248
|
);
|
|
216
249
|
|
|
217
|
-
$
|
|
250
|
+
$it.after(html);
|
|
218
251
|
|
|
219
|
-
|
|
252
|
+
seenAfterTopicPos.add(pos);
|
|
220
253
|
usedIds.add(id);
|
|
221
|
-
|
|
254
|
+
fifoCat.push({ afterPos: pos, id: id });
|
|
222
255
|
newIds.push(id);
|
|
223
|
-
}
|
|
256
|
+
});
|
|
224
257
|
|
|
225
258
|
return newIds;
|
|
226
259
|
}
|
|
227
260
|
|
|
228
261
|
async function refreshAds() {
|
|
229
|
-
const key =
|
|
262
|
+
const key = getPageKey();
|
|
230
263
|
if (pageKey !== key) {
|
|
231
264
|
pageKey = key;
|
|
232
|
-
|
|
233
|
-
|
|
265
|
+
resetState();
|
|
266
|
+
cleanupOnNav();
|
|
234
267
|
}
|
|
235
268
|
|
|
236
269
|
if (inFlight) { rerunRequested = true; return; }
|
|
@@ -249,24 +282,21 @@ async function refreshAds() {
|
|
|
249
282
|
const onTopic = isTopicPage();
|
|
250
283
|
const onCategory = !onTopic && isCategoryTopicListPage();
|
|
251
284
|
|
|
252
|
-
const $posts = onTopic ? getTopicPosts() : $();
|
|
253
|
-
const $topicItems = onCategory ? getCategoryTopicItems() : $();
|
|
254
|
-
|
|
255
|
-
if (!$posts.length && !$topicItems.length) return;
|
|
256
|
-
|
|
257
285
|
const newIds = [];
|
|
258
286
|
|
|
259
|
-
if (
|
|
260
|
-
|
|
261
|
-
|
|
287
|
+
if (onCategory) {
|
|
288
|
+
const $items = getCategoryTopicItems();
|
|
289
|
+
if (cfg.enableBetweenAds && betweenPool.length && $items.length) {
|
|
290
|
+
newIds.push(...injectCategoryBetweenAds($items, betweenPool, betweenInterval));
|
|
262
291
|
}
|
|
263
292
|
callEzoic(newIds);
|
|
264
293
|
return;
|
|
265
294
|
}
|
|
266
295
|
|
|
267
|
-
if (
|
|
268
|
-
|
|
269
|
-
|
|
296
|
+
if (onTopic) {
|
|
297
|
+
const $posts = getTopicPosts();
|
|
298
|
+
if (cfg.enableMessageAds && messagePool.length && $posts.length) {
|
|
299
|
+
newIds.push(...injectTopicMessageAds($posts, messagePool, messageInterval));
|
|
270
300
|
}
|
|
271
301
|
callEzoic(newIds);
|
|
272
302
|
}
|
|
@@ -274,16 +304,16 @@ async function refreshAds() {
|
|
|
274
304
|
inFlight = false;
|
|
275
305
|
if (rerunRequested) {
|
|
276
306
|
rerunRequested = false;
|
|
277
|
-
setTimeout(refreshAds,
|
|
307
|
+
setTimeout(refreshAds, 160);
|
|
278
308
|
}
|
|
279
309
|
}
|
|
280
310
|
}
|
|
281
311
|
|
|
282
312
|
function debounceRefresh() {
|
|
283
313
|
clearTimeout(debounceTimer);
|
|
284
|
-
debounceTimer = setTimeout(refreshAds,
|
|
314
|
+
debounceTimer = setTimeout(refreshAds, 220);
|
|
285
315
|
}
|
|
286
316
|
|
|
287
317
|
$(document).ready(debounceRefresh);
|
|
288
318
|
$(window).on('action:ajaxify.end action:posts.loaded action:topic.loaded', debounceRefresh);
|
|
289
|
-
setTimeout(debounceRefresh,
|
|
319
|
+
setTimeout(debounceRefresh, 2200);
|