nodebb-plugin-ezoic-infinite 1.6.34 → 1.6.35
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 +168 -135
- package/public/style.css +4 -6
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1514,189 +1514,222 @@ function buildOrdinalMap(items) {
|
|
|
1514
1514
|
|
|
1515
1515
|
|
|
1516
1516
|
|
|
1517
|
-
// =====
|
|
1518
|
-
(function(){
|
|
1517
|
+
// ===== V18: Always host between DIVs in <li> + anchor by topic tid (MutationObserver, no scroll hooks to injection) =====
|
|
1518
|
+
(function () {
|
|
1519
1519
|
var TOPIC_LI_SEL = 'li[component="category/topic"]';
|
|
1520
1520
|
var BETWEEN_WRAP_SEL = 'div.nodebb-ezoic-wrap.ezoic-ad-between';
|
|
1521
1521
|
var HOST_CLASS = 'nodebb-ezoic-host';
|
|
1522
|
-
var
|
|
1523
|
-
|
|
1524
|
-
var lastY = window.pageYOffset || document.documentElement.scrollTop || 0;
|
|
1525
|
-
var scheduled = false;
|
|
1526
|
-
var lastRun = 0;
|
|
1527
|
-
var COOLDOWN = 120;
|
|
1522
|
+
var ANCHOR_ATTR = 'data-ezoic-anchor-tid';
|
|
1528
1523
|
|
|
1529
|
-
|
|
1524
|
+
var pending = false;
|
|
1525
|
+
var queue = new Set();
|
|
1530
1526
|
|
|
1531
|
-
function getTopicList(){
|
|
1527
|
+
function getTopicList() {
|
|
1532
1528
|
try {
|
|
1533
1529
|
var li = document.querySelector(TOPIC_LI_SEL);
|
|
1534
1530
|
if (!li) return null;
|
|
1535
1531
|
return li.closest ? li.closest('ul,ol') : null;
|
|
1536
|
-
} catch(e){ return null; }
|
|
1532
|
+
} catch (e) { return null; }
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
function extractTidFromTopicLi(li) {
|
|
1536
|
+
// Parse tid from a topic link (/topic/{tid}/...)
|
|
1537
|
+
try {
|
|
1538
|
+
if (!li || !li.querySelector) return null;
|
|
1539
|
+
var a = li.querySelector('a[href^="/topic/"], a[href*="/topic/"]');
|
|
1540
|
+
if (!a) return null;
|
|
1541
|
+
var href = a.getAttribute('href') || '';
|
|
1542
|
+
var m = href.match(/\/topic\/(\d+)\b/);
|
|
1543
|
+
return m ? m[1] : null;
|
|
1544
|
+
} catch (e) { return null; }
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
function buildTidMap(ul) {
|
|
1548
|
+
var map = Object.create(null);
|
|
1549
|
+
try {
|
|
1550
|
+
var topics = ul.querySelectorAll(TOPIC_LI_SEL);
|
|
1551
|
+
for (var i = 0; i < topics.length; i++) {
|
|
1552
|
+
var tid = extractTidFromTopicLi(topics[i]);
|
|
1553
|
+
if (tid && !map[tid]) map[tid] = topics[i];
|
|
1554
|
+
}
|
|
1555
|
+
} catch (e) {}
|
|
1556
|
+
return map;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
function previousTopicLi(node) {
|
|
1560
|
+
try {
|
|
1561
|
+
var prev = node.previousElementSibling;
|
|
1562
|
+
while (prev) {
|
|
1563
|
+
if (prev.matches && prev.matches(TOPIC_LI_SEL)) return prev;
|
|
1564
|
+
prev = prev.previousElementSibling;
|
|
1565
|
+
}
|
|
1566
|
+
} catch (e) {}
|
|
1567
|
+
return null;
|
|
1537
1568
|
}
|
|
1538
1569
|
|
|
1539
|
-
function ensureHostForWrap(wrap, ul){
|
|
1540
|
-
|
|
1541
|
-
|
|
1570
|
+
function ensureHostForWrap(wrap, ul) {
|
|
1571
|
+
// Always ensure UL children are LI, to avoid NodeBB reparenting DIVs (root cause of pile-up).
|
|
1572
|
+
try {
|
|
1573
|
+
if (!wrap || wrap.nodeType !== 1) return null;
|
|
1542
1574
|
if (!(wrap.matches && wrap.matches(BETWEEN_WRAP_SEL))) return null;
|
|
1543
1575
|
|
|
1544
|
-
var host = wrap.closest ? wrap.closest('li.'+HOST_CLASS) : null;
|
|
1576
|
+
var host = wrap.closest ? wrap.closest('li.' + HOST_CLASS) : null;
|
|
1545
1577
|
if (host) return host;
|
|
1546
1578
|
|
|
1547
|
-
|
|
1548
|
-
if (!ul || !(ul.tagName==='UL' || ul.tagName==='OL')) return null;
|
|
1579
|
+
ul = ul || (wrap.closest ? wrap.closest('ul,ol') : null);
|
|
1580
|
+
if (!ul || !(ul.tagName === 'UL' || ul.tagName === 'OL')) return null;
|
|
1549
1581
|
|
|
1550
|
-
|
|
1582
|
+
// Only wrap if it's a direct child of the list
|
|
1583
|
+
if (wrap.parentElement === ul) {
|
|
1551
1584
|
host = document.createElement('li');
|
|
1552
1585
|
host.className = HOST_CLASS;
|
|
1553
|
-
host.setAttribute('role','listitem');
|
|
1554
|
-
host.style.listStyle='none';
|
|
1555
|
-
host.style.width='100%';
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1586
|
+
host.setAttribute('role', 'listitem');
|
|
1587
|
+
host.style.listStyle = 'none';
|
|
1588
|
+
host.style.width = '100%';
|
|
1589
|
+
|
|
1590
|
+
// anchor tid from previous topic
|
|
1591
|
+
var anchor = previousTopicLi(wrap) || wrap.previousElementSibling;
|
|
1592
|
+
if (anchor && anchor.matches && anchor.matches(TOPIC_LI_SEL)) {
|
|
1593
|
+
var tid = extractTidFromTopicLi(anchor);
|
|
1594
|
+
if (tid) host.setAttribute(ANCHOR_ATTR, tid);
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1561
1597
|
ul.insertBefore(host, wrap);
|
|
1562
1598
|
host.appendChild(wrap);
|
|
1563
|
-
try { wrap.style.width='100%'; } catch(e){}
|
|
1599
|
+
try { wrap.style.width = '100%'; } catch (e) {}
|
|
1564
1600
|
return host;
|
|
1565
1601
|
}
|
|
1566
|
-
}catch(e){}
|
|
1602
|
+
} catch (e) {}
|
|
1567
1603
|
return null;
|
|
1568
1604
|
}
|
|
1569
1605
|
|
|
1570
|
-
function
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1606
|
+
function ensureAnchorTid(host) {
|
|
1607
|
+
try {
|
|
1608
|
+
if (!host || host.nodeType !== 1) return;
|
|
1609
|
+
if (host.getAttribute(ANCHOR_ATTR)) return;
|
|
1610
|
+
var anchor = previousTopicLi(host);
|
|
1611
|
+
if (!anchor) return;
|
|
1612
|
+
var tid = extractTidFromTopicLi(anchor);
|
|
1613
|
+
if (tid) host.setAttribute(ANCHOR_ATTR, tid);
|
|
1614
|
+
} catch (e) {}
|
|
1575
1615
|
}
|
|
1576
1616
|
|
|
1577
|
-
function
|
|
1578
|
-
try{
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
if (
|
|
1582
|
-
if (n>topics.length) n=topics.length;
|
|
1583
|
-
return topics[n-1] || null;
|
|
1584
|
-
}catch(e){ return null; }
|
|
1585
|
-
}
|
|
1617
|
+
function reconcileHost(host, ul, tidMap) {
|
|
1618
|
+
try {
|
|
1619
|
+
if (!host || host.nodeType !== 1 || !host.isConnected) return;
|
|
1620
|
+
ul = ul || host.parentElement;
|
|
1621
|
+
if (!ul) return;
|
|
1586
1622
|
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
var v = host.getAttribute('data-ezoic-after');
|
|
1590
|
-
if (!v){
|
|
1591
|
-
var wrap = host.querySelector && host.querySelector(BETWEEN_WRAP_SEL);
|
|
1592
|
-
if (wrap) v = wrap.getAttribute('data-ezoic-after');
|
|
1593
|
-
}
|
|
1594
|
-
var n = parseInt(v,10);
|
|
1595
|
-
return isNaN(n)? null : n;
|
|
1596
|
-
}catch(e){ return null; }
|
|
1597
|
-
}
|
|
1623
|
+
// if host got detached from list, skip
|
|
1624
|
+
if (!(ul.tagName === 'UL' || ul.tagName === 'OL')) return;
|
|
1598
1625
|
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
var
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
if (isBetweenHost){
|
|
1610
|
-
run++;
|
|
1611
|
-
if (run>=2){
|
|
1612
|
-
// mark piled beyond the first
|
|
1613
|
-
el.setAttribute(PILED_ATTR,'1');
|
|
1614
|
-
}
|
|
1615
|
-
} else if (isTopic){
|
|
1616
|
-
run=0;
|
|
1617
|
-
} else {
|
|
1618
|
-
// reset on any non-topic
|
|
1619
|
-
}
|
|
1626
|
+
ensureAnchorTid(host);
|
|
1627
|
+
|
|
1628
|
+
var tid = host.getAttribute(ANCHOR_ATTR);
|
|
1629
|
+
if (!tid) return;
|
|
1630
|
+
|
|
1631
|
+
var anchorLi = tidMap[tid];
|
|
1632
|
+
if (!anchorLi || !anchorLi.isConnected) return;
|
|
1633
|
+
|
|
1634
|
+
if (host.previousElementSibling !== anchorLi) {
|
|
1635
|
+
anchorLi.insertAdjacentElement('afterend', host);
|
|
1620
1636
|
}
|
|
1621
|
-
}catch(e){}
|
|
1637
|
+
} catch (e) {}
|
|
1622
1638
|
}
|
|
1623
1639
|
|
|
1624
|
-
function
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
host.removeAttribute(PILED_ATTR);
|
|
1635
|
-
return;
|
|
1636
|
-
}
|
|
1637
|
-
var after = getAfter(host);
|
|
1638
|
-
var anchor = after!=null ? nthTopic(ul, after) : null;
|
|
1639
|
-
if (anchor){
|
|
1640
|
-
anchor.insertAdjacentElement('afterend', host);
|
|
1641
|
-
}
|
|
1642
|
-
host.removeAttribute(PILED_ATTR);
|
|
1643
|
-
}catch(e){}
|
|
1640
|
+
function drain() {
|
|
1641
|
+
pending = false;
|
|
1642
|
+
var ul = getTopicList();
|
|
1643
|
+
if (!ul) return;
|
|
1644
|
+
|
|
1645
|
+
// First, host any direct-child between DIVs currently in list (cheap, keeps DOM valid).
|
|
1646
|
+
try {
|
|
1647
|
+
ul.querySelectorAll(':scope > ' + BETWEEN_WRAP_SEL).forEach(function (w) {
|
|
1648
|
+
var h = ensureHostForWrap(w, ul);
|
|
1649
|
+
if (h) queue.add(h);
|
|
1644
1650
|
});
|
|
1645
|
-
}catch(e){}
|
|
1651
|
+
} catch (e) {}
|
|
1652
|
+
|
|
1653
|
+
var tidMap = buildTidMap(ul);
|
|
1654
|
+
|
|
1655
|
+
// Process a limited batch per frame
|
|
1656
|
+
var processed = 0;
|
|
1657
|
+
for (var host of Array.from(queue)) {
|
|
1658
|
+
queue.delete(host);
|
|
1659
|
+
reconcileHost(host, ul, tidMap);
|
|
1660
|
+
processed++;
|
|
1661
|
+
if (processed >= 12) break;
|
|
1662
|
+
}
|
|
1663
|
+
if (queue.size) schedule();
|
|
1646
1664
|
}
|
|
1647
1665
|
|
|
1648
|
-
function schedule(
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1666
|
+
function schedule() {
|
|
1667
|
+
if (pending) return;
|
|
1668
|
+
pending = true;
|
|
1669
|
+
requestAnimationFrame(drain);
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
function enqueueNode(node, ul) {
|
|
1673
|
+
try {
|
|
1674
|
+
if (!node || node.nodeType !== 1) return;
|
|
1675
|
+
if (node.matches && node.matches(BETWEEN_WRAP_SEL)) {
|
|
1676
|
+
var h = ensureHostForWrap(node, ul);
|
|
1677
|
+
if (h) queue.add(h);
|
|
1678
|
+
} else if (node.tagName === 'LI' && node.classList && node.classList.contains(HOST_CLASS)) {
|
|
1679
|
+
queue.add(node);
|
|
1680
|
+
} else if (node.querySelectorAll) {
|
|
1681
|
+
// only check within added subtree, not whole doc
|
|
1682
|
+
node.querySelectorAll(':scope ' + BETWEEN_WRAP_SEL).forEach(function (w) {
|
|
1683
|
+
var h2 = ensureHostForWrap(w, ul);
|
|
1684
|
+
if (h2) queue.add(h2);
|
|
1685
|
+
});
|
|
1686
|
+
node.querySelectorAll(':scope li.' + HOST_CLASS).forEach(function (h3) { queue.add(h3); });
|
|
1687
|
+
}
|
|
1688
|
+
} catch (e) {}
|
|
1658
1689
|
}
|
|
1659
1690
|
|
|
1660
|
-
function
|
|
1661
|
-
var y = getY();
|
|
1662
|
-
var dy = y - lastY;
|
|
1663
|
-
lastY = y;
|
|
1691
|
+
function init() {
|
|
1664
1692
|
var ul = getTopicList();
|
|
1665
1693
|
if (!ul) return;
|
|
1666
1694
|
|
|
1667
|
-
//
|
|
1668
|
-
|
|
1695
|
+
// Initial pass: host all between DIVs and reconcile once.
|
|
1696
|
+
schedule();
|
|
1669
1697
|
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1698
|
+
// Observe only the topic list
|
|
1699
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
1700
|
+
var mo = new MutationObserver(function (muts) {
|
|
1701
|
+
try {
|
|
1702
|
+
var u = getTopicList();
|
|
1703
|
+
if (!u) return;
|
|
1704
|
+
|
|
1705
|
+
for (var i = 0; i < muts.length; i++) {
|
|
1706
|
+
var m = muts[i];
|
|
1707
|
+
if (m.addedNodes && m.addedNodes.length) {
|
|
1708
|
+
for (var j = 0; j < m.addedNodes.length; j++) {
|
|
1709
|
+
enqueueNode(m.addedNodes[j], u);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
if (queue.size) schedule();
|
|
1714
|
+
} catch (e) {}
|
|
1715
|
+
});
|
|
1716
|
+
try { mo.observe(ul, { childList: true, subtree: true }); } catch (e) {}
|
|
1676
1717
|
}
|
|
1677
|
-
}
|
|
1678
1718
|
|
|
1679
|
-
|
|
1680
|
-
window.
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
setTimeout(function(){
|
|
1687
|
-
try{
|
|
1688
|
-
var ul = getTopicList();
|
|
1689
|
-
if (!ul) return;
|
|
1690
|
-
ul.querySelectorAll(':scope > '+BETWEEN_WRAP_SEL).forEach(function(w){ ensureHostForWrap(w, ul); });
|
|
1691
|
-
}catch(e){}
|
|
1692
|
-
}, 50);
|
|
1719
|
+
// NodeBB events: run a settle pass after batches
|
|
1720
|
+
if (window.jQuery) {
|
|
1721
|
+
try {
|
|
1722
|
+
window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function () {
|
|
1723
|
+
// Let NodeBB append topics, then reconcile hosts by anchor tid.
|
|
1724
|
+
setTimeout(function(){ schedule(); }, 120);
|
|
1725
|
+
setTimeout(function(){ schedule(); }, 520);
|
|
1693
1726
|
});
|
|
1694
|
-
}catch(e){}
|
|
1727
|
+
} catch (e) {}
|
|
1695
1728
|
}
|
|
1696
1729
|
}
|
|
1697
1730
|
|
|
1698
1731
|
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
|
1699
1732
|
else init();
|
|
1700
1733
|
})();
|
|
1701
|
-
// ===== /
|
|
1734
|
+
// ===== /V18 =====
|
|
1702
1735
|
|
package/public/style.css
CHANGED
|
@@ -88,10 +88,8 @@ li.nodebb-ezoic-host > .nodebb-ezoic-wrap.ezoic-ad-between { width: 100%; displa
|
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
|
|
91
|
-
/* =====
|
|
92
|
-
li.nodebb-ezoic-host
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
li.nodebb-ezoic-host > .nodebb-ezoic-wrap.ezoic-ad-between { width:100%; display:block; }
|
|
96
|
-
/* ===== /V17.3 ===== */
|
|
91
|
+
/* ===== V18 hosts ===== */
|
|
92
|
+
li.nodebb-ezoic-host{ list-style:none; width:100%; display:block; }
|
|
93
|
+
li.nodebb-ezoic-host > .nodebb-ezoic-wrap.ezoic-ad-between{ width:100%; display:block; }
|
|
94
|
+
/* ===== /V18 ===== */
|
|
97
95
|
|