nodebb-plugin-ezoic-infinite 1.5.60 → 1.5.62
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 +47 -269
- package/public/style.css +20 -10
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -4,108 +4,12 @@
|
|
|
4
4
|
// NodeBB client context
|
|
5
5
|
const $ = (typeof window.jQuery === 'function') ? window.jQuery : null;
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
// IMPORTANT: must NOT collide with Ezoic's own markup (they use `.ezoic-ad`).
|
|
8
|
+
// If we reuse that class, cleanup/pruning can delete real ads and cause
|
|
9
|
+
// "placeholder does not exist" spam + broken 1/X insertion.
|
|
10
|
+
const WRAP_CLASS = 'nodebb-ezoic-wrap';
|
|
8
11
|
const PLACEHOLDER_PREFIX = 'ezoic-pub-ad-placeholder-';
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
// Offscreen pool to keep placeholder elements alive across ajaxify/navigation.
|
|
12
|
-
// This prevents Ezoic from trying to define ids that are not currently injected,
|
|
13
|
-
// and eliminates "HTML element with id ... does not exist" noise.
|
|
14
|
-
const POOL_ID = 'ezoic-placeholder-pool';
|
|
15
|
-
|
|
16
|
-
function isInPool(el) {
|
|
17
|
-
try { return !!(el && el.closest && el.closest('#' + POOL_ID)); } catch (e) { return false; }
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function isPlaceholderInUse(ph) {
|
|
21
|
-
// In use = connected AND not parked in our offscreen pool.
|
|
22
|
-
try { return !!(ph && ph.isConnected && !isInPool(ph)); } catch (e) { return false; }
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function ensurePool() {
|
|
26
|
-
let pool = document.getElementById(POOL_ID);
|
|
27
|
-
if (pool) {
|
|
28
|
-
// In rare cases (aggressive SPA navigation), the pool may get detached.
|
|
29
|
-
if (!pool.isConnected) {
|
|
30
|
-
try { (document.documentElement || document.body).appendChild(pool); } catch (e) {}
|
|
31
|
-
}
|
|
32
|
-
return pool;
|
|
33
|
-
}
|
|
34
|
-
pool = document.createElement('div');
|
|
35
|
-
pool.id = POOL_ID;
|
|
36
|
-
pool.style.position = 'absolute';
|
|
37
|
-
pool.style.left = '-99999px';
|
|
38
|
-
pool.style.top = '0';
|
|
39
|
-
pool.style.width = '1px';
|
|
40
|
-
pool.style.height = '1px';
|
|
41
|
-
pool.style.overflow = 'hidden';
|
|
42
|
-
pool.setAttribute('aria-hidden', 'true');
|
|
43
|
-
// Attach early (documentElement exists before body), so placeholders are always connected.
|
|
44
|
-
try { (document.documentElement || document.body).appendChild(pool); } catch (e) {}
|
|
45
|
-
// If body exists later, move it under body (purely cosmetic).
|
|
46
|
-
try {
|
|
47
|
-
if (document.body && pool.parentNode !== document.body) {
|
|
48
|
-
document.body.appendChild(pool);
|
|
49
|
-
}
|
|
50
|
-
} catch (e) {}
|
|
51
|
-
return pool;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Create placeholder divs for all configured ids upfront.
|
|
55
|
-
// Ezoic sometimes attempts to initialize/refresh a range of ids even if we
|
|
56
|
-
// haven't injected them yet; keeping them in the offscreen pool prevents
|
|
57
|
-
// "HTML element ... does not exist" spam.
|
|
58
|
-
function primePool(ids) {
|
|
59
|
-
try {
|
|
60
|
-
if (!ids || !ids.length) return;
|
|
61
|
-
const pool = ensurePool();
|
|
62
|
-
for (const v of ids) {
|
|
63
|
-
const id = parseInt(v, 10);
|
|
64
|
-
if (!Number.isFinite(id) || id <= 0) continue;
|
|
65
|
-
const domId = `${PLACEHOLDER_PREFIX}${id}`;
|
|
66
|
-
let ph = document.getElementById(domId);
|
|
67
|
-
if (!ph) {
|
|
68
|
-
ph = document.createElement('div');
|
|
69
|
-
ph.id = domId;
|
|
70
|
-
ph.setAttribute('data-ezoic-id', String(id));
|
|
71
|
-
pool.appendChild(ph);
|
|
72
|
-
} else if (!ph.isConnected) {
|
|
73
|
-
pool.appendChild(ph);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
} catch (e) {}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function acquirePlaceholder(id) {
|
|
80
|
-
const domId = `${PLACEHOLDER_PREFIX}${id}`;
|
|
81
|
-
let ph = document.getElementById(domId);
|
|
82
|
-
if (!ph) {
|
|
83
|
-
ph = document.createElement('div');
|
|
84
|
-
ph.id = domId;
|
|
85
|
-
ph.setAttribute('data-ezoic-id', String(id));
|
|
86
|
-
ensurePool().appendChild(ph);
|
|
87
|
-
}
|
|
88
|
-
// Note: appendChild will automatically move the node, no manual detach (avoids race gaps).
|
|
89
|
-
// Clear request/defined flags when reusing
|
|
90
|
-
try {
|
|
91
|
-
if (ph.dataset) {
|
|
92
|
-
ph.dataset.ezRequested = '0';
|
|
93
|
-
ph.dataset.ezDefined = '0';
|
|
94
|
-
ph.dataset.ezActive = '0';
|
|
95
|
-
}
|
|
96
|
-
} catch (e) {}
|
|
97
|
-
return ph;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function parkPlaceholderFromWrap(wrap) {
|
|
101
|
-
try {
|
|
102
|
-
const ph = wrap && wrap.querySelector ? wrap.querySelector(`[id^="${PLACEHOLDER_PREFIX}"]`) : null;
|
|
103
|
-
if (!ph) return;
|
|
104
|
-
try { if (state && state.io) state.io.unobserve(ph); } catch (e) {}
|
|
105
|
-
try { if (ph.dataset) ph.dataset.ezActive = '0'; } catch (e) {}
|
|
106
|
-
ensurePool().appendChild(ph);
|
|
107
|
-
} catch (e) {}
|
|
108
|
-
}
|
|
109
13
|
// Insert at most N ads per run to keep the UI smooth on infinite scroll
|
|
110
14
|
const MAX_INSERTS_PER_RUN = 3;
|
|
111
15
|
|
|
@@ -318,107 +222,34 @@ function parkPlaceholderFromWrap(wrap) {
|
|
|
318
222
|
} catch (e) {}
|
|
319
223
|
}
|
|
320
224
|
|
|
321
|
-
|
|
322
225
|
// Patch showAds to avoid warnings when a placeholder disappears (infinite scroll, ajaxify)
|
|
323
|
-
// Ezoic can (re)define ezstandalone.showAds over time; we hook assignments to keep the guard.
|
|
324
226
|
function patchShowAds() {
|
|
325
|
-
|
|
326
|
-
if (orig && orig.__nodebbWrapped) return orig;
|
|
327
|
-
|
|
328
|
-
const wrapped = function (...args) {
|
|
329
|
-
if (isBlocked()) return;
|
|
330
|
-
|
|
331
|
-
let ids = [];
|
|
332
|
-
if (args.length === 1 && Array.isArray(args[0])) ids = args[0];
|
|
333
|
-
else ids = args;
|
|
334
|
-
|
|
335
|
-
const seen = new Set();
|
|
336
|
-
for (const v of ids) {
|
|
337
|
-
const id = parseInt(v, 10);
|
|
338
|
-
if (!Number.isFinite(id) || id <= 0 || seen.has(id)) continue;
|
|
339
|
-
|
|
340
|
-
const domId = `${PLACEHOLDER_PREFIX}${id}`;
|
|
341
|
-
let ph = document.getElementById(domId);
|
|
342
|
-
if (!ph || !ph.isConnected) {
|
|
343
|
-
// If Ezoic (or another script) tries to show an id we haven't injected yet,
|
|
344
|
-
// create the placeholder in the offscreen pool so it exists, but don't load.
|
|
345
|
-
try {
|
|
346
|
-
ph = document.createElement('div');
|
|
347
|
-
ph.id = domId;
|
|
348
|
-
ph.setAttribute('data-ezoic-id', String(id));
|
|
349
|
-
if (ph.dataset) ph.dataset.ezActive = '0';
|
|
350
|
-
ensurePool().appendChild(ph);
|
|
351
|
-
} catch (e) {}
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Only allow loads for placeholders actively injected into the page (not parked in the pool)
|
|
356
|
-
// and currently marked active.
|
|
357
|
-
if (!isPlaceholderInUse(ph)) continue;
|
|
358
|
-
if (ph.dataset && ph.dataset.ezActive !== '1') continue;
|
|
359
|
-
|
|
360
|
-
// Prevent repeated "define" attempts on the same placeholder while it remains in DOM.
|
|
361
|
-
if (ph.dataset && (ph.dataset.ezRequested === '1' || ph.dataset.ezDefined === '1')) continue;
|
|
362
|
-
|
|
363
|
-
seen.add(id);
|
|
364
|
-
try {
|
|
365
|
-
if (ph.dataset) ph.dataset.ezRequested = '1';
|
|
366
|
-
orig.call(ez, id);
|
|
367
|
-
if (ph.dataset) {
|
|
368
|
-
ph.dataset.ezDefined = '1';
|
|
369
|
-
ph.dataset.ezRequested = '0';
|
|
370
|
-
}
|
|
371
|
-
} catch (e) {
|
|
372
|
-
try { if (ph.dataset) ph.dataset.ezRequested = '0'; } catch (_) {}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
try { wrapped.__nodebbWrapped = true; } catch (e) {}
|
|
377
|
-
return wrapped;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function ensureHook() {
|
|
227
|
+
const applyPatch = () => {
|
|
381
228
|
try {
|
|
382
229
|
window.ezstandalone = window.ezstandalone || {};
|
|
383
230
|
const ez = window.ezstandalone;
|
|
231
|
+
if (window.__nodebbEzoicPatched) return;
|
|
232
|
+
if (typeof ez.showAds !== 'function') return;
|
|
384
233
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
ez.__nodebbShowAdsHooked = true;
|
|
388
|
-
let _showAds = ez.showAds;
|
|
389
|
-
|
|
390
|
-
Object.defineProperty(ez, 'showAds', {
|
|
391
|
-
configurable: true,
|
|
392
|
-
enumerable: true,
|
|
393
|
-
get() {
|
|
394
|
-
return _showAds;
|
|
395
|
-
},
|
|
396
|
-
set(fn) {
|
|
397
|
-
_showAds = (typeof fn === 'function') ? wrapShowAds(ez, fn) : fn;
|
|
398
|
-
},
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
// If showAds already exists, wrap it immediately
|
|
402
|
-
if (typeof _showAds === 'function') {
|
|
403
|
-
_showAds = wrapShowAds(ez, _showAds);
|
|
404
|
-
}
|
|
405
|
-
} else if (typeof ez.showAds === 'function' && !ez.showAds.__nodebbWrapped) {
|
|
406
|
-
// In case defineProperty wasn't possible (rare), re-wrap
|
|
407
|
-
ez.showAds = wrapShowAds(ez, ez.showAds);
|
|
408
|
-
}
|
|
409
|
-
} catch (e) {}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
ensureHook();
|
|
234
|
+
window.__nodebbEzoicPatched = true;
|
|
235
|
+
const orig = ez.showAds;
|
|
413
236
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
window.ezstandalone = window.ezstandalone || {};
|
|
417
|
-
window.ezstandalone.cmd = window.ezstandalone.cmd || [];
|
|
418
|
-
window.ezstandalone.cmd.push(ensureHook);
|
|
419
|
-
} catch (e) {}
|
|
420
|
-
}
|
|
237
|
+
ez.showAds = function (...args) {
|
|
238
|
+
if (isBlocked()) return;
|
|
421
239
|
|
|
240
|
+
let ids = [];
|
|
241
|
+
if (args.length === 1 && Array.isArray(args[0])) ids = args[0];
|
|
242
|
+
else ids = args;
|
|
243
|
+
|
|
244
|
+
const seen = new Set();
|
|
245
|
+
for (const v of ids) {
|
|
246
|
+
const id = parseInt(v, 10);
|
|
247
|
+
if (!Number.isFinite(id) || id <= 0 || seen.has(id)) continue;
|
|
248
|
+
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
249
|
+
if (!ph || !ph.isConnected) continue;
|
|
250
|
+
seen.add(id);
|
|
251
|
+
try { orig.call(ez, id); } catch (e) {}
|
|
252
|
+
}
|
|
422
253
|
};
|
|
423
254
|
} catch (e) {}
|
|
424
255
|
};
|
|
@@ -473,12 +304,6 @@ function withInternalDomChange(fn) {
|
|
|
473
304
|
if (state.allTopics.length === 0) state.allTopics = parsePool(cfg.placeholderIds);
|
|
474
305
|
if (state.allPosts.length === 0) state.allPosts = parsePool(cfg.messagePlaceholderIds);
|
|
475
306
|
if (state.allCategories.length === 0) state.allCategories = parsePool(cfg.categoryPlaceholderIds);
|
|
476
|
-
|
|
477
|
-
// Keep placeholders alive even before they're injected.
|
|
478
|
-
// This avoids Ezoic trying to touch ids that we haven't inserted yet.
|
|
479
|
-
primePool(state.allTopics);
|
|
480
|
-
primePool(state.allPosts);
|
|
481
|
-
primePool(state.allCategories);
|
|
482
307
|
}
|
|
483
308
|
|
|
484
309
|
// ---------- insertion primitives ----------
|
|
@@ -505,20 +330,9 @@ function withInternalDomChange(fn) {
|
|
|
505
330
|
|
|
506
331
|
function safeDestroyById(id) {
|
|
507
332
|
try {
|
|
508
|
-
const domId = `${PLACEHOLDER_PREFIX}${id}`;
|
|
509
|
-
const ph = document.getElementById(domId);
|
|
510
|
-
|
|
511
|
-
// If the element is already gone, do NOT call destroyPlaceholders (Ezoic will log "does not exist").
|
|
512
|
-
if (!ph || !ph.isConnected) return;
|
|
513
|
-
|
|
514
|
-
if (ph.dataset) {
|
|
515
|
-
delete ph.dataset.ezDefined;
|
|
516
|
-
delete ph.dataset.ezRequested;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
333
|
const ez = window.ezstandalone;
|
|
520
334
|
if (ez && typeof ez.destroyPlaceholders === 'function') {
|
|
521
|
-
ez.destroyPlaceholders([
|
|
335
|
+
ez.destroyPlaceholders([`${PLACEHOLDER_PREFIX}${id}`]);
|
|
522
336
|
}
|
|
523
337
|
} catch (e) {}
|
|
524
338
|
}
|
|
@@ -543,7 +357,6 @@ function withInternalDomChange(fn) {
|
|
|
543
357
|
withInternalDomChange(() => {
|
|
544
358
|
try {
|
|
545
359
|
if (id) safeDestroyById(id);
|
|
546
|
-
parkPlaceholderFromWrap(wrap);
|
|
547
360
|
wrap.remove();
|
|
548
361
|
} catch (e) {}
|
|
549
362
|
});
|
|
@@ -577,8 +390,9 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
577
390
|
wrap.setAttribute('data-ezoic-wrapid', String(id));
|
|
578
391
|
wrap.style.width = '100%';
|
|
579
392
|
|
|
580
|
-
const ph =
|
|
581
|
-
|
|
393
|
+
const ph = document.createElement('div');
|
|
394
|
+
ph.id = `${PLACEHOLDER_PREFIX}${id}`;
|
|
395
|
+
ph.setAttribute('data-ezoic-id', String(id));
|
|
582
396
|
wrap.appendChild(ph);
|
|
583
397
|
|
|
584
398
|
return wrap;
|
|
@@ -594,7 +408,7 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
594
408
|
if (insertingIds.has(id)) return null;
|
|
595
409
|
|
|
596
410
|
const existingPh = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
597
|
-
if (existingPh &&
|
|
411
|
+
if (existingPh && existingPh.isConnected) return null;
|
|
598
412
|
|
|
599
413
|
insertingIds.add(id);
|
|
600
414
|
try {
|
|
@@ -617,7 +431,7 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
617
431
|
|
|
618
432
|
const id = allIds[idx];
|
|
619
433
|
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
620
|
-
if (ph &&
|
|
434
|
+
if (ph && ph.isConnected) continue;
|
|
621
435
|
|
|
622
436
|
return id;
|
|
623
437
|
}
|
|
@@ -645,7 +459,6 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
645
459
|
if (ph && state.io) state.io.unobserve(ph);
|
|
646
460
|
} catch (e) {}
|
|
647
461
|
|
|
648
|
-
parkPlaceholderFromWrap(victim);
|
|
649
462
|
victim.remove();
|
|
650
463
|
return true;
|
|
651
464
|
} catch (e) {
|
|
@@ -682,11 +495,9 @@ function drainQueue() {
|
|
|
682
495
|
}
|
|
683
496
|
}
|
|
684
497
|
|
|
685
|
-
|
|
686
498
|
function startShow(id) {
|
|
687
|
-
if (!id) return;
|
|
499
|
+
if (!id || isBlocked()) return;
|
|
688
500
|
|
|
689
|
-
// Reserve an inflight slot, but ALWAYS release on any early exit.
|
|
690
501
|
state.inflight++;
|
|
691
502
|
let released = false;
|
|
692
503
|
const release = () => {
|
|
@@ -700,41 +511,30 @@ function startShow(id) {
|
|
|
700
511
|
|
|
701
512
|
requestAnimationFrame(() => {
|
|
702
513
|
try {
|
|
703
|
-
if (isBlocked())
|
|
514
|
+
if (isBlocked()) return;
|
|
704
515
|
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
if (!phNow || !phNow.isConnected) { clearTimeout(hardTimer); release(); return; }
|
|
516
|
+
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
517
|
+
if (!ph || !ph.isConnected) return;
|
|
708
518
|
|
|
709
519
|
const now2 = Date.now();
|
|
710
520
|
const last2 = state.lastShowById.get(id) || 0;
|
|
711
|
-
if (now2 - last2 < 900)
|
|
521
|
+
if (now2 - last2 < 900) return;
|
|
712
522
|
state.lastShowById.set(id, now2);
|
|
713
523
|
|
|
714
524
|
window.ezstandalone = window.ezstandalone || {};
|
|
715
525
|
const ez = window.ezstandalone;
|
|
716
526
|
|
|
717
527
|
const doShow = () => {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
// showAds is patched to ignore missing placeholders and repeated defines.
|
|
731
|
-
ez.showAds(id);
|
|
732
|
-
|
|
733
|
-
try { state.usedOnce && state.usedOnce.add(id); } catch (e) {}
|
|
734
|
-
} catch (e) {}
|
|
735
|
-
finally {
|
|
736
|
-
setTimeout(() => { try { clearTimeout(hardTimer); } catch (_) {} release(); }, 650);
|
|
737
|
-
}
|
|
528
|
+
// Do NOT call destroyPlaceholders here.
|
|
529
|
+
// In ajaxify + infinite scroll flows, Ezoic can be in the middle of a refresh cycle.
|
|
530
|
+
// Calling destroy on active placeholders is a common source of:
|
|
531
|
+
// - "HTML element ... does not exist"
|
|
532
|
+
// - "Placeholder Id ... already been defined"
|
|
533
|
+
// Prefer a straight showAds; Ezoic will refresh as needed.
|
|
534
|
+
try { ez.showAds(id); } catch (e) {}
|
|
535
|
+
try { markEmptyWrapper(id); } catch (e) {}
|
|
536
|
+
|
|
537
|
+
setTimeout(() => { clearTimeout(hardTimer); release(); }, 650);
|
|
738
538
|
};
|
|
739
539
|
|
|
740
540
|
if (Array.isArray(ez.cmd)) {
|
|
@@ -742,15 +542,13 @@ function startShow(id) {
|
|
|
742
542
|
} else {
|
|
743
543
|
doShow();
|
|
744
544
|
}
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
release();
|
|
545
|
+
} finally {
|
|
546
|
+
// If we returned early, hardTimer will release.
|
|
748
547
|
}
|
|
749
548
|
});
|
|
750
549
|
}
|
|
751
550
|
|
|
752
551
|
|
|
753
|
-
|
|
754
552
|
// ---------- preload / above-the-fold ----------
|
|
755
553
|
|
|
756
554
|
function ensurePreloadObserver() {
|
|
@@ -857,25 +655,6 @@ function startShow(id) {
|
|
|
857
655
|
inserted += 1;
|
|
858
656
|
}
|
|
859
657
|
|
|
860
|
-
// Safety: if DOM churn results in two consecutive ad wrappers, remove the latter.
|
|
861
|
-
// (This can happen when NodeBB inserts/removes spacer elements around the anchor.)
|
|
862
|
-
try {
|
|
863
|
-
const wraps = Array.from(document.querySelectorAll(`.${WRAP_CLASS}.${kindClass}`));
|
|
864
|
-
for (const w of wraps) {
|
|
865
|
-
const prev = w.previousElementSibling;
|
|
866
|
-
if (prev && prev.classList && prev.classList.contains(WRAP_CLASS)) {
|
|
867
|
-
withInternalDomChange(() => {
|
|
868
|
-
try {
|
|
869
|
-
const id = getWrapIdFromWrap(w);
|
|
870
|
-
if (id) safeDestroyById(id);
|
|
871
|
-
parkPlaceholderFromWrap(w);
|
|
872
|
-
w.remove();
|
|
873
|
-
} catch (e) {}
|
|
874
|
-
});
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
} catch (e) {}
|
|
878
|
-
|
|
879
658
|
return inserted;
|
|
880
659
|
}
|
|
881
660
|
|
|
@@ -1011,7 +790,6 @@ function startShow(id) {
|
|
|
1011
790
|
// remove all wrappers
|
|
1012
791
|
try {
|
|
1013
792
|
document.querySelectorAll(`.${WRAP_CLASS}`).forEach((el) => {
|
|
1014
|
-
try { parkPlaceholderFromWrap(el); } catch (e) {}
|
|
1015
793
|
try { el.remove(); } catch (e) {}
|
|
1016
794
|
});
|
|
1017
795
|
} catch (e) {}
|
package/public/style.css
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
1
|
+
/*
|
|
2
|
+
Keep our NodeBB-inserted wrappers CLS-safe.
|
|
3
|
+
NOTE: must not rely on `.ezoic-ad` because Ezoic uses that class internally.
|
|
4
|
+
*/
|
|
5
|
+
.nodebb-ezoic-wrap {
|
|
3
6
|
display: block;
|
|
4
7
|
width: 100%;
|
|
5
8
|
margin: 0 !important;
|
|
@@ -7,22 +10,22 @@
|
|
|
7
10
|
overflow: hidden;
|
|
8
11
|
}
|
|
9
12
|
|
|
10
|
-
.ezoic-
|
|
13
|
+
.nodebb-ezoic-wrap > [id^="ezoic-pub-ad-placeholder-"] {
|
|
11
14
|
margin: 0 !important;
|
|
12
15
|
padding: 0 !important;
|
|
13
16
|
min-height: 1px; /* keeps placeholder measurable for IO */
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
/* Ezoic
|
|
17
|
-
.ezoic-
|
|
18
|
-
.ezoic-
|
|
19
|
+
/* If Ezoic wraps inside our wrapper, keep it tight */
|
|
20
|
+
.nodebb-ezoic-wrap span.ezoic-ad,
|
|
21
|
+
.nodebb-ezoic-wrap .ezoic-ad {
|
|
19
22
|
margin: 0 !important;
|
|
20
23
|
padding: 0 !important;
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
|
|
24
27
|
/* Collapse empty ad blocks (prevents "holes" when an ad doesn't fill or gets destroyed) */
|
|
25
|
-
.ezoic-
|
|
28
|
+
.nodebb-ezoic-wrap.is-empty {
|
|
26
29
|
display: block !important;
|
|
27
30
|
margin: 0 !important;
|
|
28
31
|
padding: 0 !important;
|
|
@@ -31,12 +34,19 @@
|
|
|
31
34
|
overflow: hidden !important;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
.ezoic-
|
|
37
|
+
.nodebb-ezoic-wrap {
|
|
35
38
|
min-height: 0 !important;
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
.ezoic-
|
|
41
|
+
.nodebb-ezoic-wrap > [id^="ezoic-pub-ad-placeholder-"] {
|
|
39
42
|
min-height: 0 !important;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
|
|
45
|
+
/*
|
|
46
|
+
Optional: also neutralize spacing on native Ezoic `.ezoic-ad` blocks.
|
|
47
|
+
(Keeps your previous "CSS very good" behavior.)
|
|
48
|
+
*/
|
|
49
|
+
.ezoic-ad {
|
|
50
|
+
margin: 0 !important;
|
|
51
|
+
padding: 0 !important;
|
|
52
|
+
}
|