nodebb-plugin-ezoic-infinite 1.6.13 → 1.6.14

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 +59 -59
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.6.13",
3
+ "version": "1.6.14",
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,61 +1,65 @@
1
1
  (function () {
2
2
  'use strict';
3
3
 
4
- function ezoicAnchorKeyFromEl(el) {
4
+ function ezoicAnchorKeyFromNode(node) {
5
+ // Robustly extract an anchor id from a <li> topic or any descendant.
5
6
  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);
7
+ if (!node) return '';
8
+ var el = node;
9
+ // If node itself doesn't have ids, search descendants.
10
+ if (!(el.getAttribute && (el.getAttribute('data-tid') || el.getAttribute('data-topic-id') || el.getAttribute('data-pid') || el.getAttribute('data-id')))) {
11
+ if (el.querySelector) {
12
+ el = el.querySelector('[data-tid],[data-topic-id],[data-pid],[data-id]') || node;
13
+ }
14
+ }
15
+ if (el.getAttribute) {
16
+ var tid = el.getAttribute('data-tid') || el.getAttribute('data-topic-id');
17
+ if (tid) return 'tid:' + String(tid);
18
+ var pid = el.getAttribute('data-pid') || el.getAttribute('data-id');
19
+ if (pid) return 'pid:' + String(pid);
20
+ }
13
21
  } catch (e) {}
14
22
  return '';
15
23
  }
16
24
 
17
- function ezoicFindAnchorEl(anchorKey, scope) {
25
+ function ezoicFindAnchorLi(anchorKey, listEl) {
18
26
  try {
19
27
  if (!anchorKey) return null;
20
- var root = scope || document;
28
+ var root = listEl || document;
29
+ var el = null;
21
30
  if (anchorKey.indexOf('tid:') === 0) {
22
31
  var v = anchorKey.slice(4);
23
- return root.querySelector('[data-tid="' + v + '"], [data-topic-id="' + v + '"]');
24
- }
25
- if (anchorKey.indexOf('pid:') === 0) {
32
+ el = root.querySelector('[data-tid="' + v + '"], [data-topic-id="' + v + '"]');
33
+ } else if (anchorKey.indexOf('pid:') === 0) {
26
34
  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 + '"]');
35
+ el = root.querySelector('[data-pid="' + p + '"], [data-id="' + p + '"]');
32
36
  }
33
- } catch (e) {}
34
- return null;
37
+ if (!el) return null;
38
+ return el.closest ? (el.closest('li') || null) : null;
39
+ } catch (e) { return null; }
35
40
  }
