nodebb-plugin-ezoic-infinite 1.5.63 → 1.5.65
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 +108 -22
- package/public/style.css +4 -4
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -99,6 +99,16 @@
|
|
|
99
99
|
|
|
100
100
|
const insertingIds = new Set();
|
|
101
101
|
|
|
102
|
+
function unemptyIfFilled(wrap, ph) {
|
|
103
|
+
try {
|
|
104
|
+
if (!wrap || !ph) return false;
|
|
105
|
+
const hasAd = !!(ph.querySelector && ph.querySelector('iframe, ins, img, .ez-ad, .ezoic-ad'));
|
|
106
|
+
if (hasAd) wrap.classList.remove('is-empty');
|
|
107
|
+
return hasAd;
|
|
108
|
+
} catch (e) { return false; }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
102
112
|
|
|
103
113
|
function markEmptyWrapper(id) {
|
|
104
114
|
try {
|
|
@@ -116,6 +126,17 @@
|
|
|
116
126
|
// consider empty if only whitespace and no iframes/ins/img
|
|
117
127
|
const hasAd = !!(ph2.querySelector && ph2.querySelector('iframe, ins, img, .ez-ad, .ezoic-ad'));
|
|
118
128
|
if (!hasAd) w2.classList.add('is-empty');
|
|
129
|
+
// If the ad fills later, immediately uncollapse to avoid "missing ads" perception.
|
|
130
|
+
if (!unemptyIfFilled(w2, ph2)) {
|
|
131
|
+
try {
|
|
132
|
+
const mo = new MutationObserver(() => {
|
|
133
|
+
if (unemptyIfFilled(w2, ph2)) { try { mo.disconnect(); } catch (e) {} }
|
|
134
|
+
});
|
|
135
|
+
mo.observe(ph2, { childList: true, subtree: true });
|
|
136
|
+
// safety stop
|
|
137
|
+
setTimeout(() => { try { mo.disconnect(); } catch (e) {} }, 30000);
|
|
138
|
+
} catch (e) {}
|
|
139
|
+
}
|
|
119
140
|
} catch (e) {}
|
|
120
141
|
}, 3500);
|
|
121
142
|
} catch (e) {}
|
|
@@ -234,22 +255,40 @@
|
|
|
234
255
|
window.__nodebbEzoicPatched = true;
|
|
235
256
|
const orig = ez.showAds;
|
|
236
257
|
|
|
258
|
+
// Important: preserve the original calling convention.
|
|
259
|
+
// Some Ezoic builds expect an array; calling one-by-one can lead to
|
|
260
|
+
// repeated define attempts and "Placeholder Id ... already been defined".
|
|
237
261
|
ez.showAds = function (...args) {
|
|
238
262
|
if (isBlocked()) return;
|
|
239
263
|
|
|
264
|
+
const now = Date.now();
|
|
240
265
|
let ids = [];
|
|
241
|
-
|
|
266
|
+
const isArrayCall = (args.length === 1 && Array.isArray(args[0]));
|
|
267
|
+
if (isArrayCall) ids = args[0];
|
|
242
268
|
else ids = args;
|
|
243
269
|
|
|
270
|
+
const filtered = [];
|
|
244
271
|
const seen = new Set();
|
|
245
272
|
for (const v of ids) {
|
|
246
273
|
const id = parseInt(v, 10);
|
|
247
274
|
if (!Number.isFinite(id) || id <= 0 || seen.has(id)) continue;
|
|
248
275
|
const ph = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
249
276
|
if (!ph || !ph.isConnected) continue;
|
|
277
|
+
|
|
278
|
+
// Extra throttle to avoid rapid duplicate defines during ajaxify churn
|
|
279
|
+
const last = state.lastShowById.get(id) || 0;
|
|
280
|
+
if (now - last < 650) continue;
|
|
281
|
+
state.lastShowById.set(id, now);
|
|
282
|
+
|
|
250
283
|
seen.add(id);
|
|
251
|
-
|
|
284
|
+
filtered.push(id);
|
|
252
285
|
}
|
|
286
|
+
|
|
287
|
+
if (!filtered.length) return;
|
|
288
|
+
try {
|
|
289
|
+
if (isArrayCall) orig.call(ez, filtered);
|
|
290
|
+
else orig.apply(ez, filtered);
|
|
291
|
+
} catch (e) {}
|
|
253
292
|
};
|
|
254
293
|
} catch (e) {}
|
|
255
294
|
};
|
|
@@ -347,11 +386,21 @@ function withInternalDomChange(fn) {
|
|
|
347
386
|
// NodeBB can insert separators/spacers; accept an anchor within a few previous siblings
|
|
348
387
|
let ok = false;
|
|
349
388
|
let prev = wrap.previousElementSibling;
|
|
350
|
-
for (let i = 0; i <
|
|
389
|
+
for (let i = 0; i < 8 && prev; i++) {
|
|
351
390
|
if (itemSet.has(prev)) { ok = true; break; }
|
|
352
391
|
prev = prev.previousElementSibling;
|
|
353
392
|
}
|
|
354
393
|
|
|
394
|
+
// If it is already filled (iframe/ins/img), be conservative and keep it.
|
|
395
|
+
// Prevents ads "disappearing too fast" during ajaxify churn / minor rerenders.
|
|
396
|
+
if (!ok) {
|
|
397
|
+
try {
|
|
398
|
+
const ph = wrap.querySelector && wrap.querySelector(`[id^="${PLACEHOLDER_PREFIX}"]`);
|
|
399
|
+
const filled = !!(ph && ph.querySelector && ph.querySelector('iframe, ins, img, .ez-ad, .ezoic-ad'));
|
|
400
|
+
if (filled) ok = true;
|
|
401
|
+
} catch (e) {}
|
|
402
|
+
}
|
|
403
|
+
|
|
355
404
|
if (!ok) {
|
|
356
405
|
const id = getWrapIdFromWrap(wrap);
|
|
357
406
|
withInternalDomChange(() => {
|
|
@@ -368,6 +417,28 @@ function withInternalDomChange(fn) {
|
|
|
368
417
|
return removed;
|
|
369
418
|
}
|
|
370
419
|
|
|
420
|
+
function declusterWraps(kindClass) {
|
|
421
|
+
try {
|
|
422
|
+
const wraps = Array.from(document.querySelectorAll(`.${WRAP_CLASS}.${kindClass}`));
|
|
423
|
+
if (wraps.length < 2) return;
|
|
424
|
+
for (let i = 1; i < wraps.length; i++) {
|
|
425
|
+
const w = wraps[i];
|
|
426
|
+
if (!w || !w.isConnected) continue;
|
|
427
|
+
// If previous siblings contain another wrap within 2 hops, remove this one.
|
|
428
|
+
let prev = w.previousElementSibling;
|
|
429
|
+
let hops = 0;
|
|
430
|
+
while (prev && hops < 3) {
|
|
431
|
+
if (prev.classList && prev.classList.contains(WRAP_CLASS)) {
|
|
432
|
+
withInternalDomChange(() => { try { w.remove(); } catch (e) {} });
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
prev = prev.previousElementSibling;
|
|
436
|
+
hops++;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
} catch (e) {}
|
|
440
|
+
}
|
|
441
|
+
|
|
371
442
|
function refreshEmptyState(id) {
|
|
372
443
|
// After Ezoic has had a moment to fill the placeholder, toggle the CSS class.
|
|
373
444
|
window.setTimeout(() => {
|
|
@@ -383,17 +454,25 @@ function withInternalDomChange(fn) {
|
|
|
383
454
|
}, 3500);
|
|
384
455
|
}
|
|
385
456
|
|
|
386
|
-
function buildWrap(id, kindClass, afterPos) {
|
|
457
|
+
function buildWrap(id, kindClass, afterPos, existingPlaceholder) {
|
|
387
458
|
const wrap = document.createElement('div');
|
|
388
459
|
wrap.className = `${WRAP_CLASS} ${kindClass}`;
|
|
389
460
|
wrap.setAttribute('data-ezoic-after', String(afterPos));
|
|
390
461
|
wrap.setAttribute('data-ezoic-wrapid', String(id));
|
|
391
462
|
wrap.style.width = '100%';
|
|
392
463
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
464
|
+
if (existingPlaceholder && existingPlaceholder.nodeType === 1) {
|
|
465
|
+
try {
|
|
466
|
+
existingPlaceholder.id = `${PLACEHOLDER_PREFIX}${id}`;
|
|
467
|
+
existingPlaceholder.setAttribute('data-ezoic-id', String(id));
|
|
468
|
+
} catch (e) {}
|
|
469
|
+
wrap.appendChild(existingPlaceholder);
|
|
470
|
+
} else {
|
|
471
|
+
const ph = document.createElement('div');
|
|
472
|
+
ph.id = `${PLACEHOLDER_PREFIX}${id}`;
|
|
473
|
+
ph.setAttribute('data-ezoic-id', String(id));
|
|
474
|
+
wrap.appendChild(ph);
|
|
475
|
+
}
|
|
397
476
|
|
|
398
477
|
return wrap;
|
|
399
478
|
}
|
|
@@ -407,24 +486,28 @@ function buildWrap(id, kindClass, afterPos) {
|
|
|
407
486
|
if (findWrap(kindClass, afterPos)) return null;
|
|
408
487
|
if (insertingIds.has(id)) return null;
|
|
409
488
|
|
|
410
|
-
const existingPh = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
411
|
-
|
|
412
489
|
insertingIds.add(id);
|
|
413
490
|
try {
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
//
|
|
418
|
-
//
|
|
419
|
-
//
|
|
420
|
-
|
|
491
|
+
const existingPh = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
|
|
492
|
+
|
|
493
|
+
// CRITICAL: never create a second element with the same id, even briefly.
|
|
494
|
+
// That can trigger "Placeholder Id ... already been defined" during load.
|
|
495
|
+
// If an existing placeholder already exists, move it into the new wrapper
|
|
496
|
+
// before inserting the wrapper into the DOM.
|
|
497
|
+
let moved = null;
|
|
498
|
+
if (existingPh && existingPh.isConnected) {
|
|
499
|
+
moved = existingPh;
|
|
500
|
+
// If it was inside one of our wrappers, drop that empty wrapper.
|
|
421
501
|
try {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
}
|
|
502
|
+
const oldWrap = moved.closest && moved.closest(`.${WRAP_CLASS}`);
|
|
503
|
+
if (oldWrap && oldWrap.parentNode) {
|
|
504
|
+
withInternalDomChange(() => { try { oldWrap.remove(); } catch (e) {} });
|
|
505
|
+
}
|
|
506
|
+
} catch (e) {}
|
|
427
507
|
}
|
|
508
|
+
|
|
509
|
+
const wrap = buildWrap(id, kindClass, afterPos, moved);
|
|
510
|
+
target.insertAdjacentElement('afterend', wrap);
|
|
428
511
|
return wrap;
|
|
429
512
|
} finally {
|
|
430
513
|
insertingIds.delete(id);
|
|
@@ -752,6 +835,7 @@ function startShow(id) {
|
|
|
752
835
|
state.allPosts,
|
|
753
836
|
'curPosts'
|
|
754
837
|
);
|
|
838
|
+
declusterWraps('ezoic-ad-message');
|
|
755
839
|
}
|
|
756
840
|
} else if (kind === 'categoryTopics') {
|
|
757
841
|
if (normalizeBool(cfg.enableBetweenAds)) {
|
|
@@ -765,6 +849,7 @@ function startShow(id) {
|
|
|
765
849
|
state.allTopics,
|
|
766
850
|
'curTopics'
|
|
767
851
|
);
|
|
852
|
+
declusterWraps('ezoic-ad-between');
|
|
768
853
|
}
|
|
769
854
|
} else if (kind === 'categories') {
|
|
770
855
|
if (normalizeBool(cfg.enableCategoryAds)) {
|
|
@@ -778,6 +863,7 @@ function startShow(id) {
|
|
|
778
863
|
state.allCategories,
|
|
779
864
|
'curCategories'
|
|
780
865
|
);
|
|
866
|
+
declusterWraps('ezoic-ad-categories');
|
|
781
867
|
}
|
|
782
868
|
}
|
|
783
869
|
}
|
package/public/style.css
CHANGED
|
@@ -29,17 +29,17 @@
|
|
|
29
29
|
display: block !important;
|
|
30
30
|
margin: 0 !important;
|
|
31
31
|
padding: 0 !important;
|
|
32
|
-
height:
|
|
33
|
-
min-height:
|
|
32
|
+
height: 1px !important;
|
|
33
|
+
min-height: 1px !important;
|
|
34
34
|
overflow: hidden !important;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
.nodebb-ezoic-wrap {
|
|
38
|
-
min-height:
|
|
38
|
+
min-height: 1px !important;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
.nodebb-ezoic-wrap > [id^="ezoic-pub-ad-placeholder-"] {
|
|
42
|
-
min-height:
|
|
42
|
+
min-height: 1px !important;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/*
|