nodebb-plugin-ezoic-infinite 1.6.14 → 1.6.15

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 +47 -46
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.6.14",
3
+ "version": "1.6.15",
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,47 +1,49 @@
1
1
  (function () {
2
2
  'use strict';
3
3
 
4
- function ezoicAnchorKeyFromNode(node) {
5
- // Robustly extract an anchor id from a <li> topic or any descendant.
4
+ function ezoicTopicIdFromLi(li) {
6
5
  try {
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
- }
6
+ if (!li) return '';
7
+ // try explicit attrs first
8
+ var tid = li.getAttribute && (li.getAttribute('data-tid') || li.getAttribute('data-topic-id'));
9
+ if (tid) return String(tid);
10
+ // try finding a topic permalink like /topic/13789/...
11
+ var a = li.querySelector && li.querySelector('a[href*="/topic/"]');
12
+ if (!a) return '';
13
+ var href = a.getAttribute('href') || '';
14
+ var m = href.match(/\/topic\/(\d+)\b/);
15
+ if (m && m[1]) return m[1];
21
16
  } catch (e) {}
22
17
  return '';
23
18
  }
24
19
 
25
- function ezoicFindAnchorLi(anchorKey, listEl) {
20
+ function ezoicAnchorKeyFromTarget(target) {
21
+ try {
22
+ if (!target) return '';
23
+ var li = target.closest ? target.closest('li') : null;
24
+ if (!li) li = target.tagName === 'LI' ? target : null;
25
+ if (!li) return '';
26
+ var tid = ezoicTopicIdFromLi(li);
27
+ if (tid) return 'topic:' + tid;
28
+ } catch (e) {}
29
+ return '';
30
+ }
31
+
32
+ function ezoicFindAnchorLiByKey(anchorKey, scope) {
26
33
  try {
27
34
  if (!anchorKey) return null;
28
- var root = listEl || document;
29
- var el = null;
30
- if (anchorKey.indexOf('tid:') === 0) {
31
- var v = anchorKey.slice(4);
32
- el = root.querySelector('[data-tid="' + v + '"], [data-topic-id="' + v + '"]');
33
- } else if (anchorKey.indexOf('pid:') === 0) {
34
- var p = anchorKey.slice(4);
35
- el = root.querySelector('[data-pid="' + p + '"], [data-id="' + p + '"]');
36
- }
37
- if (!el) return null;
38
- return el.closest ? (el.closest('li') || null) : null;
39
- } catch (e) { return null; }
35
+ if (anchorKey.indexOf('topic:') !== 0) return null;
36
+ var tid = anchorKey.slice(6);
37
+ var root = scope || document;
38
+ // locate any link to this topic and climb to li
39
+ var link = root.querySelector('a[href^="/topic/' + tid + '"], a[href*="/topic/' + tid + '/"]');
40
+ if (!link) return null;
41
+ return link.closest ? link.closest('li') : null;
42
+ } catch (e) {}
43
+ return null;
40
44
  }
41
45
 
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.
46
+ function ezoicReconcileOrPurgeByTopic(scope) {
45
47
  try {
46
48
  var root = scope || document;
47
49
  var hosts = root.querySelectorAll('li.nodebb-ezoic-host[data-ezoic-anchor]');
@@ -51,12 +53,11 @@ function ezoicReconcileOrPurgeHosts(scope) {
51
53
  try {
52
54
  var listEl = host.parentElement;
53
55
  if (!listEl) return;
54
- var anchorKey = host.getAttribute('data-ezoic-anchor') || '';
55
- if (!anchorKey) return;
56
+ var key = host.getAttribute('data-ezoic-anchor') || '';
57
+ if (!key) return;
56
58
 
57
- var anchorLi = ezoicFindAnchorLi(anchorKey, listEl) || ezoicFindAnchorLi(anchorKey, document);
59
+ var anchorLi = ezoicFindAnchorLiByKey(key, listEl) || ezoicFindAnchorLiByKey(key, document);
58
60
  if (!anchorLi) {
59
- // Anchor not in DOM right now => delete host to avoid "pile at top"
60
61
  host.remove();
61
62
  return;
62
63
  }
@@ -82,8 +83,7 @@ function ezoicInsertAfterWithUlGuard(target, wrap, kindClass) {
82
83
  host.setAttribute('role', 'listitem');
83
84
  host.style.listStyle = 'none';
84
85
  host.style.width = '100%';
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) {}
86
+ try { var ak = ezoicAnchorKeyFromTarget(target); if (ak) host.setAttribute('data-ezoic-anchor', ak); } catch(e) {}
87
87
 
88
88
  // Insert host after the target listitem, then move the wrap inside.
89
89
  if (target.insertAdjacentElement) {
@@ -118,7 +118,7 @@ function ezoicRepairInvalidBetweenWraps() {
118
118
  host.setAttribute('role', 'listitem');
119
119
  host.style.listStyle = 'none';
120
120
  host.style.width = '100%';
121
- try { var ak = ezoicAnchorKeyFromNode(target); if (ak) host.setAttribute('data-ezoic-anchor', ak); } catch(e) {}
121
+ try { var prevLi = wrap.previousElementSibling; var ak2 = ezoicAnchorKeyFromTarget(prevLi || wrap); if (ak2) host.setAttribute('data-ezoic-anchor', ak2); } catch(e) {}
122
122
  p.insertBefore(host, wrap);
123
123
  host.appendChild(wrap);
124
124
  try { wrap.style.width = '100%'; } catch (e) {}
@@ -1650,9 +1650,10 @@ if (window.jQuery) {
1650
1650
  // ===== /V12.2 =====
1651
1651
 
1652
1652
 
1653
- // ===== V12.4 reconcile+purge scheduler =====
1653
+
1654
+ // ===== V12.5 topic-anchor reconcile =====
1654
1655
  (function(){
1655
- var pending=false, last=0, COOLDOWN=160;
1656
+ var pending=false, last=0, COOLDOWN=140;
1656
1657
  function schedule(scope){
1657
1658
  var now=Date.now();
1658
1659
  if (now-last<COOLDOWN) return;
@@ -1660,7 +1661,7 @@ if (window.jQuery) {
1660
1661
  pending=true;
1661
1662
  requestAnimationFrame(function(){
1662
1663
  pending=false; last=Date.now();
1663
- try { ezoicReconcileOrPurgeHosts(scope); } catch(e) {}
1664
+ try { ezoicReconcileOrPurgeByTopic(scope); } catch(e) {}
1664
1665
  });
1665
1666
  }
1666
1667
 
@@ -1675,7 +1676,6 @@ if (window.jQuery) {
1675
1676
  });
1676
1677
  }
1677
1678
 
1678
- // Observe only the main list containers if present to reduce overhead
1679
1679
  try {
1680
1680
  if (typeof MutationObserver !== 'undefined') {
1681
1681
  var mo = new MutationObserver(function(muts){
@@ -1687,12 +1687,13 @@ if (window.jQuery) {
1687
1687
  }
1688
1688
  }
1689
1689
  });
1690
- document.querySelectorAll('ul[component], ul.topic-list, ul.categories, ol[component]').forEach(function(list){
1691
- try { mo.observe(list, {childList:true}); } catch(e) {}
1690
+ document.querySelectorAll('ul,ol').forEach(function(list){
1691
+ try { mo.observe(list, {childList:true, subtree:false}); } catch(e) {}
1692
1692
  });
1693
1693
  }
1694
1694
  } catch(e){}
1695
1695
 
1696
1696
  setTimeout(function(){ schedule(document); }, 0);
1697
1697
  })();
1698
- // ===== /V12.4 =====
1698
+ // ===== /V12.5 =====
1699
+