nodebb-plugin-ezoic-infinite 1.6.35 → 1.6.36
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 +198 -133
- package/public/style.css +4 -4
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1514,15 +1514,20 @@ function buildOrdinalMap(items) {
|
|
|
1514
1514
|
|
|
1515
1515
|
|
|
1516
1516
|
|
|
1517
|
-
// =====
|
|
1517
|
+
// ===== V17.7: Keep injection, anchor each between slot to topic TID and repair on DOM moves (minimal, targeted) =====
|
|
1518
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
1522
|
var ANCHOR_ATTR = 'data-ezoic-anchor-tid';
|
|
1523
1523
|
|
|
1524
|
+
var ul = null;
|
|
1525
|
+
var mo = null;
|
|
1526
|
+
|
|
1524
1527
|
var pending = false;
|
|
1525
1528
|
var queue = new Set();
|
|
1529
|
+
var lastFlush = 0;
|
|
1530
|
+
var FLUSH_COOLDOWN = 60;
|
|
1526
1531
|
|
|
1527
1532
|
function getTopicList() {
|
|
1528
1533
|
try {
|
|
@@ -1532,43 +1537,14 @@ function buildOrdinalMap(items) {
|
|
|
1532
1537
|
} catch (e) { return null; }
|
|
1533
1538
|
}
|
|
1534
1539
|
|
|
1535
|
-
function
|
|
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
|
-
}
|
|
1540
|
+
function ensureUL() { ul = ul || getTopicList(); return ul; }
|
|
1546
1541
|
|
|
1547
|
-
function
|
|
1548
|
-
|
|
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;
|
|
1542
|
+
function isHost(el) {
|
|
1543
|
+
return !!(el && el.nodeType === 1 && el.tagName === 'LI' && el.classList && el.classList.contains(HOST_CLASS));
|
|
1557
1544
|
}
|
|
1558
1545
|
|
|
1559
|
-
function
|
|
1560
|
-
|
|
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;
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
function ensureHostForWrap(wrap, ul) {
|
|
1571
|
-
// Always ensure UL children are LI, to avoid NodeBB reparenting DIVs (root cause of pile-up).
|
|
1546
|
+
function ensureHostForWrap(wrap, ulEl) {
|
|
1547
|
+
// Only wrap invalid ul>div cases (same idea as V17), no injection hook.
|
|
1572
1548
|
try {
|
|
1573
1549
|
if (!wrap || wrap.nodeType !== 1) return null;
|
|
1574
1550
|
if (!(wrap.matches && wrap.matches(BETWEEN_WRAP_SEL))) return null;
|
|
@@ -1576,25 +1552,20 @@ function buildOrdinalMap(items) {
|
|
|
1576
1552
|
var host = wrap.closest ? wrap.closest('li.' + HOST_CLASS) : null;
|
|
1577
1553
|
if (host) return host;
|
|
1578
1554
|
|
|
1579
|
-
|
|
1580
|
-
if (!
|
|
1555
|
+
ulEl = ulEl || (wrap.closest ? wrap.closest('ul,ol') : null);
|
|
1556
|
+
if (!ulEl || !(ulEl.tagName === 'UL' || ulEl.tagName === 'OL')) return null;
|
|
1581
1557
|
|
|
1582
|
-
|
|
1583
|
-
if (wrap.parentElement === ul) {
|
|
1558
|
+
if (wrap.parentElement === ulEl) {
|
|
1584
1559
|
host = document.createElement('li');
|
|
1585
1560
|
host.className = HOST_CLASS;
|
|
1586
1561
|
host.setAttribute('role', 'listitem');
|
|
1587
1562
|
host.style.listStyle = 'none';
|
|
1588
1563
|
host.style.width = '100%';
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
if (tid) host.setAttribute(ANCHOR_ATTR, tid);
|
|
1595
|
-
}
|
|
1596
|
-
|
|
1597
|
-
ul.insertBefore(host, wrap);
|
|
1564
|
+
try {
|
|
1565
|
+
var after = wrap.getAttribute('data-ezoic-after');
|
|
1566
|
+
if (after) host.setAttribute('data-ezoic-after', after);
|
|
1567
|
+
} catch (e) {}
|
|
1568
|
+
ulEl.insertBefore(host, wrap);
|
|
1598
1569
|
host.appendChild(wrap);
|
|
1599
1570
|
try { wrap.style.width = '100%'; } catch (e) {}
|
|
1600
1571
|
return host;
|
|
@@ -1603,133 +1574,227 @@ function buildOrdinalMap(items) {
|
|
|
1603
1574
|
return null;
|
|
1604
1575
|
}
|
|
1605
1576
|
|
|
1606
|
-
function
|
|
1577
|
+
function getTidFromTopicLi(li) {
|
|
1607
1578
|
try {
|
|
1608
|
-
if (!
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
var
|
|
1613
|
-
if (
|
|
1579
|
+
if (!li) return null;
|
|
1580
|
+
var tid = li.getAttribute('data-tid') || li.getAttribute('data-topic-id') || li.getAttribute('data-topicid') || li.getAttribute('data-id');
|
|
1581
|
+
if (tid && /^\\d+$/.test(tid)) return tid;
|
|
1582
|
+
|
|
1583
|
+
var a = li.querySelector && li.querySelector('a[href*="/topic/"]');
|
|
1584
|
+
if (a) {
|
|
1585
|
+
var href = a.getAttribute('href') || '';
|
|
1586
|
+
var m = href.match(/\\/topic\\/(\\d+)(\\/|$)/);
|
|
1587
|
+
if (m) return m[1];
|
|
1588
|
+
}
|
|
1614
1589
|
} catch (e) {}
|
|
1590
|
+
return null;
|
|
1615
1591
|
}
|
|
1616
1592
|
|
|
1617
|
-
function
|
|
1593
|
+
function closestPrevTopicLi(node) {
|
|
1618
1594
|
try {
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
if (
|
|
1595
|
+
var cur = node;
|
|
1596
|
+
if (!cur) return null;
|
|
1597
|
+
if (cur.closest) {
|
|
1598
|
+
var h = cur.closest('li.' + HOST_CLASS);
|
|
1599
|
+
if (h) cur = h;
|
|
1600
|
+
}
|
|
1601
|
+
var prev = cur.previousElementSibling;
|
|
1602
|
+
while (prev) {
|
|
1603
|
+
if (prev.matches && prev.matches(TOPIC_LI_SEL)) return prev;
|
|
1604
|
+
prev = prev.previousElementSibling;
|
|
1605
|
+
}
|
|
1606
|
+
} catch (e) {}
|
|
1607
|
+
return null;
|
|
1608
|
+
}
|
|
1622
1609
|
|
|
1623
|
-
|
|
1624
|
-
|
|
1610
|
+
function topicLiByTid(ulEl, tid) {
|
|
1611
|
+
try {
|
|
1612
|
+
if (!ulEl || !tid) return null;
|
|
1613
|
+
var q = ulEl.querySelector(
|
|
1614
|
+
TOPIC_LI_SEL + '[data-tid="' + tid + '"], ' +
|
|
1615
|
+
TOPIC_LI_SEL + '[data-topic-id="' + tid + '"], ' +
|
|
1616
|
+
TOPIC_LI_SEL + '[data-topicid="' + tid + '"]'
|
|
1617
|
+
);
|
|
1618
|
+
if (q) return q;
|
|
1619
|
+
|
|
1620
|
+
var topics = ulEl.querySelectorAll(TOPIC_LI_SEL);
|
|
1621
|
+
for (var i=0;i<topics.length;i++){
|
|
1622
|
+
var t = getTidFromTopicLi(topics[i]);
|
|
1623
|
+
if (t === tid) return topics[i];
|
|
1624
|
+
}
|
|
1625
|
+
} catch (e) {}
|
|
1626
|
+
return null;
|
|
1627
|
+
}
|
|
1625
1628
|
|
|
1626
|
-
|
|
1629
|
+
function rememberAnchor(el) {
|
|
1630
|
+
try {
|
|
1631
|
+
if (!el) return;
|
|
1632
|
+
|
|
1633
|
+
// normalize to host if wrap
|
|
1634
|
+
if (el.matches && el.matches(BETWEEN_WRAP_SEL)) {
|
|
1635
|
+
var h = el.closest ? el.closest('li.' + HOST_CLASS) : null;
|
|
1636
|
+
if (h) el = h;
|
|
1637
|
+
}
|
|
1638
|
+
if (!isHost(el) && !(el.matches && el.matches(BETWEEN_WRAP_SEL))) return;
|
|
1627
1639
|
|
|
1628
|
-
|
|
1640
|
+
if (el.getAttribute && el.getAttribute(ANCHOR_ATTR)) return;
|
|
1641
|
+
|
|
1642
|
+
var prevTopic = closestPrevTopicLi(el);
|
|
1643
|
+
if (!prevTopic) return;
|
|
1644
|
+
var tid = getTidFromTopicLi(prevTopic);
|
|
1629
1645
|
if (!tid) return;
|
|
1630
1646
|
|
|
1631
|
-
|
|
1632
|
-
|
|
1647
|
+
el.setAttribute(ANCHOR_ATTR, tid);
|
|
1648
|
+
} catch (e) {}
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
function repairOne(node, ulEl) {
|
|
1652
|
+
try {
|
|
1653
|
+
ulEl = ulEl || ensureUL();
|
|
1654
|
+
if (!ulEl) return;
|
|
1655
|
+
|
|
1656
|
+
var el = node;
|
|
1633
1657
|
|
|
1634
|
-
if (
|
|
1635
|
-
|
|
1658
|
+
if (el && el.nodeType === 1 && el.matches && el.matches(BETWEEN_WRAP_SEL)) {
|
|
1659
|
+
var host = ensureHostForWrap(el, ulEl) || (el.closest ? el.closest('li.' + HOST_CLASS) : null);
|
|
1660
|
+
if (host) el = host;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
if (isHost(el)) {
|
|
1664
|
+
rememberAnchor(el);
|
|
1665
|
+
var tid = el.getAttribute(ANCHOR_ATTR);
|
|
1666
|
+
if (!tid) return;
|
|
1667
|
+
var anchorTopic = topicLiByTid(ulEl, tid);
|
|
1668
|
+
if (!anchorTopic) return;
|
|
1669
|
+
if (el.previousElementSibling !== anchorTopic) {
|
|
1670
|
+
anchorTopic.insertAdjacentElement('afterend', el);
|
|
1671
|
+
}
|
|
1672
|
+
return;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
if (el && el.nodeType === 1 && el.matches && el.matches(BETWEEN_WRAP_SEL)) {
|
|
1676
|
+
rememberAnchor(el);
|
|
1677
|
+
var tid2 = el.getAttribute(ANCHOR_ATTR);
|
|
1678
|
+
if (!tid2) return;
|
|
1679
|
+
var anchor2 = topicLiByTid(ulEl, tid2);
|
|
1680
|
+
if (!anchor2) return;
|
|
1681
|
+
if (el.previousElementSibling !== anchor2) {
|
|
1682
|
+
anchor2.insertAdjacentElement('afterend', el);
|
|
1683
|
+
}
|
|
1636
1684
|
}
|
|
1637
1685
|
} catch (e) {}
|
|
1638
1686
|
}
|
|
1639
1687
|
|
|
1640
|
-
function
|
|
1688
|
+
function enqueue(node) {
|
|
1689
|
+
try {
|
|
1690
|
+
if (!node || node.nodeType !== 1) return;
|
|
1691
|
+
|
|
1692
|
+
if (isHost(node) || (node.matches && node.matches(BETWEEN_WRAP_SEL))) {
|
|
1693
|
+
queue.add(node);
|
|
1694
|
+
scheduleFlush();
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
if (node.querySelectorAll) {
|
|
1698
|
+
var wraps = node.querySelectorAll(BETWEEN_WRAP_SEL);
|
|
1699
|
+
if (wraps && wraps.length) wraps.forEach(function(w){ queue.add(w); });
|
|
1700
|
+
var hosts = node.querySelectorAll('li.' + HOST_CLASS);
|
|
1701
|
+
if (hosts && hosts.length) hosts.forEach(function(h){ queue.add(h); });
|
|
1702
|
+
if ((wraps && wraps.length) || (hosts && hosts.length)) scheduleFlush();
|
|
1703
|
+
}
|
|
1704
|
+
} catch (e) {}
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
function flush() {
|
|
1641
1708
|
pending = false;
|
|
1642
|
-
var
|
|
1643
|
-
if (!
|
|
1709
|
+
var ulEl = ensureUL();
|
|
1710
|
+
if (!ulEl) return;
|
|
1644
1711
|
|
|
1645
|
-
//
|
|
1712
|
+
// host invalid ul>div and capture anchors
|
|
1646
1713
|
try {
|
|
1647
|
-
|
|
1648
|
-
var
|
|
1649
|
-
if (
|
|
1714
|
+
ulEl.querySelectorAll(':scope > ' + BETWEEN_WRAP_SEL).forEach(function(w){
|
|
1715
|
+
var host = ensureHostForWrap(w, ulEl);
|
|
1716
|
+
if (host) queue.add(host);
|
|
1650
1717
|
});
|
|
1718
|
+
ulEl.querySelectorAll('li.' + HOST_CLASS).forEach(function(h){ rememberAnchor(h); });
|
|
1719
|
+
ulEl.querySelectorAll(BETWEEN_WRAP_SEL).forEach(function(w){ rememberAnchor(w); });
|
|
1651
1720
|
} catch (e) {}
|
|
1652
1721
|
|
|
1653
|
-
var
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
reconcileHost(host, ul, tidMap);
|
|
1660
|
-
processed++;
|
|
1661
|
-
if (processed >= 12) break;
|
|
1722
|
+
var n = 0;
|
|
1723
|
+
for (var item of Array.from(queue)) {
|
|
1724
|
+
queue.delete(item);
|
|
1725
|
+
repairOne(item, ulEl);
|
|
1726
|
+
n++;
|
|
1727
|
+
if (n >= 10) break;
|
|
1662
1728
|
}
|
|
1663
|
-
if (queue.size)
|
|
1729
|
+
if (queue.size) scheduleFlush();
|
|
1664
1730
|
}
|
|
1665
1731
|
|
|
1666
|
-
function
|
|
1732
|
+
function scheduleFlush() {
|
|
1733
|
+
var now = Date.now();
|
|
1667
1734
|
if (pending) return;
|
|
1735
|
+
if (now - lastFlush < FLUSH_COOLDOWN) return;
|
|
1668
1736
|
pending = true;
|
|
1669
|
-
|
|
1737
|
+
lastFlush = now;
|
|
1738
|
+
requestAnimationFrame(flush);
|
|
1670
1739
|
}
|
|
1671
1740
|
|
|
1672
|
-
function
|
|
1741
|
+
function initObserver() {
|
|
1742
|
+
var ulEl = ensureUL();
|
|
1743
|
+
if (!ulEl || mo) return;
|
|
1744
|
+
|
|
1745
|
+
// initial capture
|
|
1673
1746
|
try {
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
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
|
-
}
|
|
1747
|
+
ulEl.querySelectorAll(BETWEEN_WRAP_SEL).forEach(function(w){
|
|
1748
|
+
var host = ensureHostForWrap(w, ulEl) || (w.closest ? w.closest('li.' + HOST_CLASS) : null);
|
|
1749
|
+
rememberAnchor(host || w);
|
|
1750
|
+
});
|
|
1688
1751
|
} catch (e) {}
|
|
1752
|
+
|
|
1753
|
+
mo = new MutationObserver(function(muts){
|
|
1754
|
+
try {
|
|
1755
|
+
for (var i=0;i<muts.length;i++){
|
|
1756
|
+
var m = muts[i];
|
|
1757
|
+
if (m.addedNodes && m.addedNodes.length) {
|
|
1758
|
+
for (var j=0;j<m.addedNodes.length;j++) enqueue(m.addedNodes[j]);
|
|
1759
|
+
}
|
|
1760
|
+
if (m.target) enqueue(m.target);
|
|
1761
|
+
}
|
|
1762
|
+
} catch (e) {}
|
|
1763
|
+
});
|
|
1764
|
+
mo.observe(ulEl, { childList:true, subtree:true });
|
|
1689
1765
|
}
|
|
1690
1766
|
|
|
1691
1767
|
function init() {
|
|
1692
|
-
|
|
1693
|
-
|
|
1768
|
+
initObserver();
|
|
1769
|
+
scheduleFlush();
|
|
1694
1770
|
|
|
1695
|
-
// Initial pass: host all between DIVs and reconcile once.
|
|
1696
|
-
schedule();
|
|
1697
|
-
|
|
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) {}
|
|
1717
|
-
}
|
|
1718
|
-
|
|
1719
|
-
// NodeBB events: run a settle pass after batches
|
|
1720
1771
|
if (window.jQuery) {
|
|
1721
1772
|
try {
|
|
1722
|
-
window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1773
|
+
window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function(){
|
|
1774
|
+
ul = null;
|
|
1775
|
+
try { if (mo) { mo.disconnect(); } } catch(e){}
|
|
1776
|
+
mo = null;
|
|
1777
|
+
initObserver();
|
|
1778
|
+
setTimeout(function(){ scheduleFlush(); }, 80);
|
|
1779
|
+
setTimeout(function(){ scheduleFlush(); }, 450);
|
|
1726
1780
|
});
|
|
1727
1781
|
} catch (e) {}
|
|
1728
1782
|
}
|
|
1783
|
+
|
|
1784
|
+
var tries = 0;
|
|
1785
|
+
var t = setInterval(function(){
|
|
1786
|
+
tries++;
|
|
1787
|
+
if (ensureUL()) {
|
|
1788
|
+
clearInterval(t);
|
|
1789
|
+
initObserver();
|
|
1790
|
+
scheduleFlush();
|
|
1791
|
+
}
|
|
1792
|
+
if (tries > 25) clearInterval(t);
|
|
1793
|
+
}, 200);
|
|
1729
1794
|
}
|
|
1730
1795
|
|
|
1731
1796
|
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
|
1732
1797
|
else init();
|
|
1733
1798
|
})();
|
|
1734
|
-
// ===== /
|
|
1799
|
+
// ===== /V17.7 =====
|
|
1735
1800
|
|
package/public/style.css
CHANGED
|
@@ -88,8 +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{ list-style:none; width:100%; display:block; }
|
|
93
|
-
li.nodebb-ezoic-host > .nodebb-ezoic-wrap.ezoic-ad-between{ width:100%; display:block; }
|
|
94
|
-
/* ===== /
|
|
91
|
+
/* ===== V17.7 host styling ===== */
|
|
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
|
+
/* ===== /V17.7 ===== */
|
|
95
95
|
|