nodebb-plugin-ezoic-infinite 1.6.93 → 1.6.95

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.6.93",
3
+ "version": "1.6.95",
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
@@ -6,15 +6,8 @@
6
6
 
7
7
  const WRAP_CLASS = 'nodebb-ezoic-wrap';
8
8
  const POOL_ID = 'nodebb-ezoic-placeholder-pool';
9
-
10
9
  let config = null;
11
10
  let isInternalChange = false;
12
-
13
- // Registre global pour ne JAMAIS redéfinir un ID déjà vu par Ezoic
14
- window.ezoicDefinedIds = window.ezoicDefinedIds || new Set();
15
-
16
- let pendingIds = new Set();
17
- let triggerTimer = null;
18
11
 
19
12
  function getPool() {
20
13
  let p = document.getElementById(POOL_ID);
@@ -27,41 +20,30 @@
27
20
  return p;
28
21
  }
29
22
 
30
- function triggerEzoic() {
31
- if (typeof window.ezstandalone === 'undefined' || pendingIds.size === 0) return;
23
+ // Cette fonction force Ezoic à remplir le placeholder
24
+ function forceFillAd(id) {
25
+ if (typeof window.ezstandalone === 'undefined') return;
32
26
 
33
27
  window.ezstandalone.cmd.push(function() {
34
- const allPending = Array.from(pendingIds);
35
- pendingIds.clear();
36
-
37
- // Filtrer pour ne garder que les IDs JAMAIS définis auparavant
38
- const newIdsToDefine = allPending.filter(id => !window.ezoicDefinedIds.has(id));
39
-
40
- if (newIdsToDefine.length > 0) {
41
- window.ezstandalone.define(newIdsToDefine);
42
- newIdsToDefine.forEach(id => window.ezoicDefinedIds.add(id));
43
- }
44
-
45
- // La doc dit : showAds(id1, id2) pour le nouveau contenu
46
- // On appelle showAds sur tous les IDs qu'on vient d'injecter,
47
- // qu'ils soient nouveaux ou recyclés.
48
- try {
49
- window.ezstandalone.showAds.apply(null, allPending);
50
- } catch (e) {
51
- console.warn('[Ezoic] showAds failed', e);
52
- }
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);
42
+ }
43
+ }, 200);
53
44
  });
54
45
  }
55
46
 
56
- function callEzoic(id) {
57
- const pid = parseInt(id, 10);
58
- if (isNaN(pid)) return;
59
- pendingIds.add(pid);
60
-
61
- clearTimeout(triggerTimer);
62
- triggerTimer = setTimeout(triggerEzoic, 150);
63
- }
64
-
65
47
  function redistribute() {
66
48
  if (!config || config.excluded) return;
67
49
 
@@ -71,36 +53,35 @@
71
53
  'message': '[component="post"]'
72
54
  };
73
55
 
74
- if (config.enableCategoryAds) {
75
- process(Array.from(document.querySelectorAll(selectors.home)), 'home', config.intervalCategories, config.showFirstCategoryAd);
76
- }
77
- if (config.enableBetweenAds) {
78
- process(Array.from(document.querySelectorAll(selectors['topic-list'])), 'topic-list', config.intervalPosts, config.showFirstTopicAd);
79
- }
80
- if (config.enableMessageAds) {
81
- process(Array.from(document.querySelectorAll(selectors.message)), 'message', config.messageIntervalPosts, config.showFirstMessageAd);
82
- }
83
- }
84
-
85
- function process(items, kind, interval, showFirst) {
86
- const int = parseInt(interval, 10) || 10;
87
- items.forEach((item, index) => {
88
- const pos = index + 1;
89
- const shouldHaveAd = (pos === 1 && showFirst) || (pos % int === 0);
90
- const next = item.nextElementSibling;
91
-
92
- if (shouldHaveAd && !(next && next.classList.contains(WRAP_CLASS))) {
93
- const pool = getPool();
94
- const available = pool.querySelector(`.${WRAP_CLASS}[data-kind="${kind}"]`);
95
-
96
- if (available) {
97
- isInternalChange = true;
98
- item.parentNode.insertBefore(available, item.nextSibling);
99
- callEzoic(available.getAttribute('data-placeholder-id'));
100
- setTimeout(() => { isInternalChange = false; }, 50);
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
+ }
101
78
  }
102
- }
103
- });
79
+ });
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);
104
85
  }
105
86
 
