nodebb-plugin-ezoic-infinite 1.6.32 → 1.6.33

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.32",
3
+ "version": "1.6.33",
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
@@ -1514,76 +1514,101 @@ function buildOrdinalMap(items) {
1514
1514
 
1515
1515
 
1516
1516
 
1517
- // ===== V17.4: Hide top pile (supports ul>div OR li hosts), no moving, keeps injection intact =====
1517
+ // ===== V17.5: Viewport-based pile masking (no moves, keeps injection intact) =====
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 PILED_ATTR = 'data-ezoic-piled';
1523
1523
 
1524
- var lastY = window.pageYOffset || document.documentElement.scrollTop || 0;
1525
1524
  var scheduled = false;
1526
1525
  var lastRun = 0;
1527
- var COOLDOWN = 90;
1526
+ var COOLDOWN = 70;
1527
+
1528
+ var lastY = window.pageYOffset || document.documentElement.scrollTop || 0;
1528
1529
 
1529
1530
  function getY(){ return window.pageYOffset || document.documentElement.scrollTop || 0; }
1530
1531
 
1531
1532
  function getTopicList(){
1532
- try {
1533
+ try{
1533
1534
  var li = document.querySelector(TOPIC_LI_SEL);
1534
1535
  if (!li) return null;
1535
1536
  return li.closest ? li.closest('ul,ol') : null;
1536
- } catch(e){ return null; }
1537
+ }catch(e){ return null; }
1537
1538
  }
1538
1539
 
1539
1540
  function isBetweenNode(el){
1540
- try {
1541
- if (!el || el.nodeType !== 1) return false;
1542
- if (el.matches && el.matches(BETWEEN_WRAP_SEL)) return true; // ul>div case
1543
- if (el.tagName === 'LI' && el.classList && el.classList.contains(HOST_CLASS)) {
1541
+ try{
1542
+ if (!el || el.nodeType!==1) return false;
1543
+ if (el.matches && el.matches(BETWEEN_WRAP_SEL)) return true; // ul>div
1544
+ if (el.tagName==='LI' && el.classList && el.classList.contains(HOST_CLASS)) {
1544
1545
  return !!(el.querySelector && el.querySelector(BETWEEN_WRAP_SEL));
1545
1546
  }
1546
- } catch(e){}
1547
+ }catch(e){}
1547
1548
  return false;
1548
1549
  }
1549
1550
 
1550
1551
  function isTopicNode(el){
1551
- try { return !!(el && el.nodeType===1 && el.matches && el.matches(TOPIC_LI_SEL)); } catch(e){ return false; }
1552
+ try{ return !!(el && el.nodeType===1 && el.matches && el.matches(TOPIC_LI_SEL)); }catch(e){ return false; }
1552
1553
  }
1553
1554
 
1554
- function clearPiled(ul){
1555
- try {
1555
+ function setPiled(el, piled){
1556
+ try{
1557
+ if (!el) return;
1558
+ if (piled) el.setAttribute(PILED_ATTR,'1');
1559
+ else el.removeAttribute(PILED_ATTR);
1560
+ }catch(e){}
1561
+ }
1562
+
1563
+ function clearAll(ul){
1564
+ try{
1556
1565
  if (!ul) return;
1557
- ul.querySelectorAll('['+PILED_ATTR+'="1"]').forEach(function(n){
1558
- try { n.removeAttribute(PILED_ATTR); } catch(e){}
1559
- });
1560
- } catch(e){}
1566
+ ul.querySelectorAll('['+PILED_ATTR+'="1"]').forEach(function(n){ setPiled(n,false); });
1567
+ }catch(e){}
1561
1568
  }
1562
1569
 
1563
- function markTopPile(ul){
1564
- // Mark any consecutive between nodes near top (keep the first, hide the rest until next topic).
1565
- try {
1570
+ function maskViewportPile(ul){
1571
+ // We mask piled ads based on what is actually near/in the viewport, not just first N children.
1572
+ // This catches cases where virtualization moves some ads but not others.
1573
+ try{
1566
1574
  if (!ul) return;
1575
+ var vh = window.innerHeight || 800;
1576
+ var bandTop = -200; // slightly above viewport
1577
+ var bandBottom = vh * 1.6; // covers top area user sees when returning up
1578
+
1579
+ // collect candidates in band in DOM order
1567
1580
  var kids = ul.children;
1568
- var limit = Math.min(kids.length, 140);
1569
- var inRun = 0;
1570
- for (var i=0;i<limit;i++){
1581
+ var candidates = [];
1582
+ for (var i=0;i<kids.length;i++){
1571
1583
  var el = kids[i];
1572
- if (isBetweenNode(el)){
1573
- inRun++;
1574
- if (inRun >= 2){
1575
- try { el.setAttribute(PILED_ATTR,'1'); } catch(e){}
1576
- } else {
1577
- try { el.removeAttribute(PILED_ATTR); } catch(e){}
1578
- }
1579
- } else if (isTopicNode(el)){
1580
- inRun = 0;
1581
- } else {
1582
- // other node breaks run as well
1583
- inRun = 0;
1584
+ if (!isBetweenNode(el) && !isTopicNode(el)) continue;
1585
+ // compute rect (cheap enough on limited band; stop after we've passed far below band)
1586
+ var r = el.getBoundingClientRect ? el.getBoundingClientRect() : null;
1587
+ if (!r) continue;
1588
+ if (r.top > bandBottom && candidates.length > 0) {
1589
+ // Once we've started collecting and we are past band, we can stop scanning further.
1590
+ break;
1584
1591
  }
1592
+ if (r.bottom < bandTop) continue;
1593
+ if (r.top > bandBottom) continue;
1594
+
1595
+ candidates.push(el);
1585
1596
  }
1586
- } catch(e){}
1597
+
1598
+ // Now walk candidates and hide consecutive between nodes (keep first between in a run)
1599
+ var run = 0;
1600
+ for (var j=0;j<candidates.length;j++){
1601
+ var el2 = candidates[j];
1602
+ if (isTopicNode(el2)){
1603
+ run = 0;
1604
+ continue;
1605
+ }
1606
+ if (isBetweenNode(el2)){
1607
+ run++;
1608
+ setPiled(el2, run >= 2);
1609
+ }
1610
+ }
1611
+ }catch(e){}
1587
1612
  }
1588
1613
 
1589
1614
  function schedule(fn){
@@ -1606,38 +1631,45 @@ function buildOrdinalMap(items) {
1606
1631
  var ul = getTopicList();
1607
1632
  if (!ul) return;
1608
1633
 
1609
- // Only manage pile visibility when user is near the top area.
1610
- if (y < 1100 && dy < -6){
1611
- schedule(function(){ markTopPile(ul); });
1612
- } else if (y > 1300 || dy > 10){
1613
- // leaving top area or scrolling down: restore visibility
1614
- schedule(function(){ clearPiled(ul); });
1634
+ // Only manage pile masking when user is heading upward OR is near top-ish.
1635
+ if (dy < -6 || y < 1100){
1636
+ schedule(function(){ maskViewportPile(ul); });
1637
+ } else if (dy > 12 && y > 1400){
1638
+ // when leaving the top area, restore visibility
1639
+ schedule(function(){ clearAll(ul); });
1615
1640
  }
1616
1641
  }
1617
1642
 
1618
1643
  function init(){
1619
1644
  window.addEventListener('scroll', onScroll, { passive:true });
1645
+ window.addEventListener('resize', function(){
1646
+ var ul = getTopicList();
1647
+ if (!ul) return;
1648
+ schedule(function(){ maskViewportPile(ul); });
1649
+ }, { passive:true });
1620
1650
 
1621
1651
  if (window.jQuery){
1622
1652
  try{
1623
1653
  window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function(){
1624
- // if we are near top, re-evaluate pile quickly; otherwise ensure no stale hiding
1625
1654
  setTimeout(function(){
1626
- try {
1627
- var ul = getTopicList();
1628
- if (!ul) return;
1629
- var y = getY();
1630
- if (y < 1100) markTopPile(ul);
1631
- else clearPiled(ul);
1632
- } catch(e){}
1633
- }, 80);
1655
+ var ul = getTopicList();
1656
+ if (!ul) return;
1657
+ schedule(function(){ maskViewportPile(ul); });
1658
+ }, 120);
1634
1659
  });
1635
1660
  }catch(e){}
1636
1661
  }
1662
+
1663
+ // initial
1664
+ setTimeout(function(){
1665
+ var ul = getTopicList();
1666
+ if (!ul) return;
1667
+ schedule(function(){ maskViewportPile(ul); });
1668
+ }, 250);
1637
1669
  }
1638
1670
 
1639
1671
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
1640
1672
  else init();
1641
1673
  })();
1642
- // ===== /V17.4 =====
1674
+ // ===== /V17.5 =====
1643
1675
 
package/public/style.css CHANGED
@@ -88,10 +88,10 @@ li.nodebb-ezoic-host > .nodebb-ezoic-wrap.ezoic-ad-between { width: 100%; displa
88
88
 
89
89
 
90
90
 
91
- /* ===== V17.4 pile hide ===== */
91
+ /* ===== V17.5 pile hide ===== */
92
92
  [data-ezoic-piled="1"] { display: none !important; }
93
93
  /* keep host stable */
94
94
  li.nodebb-ezoic-host { list-style:none; width:100%; display:block; }
95
95
  li.nodebb-ezoic-host > .nodebb-ezoic-wrap.ezoic-ad-between { width:100%; display:block; }
96
- /* ===== /V17.4 ===== */
96
+ /* ===== /V17.5 ===== */
97
97