nodebb-plugin-ezoic-infinite 1.6.5 → 1.6.6
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 +128 -31
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1348,30 +1348,35 @@ 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
|
-
// -
|
|
1357
|
-
//
|
|
1358
|
-
// Root cause: calling showAds repeatedly for the same placeholder id and/or
|
|
1359
|
-
// removing/recreating wrappers with the same IDs causes Ezoic to treat them as re-defined.
|
|
1354
|
+
// v2.4 (anchor-guard):
|
|
1355
|
+
// Issue reported: when scrolling back up, ad wraps accumulate before the first post.
|
|
1356
|
+
// Root cause (most likely): some script/virtualization detaches ad nodes from their original place and
|
|
1357
|
+
// re-inserts them near the top, without their original context.
|
|
1360
1358
|
//
|
|
1361
1359
|
// Fix:
|
|
1362
|
-
// -
|
|
1363
|
-
// -
|
|
1364
|
-
//
|
|
1360
|
+
// - On creation of each wrap, insert a hidden "anchor" node right before it and tag the wrap with that anchor id.
|
|
1361
|
+
// - Periodically validate: if a wrap is no longer immediately preceded by its anchor, remove the wrap.
|
|
1362
|
+
// (We do NOT recreate here; the normal injector will insert correct wraps as needed.)
|
|
1363
|
+
//
|
|
1364
|
+
// We also keep v2.3 no-redefine rules:
|
|
1365
|
+
// - no wrap deletion for cleanup except for misplaced wraps / duplicate placeholders
|
|
1366
|
+
// - showAds only once per placeholder id
|
|
1365
1367
|
|
|
1366
1368
|
var BETWEEN_SELECTOR = '.nodebb-ezoic-wrap.ezoic-ad-between';
|
|
1367
1369
|
var MESSAGE_SELECTOR = '.nodebb-ezoic-wrap.ezoic-ad-message';
|
|
1368
1370
|
var WRAP_SELECTOR = BETWEEN_SELECTOR + ', ' + MESSAGE_SELECTOR;
|
|
1369
1371
|
|
|
1370
|
-
// show tuning (safe)
|
|
1371
1372
|
var MAX_SHOW_PER_TICK = 4;
|
|
1372
1373
|
|
|
1374
|
+
// validation throttles
|
|
1375
|
+
var VALIDATE_COOLDOWN_MS = 260;
|
|
1376
|
+
var lastValidate = 0;
|
|
1377
|
+
|
|
1373
1378
|
// internal state
|
|
1374
|
-
var activatedById = Object.create(null);
|
|
1379
|
+
var activatedById = Object.create(null);
|
|
1375
1380
|
var showQueue = [];
|
|
1376
1381
|
var showTicking = false;
|
|
1377
1382
|
|
|
@@ -1388,7 +1393,6 @@ function buildOrdinalMap(items) {
|
|
|
1388
1393
|
|
|
1389
1394
|
function isFilled(w) {
|
|
1390
1395
|
try {
|
|
1391
|
-
// if Ezoic/Google already injected, there will be an iframe or an element with id starting google_ads_iframe
|
|
1392
1396
|
if (w.querySelector('iframe')) return true;
|
|
1393
1397
|
if (w.querySelector('[id^="google_ads_iframe"]')) return true;
|
|
1394
1398
|
if (w.querySelector('.ezoic-ad')) return true;
|
|
@@ -1398,9 +1402,7 @@ function buildOrdinalMap(items) {
|
|
|
1398
1402
|
|
|
1399
1403
|
function enqueueShow(id) {
|
|
1400
1404
|
if (!id) return;
|
|
1401
|
-
// show only once (avoid "already defined")
|
|
1402
1405
|
if (activatedById[id]) return;
|
|
1403
|
-
|
|
1404
1406
|
for (var i = 0; i < showQueue.length; i++) if (showQueue[i] === id) return;
|
|
1405
1407
|
showQueue.push(id);
|
|
1406
1408
|
scheduleShowTick();
|
|
@@ -1426,7 +1428,78 @@ function buildOrdinalMap(items) {
|
|
|
1426
1428
|
});
|
|
1427
1429
|
}
|
|
1428
1430
|
|
|
1429
|
-
//
|
|
1431
|
+
// --- Anchor guard ---
|
|
1432
|
+
function ensureAnchor(w) {
|
|
1433
|
+
try {
|
|
1434
|
+
if (!w || !w.parentNode) return;
|
|
1435
|
+
if (w.getAttribute('data-ezoic-anchored') === '1') return;
|
|
1436
|
+
|
|
1437
|
+
var wrapUid = w.getAttribute('data-ezoic-wrapuid');
|
|
1438
|
+
if (!wrapUid) {
|
|
1439
|
+
wrapUid = String(Date.now()) + '-' + Math.floor(Math.random() * 1e9);
|
|
1440
|
+
w.setAttribute('data-ezoic-wrapuid', wrapUid);
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// If already preceded by matching anchor, mark anchored.
|
|
1444
|
+
var prev = w.previousSibling;
|
|
1445
|
+
if (prev && prev.nodeType === 1 && prev.classList && prev.classList.contains('nodebb-ezoic-anchor')) {
|
|
1446
|
+
if (prev.getAttribute('data-anchor-for') === wrapUid) {
|
|
1447
|
+
w.setAttribute('data-ezoic-anchored', '1');
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
// Create anchor node
|
|
1453
|
+
var a = document.createElement('span');
|
|
1454
|
+
a.className = 'nodebb-ezoic-anchor';
|
|
1455
|
+
a.setAttribute('data-anchor-for', wrapUid);
|
|
1456
|
+
a.style.display = 'none';
|
|
1457
|
+
|
|
1458
|
+
w.parentNode.insertBefore(a, w);
|
|
1459
|
+
w.setAttribute('data-ezoic-anchored', '1');
|
|
1460
|
+
} catch (e) {}
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
function validateAnchors() {
|
|
1464
|
+
var now = Date.now();
|
|
1465
|
+
if (now - lastValidate < VALIDATE_COOLDOWN_MS) return;
|
|
1466
|
+
lastValidate = now;
|
|
1467
|
+
|
|
1468
|
+
try {
|
|
1469
|
+
// Remove wraps that lost their anchor adjacency (they have been moved)
|
|
1470
|
+
var wraps = document.querySelectorAll('.nodebb-ezoic-wrap');
|
|
1471
|
+
for (var i = 0; i < wraps.length; i++) {
|
|
1472
|
+
var w = wraps[i];
|
|
1473
|
+
try {
|
|
1474
|
+
var uid = w.getAttribute('data-ezoic-wrapuid');
|
|
1475
|
+
if (!uid) {
|
|
1476
|
+
// If it's an old wrap with no uid, anchor it once.
|
|
1477
|
+
ensureAnchor(w);
|
|
1478
|
+
continue;
|
|
1479
|
+
}
|
|
1480
|
+
var prev = w.previousSibling;
|
|
1481
|
+
if (!(prev && prev.nodeType === 1 && prev.classList && prev.classList.contains('nodebb-ezoic-anchor') && prev.getAttribute('data-anchor-for') === uid)) {
|
|
1482
|
+
// Misplaced wrap -> remove it (prevents pile-up before first post)
|
|
1483
|
+
w.remove();
|
|
1484
|
+
}
|
|
1485
|
+
} catch (e) {}
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
// Remove orphan anchors (anchor without following wrap)
|
|
1489
|
+
var anchors = document.querySelectorAll('.nodebb-ezoic-anchor');
|
|
1490
|
+
for (var j = 0; j < anchors.length; j++) {
|
|
1491
|
+
var a = anchors[j];
|
|
1492
|
+
try {
|
|
1493
|
+
var next = a.nextSibling;
|
|
1494
|
+
if (!(next && next.nodeType === 1 && next.classList && next.classList.contains('nodebb-ezoic-wrap'))) {
|
|
1495
|
+
a.remove();
|
|
1496
|
+
}
|
|
1497
|
+
} catch (e) {}
|
|
1498
|
+
}
|
|
1499
|
+
} catch (e) {}
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
// --- De-dupe placeholders to avoid Ezoic warnings ---
|
|
1430
1503
|
function dedupePlaceholders() {
|
|
1431
1504
|
var seen = Object.create(null);
|
|
1432
1505
|
try {
|
|
@@ -1434,10 +1507,15 @@ function buildOrdinalMap(items) {
|
|
|
1434
1507
|
try {
|
|
1435
1508
|
var id = ph.getAttribute('data-ezoic-id');
|
|
1436
1509
|
if (!id) return;
|
|
1510
|
+
var wrap = ph.closest('.nodebb-ezoic-wrap');
|
|
1511
|
+
if (!wrap) return;
|
|
1512
|
+
|
|
1513
|
+
// ensure anchor for any wrap we touch
|
|
1514
|
+
ensureAnchor(wrap);
|
|
1515
|
+
|
|
1437
1516
|
if (seen[id]) {
|
|
1438
|
-
// remove
|
|
1439
|
-
|
|
1440
|
-
if (wrap) wrap.remove();
|
|
1517
|
+
// remove duplicates; keep first occurrence
|
|
1518
|
+
wrap.remove();
|
|
1441
1519
|
} else {
|
|
1442
1520
|
seen[id] = true;
|
|
1443
1521
|
}
|
|
@@ -1446,7 +1524,7 @@ function buildOrdinalMap(items) {
|
|
|
1446
1524
|
} catch (e) {}
|
|
1447
1525
|
}
|
|
1448
1526
|
|
|
1449
|
-
//
|
|
1527
|
+
// --- Visibility: trigger show once if empty ---
|
|
1450
1528
|
var io = null;
|
|
1451
1529
|
function installIO() {
|
|
1452
1530
|
if (io || typeof IntersectionObserver === 'undefined') return;
|
|
@@ -1455,8 +1533,11 @@ function buildOrdinalMap(items) {
|
|
|
1455
1533
|
try {
|
|
1456
1534
|
entries.forEach(function (e) {
|
|
1457
1535
|
if (!e || !e.target) return;
|
|
1536
|
+
|
|
1537
|
+
// Always ensure anchor while visible/near
|
|
1538
|
+
ensureAnchor(e.target);
|
|
1539
|
+
|
|
1458
1540
|
if (e.isIntersecting) {
|
|
1459
|
-
// If the slot is already filled, mark it as activated to prevent re-define attempts.
|
|
1460
1541
|
var id = getId(e.target);
|
|
1461
1542
|
if (!id) return;
|
|
1462
1543
|
|
|
@@ -1470,17 +1551,16 @@ function buildOrdinalMap(items) {
|
|
|
1470
1551
|
} catch (e) {}
|
|
1471
1552
|
}, { root: null, rootMargin: '1200px 0px 1200px 0px', threshold: 0.01 });
|
|
1472
1553
|
|
|
1473
|
-
try { document.querySelectorAll(WRAP_SELECTOR).forEach(function (w) { try { io.observe(w); } catch(e) {} }); } catch (e) {}
|
|
1554
|
+
try { document.querySelectorAll(WRAP_SELECTOR).forEach(function (w) { try { ensureAnchor(w); io.observe(w); } catch(e) {} }); } catch (e) {}
|
|
1474
1555
|
}
|
|
1475
1556
|
|
|
1476
|
-
// Observe newly added wraps and
|
|
1557
|
+
// Observe newly added wraps and anchor them
|
|
1477
1558
|
var moInstalled = false;
|
|
1478
1559
|
function installMO() {
|
|
1479
1560
|
if (moInstalled || typeof MutationObserver === 'undefined') return;
|
|
1480
1561
|
moInstalled = true;
|
|
1481
1562
|
|
|
1482
1563
|
var mo = new MutationObserver(function (muts) {
|
|
1483
|
-
// dedupe quickly, then observe new wraps
|
|
1484
1564
|
try { dedupePlaceholders(); } catch (e) {}
|
|
1485
1565
|
|
|
1486
1566
|
if (!io) return;
|
|
@@ -1493,14 +1573,15 @@ function buildOrdinalMap(items) {
|
|
|
1493
1573
|
if (!n || n.nodeType !== 1) continue;
|
|
1494
1574
|
|
|
1495
1575
|
if (n.matches && n.matches(WRAP_SELECTOR)) {
|
|
1576
|
+
ensureAnchor(n);
|
|
1496
1577
|
try { io.observe(n); } catch (e) {}
|
|
1497
|
-
// eager show if empty
|
|
1498
1578
|
var id = getId(n);
|
|
1499
1579
|
if (id && !isFilled(n)) enqueueShow(id);
|
|
1500
1580
|
else if (id) activatedById[id] = activatedById[id] || Date.now();
|
|
1501
1581
|
} else if (n.querySelectorAll) {
|
|
1502
1582
|
var inner = n.querySelectorAll(WRAP_SELECTOR);
|
|
1503
1583
|
for (var k = 0; k < inner.length; k++) {
|
|
1584
|
+
ensureAnchor(inner[k]);
|
|
1504
1585
|
try { io.observe(inner[k]); } catch (e) {}
|
|
1505
1586
|
}
|
|
1506
1587
|
}
|
|
@@ -1513,14 +1594,16 @@ function buildOrdinalMap(items) {
|
|
|
1513
1594
|
}
|
|
1514
1595
|
|
|
1515
1596
|
function init() {
|
|
1516
|
-
//
|
|
1597
|
+
// anchor + dedupe existing
|
|
1598
|
+
try {
|
|
1599
|
+
document.querySelectorAll('.nodebb-ezoic-wrap').forEach(function (w) { ensureAnchor(w); });
|
|
1600
|
+
} catch (e) {}
|
|
1517
1601
|
dedupePlaceholders();
|
|
1518
1602
|
|
|
1519
|
-
// 2) install observers
|
|
1520
1603
|
installIO();
|
|
1521
1604
|
installMO();
|
|
1522
1605
|
|
|
1523
|
-
//
|
|
1606
|
+
// initial eager show for empty visible-ish wraps (bounded)
|
|
1524
1607
|
try {
|
|
1525
1608
|
var vh = window.innerHeight || document.documentElement.clientHeight || 0;
|
|
1526
1609
|
var margin = 900;
|
|
@@ -1528,6 +1611,7 @@ function buildOrdinalMap(items) {
|
|
|
1528
1611
|
var budget = 12;
|
|
1529
1612
|
for (var i = 0; i < wraps.length && budget > 0; i++) {
|
|
1530
1613
|
var w = wraps[i];
|
|
1614
|
+
ensureAnchor(w);
|
|
1531
1615
|
var r = w.getBoundingClientRect();
|
|
1532
1616
|
if (r.bottom >= -margin && r.top <= (vh + margin)) {
|
|
1533
1617
|
var id = getId(w);
|
|
@@ -1540,19 +1624,31 @@ function buildOrdinalMap(items) {
|
|
|
1540
1624
|
}
|
|
1541
1625
|
} catch (e) {}
|
|
1542
1626
|
|
|
1543
|
-
|
|
1544
|
-
window.addEventListener('
|
|
1627
|
+
// validate regularly on scroll/resize (cheap)
|
|
1628
|
+
window.addEventListener('scroll', function () {
|
|
1629
|
+
validateAnchors();
|
|
1630
|
+
scheduleShowTick();
|
|
1631
|
+
}, { passive: true });
|
|
1632
|
+
window.addEventListener('resize', function () {
|
|
1633
|
+
validateAnchors();
|
|
1634
|
+
scheduleShowTick();
|
|
1635
|
+
}, { passive: true });
|
|
1545
1636
|
|
|
1546
1637
|
if (window.jQuery) {
|
|
1547
1638
|
window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function () {
|
|
1548
1639
|
setTimeout(function () {
|
|
1640
|
+
try { document.querySelectorAll('.nodebb-ezoic-wrap').forEach(function (w) { ensureAnchor(w); }); } catch (e) {}
|
|
1549
1641
|
dedupePlaceholders();
|
|
1642
|
+
validateAnchors();
|
|
1550
1643
|
scheduleShowTick();
|
|
1551
1644
|
}, 0);
|
|
1552
1645
|
});
|
|
1553
1646
|
}
|
|
1554
1647
|
|
|
1555
|
-
|
|
1648
|
+
// periodic validate safety net
|
|
1649
|
+
setInterval(validateAnchors, 1200);
|
|
1650
|
+
|
|
1651
|
+
setTimeout(function () { validateAnchors(); scheduleShowTick(); }, 0);
|
|
1556
1652
|
}
|
|
1557
1653
|
|
|
1558
1654
|
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
|
@@ -1564,3 +1660,4 @@ function buildOrdinalMap(items) {
|
|
|
1564
1660
|
|
|
1565
1661
|
|
|
1566
1662
|
|
|
1663
|
+
|