nodebb-plugin-ezoic-infinite 0.5.2 → 0.5.4
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/admin.js +4 -13
- package/public/client.js +49 -43
- package/public/templates/admin/plugins/ezoic-infinite.tpl +1 -1
package/package.json
CHANGED
package/plugin.json
CHANGED
package/public/admin.js
CHANGED
|
@@ -9,27 +9,18 @@
|
|
|
9
9
|
require(['settings', 'alerts'], function (Settings, alerts) {
|
|
10
10
|
Settings.load('ezoic-infinite', $form);
|
|
11
11
|
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
const $btn = $('#save');
|
|
15
|
-
$btn.prop('disabled', true);
|
|
12
|
+
$('#save').off('click.ezoicInfinite').on('click.ezoicInfinite', function (e) {
|
|
13
|
+
e.preventDefault();
|
|
16
14
|
|
|
17
|
-
// Settings.save signature differs slightly across versions; keep compatible
|
|
18
15
|
Settings.save('ezoic-infinite', $form, function () {
|
|
16
|
+
// Toast vert (NodeBB core)
|
|
19
17
|
if (alerts && typeof alerts.success === 'function') {
|
|
20
18
|
alerts.success('Enregistré');
|
|
21
19
|
} else if (window.app && typeof window.app.alertSuccess === 'function') {
|
|
22
20
|
window.app.alertSuccess('Enregistré');
|
|
23
21
|
}
|
|
24
|
-
$btn.prop('disabled', false);
|
|
25
22
|
});
|
|
26
|
-
|
|
27
|
-
// Fallback: re-enable even if callback not fired (mobile sometimes)
|
|
28
|
-
setTimeout(function () { $btn.prop('disabled', false); }, 4000);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
$form.off('submit.ezoicInfinite').on('submit.ezoicInfinite', doSave);
|
|
32
|
-
$('#save').off('click.ezoicInfinite').on('click.ezoicInfinite', doSave);
|
|
23
|
+
});
|
|
33
24
|
});
|
|
34
25
|
}
|
|
35
26
|
|
package/public/client.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* globals ajaxify */
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
window.ezoicInfiniteLoaded = true;
|
|
5
|
+
|
|
4
6
|
let cachedConfig;
|
|
5
7
|
let lastFetch = 0;
|
|
6
8
|
let debounceTimer;
|
|
@@ -22,14 +24,30 @@ function parsePool(raw) {
|
|
|
22
24
|
));
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Harmony: the real post wrapper is usually [component="post"][data-pid]
|
|
29
|
+
* We must avoid counting nested nodes like component="post/parent" or other elements
|
|
30
|
+
* that can also carry data-pid in some setups.
|
|
31
|
+
*/
|
|
25
32
|
function getTopicPosts() {
|
|
26
|
-
const $
|
|
27
|
-
if ($
|
|
33
|
+
const $primary = $('[component="post"][data-pid]');
|
|
34
|
+
if ($primary.length) return $primary.not('.ezoic-ad-post');
|
|
35
|
+
|
|
36
|
+
// Fallback: top-level nodes with data-pid that contain the post content,
|
|
37
|
+
// excluding nodes nested inside another data-pid container.
|
|
38
|
+
const $top = $('[data-pid]').filter(function () {
|
|
39
|
+
const $el = $(this);
|
|
40
|
+
const hasContent = $el.find('[component="post/content"]').length > 0;
|
|
41
|
+
const nested = $el.parents('[data-pid]').length > 0;
|
|
42
|
+
return hasContent && !nested;
|
|
43
|
+
});
|
|
44
|
+
if ($top.length) return $top.not('.ezoic-ad-post');
|
|
45
|
+
|
|
28
46
|
return $('.posts .post').not('.ezoic-ad-post');
|
|
29
47
|
}
|
|
30
48
|
|
|
31
|
-
function
|
|
32
|
-
return ($el && $el.length
|
|
49
|
+
function tagName($el) {
|
|
50
|
+
return ($el && $el.length ? (($el.prop('tagName') || '').toUpperCase()) : '');
|
|
33
51
|
}
|
|
34
52
|
|
|
35
53
|
function removePlaceholdersByPool(pool) {
|
|
@@ -42,42 +60,25 @@ function removeAdWrappers() {
|
|
|
42
60
|
}
|
|
43
61
|
|
|
44
62
|
function computeWindowSlots(totalItems, interval, poolSize) {
|
|
63
|
+
// totalItems posts -> number of ad slots at positions interval, 2*interval, ...
|
|
45
64
|
const slots = Math.floor(totalItems / interval);
|
|
46
65
|
if (slots <= 0) return [];
|
|
66
|
+
|
|
67
|
+
// IMPORTANT:
|
|
68
|
+
// We cannot display more than poolSize ads at once because Ezoic placeholder IDs
|
|
69
|
+
// must be unique on the page. If slots > poolSize, we only render the latest poolSize slots.
|
|
47
70
|
const start = Math.max(1, slots - poolSize + 1);
|
|
48
71
|
const out = [];
|
|
49
72
|
for (let s = start; s <= slots; s++) out.push(s);
|
|
50
73
|
return out;
|
|
51
74
|
}
|
|
52
75
|
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
'<div id="ezoic-pub-ad-placeholder-' + placeholderId + '"></div>' +
|
|
58
|
-
'</li>'
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
return '<div class="ezoic-ad-between" id="ezoic-pub-ad-placeholder-' + placeholderId + '"></div>';
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function makeAdMessageWrapper($targetPost, placeholderId) {
|
|
65
|
-
if (isLi($targetPost)) {
|
|
66
|
-
return (
|
|
67
|
-
'<li class="post ezoic-ad-post" data-ezoic-ad="1">' +
|
|
68
|
-
'<div class="content">' +
|
|
69
|
-
'<div id="ezoic-pub-ad-placeholder-' + placeholderId + '"></div>' +
|
|
70
|
-
'</div>' +
|
|
71
|
-
'</li>'
|
|
72
|
-
);
|
|
76
|
+
function makeWrapperLike($target, classes, innerHtml) {
|
|
77
|
+
const t = tagName($target);
|
|
78
|
+
if (t === 'LI') {
|
|
79
|
+
return '<li class="' + classes + ' list-unstyled" data-ezoic-ad="1">' + innerHtml + '</li>';
|
|
73
80
|
}
|
|
74
|
-
return
|
|
75
|
-
'<div class="post ezoic-ad-post" data-ezoic-ad="1">' +
|
|
76
|
-
'<div class="content">' +
|
|
77
|
-
'<div id="ezoic-pub-ad-placeholder-' + placeholderId + '"></div>' +
|
|
78
|
-
'</div>' +
|
|
79
|
-
'</div>'
|
|
80
|
-
);
|
|
81
|
+
return '<div class="' + classes + '" data-ezoic-ad="1">' + innerHtml + '</div>';
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
function insertBetweenPosts($posts, pool, interval) {
|
|
@@ -88,12 +89,13 @@ function insertBetweenPosts($posts, pool, interval) {
|
|
|
88
89
|
const activeIds = [];
|
|
89
90
|
for (let i = 0; i < slotsToRender.length; i++) {
|
|
90
91
|
const slotNumber = slotsToRender[i];
|
|
91
|
-
const id = pool[i];
|
|
92
|
-
const index = slotNumber * interval - 1;
|
|
92
|
+
const id = pool[i]; // map latest slots to pool in order
|
|
93
|
+
const index = slotNumber * interval - 1; // 0-based index of the post after which we insert
|
|
93
94
|
const $target = $posts.eq(index);
|
|
94
95
|
if (!$target.length) continue;
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
const html = makeWrapperLike($target, 'ezoic-ad-between', '<div id="ezoic-pub-ad-placeholder-' + id + '"></div>');
|
|
98
|
+
$target.after(html);
|
|
97
99
|
activeIds.push(id);
|
|
98
100
|
}
|
|
99
101
|
return activeIds;
|
|
@@ -112,7 +114,9 @@ function insertAdMessagesBetweenReplies($posts, pool, interval) {
|
|
|
112
114
|
const $target = $posts.eq(index);
|
|
113
115
|
if (!$target.length) continue;
|
|
114
116
|
|
|
115
|
-
|
|
117
|
+
const inner = '<div class="content"><div id="ezoic-pub-ad-placeholder-' + id + '"></div></div>';
|
|
118
|
+
const html = makeWrapperLike($target, 'post ezoic-ad-post', inner);
|
|
119
|
+
$target.after(html);
|
|
116
120
|
activeIds.push(id);
|
|
117
121
|
}
|
|
118
122
|
return activeIds;
|
|
@@ -120,11 +124,7 @@ function insertAdMessagesBetweenReplies($posts, pool, interval) {
|
|
|
120
124
|
|
|
121
125
|
async function refreshAds() {
|
|
122
126
|
let cfg;
|
|
123
|
-
try {
|
|
124
|
-
cfg = await fetchConfig();
|
|
125
|
-
} catch (e) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
127
|
+
try { cfg = await fetchConfig(); } catch (e) { return; }
|
|
128
128
|
if (!cfg || cfg.excluded) return;
|
|
129
129
|
|
|
130
130
|
const betweenPool = parsePool(cfg.placeholderIds);
|
|
@@ -136,6 +136,7 @@ async function refreshAds() {
|
|
|
136
136
|
const $posts = getTopicPosts();
|
|
137
137
|
if (!$posts.length) return;
|
|
138
138
|
|
|
139
|
+
// Clean first
|
|
139
140
|
removeAdWrappers();
|
|
140
141
|
removePlaceholdersByPool(betweenPool);
|
|
141
142
|
removePlaceholdersByPool(messagePool);
|
|
@@ -150,19 +151,24 @@ async function refreshAds() {
|
|
|
150
151
|
activeIds.push(...insertAdMessagesBetweenReplies($posts, messagePool, messageInterval));
|
|
151
152
|
}
|
|
152
153
|
|
|
154
|
+
// Ezoic render
|
|
153
155
|
if (activeIds.length && window.ezstandalone && typeof window.ezstandalone.destroyPlaceholders === 'function') {
|
|
154
156
|
try { window.ezstandalone.destroyPlaceholders(); } catch (e) {}
|
|
155
157
|
}
|
|
156
158
|
activeIds.forEach(id => {
|
|
157
|
-
try {
|
|
159
|
+
try {
|
|
160
|
+
if (window.ezstandalone && typeof window.ezstandalone.showAds === 'function') {
|
|
161
|
+
window.ezstandalone.showAds(id);
|
|
162
|
+
}
|
|
163
|
+
} catch (e) {}
|
|
158
164
|
});
|
|
159
165
|
}
|
|
160
166
|
|
|
161
167
|
function debounceRefresh() {
|
|
162
168
|
clearTimeout(debounceTimer);
|
|
163
|
-
debounceTimer = setTimeout(refreshAds,
|
|
169
|
+
debounceTimer = setTimeout(refreshAds, 150);
|
|
164
170
|
}
|
|
165
171
|
|
|
166
172
|
$(document).ready(debounceRefresh);
|
|
167
173
|
$(window).on('action:ajaxify.end action:posts.loaded action:topic.loaded', debounceRefresh);
|
|
168
|
-
setTimeout(debounceRefresh,
|
|
174
|
+
setTimeout(debounceRefresh, 1500);
|
|
@@ -54,6 +54,6 @@
|
|
|
54
54
|
<p class="form-text">Si l’utilisateur appartient à un de ces groupes, aucune pub n’est injectée.</p>
|
|
55
55
|
</div>
|
|
56
56
|
|
|
57
|
-
<button id="save"
|
|
57
|
+
<button id="save" class="btn btn-primary">Enregistrer</button>
|
|
58
58
|
</form>
|
|
59
59
|
</div>
|