nodebb-plugin-ezoic-infinite 1.6.85 → 1.6.87

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.85",
3
+ "version": "1.6.87",
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,124 +1,138 @@
1
1
  (function () {
2
- 'use strict';
2
+ 'use strict';
3
3
 
4
- if (window.ezInfiniteInjected) return;
5
- window.ezInfiniteInjected = true;
4
+ if (window.ezInfiniteInjected) return;
5
+ window.ezInfiniteInjected = true;
6
6
 
7
- const WRAP_CLASS = 'nodebb-ezoic-wrap';
8
- const POOL_ID = 'nodebb-ezoic-placeholder-pool';
9
-
10
- let config = null;
11
- let isInternalChange = false;
12
-
13
- function getPool() {
14
- let p = document.getElementById(POOL_ID);
15
- if (!p) {
16
- p = document.createElement('div');
17
- p.id = POOL_ID;
18
- p.style.display = 'none';
19
- document.body.appendChild(p);
20
- }
21
- return p;
22
- }
7
+ const WRAP_CLASS = 'nodebb-ezoic-wrap';
8
+ const POOL_ID = 'nodebb-ezoic-placeholder-pool';
9
+
10
+ let config = null;
11
+ let isInternalChange = false;
12
+ let activePlaceholders = new Set();
23
13
 
24
- function callEzoic(pid) {
25
- if (typeof window.ezstandalone === 'undefined') return;
26
- const id = parseInt(pid, 10);
27
- if (isNaN(id)) return;
28
-
29
- // On utilise la queue que tu as définie dans ton header
30
- window.ezstandalone.cmd.push(function() {
31
- window.ezstandalone.define(id);
32
-
33
- // On laisse Ezoic décider s'il doit faire enable() ou refresh()
34
- if (!window.ezstandalone.enabled) {
35
- window.ezstandalone.enable();
36
- window.ezstandalone.display();
37
- } else {
38
- // On utilise refresh uniquement si l'ID est déjà affiché
39
- // ou si le cycle initial est terminé.
40
- window.ezstandalone.refresh();
41
- }
42
- });
14
+ function getPool() {
15
+ let p = document.getElementById(POOL_ID);
16
+ if (!p) {
17
+ p = document.createElement('div');
18
+ p.id = POOL_ID;
19
+ p.style.display = 'none';
20
+ document.body.appendChild(p);
43
21
  }
22
+ return p;
23
+ }
44
24
 
45
- function redistribute() {
46
- if (!config || config.excluded) return;
25
+ // Utilisation stricte de la file d'attente CMD du zip
26
+ function callEzoic(id) {
27
+ if (typeof window.ezstandalone === 'undefined') return;
28
+
29
+ window.ezstandalone.cmd.push(function() {
30
+ // Si l'ID est déjà affiché, on ne fait rien pour éviter le spam de refresh
31
+ if (activePlaceholders.has(id)) {
32
+ window.ezstandalone.refresh();
33
+ return;
34
+ }
47
35
 
48
- // Sélecteurs NodeBB 4.x Harmony
49
- // TopicItems = Lignes de sujets sur l'accueil
50
- // PostItems = Messages dans un sujet
51
- const topicItems = document.querySelectorAll('[component="category/topic"]');
52
- const postItems = document.querySelectorAll('[component="post"]');
36
+ window.ezstandalone.define(id);
37
+ activePlaceholders.add(id);
53
38
 
54
- if (topicItems.length > 0 && config.enableBetweenAds) {
55
- processItems(Array.from(topicItems), 'between', config.intervalPosts, config.showFirstTopicAd);
56
- }
39
+ if (!window.ezstandalone.enabled) {
40
+ window.ezstandalone.enable();
41
+ window.ezstandalone.display();
42
+ } else {
43
+ window.ezstandalone.refresh();
44
+ }
45
+ });
46
+ }
47
+
48
+ function redistribute() {
49
+ if (!config || config.excluded) return;
50
+
51
+ // Utilisation des sélecteurs exacts du zip V17 (Harmony/NodeBB 4)
52
+ const topicItems = document.querySelectorAll('li[component="category/topic"]');
53
+ const postItems = document.querySelectorAll('[component="post"][data-pid]');
54
+
55
+ // Injection pour la page d'accueil / catégories
56
+ if (topicItems.length > 0 && config.enableBetweenAds) {
57
+ inject(Array.from(topicItems), 'between', config.intervalPosts, config.showFirstTopicAd);
58
+ }
59
+
60
+ // Injection pour les messages (topics)
61
+ if (postItems.length > 0 && config.enableMessageAds) {
62
+ inject(Array.from(postItems), 'message', config.messageIntervalPosts, config.showFirstMessageAd);
63
+ }
64
+ }
65
+
66
+ function inject(items, kind, interval, showFirst) {
67
+ const int = parseInt(interval, 10) || 10;
68
+ items.forEach((item, index) => {
69
+ const pos = index + 1;
70
+ const shouldHaveAd = (pos === 1 && showFirst) || (pos % int === 0);
71
+
72
+ const next = item.nextElementSibling;
73
+ if (shouldHaveAd && !(next && next.classList.contains(WRAP_CLASS))) {
74
+ const pool = getPool();
75
+ const available = pool.querySelector(`.${WRAP_CLASS}[data-kind="${kind}"]`);
57
76
 
58
- if (postItems.length > 0 && config.enableMessageAds) {
59
- processItems(Array.from(postItems), 'message', config.messageIntervalPosts, config.showFirstMessageAd);
77
+ if (available) {
78
+ isInternalChange = true;
79
+ // On insère l'élément comme dans le zip original
80
+ item.parentNode.insertBefore(available, item.nextSibling);
81
+
82
+ const pid = parseInt(available.getAttribute('data-placeholder-id'), 10);
83
+ callEzoic(pid);
84
+
85
+ setTimeout(() => { isInternalChange = false; }, 100);
60
86
  }
61
- }
87
+ }
88
+ });
89
+ }
62
90
 
63
- function processItems(items, kind, interval, showFirst) {
64
- const int = parseInt(interval, 10) || 10;
65
- items.forEach((item, index) => {
66
- const pos = index + 1;
67
- const shouldHaveAd = (pos === 1 && showFirst) || (pos % int === 0);
68
-
69
- const next = item.nextElementSibling;
70
- if (shouldHaveAd && !(next && next.classList.contains(WRAP_CLASS))) {
71
- const pool = getPool();
72
- const available = pool.querySelector(`.${WRAP_CLASS}[data-kind="${kind}"]`);
73
- if (available) {
74
- isInternalChange = true;
75
- item.parentNode.insertBefore(available, item.nextSibling);
76
- callEzoic(available.getAttribute('data-placeholder-id'));
77
- setTimeout(() => { isInternalChange = false; }, 100);
78
- }
91
+ function init() {
92
+ fetch('/api/plugins/ezoic-infinite/config')
93
+ .then(r => r.json())
94
+ .then(data => {
95
+ config = data;
96
+ const pool = getPool();
97
+
98
+ const setupPool = (raw, kind) => {
99
+ if (!raw) return;
100
+ raw.split(/[\s,]+/).filter(Boolean).forEach(id => {
101
+ if (!document.querySelector(`[data-placeholder-id="${id}"]`)) {
102
+ const d = document.createElement('div');
103
+ d.className = WRAP_CLASS;
104
+ d.setAttribute('data-kind', kind);
105
+ d.setAttribute('data-placeholder-id', id);
106
+ // Structure HTML propre
107
+ d.innerHTML = `<div id="ezoic-pub-ad-placeholder-${id}" class="ezoic-ad"></div>`;
108
+ pool.appendChild(d);
79
109
  }
80
- });
81
- }
110
+ });
111
+ };
82
112
 
83
- function init() {
84
- fetch('/api/plugins/ezoic-infinite/config')
85
- .then(r => r.json())
86
- .then(data => {
87
- config = data;
88
- const pool = getPool();
89
- const setup = (raw, kind) => {
90
- if (!raw) return;
91
- raw.split(/[\s,]+/).filter(Boolean).forEach(id => {
92
- if (!document.querySelector(`[data-placeholder-id="${id}"]`)) {
93
- const d = document.createElement('div');
94
- d.className = WRAP_CLASS;
95
- d.setAttribute('data-kind', kind);
96
- d.setAttribute('data-placeholder-id', id);
97
- d.innerHTML = `<div id="ezoic-pub-ad-placeholder-${id}" class="ezoic-ad"></div>`;
98
- pool.appendChild(d);
99
- }
100
- });
101
- };
102
- setup(config.placeholderIds, 'between');
103
- setup(config.messagePlaceholderIds, 'message');
104
-
105
- redistribute();
106
-
107
- const observer = new MutationObserver(() => {
108
- if (!isInternalChange) redistribute();
109
- });
110
- observer.observe(document.body, { childList: true, subtree: true });
111
- });
112
- }
113
+ setupPool(config.placeholderIds, 'between');
114
+ setupPool(config.messagePlaceholderIds, 'message');
115
+
116
+ redistribute();
113
117
 
114
- // Gestion de la navigation AJAX de NodeBB 4
115
- window.addEventListener('action:ajaxify.end', function() {
116
- setTimeout(redistribute, 500);
118
+ // Observer pour l'infinite scroll (reprise du zip)
119
+ const observer = new MutationObserver(() => {
120
+ if (!isInternalChange) redistribute();
121
+ });
122
+ observer.observe(document.body, { childList: true, subtree: true });
123
+ });
124
+ }
125
+
126
+ // Événements NodeBB pour gérer la navigation sans rechargement
127
+ if (window.jQuery) {
128
+ window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function() {
129
+ setTimeout(redistribute, 500);
117
130
  });
131
+ }
118
132
 
119
- if (document.readyState === 'loading') {
120
- document.addEventListener('DOMContentLoaded', init);
121
- } else {
122
- init();
123
- }
133
+ if (document.readyState === 'loading') {
134
+ document.addEventListener('DOMContentLoaded', init);
135
+ } else {
136
+ init();
137
+ }
124
138
  })();
package/public/style.css CHANGED
@@ -1,25 +1,20 @@
1
1
  .nodebb-ezoic-wrap {
2
- display: block !important;
3
- width: 100% !important;
4
- margin: 25px auto !important;
5
- min-height: 250px; /* Réserve l'espace pour éviter les sauts de page */
6
- clear: both;
7
- text-align: center;
2
+ display: block !important;
3
+ width: 100% !important;
4
+ margin: 30px 0 !important;
5
+ min-height: 250px;
6
+ clear: both;
8
7
  }
9
8
 
10
- /* Accueil : Ajout d'une séparation propre entre les lignes de sujets */
11
- [component="category/topic"] + .nodebb-ezoic-wrap {
12
- border-bottom: 1px solid rgba(0,0,0,0.05);
13
- margin-bottom: 15px !important;
9
+ /* Fix pour les listes de l'accueil Harmony */
10
+ li[component="category/topic"] + .nodebb-ezoic-wrap {
11
+ list-style: none;
12
+ padding: 15px;
13
+ background: rgba(0,0,0,0.02);
14
+ border-radius: 8px;
14
15
  }
15
16
 
16
- /* Cache si vide (Ezoic ajoute des classes quand il ne remplit pas) */
17
+ /* Éviter les trous si la pub ne charge pas */
17
18
  .nodebb-ezoic-wrap:empty {
18
- display: none !important;
19
- min-height: 0;
20
- }
21
-
22
- /* Anti-empilement */
23
- .nodebb-ezoic-wrap + .nodebb-ezoic-wrap {
24
- display: none !important;
19
+ min-height: 1px;
25
20
  }