nodebb-plugin-ezoic-infinite 1.6.5 → 1.6.7
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 +168 -32
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1348,30 +1348,33 @@ function buildOrdinalMap(items) {
|
|
|
1348
1348
|
|
|
1349
1349
|
|
|
1350
1350
|
|
|
1351
|
+
|
|
1351
1352
|
// ===== CLEAN REFRACTOR: visibility manager for Ezoic wraps =====
|
|
1352
1353
|
(function () {
|
|
1353
|
-
// v2.
|
|
1354
|
-
//
|
|
1355
|
-
// -
|
|
1356
|
-
//
|
|
1354
|
+
// v2.5 (position-enforcer):
|
|
1355
|
+
// - Keep "no-redefine" (showAds only once per id, dedupe placeholders).
|
|
1356
|
+
// - Fix pile-up at top when scrolling up: wraps are being detached and re-inserted near the first post.
|
|
1357
|
+
// Adjacent-anchor can move with the wrap; so we anchor INSIDE the host post/topic element.
|
|
1357
1358
|
//
|
|
1358
|
-
//
|
|
1359
|
-
//
|
|
1359
|
+
// Mechanism:
|
|
1360
|
+
// 1) For each wrap, find a "host" element (closest previous post/topic item).
|
|
1361
|
+
// 2) Insert an invisible marker span INSIDE that host (stays with host even if wrap is moved).
|
|
1362
|
+
// 3) On scroll/interval, if wrap is not located right AFTER its host element, move it back.
|
|
1360
1363
|
//
|
|
1361
|
-
//
|
|
1362
|
-
// - NEVER remove wraps/placeholders here (no DOM deletion of ads).
|
|
1363
|
-
// - Only call showAds ONCE per placeholder per page lifetime (unless the placeholder is truly empty).
|
|
1364
|
-
// - De-duplicate placeholders in DOM: if the same data-ezoic-id appears multiple times, keep the first.
|
|
1364
|
+
// This moves existing DOM nodes back (no placeholder recreation).
|
|
1365
1365
|
|
|
1366
1366
|
var BETWEEN_SELECTOR = '.nodebb-ezoic-wrap.ezoic-ad-between';
|
|
1367
1367
|
var MESSAGE_SELECTOR = '.nodebb-ezoic-wrap.ezoic-ad-message';
|
|
1368
1368
|
var WRAP_SELECTOR = BETWEEN_SELECTOR + ', ' + MESSAGE_SELECTOR;
|
|
1369
1369
|
|
|
1370
|
-
// show tuning (safe)
|
|
1371
1370
|
var MAX_SHOW_PER_TICK = 4;
|
|
1372
1371
|
|
|
1372
|
+
// validation throttles
|
|
1373
|
+
var ENFORCE_COOLDOWN_MS = 220;
|
|
1374
|
+
var lastEnforce = 0;
|
|
1375
|
+
|
|
1373
1376
|
// internal state
|
|
1374
|
-
var activatedById = Object.create(null);
|
|
1377
|
+
var activatedById = Object.create(null);
|
|
1375
1378
|
var showQueue = [];
|
|
1376
1379
|
var showTicking = false;
|
|
1377
1380
|
|
|
@@ -1388,7 +1391,6 @@ function buildOrdinalMap(items) {
|
|
|
1388
1391
|
|
|
1389
1392
|
function isFilled(w) {
|
|
1390
1393
|
try {
|
|
1391
|
-
// if Ezoic/Google already injected, there will be an iframe or an element with id starting google_ads_iframe
|
|
1392
1394
|
if (w.querySelector('iframe')) return true;
|
|
1393
1395
|
if (w.querySelector('[id^="google_ads_iframe"]')) return true;
|
|
1394
1396
|
if (w.querySelector('.ezoic-ad')) return true;
|
|
@@ -1398,9 +1400,7 @@ function buildOrdinalMap(items) {
|
|
|
1398
1400
|
|
|
1399
1401
|
function enqueueShow(id) {
|
|
1400
1402
|
if (!id) return;
|
|
1401
|
-
// show only once (avoid "already defined")
|
|
1402
1403
|
if (activatedById[id]) return;
|
|
1403
|
-
|
|
1404
1404
|
for (var i = 0; i < showQueue.length; i++) if (showQueue[i] === id) return;
|
|
1405
1405
|
showQueue.push(id);
|
|
1406
1406
|
scheduleShowTick();
|
|
@@ -1426,7 +1426,7 @@ function buildOrdinalMap(items) {
|
|
|
1426
1426
|
});
|
|
1427
1427
|
}
|
|
1428
1428
|
|
|
1429
|
-
// De-
|
|
1429
|
+
// --- De-dupe placeholders to avoid Ezoic warnings ---
|
|
1430
1430
|
function dedupePlaceholders() {
|
|
1431
1431
|
var seen = Object.create(null);
|
|
1432
1432
|
try {
|
|
@@ -1434,10 +1434,10 @@ function buildOrdinalMap(items) {
|
|
|
1434
1434
|
try {
|
|
1435
1435
|
var id = ph.getAttribute('data-ezoic-id');
|
|
1436
1436
|
if (!id) return;
|
|
1437
|
+
var wrap = ph.closest('.nodebb-ezoic-wrap');
|
|
1438
|
+
if (!wrap) return;
|
|
1437
1439
|
if (seen[id]) {
|
|
1438
|
-
|
|
1439
|
-
var wrap = ph.closest('.nodebb-ezoic-wrap');
|
|
1440
|
-
if (wrap) wrap.remove();
|
|
1440
|
+
wrap.remove();
|
|
1441
1441
|
} else {
|
|
1442
1442
|
seen[id] = true;
|
|
1443
1443
|
}
|
|
@@ -1446,7 +1446,124 @@ function buildOrdinalMap(items) {
|
|
|
1446
1446
|
} catch (e) {}
|
|
1447
1447
|
}
|
|
1448
1448
|
|
|
1449
|
-
//
|
|
1449
|
+
// --- Position Enforcer ---
|
|
1450
|
+
function ensureUid(w) {
|
|
1451
|
+
try {
|
|
1452
|
+
var uid = w.getAttribute('data-ezoic-wrapuid');
|
|
1453
|
+
if (!uid) {
|
|
1454
|
+
uid = String(Date.now()) + '-' + Math.floor(Math.random() * 1e9);
|
|
1455
|
+
w.setAttribute('data-ezoic-wrapuid', uid);
|
|
1456
|
+
}
|
|
1457
|
+
return uid;
|
|
1458
|
+
} catch (e) { return null; }
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
function findHostForWrap(w) {
|
|
1462
|
+
// Host should be a stable post/topic element, NOT the wrap itself.
|
|
1463
|
+
// Heuristics: previous siblings that look like topic/post items.
|
|
1464
|
+
try {
|
|
1465
|
+
var cur = w.previousElementSibling;
|
|
1466
|
+
// walk backward a bit
|
|
1467
|
+
for (var i = 0; i < 18 && cur; i++) {
|
|
1468
|
+
if (cur.classList && (cur.classList.contains('topic-item') || cur.classList.contains('posts-list-item') || cur.classList.contains('post') || cur.classList.contains('category-item'))) {
|
|
1469
|
+
return cur;
|
|
1470
|
+
}
|
|
1471
|
+
if (cur.getAttribute) {
|
|
1472
|
+
if (cur.getAttribute('data-pid') || cur.getAttribute('data-tid') || cur.getAttribute('data-topic-id') || cur.getAttribute('data-index')) return cur;
|
|
1473
|
+
}
|
|
1474
|
+
cur = cur.previousElementSibling;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
// fallback: walk up from wrap to find nearest list container, then approximate by data-ezoic-after index
|
|
1478
|
+
var afterPos = parseInt(w.getAttribute('data-ezoic-after') || '0', 10) || 0;
|
|
1479
|
+
if (afterPos > 0) {
|
|
1480
|
+
var list = w.parentElement;
|
|
1481
|
+
for (var up = 0; up < 6 && list && list !== document.body; up++) {
|
|
1482
|
+
if (list.classList && (list.classList.contains('topic-list') || list.classList.contains('topics') || list.classList.contains('posts') || list.classList.contains('category'))) break;
|
|
1483
|
+
list = list.parentElement;
|
|
1484
|
+
}
|
|
1485
|
+
if (list && list.querySelectorAll) {
|
|
1486
|
+
var items = list.querySelectorAll('.topic-item, .posts-list-item, .post, [data-pid], [data-tid], [data-topic-id]');
|
|
1487
|
+
if (items && items.length >= afterPos) {
|
|
1488
|
+
return items[Math.min(items.length - 1, afterPos - 1)];
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
} catch (e) {}
|
|
1493
|
+
return null;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
function ensureMarkerInHost(w) {
|
|
1497
|
+
try {
|
|
1498
|
+
var uid = ensureUid(w);
|
|
1499
|
+
if (!uid) return;
|
|
1500
|
+
|
|
1501
|
+
var markerId = w.getAttribute('data-ezoic-markerid');
|
|
1502
|
+
if (markerId) {
|
|
1503
|
+
var existing = document.getElementById(markerId);
|
|
1504
|
+
if (existing) return;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
var host = findHostForWrap(w);
|
|
1508
|
+
if (!host) return;
|
|
1509
|
+
|
|
1510
|
+
markerId = 'nodebb-ezoic-marker-' + uid;
|
|
1511
|
+
// if already exists somewhere else, reuse
|
|
1512
|
+
var m = document.getElementById(markerId);
|
|
1513
|
+
if (!m) {
|
|
1514
|
+
m = document.createElement('span');
|
|
1515
|
+
m.id = markerId;
|
|
1516
|
+
m.className = 'nodebb-ezoic-marker';
|
|
1517
|
+
m.setAttribute('data-marker-for', uid);
|
|
1518
|
+
m.style.display = 'none';
|
|
1519
|
+
host.appendChild(m);
|
|
1520
|
+
} else {
|
|
1521
|
+
// ensure marker is inside host (if moved, re-append)
|
|
1522
|
+
if (m.parentElement !== host) host.appendChild(m);
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
w.setAttribute('data-ezoic-markerid', markerId);
|
|
1526
|
+
} catch (e) {}
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
function insertAfter(ref, node) {
|
|
1530
|
+
try {
|
|
1531
|
+
if (!ref || !ref.parentNode || !node) return;
|
|
1532
|
+
if (ref.nextSibling) ref.parentNode.insertBefore(node, ref.nextSibling);
|
|
1533
|
+
else ref.parentNode.appendChild(node);
|
|
1534
|
+
} catch (e) {}
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
function enforcePositions() {
|
|
1538
|
+
var now = Date.now();
|
|
1539
|
+
if (now - lastEnforce < ENFORCE_COOLDOWN_MS) return;
|
|
1540
|
+
lastEnforce = now;
|
|
1541
|
+
|
|
1542
|
+
try {
|
|
1543
|
+
var wraps = document.querySelectorAll('.nodebb-ezoic-wrap');
|
|
1544
|
+
for (var i = 0; i < wraps.length; i++) {
|
|
1545
|
+
var w = wraps[i];
|
|
1546
|
+
try {
|
|
1547
|
+
ensureMarkerInHost(w);
|
|
1548
|
+
|
|
1549
|
+
var markerId = w.getAttribute('data-ezoic-markerid');
|
|
1550
|
+
if (!markerId) continue;
|
|
1551
|
+
|
|
1552
|
+
var marker = document.getElementById(markerId);
|
|
1553
|
+
if (!marker || !marker.parentElement) continue;
|
|
1554
|
+
|
|
1555
|
+
var host = marker.parentElement;
|
|
1556
|
+
// desired: wrap should be directly after host (as sibling)
|
|
1557
|
+
if (!host.parentElement) continue;
|
|
1558
|
+
if (w.parentElement !== host.parentElement || w.previousElementSibling !== host) {
|
|
1559
|
+
insertAfter(host, w);
|
|
1560
|
+
}
|
|
1561
|
+
} catch (e) {}
|
|
1562
|
+
}
|
|
1563
|
+
} catch (e) {}
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
// --- Visibility: trigger show once if empty ---
|
|
1450
1567
|
var io = null;
|
|
1451
1568
|
function installIO() {
|
|
1452
1569
|
if (io || typeof IntersectionObserver === 'undefined') return;
|
|
@@ -1455,8 +1572,11 @@ function buildOrdinalMap(items) {
|
|
|
1455
1572
|
try {
|
|
1456
1573
|
entries.forEach(function (e) {
|
|
1457
1574
|
if (!e || !e.target) return;
|
|
1575
|
+
|
|
1576
|
+
// ensure host marker on sight
|
|
1577
|
+
ensureMarkerInHost(e.target);
|
|
1578
|
+
|
|
1458
1579
|
if (e.isIntersecting) {
|
|
1459
|
-
// If the slot is already filled, mark it as activated to prevent re-define attempts.
|
|
1460
1580
|
var id = getId(e.target);
|
|
1461
1581
|
if (!id) return;
|
|
1462
1582
|
|
|
@@ -1470,20 +1590,19 @@ function buildOrdinalMap(items) {
|
|
|
1470
1590
|
} catch (e) {}
|
|
1471
1591
|
}, { root: null, rootMargin: '1200px 0px 1200px 0px', threshold: 0.01 });
|
|
1472
1592
|
|
|
1473
|
-
try { document.querySelectorAll(WRAP_SELECTOR).forEach(function (w) { try { io.observe(w); } catch(e) {} }); } catch (e) {}
|
|
1593
|
+
try { document.querySelectorAll(WRAP_SELECTOR).forEach(function (w) { try { ensureMarkerInHost(w); io.observe(w); } catch(e) {} }); } catch (e) {}
|
|
1474
1594
|
}
|
|
1475
1595
|
|
|
1476
|
-
// Observe newly added wraps and
|
|
1596
|
+
// Observe newly added wraps and marker them
|
|
1477
1597
|
var moInstalled = false;
|
|
1478
1598
|
function installMO() {
|
|
1479
1599
|
if (moInstalled || typeof MutationObserver === 'undefined') return;
|
|
1480
1600
|
moInstalled = true;
|
|
1481
1601
|
|
|
1482
1602
|
var mo = new MutationObserver(function (muts) {
|
|
1483
|
-
// dedupe quickly, then observe new wraps
|
|
1484
1603
|
try { dedupePlaceholders(); } catch (e) {}
|
|
1485
|
-
|
|
1486
1604
|
if (!io) return;
|
|
1605
|
+
|
|
1487
1606
|
try {
|
|
1488
1607
|
for (var i = 0; i < muts.length; i++) {
|
|
1489
1608
|
var m = muts[i];
|
|
@@ -1493,34 +1612,40 @@ function buildOrdinalMap(items) {
|
|
|
1493
1612
|
if (!n || n.nodeType !== 1) continue;
|
|
1494
1613
|
|
|
1495
1614
|
if (n.matches && n.matches(WRAP_SELECTOR)) {
|
|
1615
|
+
ensureMarkerInHost(n);
|
|
1496
1616
|
try { io.observe(n); } catch (e) {}
|
|
1497
|
-
// eager show if empty
|
|
1498
1617
|
var id = getId(n);
|
|
1499
1618
|
if (id && !isFilled(n)) enqueueShow(id);
|
|
1500
1619
|
else if (id) activatedById[id] = activatedById[id] || Date.now();
|
|
1501
1620
|
} else if (n.querySelectorAll) {
|
|
1502
1621
|
var inner = n.querySelectorAll(WRAP_SELECTOR);
|
|
1503
1622
|
for (var k = 0; k < inner.length; k++) {
|
|
1623
|
+
ensureMarkerInHost(inner[k]);
|
|
1504
1624
|
try { io.observe(inner[k]); } catch (e) {}
|
|
1505
1625
|
}
|
|
1506
1626
|
}
|
|
1507
1627
|
}
|
|
1508
1628
|
}
|
|
1509
1629
|
} catch (e) {}
|
|
1630
|
+
|
|
1631
|
+
// enforce after mutations (cheap throttle will apply)
|
|
1632
|
+
enforcePositions();
|
|
1510
1633
|
});
|
|
1511
1634
|
|
|
1512
1635
|
try { mo.observe(document.documentElement || document.body, { childList: true, subtree: true }); } catch (e) {}
|
|
1513
1636
|
}
|
|
1514
1637
|
|
|
1515
1638
|
function init() {
|
|
1516
|
-
// 1) dedupe existing
|
|
1517
1639
|
dedupePlaceholders();
|
|
1518
1640
|
|
|
1519
|
-
|
|
1641
|
+
try {
|
|
1642
|
+
document.querySelectorAll('.nodebb-ezoic-wrap').forEach(function (w) { ensureMarkerInHost(w); });
|
|
1643
|
+
} catch (e) {}
|
|
1644
|
+
|
|
1520
1645
|
installIO();
|
|
1521
1646
|
installMO();
|
|
1522
1647
|
|
|
1523
|
-
//
|
|
1648
|
+
// initial eager show (bounded)
|
|
1524
1649
|
try {
|
|
1525
1650
|
var vh = window.innerHeight || document.documentElement.clientHeight || 0;
|
|
1526
1651
|
var margin = 900;
|
|
@@ -1528,6 +1653,7 @@ function buildOrdinalMap(items) {
|
|
|
1528
1653
|
var budget = 12;
|
|
1529
1654
|
for (var i = 0; i < wraps.length && budget > 0; i++) {
|
|
1530
1655
|
var w = wraps[i];
|
|
1656
|
+
ensureMarkerInHost(w);
|
|
1531
1657
|
var r = w.getBoundingClientRect();
|
|
1532
1658
|
if (r.bottom >= -margin && r.top <= (vh + margin)) {
|
|
1533
1659
|
var id = getId(w);
|
|
@@ -1540,19 +1666,28 @@ function buildOrdinalMap(items) {
|
|
|
1540
1666
|
}
|
|
1541
1667
|
} catch (e) {}
|
|
1542
1668
|
|
|
1543
|
-
window.addEventListener('scroll',
|
|
1544
|
-
|
|
1669
|
+
window.addEventListener('scroll', function () {
|
|
1670
|
+
enforcePositions();
|
|
1671
|
+
scheduleShowTick();
|
|
1672
|
+
}, { passive: true });
|
|
1673
|
+
window.addEventListener('resize', function () {
|
|
1674
|
+
enforcePositions();
|
|
1675
|
+
scheduleShowTick();
|
|
1676
|
+
}, { passive: true });
|
|
1545
1677
|
|
|
1546
1678
|
if (window.jQuery) {
|
|
1547
1679
|
window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function () {
|
|
1548
1680
|
setTimeout(function () {
|
|
1549
1681
|
dedupePlaceholders();
|
|
1682
|
+
try { document.querySelectorAll('.nodebb-ezoic-wrap').forEach(function (w) { ensureMarkerInHost(w); }); } catch (e) {}
|
|
1683
|
+
enforcePositions();
|
|
1550
1684
|
scheduleShowTick();
|
|
1551
1685
|
}, 0);
|
|
1552
1686
|
});
|
|
1553
1687
|
}
|
|
1554
1688
|
|
|
1555
|
-
|
|
1689
|
+
setInterval(enforcePositions, 1000);
|
|
1690
|
+
setTimeout(function () { enforcePositions(); scheduleShowTick(); }, 0);
|
|
1556
1691
|
}
|
|
1557
1692
|
|
|
1558
1693
|
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
|
@@ -1564,3 +1699,4 @@ function buildOrdinalMap(items) {
|
|
|
1564
1699
|
|
|
1565
1700
|
|
|
1566
1701
|
|
|
1702
|
+
|