nodebb-plugin-ezoic-infinite 1.5.76 → 1.5.77

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/client.js +26 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.5.76",
3
+ "version": "1.5.77",
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
@@ -135,11 +135,8 @@ function tightenEzoicMinHeight(wrap) {
135
135
  }
136
136
  if (!maxBottom) return;
137
137
 
138
- // Account for the Ezoic badge (reportline) which is absolutely positioned.
139
- const report = refNode.querySelector('.reportline');
140
- if (report && report.offsetHeight) {
141
- maxBottom += report.offsetHeight;
142
- }
138
+ // NOTE: Do NOT add the Ezoic badge (reportline) height here.
139
+ // It is absolutely positioned and should not reserve layout space.
143
140
 
144
141
  const h = Math.max(1, Math.ceil(maxBottom));
145
142
 
@@ -229,6 +226,9 @@ function globalGapFixInit() {
229
226
  if (window.__nodebbEzoicGapFix) return;
230
227
  window.__nodebbEzoicGapFix = true;
231
228
 
229
+ // Observe only the main content area to minimize overhead.
230
+ const root = document.getElementById('content') || document.querySelector('[component="content"], #panel') || document.body;
231
+
232
232
  const inPostArea = (el) => {
233
233
  try {
234
234
  return !!(el && el.closest && el.closest('[component="post"], .topic, .posts, [component="topic"]'));
@@ -249,21 +249,37 @@ function globalGapFixInit() {
249
249
  });
250
250
  };
251
251
 
252
- requestAnimationFrame(() => maybeFix(document));
252
+ requestAnimationFrame(() => maybeFix(root));
253
+
254
+ // Batch DOM mutation processing into a single rAF to avoid doing work per mutation.
255
+ const pending = new Set();
256
+ let scheduled = false;
257
+ const scheduleFlush = () => {
258
+ if (scheduled) return;
259
+ scheduled = true;
260
+ requestAnimationFrame(() => {
261
+ scheduled = false;
262
+ pending.forEach((n) => {
263
+ try { maybeFix(n); } catch (e) {}
264
+ });
265
+ pending.clear();
266
+ });
267
+ };
253
268
 
254
269
  const obs = new MutationObserver((muts) => {
255
270
  for (const m of muts) {
256
- const t = m.target;
257
271
  if (m.type === 'attributes') {
258
- maybeFix(t && t.nodeType === 1 ? t : t && t.parentElement);
272
+ const t = m.target && m.target.nodeType === 1 ? m.target : m.target && m.target.parentElement;
273
+ if (t) pending.add(t);
259
274
  } else if (m.addedNodes && m.addedNodes.length) {
260
275
  m.addedNodes.forEach((n) => {
261
- if (n && n.nodeType === 1) maybeFix(n);
276
+ if (n && n.nodeType === 1) pending.add(n);
262
277
  });
263
278
  }
264
279
  }
280
+ if (pending.size) scheduleFlush();
265
281
  });
266
- obs.observe(document.documentElement, { subtree: true, childList: true, attributes: true, attributeFilter: ['style'] });
282
+ obs.observe(root, { subtree: true, childList: true, attributes: true, attributeFilter: ['style'] });
267
283
  } catch (e) {}
268
284
  }
269
285