nodebb-plugin-ezoic-infinite 1.6.82 → 1.6.83
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/library.js +40 -47
- package/package.json +1 -1
- package/public/client.js +34 -135
- package/public/style.css +10 -27
- package/public/test.txt +0 -1
package/library.js
CHANGED
|
@@ -2,65 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
const meta = require.main.require('./src/meta');
|
|
4
4
|
const groups = require.main.require('./src/groups');
|
|
5
|
-
const db = require.main.require('./src/database');
|
|
6
5
|
|
|
7
6
|
const SETTINGS_KEY = 'ezoic-infinite';
|
|
8
7
|
const plugin = {};
|
|
9
8
|
|
|
10
9
|
async function getSettings() {
|
|
11
|
-
|
|
12
|
-
return settings || {};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async function isUserExcluded(uid, excludedGroups) {
|
|
16
|
-
if (!uid || !excludedGroups) return false;
|
|
17
|
-
const groupsList = Array.isArray(excludedGroups) ? excludedGroups : [excludedGroups];
|
|
18
|
-
if (!groupsList.length) return false;
|
|
19
|
-
return await groups.isMemberOfGroups(uid, groupsList);
|
|
10
|
+
return await meta.settings.get(SETTINGS_KEY) || {};
|
|
20
11
|
}
|
|
21
12
|
|
|
22
13
|
plugin.init = async ({ router, middleware }) => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
14
|
+
const renderAdmin = async (req, res) => {
|
|
15
|
+
const settings = await getSettings();
|
|
16
|
+
const db = require.main.require('./src/database');
|
|
17
|
+
const names = await db.getSortedSetRange('groups:createtime', 0, -1);
|
|
18
|
+
const groupsData = await groups.getGroupsData(names);
|
|
19
|
+
const allGroups = groupsData.filter(g => g && g.name).map(g => ({ name: g.name }));
|
|
20
|
+
|
|
21
|
+
res.render('admin/plugins/ezoic-infinite', {
|
|
22
|
+
...settings,
|
|
23
|
+
allGroups,
|
|
24
|
+
enableBetweenAds_checked: settings.enableBetweenAds === 'on' ? 'checked' : '',
|
|
25
|
+
enableMessageAds_checked: settings.enableMessageAds === 'on' ? 'checked' : ''
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
router.get('/admin/plugins/ezoic-infinite', middleware.admin.buildHeader, renderAdmin);
|
|
30
|
+
router.get('/api/admin/plugins/ezoic-infinite', renderAdmin);
|
|
31
|
+
|
|
32
|
+
router.get('/api/plugins/ezoic-infinite/config', async (req, res) => {
|
|
33
|
+
const settings = await getSettings();
|
|
34
|
+
let excluded = false;
|
|
35
|
+
if (req.uid && settings.excludedGroups) {
|
|
36
|
+
const groupsList = Array.isArray(settings.excludedGroups) ? settings.excludedGroups : [settings.excludedGroups];
|
|
37
|
+
excluded = await groups.isMemberOfGroups(req.uid, groupsList);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
res.json({
|
|
41
|
+
excluded,
|
|
42
|
+
enableBetweenAds: settings.enableBetweenAds === 'on',
|
|
43
|
+
showFirstTopicAd: settings.showFirstTopicAd === 'on',
|
|
44
|
+
placeholderIds: settings.placeholderIds || '',
|
|
45
|
+
intervalPosts: settings.intervalPosts || 10,
|
|
46
|
+
enableMessageAds: settings.enableMessageAds === 'on',
|
|
47
|
+
showFirstMessageAd: settings.showFirstMessageAd === 'on',
|
|
48
|
+
messagePlaceholderIds: settings.messagePlaceholderIds || '',
|
|
49
|
+
messageIntervalPosts: settings.messageIntervalPosts || 10,
|
|
50
|
+
});
|
|
53
51
|
});
|
|
54
|
-
});
|
|
55
52
|
};
|
|
56
53
|
|
|
57
54
|
plugin.addAdminNavigation = async (header) => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
icon: 'fa-ad',
|
|
61
|
-
name: 'Ezoic Infinite'
|
|
62
|
-
});
|
|
63
|
-
return header;
|
|
55
|
+
header.plugins.push({ route: '/plugins/ezoic-infinite', icon: 'fa-ad', name: 'Ezoic Infinite' });
|
|
56
|
+
return header;
|
|
64
57
|
};
|
|
65
58
|
|
|
66
59
|
module.exports = plugin;
|
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
// Singleton pour éviter les conflits lors de la navigation AJAX de NodeBB
|
|
5
4
|
if (window.ezInfiniteInjected) return;
|
|
6
5
|
window.ezInfiniteInjected = true;
|
|
7
6
|
|
|
@@ -10,21 +9,7 @@
|
|
|
10
9
|
|
|
11
10
|
let config = null;
|
|
12
11
|
let isInternalChange = false;
|
|
13
|
-
let
|
|
14
|
-
|
|
15
|
-
// Détection du sens du scroll pour le nettoyage (Pillup prevention)
|
|
16
|
-
let lastScrollY = window.scrollY;
|
|
17
|
-
let scrollDir = 1;
|
|
18
|
-
window.addEventListener('scroll', () => {
|
|
19
|
-
const y = window.scrollY;
|
|
20
|
-
scrollDir = y > lastScrollY ? 1 : -1;
|
|
21
|
-
lastScrollY = y;
|
|
22
|
-
}, { passive: true });
|
|
23
|
-
|
|
24
|
-
function withInternalDomChange(fn) {
|
|
25
|
-
isInternalChange = true;
|
|
26
|
-
try { fn(); } finally { isInternalChange = false; }
|
|
27
|
-
}
|
|
12
|
+
let ezEnabled = false;
|
|
28
13
|
|
|
29
14
|
function getPool() {
|
|
30
15
|
let p = document.getElementById(POOL_ID);
|
|
@@ -37,115 +22,40 @@
|
|
|
37
22
|
return p;
|
|
38
23
|
}
|
|
39
24
|
|
|
40
|
-
function
|
|
41
|
-
if (!wrap || !wrap.parentNode) return;
|
|
42
|
-
const pool = getPool();
|
|
43
|
-
wrap.classList.remove('ez-orphan-hidden');
|
|
44
|
-
if (wrap.parentNode !== pool) {
|
|
45
|
-
pool.appendChild(wrap);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ANTI-PILLUP : Supprime les pubs si elles se touchent
|
|
50
|
-
function decluster(container) {
|
|
51
|
-
const wraps = Array.from(container.querySelectorAll(`.${WRAP_CLASS}`));
|
|
52
|
-
wraps.forEach(wrap => {
|
|
53
|
-
let next = wrap.nextElementSibling;
|
|
54
|
-
// Si l'élément suivant est une autre pub, on la remet au pool
|
|
55
|
-
if (next && next.classList.contains(WRAP_CLASS)) {
|
|
56
|
-
withInternalDomChange(() => releaseWrapNode(next));
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Nettoyage des orphelins (Virtualisation NodeBB)
|
|
62
|
-
function pruneOrphanWraps() {
|
|
63
|
-
const wraps = document.querySelectorAll(`.${WRAP_CLASS}`);
|
|
64
|
-
const items = document.querySelectorAll('[component="category/topic"], [component="post"]');
|
|
65
|
-
const itemSet = new Set(items);
|
|
66
|
-
|
|
67
|
-
wraps.forEach(wrap => {
|
|
68
|
-
if (wrap.parentElement && wrap.parentElement.id === POOL_ID) return;
|
|
69
|
-
|
|
70
|
-
let hasNeighbor = false;
|
|
71
|
-
let p = wrap.previousElementSibling;
|
|
72
|
-
// On vérifie sur 2 voisins pour être sûr
|
|
73
|
-
for (let i = 0; i < 2 && p; i++) {
|
|
74
|
-
if (itemSet.has(p)) { hasNeighbor = true; break; }
|
|
75
|
-
p = p.previousElementSibling;
|
|
76
|
-
}
|
|
77
|
-
if (!hasNeighbor) {
|
|
78
|
-
let n = wrap.nextElementSibling;
|
|
79
|
-
for (let i = 0; i < 2 && n; i++) {
|
|
80
|
-
if (itemSet.has(n)) { hasNeighbor = true; break; }
|
|
81
|
-
n = n.nextElementSibling;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (!hasNeighbor) {
|
|
86
|
-
// En remontée (Up), on recycle immédiatement pour éviter l'empilement
|
|
87
|
-
if (scrollDir === -1) {
|
|
88
|
-
withInternalDomChange(() => releaseWrapNode(wrap));
|
|
89
|
-
} else {
|
|
90
|
-
wrap.classList.add('ez-orphan-hidden');
|
|
91
|
-
}
|
|
92
|
-
} else {
|
|
93
|
-
wrap.classList.remove('ez-orphan-hidden');
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Appel à la bibliothèque Ezoic déjà initialisée
|
|
99
|
-
function callEzoicRefresh(placeholderId) {
|
|
25
|
+
function callEzoic(pid) {
|
|
100
26
|
if (typeof window.ezstandalone === 'undefined') return;
|
|
101
|
-
const
|
|
102
|
-
|
|
27
|
+
const id = parseInt(pid, 10);
|
|
103
28
|
try {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
// Si c'est le tout premier, on tente un display
|
|
108
|
-
if (!ezEnabledInternally) {
|
|
29
|
+
window.ezstandalone.define(id);
|
|
30
|
+
if (!ezEnabled) {
|
|
109
31
|
window.ezstandalone.enable();
|
|
110
32
|
window.ezstandalone.display();
|
|
111
|
-
|
|
33
|
+
ezEnabled = true;
|
|
112
34
|
} else {
|
|
113
|
-
//
|
|
114
|
-
setTimeout(() => {
|
|
115
|
-
const el = document.getElementById('ezoic-pub-ad-placeholder-' + pid);
|
|
116
|
-
if (el && el.offsetParent !== null) {
|
|
117
|
-
window.ezstandalone.refresh();
|
|
118
|
-
}
|
|
119
|
-
}, 250);
|
|
35
|
+
// Délai pour s'assurer que le div est bien rendu par le navigateur
|
|
36
|
+
setTimeout(() => { window.ezstandalone.refresh(); }, 200);
|
|
120
37
|
}
|
|
121
|
-
} catch (e) {
|
|
122
|
-
console.warn('[Ezoic-Infinite] Refresh skip:', e.message);
|
|
123
|
-
}
|
|
38
|
+
} catch (e) { console.warn('[Ezoic] Error:', e); }
|
|
124
39
|
}
|
|
125
40
|
|
|
126
|
-
function redistribute(
|
|
127
|
-
if (!
|
|
128
|
-
|
|
129
|
-
pruneOrphanWraps();
|
|
130
|
-
decluster(container);
|
|
41
|
+
function redistribute() {
|
|
42
|
+
if (!config || config.excluded) return;
|
|
131
43
|
|
|
132
|
-
|
|
133
|
-
const
|
|
44
|
+
// Sélecteurs spécifiques à NodeBB 4.x / Harmony
|
|
45
|
+
const topicItems = document.querySelectorAll('[component="category/topic"]');
|
|
46
|
+
const postItems = document.querySelectorAll('[component="post"]');
|
|
134
47
|
|
|
135
|
-
let interval = 10;
|
|
136
|
-
let kind = '';
|
|
137
|
-
let items = [];
|
|
138
|
-
let showFirst = false;
|
|
48
|
+
let items = [], kind = '', interval = 10, showFirst = false;
|
|
139
49
|
|
|
140
|
-
if (
|
|
141
|
-
|
|
50
|
+
if (topicItems.length > 0 && config.enableBetweenAds) {
|
|
51
|
+
items = Array.from(topicItems);
|
|
142
52
|
kind = 'between';
|
|
143
|
-
|
|
53
|
+
interval = parseInt(config.intervalPosts, 10);
|
|
144
54
|
showFirst = config.showFirstTopicAd;
|
|
145
|
-
} else if (
|
|
146
|
-
|
|
55
|
+
} else if (postItems.length > 0 && config.enableMessageAds) {
|
|
56
|
+
items = Array.from(postItems);
|
|
147
57
|
kind = 'message';
|
|
148
|
-
|
|
58
|
+
interval = parseInt(config.messageIntervalPosts, 10);
|
|
149
59
|
showFirst = config.showFirstMessageAd;
|
|
150
60
|
}
|
|
151
61
|
|
|
@@ -153,32 +63,22 @@
|
|
|
153
63
|
|
|
154
64
|
items.forEach((item, index) => {
|
|
155
65
|
const pos = index + 1;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
66
|
+
const shouldHaveAd = (pos === 1 && showFirst) || (pos % interval === 0);
|
|
67
|
+
|
|
159
68
|
const next = item.nextElementSibling;
|
|
160
69
|
if (shouldHaveAd && !(next && next.classList.contains(WRAP_CLASS))) {
|
|
161
70
|
const pool = getPool();
|
|
162
71
|
const available = pool.querySelector(`.${WRAP_CLASS}[data-kind="${kind}"]`);
|
|
163
72
|
if (available) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
});
|
|
73
|
+
isInternalChange = true;
|
|
74
|
+
item.parentNode.insertBefore(available, item.nextSibling);
|
|
75
|
+
callEzoic(available.getAttribute('data-placeholder-id'));
|
|
76
|
+
setTimeout(() => { isInternalChange = false; }, 100);
|
|
168
77
|
}
|
|
169
78
|
}
|
|
170
79
|
});
|
|
171
80
|
}
|
|
172
81
|
|
|
173
|
-
let timer = null;
|
|
174
|
-
function schedule() {
|
|
175
|
-
if (timer) clearTimeout(timer);
|
|
176
|
-
timer = setTimeout(() => {
|
|
177
|
-
const targets = document.querySelectorAll('[component="category"], .topic-list, [component="topic"], [component="category/topic/list"]');
|
|
178
|
-
targets.forEach(redistribute);
|
|
179
|
-
}, 300);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
82
|
function init() {
|
|
183
83
|
fetch('/api/plugins/ezoic-infinite/config')
|
|
184
84
|
.then(r => r.json())
|
|
@@ -201,14 +101,13 @@
|
|
|
201
101
|
setup(config.placeholderIds, 'between');
|
|
202
102
|
setup(config.messagePlaceholderIds, 'message');
|
|
203
103
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
104
|
+
redistribute();
|
|
105
|
+
|
|
106
|
+
// On surveille les changements de page et l'infinite scroll
|
|
107
|
+
const observer = new MutationObserver(() => {
|
|
108
|
+
if (!isInternalChange) redistribute();
|
|
109
|
+
});
|
|
110
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
212
111
|
});
|
|
213
112
|
}
|
|
214
113
|
|
package/public/style.css
CHANGED
|
@@ -1,37 +1,20 @@
|
|
|
1
|
-
/*
|
|
1
|
+
/* Style du container injecté */
|
|
2
2
|
.nodebb-ezoic-wrap {
|
|
3
|
-
display: block;
|
|
4
|
-
width: 100
|
|
5
|
-
margin: 30px
|
|
6
|
-
|
|
3
|
+
display: block !important;
|
|
4
|
+
width: 100% !important;
|
|
5
|
+
margin: 30px 0 !important;
|
|
6
|
+
min-height: 100px; /* Force un espace pour qu'Ezoic puisse injecter */
|
|
7
7
|
clear: both;
|
|
8
|
-
min-height: 100px; /* Important pour Ezoic */
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
/* ANTI-PILLUP
|
|
10
|
+
/* ANTI-PILLUP : Interdit deux pubs consécutives */
|
|
12
11
|
.nodebb-ezoic-wrap + .nodebb-ezoic-wrap {
|
|
13
12
|
display: none !important;
|
|
14
|
-
height: 0 !important;
|
|
15
|
-
margin: 0 !important;
|
|
16
13
|
}
|
|
17
14
|
|
|
18
|
-
/*
|
|
19
|
-
.nodebb-ezoic-wrap
|
|
20
|
-
|
|
21
|
-
height: 0 !important;
|
|
22
|
-
margin: 0 !important;
|
|
23
|
-
padding: 0 !important;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/* Évite les espaces blancs inutiles à l'intérieur */
|
|
27
|
-
.nodebb-ezoic-wrap .ezoic-ad {
|
|
28
|
-
margin: 0 auto !important;
|
|
29
|
-
min-height: 1px !important;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/* Harmonisation NodeBB 4.x / Harmony */
|
|
33
|
-
[component="category"] .nodebb-ezoic-wrap,
|
|
34
|
-
.topic-list .nodebb-ezoic-wrap {
|
|
15
|
+
/* Alignement Harmony */
|
|
16
|
+
[component="category/topic"] + .nodebb-ezoic-wrap,
|
|
17
|
+
[component="post"] + .nodebb-ezoic-wrap {
|
|
35
18
|
border-top: 1px solid rgba(0,0,0,0.05);
|
|
36
|
-
padding
|
|
19
|
+
padding: 15px 0;
|
|
37
20
|
}
|
package/public/test.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
hi
|