nodebb-plugin-ezoic-infinite 1.6.26 → 1.6.28
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 +179 -61
- package/public/style.css +4 -10
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1,43 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
function ezoicInsertAfterTopicHost(target, wrap, kindClass) {
|
|
5
|
-
try {
|
|
6
|
-
if (!target || !wrap) return false;
|
|
7
|
-
if (kindClass !== 'ezoic-ad-between') return false;
|
|
8
|
-
|
|
9
|
-
// Ensure we insert a LI host that looks like a topic item so NodeBB list virtualization keeps ordering.
|
|
10
|
-
var anchorLi = target.closest ? (target.closest('li[component="category/topic"]') || target.closest('li')) : null;
|
|
11
|
-
if (!anchorLi && target.tagName === 'LI') anchorLi = target;
|
|
12
|
-
if (!anchorLi) return false;
|
|
13
|
-
|
|
14
|
-
var ul = anchorLi.parentElement;
|
|
15
|
-
if (!ul || !(ul.tagName === 'UL' || ul.tagName === 'OL')) return false;
|
|
16
|
-
|
|
17
|
-
// If wrap already hosted, do nothing
|
|
18
|
-
var existingHost = wrap.closest ? wrap.closest('li.nodebb-ezoic-host') : null;
|
|
19
|
-
if (existingHost) return true;
|
|
20
|
-
|
|
21
|
-
var host = document.createElement('li');
|
|
22
|
-
host.className = 'nodebb-ezoic-host';
|
|
23
|
-
// mimic topic list item so NodeBB doesn't relocate it
|
|
24
|
-
host.setAttribute('component', 'category/topic');
|
|
25
|
-
host.setAttribute('data-ezoic-host', 'between');
|
|
26
|
-
host.style.listStyle = 'none';
|
|
27
|
-
host.style.width = '100%';
|
|
28
|
-
|
|
29
|
-
// Insert host after anchorLi
|
|
30
|
-
if (anchorLi.insertAdjacentElement) anchorLi.insertAdjacentElement('afterend', host);
|
|
31
|
-
else ul.insertBefore(host, anchorLi.nextSibling);
|
|
32
|
-
|
|
33
|
-
host.appendChild(wrap);
|
|
34
|
-
try { wrap.style.width = '100%'; } catch (e) {}
|
|
35
|
-
return true;
|
|
36
|
-
} catch (e) {}
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
4
|
// Track scroll direction to avoid aggressive recycling when the user scrolls upward.
|
|
42
5
|
// Recycling while scrolling up is a common cause of ads "bunching" and a "disappearing too fast" feeling.
|
|
43
6
|
let lastScrollY = 0;
|
|
@@ -705,8 +668,7 @@ function globalGapFixInit() {
|
|
|
705
668
|
insertingIds.add(id);
|
|
706
669
|
try {
|
|
707
670
|
const wrap = buildWrap(id, kindClass, afterPos, !existingPh);
|
|
708
|
-
|
|
709
|
-
target.insertAdjacentElement('afterend', wrap);
|
|
671
|
+
target.insertAdjacentElement('afterend', wrap);
|
|
710
672
|
|
|
711
673
|
// If placeholder exists elsewhere (including pool), move it into the wrapper.
|
|
712
674
|
if (existingPh) {
|
|
@@ -1198,8 +1160,7 @@ function buildOrdinalMap(items) {
|
|
|
1198
1160
|
if (!anchorEl || !wrap || !wrap.isConnected) return null;
|
|
1199
1161
|
|
|
1200
1162
|
wrap.setAttribute('data-ezoic-after', String(afterPos));
|
|
1201
|
-
|
|
1202
|
-
anchorEl.insertAdjacentElement('afterend', wrap);
|
|
1163
|
+
anchorEl.insertAdjacentElement('afterend', wrap);
|
|
1203
1164
|
|
|
1204
1165
|
// Ensure minimal layout impact.
|
|
1205
1166
|
try { wrap.style.contain = 'layout style paint'; } catch (e) {}
|
|
@@ -1550,27 +1511,184 @@ function buildOrdinalMap(items) {
|
|
|
1550
1511
|
|
|
1551
1512
|
|
|
1552
1513
|
|
|
1553
|
-
// =====
|
|
1554
|
-
function
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1514
|
+
// ===== V17 minimal pile-fix (no insert hooks) =====
|
|
1515
|
+
(function () {
|
|
1516
|
+
// Goal: keep ad injection intact. Only repair when we detect "pile-up" of between wraps.
|
|
1517
|
+
var TOPIC_LI_SEL = 'li[component="category/topic"]';
|
|
1518
|
+
var BETWEEN_WRAP_SEL = 'div.nodebb-ezoic-wrap.ezoic-ad-between';
|
|
1519
|
+
var HOST_CLASS = 'nodebb-ezoic-host';
|
|
1520
|
+
|
|
1521
|
+
var scheduled = false;
|
|
1522
|
+
var lastRun = 0;
|
|
1523
|
+
var COOLDOWN = 180;
|
|
1524
|
+
|
|
1525
|
+
function getTopicList() {
|
|
1526
|
+
try {
|
|
1527
|
+
var li = document.querySelector(TOPIC_LI_SEL);
|
|
1528
|
+
if (!li) return null;
|
|
1529
|
+
return li.closest ? li.closest('ul,ol') : null;
|
|
1530
|
+
} catch (e) { return null; }
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
function isHost(node) {
|
|
1534
|
+
return !!(node && node.nodeType === 1 && node.tagName === 'LI' && node.classList && node.classList.contains(HOST_CLASS));
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
function ensureHostForWrap(wrap, ul) {
|
|
1538
|
+
try {
|
|
1539
|
+
if (!wrap || wrap.nodeType !== 1) return null;
|
|
1540
|
+
if (!(wrap.matches && wrap.matches(BETWEEN_WRAP_SEL))) return null;
|
|
1541
|
+
|
|
1542
|
+
var host = wrap.closest ? wrap.closest('li.' + HOST_CLASS) : null;
|
|
1543
|
+
if (host) return host;
|
|
1544
|
+
|
|
1545
|
+
if (!ul) ul = wrap.closest ? wrap.closest('ul,ol') : null;
|
|
1546
|
+
if (!ul || !(ul.tagName === 'UL' || ul.tagName === 'OL')) return null;
|
|
1547
|
+
|
|
1548
|
+
// Only wrap if direct child of list (invalid / fragile)
|
|
1549
|
+
if (wrap.parentElement === ul) {
|
|
1550
|
+
host = document.createElement('li');
|
|
1551
|
+
host.className = HOST_CLASS;
|
|
1552
|
+
host.setAttribute('role', 'listitem');
|
|
1553
|
+
host.style.listStyle = 'none';
|
|
1554
|
+
host.style.width = '100%';
|
|
1555
|
+
ul.insertBefore(host, wrap);
|
|
1556
|
+
host.appendChild(wrap);
|
|
1557
|
+
try { wrap.style.width = '100%'; } catch (e) {}
|
|
1558
|
+
return host;
|
|
1559
|
+
}
|
|
1560
|
+
} catch (e) {}
|
|
1561
|
+
return null;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
function previousTopicLi(node) {
|
|
1565
|
+
try {
|
|
1566
|
+
var prev = node.previousElementSibling;
|
|
1567
|
+
while (prev) {
|
|
1568
|
+
if (prev.matches && prev.matches(TOPIC_LI_SEL)) return prev;
|
|
1569
|
+
// skip other hosts/wraps
|
|
1570
|
+
prev = prev.previousElementSibling;
|
|
1571
|
+
}
|
|
1572
|
+
} catch (e) {}
|
|
1573
|
+
return null;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
function detectPileUp(ul) {
|
|
1577
|
+
// Pile-up signature: 2+ between wraps/hosts adjacent with no topics between, often near top.
|
|
1578
|
+
try {
|
|
1579
|
+
var kids = ul.children;
|
|
1580
|
+
var run = 0;
|
|
1581
|
+
var maxRun = 0;
|
|
1582
|
+
for (var i = 0; i < kids.length; i++) {
|
|
1583
|
+
var el = kids[i];
|
|
1584
|
+
var isBetween = false;
|
|
1585
|
+
if (isHost(el)) {
|
|
1586
|
+
isBetween = !!(el.querySelector && el.querySelector(BETWEEN_WRAP_SEL));
|
|
1587
|
+
} else if (el.matches && el.matches(BETWEEN_WRAP_SEL)) {
|
|
1588
|
+
isBetween = true;
|
|
1589
|
+
}
|
|
1590
|
+
if (isBetween) {
|
|
1591
|
+
run++;
|
|
1592
|
+
if (run > maxRun) maxRun = run;
|
|
1593
|
+
} else if (el.matches && el.matches(TOPIC_LI_SEL)) {
|
|
1594
|
+
run = 0;
|
|
1595
|
+
} else {
|
|
1596
|
+
// other nodes reset lightly
|
|
1597
|
+
run = 0;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
return maxRun >= 2;
|
|
1601
|
+
} catch (e) {}
|
|
1602
|
+
return false;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
function redistribute(ul) {
|
|
1606
|
+
try {
|
|
1607
|
+
if (!ul) return;
|
|
1608
|
+
|
|
1609
|
+
// Step 1: wrap any direct child between DIVs into LI hosts (makes list stable)
|
|
1610
|
+
ul.querySelectorAll(':scope > ' + BETWEEN_WRAP_SEL).forEach(function(w){ ensureHostForWrap(w, ul); });
|
|
1611
|
+
|
|
1612
|
+
// Step 2: only act if we see pile-up (avoid touching infinite scroll during normal flow)
|
|
1613
|
+
if (!detectPileUp(ul)) return;
|
|
1614
|
+
|
|
1615
|
+
// Move each host to immediately after the closest previous topic LI at its current position.
|
|
1616
|
+
var hosts = ul.querySelectorAll(':scope > li.' + HOST_CLASS);
|
|
1617
|
+
hosts.forEach(function(host){
|
|
1618
|
+
try {
|
|
1619
|
+
var wrap = host.querySelector && host.querySelector(BETWEEN_WRAP_SEL);
|
|
1620
|
+
if (!wrap) return;
|
|
1621
|
+
|
|
1622
|
+
var anchor = previousTopicLi(host);
|
|
1623
|
+
if (!anchor) return; // if none, don't move (prevents yanking to top/bottom)
|
|
1624
|
+
|
|
1625
|
+
if (host.previousElementSibling !== anchor) {
|
|
1626
|
+
anchor.insertAdjacentElement('afterend', host);
|
|
1627
|
+
}
|
|
1628
|
+
} catch (e) {}
|
|
1629
|
+
});
|
|
1630
|
+
} catch (e) {}
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
function schedule(reason) {
|
|
1634
|
+
var now = Date.now();
|
|
1635
|
+
if (now - lastRun < COOLDOWN) return;
|
|
1636
|
+
if (scheduled) return;
|
|
1637
|
+
scheduled = true;
|
|
1638
|
+
requestAnimationFrame(function () {
|
|
1639
|
+
scheduled = false;
|
|
1640
|
+
lastRun = Date.now();
|
|
1558
1641
|
try {
|
|
1559
|
-
var
|
|
1560
|
-
if (!
|
|
1561
|
-
|
|
1642
|
+
var ul = getTopicList();
|
|
1643
|
+
if (!ul) return;
|
|
1644
|
+
redistribute(ul);
|
|
1562
1645
|
} catch (e) {}
|
|
1563
1646
|
});
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
//
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
function init() {
|
|
1650
|
+
schedule('init');
|
|
1651
|
+
|
|
1652
|
+
// Observe only the topic list once available
|
|
1653
|
+
try {
|
|
1654
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
1655
|
+
var observeList = function(ul){
|
|
1656
|
+
if (!ul) return;
|
|
1657
|
+
var mo = new MutationObserver(function(muts){
|
|
1658
|
+
// schedule on any change; redistribute() itself is guarded by pile-up detection
|
|
1659
|
+
schedule('mo');
|
|
1660
|
+
});
|
|
1661
|
+
mo.observe(ul, { childList: true, subtree: true });
|
|
1662
|
+
};
|
|
1663
|
+
|
|
1664
|
+
var ul = getTopicList();
|
|
1665
|
+
if (ul) observeList(ul);
|
|
1666
|
+
else {
|
|
1667
|
+
var mo2 = new MutationObserver(function(){
|
|
1668
|
+
var u2 = getTopicList();
|
|
1669
|
+
if (u2) {
|
|
1670
|
+
try { observeList(u2); } catch(e){}
|
|
1671
|
+
try { mo2.disconnect(); } catch(e){}
|
|
1672
|
+
}
|
|
1673
|
+
});
|
|
1674
|
+
mo2.observe(document.documentElement || document.body, { childList: true, subtree: true });
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
} catch (e) {}
|
|
1678
|
+
|
|
1679
|
+
// NodeBB events: run after infinite scroll batches
|
|
1680
|
+
if (window.jQuery) {
|
|
1681
|
+
try {
|
|
1682
|
+
window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function(){
|
|
1683
|
+
setTimeout(function(){ schedule('event'); }, 50);
|
|
1684
|
+
setTimeout(function(){ schedule('event2'); }, 400);
|
|
1685
|
+
});
|
|
1686
|
+
} catch (e) {}
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
|
1691
|
+
else init();
|
|
1692
|
+
})();
|
|
1693
|
+
// ===== /V17 =====
|
|
1576
1694
|
|
package/public/style.css
CHANGED
|
@@ -81,14 +81,8 @@
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
/* =====
|
|
85
|
-
li.nodebb-ezoic-host
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
/* ensure host doesn't inherit topic card layout */
|
|
90
|
-
li.nodebb-ezoic-host[component="category/topic"] > .nodebb-ezoic-wrap.ezoic-ad-between{
|
|
91
|
-
width:100%;
|
|
92
|
-
}
|
|
93
|
-
/* ===== /V16 ===== */
|
|
84
|
+
/* ===== V17 host styling ===== */
|
|
85
|
+
li.nodebb-ezoic-host { list-style: none; width: 100%; display: block; }
|
|
86
|
+
li.nodebb-ezoic-host > .nodebb-ezoic-wrap.ezoic-ad-between { width: 100%; display: block; }
|
|
87
|
+
/* ===== /V17 ===== */
|
|
94
88
|
|