nodebb-plugin-ezoic-infinite 1.6.11 → 1.6.12

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.11",
3
+ "version": "1.6.12",
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,34 +1,59 @@
1
1
  (function () {
2
2
  'use strict';
3
3
 
4
- function createWrapHostAndWrap(kindClass, targetEl) {
5
- // For <ul>/<ol> we MUST insert a <li> to keep valid DOM.
6
- // But for compatibility with existing selectors (often 'div.nodebb-ezoic-wrap'),
7
- // we keep the actual wrap as a DIV inside the LI.
8
- var host = null;
4
+ function ezoicInsertAfterWithUlGuard(target, wrap, kindClass) {
9
5
  try {
6
+ if (!target || !wrap) return;
7
+ // Only guard for BETWEEN placements (known to be inserted between <li> items inside <ul>/<ol>)
10
8
  if (kindClass === 'ezoic-ad-between') {
11
- var p = targetEl && targetEl.parentElement;
9
+ var p = target.parentElement;
12
10
  if (p && (p.tagName === 'UL' || p.tagName === 'OL')) {
13
- host = document.createElement('li');
11
+ // Ensure wrap is not a direct child of UL/OL (invalid HTML); wrap it in an LI host.
12
+ var host = document.createElement('li');
14
13
  host.className = 'nodebb-ezoic-host';
15
14
  host.setAttribute('role', 'listitem');
16
15
  host.style.listStyle = 'none';
17
16
  host.style.width = '100%';
17
+
18
+ // Insert host after the target listitem, then move the wrap inside.
19
+ if (target.insertAdjacentElement) {
20
+ target.insertAdjacentElement('afterend', host);
21
+ } else if (p.insertBefore) {
22
+ p.insertBefore(host, target.nextSibling);
23
+ }
24
+ try { host.appendChild(wrap); } catch (e) {}
25
+
26
+ // Keep wrap full width
27
+ try { wrap.style.width = '100%'; } catch (e) {}
28
+ return;
18
29
  }
19
30
  }
20
- } catch (e) {}
21
31
 
22
- var pair = createWrapHostAndWrap(kindClass, el);
23
- var host = pair.hostEl;
24
- var wrap = pair.wrapEl;
25
- wrap.className = 'nodebb-ezoic-wrap ' + kindClass;
32
+ // Default behavior
33
+ if (target.insertAdjacentElement) ezoicInsertAfterWithUlGuard(target, wrap, kindClass);
34
+ else if (target.parentNode) target.parentNode.insertBefore(wrap, target.nextSibling);
35
+ } catch (e) {}
36
+ }
26
37
 
27
- if (host) {
28
- host.appendChild(wrap);
29
- return { hostEl: host, wrapEl: wrap };
30
- }
31
- return { hostEl: wrap, wrapEl: wrap };
38
+ function ezoicRepairInvalidBetweenWraps() {
39
+ // If any legacy DIV wraps were already inserted directly under UL/OL, repair them once.
40
+ try {
41
+ var bad = document.querySelectorAll('ul > div.nodebb-ezoic-wrap.ezoic-ad-between, ol > div.nodebb-ezoic-wrap.ezoic-ad-between');
42
+ bad.forEach(function (wrap) {
43
+ try {
44
+ var p = wrap.parentElement;
45
+ if (!p) return;
46
+ var host = document.createElement('li');
47
+ host.className = 'nodebb-ezoic-host';
48
+ host.setAttribute('role', 'listitem');
49
+ host.style.listStyle = 'none';
50
+ host.style.width = '100%';
51
+ p.insertBefore(host, wrap);
52
+ host.appendChild(wrap);
53
+ try { wrap.style.width = '100%'; } catch (e) {}
54
+ } catch (e) {}
55
+ });
56
+ } catch (e) {}
32
57
  }
33
58
 
34
59
 
@@ -668,9 +693,7 @@ function globalGapFixInit() {
668
693
  // ---------------- insertion primitives ----------------
669
694
 
670
695
  function buildWrap(id, kindClass, afterPos, createPlaceholder) {
671
- const pair = createWrapHostAndWrap(kindClass, el);
672
- const host = pair.hostEl;
673
- const wrap = pair.wrapEl;
696
+ const wrap = document.createElement('div');
674
697
  wrap.className = `${WRAP_CLASS} ${kindClass}`;
675
698
  wrap.setAttribute('data-ezoic-after', String(afterPos));
676
699
  wrap.setAttribute('data-ezoic-wrapid', String(id));
@@ -701,7 +724,7 @@ function globalGapFixInit() {
701
724
  insertingIds.add(id);
702
725
  try {
703
726
  const wrap = buildWrap(id, kindClass, afterPos, !existingPh);
704
- target.insertAdjacentElement('afterend', wrap);
727
+ ezoicInsertAfterWithUlGuard(target, wrap, kindClass);
705
728
 
706
729
  // If placeholder exists elsewhere (including pool), move it into the wrapper.
707
730
  if (existingPh) {
@@ -1161,12 +1184,48 @@ function buildOrdinalMap(items) {
1161
1184
  }
1162
1185
 
1163
1186
  function pickRecyclableWrap(kindClass) {
1164
- return null;
1165
- }
1187
+ // Only recycle wrappers that are well above the viewport to avoid visible "disappearing".
1188
+ // With very small id pools (e.g. 6 ids), recycling is the only way to keep ads appearing
1189
+ // on long topics without redefining placeholders.
1190
+ const wraps = document.querySelectorAll('.' + kindClass + '[data-ezoic-wrapid]');
1191
+ if (!wraps || !wraps.length) return null;
1192
+
1193
+ const vh = Math.max(300, window.innerHeight || 800);
1194
+ // Recycle only when the wrapper is far above the viewport.
1195
+ // This keeps ads on-screen longer (especially on mobile) and reduces "blink".
1196
+ const threshold = -Math.min(9000, Math.round(vh * 6));
1197
+
1198
+ let best = null;
1199
+ let bestBottom = Infinity;
1200
+ for (const w of wraps) {
1201
+ if (!w || !w.isConnected) continue;
1202
+ if (w.getAttribute && w.getAttribute('data-ezoic-pin') === '1') continue;
1203
+ const rect = w.getBoundingClientRect();
1204
+ if (rect.bottom < threshold) {
1205
+ if (rect.bottom < bestBottom) {
1206
+ bestBottom = rect.bottom;
1207
+ best = w;
1208
+ }
1209
+ }
1210
+ }
1211
+ return best;
1212
+ }
1166
1213
 
1167
1214
  function moveWrapAfter(anchorEl, wrap, kindClass, afterPos) {
1168
- return;
1169
- }
1215
+ try {
1216
+ if (!anchorEl || !wrap || !wrap.isConnected) return null;
1217
+
1218
+ wrap.setAttribute('data-ezoic-after', String(afterPos));
1219
+ ezoicInsertAfterWithUlGuard(anchorEl, wrap, kindClass);
1220
+
1221
+ // Ensure minimal layout impact.
1222
+ try { wrap.style.contain = 'layout style paint'; } catch (e) {}
1223
+ try { tightenStickyIn(wrap); } catch (e) {}
1224
+ return wrap;
1225
+ } catch (e) {
1226
+ return null;
1227
+ }
1228
+ }
1170
1229
 
1171
1230
  async function runCore() {
1172
1231
  if (isBlocked()) return 0;
@@ -1505,3 +1564,16 @@ function buildOrdinalMap(items) {
1505
1564
  insertHeroAdEarly().catch(() => {});
1506
1565
  requestBurst();
1507
1566
  })();
1567
+
1568
+
1569
+ // ===== V12.2: run UL/OL repair =====
1570
+ try { ezoicRepairInvalidBetweenWraps(); } catch (e) {}
1571
+ if (window.jQuery) {
1572
+ try {
1573
+ window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function () {
1574
+ setTimeout(function(){ try { ezoicRepairInvalidBetweenWraps(); } catch(e) {} }, 0);
1575
+ setTimeout(function(){ try { ezoicRepairInvalidBetweenWraps(); } catch(e) {} }, 200);
1576
+ });
1577
+ } catch (e) {}
1578
+ }
1579
+ // ===== /V12.2 =====
package/public/style.css CHANGED
@@ -81,9 +81,8 @@
81
81
  }
82
82
 
83
83
 
84
- /* ===== V12.1 li host wrapper ===== */
84
+ /* ===== V12.2 UL host for between wraps ===== */
85
85
  li.nodebb-ezoic-host { list-style: none; width: 100%; }
86
- /* keep inner wrap full width */
87
86
  li.nodebb-ezoic-host > .nodebb-ezoic-wrap { width: 100%; }
88
- /* ===== /V12.1 ===== */
87
+ /* ===== /V12.2 ===== */
89
88