nodebb-plugin-ezoic-infinite 1.6.79 → 1.6.81

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 CHANGED
@@ -8,27 +8,30 @@ const SETTINGS_KEY = 'ezoic-infinite';
8
8
  const plugin = {};
9
9
 
10
10
  async function getSettings() {
11
- return await meta.settings.get(SETTINGS_KEY);
12
- }
13
-
14
- async function getAllGroups() {
15
- const names = await db.getSortedSetRange('groups:createtime', 0, -1);
16
- const data = await groups.getGroupsData(names);
17
- return data.filter(g => g && g.name).map(g => ({ name: g.name }));
11
+ const settings = await meta.settings.get(SETTINGS_KEY);
12
+ return settings || {};
18
13
  }
19
14
 
20
15
  async function isUserExcluded(uid, excludedGroups) {
21
- if (!uid || !excludedGroups || !excludedGroups.length) return false;
22
- return await groups.isMemberOfGroups(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);
23
20
  }
24
21
 
25
22
  plugin.init = async ({ router, middleware }) => {
26
23
  const renderAdmin = async (req, res) => {
27
24
  const settings = await getSettings();
28
- const allGroups = await getAllGroups();
25
+ const names = await db.getSortedSetRange('groups:createtime', 0, -1);
26
+ const groupsData = await groups.getGroupsData(names);
27
+ const allGroups = groupsData.filter(g => g && g.name).map(g => ({ name: g.name }));
28
+
29
29
  res.render('admin/plugins/ezoic-infinite', {
30
30
  ...settings,
31
31
  allGroups,
32
+ // Helper pour le tpl
33
+ enableBetweenAds_checked: settings.enableBetweenAds === 'on' ? 'checked' : '',
34
+ enableMessageAds_checked: settings.enableMessageAds === 'on' ? 'checked' : ''
32
35
  });
33
36
  };
34
37
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.6.79",
3
+ "version": "1.6.81",
4
4
  "description": "Production-ready Ezoic infinite ads integration for NodeBB 4.x",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/public/client.js CHANGED
@@ -1,9 +1,8 @@
1
1
  (function () {
2
2
  'use strict';
3
3
 
4
- // --- Gestion de la direction du scroll ---
5
4
  let lastScrollY = 0;
6
- let scrollDir = 1; // 1 = down, -1 = up
5
+ let scrollDir = 1;
7
6
  try {
8
7
  lastScrollY = window.scrollY || 0;
9
8
  window.addEventListener('scroll', () => {
@@ -22,6 +21,7 @@
22
21
 
23
22
  let config = null;
24
23
  let isInternalChange = false;
24
+ let ezInitialized = false; // Flag crucial pour éviter l'erreur de "refresh"
25
25
 
26
26
  function withInternalDomChange(fn) {
27
27
  isInternalChange = true;
@@ -40,7 +40,7 @@
40
40
  }
41
41
 
42
42
  function releaseWrapNode(wrap) {
43
- if (!wrap) return;
43
+ if (!wrap || !wrap.parentNode) return;
44
44
  const pool = getPool();
45
45
  wrap.classList.remove('ez-orphan-hidden');
46
46
  if (wrap.parentNode !== pool) {
@@ -48,19 +48,18 @@
48
48
  }
49
49
  }
50
50
 
51
- // --- ANTI-PILLUP : Supprime les pubs consécutives ---
51
+ // Anti-pillup : évite que deux pubs se suivent
52
52
  function decluster(container) {
53
53
  const wraps = Array.from(container.querySelectorAll(`.${WRAP_CLASS}`));
54
54
  wraps.forEach(wrap => {
55
55
  let next = wrap.nextElementSibling;
56
- // Si deux blocs de pub se suivent sans contenu entre les deux
57
56
  if (next && next.classList.contains(WRAP_CLASS)) {
58
57
  withInternalDomChange(() => releaseWrapNode(next));
59
58
  }
60
59
  });
61
60
  }
62
61
 
63
- // --- NETTOYAGE DES ORPHELINS (Virtualisation NodeBB) ---
62
+ // Nettoyage des pubs orphelines lors de la virtualisation
64
63
  function pruneOrphanWraps() {
65
64
  const wraps = document.querySelectorAll(`.${WRAP_CLASS}`);
66
65
  const items = document.querySelectorAll('[component="category/topic"], [component="post"]');
@@ -68,9 +67,7 @@
68
67
 
69
68
  wraps.forEach(wrap => {
70
69
  if (wrap.parentElement && wrap.parentElement.id === POOL_ID) return;
71
-
72
70
  let hasNeighbor = false;
73
- // On vérifie la proximité immédiate (3 éléments) pour voir si le contenu est toujours là
74
71
  let prev = wrap.previousElementSibling;
75
72
  for (let i = 0; i < 3 && prev; i++) {
76
73
  if (itemSet.has(prev)) { hasNeighbor = true; break; }
@@ -85,7 +82,6 @@
85
82
  }
86
83
 
87
84
  if (!hasNeighbor) {
88
- // En remontee (scroll UP), on recycle immédiatement pour éviter l'empilement visuel
89
85
  if (scrollDir === -1) {
90
86
  withInternalDomChange(() => releaseWrapNode(wrap));
91
87
  } else {
@@ -97,10 +93,36 @@
97
93
  });
98
94
  }
99
95
 
96
+ function callEzoic(placeholderId) {
97
+ if (typeof window.ezstandalone === 'undefined') return;
98
+ const pid = parseInt(placeholderId, 10);
99
+ if (isNaN(pid)) return;
100
+
101
+ try {
102
+ if (!ezInitialized) {
103
+ // PREMIER APPEL : define + enable + display
104
+ window.ezstandalone.define(pid);
105
+ window.ezstandalone.enable();
106
+ window.ezstandalone.display();
107
+ ezInitialized = true;
108
+ } else {
109
+ // APPELS SUIVANTS (Scroll) : define + refresh
110
+ window.ezstandalone.define(pid);
111
+ // On attend que le DOM soit stable pour le refresh
112
+ setTimeout(() => {
113
+ if (document.getElementById('ezoic-pub-ad-placeholder-' + pid)) {
114
+ window.ezstandalone.refresh();
115
+ }
116
+ }, 150);
117
+ }
118
+ } catch (e) {
119
+ console.warn('[Ezoic-Infinite] Ez Error:', e.message);
120
+ }
121
+ }
122
+
100
123
  function redistribute(container) {
101
124
  if (!container || !config || config.excluded) return;
102
125
 
103
- // 1. On nettoie avant d'injecter
104
126
  pruneOrphanWraps();
105
127
  decluster(container);
106
128
 
@@ -132,7 +154,6 @@
132
154
  let inserts = 0;
133
155
  items.forEach((item, index) => {
134
156
  if (inserts >= MAX_INSERTS_PER_RUN) return;
135
-
136
157
  const pos = index + 1;
137
158
  let shouldHaveAd = (pos % interval === 0);
138
159
  if (pos === 1 && showFirst) shouldHaveAd = true;
@@ -146,14 +167,7 @@
146
167
  if (available) {
147
168
  withInternalDomChange(() => {
148
169
  item.parentNode.insertBefore(available, item.nextSibling);
149
- // Appel Ezoic Standalone si présent
150
- if (typeof window.ezstandalone !== 'undefined') {
151
- const pid = available.getAttribute('data-placeholder-id');
152
- try {
153
- window.ezstandalone.define(parseInt(pid, 10));
154
- window.ezstandalone.refresh();
155
- } catch (e) {}
156
- }
170
+ callEzoic(available.getAttribute('data-placeholder-id'));
157
171
  });
158
172
  inserts++;
159
173
  }
@@ -166,11 +180,10 @@
166
180
  .then(r => r.json())
167
181
  .then(data => {
168
182
  config = data;
169
- // Initialisation du pool d'IDs
170
183
  const pool = getPool();
171
184
  const setupPool = (idsRaw, kind) => {
172
185
  if (!idsRaw) return;
173
- const ids = idsRaw.split(/[\s,]+/).filter(Boolean);
186
+ const ids = idsRaw.split(/[\s,]+/).map(s => s.trim()).filter(Boolean);
174
187
  ids.forEach(id => {
175
188
  if (!document.querySelector(`[data-placeholder-id="${id}"]`)) {
176
189
  const d = document.createElement('div');
@@ -188,16 +201,17 @@
188
201
  setupPool(config.placeholderIds, 'between');
189
202
  setupPool(config.messagePlaceholderIds, 'message');
190
203
  cb();
191
- });
204
+ }).catch(e => console.error('[Ezoic] Config load error', e));
192
205
  }
193
206
 
194
207
  let timer = null;
195
208
  function schedule() {
196
209
  if (timer) clearTimeout(timer);
197
210
  timer = setTimeout(() => {
198
- const lists = document.querySelectorAll('[component="category"], .topic-list, [component="topic"]');
211
+ // Sélecteurs pour NodeBB 4.x / Harmony
212
+ const lists = document.querySelectorAll('[component="category"], .topic-list, [component="topic"], [component="category/topic/list"]');
199
213
  lists.forEach(redistribute);
200
- }, 100);
214
+ }, 200);
201
215
  }
202
216
 
203
217
  function init() {
@@ -206,7 +220,9 @@
206
220
  if (typeof MutationObserver !== 'undefined') {
207
221
  const mo = new MutationObserver((muts) => {
208
222
  if (isInternalChange) return;
209
- schedule();
223
+ // On vérifie si un élément structurel a été ajouté
224
+ const shouldRun = muts.some(m => m.addedNodes.length > 0);
225
+ if (shouldRun) schedule();
210
226
  });
211
227
  mo.observe(document.body, { childList: true, subtree: true });
212
228
  }
package/public/style.css CHANGED
@@ -1,24 +1,22 @@
1
- /* Container de base */
1
+ /* Container principal */
2
2
  .nodebb-ezoic-wrap {
3
3
  display: block;
4
4
  width: 100%;
5
- margin: 15px 0 !important;
5
+ margin: 20px 0 !important;
6
6
  padding: 0 !important;
7
7
  clear: both;
8
- overflow: hidden;
9
- min-height: 1px;
8
+ min-height: 50px; /* Important pour que l'ad-tester détecte le bloc */
10
9
  }
11
10
 
12
- /* Cache les pubs orphelines sans casser le flux du DOM */
11
+ /* Cache les pubs orphelines sans les supprimer du DOM */
13
12
  .nodebb-ezoic-wrap.ez-orphan-hidden {
14
13
  display: none !important;
15
14
  height: 0 !important;
15
+ min-height: 0 !important;
16
16
  margin: 0 !important;
17
- padding: 0 !important;
18
- pointer-events: none;
19
17
  }
20
18
 
21
- /* Force la suppression des marges Ezoic internes pour garder le contrôle */
19
+ /* Nettoyage des styles internes Ezoic */
22
20
  .nodebb-ezoic-wrap .ezoic-ad {
23
21
  margin: 0 auto !important;
24
22
  padding: 0 !important;
@@ -26,23 +24,12 @@
26
24
  height: auto !important;
27
25
  }
28
26
 
29
- /* Neutralisation du line-height pour éviter les décalages de 1px */
30
- .nodebb-ezoic-wrap,
31
- .nodebb-ezoic-wrap * {
32
- line-height: 0 !important;
33
- font-size: 0 !important;
34
- }
35
-
36
- /* Harmonisation pour Harmony/NodeBB 4 */
37
- [component="category"] .nodebb-ezoic-wrap,
38
- .topic-list .nodebb-ezoic-wrap {
39
- border-bottom: 1px solid rgba(0,0,0,0.05);
40
- background: transparent;
27
+ /* Neutralise les marges doubles */
28
+ .nodebb-ezoic-wrap + .nodebb-ezoic-wrap {
29
+ margin-top: 0 !important;
41
30
  }
42
31
 
43
- /* Empêche le saut visuel si Ezoic met du temps à charger */
44
- .nodebb-ezoic-wrap iframe {
45
- display: block !important;
46
- max-width: 100%;
47
- margin: 0 auto;
32
+ /* Évite les débordements sur mobile */
33
+ .ezoic-ad iframe {
34
+ max-width: 100% !important;
48
35
  }