nodebb-plugin-ezoic-infinite 1.6.14 → 1.6.16
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 +96 -181
- package/public/style.css +7 -4
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1,133 +1,6 @@
|
|
|
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.
|
|
6
|
-
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
|
-
}
|
|
21
|
-
} catch (e) {}
|
|
22
|
-
return '';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function ezoicFindAnchorLi(anchorKey, listEl) {
|
|
26
|
-
try {
|
|
27
|
-
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; }
|
|
40
|
-
}
|
|
41
|
-
|
|
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.
|
|
45
|
-
try {
|
|
46
|
-
var root = scope || document;
|
|
47
|
-
var hosts = root.querySelectorAll('li.nodebb-ezoic-host[data-ezoic-anchor]');
|
|
48
|
-
if (!hosts || !hosts.length) return;
|
|
49
|
-
|
|
50
|
-
hosts.forEach(function(host){
|
|
51
|
-
try {
|
|
52
|
-
var listEl = host.parentElement;
|
|
53
|
-
if (!listEl) return;
|
|
54
|
-
var anchorKey = host.getAttribute('data-ezoic-anchor') || '';
|
|
55
|
-
if (!anchorKey) return;
|
|
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
|
-
}
|
|
63
|
-
if (host.previousElementSibling !== anchorLi) {
|
|
64
|
-
anchorLi.insertAdjacentElement('afterend', host);
|
|
65
|
-
}
|
|
66
|
-
} catch (e) {}
|
|
67
|
-
});
|
|
68
|
-
} catch (e) {}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
function ezoicInsertAfterWithUlGuard(target, wrap, kindClass) {
|
|
73
|
-
try {
|
|
74
|
-
if (!target || !wrap) return;
|
|
75
|
-
// Only guard for BETWEEN placements (known to be inserted between <li> items inside <ul>/<ol>)
|
|
76
|
-
if (kindClass === 'ezoic-ad-between') {
|
|
77
|
-
var p = target.parentElement;
|
|
78
|
-
if (p && (p.tagName === 'UL' || p.tagName === 'OL')) {
|
|
79
|
-
// Ensure wrap is not a direct child of UL/OL (invalid HTML); wrap it in an LI host.
|
|
80
|
-
var host = document.createElement('li');
|
|
81
|
-
host.className = 'nodebb-ezoic-host';
|
|
82
|
-
host.setAttribute('role', 'listitem');
|
|
83
|
-
host.style.listStyle = 'none';
|
|
84
|
-
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) {}
|
|
87
|
-
|
|
88
|
-
// Insert host after the target listitem, then move the wrap inside.
|
|
89
|
-
if (target.insertAdjacentElement) {
|
|
90
|
-
target.insertAdjacentElement('afterend', host);
|
|
91
|
-
} else if (p.insertBefore) {
|
|
92
|
-
p.insertBefore(host, target.nextSibling);
|
|
93
|
-
}
|
|
94
|
-
try { host.appendChild(wrap); } catch (e) {}
|
|
95
|
-
|
|
96
|
-
// Keep wrap full width
|
|
97
|
-
try { wrap.style.width = '100%'; } catch (e) {}
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Default behavior
|
|
103
|
-
if (target.insertAdjacentElement) ezoicInsertAfterWithUlGuard(target, wrap, kindClass);
|
|
104
|
-
else if (target.parentNode) target.parentNode.insertBefore(wrap, target.nextSibling);
|
|
105
|
-
} catch (e) {}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function ezoicRepairInvalidBetweenWraps() {
|
|
109
|
-
// If any legacy DIV wraps were already inserted directly under UL/OL, repair them once.
|
|
110
|
-
try {
|
|
111
|
-
var bad = document.querySelectorAll('ul > div.nodebb-ezoic-wrap.ezoic-ad-between, ol > div.nodebb-ezoic-wrap.ezoic-ad-between');
|
|
112
|
-
bad.forEach(function (wrap) {
|
|
113
|
-
try {
|
|
114
|
-
var p = wrap.parentElement;
|
|
115
|
-
if (!p) return;
|
|
116
|
-
var host = document.createElement('li');
|
|
117
|
-
host.className = 'nodebb-ezoic-host';
|
|
118
|
-
host.setAttribute('role', 'listitem');
|
|
119
|
-
host.style.listStyle = 'none';
|
|
120
|
-
host.style.width = '100%';
|
|
121
|
-
try { var ak = ezoicAnchorKeyFromNode(target); if (ak) host.setAttribute('data-ezoic-anchor', ak); } catch(e) {}
|
|
122
|
-
p.insertBefore(host, wrap);
|
|
123
|
-
host.appendChild(wrap);
|
|
124
|
-
try { wrap.style.width = '100%'; } catch (e) {}
|
|
125
|
-
} catch (e) {}
|
|
126
|
-
});
|
|
127
|
-
} catch (e) {}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
4
|
// Track scroll direction to avoid aggressive recycling when the user scrolls upward.
|
|
132
5
|
// Recycling while scrolling up is a common cause of ads "bunching" and a "disappearing too fast" feeling.
|
|
133
6
|
let lastScrollY = 0;
|
|
@@ -795,7 +668,7 @@ function globalGapFixInit() {
|
|
|
795
668
|
insertingIds.add(id);
|
|
796
669
|
try {
|
|
797
670
|
const wrap = buildWrap(id, kindClass, afterPos, !existingPh);
|
|
798
|
-
|
|
671
|
+
target.insertAdjacentElement('afterend', wrap);
|
|
799
672
|
|
|
800
673
|
// If placeholder exists elsewhere (including pool), move it into the wrapper.
|
|
801
674
|
if (existingPh) {
|
|
@@ -1287,7 +1160,7 @@ function buildOrdinalMap(items) {
|
|
|
1287
1160
|
if (!anchorEl || !wrap || !wrap.isConnected) return null;
|
|
1288
1161
|
|
|
1289
1162
|
wrap.setAttribute('data-ezoic-after', String(afterPos));
|
|
1290
|
-
|
|
1163
|
+
anchorEl.insertAdjacentElement('afterend', wrap);
|
|
1291
1164
|
|
|
1292
1165
|
// Ensure minimal layout impact.
|
|
1293
1166
|
try { wrap.style.contain = 'layout style paint'; } catch (e) {}
|
|
@@ -1637,62 +1510,104 @@ function buildOrdinalMap(items) {
|
|
|
1637
1510
|
})();
|
|
1638
1511
|
|
|
1639
1512
|
|
|
1640
|
-
// ===== V12.2: run UL/OL repair =====
|
|
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
|
-
// ===== V12.4 reconcile+purge scheduler =====
|
|
1654
|
-
(function(){
|
|
1655
|
-
var pending=false, last=0, COOLDOWN=160;
|
|
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; last=Date.now();
|
|
1663
|
-
try { ezoicReconcileOrPurgeHosts(scope); } catch(e) {}
|
|
1664
|
-
});
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
window.addEventListener('scroll', function(){ schedule(document); }, { passive:true });
|
|
1668
|
-
window.addEventListener('resize', function(){ schedule(document); }, { passive:true });
|
|
1669
1513
|
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
setTimeout(function(){ schedule(document); }, 700);
|
|
1675
|
-
});
|
|
1676
|
-
}
|
|
1514
|
+
// ===== V13 sticky-killer for Ezoic/AMP in list ads =====
|
|
1515
|
+
(function () {
|
|
1516
|
+
// Hypothesis: the "pile at top" is a visual effect from multiple sticky intradiv ads
|
|
1517
|
+
// (ezads-sticky-intradiv with inline !important). We neutralize sticky continuously.
|
|
1677
1518
|
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
var
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1519
|
+
function killStickyIn(root) {
|
|
1520
|
+
try {
|
|
1521
|
+
var scope = root || document;
|
|
1522
|
+
var nodes = scope.querySelectorAll('.nodebb-ezoic-wrap .ezads-sticky-intradiv, .nodebb-ezoic-wrap [style*="position: sticky"], .nodebb-ezoic-wrap [style*="position:sticky"]');
|
|
1523
|
+
nodes.forEach(function(n){
|
|
1524
|
+
try {
|
|
1525
|
+
n.style.setProperty('position', 'static', 'important');
|
|
1526
|
+
n.style.setProperty('top', 'auto', 'important');
|
|
1527
|
+
n.style.setProperty('bottom', 'auto', 'important');
|
|
1528
|
+
n.style.setProperty('left', 'auto', 'important');
|
|
1529
|
+
n.style.setProperty('right', 'auto', 'important');
|
|
1530
|
+
// if they force translate/transform for sticky, remove it
|
|
1531
|
+
n.style.setProperty('transform', 'none', 'important');
|
|
1532
|
+
n.style.setProperty('will-change', 'auto', 'important');
|
|
1533
|
+
// also remove class to reduce re-application
|
|
1534
|
+
if (n.classList) n.classList.remove('ezads-sticky-intradiv');
|
|
1535
|
+
} catch (e) {}
|
|
1536
|
+
// If inline style string contains "sticky", scrub it (some libs reparse cssText)
|
|
1537
|
+
try {
|
|
1538
|
+
var st = n.getAttribute && n.getAttribute('style');
|
|
1539
|
+
if (st && (st.indexOf('sticky') !== -1)) {
|
|
1540
|
+
var cleaned = st.replace(/position\s*:\s*sticky\s*!important\s*;?/gi, 'position: static !important;')
|
|
1541
|
+
.replace(/position\s*:\s*sticky\s*;?/gi, 'position: static;')
|
|
1542
|
+
.replace(/top\s*:\s*0px\s*!important\s*;?/gi, 'top: auto !important;')
|
|
1543
|
+
.replace(/top\s*:\s*0px\s*;?/gi, 'top: auto;');
|
|
1544
|
+
n.setAttribute('style', cleaned);
|
|
1687
1545
|
}
|
|
1688
|
-
}
|
|
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) {}
|
|
1546
|
+
} catch (e) {}
|
|
1692
1547
|
});
|
|
1548
|
+
} catch (e) {}
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
function install() {
|
|
1552
|
+
// initial pass
|
|
1553
|
+
killStickyIn(document);
|
|
1554
|
+
|
|
1555
|
+
// Throttled scroll pass (in case scripts reapply on scroll)
|
|
1556
|
+
var t = null;
|
|
1557
|
+
window.addEventListener('scroll', function(){
|
|
1558
|
+
if (t) return;
|
|
1559
|
+
t = setTimeout(function(){ t = null; killStickyIn(document); }, 120);
|
|
1560
|
+
}, { passive: true });
|
|
1561
|
+
|
|
1562
|
+
// MutationObserver to catch late injections / style changes
|
|
1563
|
+
try {
|
|
1564
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
1565
|
+
var mo = new MutationObserver(function(muts){
|
|
1566
|
+
try {
|
|
1567
|
+
for (var i=0;i<muts.length;i++){
|
|
1568
|
+
var m = muts[i];
|
|
1569
|
+
if (m.type === 'attributes') {
|
|
1570
|
+
// style/class changed
|
|
1571
|
+
if (m.attributeName === 'style' || m.attributeName === 'class') {
|
|
1572
|
+
killStickyIn(m.target && m.target.closest ? (m.target.closest('.nodebb-ezoic-wrap') || document) : document);
|
|
1573
|
+
}
|
|
1574
|
+
} else if (m.addedNodes && m.addedNodes.length) {
|
|
1575
|
+
for (var j=0;j<m.addedNodes.length;j++){
|
|
1576
|
+
var n = m.addedNodes[j];
|
|
1577
|
+
if (!n || n.nodeType !== 1) continue;
|
|
1578
|
+
if (n.matches && (n.matches('.nodebb-ezoic-wrap') || n.matches('.ezads-sticky-intradiv'))) {
|
|
1579
|
+
killStickyIn(n);
|
|
1580
|
+
} else if (n.querySelector) {
|
|
1581
|
+
if (n.querySelector('.nodebb-ezoic-wrap, .ezads-sticky-intradiv')) killStickyIn(n);
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
} catch (e) {}
|
|
1587
|
+
});
|
|
1588
|
+
mo.observe(document.documentElement || document.body, {
|
|
1589
|
+
subtree: true,
|
|
1590
|
+
childList: true,
|
|
1591
|
+
attributes: true,
|
|
1592
|
+
attributeFilter: ['style','class']
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
} catch (e) {}
|
|
1596
|
+
|
|
1597
|
+
// NodeBB events
|
|
1598
|
+
if (window.jQuery) {
|
|
1599
|
+
try {
|
|
1600
|
+
window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function(){
|
|
1601
|
+
setTimeout(function(){ killStickyIn(document); }, 0);
|
|
1602
|
+
setTimeout(function(){ killStickyIn(document); }, 250);
|
|
1603
|
+
setTimeout(function(){ killStickyIn(document); }, 900);
|
|
1604
|
+
});
|
|
1605
|
+
} catch (e) {}
|
|
1693
1606
|
}
|
|
1694
|
-
}
|
|
1607
|
+
}
|
|
1695
1608
|
|
|
1696
|
-
|
|
1609
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', install);
|
|
1610
|
+
else install();
|
|
1697
1611
|
})();
|
|
1698
|
-
// ===== /
|
|
1612
|
+
// ===== /V13 =====
|
|
1613
|
+
|
package/public/style.css
CHANGED
|
@@ -81,8 +81,11 @@
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
/* =====
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
/* ===== V13 sticky-killer CSS fallback ===== */
|
|
85
|
+
.nodebb-ezoic-wrap .ezads-sticky-intradiv {
|
|
86
|
+
position: static !important;
|
|
87
|
+
top: auto !important;
|
|
88
|
+
transform: none !important;
|
|
89
|
+
}
|
|
90
|
+
/* ===== /V13 ===== */
|
|
88
91
|
|