nodebb-plugin-ezoic-infinite 1.5.85 → 1.5.86

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 +34 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.5.85",
3
+ "version": "1.5.86",
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
@@ -486,6 +486,24 @@ function globalGapFixInit() {
486
486
  return document.querySelector(`.${WRAP_CLASS}.${kindClass}[data-ezoic-after="${afterPos}"]`);
487
487
  }
488
488
 
489
+ function getStableAnchorKey(el) {
490
+ try {
491
+ if (!el) return '';
492
+ const pid = el.getAttribute('data-pid');
493
+ if (pid) return 'pid:' + pid;
494
+ const tid = el.getAttribute('data-tid');
495
+ if (tid) return 'tid:' + tid;
496
+ const slug = el.getAttribute('data-slug');
497
+ if (slug) return 'slug:' + slug;
498
+ } catch (e) {}
499
+ return '';
500
+ }
501
+
502
+ function findWrapByAnchor(kindClass, anchorKey) {
503
+ if (!anchorKey) return null;
504
+ return document.querySelector(`.${WRAP_CLASS}.${kindClass}[data-ezoic-anchor="${anchorKey}"]`);
505
+ }
506
+
489
507
  // ---------------- placeholder pool ----------------
490
508
 
491
509
  function getPoolEl() {
@@ -636,12 +654,13 @@ function globalGapFixInit() {
636
654
 
637
655
  // ---------------- insertion primitives ----------------
638
656
 
639
- function buildWrap(id, kindClass, afterPos, createPlaceholder) {
657
+ function buildWrap(id, kindClass, afterPos, createPlaceholder, anchorKey) {
640
658
  const wrap = document.createElement('div');
641
659
  wrap.className = `${WRAP_CLASS} ${kindClass}`;
642
660
  wrap.setAttribute('data-ezoic-after', String(afterPos));
643
661
  wrap.setAttribute('data-ezoic-wrapid', String(id));
644
662
  wrap.setAttribute('data-created', String(now()));
663
+ if (anchorKey) wrap.setAttribute('data-ezoic-anchor', String(anchorKey));
645
664
  // "Pinned" placements (after the first item) should remain stable.
646
665
  if (afterPos === 1) {
647
666
  wrap.setAttribute('data-ezoic-pin', '1');
@@ -658,16 +677,16 @@ function globalGapFixInit() {
658
677
  return wrap;
659
678
  }
660
679
 
661
- function insertAfter(target, id, kindClass, afterPos) {
680
+ function insertAfter(target, id, kindClass, afterPos, anchorKey) {
662
681
  if (!target || !target.insertAdjacentElement) return null;
663
- if (findWrap(kindClass, afterPos)) return null;
682
+ if (findWrap(kindClass, afterPos) || findWrapByAnchor(kindClass, anchorKey)) return null;
664
683
  if (insertingIds.has(id)) return null;
665
684
 
666
685
  const existingPh = document.getElementById(`${PLACEHOLDER_PREFIX}${id}`);
667
686
 
668
687
  insertingIds.add(id);
669
688
  try {
670
- const wrap = buildWrap(id, kindClass, afterPos, !existingPh);
689
+ const wrap = buildWrap(id, kindClass, afterPos, !existingPh, anchorKey);
671
690
  target.insertAdjacentElement('afterend', wrap);
672
691
 
673
692
  // If placeholder exists elsewhere (including pool), move it into the wrapper.
@@ -1092,6 +1111,16 @@ function buildOrdinalMap(items) {
1092
1111
  if (!el) continue;
1093
1112
  if (!el || !el.isConnected) continue;
1094
1113
  if (isAdjacentAd(el)) continue;
1114
+ const anchorKey = getStableAnchorKey(el);
1115
+ const existingByAnchor = findWrapByAnchor(kindClass, anchorKey);
1116
+ if (existingByAnchor && existingByAnchor.isConnected) {
1117
+ const next = el.nextElementSibling;
1118
+ if (next !== existingByAnchor) {
1119
+ try { el.insertAdjacentElement('afterend', existingByAnchor); } catch (e) {}
1120
+ }
1121
+ existingByAnchor.setAttribute('data-ezoic-after', String(afterPos));
1122
+ continue;
1123
+ }
1095
1124
  if (findWrap(kindClass, afterPos)) continue;
1096
1125
 
1097
1126
  let id = pickIdFromAll(allIds, cursorKey);
@@ -1115,7 +1144,7 @@ function buildOrdinalMap(items) {
1115
1144
 
1116
1145
  const wrap = recycledWrap
1117
1146
  ? moveWrapAfter(el, recycledWrap, kindClass, afterPos)
1118
- : insertAfter(el, id, kindClass, afterPos);
1147
+ : insertAfter(el, id, kindClass, afterPos, anchorKey);
1119
1148
  if (!wrap) continue;
1120
1149
 
1121
1150
  // observePlaceholder is safe for existing ids (it is idempotent) and helps with "late fill"