nodebb-plugin-ezoic-infinite 1.6.31 → 1.6.32

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.31",
3
+ "version": "1.6.32",
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,7 +1514,7 @@ function buildOrdinalMap(items) {
1514
1514
 
1515
1515
 
1516
1516
 
1517
- // ===== V17.3: keep injection; hide top pile on upscroll; rehome EMPTY hosts on downscroll =====
1517
+ // ===== V17.4: Hide top pile (supports ul>div OR li hosts), no moving, 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';
@@ -1524,7 +1524,7 @@ function buildOrdinalMap(items) {
1524
1524
  var lastY = window.pageYOffset || document.documentElement.scrollTop || 0;
1525
1525
  var scheduled = false;
1526
1526
  var lastRun = 0;
1527
- var COOLDOWN = 120;
1527
+ var COOLDOWN = 90;
1528
1528
 
1529
1529
  function getY(){ return window.pageYOffset || document.documentElement.scrollTop || 0; }
1530
1530
 
@@ -1536,113 +1536,54 @@ function buildOrdinalMap(items) {
1536
1536
  } catch(e){ return null; }
1537
1537
  }
1538
1538
 
1539
- function ensureHostForWrap(wrap, ul){
1540
- try{
1541
- if (!wrap || wrap.nodeType!==1) return null;
1542
- if (!(wrap.matches && wrap.matches(BETWEEN_WRAP_SEL))) return null;
1543
-
1544
- var host = wrap.closest ? wrap.closest('li.'+HOST_CLASS) : null;
1545
- if (host) return host;
1546
-
1547
- if (!ul) ul = wrap.closest ? wrap.closest('ul,ol') : null;
1548
- if (!ul || !(ul.tagName==='UL' || ul.tagName==='OL')) return null;
1549
-
1550
- if (wrap.parentElement === ul){
1551
- host = document.createElement('li');
1552
- host.className = HOST_CLASS;
1553
- host.setAttribute('role','listitem');
1554
- host.style.listStyle='none';
1555
- host.style.width='100%';
1556
- // preserve after
1557
- try {
1558
- var after = wrap.getAttribute('data-ezoic-after');
1559
- if (after) host.setAttribute('data-ezoic-after', after);
1560
- } catch(e){}
1561
- ul.insertBefore(host, wrap);
1562
- host.appendChild(wrap);
1563
- try { wrap.style.width='100%'; } catch(e){}
1564
- return host;
1539
+ 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)) {
1544
+ return !!(el.querySelector && el.querySelector(BETWEEN_WRAP_SEL));
1565
1545
  }
1566
- }catch(e){}
1567
- return null;
1568
- }
1569
-
1570
- function hostHasAdContent(host){
1571
- // iframes/amp ads mean it's already rendered; moving might reduce fill
1572
- try{
1573
- return !!(host.querySelector && host.querySelector('iframe, amp-ad, amp-iframe, .amp-ads, .ezoic-ad iframe'));
1574
- }catch(e){ return false; }
1546
+ } catch(e){}
1547
+ return false;
1575
1548
  }
1576
1549
 
