nodebb-plugin-ezoic-infinite 1.6.82 → 1.6.84
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 +47 -130
- package/public/style.css +10 -29
- 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,8 @@
|
|
|
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;
|
|
13
|
+
let definedIds = new Set();
|
|
28
14
|
|
|
29
15
|
function getPool() {
|
|
30
16
|
let p = document.getElementById(POOL_ID);
|
|
@@ -37,115 +23,56 @@
|
|
|
37
23
|
return p;
|
|
38
24
|
}
|
|
39
25
|
|
|
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) {
|
|
26
|
+
function callEzoic(pid) {
|
|
100
27
|
if (typeof window.ezstandalone === 'undefined') return;
|
|
101
|
-
const
|
|
102
|
-
|
|
28
|
+
const id = parseInt(pid, 10);
|
|
29
|
+
if (isNaN(id)) return;
|
|
30
|
+
|
|
103
31
|
try {
|
|
104
|
-
// On définit l'ID
|
|
105
|
-
window.ezstandalone.define(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
32
|
+
// 1. On définit TOUJOURS l'ID avant toute autre action
|
|
33
|
+
window.ezstandalone.define(id);
|
|
34
|
+
definedIds.add(id);
|
|
35
|
+
|
|
36
|
+
// 2. Si c'est la toute première fois de la page
|
|
37
|
+
if (!ezEnabled) {
|
|
109
38
|
window.ezstandalone.enable();
|
|
110
39
|
window.ezstandalone.display();
|
|
111
|
-
|
|
40
|
+
ezEnabled = true;
|
|
41
|
+
console.log('[Ezoic-Infinite] Initialized with ID:', id);
|
|
112
42
|
} else {
|
|
113
|
-
// Sinon on
|
|
43
|
+
// 3. Sinon, on utilise refresh avec un léger délai
|
|
44
|
+
// pour s'assurer que le navigateur a fini de dessiner le DIV
|
|
114
45
|
setTimeout(() => {
|
|
115
|
-
const el = document.getElementById('ezoic-pub-ad-placeholder-' +
|
|
116
|
-
if (el
|
|
46
|
+
const el = document.getElementById('ezoic-pub-ad-placeholder-' + id);
|
|
47
|
+
if (el) {
|
|
117
48
|
window.ezstandalone.refresh();
|
|
49
|
+
console.log('[Ezoic-Infinite] Refresh called for:', id);
|
|
118
50
|
}
|
|
119
|
-
},
|
|
51
|
+
}, 300);
|
|
120
52
|
}
|
|
121
53
|
} catch (e) {
|
|
122
|
-
console.warn('[Ezoic-Infinite]
|
|
54
|
+
console.warn('[Ezoic-Infinite] JS Error:', e.message);
|
|
123
55
|
}
|
|
124
56
|
}
|
|
125
57
|
|
|
126
|
-
function redistribute(
|
|
127
|
-
if (!
|
|
128
|
-
|
|
129
|
-
pruneOrphanWraps();
|
|
130
|
-
decluster(container);
|
|
58
|
+
function redistribute() {
|
|
59
|
+
if (!config || config.excluded) return;
|
|
131
60
|
|
|
132
|
-
|
|
133
|
-
const
|
|
61
|
+
// Ciblage Harmony NodeBB 4
|
|
62
|
+
const topicItems = document.querySelectorAll('[component="category/topic"]');
|
|
63
|
+
const postItems = document.querySelectorAll('[component="post"]');
|
|
134
64
|
|
|
135
|
-
let interval = 10;
|
|
136
|
-
let kind = '';
|
|
137
|
-
let items = [];
|
|
138
|
-
let showFirst = false;
|
|
65
|
+
let items = [], kind = '', interval = 10, showFirst = false;
|
|
139
66
|
|
|
140
|
-
if (
|
|
141
|
-
|
|
67
|
+
if (topicItems.length > 0 && config.enableBetweenAds) {
|
|
68
|
+
items = Array.from(topicItems);
|
|
142
69
|
kind = 'between';
|
|
143
|
-
|
|
70
|
+
interval = parseInt(config.intervalPosts, 10);
|
|
144
71
|
showFirst = config.showFirstTopicAd;
|
|
145
|
-
} else if (
|
|
146
|
-
|
|
72
|
+
} else if (postItems.length > 0 && config.enableMessageAds) {
|
|
73
|
+
items = Array.from(postItems);
|
|
147
74
|
kind = 'message';
|
|
148
|
-
|
|
75
|
+
interval = parseInt(config.messageIntervalPosts, 10);
|
|
149
76
|
showFirst = config.showFirstMessageAd;
|
|
150
77
|
}
|
|
151
78
|
|
|
@@ -153,32 +80,24 @@
|
|
|
153
80
|
|
|
154
81
|
items.forEach((item, index) => {
|
|
155
82
|
const pos = index + 1;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
83
|
+
const shouldHaveAd = (pos === 1 && showFirst) || (pos % interval === 0);
|
|
84
|
+
|
|
159
85
|
const next = item.nextElementSibling;
|
|
160
86
|
if (shouldHaveAd && !(next && next.classList.contains(WRAP_CLASS))) {
|
|
161
87
|
const pool = getPool();
|
|
162
88
|
const available = pool.querySelector(`.${WRAP_CLASS}[data-kind="${kind}"]`);
|
|
163
89
|
if (available) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
90
|
+
isInternalChange = true;
|
|
91
|
+
// Insertion physique dans le DOM
|
|
92
|
+
item.parentNode.insertBefore(available, item.nextSibling);
|
|
93
|
+
// Activation Ezoic
|
|
94
|
+
callEzoic(available.getAttribute('data-placeholder-id'));
|
|
95
|
+
setTimeout(() => { isInternalChange = false; }, 100);
|
|
168
96
|
}
|
|
169
97
|
}
|
|
170
98
|
});
|
|
171
99
|
}
|
|
172
100
|
|
|
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
101
|
function init() {
|
|
183
102
|
fetch('/api/plugins/ezoic-infinite/config')
|
|
184
103
|
.then(r => r.json())
|
|
@@ -201,14 +120,12 @@
|
|
|
201
120
|
setup(config.placeholderIds, 'between');
|
|
202
121
|
setup(config.messagePlaceholderIds, 'message');
|
|
203
122
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
mo.observe(document.body, { childList: true, subtree: true });
|
|
211
|
-
}
|
|
123
|
+
redistribute();
|
|
124
|
+
|
|
125
|
+
const observer = new MutationObserver(() => {
|
|
126
|
+
if (!isInternalChange) redistribute();
|
|
127
|
+
});
|
|
128
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
212
129
|
});
|
|
213
130
|
}
|
|
214
131
|
|
package/public/style.css
CHANGED
|
@@ -1,37 +1,18 @@
|
|
|
1
|
-
/* Container de base */
|
|
2
1
|
.nodebb-ezoic-wrap {
|
|
3
|
-
display: block;
|
|
4
|
-
width: 100
|
|
5
|
-
margin: 30px
|
|
6
|
-
|
|
2
|
+
display: block !important;
|
|
3
|
+
width: 100% !important;
|
|
4
|
+
margin: 30px 0 !important;
|
|
5
|
+
min-height: 250px; /* Taille minimum pour forcer le chargement */
|
|
7
6
|
clear: both;
|
|
8
|
-
|
|
7
|
+
overflow: visible !important;
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
/* ANTI-PILLUP RADICAL : Si deux pubs se suivent, on cache la 2ème immédiatement par CSS */
|
|
12
|
-
.nodebb-ezoic-wrap + .nodebb-ezoic-wrap {
|
|
13
|
-
display: none !important;
|
|
14
|
-
height: 0 !important;
|
|
15
|
-
margin: 0 !important;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/* Cache les blocs orphelins (ceux qui ont perdu leurs posts voisins au scroll up) */
|
|
19
|
-
.nodebb-ezoic-wrap.ez-orphan-hidden {
|
|
20
|
-
display: none !important;
|
|
21
|
-
height: 0 !important;
|
|
22
|
-
margin: 0 !important;
|
|
23
|
-
padding: 0 !important;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/* Évite les espaces blancs inutiles à l'intérieur */
|
|
27
10
|
.nodebb-ezoic-wrap .ezoic-ad {
|
|
28
|
-
|
|
29
|
-
min-height: 1px
|
|
11
|
+
min-width: 1px;
|
|
12
|
+
min-height: 1px;
|
|
30
13
|
}
|
|
31
14
|
|
|
32
|
-
/*
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
border-top: 1px solid rgba(0,0,0,0.05);
|
|
36
|
-
padding-top: 10px !important;
|
|
15
|
+
/* Évite que les pubs se collent */
|
|
16
|
+
.nodebb-ezoic-wrap + .nodebb-ezoic-wrap {
|
|
17
|
+
display: none !important;
|
|
37
18
|
}
|
package/public/test.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
hi
|