nodebb-plugin-ezoic-infinite 1.6.15 → 1.6.17
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 +1 -1
- package/public/client.js +80 -111
- package/public/style.css +2 -3
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1,127 +1,110 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
function
|
|
5
|
-
|
|
6
|
-
|
|
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];
|
|
16
|
-
} catch (e) {}
|
|
17
|
-
return '';
|
|
4
|
+
function ezoicAnchorToken() {
|
|
5
|
+
// cheap unique-ish token
|
|
6
|
+
try { return String(Date.now()) + '-' + Math.random().toString(16).slice(2); } catch (e) { return String(Date.now()); }
|
|
18
7
|
}
|
|
19
8
|
|
|
20
|
-
function
|
|
9
|
+
function ezoicInsertAfterWithToken(target, wrap, kindClass) {
|
|
21
10
|
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) {
|
|
33
|
-
try {
|
|
34
|
-
if (!anchorKey) 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;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function ezoicReconcileOrPurgeByTopic(scope) {
|
|
47
|
-
try {
|
|
48
|
-
var root = scope || document;
|
|
49
|
-
var hosts = root.querySelectorAll('li.nodebb-ezoic-host[data-ezoic-anchor]');
|
|
50
|
-
if (!hosts || !hosts.length) return;
|
|
51
|
-
|
|
52
|
-
hosts.forEach(function(host){
|
|
53
|
-
try {
|
|
54
|
-
var listEl = host.parentElement;
|
|
55
|
-
if (!listEl) return;
|
|
56
|
-
var key = host.getAttribute('data-ezoic-anchor') || '';
|
|
57
|
-
if (!key) return;
|
|
58
|
-
|
|
59
|
-
var anchorLi = ezoicFindAnchorLiByKey(key, listEl) || ezoicFindAnchorLiByKey(key, document);
|
|
60
|
-
if (!anchorLi) {
|
|
61
|
-
host.remove();
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
if (host.previousElementSibling !== anchorLi) {
|
|
65
|
-
anchorLi.insertAdjacentElement('afterend', host);
|
|
66
|
-
}
|
|
67
|
-
} catch (e) {}
|
|
68
|
-
});
|
|
69
|
-
} catch (e) {}
|
|
70
|
-
}
|
|
11
|
+
if (!target || !wrap) return;
|
|
71
12
|
|
|
13
|
+
// Tag the anchor LI (topic item) with a stable token the first time we attach a between ad to it.
|
|
14
|
+
// If NodeBB re-renders/virtualizes and recreates the LI, this tag disappears => we can drop orphan ads.
|
|
15
|
+
var anchorLi = null;
|
|
16
|
+
try { anchorLi = target.closest ? target.closest('li') : null; } catch (e) {}
|
|
17
|
+
if (!anchorLi && target.tagName === 'LI') anchorLi = target;
|
|
18
|
+
|
|
19
|
+
if (kindClass === 'ezoic-ad-between' && anchorLi) {
|
|
20
|
+
var token = anchorLi.getAttribute('data-ezoic-anchor-token');
|
|
21
|
+
if (!token) {
|
|
22
|
+
token = ezoicAnchorToken();
|
|
23
|
+
try { anchorLi.setAttribute('data-ezoic-anchor-token', token); } catch (e) {}
|
|
24
|
+
}
|
|
72
25
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (!target || !wrap) return;
|
|
76
|
-
// Only guard for BETWEEN placements (known to be inserted between <li> items inside <ul>/<ol>)
|
|
77
|
-
if (kindClass === 'ezoic-ad-between') {
|
|
78
|
-
var p = target.parentElement;
|
|
26
|
+
// If inside UL/OL, keep valid DOM with LI host, but keep wrap as DIV (compat).
|
|
27
|
+
var p = anchorLi.parentElement;
|
|
79
28
|
if (p && (p.tagName === 'UL' || p.tagName === 'OL')) {
|
|
80
|
-
// Ensure wrap is not a direct child of UL/OL (invalid HTML); wrap it in an LI host.
|
|
81
29
|
var host = document.createElement('li');
|
|
82
30
|
host.className = 'nodebb-ezoic-host';
|
|
83
31
|
host.setAttribute('role', 'listitem');
|
|
84
32
|
host.style.listStyle = 'none';
|
|
85
33
|
host.style.width = '100%';
|
|
86
|
-
try {
|
|
34
|
+
try { host.setAttribute('data-ezoic-anchor-token', token); } catch (e) {}
|
|
87
35
|
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
target.insertAdjacentElement('afterend', host);
|
|
91
|
-
} else if (p.insertBefore) {
|
|
92
|
-
p.insertBefore(host, target.nextSibling);
|
|
93
|
-
}
|
|
94
|
-
try { host.appendChild(wrap); } catch (e) {}
|
|
36
|
+
if (anchorLi.insertAdjacentElement) anchorLi.insertAdjacentElement('afterend', host);
|
|
37
|
+
else if (p.insertBefore) p.insertBefore(host, anchorLi.nextSibling);
|
|
95
38
|
|
|
96
|
-
|
|
39
|
+
try { host.appendChild(wrap); } catch (e) {}
|
|
97
40
|
try { wrap.style.width = '100%'; } catch (e) {}
|
|
98
41
|
return;
|
|
99
42
|
}
|
|
43
|
+
|
|
44
|
+
// Non-list parent: just insert sibling but still tag wrap so we can reconcile
|
|
45
|
+
try { wrap.setAttribute('data-ezoic-anchor-token', token); } catch (e) {}
|
|
100
46
|
}
|
|
101
47
|
|
|
102
|
-
|
|
103
|
-
if (target.insertAdjacentElement) ezoicInsertAfterWithUlGuard(target, wrap, kindClass);
|
|
48
|
+
if (target.insertAdjacentElement) ezoicInsertAfterWithToken(target, wrap, kindClass);
|
|
104
49
|
else if (target.parentNode) target.parentNode.insertBefore(wrap, target.nextSibling);
|
|
105
50
|
} catch (e) {}
|
|
106
51
|
}
|
|
107
52
|
|
|
108
|
-
function
|
|
109
|
-
//
|
|
53
|
+
function ezoicRepairBetweenWrapsToHost() {
|
|
54
|
+
// Repair any invalid UL children and ensure hosts/wraps carry token if possible.
|
|
110
55
|
try {
|
|
111
56
|
var bad = document.querySelectorAll('ul > div.nodebb-ezoic-wrap.ezoic-ad-between, ol > div.nodebb-ezoic-wrap.ezoic-ad-between');
|
|
112
57
|
bad.forEach(function (wrap) {
|
|
113
58
|
try {
|
|
114
|
-
var
|
|
115
|
-
if (!
|
|
59
|
+
var ul = wrap.parentElement;
|
|
60
|
+
if (!ul) return;
|
|
61
|
+
var prevLi = wrap.previousElementSibling && wrap.previousElementSibling.tagName === 'LI' ? wrap.previousElementSibling : null;
|
|
62
|
+
var token = prevLi ? prevLi.getAttribute('data-ezoic-anchor-token') : null;
|
|
63
|
+
if (!token && prevLi) {
|
|
64
|
+
token = ezoicAnchorToken();
|
|
65
|
+
prevLi.setAttribute('data-ezoic-anchor-token', token);
|
|
66
|
+
}
|
|
67
|
+
|
|
116
68
|
var host = document.createElement('li');
|
|
117
69
|
host.className = 'nodebb-ezoic-host';
|
|
118
70
|
host.setAttribute('role', 'listitem');
|
|
119
71
|
host.style.listStyle = 'none';
|
|
120
72
|
host.style.width = '100%';
|
|
121
|
-
|
|
122
|
-
|
|
73
|
+
if (token) host.setAttribute('data-ezoic-anchor-token', token);
|
|
74
|
+
|
|
75
|
+
ul.insertBefore(host, wrap);
|
|
123
76
|
host.appendChild(wrap);
|
|
124
|
-
|
|
77
|
+
wrap.style.width = '100%';
|
|
78
|
+
} catch (e) {}
|
|
79
|
+
});
|
|
80
|
+
} catch (e) {}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function ezoicReconcileOrDropHostsByToken(scope) {
|
|
84
|
+
// Core fix: if NodeBB virtualizes and anchors disappear, DROP hosts so they can't pile up at top.
|
|
85
|
+
// If anchor exists, ensure host sits right after it.
|
|
86
|
+
try {
|
|
87
|
+
var root = scope || document;
|
|
88
|
+
var hosts = root.querySelectorAll('li.nodebb-ezoic-host[data-ezoic-anchor-token]');
|
|
89
|
+
if (!hosts || !hosts.length) return;
|
|
90
|
+
|
|
91
|
+
hosts.forEach(function(host){
|
|
92
|
+
try {
|
|
93
|
+
var token = host.getAttribute('data-ezoic-anchor-token');
|
|
94
|
+
if (!token) return;
|
|
95
|
+
var listEl = host.parentElement;
|
|
96
|
+
if (!listEl) return;
|
|
97
|
+
|
|
98
|
+
// Find the exact anchor LI that still carries the token.
|
|
99
|
+
var anchor = listEl.querySelector('li[data-ezoic-anchor-token="' + token + '"]');
|
|
100
|
+
if (!anchor) {
|
|
101
|
+
// anchor not in DOM => virtualized/re-rendered: remove host to avoid stacking
|
|
102
|
+
host.remove();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (host.previousElementSibling !== anchor) {
|
|
106
|
+
anchor.insertAdjacentElement('afterend', host);
|
|
107
|
+
}
|
|
125
108
|
} catch (e) {}
|
|
126
109
|
});
|
|
127
110
|
} catch (e) {}
|
|
@@ -795,7 +778,7 @@ function globalGapFixInit() {
|
|
|
795
778
|
insertingIds.add(id);
|
|
796
779
|
try {
|
|
797
780
|
const wrap = buildWrap(id, kindClass, afterPos, !existingPh);
|
|
798
|
-
|
|
781
|
+
ezoicInsertAfterWithToken(target, wrap, kindClass);
|
|
799
782
|
|
|
800
783
|
// If placeholder exists elsewhere (including pool), move it into the wrapper.
|
|
801
784
|
if (existingPh) {
|
|
@@ -1287,7 +1270,7 @@ function buildOrdinalMap(items) {
|
|
|
1287
1270
|
if (!anchorEl || !wrap || !wrap.isConnected) return null;
|
|
1288
1271
|
|
|
1289
1272
|
wrap.setAttribute('data-ezoic-after', String(afterPos));
|
|
1290
|
-
|
|
1273
|
+
ezoicInsertAfterWithToken(anchorEl, wrap, kindClass);
|
|
1291
1274
|
|
|
1292
1275
|
// Ensure minimal layout impact.
|
|
1293
1276
|
try { wrap.style.contain = 'layout style paint'; } catch (e) {}
|
|
@@ -1637,21 +1620,7 @@ function buildOrdinalMap(items) {
|
|
|
1637
1620
|
})();
|
|
1638
1621
|
|
|
1639
1622
|
|
|
1640
|
-
// =====
|
|
1641
|
-
try { ezoicRepairInvalidBetweenWraps(); } catch (e) {}
|
|
1642
|
-
if (window.jQuery) {
|
|
1643
|
-
try {
|
|
1644
|
-
window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function () {
|
|
1645
|
-
setTimeout(function(){ try { ezoicRepairInvalidBetweenWraps(); } catch(e) {} }, 0);
|
|
1646
|
-
setTimeout(function(){ try { ezoicRepairInvalidBetweenWraps(); } catch(e) {} }, 200);
|
|
1647
|
-
});
|
|
1648
|
-
} catch (e) {}
|
|
1649
|
-
}
|
|
1650
|
-
// ===== /V12.2 =====
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
// ===== V12.5 topic-anchor reconcile =====
|
|
1623
|
+
// ===== V14 token reconcile scheduler =====
|
|
1655
1624
|
(function(){
|
|
1656
1625
|
var pending=false, last=0, COOLDOWN=140;
|
|
1657
1626
|
function schedule(scope){
|
|
@@ -1661,7 +1630,8 @@ if (window.jQuery) {
|
|
|
1661
1630
|
pending=true;
|
|
1662
1631
|
requestAnimationFrame(function(){
|
|
1663
1632
|
pending=false; last=Date.now();
|
|
1664
|
-
try {
|
|
1633
|
+
try { ezoicRepairBetweenWrapsToHost(); } catch(e) {}
|
|
1634
|
+
try { ezoicReconcileOrDropHostsByToken(scope); } catch(e) {}
|
|
1665
1635
|
});
|
|
1666
1636
|
}
|
|
1667
1637
|
|
|
@@ -1672,7 +1642,7 @@ if (window.jQuery) {
|
|
|
1672
1642
|
window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function(){
|
|
1673
1643
|
setTimeout(function(){ schedule(document); }, 0);
|
|
1674
1644
|
setTimeout(function(){ schedule(document); }, 220);
|
|
1675
|
-
setTimeout(function(){ schedule(document); },
|
|
1645
|
+
setTimeout(function(){ schedule(document); }, 800);
|
|
1676
1646
|
});
|
|
1677
1647
|
}
|
|
1678
1648
|
|
|
@@ -1688,12 +1658,11 @@ if (window.jQuery) {
|
|
|
1688
1658
|
}
|
|
1689
1659
|
});
|
|
1690
1660
|
document.querySelectorAll('ul,ol').forEach(function(list){
|
|
1691
|
-
try { mo.observe(list, {childList:true
|
|
1661
|
+
try { mo.observe(list, {childList:true}); } catch(e) {}
|
|
1692
1662
|
});
|
|
1693
1663
|
}
|
|
1694
1664
|
} catch(e){}
|
|
1695
1665
|
|
|
1696
1666
|
setTimeout(function(){ schedule(document); }, 0);
|
|
1697
1667
|
})();
|
|
1698
|
-
// ===== /
|
|
1699
|
-
|
|
1668
|
+
// ===== /V14 =====
|
package/public/style.css
CHANGED
|
@@ -81,8 +81,7 @@
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
/* =====
|
|
84
|
+
/* ===== V14 token host styles ===== */
|
|
85
85
|
li.nodebb-ezoic-host { list-style: none; width: 100%; }
|
|
86
|
-
|
|
87
|
-
/* ===== /V12.2 ===== */
|
|
86
|
+
/* ===== /V14 ===== */
|
|
88
87
|
|