nodebb-plugin-ezoic-infinite 1.6.35 → 1.6.37
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 +131 -144
- package/public/style.css +14 -4
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1514,15 +1514,18 @@ function buildOrdinalMap(items) {
|
|
|
1514
1514
|
|
|
1515
1515
|
|
|
1516
1516
|
|
|
1517
|
-
// =====
|
|
1517
|
+
// ===== V17.8: No pile-up by design — keep "future" between slots pending/collapsed until their anchor topic exists =====
|
|
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
|
-
var
|
|
1522
|
+
var PENDING_CLASS = 'nodebb-ezoic-pending';
|
|
1523
1523
|
|
|
1524
|
-
var
|
|
1525
|
-
var
|
|
1524
|
+
var ul = null;
|
|
1525
|
+
var mo = null;
|
|
1526
|
+
var scheduled = false;
|
|
1527
|
+
var lastRun = 0;
|
|
1528
|
+
var COOLDOWN = 80;
|
|
1526
1529
|
|
|
1527
1530
|
function getTopicList() {
|
|
1528
1531
|
try {
|
|
@@ -1532,69 +1535,41 @@ function buildOrdinalMap(items) {
|
|
|
1532
1535
|
} catch (e) { return null; }
|
|
1533
1536
|
}
|
|
1534
1537
|
|
|
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
|
-
}
|
|
1538
|
+
function ensureUL() { ul = ul || getTopicList(); return ul; }
|
|
1546
1539
|
|
|
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;
|
|
1540
|
+
function isHost(el) {
|
|
1541
|
+
return !!(el && el.nodeType === 1 && el.tagName === 'LI' && el.classList && el.classList.contains(HOST_CLASS));
|
|
1557
1542
|
}
|
|
1558
1543
|
|
|
1559
|
-
function
|
|
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;
|
|
1544
|
+
function isBetweenWrap(el) {
|
|
1545
|
+
try { return !!(el && el.nodeType === 1 && el.matches && el.matches(BETWEEN_WRAP_SEL)); } catch(e){ return false; }
|
|
1568
1546
|
}
|
|
1569
1547
|
|
|
1570
|
-
function ensureHostForWrap(wrap,
|
|
1571
|
-
//
|
|
1548
|
+
function ensureHostForWrap(wrap, ulEl) {
|
|
1549
|
+
// If Ezoic inserts ul > div..., wrap it into a LI to keep a valid list structure (less NodeBB churn).
|
|
1572
1550
|
try {
|
|
1573
|
-
if (!wrap || wrap
|
|
1574
|
-
if (!(wrap.matches && wrap.matches(BETWEEN_WRAP_SEL))) return null;
|
|
1575
|
-
|
|
1551
|
+
if (!wrap || !isBetweenWrap(wrap)) return null;
|
|
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
1564
|
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
var
|
|
1594
|
-
if (
|
|
1595
|
-
}
|
|
1565
|
+
try {
|
|
1566
|
+
var after = wrap.getAttribute('data-ezoic-after');
|
|
1567
|
+
if (after) host.setAttribute('data-ezoic-after', after);
|
|
1568
|
+
var pin = wrap.getAttribute('data-ezoic-pin');
|
|
1569
|
+
if (pin) host.setAttribute('data-ezoic-pin', pin);
|
|
1570
|
+
} catch (e) {}
|
|
1596
1571
|
|
|
1597
|
-
|
|
1572
|
+
ulEl.insertBefore(host, wrap);
|
|
1598
1573
|
host.appendChild(wrap);
|
|
1599
1574
|
try { wrap.style.width = '100%'; } catch (e) {}
|
|
1600
1575
|
return host;
|
|
@@ -1603,133 +1578,145 @@ function buildOrdinalMap(items) {
|
|
|
1603
1578
|
return null;
|
|
1604
1579
|
}
|
|
1605
1580
|
|
|
1606
|
-
function
|
|
1581
|
+
function getAfter(el) {
|
|
1607
1582
|
try {
|
|
1608
|
-
|
|
1609
|
-
if (
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1583
|
+
var v = null;
|
|
1584
|
+
if (el && el.getAttribute) v = el.getAttribute('data-ezoic-after');
|
|
1585
|
+
if (!v && el && el.querySelector) {
|
|
1586
|
+
var w = el.querySelector(BETWEEN_WRAP_SEL);
|
|
1587
|
+
if (w) v = w.getAttribute('data-ezoic-after');
|
|
1588
|
+
}
|
|
1589
|
+
var n = parseInt(v, 10);
|
|
1590
|
+
return isNaN(n) ? null : n;
|
|
1591
|
+
} catch (e) { return null; }
|
|
1615
1592
|
}
|
|
1616
1593
|
|
|
1617
|
-
function
|
|
1618
|
-
try {
|
|
1619
|
-
|
|
1620
|
-
ul = ul || host.parentElement;
|
|
1621
|
-
if (!ul) return;
|
|
1622
|
-
|
|
1623
|
-
// if host got detached from list, skip
|
|
1624
|
-
if (!(ul.tagName === 'UL' || ul.tagName === 'OL')) return;
|
|
1594
|
+
function getTopics(ulEl) {
|
|
1595
|
+
try { return ulEl ? ulEl.querySelectorAll(TOPIC_LI_SEL) : []; } catch(e){ return []; }
|
|
1596
|
+
}
|
|
1625
1597
|
|
|
1626
|
-
|
|
1598
|
+
function lastTopic(ulEl, topics) {
|
|
1599
|
+
try {
|
|
1600
|
+
topics = topics || getTopics(ulEl);
|
|
1601
|
+
return topics && topics.length ? topics[topics.length - 1] : null;
|
|
1602
|
+
} catch (e) { return null; }
|
|
1603
|
+
}
|
|
1627
1604
|
|
|
1628
|
-
|
|
1629
|
-
|
|
1605
|
+
function moveAfter(node, anchor) {
|
|
1606
|
+
try {
|
|
1607
|
+
if (!node || !anchor || !anchor.insertAdjacentElement) return;
|
|
1608
|
+
if (node.previousElementSibling === anchor) return;
|
|
1609
|
+
anchor.insertAdjacentElement('afterend', node);
|
|
1610
|
+
} catch (e) {}
|
|
1611
|
+
}
|
|
1630
1612
|
|
|
1631
|
-
|
|
1632
|
-
|
|
1613
|
+
function placeOrPend(host, ulEl, topics) {
|
|
1614
|
+
try {
|
|
1615
|
+
if (!host) return;
|
|
1616
|
+
ulEl = ulEl || ensureUL();
|
|
1617
|
+
if (!ulEl) return;
|
|
1618
|
+
|
|
1619
|
+
topics = topics || getTopics(ulEl);
|
|
1620
|
+
|
|
1621
|
+
var after = getAfter(host);
|
|
1622
|
+
if (!after) {
|
|
1623
|
+
var lt = lastTopic(ulEl, topics);
|
|
1624
|
+
if (lt) moveAfter(host, lt);
|
|
1625
|
+
host.classList && host.classList.remove(PENDING_CLASS);
|
|
1626
|
+
return;
|
|
1627
|
+
}
|
|
1633
1628
|
|
|
1634
|
-
if (
|
|
1635
|
-
|
|
1629
|
+
if (after > topics.length) {
|
|
1630
|
+
var lt2 = lastTopic(ulEl, topics);
|
|
1631
|
+
if (lt2) moveAfter(host, lt2);
|
|
1632
|
+
host.classList && host.classList.add(PENDING_CLASS);
|
|
1633
|
+
return;
|
|
1636
1634
|
}
|
|
1635
|
+
|
|
1636
|
+
var anchor = topics[after - 1];
|
|
1637
|
+
if (anchor) moveAfter(host, anchor);
|
|
1638
|
+
host.classList && host.classList.remove(PENDING_CLASS);
|
|
1637
1639
|
} catch (e) {}
|
|
1638
1640
|
}
|
|
1639
1641
|
|
|
1640
|
-
function
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1642
|
+
function reconcile() {
|
|
1643
|
+
var ulEl = ensureUL();
|
|
1644
|
+
if (!ulEl) return;
|
|
1645
|
+
|
|
1646
|
+
var topics = getTopics(ulEl);
|
|
1644
1647
|
|
|
1645
|
-
// First, host any direct-child between DIVs currently in list (cheap, keeps DOM valid).
|
|
1646
1648
|
try {
|
|
1647
|
-
|
|
1648
|
-
var h = ensureHostForWrap(w,
|
|
1649
|
-
if (h)
|
|
1649
|
+
ulEl.querySelectorAll(':scope > ' + BETWEEN_WRAP_SEL).forEach(function (w) {
|
|
1650
|
+
var h = ensureHostForWrap(w, ulEl);
|
|
1651
|
+
if (h) placeOrPend(h, ulEl, topics);
|
|
1650
1652
|
});
|
|
1651
|
-
} catch (e) {}
|
|
1652
1653
|
|
|
1653
|
-
|
|
1654
|
+
ulEl.querySelectorAll('li.' + HOST_CLASS).forEach(function (h) {
|
|
1655
|
+
placeOrPend(h, ulEl, topics);
|
|
1656
|
+
});
|
|
1654
1657
|
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
processed++;
|
|
1661
|
-
if (processed >= 12) break;
|
|
1662
|
-
}
|
|
1663
|
-
if (queue.size) schedule();
|
|
1658
|
+
ulEl.querySelectorAll(BETWEEN_WRAP_SEL).forEach(function (w) {
|
|
1659
|
+
var h = ensureHostForWrap(w, ulEl) || (w.closest ? w.closest('li.' + HOST_CLASS) : null);
|
|
1660
|
+
if (h) placeOrPend(h, ulEl, topics);
|
|
1661
|
+
});
|
|
1662
|
+
} catch (e) {}
|
|
1664
1663
|
}
|
|
1665
1664
|
|
|
1666
|
-
function
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1665
|
+
function scheduleReconcile() {
|
|
1666
|
+
var now = Date.now();
|
|
1667
|
+
if (scheduled) return;
|
|
1668
|
+
if (now - lastRun < COOLDOWN) return;
|
|
1669
|
+
scheduled = true;
|
|
1670
|
+
lastRun = now;
|
|
1671
|
+
requestAnimationFrame(function () {
|
|
1672
|
+
scheduled = false;
|
|
1673
|
+
reconcile();
|
|
1674
|
+
});
|
|
1670
1675
|
}
|
|
1671
1676
|
|
|
1672
|
-
function
|
|
1673
|
-
|
|
1674
|
-
|
|
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) {}
|
|
1689
|
-
}
|
|
1677
|
+
function initObserver() {
|
|
1678
|
+
var ulEl = ensureUL();
|
|
1679
|
+
if (!ulEl || mo) return;
|
|
1690
1680
|
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1681
|
+
mo = new MutationObserver(function () {
|
|
1682
|
+
scheduleReconcile();
|
|
1683
|
+
});
|
|
1694
1684
|
|
|
1695
|
-
|
|
1696
|
-
|
|
1685
|
+
mo.observe(ulEl, { childList: true, subtree: true });
|
|
1686
|
+
}
|
|
1697
1687
|
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
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
|
-
}
|
|
1688
|
+
function init() {
|
|
1689
|
+
initObserver();
|
|
1690
|
+
scheduleReconcile();
|
|
1718
1691
|
|
|
1719
|
-
// NodeBB events: run a settle pass after batches
|
|
1720
1692
|
if (window.jQuery) {
|
|
1721
1693
|
try {
|
|
1722
1694
|
window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function () {
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1695
|
+
ul = null;
|
|
1696
|
+
try { if (mo) mo.disconnect(); } catch (e) {}
|
|
1697
|
+
mo = null;
|
|
1698
|
+
initObserver();
|
|
1699
|
+
scheduleReconcile();
|
|
1700
|
+
setTimeout(scheduleReconcile, 120);
|
|
1701
|
+
setTimeout(scheduleReconcile, 500);
|
|
1726
1702
|
});
|
|
1727
1703
|
} catch (e) {}
|
|
1728
1704
|
}
|
|
1705
|
+
|
|
1706
|
+
var tries = 0;
|
|
1707
|
+
var t = setInterval(function () {
|
|
1708
|
+
tries++;
|
|
1709
|
+
if (ensureUL()) {
|
|
1710
|
+
clearInterval(t);
|
|
1711
|
+
initObserver();
|
|
1712
|
+
scheduleReconcile();
|
|
1713
|
+
}
|
|
1714
|
+
if (tries > 30) clearInterval(t);
|
|
1715
|
+
}, 200);
|
|
1729
1716
|
}
|
|
1730
1717
|
|
|
1731
1718
|
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
|
1732
1719
|
else init();
|
|
1733
1720
|
})();
|
|
1734
|
-
// ===== /
|
|
1721
|
+
// ===== /V17.8 =====
|
|
1735
1722
|
|
package/public/style.css
CHANGED
|
@@ -88,8 +88,18 @@ 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.8 pending slots (prevents pile-up top/bottom) ===== */
|
|
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
|
+
|
|
95
|
+
/* slots whose anchor topic isn't loaded yet */
|
|
96
|
+
li.nodebb-ezoic-host.nodebb-ezoic-pending{
|
|
97
|
+
max-height: 0 !important;
|
|
98
|
+
margin: 0 !important;
|
|
99
|
+
padding: 0 !important;
|
|
100
|
+
overflow: hidden !important;
|
|
101
|
+
opacity: 0 !important;
|
|
102
|
+
pointer-events: none !important;
|
|
103
|
+
}
|
|
104
|
+
/* ===== /V17.8 ===== */
|
|
95
105
|
|