nodebb-plugin-ezoic-infinite 1.6.12 → 1.6.13

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/client.js +119 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.6.12",
3
+ "version": "1.6.13",
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,6 +1,72 @@
1
1
  (function () {
2
2
  'use strict';
3
3
 
4
+ function ezoicAnchorKeyFromEl(el) {
5
+ try {
6
+ if (!el || !el.getAttribute) return '';
7
+ var tid = el.getAttribute('data-tid') || el.getAttribute('data-topic-id');
8
+ if (tid) return 'tid:' + String(tid);
9
+ var pid = el.getAttribute('data-pid') || el.getAttribute('data-id');
10
+ if (pid) return 'pid:' + String(pid);
11
+ var uid = el.getAttribute('data-uid');
12
+ if (uid) return 'uid:' + String(uid);
13
+ } catch (e) {}
14
+ return '';
15
+ }
16
+
17
+ function ezoicFindAnchorEl(anchorKey, scope) {
18
+ try {
19
+ if (!anchorKey) return null;
20
+ var root = scope || document;
21
+ if (anchorKey.indexOf('tid:') === 0) {
22
+ var v = anchorKey.slice(4);
23
+ return root.querySelector('[data-tid="' + v + '"], [data-topic-id="' + v + '"]');
24
+ }
25
+ if (anchorKey.indexOf('pid:') === 0) {
26
+ var p = anchorKey.slice(4);
27
+ return root.querySelector('[data-pid="' + p + '"], [data-id="' + p + '"]');
28
+ }
29
+ if (anchorKey.indexOf('uid:') === 0) {
30
+ var u = anchorKey.slice(4);
31
+ return root.querySelector('[data-uid="' + u + '"]');
32
+ }
33
+ } catch (e) {}
34
+ return null;
35
+ }
36
+
37
+ function ezoicReconcileHosts(scope) {
38
+ // Ensure each li.nodebb-ezoic-host stays directly after its anchor <li>.
39
+ // Prevents "all hosts under first topic" after NodeBB re-render/virtualize.
40
+ try {
41
+ var root = scope || document;
42
+ var hosts = root.querySelectorAll('li.nodebb-ezoic-host[data-ezoic-anchor]');
43
+ if (!hosts || !hosts.length) return;
44
+
45
+ hosts.forEach(function (host) {
46
+ try {
47
+ var anchorKey = host.getAttribute('data-ezoic-anchor') || '';
48
+ if (!anchorKey) return;
49
+ var ul = host.parentElement;
50
+ if (!ul) return;
51
+
52
+ var anchor = ezoicFindAnchorEl(anchorKey, ul) || ezoicFindAnchorEl(anchorKey, document);
53
+ if (!anchor) return;
54
+
55
+ // Anchor is often inside the <li> topic; normalize to list item
56
+ var anchorLi = anchor.closest ? (anchor.closest('li') || anchor) : anchor;
57
+ if (!anchorLi || !anchorLi.parentElement) return;
58
+
59
+ if (host.previousElementSibling !== anchorLi) {
60
+ anchorLi.insertAdjacentElement('afterend', host);
61
+ }
62
+ } catch (e) {}
63
+ });
64
+ } catch (e) {}
65
+ }
66
+
67
+ ' + '';
68
+
69
+
4
70
  function ezoicInsertAfterWithUlGuard(target, wrap, kindClass) {
5
71
  try {
6
72
  if (!target || !wrap) return;
@@ -14,6 +80,7 @@ function ezoicInsertAfterWithUlGuard(target, wrap, kindClass) {
14
80
  host.setAttribute('role', 'listitem');
15
81
  host.style.listStyle = 'none';
16
82
  host.style.width = '100%';
83
+ try { var ak = ezoicAnchorKeyFromEl(target); if (ak) host.setAttribute('data-ezoic-anchor', ak); } catch(e) {}
17
84
 
18
85
  // Insert host after the target listitem, then move the wrap inside.
19
86
  if (target.insertAdjacentElement) {
@@ -48,6 +115,7 @@ function ezoicRepairInvalidBetweenWraps() {
48
115
  host.setAttribute('role', 'listitem');
49
116
  host.style.listStyle = 'none';
50
117
  host.style.width = '100%';
118
+ try { var ak = ezoicAnchorKeyFromEl(target); if (ak) host.setAttribute('data-ezoic-anchor', ak); } catch(e) {}
51
119
  p.insertBefore(host, wrap);
52
120
  host.appendChild(wrap);
53
121
  try { wrap.style.width = '100%'; } catch (e) {}
@@ -1577,3 +1645,54 @@ if (window.jQuery) {
1577
1645
  } catch (e) {}
1578
1646
  }
1579
1647
  // ===== /V12.2 =====
1648
+
1649
+
1650
+ // ===== V12.3 reconcile scheduler =====
1651
+ (function(){
1652
+ var pending = false;
1653
+ var last = 0;
1654
+ var COOLDOWN = 180;
1655
+
1656
+ function schedule(scope){
1657
+ var now = Date.now();
1658
+ if (now - last < COOLDOWN) return;
1659
+ if (pending) return;
1660
+ pending = true;
1661
+ requestAnimationFrame(function(){
1662
+ pending = false;
1663
+ last = Date.now();
1664
+ try { ezoicReconcileHosts(scope); } catch(e) {}
1665
+ });
1666
+ }
1667
+
1668
+ window.addEventListener('scroll', function(){ schedule(document); }, { passive: true });
1669
+ window.addEventListener('resize', function(){ schedule(document); }, { passive: true });
1670
+
1671
+ if (window.jQuery) {
1672
+ window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function(){
1673
+ setTimeout(function(){ schedule(document); }, 0);
1674
+ setTimeout(function(){ schedule(document); }, 220);
1675
+ setTimeout(function(){ schedule(document); }, 600);
1676
+ });
1677
+ }
1678
+
1679
+ // MutationObserver lightweight: only watch ULs for child list changes
1680
+ try {
1681
+ if (typeof MutationObserver !== 'undefined') {
1682
+ var mo = new MutationObserver(function(muts){
1683
+ // if any li hosts are moved/added, reconcile
1684
+ for (var i=0;i<muts.length;i++){
1685
+ var m = muts[i];
1686
+ if (m.addedNodes && m.addedNodes.length) { schedule(m.target); break; }
1687
+ if (m.removedNodes && m.removedNodes.length) { schedule(m.target); break; }
1688
+ }
1689
+ });
1690
+ document.querySelectorAll('ul,ol').forEach(function(list){
1691
+ try { mo.observe(list, {childList:true}); } catch(e) {}
1692
+ });
1693
+ }
1694
+ } catch(e){}
1695
+
1696
+ setTimeout(function(){ try { schedule(document); } catch(e) {} }, 0);
1697
+ })();
1698
+ // ===== /V12.3 =====