nodebb-plugin-ezoic-infinite 1.6.94 → 1.6.96
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 +19 -40
- package/package.json +1 -1
- package/public/client.js +73 -73
package/library.js
CHANGED
|
@@ -7,33 +7,24 @@ const db = require.main.require('./src/database');
|
|
|
7
7
|
const SETTINGS_KEY = 'ezoic-infinite';
|
|
8
8
|
const plugin = {};
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
* Récupère les paramètres du plugin
|
|
12
|
-
*/
|
|
13
10
|
async function getSettings() {
|
|
14
11
|
return await meta.settings.get(SETTINGS_KEY);
|
|
15
12
|
}
|
|
16
13
|
|
|
17
14
|
/**
|
|
18
|
-
* Vérifie
|
|
15
|
+
* Vérifie l'exclusion par groupe avec gestion du format NodeBB
|
|
19
16
|
*/
|
|
20
17
|
async function isUserExcluded(uid, excludedGroups) {
|
|
21
18
|
if (!uid || uid <= 0) return false;
|
|
22
|
-
if (!excludedGroups ||
|
|
19
|
+
if (!excludedGroups || (Array.isArray(excludedGroups) && excludedGroups.length === 0)) return false;
|
|
23
20
|
|
|
24
|
-
// S'assurer que excludedGroups est un tableau
|
|
25
21
|
const excludedList = Array.isArray(excludedGroups) ? excludedGroups : [excludedGroups];
|
|
26
|
-
|
|
27
|
-
// Récupérer les groupes de l'utilisateur
|
|
28
22
|
const userGroups = await groups.getUserGroupsNames([uid]);
|
|
29
23
|
|
|
30
|
-
//
|
|
24
|
+
// userGroups[0] contient le tableau des noms de groupes de l'utilisateur
|
|
31
25
|
return excludedList.some(g => userGroups[0].includes(g));
|
|
32
26
|
}
|
|
33
27
|
|
|
34
|
-
/**
|
|
35
|
-
* Récupère la liste de tous les groupes pour l'affichage dans l'admin
|
|
36
|
-
*/
|
|
37
28
|
async function getAllGroups() {
|
|
38
29
|
let names = await db.getSortedSetRange('groups:createtime', 0, -1);
|
|
39
30
|
if (!names || !names.length) {
|
|
@@ -46,9 +37,6 @@ async function getAllGroups() {
|
|
|
46
37
|
return valid;
|
|
47
38
|
}
|
|
48
39
|
|
|
49
|
-
/**
|
|
50
|
-
* Initialisation du plugin (Routes et API)
|
|
51
|
-
*/
|
|
52
40
|
plugin.init = async ({ router, middleware }) => {
|
|
53
41
|
async function render(req, res) {
|
|
54
42
|
const settings = await getSettings();
|
|
@@ -57,10 +45,10 @@ plugin.init = async ({ router, middleware }) => {
|
|
|
57
45
|
res.render('admin/plugins/ezoic-infinite', {
|
|
58
46
|
title: 'Ezoic Infinite Ads',
|
|
59
47
|
...settings,
|
|
60
|
-
// On
|
|
61
|
-
enableCategoryAds_checked: settings.enableCategoryAds === 'on'
|
|
62
|
-
enableBetweenAds_checked: settings.enableBetweenAds === 'on'
|
|
63
|
-
enableMessageAds_checked: settings.enableMessageAds === 'on'
|
|
48
|
+
// On s'assure que les checkbox sont bien cochées dans l'admin
|
|
49
|
+
enableCategoryAds_checked: settings.enableCategoryAds === 'on' ? 'checked' : '',
|
|
50
|
+
enableBetweenAds_checked: settings.enableBetweenAds === 'on' ? 'checked' : '',
|
|
51
|
+
enableMessageAds_checked: settings.enableMessageAds === 'on' ? 'checked' : '',
|
|
64
52
|
allGroups,
|
|
65
53
|
});
|
|
66
54
|
}
|
|
@@ -68,40 +56,34 @@ plugin.init = async ({ router, middleware }) => {
|
|
|
68
56
|
router.get('/admin/plugins/ezoic-infinite', middleware.admin.buildHeader, render);
|
|
69
57
|
router.get('/api/admin/plugins/ezoic-infinite', render);
|
|
70
58
|
|
|
71
|
-
// API
|
|
59
|
+
// API consommée par le client.js
|
|
72
60
|
router.get('/api/plugins/ezoic-infinite/config', async (req, res) => {
|
|
73
61
|
const settings = await getSettings();
|
|
74
|
-
|
|
75
|
-
// Vérification de l'exclusion
|
|
76
|
-
const excludedGroups = settings.excludedGroups ? (Array.isArray(settings.excludedGroups) ? settings.excludedGroups : [settings.excludedGroups]) : [];
|
|
77
|
-
const excluded = await isUserExcluded(req.uid, excludedGroups);
|
|
62
|
+
const excluded = await isUserExcluded(req.uid, settings.excludedGroups);
|
|
78
63
|
|
|
79
64
|
res.json({
|
|
80
65
|
excluded,
|
|
81
|
-
//
|
|
82
|
-
enableCategoryAds: settings.enableCategoryAds === 'on'
|
|
83
|
-
showFirstCategoryAd: settings.showFirstCategoryAd === 'on'
|
|
66
|
+
// Pool Accueil
|
|
67
|
+
enableCategoryAds: settings.enableCategoryAds === 'on',
|
|
68
|
+
showFirstCategoryAd: settings.showFirstCategoryAd === 'on',
|
|
84
69
|
categoryPlaceholderIds: settings.categoryPlaceholderIds || "",
|
|
85
70
|
intervalCategories: parseInt(settings.intervalCategories, 10) || 5,
|
|
86
71
|
|
|
87
|
-
//
|
|
88
|
-
enableBetweenAds: settings.enableBetweenAds === 'on'
|
|
89
|
-
showFirstTopicAd: settings.showFirstTopicAd === 'on'
|
|
72
|
+
// Pool Topics (Catégories)
|
|
73
|
+
enableBetweenAds: settings.enableBetweenAds === 'on',
|
|
74
|
+
showFirstTopicAd: settings.showFirstTopicAd === 'on',
|
|
90
75
|
placeholderIds: settings.placeholderIds || "",
|
|
91
76
|
intervalPosts: parseInt(settings.intervalPosts, 10) || 10,
|
|
92
77
|
|
|
93
|
-
//
|
|
94
|
-
enableMessageAds: settings.enableMessageAds === 'on'
|
|
95
|
-
showFirstMessageAd: settings.showFirstMessageAd === 'on'
|
|
78
|
+
// Pool Messages (Topics)
|
|
79
|
+
enableMessageAds: settings.enableMessageAds === 'on',
|
|
80
|
+
showFirstMessageAd: settings.showFirstMessageAd === 'on',
|
|
96
81
|
messagePlaceholderIds: settings.messagePlaceholderIds || "",
|
|
97
82
|
messageIntervalPosts: parseInt(settings.messageIntervalPosts, 10) || 10,
|
|
98
83
|
});
|
|
99
84
|
});
|
|
100
85
|
};
|
|
101
86
|
|
|
102
|
-
/**
|
|
103
|
-
* Ajoute le lien dans le menu de navigation de l'administration
|
|
104
|
-
*/
|
|
105
87
|
plugin.addAdminNavigation = async (header) => {
|
|
106
88
|
header.plugins.push({
|
|
107
89
|
route: '/plugins/ezoic-infinite',
|
|
@@ -111,12 +93,9 @@ plugin.addAdminNavigation = async (header) => {
|
|
|
111
93
|
return header;
|
|
112
94
|
};
|
|
113
95
|
|
|
114
|
-
/**
|
|
115
|
-
* Gère la sauvegarde des paramètres
|
|
116
|
-
*/
|
|
117
96
|
plugin.onSettingsSet = async (data) => {
|
|
118
97
|
if (data.plugin === 'ezoic-infinite') {
|
|
119
|
-
//
|
|
98
|
+
// Optionnel : purger un cache si nécessaire
|
|
120
99
|
}
|
|
121
100
|
};
|
|
122
101
|
|
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -5,76 +5,83 @@
|
|
|
5
5
|
window.ezInfiniteInjected = true;
|
|
6
6
|
|
|
7
7
|
const WRAP_CLASS = 'nodebb-ezoic-wrap';
|
|
8
|
+
const POOL_ID = 'nodebb-ezoic-placeholder-pool';
|
|
8
9
|
let config = null;
|
|
9
10
|
let isInternalChange = false;
|
|
10
|
-
let triggerTimer = null;
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
'topic-list': 'li[component="category/topic"]',
|
|
20
|
-
'message': '[component="post"]'
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
if (config.enableCategoryAds) {
|
|
24
|
-
process(Array.from(document.querySelectorAll(selectors.home)), 'home', config.intervalCategories, config.showFirstCategoryAd);
|
|
25
|
-
}
|
|
26
|
-
if (config.enableBetweenAds) {
|
|
27
|
-
process(Array.from(document.querySelectorAll(selectors['topic-list'])), 'topic-list', config.intervalPosts, config.showFirstTopicAd);
|
|
28
|
-
}
|
|
29
|
-
if (config.enableMessageAds) {
|
|
30
|
-
process(Array.from(document.querySelectorAll(selectors.message)), 'message', config.messageIntervalPosts, config.showFirstMessageAd);
|
|
12
|
+
function getPool() {
|
|
13
|
+
let p = document.getElementById(POOL_ID);
|
|
14
|
+
if (!p) {
|
|
15
|
+
p = document.createElement('div');
|
|
16
|
+
p.id = POOL_ID;
|
|
17
|
+
p.style.display = 'none';
|
|
18
|
+
document.body.appendChild(p);
|
|
31
19
|
}
|
|
20
|
+
return p;
|
|
32
21
|
}
|
|
33
22
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (!pool) return;
|
|
38
|
-
|
|
39
|
-
items.forEach((item, index) => {
|
|
40
|
-
const pos = index + 1;
|
|
41
|
-
const shouldHaveAd = (pos === 1 && showFirst) || (pos % int === 0);
|
|
42
|
-
const next = item.nextElementSibling;
|
|
23
|
+
// Cette fonction force Ezoic à remplir le placeholder
|
|
24
|
+
function forceFillAd(id) {
|
|
25
|
+
if (typeof window.ezstandalone === 'undefined') return;
|
|
43
26
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
27
|
+
window.ezstandalone.cmd.push(function() {
|
|
28
|
+
// 1. On s'assure que l'ID est bien dans la liste d'Ezoic
|
|
29
|
+
window.ezstandalone.define(parseInt(id, 10));
|
|
30
|
+
|
|
31
|
+
// 2. On attend un micro-délai pour que le DOM soit stable
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
try {
|
|
34
|
+
// La doc précise que showAds avec IDs est le mode "Dynamic"
|
|
35
|
+
window.ezstandalone.showAds(parseInt(id, 10));
|
|
36
|
+
// On force un rafraîchissement spécifique si showAds ne suffit pas
|
|
37
|
+
if (window.ezstandalone.refresh) {
|
|
38
|
+
window.ezstandalone.refresh(parseInt(id, 10));
|
|
39
|
+
}
|
|
40
|
+
} catch (e) {
|
|
41
|
+
console.warn('[Ezoic] Fill failed for', id, e);
|
|
56
42
|
}
|
|
57
|
-
}
|
|
43
|
+
}, 200);
|
|
58
44
|
});
|
|
59
45
|
}
|
|
60
46
|
|
|
61
|
-
function
|
|
62
|
-
if (
|
|
47
|
+
function redistribute() {
|
|
48
|
+
if (!config || config.excluded) return;
|
|
63
49
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
50
|
+
const selectors = {
|
|
51
|
+
'home': '.category-item, [component="categories/category"]',
|
|
52
|
+
'topic-list': 'li[component="category/topic"]',
|
|
53
|
+
'message': '[component="post"]'
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const process = (items, kind, interval, showFirst) => {
|
|
57
|
+
const int = parseInt(interval, 10) || 10;
|
|
58
|
+
const pool = getPool();
|
|
59
|
+
|
|
60
|
+
items.forEach((item, index) => {
|
|
61
|
+
const pos = index + 1;
|
|
62
|
+
const shouldHaveAd = (pos === 1 && showFirst) || (pos % int === 0);
|
|
63
|
+
const next = item.nextElementSibling;
|
|
64
|
+
|
|
65
|
+
if (shouldHaveAd && !(next && next.classList.contains(WRAP_CLASS))) {
|
|
66
|
+
const available = pool.querySelector(`.${WRAP_CLASS}[data-kind="${kind}"]`);
|
|
67
|
+
if (available) {
|
|
68
|
+
isInternalChange = true;
|
|
69
|
+
// On insère l'élément
|
|
70
|
+
item.parentNode.insertBefore(available, item.nextSibling);
|
|
71
|
+
|
|
72
|
+
// On déclenche le remplissage publicitaire
|
|
73
|
+
const pid = available.getAttribute('data-placeholder-id');
|
|
74
|
+
forceFillAd(pid);
|
|
75
|
+
|
|
76
|
+
setTimeout(() => { isInternalChange = false; }, 50);
|
|
77
|
+
}
|
|
75
78
|
}
|
|
76
79
|
});
|
|
77
|
-
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
if (config.enableCategoryAds) process(Array.from(document.querySelectorAll(selectors.home)), 'home', config.intervalCategories, config.showFirstCategoryAd);
|
|
83
|
+
if (config.enableBetweenAds) process(Array.from(document.querySelectorAll(selectors['topic-list'])), 'topic-list', config.intervalPosts, config.showFirstTopicAd);
|
|
84
|
+
if (config.enableMessageAds) process(Array.from(document.querySelectorAll(selectors.message)), 'message', config.messageIntervalPosts, config.showFirstMessageAd);
|
|
78
85
|
}
|
|
79
86
|
|
|
80
87
|
function init() {
|
|
@@ -82,27 +89,18 @@
|
|
|
82
89
|
.then(r => r.json())
|
|
83
90
|
.then(data => {
|
|
84
91
|
config = data;
|
|
92
|
+
const pool = getPool();
|
|
85
93
|
|
|
86
|
-
// On crée un pool CACHÉ qui contient tous les placeholders déclarés dans l'admin
|
|
87
|
-
let pool = document.getElementById('nodebb-ezoic-placeholder-pool');
|
|
88
|
-
if (!pool) {
|
|
89
|
-
pool = document.createElement('div');
|
|
90
|
-
pool.id = 'nodebb-ezoic-placeholder-pool';
|
|
91
|
-
pool.style.display = 'none';
|
|
92
|
-
document.body.appendChild(pool);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
94
|
const setup = (raw, kind) => {
|
|
96
95
|
if (!raw) return;
|
|
97
96
|
raw.split(/[\s,]+/).filter(Boolean).forEach(id => {
|
|
98
97
|
if (!document.getElementById(`ezoic-pub-ad-placeholder-${id}`)) {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
pool.appendChild(wrap);
|
|
98
|
+
const d = document.createElement('div');
|
|
99
|
+
d.className = WRAP_CLASS;
|
|
100
|
+
d.setAttribute('data-kind', kind);
|
|
101
|
+
d.setAttribute('data-placeholder-id', id);
|
|
102
|
+
d.innerHTML = `<div id="ezoic-pub-ad-placeholder-${id}"></div>`;
|
|
103
|
+
pool.appendChild(d);
|
|
106
104
|
}
|
|
107
105
|
});
|
|
108
106
|
};
|
|
@@ -120,7 +118,9 @@
|
|
|
120
118
|
});
|
|
121
119
|
}
|
|
122
120
|
|
|
123
|
-
window.addEventListener('action:ajaxify.end', () =>
|
|
121
|
+
window.addEventListener('action:ajaxify.end', () => {
|
|
122
|
+
setTimeout(redistribute, 500);
|
|
123
|
+
});
|
|
124
124
|
|
|
125
125
|
if (document.readyState === 'loading') {
|
|
126
126
|
document.addEventListener('DOMContentLoaded', init);
|