nodebb-plugin-ezoic-infinite 0.8.9 → 0.9.0
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/plugin.json +2 -2
- package/public/client.js +318 -255
- package/public/style.css +4 -2
package/package.json
CHANGED
package/plugin.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1,174 +1,174 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
2
|
/* globals ajaxify */
|
|
3
|
+
|
|
4
4
|
window.ezoicInfiniteLoaded = true;
|
|
5
5
|
|
|
6
|
-
let cachedConfig;
|
|
6
|
+
let cachedConfig = null;
|
|
7
7
|
let lastFetch = 0;
|
|
8
|
-
let debounceTimer;
|
|
9
|
-
|
|
10
8
|
let inFlight = false;
|
|
11
9
|
let rerunRequested = false;
|
|
10
|
+
let debounceTimer = null;
|
|
12
11
|
|
|
13
|
-
// Per-page state (keyed by tid/cid)
|
|
14
12
|
let pageKey = null;
|
|
15
13
|
|
|
16
|
-
//
|
|
17
|
-
let
|
|
18
|
-
let
|
|
19
|
-
let fifo = []; // [{afterPostNo, id}]
|
|
14
|
+
// Separate state per "mode" so category and topic don't leak ids
|
|
15
|
+
let usedBetween = new Set();
|
|
16
|
+
let usedMessages = new Set();
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
let
|
|
23
|
-
let
|
|
18
|
+
let seenBetweenAfter = new Set(); // category: after absolute topic position
|
|
19
|
+
let fifoBetween = []; // [{afterPos, id}]
|
|
20
|
+
let seenMsgAfter = new Set(); // topic: after absolute post number
|
|
21
|
+
let fifoMsg = []; // [{afterPostNo, id}]
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
usedIds = new Set();
|
|
29
|
-
fifo = [];
|
|
30
|
-
fifoCat = [];
|
|
31
|
-
}
|
|
23
|
+
// Destroy spam guard
|
|
24
|
+
window.__ezoicLastDestroy = window.__ezoicLastDestroy || {};
|
|
25
|
+
window.__ezoicRecycling = false;
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
} catch (e) {}
|
|
40
|
-
return window.location.pathname;
|
|
41
|
-
}
|
|
27
|
+
// ---------- Config ----------
|
|
28
|
+
async function fetchConfig() {
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
if (cachedConfig && (now - lastFetch) < 5000) return cachedConfig;
|
|
31
|
+
lastFetch = now;
|
|
42
32
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
.
|
|
48
|
-
|
|
49
|
-
|
|
33
|
+
try {
|
|
34
|
+
const res = await fetch('/api/admin/settings/ezoic-infinite', { credentials: 'same-origin' });
|
|
35
|
+
const data = await res.json();
|
|
36
|
+
cachedConfig = {
|
|
37
|
+
excluded: !!data.excluded,
|
|
38
|
+
enableBetweenAds: data.enableBetweenAds !== false,
|
|
39
|
+
placeholderIds: String(data.placeholderIds || '').trim(),
|
|
40
|
+
intervalPosts: parseInt(data.intervalPosts, 10) || 6,
|
|
41
|
+
|
|
42
|
+
enableMessageAds: data.enableMessageAds !== false,
|
|
43
|
+
messagePlaceholderIds: String(data.messagePlaceholderIds || '').trim(),
|
|
44
|
+
messageIntervalPosts: parseInt(data.messageIntervalPosts, 10) || 3,
|
|
45
|
+
};
|
|
46
|
+
return cachedConfig;
|
|
47
|
+
} catch (e) {
|
|
48
|
+
return cachedConfig || {
|
|
49
|
+
excluded: false,
|
|
50
|
+
enableBetweenAds: true,
|
|
51
|
+
placeholderIds: '',
|
|
52
|
+
intervalPosts: 6,
|
|
53
|
+
enableMessageAds: true,
|
|
54
|
+
messagePlaceholderIds: '',
|
|
55
|
+
messageIntervalPosts: 3,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
50
58
|
}
|
|
51
59
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
function parsePool(text) {
|
|
61
|
+
return String(text || '')
|
|
62
|
+
.split(/\r?\n|,|;/g)
|
|
63
|
+
.map(s => s.trim())
|
|
64
|
+
.filter(Boolean)
|
|
65
|
+
.map(s => parseInt(s, 10))
|
|
66
|
+
.filter(n => Number.isFinite(n) && n > 0);
|
|
58
67
|
}
|
|
59
68
|
|
|
69
|
+
// ---------- Page detection ----------
|
|
60
70
|
function isTopicPage() {
|
|
61
|
-
|
|
71
|
+
try {
|
|
72
|
+
if (ajaxify && ajaxify.data && ajaxify.data.tid) return true;
|
|
73
|
+
} catch (e) {}
|
|
74
|
+
return /^\/topic\//.test(window.location.pathname);
|
|
62
75
|
}
|
|
63
76
|
|
|
64
77
|
function isCategoryTopicListPage() {
|
|
65
|
-
return
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function getTopicPosts() {
|
|
69
|
-
const $primary = $('[component="post"][data-pid]');
|
|
70
|
-
if ($primary.length) return $primary;
|
|
71
|
-
|
|
72
|
-
// fallback: top-level with post/content
|
|
73
|
-
return $('[data-pid]').filter(function () {
|
|
74
|
-
const $el = $(this);
|
|
75
|
-
const hasContent = $el.find('[component="post/content"]').length > 0;
|
|
76
|
-
const nested = $el.parents('[data-pid]').length > 0;
|
|
77
|
-
return hasContent && !nested;
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function getCategoryTopicItems() {
|
|
82
|
-
return $('li[component="category/topic"]');
|
|
78
|
+
return document.querySelectorAll('li[component="category/topic"]').length > 0;
|
|
83
79
|
}
|
|
84
80
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return
|
|
81
|
+
function getPageKey() {
|
|
82
|
+
try {
|
|
83
|
+
if (ajaxify && ajaxify.data) {
|
|
84
|
+
if (ajaxify.data.tid) return `topic:${ajaxify.data.tid}`;
|
|
85
|
+
if (ajaxify.data.cid) return `category:${ajaxify.data.cid}`;
|
|
86
|
+
}
|
|
87
|
+
} catch (e) {}
|
|
88
|
+
return `path:${window.location.pathname}`;
|
|
93
89
|
}
|
|
94
90
|
|
|
95
|
-
function
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
91
|
+
function resetState() {
|
|
92
|
+
usedBetween = new Set();
|
|
93
|
+
usedMessages = new Set();
|
|
94
|
+
seenBetweenAfter = new Set();
|
|
95
|
+
seenMsgAfter = new Set();
|
|
96
|
+
fifoBetween = [];
|
|
97
|
+
fifoMsg = [];
|
|
98
|
+
window.__ezoicLastShowKey = null;
|
|
99
|
+
window.__ezoicLastShowAt = 0;
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
function cleanupOnNav() {
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function pickNextId(pool) {
|
|
109
|
-
for (const id of pool) {
|
|
110
|
-
if (!usedIds.has(id)) return id;
|
|
111
|
-
}
|
|
112
|
-
return null;
|
|
103
|
+
document.querySelectorAll('.ezoic-ad-post, .ezoic-ad-topic, .ezoic-ad').forEach(el => el.remove());
|
|
113
104
|
}
|
|
114
105
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
if (
|
|
119
|
-
|
|
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();
|
|
106
|
+
// ---------- Ezoic helpers ----------
|
|
107
|
+
function destroyEzoicId(id) {
|
|
108
|
+
const now = Date.now();
|
|
109
|
+
if (window.__ezoicLastDestroy[id] && (now - window.__ezoicLastDestroy[id]) < 2000) return;
|
|
110
|
+
window.__ezoicLastDestroy[id] = now;
|
|
123
111
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
112
|
+
try {
|
|
113
|
+
window.ezstandalone = window.ezstandalone || {};
|
|
114
|
+
if (typeof window.ezstandalone.destroyPlaceholders === 'function') {
|
|
115
|
+
window.ezstandalone.destroyPlaceholders(id);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
window.ezstandalone.cmd = window.ezstandalone.cmd || [];
|
|
119
|
+
window.ezstandalone.cmd.push(function () {
|
|
120
|
+
try {
|
|
121
|
+
if (typeof window.ezstandalone.destroyPlaceholders === 'function') {
|
|
122
|
+
window.ezstandalone.destroyPlaceholders(id);
|
|
123
|
+
}
|
|
124
|
+
} catch (e) {}
|
|
125
|
+
});
|
|
126
|
+
} catch (e) {}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
// Auto-height: hide until filled
|
|
130
|
+
function setupAdAutoHeight() {
|
|
131
|
+
if (window.__ezoicAutoHeightAttached) return;
|
|
132
|
+
window.__ezoicAutoHeightAttached = true;
|
|
133
133
|
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
const attach = function () {
|
|
135
|
+
document.querySelectorAll('.ezoic-ad').forEach(function (wrap) {
|
|
136
|
+
if (!wrap.classList.contains('ezoic-filled')) {
|
|
137
|
+
wrap.style.display = 'none';
|
|
138
|
+
}
|
|
139
|
+
const ph = wrap.querySelector('[id^="ezoic-pub-ad-placeholder-"]');
|
|
140
|
+
if (ph && ph.children && ph.children.length) {
|
|
141
|
+
wrap.classList.add('ezoic-filled');
|
|
142
|
+
wrap.style.display = '';
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
};
|
|
137
146
|
|
|
138
|
-
|
|
139
|
-
|
|
147
|
+
attach();
|
|
148
|
+
setTimeout(attach, 500);
|
|
149
|
+
setTimeout(attach, 1500);
|
|
150
|
+
setTimeout(attach, 3000);
|
|
151
|
+
setInterval(attach, 1000);
|
|
140
152
|
}
|
|
141
153
|
|
|
142
154
|
function callEzoic(ids) {
|
|
143
|
-
// ids optional; if omitted, we will scan DOM for unrendered placeholders
|
|
144
155
|
window.ezstandalone = window.ezstandalone || {};
|
|
145
156
|
window.ezstandalone.cmd = window.ezstandalone.cmd || [];
|
|
146
157
|
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
document.querySelectorAll('.ezoic-ad [id^="ezoic-pub-ad-placeholder-"]').forEach(function (ph) {
|
|
150
|
-
const idStr = ph.id.replace('ezoic-pub-ad-placeholder-', '');
|
|
151
|
-
const id = parseInt(idStr, 10);
|
|
152
|
-
if (!Number.isFinite(id) || id <= 0) return;
|
|
158
|
+
const uniq = Array.from(new Set(ids || []));
|
|
159
|
+
if (!uniq.length) return;
|
|
153
160
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
});
|
|
161
|
-
// de-dupe
|
|
162
|
-
return Array.from(new Set(list));
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
const toShow = (ids && ids.length) ? Array.from(new Set(ids)) : collect();
|
|
166
|
-
if (!toShow.length) return;
|
|
161
|
+
// De-dupe rapid duplicates
|
|
162
|
+
const key = uniq.join(',');
|
|
163
|
+
const now = Date.now();
|
|
164
|
+
if (window.__ezoicLastShowKey === key && (now - (window.__ezoicLastShowAt || 0)) < 1200) return;
|
|
165
|
+
window.__ezoicLastShowKey = key;
|
|
166
|
+
window.__ezoicLastShowAt = now;
|
|
167
167
|
|
|
168
168
|
const run = function () {
|
|
169
169
|
try {
|
|
170
170
|
if (typeof window.ezstandalone.showAds === 'function') {
|
|
171
|
-
window.ezstandalone.showAds.apply(window.ezstandalone,
|
|
171
|
+
window.ezstandalone.showAds.apply(window.ezstandalone, uniq);
|
|
172
172
|
return true;
|
|
173
173
|
}
|
|
174
174
|
} catch (e) {}
|
|
@@ -179,194 +179,235 @@ function callEzoic(ids) {
|
|
|
179
179
|
window.ezstandalone.cmd.push(function () { run(); });
|
|
180
180
|
|
|
181
181
|
// Retry only if showAds isn't available yet
|
|
182
|
-
let tries = 0;
|
|
183
|
-
const maxTries = 6;
|
|
184
|
-
const retry = function () {
|
|
185
|
-
tries++;
|
|
186
|
-
const ok = run();
|
|
187
|
-
if (ok) return;
|
|
188
|
-
try {
|
|
189
|
-
if (typeof window.ezstandalone.showAds === 'function') return;
|
|
190
|
-
} catch (e) {}
|
|
191
|
-
if (tries < maxTries) setTimeout(retry, 800);
|
|
192
|
-
};
|
|
193
|
-
|
|
194
182
|
try {
|
|
195
183
|
if (typeof window.ezstandalone.showAds !== 'function') {
|
|
184
|
+
let tries = 0;
|
|
185
|
+
const retry = function () {
|
|
186
|
+
tries++;
|
|
187
|
+
if (run()) return;
|
|
188
|
+
if (tries < 6) setTimeout(retry, 800);
|
|
189
|
+
};
|
|
196
190
|
setTimeout(retry, 800);
|
|
197
191
|
}
|
|
198
|
-
} catch (e) {
|
|
199
|
-
setTimeout(retry, 800);
|
|
200
|
-
}
|
|
192
|
+
} catch (e) {}
|
|
201
193
|
}
|
|
202
194
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (m) return parseInt(m[1], 10);
|
|
210
|
-
|
|
211
|
-
return NaN;
|
|
195
|
+
// ---------- Pool logic ----------
|
|
196
|
+
function pickNextId(pool, usedSet) {
|
|
197
|
+
for (const id of pool) {
|
|
198
|
+
if (!usedSet.has(id)) return id;
|
|
199
|
+
}
|
|
200
|
+
return null;
|
|
212
201
|
}
|
|
213
202
|
|
|
214
|
-
function
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
203
|
+
function recycleOldest(fifo, usedSet, selector, avoidAfterNode) {
|
|
204
|
+
if (window.__ezoicRecycling) return null;
|
|
205
|
+
window.__ezoicRecycling = true;
|
|
206
|
+
try {
|
|
207
|
+
fifo.sort((a, b) => (a.after - b.after));
|
|
208
|
+
while (fifo.length) {
|
|
209
|
+
const old = fifo.shift();
|
|
210
|
+
const el = document.querySelector(selector(old));
|
|
211
|
+
if (!el) continue;
|
|
212
|
+
|
|
213
|
+
// Don't recycle if it is right after the last real item (protect sentinel)
|
|
214
|
+
try {
|
|
215
|
+
if (avoidAfterNode && el.previousElementSibling === avoidAfterNode) {
|
|
216
|
+
fifo.push(old);
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
} catch (e) {}
|
|
221
220
|
|
|
222
|
-
|
|
223
|
-
|
|
221
|
+
el.remove();
|
|
222
|
+
usedSet.delete(old.id);
|
|
223
|
+
destroyEzoicId(old.id);
|
|
224
|
+
return old.id;
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
} finally {
|
|
228
|
+
window.__ezoicRecycling = false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
224
231
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
if (!Number.isFinite(postNo) || postNo <= 0) return;
|
|
232
|
+
// ---------- Injection ----------
|
|
233
|
+
function injectBetweenAds(config) {
|
|
234
|
+
if (!config.enableBetweenAds) return;
|
|
235
|
+
const pool = parsePool(config.placeholderIds);
|
|
236
|
+
if (!pool.length) return;
|
|
231
237
|
|
|
232
|
-
|
|
233
|
-
|
|
238
|
+
const interval = Math.max(1, config.intervalPosts);
|
|
239
|
+
const items = Array.from(document.querySelectorAll('li[component="category/topic"]'));
|
|
240
|
+
if (!items.length) return;
|
|
234
241
|
|
|
235
|
-
|
|
236
|
-
|
|
242
|
+
const newIds = [];
|
|
243
|
+
const lastItem = items[items.length - 1];
|
|
244
|
+
|
|
245
|
+
for (let i = 0; i < items.length; i++) {
|
|
246
|
+
const pos = i + 1; // absolute position in loaded list
|
|
247
|
+
if (pos % interval !== 0) continue;
|
|
248
|
+
if (seenBetweenAfter.has(pos)) continue;
|
|
249
|
+
|
|
250
|
+
let id = pickNextId(pool, usedBetween);
|
|
251
|
+
if (!id) {
|
|
252
|
+
// recycle oldest
|
|
253
|
+
id = recycleOldest(
|
|
254
|
+
fifoBetween,
|
|
255
|
+
usedBetween,
|
|
256
|
+
(o) => `.ezoic-ad-topic[data-ezoic-after="${o.after}"][data-ezoic-id="${o.id}"]`,
|
|
257
|
+
lastItem
|
|
258
|
+
);
|
|
259
|
+
if (!id) break;
|
|
260
|
+
}
|
|
237
261
|
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
);
|
|
262
|
+
const anchor = items[i];
|
|
263
|
+
const wrap = document.createElement('li');
|
|
264
|
+
wrap.className = 'ezoic-ad ezoic-ad-topic';
|
|
265
|
+
wrap.setAttribute('data-ezoic-after', String(pos));
|
|
266
|
+
wrap.setAttribute('data-ezoic-id', String(id));
|
|
267
|
+
wrap.innerHTML = `<div id="ezoic-pub-ad-placeholder-${id}"></div>`;
|
|
245
268
|
|
|
246
|
-
|
|
269
|
+
anchor.insertAdjacentElement('afterend', wrap);
|
|
247
270
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
271
|
+
seenBetweenAfter.add(pos);
|
|
272
|
+
usedBetween.add(id);
|
|
273
|
+
fifoBetween.push({ after: pos, id });
|
|
251
274
|
newIds.push(id);
|
|
252
|
-
}
|
|
275
|
+
}
|
|
253
276
|
|
|
254
|
-
|
|
277
|
+
if (newIds.length) callEzoic(newIds);
|
|
255
278
|
}
|
|
256
279
|
|
|
257
|
-
function
|
|
258
|
-
|
|
280
|
+
function getPostNumberFromPost(postEl) {
|
|
281
|
+
// Prefer post-index text (#72)
|
|
282
|
+
try {
|
|
283
|
+
const idx = postEl.querySelector('a.post-index');
|
|
284
|
+
if (idx) {
|
|
285
|
+
const n = parseInt(String(idx.textContent || '').replace('#', '').trim(), 10);
|
|
286
|
+
if (Number.isFinite(n)) return n;
|
|
287
|
+
}
|
|
288
|
+
} catch (e) {}
|
|
289
|
+
|
|
290
|
+
// Fallback: pid-based ordering not reliable, but DOM order is ok for interval within loaded window.
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
259
293
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const pos = getTopicPos($it);
|
|
265
|
-
if (!Number.isFinite(pos) || pos <= 0) return;
|
|
294
|
+
function injectMessageAds(config) {
|
|
295
|
+
if (!config.enableMessageAds) return;
|
|
296
|
+
const pool = parsePool(config.messagePlaceholderIds);
|
|
297
|
+
if (!pool.length) return;
|
|
266
298
|
|
|
267
|
-
|
|
268
|
-
|
|
299
|
+
const interval = Math.max(1, config.messageIntervalPosts);
|
|
300
|
+
const posts = Array.from(document.querySelectorAll('[component="post"][data-pid]'));
|
|
301
|
+
if (!posts.length) return;
|
|
269
302
|
|
|
270
|
-
|
|
271
|
-
|
|
303
|
+
const newIds = [];
|
|
304
|
+
const lastPost = posts[posts.length - 1];
|
|
305
|
+
|
|
306
|
+
// Determine absolute post numbers if available; else use DOM position
|
|
307
|
+
let numbers = posts.map((p, i) => ({ el: p, no: getPostNumberFromPost(p) || (i + 1) }));
|
|
308
|
+
// Ensure strictly increasing by DOM
|
|
309
|
+
numbers = numbers.map((x, i) => ({ el: x.el, no: x.no || (i + 1) }));
|
|
310
|
+
|
|
311
|
+
for (const entry of numbers) {
|
|
312
|
+
const afterNo = entry.no;
|
|
313
|
+
if (afterNo % interval !== 0) continue;
|
|
314
|
+
if (seenMsgAfter.has(afterNo)) continue;
|
|
315
|
+
|
|
316
|
+
let id = pickNextId(pool, usedMessages);
|
|
317
|
+
if (!id) {
|
|
318
|
+
id = recycleOldest(
|
|
319
|
+
fifoMsg,
|
|
320
|
+
usedMessages,
|
|
321
|
+
(o) => `.ezoic-ad-post[data-ezoic-after="${o.after}"][data-ezoic-id="${o.id}"]`,
|
|
322
|
+
lastPost
|
|
323
|
+
);
|
|
324
|
+
if (!id) break;
|
|
325
|
+
}
|
|
272
326
|
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
'data-ezoic-after="' + pos + '" data-ezoic-id="' + id + '"'
|
|
279
|
-
);
|
|
327
|
+
const wrap = document.createElement('div');
|
|
328
|
+
wrap.className = 'ezoic-ad ezoic-ad-post';
|
|
329
|
+
wrap.setAttribute('data-ezoic-after', String(afterNo));
|
|
330
|
+
wrap.setAttribute('data-ezoic-id', String(id));
|
|
331
|
+
wrap.innerHTML = `<div class="ezoic-ad-message-inner"><div id="ezoic-pub-ad-placeholder-${id}"></div></div>`;
|
|
280
332
|
|
|
281
|
-
|
|
333
|
+
entry.el.insertAdjacentElement('afterend', wrap);
|
|
282
334
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
335
|
+
seenMsgAfter.add(afterNo);
|
|
336
|
+
usedMessages.add(id);
|
|
337
|
+
fifoMsg.push({ after: afterNo, id });
|
|
286
338
|
newIds.push(id);
|
|
287
|
-
}
|
|
339
|
+
}
|
|
288
340
|
|
|
289
|
-
|
|
341
|
+
if (newIds.length) callEzoic(newIds);
|
|
290
342
|
}
|
|
291
343
|
|
|
344
|
+
// ---------- Main refresh ----------
|
|
292
345
|
async function refreshAds() {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
resetState();
|
|
297
|
-
cleanupOnNav();
|
|
346
|
+
if (inFlight) {
|
|
347
|
+
rerunRequested = true;
|
|
348
|
+
return;
|
|
298
349
|
}
|
|
299
|
-
|
|
300
|
-
if (inFlight) { rerunRequested = true; return; }
|
|
301
350
|
inFlight = true;
|
|
351
|
+
rerunRequested = false;
|
|
302
352
|
|
|
303
353
|
try {
|
|
304
354
|
const cfg = await fetchConfig();
|
|
305
|
-
if (
|
|
355
|
+
if (cfg.excluded) return;
|
|
306
356
|
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
357
|
+
const key = getPageKey();
|
|
358
|
+
if (key !== pageKey) {
|
|
359
|
+
pageKey = key;
|
|
360
|
+
resetState();
|
|
361
|
+
cleanupOnNav();
|
|
362
|
+
}
|
|
312
363
|
|
|
313
364
|
const onTopic = isTopicPage();
|
|
314
|
-
const onCategory =
|
|
315
|
-
|
|
316
|
-
const newIds = [];
|
|
317
|
-
|
|
318
|
-
if (onCategory) {
|
|
319
|
-
const $items = getCategoryTopicItems();
|
|
320
|
-
if (cfg.enableBetweenAds && betweenPool.length && $items.length) {
|
|
321
|
-
newIds.push(...injectCategoryBetweenAds($items, betweenPool, betweenInterval));
|
|
322
|
-
}
|
|
323
|
-
callEzoic(newIds);
|
|
324
|
-
callEzoic();
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
365
|
+
const onCategory = isCategoryTopicListPage() && !onTopic;
|
|
327
366
|
|
|
328
|
-
if (
|
|
329
|
-
|
|
330
|
-
if (cfg.enableMessageAds && messagePool.length && $posts.length) {
|
|
331
|
-
newIds.push(...injectTopicMessageAds($posts, messagePool, messageInterval));
|
|
332
|
-
}
|
|
333
|
-
callEzoic(newIds);
|
|
334
|
-
callEzoic();
|
|
335
|
-
}
|
|
367
|
+
if (onCategory) injectBetweenAds(cfg);
|
|
368
|
+
if (onTopic) injectMessageAds(cfg);
|
|
336
369
|
} finally {
|
|
337
370
|
inFlight = false;
|
|
338
|
-
if (rerunRequested)
|
|
339
|
-
rerunRequested = false;
|
|
340
|
-
setTimeout(refreshAds, 160);
|
|
341
|
-
}
|
|
371
|
+
if (rerunRequested) setTimeout(refreshAds, 50);
|
|
342
372
|
}
|
|
343
373
|
}
|
|
344
374
|
|
|
345
375
|
function debounceRefresh() {
|
|
346
|
-
clearTimeout(debounceTimer);
|
|
347
|
-
debounceTimer = setTimeout(refreshAds,
|
|
376
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
377
|
+
debounceTimer = setTimeout(refreshAds, 250);
|
|
348
378
|
}
|
|
349
379
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
380
|
+
// ---------- Observers / Events ----------
|
|
381
|
+
(function setupTriggers() {
|
|
382
|
+
// Ajaxify navigation: only cleanup when URL changes
|
|
383
|
+
$(window).on('action:ajaxify.start', function (ev, data) {
|
|
384
|
+
try {
|
|
385
|
+
const targetUrl = (data && (data.url || data.href)) ? String(data.url || data.href) : '';
|
|
386
|
+
if (targetUrl) {
|
|
387
|
+
const a = document.createElement('a');
|
|
388
|
+
a.href = targetUrl;
|
|
389
|
+
const targetPath = a.pathname || targetUrl;
|
|
390
|
+
if (targetPath === window.location.pathname) return;
|
|
391
|
+
}
|
|
392
|
+
} catch (e) {}
|
|
393
|
+
pageKey = null;
|
|
394
|
+
resetState();
|
|
395
|
+
cleanupOnNav();
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
$(window).on('action:ajaxify.end action:posts.loaded action:topics.loaded action:topic.loaded action:category.loaded', debounceRefresh);
|
|
353
399
|
|
|
354
|
-
//
|
|
355
|
-
// Observe DOM additions and trigger a refresh when new posts/topics are appended/prepended.
|
|
356
|
-
(function setupEzoicObserver() {
|
|
357
|
-
if (window.__ezoicInfiniteObserver) return;
|
|
400
|
+
// MutationObserver (new posts/topics appended)
|
|
358
401
|
try {
|
|
359
402
|
const obs = new MutationObserver(function (mutations) {
|
|
360
403
|
for (const m of mutations) {
|
|
361
|
-
if (!m.addedNodes
|
|
404
|
+
if (!m.addedNodes) continue;
|
|
362
405
|
for (const n of m.addedNodes) {
|
|
363
406
|
if (!n || n.nodeType !== 1) continue;
|
|
364
|
-
// direct match
|
|
365
407
|
if (n.matches && (n.matches('[component="post"][data-pid]') || n.matches('li[component="category/topic"]'))) {
|
|
366
408
|
debounceRefresh();
|
|
367
409
|
return;
|
|
368
410
|
}
|
|
369
|
-
// descendant match
|
|
370
411
|
if (n.querySelector && (n.querySelector('[component="post"][data-pid]') || n.querySelector('li[component="category/topic"]'))) {
|
|
371
412
|
debounceRefresh();
|
|
372
413
|
return;
|
|
@@ -377,4 +418,26 @@ setTimeout(debounceRefresh, 2200);
|
|
|
377
418
|
obs.observe(document.body, { childList: true, subtree: true });
|
|
378
419
|
window.__ezoicInfiniteObserver = obs;
|
|
379
420
|
} catch (e) {}
|
|
421
|
+
|
|
422
|
+
// Poller fallback (count changes)
|
|
423
|
+
let lastPosts = 0;
|
|
424
|
+
let lastTopics = 0;
|
|
425
|
+
setInterval(function () {
|
|
426
|
+
const p = document.querySelectorAll('[component="post"][data-pid]').length;
|
|
427
|
+
const t = document.querySelectorAll('li[component="category/topic"]').length;
|
|
428
|
+
if (p !== lastPosts || t !== lastTopics) {
|
|
429
|
+
lastPosts = p; lastTopics = t;
|
|
430
|
+
debounceRefresh();
|
|
431
|
+
}
|
|
432
|
+
}, 1500);
|
|
433
|
+
|
|
434
|
+
// First run(s) - important for hard load
|
|
435
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
436
|
+
debounceRefresh();
|
|
437
|
+
setTimeout(debounceRefresh, 1500);
|
|
438
|
+
setTimeout(debounceRefresh, 5000);
|
|
439
|
+
setTimeout(debounceRefresh, 10000);
|
|
440
|
+
});
|
|
441
|
+
// In case this script loads after DOMContentLoaded
|
|
442
|
+
setTimeout(debounceRefresh, 800);
|
|
380
443
|
})();
|
package/public/style.css
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
.ezoic-ad-
|
|
2
|
-
.ezoic-ad-
|
|
1
|
+
.ezoic-ad{min-height:0 !important;height:auto !important;padding:0 !important;margin:0.5rem 0;}
|
|
2
|
+
.ezoic-ad:not(.ezoic-filled){display:none !important;}
|
|
3
|
+
.ezoic-ad-message-inner{padding:0;margin:0;}
|
|
4
|
+
.ezoic-ad-message-inner > div{margin:0;padding:0;}
|