nodebb-plugin-ezoic-infinite 1.5.99 → 1.6.0

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.5.99",
3
+ "version": "1.6.0",
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
@@ -1344,92 +1344,114 @@ function buildOrdinalMap(items) {
1344
1344
 
1345
1345
 
1346
1346
 
1347
- // ===== V8 between-cap-per-window =====
1347
+ // ===== CLEAN REFRACTOR: visibility manager for Ezoic wraps =====
1348
1348
  (function () {
1349
- var ticking = false;
1350
- var lastRun = 0;
1351
- var RUN_COOLDOWN = 220; // ms
1349
+ var WRAP_SELECTOR = '.nodebb-ezoic-wrap.ezoic-ad-between, .nodebb-ezoic-wrap.ezoic-ad-message';
1350
+ var KEEP_MARGIN_PX_DESKTOP = 1600;
1351
+ var KEEP_MARGIN_PX_MOBILE = 1100;
1352
+ var MAX_REMOVALS_PER_SWEEP = 6;
1352
1353
 
1353
- // Keep at most N between-wraps per vertical band around viewport
1354
- var BAND_PX = 900;
1355
- var MAX_PER_BAND = 2;
1356
-
1357
- function capBetweenWraps() {
1358
- var now = Date.now();
1359
- if (now - lastRun < RUN_COOLDOWN) return;
1360
- lastRun = now;
1354
+ function isMobile() {
1355
+ try { return window.matchMedia && window.matchMedia('(max-width: 767px)').matches; } catch (e) { return false; }
1356
+ }
1357
+ function keepMargin() { return isMobile() ? KEEP_MARGIN_PX_MOBILE : KEEP_MARGIN_PX_DESKTOP; }
1361
1358
 
1359
+ function removeFarWraps() {
1360
+ var margin = keepMargin();
1361
+ var removed = 0;
1362
1362
  var wraps;
1363
- try { wraps = Array.prototype.slice.call(document.querySelectorAll('.nodebb-ezoic-wrap.ezoic-ad-between')); }
1364
- catch (e) { return; }
1365
-
1366
- if (!wraps.length) return;
1367
-
1368
- var y = window.pageYOffset || document.documentElement.scrollTop || 0;
1369
- var viewportTop = y;
1370
- var viewportBottom = y + (window.innerHeight || document.documentElement.clientHeight || 0);
1371
-
1372
- // Priorité: conserver ce qui est proche/visible, limiter le reste par bande
1373
- var buckets = Object.create(null);
1374
-
1363
+ try { wraps = document.querySelectorAll(WRAP_SELECTOR); } catch (e) { return; }
1375
1364
  wraps.forEach(function (w) {
1365
+ if (removed >= MAX_REMOVALS_PER_SWEEP) return;
1376
1366
  try {
1367
+ var lv = parseInt(w.getAttribute('data-last-visible') || '0', 10);
1368
+ if (lv && (Date.now() - lv) < 8000) return;
1369
+
1377
1370
  var r = w.getBoundingClientRect();
1378
- var absTop = y + r.top;
1379
- var absBottom = y + r.bottom;
1380
-
1381
- var inOrNearViewport = (absBottom >= viewportTop - 200) && (absTop <= viewportBottom + 200);
1382
- var band = Math.floor(absTop / BAND_PX);
1383
- var key = String(band);
1384
-
1385
- if (!buckets[key]) buckets[key] = [];
1386
- buckets[key].push({
1387
- node: w,
1388
- absTop: absTop,
1389
- absBottom: absBottom,
1390
- inOrNearViewport: inOrNearViewport
1391
- });
1371
+ if (r.bottom < -margin || r.top > ((window.innerHeight || 0) + margin)) {
1372
+ w.remove();
1373
+ removed += 1;
1374
+ }
1392
1375
  } catch (e) {}
1393
1376
  });
1377
+ }
1394
1378
 
1395
- Object.keys(buckets).forEach(function (k) {
1396
- var arr = buckets[k];
1397
- // garde d'abord proche/visible, puis les plus récents (data-created), puis position
1398
- arr.sort(function (a, b) {
1399
- if (a.inOrNearViewport !== b.inOrNearViewport) return a.inOrNearViewport ? -1 : 1;
1400
- var ac = parseInt((a.node.getAttribute('data-created') || '0'), 10);
1401
- var bc = parseInt((b.node.getAttribute('data-created') || '0'), 10);
1402
- if (ac !== bc) return bc - ac; // garder plus récent
1403
- return a.absTop - b.absTop;
1404
- });
1379
+ var io = null;
1380
+ function installIO() {
1381
+ if (io || typeof IntersectionObserver === 'undefined') return;
1382
+ io = new IntersectionObserver(function (entries) {
1383
+ try {
1384
+ entries.forEach(function (e) {
1385
+ if (e && e.target && e.isIntersecting) {
1386
+ try { e.target.setAttribute('data-last-visible', String(Date.now())); } catch (err) {}
1387
+ }
1388
+ });
1389
+ } catch (e) {}
1390
+ }, { root: null, rootMargin: '0px', threshold: 0.01 });
1405
1391
 
1406
- for (var i = MAX_PER_BAND; i < arr.length; i++) {
1407
- try { arr[i].node.remove(); } catch (e) {}
1408
- }
1392
+ try { document.querySelectorAll(WRAP_SELECTOR).forEach(function (w) { try { io.observe(w); } catch(e) {} }); } catch (e) {}
1393
+ }
1394
+
1395
+ var moInstalled = false;
1396
+ function installMO() {
1397
+ if (moInstalled || typeof MutationObserver === 'undefined') return;
1398
+ moInstalled = true;
1399
+ var mo = new MutationObserver(function (muts) {
1400
+ if (!io) return;
1401
+ try {
1402
+ for (var i = 0; i < muts.length; i++) {
1403
+ var m = muts[i];
1404
+ if (!m.addedNodes) continue;
1405
+ for (var j = 0; j < m.addedNodes.length; j++) {
1406
+ var n = m.addedNodes[j];
1407
+ if (!n || n.nodeType !== 1) continue;
1408
+ if (n.matches && n.matches(WRAP_SELECTOR)) {
1409
+ try { io.observe(n); } catch (e) {}
1410
+ } else if (n.querySelectorAll) {
1411
+ var inner = n.querySelectorAll(WRAP_SELECTOR);
1412
+ for (var k = 0; k < inner.length; k++) {
1413
+ try { io.observe(inner[k]); } catch (e) {}
1414
+ }
1415
+ }
1416
+ }
1417
+ }
1418
+ } catch (e) {}
1409
1419
  });
1420
+ try { mo.observe(document.documentElement || document.body, { childList: true, subtree: true }); } catch (e) {}
1410
1421
  }
1411
1422
 
1412
- function scheduleCap() {
1413
- if (ticking) return;
1414
- ticking = true;
1423
+ var sweepPending = false;
1424
+ var lastSweep = 0;
1425
+ var SWEEP_COOLDOWN_MS = 250;
1426
+
1427
+ function scheduleSweep() {
1428
+ var now = Date.now();
1429
+ if (now - lastSweep < SWEEP_COOLDOWN_MS) return;
1430
+ if (sweepPending) return;
1431
+ sweepPending = true;
1415
1432
  requestAnimationFrame(function () {
1416
- try { capBetweenWraps(); } catch (e) {}
1417
- ticking = false;
1433
+ sweepPending = false;
1434
+ lastSweep = Date.now();
1435
+ removeFarWraps();
1418
1436
  });
1419
1437
  }
1420
1438
 
1421
- window.addEventListener('scroll', scheduleCap, { passive: true });
1422
- window.addEventListener('resize', scheduleCap, { passive: true });
1439
+ function init() {
1440
+ installIO();
1441
+ installMO();
1442
+ window.addEventListener('scroll', scheduleSweep, { passive: true });
1443
+ window.addEventListener('resize', scheduleSweep, { passive: true });
1423
1444
 
1424
- if (window.jQuery) {
1425
- window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function () {
1426
- setTimeout(scheduleCap, 0);
1427
- setTimeout(scheduleCap, 200);
1428
- setTimeout(scheduleCap, 700);
1429
- });
1445
+ if (window.jQuery) {
1446
+ window.jQuery(window).on('action:ajaxify.end action:infiniteScroll.loaded', function () {
1447
+ setTimeout(function () { installIO(); scheduleSweep(); }, 0);
1448
+ });
1449
+ }
1450
+ setTimeout(function () { installIO(); scheduleSweep(); }, 0);
1430
1451
  }
1431
1452
 
1432
- setTimeout(scheduleCap, 0);
1453
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
1454
+ else init();
1433
1455
  })();
1434
- // ===== /V8 =====
1456
+ // ===== /CLEAN REFRACTOR =====
1435
1457
 
package/public/style.css CHANGED
@@ -79,3 +79,9 @@
79
79
  position: static !important;
80
80
  top: auto !important;
81
81
  }
82
+
83
+
84
+ /* ===== CLEAN REFRACTOR perf notes ===== */
85
+ .nodebb-ezoic-wrap { contain: content; }
86
+ /* ===== /CLEAN REFRACTOR ===== */
87
+