1577
- function nthTopic(ul, n){
1578
- try{
1579
- var topics = ul.querySelectorAll(TOPIC_LI_SEL);
1580
- if (!topics || !topics.length) return null;
1581
- if (n<1) n=1;
1582
- if (n>topics.length) n=topics.length;
1583
- return topics[n-1] || null;
1584
- }catch(e){ return null; }
1550
+ function isTopicNode(el){
1551
+ try { return !!(el && el.nodeType===1 && el.matches && el.matches(TOPIC_LI_SEL)); } catch(e){ return false; }
1585
1552
  }
1586
1553
 
1587
- function getAfter(host){
1588
- try{
1589
- var v = host.getAttribute('data-ezoic-after');
1590
- if (!v){
1591
- var wrap = host.querySelector && host.querySelector(BETWEEN_WRAP_SEL);
1592
- if (wrap) v = wrap.getAttribute('data-ezoic-after');
1593
- }
1594
- var n = parseInt(v,10);
1595
- return isNaN(n)? null : n;
1596
- }catch(e){ return null; }
1554
+ function clearPiled(ul){
1555
+ try {
1556
+ if (!ul) return;
1557
+ ul.querySelectorAll('['+PILED_ATTR+'="1"]').forEach(function(n){
1558
+ try { n.removeAttribute(PILED_ATTR); } catch(e){}
1559
+ });
1560
+ } catch(e){}
1597
1561
  }
1598
1562
 
1599
- function detectAndHideTopPile(ul){
1600
- // Hide piled hosts near top so user doesn't see the stack.
1601
- try{
1563
+ function markTopPile(ul){
1564
+ // Mark any consecutive between nodes near top (keep the first, hide the rest until next topic).
1565
+ try {
1566
+ if (!ul) return;
1602
1567
  var kids = ul.children;
1603
- var limit = Math.min(kids.length, 60);
1604
- var run = 0;
1568
+ var limit = Math.min(kids.length, 140);
1569
+ var inRun = 0;
1605
1570
  for (var i=0;i<limit;i++){
1606
1571
  var el = kids[i];
1607
- var isBetweenHost = (el.tagName==='LI' && el.classList && el.classList.contains(HOST_CLASS) && el.querySelector && el.querySelector(BETWEEN_WRAP_SEL));
1608
- var isTopic = (el.matches && el.matches(TOPIC_LI_SEL));
1609
- if (isBetweenHost){
1610
- run++;
1611
- if (run>=2){
1612
- // mark piled beyond the first
1613
- el.setAttribute(PILED_ATTR,'1');
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){}
1614
1578
  }
1615
- } else if (isTopic){
1616
- run=0;
1579
+ } else if (isTopicNode(el)){
1580
+ inRun = 0;
1617
1581
  } else {
1618
- // reset on any non-topic
1582
+ // other node breaks run as well
1583
+ inRun = 0;
1619
1584
  }
1620
1585
  }
1621
- }catch(e){}
1622
- }
1623
-
1624
- function rehomePiledEmptyOnDownscroll(ul){
1625
- // On downscroll, try to move only EMPTY (not yet rendered) piled hosts to intended anchors and unhide them.
1626
- try{
1627
- var piled = ul.querySelectorAll('li.'+HOST_CLASS+'['+PILED_ATTR+'="1"]');
1628
- if (!piled.length) return;
1629
-
1630
- piled.forEach(function(host){
1631
- try{
1632
- // if it already has rendered ad, just unhide; do not move
1633
- if (hostHasAdContent(host)){
1634
- host.removeAttribute(PILED_ATTR);
1635
- return;
1636
- }
1637
- var after = getAfter(host);
1638
- var anchor = after!=null ? nthTopic(ul, after) : null;
1639
- if (anchor){
1640
- anchor.insertAdjacentElement('afterend', host);
1641
- }
1642
- host.removeAttribute(PILED_ATTR);
1643
- }catch(e){}
1644
- });
1645
- }catch(e){}
1586
+ } catch(e){}
1646
1587
  }
1647
1588
 
1648
1589
  function schedule(fn){
@@ -1651,7 +1592,7 @@ function buildOrdinalMap(items) {
1651
1592
  if (scheduled) return;
1652
1593
  scheduled = true;
1653
1594
  requestAnimationFrame(function(){
1654
- scheduled=false;
1595
+ scheduled = false;
1655
1596
  lastRun = Date.now();
1656
1597
  fn();
1657
1598
  });
@@ -1661,18 +1602,16 @@ function buildOrdinalMap(items) {
1661
1602
  var y = getY();
1662
1603
  var dy = y - lastY;
1663
1604
  lastY = y;
1605
+
1664
1606
  var ul = getTopicList();
1665
1607
  if (!ul) return;
1666
1608
 
1667
- // always wrap invalid ul>div (cheap)
1668
- try { ul.querySelectorAll(':scope > '+BETWEEN_WRAP_SEL).forEach(function(w){ ensureHostForWrap(w, ul); }); } catch(e){}
1669
-
1670
- if (dy < -8 && y < 900){
1671
- // upscroll near top: hide pile quickly (no moving)
1672
- schedule(function(){ detectAndHideTopPile(ul); });
1673
- } else if (dy > 8){
1674
- // downscroll: rehome only empty piled hosts (safe) and unhide
1675
- schedule(function(){ rehomePiledEmptyOnDownscroll(ul); });
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); });
1676
1615
  }
1677
1616
  }
1678
1617
 
@@ -1682,14 +1621,16 @@ function buildOrdinalMap(items) {
1682
1621
  if (window.jQuery){
1683
1622
  try{
1684
1623
  window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function(){
1685
- // wrap invalids only
1624
+ // if we are near top, re-evaluate pile quickly; otherwise ensure no stale hiding
1686
1625
  setTimeout(function(){
1687
- try{
1626
+ try {
1688
1627
  var ul = getTopicList();
1689
1628
  if (!ul) return;
1690
- ul.querySelectorAll(':scope > '+BETWEEN_WRAP_SEL).forEach(function(w){ ensureHostForWrap(w, ul); });
1691
- }catch(e){}
1692
- }, 50);
1629
+ var y = getY();
1630
+ if (y < 1100) markTopPile(ul);
1631
+ else clearPiled(ul);
1632
+ } catch(e){}
1633
+ }, 80);
1693
1634
  });
1694
1635
  }catch(e){}
1695
1636
  }
@@ -1698,5 +1639,5 @@ function buildOrdinalMap(items) {
1698
1639
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
1699
1640
  else init();
1700
1641
  })();
1701
- // ===== /V17.3 =====
1642
+ // ===== /V17.4 =====
1702
1643
 
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.3 piled hide ===== */
92
- li.nodebb-ezoic-host[data-ezoic-piled="1"] { display: none !important; }
91
+ /* ===== V17.4 pile hide ===== */
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.3 ===== */
96
+ /* ===== /V17.4 ===== */
97
97