36
41
 
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.
42
+ function ezoicReconcileOrPurgeHosts(scope) {
43
+ // Reposition each host after its anchor li. If anchor doesn't exist (virtualized away),
44
+ // remove the host to prevent it from collecting at the top.
40
45
  try {
41
46
  var root = scope || document;
42
47
  var hosts = root.querySelectorAll('li.nodebb-ezoic-host[data-ezoic-anchor]');
43
48
  if (!hosts || !hosts.length) return;
44
49
 
45
- hosts.forEach(function (host) {
50
+ hosts.forEach(function(host){
46
51
  try {
52
+ var listEl = host.parentElement;
53
+ if (!listEl) return;
47
54
  var anchorKey = host.getAttribute('data-ezoic-anchor') || '';
48
55
  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
56
 
57
+ var anchorLi = ezoicFindAnchorLi(anchorKey, listEl) || ezoicFindAnchorLi(anchorKey, document);
58
+ if (!anchorLi) {
59
+ // Anchor not in DOM right now => delete host to avoid "pile at top"
60
+ host.remove();
61
+ return;
62
+ }
59
63
  if (host.previousElementSibling !== anchorLi) {
60
64
  anchorLi.insertAdjacentElement('afterend', host);
61
65
  }
@@ -64,8 +68,6 @@ function ezoicReconcileHosts(scope) {
64
68
  } catch (e) {}
65
69
  }
66
70
 
67
- ' + '';
68
-
69
71
 
70
72
  function ezoicInsertAfterWithUlGuard(target, wrap, kindClass) {
71
73
  try {
@@ -80,7 +82,8 @@ function ezoicInsertAfterWithUlGuard(target, wrap, kindClass) {
80
82
  host.setAttribute('role', 'listitem');
81
83
  host.style.listStyle = 'none';
82
84
  host.style.width = '100%';
83
- try { var ak = ezoicAnchorKeyFromEl(target); if (ak) host.setAttribute('data-ezoic-anchor', ak); } catch(e) {}
85
+ try { var prev = wrap.previousElementSibling; var ak2 = ezoicAnchorKeyFromNode(prev || (wrap.parentElement && wrap.parentElement.previousElementSibling)); if (ak2) host.setAttribute('data-ezoic-anchor', ak2); } catch(e) {}
86
+ try { var ak = ezoicAnchorKeyFromNode(target); if (ak) host.setAttribute('data-ezoic-anchor', ak); } catch(e) {}
84
87
 
85
88
  // Insert host after the target listitem, then move the wrap inside.
86
89
  if (target.insertAdjacentElement) {
@@ -115,7 +118,7 @@ function ezoicRepairInvalidBetweenWraps() {
115
118
  host.setAttribute('role', 'listitem');
116
119
  host.style.listStyle = 'none';
117
120
  host.style.width = '100%';
118
- try { var ak = ezoicAnchorKeyFromEl(target); if (ak) host.setAttribute('data-ezoic-anchor', ak); } catch(e) {}
121
+ try { var ak = ezoicAnchorKeyFromNode(target); if (ak) host.setAttribute('data-ezoic-anchor', ak); } catch(e) {}
119
122
  p.insertBefore(host, wrap);
120
123
  host.appendChild(wrap);
121
124
  try { wrap.style.width = '100%'; } catch (e) {}
@@ -1647,52 +1650,49 @@ if (window.jQuery) {
1647
1650
  // ===== /V12.2 =====
1648
1651
 
1649
1652
 
1650
- // ===== V12.3 reconcile scheduler =====
1653
+ // ===== V12.4 reconcile+purge scheduler =====
1651
1654
  (function(){
1652
- var pending = false;
1653
- var last = 0;
1654
- var COOLDOWN = 180;
1655
-
1655
+ var pending=false, last=0, COOLDOWN=160;
1656
1656
  function schedule(scope){
1657
- var now = Date.now();
1658
- if (now - last < COOLDOWN) return;
1657
+ var now=Date.now();
1658
+ if (now-last<COOLDOWN) return;
1659
1659
  if (pending) return;
1660
- pending = true;
1660
+ pending=true;
1661
1661
  requestAnimationFrame(function(){
1662
- pending = false;
1663
- last = Date.now();
1664
- try { ezoicReconcileHosts(scope); } catch(e) {}
1662
+ pending=false; last=Date.now();
1663
+ try { ezoicReconcileOrPurgeHosts(scope); } catch(e) {}
1665
1664
  });
1666
1665
  }
1667
1666
 
1668
- window.addEventListener('scroll', function(){ schedule(document); }, { passive: true });
1669
- window.addEventListener('resize', function(){ schedule(document); }, { passive: true });
1667
+ window.addEventListener('scroll', function(){ schedule(document); }, { passive:true });
1668
+ window.addEventListener('resize', function(){ schedule(document); }, { passive:true });
1670
1669
 
1671
1670
  if (window.jQuery) {
1672
1671
  window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function(){
1673
1672
  setTimeout(function(){ schedule(document); }, 0);
1674
1673
  setTimeout(function(){ schedule(document); }, 220);
1675
- setTimeout(function(){ schedule(document); }, 600);
1674
+ setTimeout(function(){ schedule(document); }, 700);
1676
1675
  });
1677
1676
  }
1678
1677
 
1679
- // MutationObserver lightweight: only watch ULs for child list changes
1678
+ // Observe only the main list containers if present to reduce overhead
1680
1679
  try {
1681
1680
  if (typeof MutationObserver !== 'undefined') {
1682
1681
  var mo = new MutationObserver(function(muts){
1683
- // if any li hosts are moved/added, reconcile
1684
1682
  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; }
1683
+ var m=muts[i];
1684
+ if ((m.addedNodes && m.addedNodes.length) || (m.removedNodes && m.removedNodes.length)) {
1685
+ schedule(m.target);
1686
+ break;
1687
+ }
1688
1688
  }
1689
1689
  });
1690
- document.querySelectorAll('ul,ol').forEach(function(list){
1690
+ document.querySelectorAll('ul[component], ul.topic-list, ul.categories, ol[component]').forEach(function(list){
1691
1691
  try { mo.observe(list, {childList:true}); } catch(e) {}
1692
1692
  });
1693
1693
  }
1694
1694
  } catch(e){}
1695
1695
 
1696
- setTimeout(function(){ try { schedule(document); } catch(e) {} }, 0);
1696
+ setTimeout(function(){ schedule(document); }, 0);
1697
1697
  })();
1698
- // ===== /V12.3 =====
1698
+ // ===== /V12.4 =====