nodebb-plugin-ezoic-infinite 1.6.21 → 1.6.22

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.6.21",
3
+ "version": "1.6.22",
4
4
  "description": "Production-ready Ezoic infinite ads integration for NodeBB 4.x",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/public/client.js CHANGED
@@ -1511,24 +1511,11 @@ function buildOrdinalMap(items) {
1511
1511
 
1512
1512
 
1513
1513
 
1514
- // ===== V14.1.1 Hook between-wrap (safe): host repair always, reconcile ONLY on upscroll, never append host to bottom =====
1514
+ // ===== V14.1.2 IO reconcile (visible only) minimal impact on infinite scroll =====
1515
1515
  (function () {
1516
- var BETWEEN_SEL = 'div.nodebb-ezoic-wrap.ezoic-ad-between';
1516
+ var WRAP_SEL = 'div.nodebb-ezoic-wrap.ezoic-ad-between';
1517
1517
  var HOST_CLASS = 'nodebb-ezoic-host';
1518
- var TOKEN_ATTR = 'data-ezoic-anchor-token';
1519
-
1520
- var lastY = window.pageYOffset || document.documentElement.scrollTop || 0;
1521
- var pending = false;
1522
- var lastRun = 0;
1523
- var COOLDOWN = 140;
1524
-
1525
- function getY() {
1526
- return window.pageYOffset || document.documentElement.scrollTop || 0;
1527
- }
1528
-
1529
- function token() {
1530
- try { return String(Date.now()) + '-' + Math.random().toString(16).slice(2); } catch (e) { return String(Date.now()); }
1531
- }
1518
+ var io = null;
1532
1519
 
1533
1520
  function getListContainer(node) {
1534
1521
  try {
@@ -1547,6 +1534,7 @@ function buildOrdinalMap(items) {
1547
1534
  try {
1548
1535
  var cur = node;
1549
1536
  if (!cur) return null;
1537
+ // If inside host, start from host
1550
1538
  if (cur.closest) {
1551
1539
  var host = cur.closest('li.' + HOST_CLASS);
1552
1540
  if (host) cur = host;
@@ -1560,26 +1548,24 @@ function buildOrdinalMap(items) {
1560
1548
  return null;
1561
1549
  }
1562
1550
 
1563
- function ensureHost(wrap) {
1564
- // Always ensure UL/OL doesn't directly contain DIV wraps.
1551
+ function ensureHostForWrap(wrap) {
1552
+ // Only repairs invalid UL>DIV. Does NOT move around the list except wrapping in-place.
1565
1553
  try {
1566
1554
  if (!wrap || wrap.nodeType !== 1) return null;
1567
- if (!(wrap.matches && wrap.matches(BETWEEN_SEL))) return null;
1568
-
1569
- var ul = getListContainer(wrap);
1570
- if (!ul) return null;
1555
+ if (!(wrap.matches && wrap.matches(WRAP_SEL))) return null;
1571
1556
 
1572
1557
  var host = wrap.closest ? wrap.closest('li.' + HOST_CLASS) : null;
1573
1558
  if (host) return host;
1574
1559
 
1575
- // If direct child of UL/OL, create host in-place (does not affect infinite scroll measurements much)
1560
+ var ul = getListContainer(wrap);
1561
+ if (!ul) return null;
1562
+
1576
1563
  if (wrap.parentElement === ul) {
1577
1564
  host = document.createElement('li');
1578
1565
  host.className = HOST_CLASS;
1579
1566
  host.setAttribute('role', 'listitem');
1580
1567
  host.style.listStyle = 'none';
1581
1568
  host.style.width = '100%';
1582
-
1583
1569
  ul.insertBefore(host, wrap);
1584
1570
  host.appendChild(wrap);
1585
1571
  try { wrap.style.width = '100%'; } catch (e) {}
@@ -1589,118 +1575,105 @@ function buildOrdinalMap(items) {
1589
1575
  return null;
1590
1576
  }
1591
1577
 
1592
- function tetherHostToAnchor(host, ul) {
1593
- // Only called on upscroll to avoid breaking load logic.
1578
+ function reconcileHostPosition(host) {
1579
+ // Moves ONLY the one host we are currently handling (visible or just inserted).
1594
1580
  try {
1595
- if (!host) return;
1596
- var wrap = host.querySelector && host.querySelector(BETWEEN_SEL);
1597
- if (!wrap) { host.remove(); return; }
1581
+ if (!host || host.nodeType !== 1) return;
1582
+ var ul = getListContainer(host);
1583
+ if (!ul) return;
1598
1584
 
1599
- // Determine anchor = nearest previous non-host li
1600
1585
  var anchorLi = closestNonHostLi(host);
1601
- if (!anchorLi) {
1602
- // No anchor in DOM -> mark orphan (handled on upscroll only)
1603
- host.setAttribute('data-ezoic-orphan', '1');
1604
- return;
1605
- }
1606
-
1607
- var t = anchorLi.getAttribute(TOKEN_ATTR);
1608
- if (!t) {
1609
- t = token();
1610
- anchorLi.setAttribute(TOKEN_ATTR, t);
1611
- }
1612
- host.setAttribute(TOKEN_ATTR, t);
1613
- host.removeAttribute('data-ezoic-orphan');
1586
+ if (!anchorLi) return;
1614
1587
 
1615
- // If host drifted, put it back right after anchor
1616
1588
  if (host.previousElementSibling !== anchorLi) {
1617
1589
  anchorLi.insertAdjacentElement('afterend', host);
1618
1590
  }
1619
1591
  } catch (e) {}
1620
1592
  }
1621
1593
 
1622
- function reconcileUpScroll() {
1623
- var y = getY();
1624
- var dy = y - lastY;
1625
- lastY = y;
1626
-
1627
- // ALWAYS: repair invalid ul>div occurrences (cheap) but don't reorder
1594
+ function observeHost(host) {
1628
1595
  try {
1629
- var bad = document.querySelectorAll('ul > ' + BETWEEN_SEL + ', ol > ' + BETWEEN_SEL);
1630
- bad.forEach(function(w){ ensureHost(w); });
1596
+ if (!host) return;
1597
+ if (!io) return;
1598
+ io.observe(host);
1631
1599
  } catch (e) {}
1600
+ }
1632
1601
 
1633
- // If NOT upscroll, do nothing else (prevents "ads accumulate at bottom" and avoids scroll blocking)
1634
- if (dy > -8) return;
1602
+ function initIO() {
1603
+ if (io || typeof IntersectionObserver === 'undefined') return;
1604
+ io = new IntersectionObserver(function (entries) {
1605
+ try {
1606
+ entries.forEach(function (e) {
1607
+ if (!e || !e.isIntersecting || !e.target) return;
1608
+ // When host is near viewport, reconcile once.
1609
+ reconcileHostPosition(e.target);
1610
+ });
1611
+ } catch (e) {}
1612
+ }, { root: null, rootMargin: '800px 0px 800px 0px', threshold: 0.01 });
1613
+ }
1635
1614
 
1636
- // Up-scroll: tether/reconcile and drop orphan hosts (they cause pile-ups)
1615
+ function processWrap(wrap) {
1637
1616
  try {
1638
- var wraps = document.querySelectorAll(BETWEEN_SEL);
1639
- wraps.forEach(function(w){
1640
- var host = ensureHost(w);
1641
- if (!host) host = w.closest ? w.closest('li.' + HOST_CLASS) : null;
1642
- var ul = getListContainer(host || w);
1643
- if (host && ul) tetherHostToAnchor(host, ul);
1644
- });
1645
-
1646
- // Drop orphans only on upscroll
1647
- var orphans = document.querySelectorAll('li.' + HOST_CLASS + '[data-ezoic-orphan="1"]');
1648
- orphans.forEach(function(h){ try { h.remove(); } catch(e) {} });
1649
-
1650
- // Drop empty hosts
1651
- var empties = document.querySelectorAll('li.' + HOST_CLASS);
1652
- empties.forEach(function(h){
1653
- try { if (!(h.querySelector && h.querySelector(BETWEEN_SEL))) h.remove(); } catch(e) {}
1654
- });
1617
+ var host = ensureHostForWrap(wrap) || (wrap.closest ? wrap.closest('li.' + HOST_CLASS) : null);
1618
+ if (host) {
1619
+ // reconcile immediately only for the newly processed node (cheap)
1620
+ reconcileHostPosition(host);
1621
+ observeHost(host);
1622
+ }
1655
1623
  } catch (e) {}
1656
1624
  }
1657
1625
 
1658
- function schedule() {
1659
- var now = Date.now();
1660
- if (now - lastRun < COOLDOWN) return;
1661
- if (pending) return;
1662
- pending = true;
1663
- requestAnimationFrame(function(){
1664
- pending = false;
1665
- lastRun = Date.now();
1666
- reconcileUpScroll();
1667
- });
1626
+ function scanInitial() {
1627
+ try {
1628
+ document.querySelectorAll(WRAP_SEL).forEach(processWrap);
1629
+ } catch (e) {}
1668
1630
  }
1669
1631
 
1670
- function init() {
1671
- // Initial repair only
1632
+ function installMO() {
1672
1633
  try {
1673
- var bad = document.querySelectorAll('ul > ' + BETWEEN_SEL + ', ol > ' + BETWEEN_SEL);
1674
- bad.forEach(function(w){ ensureHost(w); });
1634
+ if (typeof MutationObserver === 'undefined') return;
1635
+ var mo = new MutationObserver(function (muts) {
1636
+ try {
1637
+ for (var i = 0; i < muts.length; i++) {
1638
+ var m = muts[i];
1639
+ if (!m.addedNodes || !m.addedNodes.length) continue;
1640
+
1641
+ for (var j = 0; j < m.addedNodes.length; j++) {
1642
+ var n = m.addedNodes[j];
1643
+ if (!n || n.nodeType !== 1) continue;
1644
+
1645
+ if (n.matches && n.matches(WRAP_SEL)) {
1646
+ processWrap(n);
1647
+ } else if (n.querySelectorAll) {
1648
+ var inner = n.querySelectorAll(WRAP_SEL);
1649
+ if (inner && inner.length) inner.forEach(processWrap);
1650
+ }
1651
+ }
1652
+ }
1653
+ } catch (e) {}
1654
+ });
1655
+ mo.observe(document.documentElement || document.body, { childList: true, subtree: true });
1675
1656
  } catch (e) {}
1657
+ }
1676
1658
 
1677
- window.addEventListener('scroll', schedule, { passive: true });
1678
- window.addEventListener('resize', schedule, { passive: true });
1659
+ function init() {
1660
+ initIO();
1661
+ scanInitial();
1662
+ installMO();
1679
1663
 
1680
1664
  if (window.jQuery) {
1681
- window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function(){
1682
- setTimeout(schedule, 0);
1683
- setTimeout(schedule, 250);
1684
- setTimeout(schedule, 900);
1685
- });
1686
- }
1687
-
1688
- // MutationObserver: only schedule (no immediate heavy work)
1689
- try {
1690
- if (typeof MutationObserver !== 'undefined') {
1691
- var mo = new MutationObserver(function(muts){
1692
- for (var i=0;i<muts.length;i++){
1693
- var m=muts[i];
1694
- if ((m.addedNodes && m.addedNodes.length) || (m.removedNodes && m.removedNodes.length)) { schedule(); break; }
1695
- }
1665
+ try {
1666
+ window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function () {
1667
+ // do a light rescan (no scroll listeners)
1668
+ setTimeout(scanInitial, 0);
1669
+ setTimeout(scanInitial, 250);
1696
1670
  });
1697
- mo.observe(document.documentElement || document.body, { childList:true, subtree:true });
1698
- }
1699
- } catch (e) {}
1671
+ } catch (e) {}
1672
+ }
1700
1673
  }
1701
1674
 
1702
1675
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
1703
1676
  else init();
1704
1677
  })();
1705
- // ===== /V14.1.1 =====
1678
+ // ===== /V14.1.2 =====
1706
1679
 
package/public/style.css CHANGED
@@ -81,7 +81,7 @@
81
81
  }
82
82
 
83
83
 
84
- /* ===== V14.1.1 host ===== */
84
+ /* ===== V14.1.2 host ===== */
85
85
  li.nodebb-ezoic-host { list-style: none; width: 100%; }
86
- /* ===== /V14.1.1 ===== */
86
+ /* ===== /V14.1.2 ===== */
87
87