nodebb-plugin-ezoic-infinite 1.5.50 → 1.5.51
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 +36 -74
- package/public/style.css +8 -1
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -96,53 +96,11 @@
|
|
|
96
96
|
|
|
97
97
|
const insertingIds = new Set();
|
|
98
98
|
|
|
99
|
-
// ---------- lightweight "fade-in" for ad iframes ----------
|
|
100
|
-
// This reduces the perception of "flashing" when a slot appears empty then fills.
|
|
101
|
-
// We avoid scroll listeners and only react to DOM insertions.
|
|
102
|
-
const _faded = new WeakSet();
|
|
103
|
-
function _fadeInIframe(iframe) {
|
|
104
|
-
try {
|
|
105
|
-
if (!iframe || _faded.has(iframe)) return;
|
|
106
|
-
_faded.add(iframe);
|
|
107
|
-
iframe.style.opacity = '0';
|
|
108
|
-
iframe.style.transition = 'opacity 140ms ease';
|
|
109
|
-
// Next frame: show
|
|
110
|
-
requestAnimationFrame(() => {
|
|
111
|
-
try { iframe.style.opacity = '1'; } catch (e) {}
|
|
112
|
-
});
|
|
113
|
-
} catch (e) {}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const _adFillObserver = new MutationObserver((muts) => {
|
|
117
|
-
try {
|
|
118
|
-
for (const m of muts) {
|
|
119
|
-
if (m.addedNodes && m.addedNodes.length) {
|
|
120
|
-
for (const n of m.addedNodes) {
|
|
121
|
-
if (!n || n.nodeType !== 1) continue;
|
|
122
|
-
if (n.tagName === 'IFRAME') {
|
|
123
|
-
const w = n.closest && n.closest(`.${WRAP_CLASS}`);
|
|
124
|
-
if (w) _fadeInIframe(n);
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
// If a subtree is added, look for iframes inside ad wrappers only.
|
|
128
|
-
const ifs = n.querySelectorAll ? n.querySelectorAll(`.${WRAP_CLASS} iframe`) : null;
|
|
129
|
-
if (ifs && ifs.length) ifs.forEach(_fadeInIframe);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
} catch (e) {}
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
_adFillObserver.observe(document.documentElement, { subtree: true, childList: true });
|
|
138
|
-
} catch (e) {}
|
|
139
|
-
|
|
140
|
-
|
|
141
99
|
|
|
142
100
|
function markEmptyWrapper(id) {
|
|
143
101
|
try {
|
|
144
102
|
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
145
|
-
if (!ph || !ph.isConnected) return;
|
|
103
|
+
if (!ph || !ph.isConnected) { try { clearTimeout(hardTimer); } catch (e) {} release(); return; }
|
|
146
104
|
const wrap = ph.closest ? ph.closest(`.${WRAP_CLASS}`) : null;
|
|
147
105
|
if (!wrap) return;
|
|
148
106
|
// If still empty after a delay, collapse it.
|
|
@@ -247,18 +205,13 @@
|
|
|
247
205
|
['dns-prefetch', 'https://g.ezoic.net', false],
|
|
248
206
|
['preconnect', 'https://go.ezoic.net', true],
|
|
249
207
|
['dns-prefetch', 'https://go.ezoic.net', false],
|
|
250
|
-
|
|
251
|
-
// Google ad stack (helps Safeframe/GPT warm up)
|
|
208
|
+
// Google Ads / Safeframe warm-up (helps cold-start latency)
|
|
252
209
|
['preconnect', 'https://pagead2.googlesyndication.com', true],
|
|
253
210
|
['dns-prefetch', 'https://pagead2.googlesyndication.com', false],
|
|
254
211
|
['preconnect', 'https://securepubads.g.doubleclick.net', true],
|
|
255
212
|
['dns-prefetch', 'https://securepubads.g.doubleclick.net', false],
|
|
256
213
|
['preconnect', 'https://tpc.googlesyndication.com', true],
|
|
257
214
|
['dns-prefetch', 'https://tpc.googlesyndication.com', false],
|
|
258
|
-
['preconnect', 'https://googleads.g.doubleclick.net', true],
|
|
259
|
-
['dns-prefetch', 'https://googleads.g.doubleclick.net', false],
|
|
260
|
-
['preconnect', 'https://static.doubleclick.net', true],
|
|
261
|
-
['dns-prefetch', 'https://static.doubleclick.net', false],
|
|
262
215
|
];
|
|
263
216
|
for (const [rel, href, cors] of links) {
|
|
264
217
|
const key = `${rel}|${href}`;
|
|
@@ -286,7 +239,7 @@
|
|
|
286
239
|
const orig = ez.showAds;
|
|
287
240
|
|
|
288
241
|
ez.showAds = function (...args) {
|
|
289
|
-
if (isBlocked()) return;
|
|
242
|
+
if (isBlocked()) { try { clearTimeout(hardTimer); } catch (e) {} release(); return; }
|
|
290
243
|
|
|
291
244
|
let ids = [];
|
|
292
245
|
if (args.length === 1 && Array.isArray(args[0])) ids = args[0];
|
|
@@ -424,7 +377,7 @@ function withInternalDomChange(fn) {
|
|
|
424
377
|
window.setTimeout(() => {
|
|
425
378
|
try {
|
|
426
379
|
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
427
|
-
if (!ph || !ph.isConnected) return;
|
|
380
|
+
if (!ph || !ph.isConnected) { try { clearTimeout(hardTimer); } catch (e) {} release(); return; }
|
|
428
381
|
const wrap = ph.closest(`.${WRAP_CLASS}`);
|
|
429
382
|
if (!wrap) return;
|
|
430
383
|
const hasContent = ph.childElementCount > 0 || ph.offsetHeight > 0;
|
|
@@ -439,7 +392,6 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
439
392
|
wrap.className = `${WRAP_CLASS} ${kindClass}`;
|
|
440
393
|
wrap.setAttribute('data-ezoic-after', String(afterPos));
|
|
441
394
|
wrap.setAttribute('data-ezoic-wrapid', String(id));
|
|
442
|
-
wrap.setAttribute('data-ezoic-ts', String(Date.now()));
|
|
443
395
|
wrap.style.width = '100%';
|
|
444
396
|
|
|
445
397
|
const ph = document.createElement('div');
|
|
@@ -496,23 +448,14 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
496
448
|
const wraps = Array.from(document.querySelectorAll(`.${WRAP_CLASS}.${kindClass}`));
|
|
497
449
|
if (!wraps.length) return false;
|
|
498
450
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
// Only recycle wraps that are clearly out of view AND old enough.
|
|
502
|
-
// This avoids the "unstable" feeling where ads disappear when the user scrolls back a bit.
|
|
503
|
-
const MIN_AGE_MS = 20000; // 20s
|
|
504
|
-
const OFFSCREEN_PX = -5000; // far above viewport
|
|
505
|
-
|
|
451
|
+
// Prefer a wrap far above the viewport
|
|
506
452
|
let victim = null;
|
|
507
453
|
for (const w of wraps) {
|
|
508
454
|
const r = w.getBoundingClientRect();
|
|
509
|
-
|
|
510
|
-
const ageOk = !ts || (now - ts) >= MIN_AGE_MS;
|
|
511
|
-
if (ageOk && r.bottom < OFFSCREEN_PX) { victim = w; break; }
|
|
455
|
+
if (r.bottom < -2000) { victim = w; break; }
|
|
512
456
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
if (!victim) return false;
|
|
457
|
+
// Otherwise remove the earliest one in the document
|
|
458
|
+
if (!victim) victim = wraps[0];
|
|
516
459
|
|
|
517
460
|
// Unobserve placeholder if still observed
|
|
518
461
|
try {
|
|
@@ -547,7 +490,7 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
547
490
|
}
|
|
548
491
|
|
|
549
492
|
function drainQueue() {
|
|
550
|
-
if (isBlocked()) return;
|
|
493
|
+
if (isBlocked()) { try { clearTimeout(hardTimer); } catch (e) {} release(); return; }
|
|
551
494
|
const max = getMaxInflight();
|
|
552
495
|
while (state.inflight < max && state.pending.length) {
|
|
553
496
|
const id = state.pending.shift();
|
|
@@ -572,14 +515,14 @@ function startShow(id) {
|
|
|
572
515
|
|
|
573
516
|
requestAnimationFrame(() => {
|
|
574
517
|
try {
|
|
575
|
-
if (isBlocked()) return;
|
|
518
|
+
if (isBlocked()) { try { clearTimeout(hardTimer); } catch (e) {} release(); return; }
|
|
576
519
|
|
|
577
520
|
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
578
|
-
if (!ph || !ph.isConnected) return;
|
|
521
|
+
if (!ph || !ph.isConnected) { try { clearTimeout(hardTimer); } catch (e) {} release(); return; }
|
|
579
522
|
|
|
580
523
|
const now2 = Date.now();
|
|
581
524
|
const last2 = state.lastShowById.get(id) || 0;
|
|
582
|
-
if (now2 - last2 < 900) return;
|
|
525
|
+
if (now2 - last2 < 900) { try { clearTimeout(hardTimer); } catch (e) {} release(); return; }
|
|
583
526
|
state.lastShowById.set(id, now2);
|
|
584
527
|
|
|
585
528
|
window.ezstandalone = window.ezstandalone || {};
|
|
@@ -587,16 +530,35 @@ function startShow(id) {
|
|
|
587
530
|
|
|
588
531
|
const doShow = () => {
|
|
589
532
|
try {
|
|
533
|
+
// Re-check at execution time: ajaxify/infinite-scroll may have removed the placeholder.
|
|
534
|
+
const phNow = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
535
|
+
if (!phNow || !phNow.isConnected) {
|
|
536
|
+
try { clearTimeout(hardTimer); } catch (e) {}
|
|
537
|
+
release();
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
} catch (e) {}
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
// If we reused an id in this pageview, destroy first (use DOM id string form).
|
|
590
544
|
if (state.usedOnce && state.usedOnce.has(id) && typeof ez.destroyPlaceholders === 'function') {
|
|
591
|
-
try { ez.destroyPlaceholders(id); } catch (e) {}
|
|
545
|
+
try { ez.destroyPlaceholders([`${PLACEHOLDER_PREFIX}${id}`]); } catch (e) {}
|
|
592
546
|
}
|
|
593
547
|
} catch (e) {}
|
|
594
548
|
|
|
595
|
-
try {
|
|
549
|
+
try {
|
|
550
|
+
// Call Ezoic. Our showAds patch will also filter if DOM disappeared.
|
|
551
|
+
ez.showAds(id);
|
|
552
|
+
} catch (e) {}
|
|
553
|
+
|
|
596
554
|
try { state.usedOnce && state.usedOnce.add(id); } catch (e) {}
|
|
597
555
|
try { markEmptyWrapper(id); } catch (e) {}
|
|
598
556
|
|
|
599
|
-
|
|
557
|
+
// Release budget quickly; rendering continues async in ad stack.
|
|
558
|
+
setTimeout(() => {
|
|
559
|
+
try { clearTimeout(hardTimer); } catch (e) {}
|
|
560
|
+
release();
|
|
561
|
+
}, 300);
|
|
600
562
|
};
|
|
601
563
|
|
|
602
564
|
if (Array.isArray(ez.cmd)) {
|
|
@@ -652,7 +614,7 @@ function startShow(id) {
|
|
|
652
614
|
|
|
653
615
|
function observePlaceholder(id) {
|
|
654
616
|
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
655
|
-
if (!ph || !ph.isConnected) return;
|
|
617
|
+
if (!ph || !ph.isConnected) { try { clearTimeout(hardTimer); } catch (e) {} release(); return; }
|
|
656
618
|
const io = ensurePreloadObserver();
|
|
657
619
|
try { io && io.observe(ph); } catch (e) {}
|
|
658
620
|
|
|
@@ -912,7 +874,7 @@ function startShow(id) {
|
|
|
912
874
|
|
|
913
875
|
// Infinite scroll / partial updates
|
|
914
876
|
$(window).on('action:posts.loaded.ezoicInfinite action:topics.loaded.ezoicInfinite action:category.loaded.ezoicInfinite action:topic.loaded.ezoicInfinite', () => {
|
|
915
|
-
if (isBlocked()) return;
|
|
877
|
+
if (isBlocked()) { try { clearTimeout(hardTimer); } catch (e) {} release(); return; }
|
|
916
878
|
scheduleRun();
|
|
917
879
|
});
|
|
918
880
|
}
|
package/public/style.css
CHANGED
|
@@ -39,8 +39,15 @@
|
|
|
39
39
|
min-height: 0 !important;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
|
|
43
|
+
/* Smooth fill: avoid harsh flash when safeframe/iframe arrives */
|
|
43
44
|
.ezoic-ad iframe {
|
|
45
|
+
opacity: 0;
|
|
46
|
+
transition: opacity 140ms ease;
|
|
44
47
|
display: block !important;
|
|
45
48
|
vertical-align: top !important;
|
|
46
49
|
}
|
|
50
|
+
.ezoic-ad iframe[data-load-complete="true"],
|
|
51
|
+
.ezoic-ad iframe[src] {
|
|
52
|
+
opacity: 1;
|
|
53
|
+
}
|