106
87
  function init() {
@@ -109,11 +90,11 @@
109
90
  .then(data => {
110
91
  config = data;
111
92
  const pool = getPool();
93
+
112
94
  const setup = (raw, kind) => {
113
95
  if (!raw) return;
114
96
  raw.split(/[\s,]+/).filter(Boolean).forEach(id => {
115
- // Créer le placeholder dans le pool s'il n'existe pas encore physiquement
116
- if (!pool.querySelector(`[data-placeholder-id="${id}"]`)) {
97
+ if (!document.getElementById(`ezoic-pub-ad-placeholder-${id}`)) {
117
98
  const d = document.createElement('div');
118
99
  d.className = WRAP_CLASS;
119
100
  d.setAttribute('data-kind', kind);
@@ -123,6 +104,7 @@
123
104
  }
124
105
  });
125
106
  };
107
+
126
108
  setup(config.categoryPlaceholderIds, 'home');
127
109
  setup(config.placeholderIds, 'topic-list');
128
110
  setup(config.messagePlaceholderIds, 'message');
@@ -136,10 +118,7 @@
136
118
  });
137
119
  }
138
120
 
139
- // Navigation NodeBB (Ajaxify)
140
121
  window.addEventListener('action:ajaxify.end', () => {
141
- // On ne détruit RIEN au changement de page pour éviter les erreurs "already defined"
142
- // On se contente de ré-injecter les placeholders du pool
143
122
  setTimeout(redistribute, 500);
144
123
  });
145
124
 
package/public/style.css CHANGED
@@ -1,34 +1,91 @@
1
- /* Container global de pub */
1
+ /* ============================================================
2
+ CONTAINER GLOBAL DES PUBS
3
+ ============================================================ */
2
4
  .nodebb-ezoic-wrap {
3
5
  display: block !important;
4
6
  width: 100% !important;
5
- margin: 20px 0 !important;
6
- min-height: 250px;
7
- clear: both;
7
+ min-height: 250px; /* Réserve l'espace pour éviter le saut de contenu (CLS) */
8
+ margin: 30px 0 !important;
9
+ padding: 0;
10
+ clear: both !important;
8
11
  text-align: center;
12
+ position: relative;
13
+ overflow: hidden;
9
14
  }
10
15
 
11
- /* Accueil (Catégories) */
16
+ /* On s'assure que le contenu Ezoic à l'intérieur est centré */
17
+ .nodebb-ezoic-wrap > div {
18
+ margin: 0 auto !important;
19
+ }
20
+
21
+ /* ============================================================
22
+ 1. PAGE D'ACCUEIL (Liste des catégories)
23
+ ============================================================ */
12
24
  [component="categories/category"] + .nodebb-ezoic-wrap,
13
25
  .category-item + .nodebb-ezoic-wrap {
14
26
  margin: 40px 0 !important;
15
27
  border-top: 1px solid rgba(0,0,0,0.05);
28
+ padding-top: 25px;
29
+ background: transparent;
16
30
  }
17
31
 
18
- /* Liste des Topics (Page catégorie) */
32
+ /* ============================================================
33
+ 2. PAGE CATÉGORIE (Liste des Topics / Sujets)
34
+ ============================================================ */
35
+ /* Important : NodeBB Harmony utilise des <li> pour les topics.
36
+ On s'assure que notre wrap ne casse pas la structure de liste
37
+ mais s'affiche comme un bloc complet. */
19
38
  li[component="category/topic"] + .nodebb-ezoic-wrap {
20
39
  list-style: none !important;
21
- padding: 15px 0;
40
+ margin: 0 !important;
41
+ padding: 20px 0 !important;
22
42
  border-bottom: 1px solid rgba(0,0,0,0.05);
43
+ display: block !important;
44
+ float: none !important;
45
+ width: 100%;
23
46
  }
24
47
 
25
- /* Messages (Dans un post) */
48
+ /* ============================================================
49
+ 3. PAGE DES POSTS (Messages à l'intérieur d'un topic)
50
+ ============================================================ */
26
51
  [component="post"] + .nodebb-ezoic-wrap {
27
- margin: 40px 0 !important;
28
- padding: 20px;
29
- background: rgba(0,0,0,0.01);
52
+ margin: 45px 0 !important;
53
+ padding: 25px;
54
+ background: rgba(0,0,0,0.02); /* Léger fond pour distinguer le message pub */
55
+ border-radius: 12px;
56
+ border: 1px inset rgba(0,0,0,0.03);
57
+ }
58
+
59
+ /* ============================================================
60
+ CORRECTIFS ANTI "PILE-UP" & AFFICHAGE
61
+ ============================================================ */
62
+
63
+ /* Évite que les pubs ne soient invisibles si Ezoic ne charge rien immédiatement */
64
+ .nodebb-ezoic-wrap:empty {
65
+ min-height: 1px;
66
+ height: 1px;
67
+ }
68
+
69
+ /* Neutralise les marges forcées par Ezoic qui pourraient décaler le layout */
70
+ .ezoic-ad {
71
+ margin: 10px auto !important;
72
+ display: block !important;
73
+ }
74
+
75
+ /* Mobile : Réduction des marges pour ne pas perdre trop de place */
76
+ @media (max-width: 767px) {
77
+ .nodebb-ezoic-wrap {
78
+ margin: 20px 0 !important;
79
+ min-height: 100px;
80
+ }
81
+ [component="post"] + .nodebb-ezoic-wrap {
82
+ padding: 10px;
83
+ margin: 25px 0 !important;
84
+ }
30
85
  }
31
86
 
32
- /* Masquage des blocs vides */
33
- .nodebb-ezoic-wrap:empty { min-height: 1px; }
34
- .ezoic-ad { margin: 0 auto !important; }
87
+ /* Empêche les sauts de ligne bizarres dans les listes Harmony */
88
+ .categories > li.nodebb-ezoic-wrap,
89
+ .category > li.nodebb-ezoic-wrap {
90
+ float: none !important;
91
+ }