@broberg/cms-inline-edit 0.5.3 → 0.5.5
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/dist/index.cjs +101 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -1
- package/dist/index.d.ts +47 -1
- package/dist/index.js +97 -24
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -26,7 +26,10 @@ __export(index_exports, {
|
|
|
26
26
|
getConnectedToken: () => getConnectedToken,
|
|
27
27
|
htmlToMarkdown: () => htmlToMarkdown,
|
|
28
28
|
initInlineEdit: () => initInlineEdit,
|
|
29
|
-
|
|
29
|
+
positionPopover: () => positionPopover,
|
|
30
|
+
renderCurrentRefLine: () => renderCurrentRefLine,
|
|
31
|
+
rescanFields: () => rescanFields,
|
|
32
|
+
resolveExistingRef: () => resolveExistingRef
|
|
30
33
|
});
|
|
31
34
|
module.exports = __toCommonJS(index_exports);
|
|
32
35
|
|
|
@@ -102,7 +105,8 @@ var DEFAULT_LABELS = {
|
|
|
102
105
|
linkYes: "Ja",
|
|
103
106
|
linkNo: "Nej",
|
|
104
107
|
linkEmpty: "Ingen sider fundet",
|
|
105
|
-
linkLoading: "Henter sider\u2026"
|
|
108
|
+
linkLoading: "Henter sider\u2026",
|
|
109
|
+
linkCurrent: "Linker til"
|
|
106
110
|
};
|
|
107
111
|
var uiLabels = DEFAULT_LABELS;
|
|
108
112
|
function resolveOptions(options) {
|
|
@@ -499,6 +503,22 @@ async function fetchLinkablePages() {
|
|
|
499
503
|
linkPages = body.pages ?? [];
|
|
500
504
|
return linkPages;
|
|
501
505
|
}
|
|
506
|
+
function positionPopover(el, rect, gap, width) {
|
|
507
|
+
const MARGIN = 8;
|
|
508
|
+
const vh = window.innerHeight;
|
|
509
|
+
const vw = window.innerWidth;
|
|
510
|
+
el.style.maxHeight = `${Math.max(120, vh - MARGIN * 2)}px`;
|
|
511
|
+
el.style.overflowY = "auto";
|
|
512
|
+
el.style.display = "block";
|
|
513
|
+
const h = el.getBoundingClientRect().height || el.offsetHeight || 0;
|
|
514
|
+
let top = rect.bottom + gap;
|
|
515
|
+
if (top + h > vh - MARGIN) {
|
|
516
|
+
const above = rect.top - gap - h;
|
|
517
|
+
top = above >= MARGIN ? above : vh - MARGIN - h;
|
|
518
|
+
}
|
|
519
|
+
el.style.top = `${Math.max(MARGIN, top)}px`;
|
|
520
|
+
el.style.left = `${Math.max(MARGIN, Math.min(rect.left, vw - width - MARGIN))}px`;
|
|
521
|
+
}
|
|
502
522
|
function toggleLinkDialog(anchor) {
|
|
503
523
|
if (linkDialog && linkDialog.style.display === "block") {
|
|
504
524
|
hideLinkDialog();
|
|
@@ -510,9 +530,12 @@ function toggleLinkDialog(anchor) {
|
|
|
510
530
|
if (!linkDialog) linkDialog = buildLinkDialog();
|
|
511
531
|
renderLinkDialog();
|
|
512
532
|
const rect = anchor.getBoundingClientRect();
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
533
|
+
positionPopover(
|
|
534
|
+
linkDialog,
|
|
535
|
+
{ top: rect.top, bottom: rect.bottom, left: rect.left - 180 },
|
|
536
|
+
8,
|
|
537
|
+
392
|
|
538
|
+
);
|
|
516
539
|
}
|
|
517
540
|
function buildLinkDialog() {
|
|
518
541
|
const d = document.createElement("div");
|
|
@@ -534,7 +557,7 @@ function renderLinkDialog() {
|
|
|
534
557
|
const editing = !!linkEditing;
|
|
535
558
|
const existingRef = linkEditing?.getAttribute("data-cms-ref") ?? "";
|
|
536
559
|
const onPageTab = !editing || !!existingRef;
|
|
537
|
-
d.innerHTML = `<div style="display:flex;gap:4px;padding:8px 8px 0"><button type="button" data-testid="inline-link-tab-page" data-tab="page" style="${tabCss(onPageTab)}">${L.linkTabPage}</button><button type="button" data-testid="inline-link-tab-url" data-tab="url" style="${tabCss(!onPageTab)}">${L.linkTabUrl}</button></div><div style="padding:10px 12px 12px"><div data-pane="page" style="display:${onPageTab ? "block" : "none"}"><input data-testid="inline-link-search" data-role="search" placeholder="${L.linkSearch}" style="${fieldCss()}"><div data-role="list" data-testid="inline-link-list" style="margin-top:8px;max-height:196px;overflow-y:auto;border:1px solid #3a3f4a;border-radius:8px;background:#141821"></div></div><div data-pane="url" style="display:${onPageTab ? "none" : "block"}"><label style="${labelCss()}">${L.linkUrl}</label><input data-testid="inline-link-url" data-role="url" placeholder="https://\u2026" style="${fieldCss()}"></div><label style="${labelCss()}">${L.linkText}</label><input data-testid="inline-link-text" data-role="text" placeholder="${L.linkTextAuto}" style="${fieldCss()}"><p data-role="hint" style="font-size:11.5px;color:#9aa3b2;margin:6px 0 0;line-height:1.5"></p><div data-role="live" style="display:flex;gap:8px;margin-top:12px;padding:9px 10px;background:rgba(0,178,255,.08);border:1px solid rgba(0,178,255,.28);border-radius:8px"><p style="margin:0;font-size:11.5px;color:#c9d1dd;line-height:1.55">${L.linkLiveHint}</p></div><div style="display:flex;gap:8px;align-items:center;margin-top:14px"><div data-role="remove"></div><div style="flex:1"></div><button type="button" data-testid="inline-link-cancel" data-role="cancel" style="${btnCss(false)}">${L.linkCancel}</button><button type="button" data-testid="inline-link-submit" data-role="submit" style="${btnCss(true)}" disabled>${editing ? L.linkSave : L.linkInsert}</button></div></div>`;
|
|
560
|
+
d.innerHTML = `<div style="display:flex;gap:4px;padding:8px 8px 0"><button type="button" data-testid="inline-link-tab-page" data-tab="page" style="${tabCss(onPageTab)}">${L.linkTabPage}</button><button type="button" data-testid="inline-link-tab-url" data-tab="url" style="${tabCss(!onPageTab)}">${L.linkTabUrl}</button></div><div style="padding:10px 12px 12px"><div data-pane="page" style="display:${onPageTab ? "block" : "none"}"><input data-testid="inline-link-search" data-role="search" placeholder="${L.linkSearch}" style="${fieldCss()}"><div data-role="current" data-testid="inline-link-current" style="display:none;margin-top:8px;padding:7px 10px;background:rgba(0,178,255,.08);border:1px solid rgba(0,178,255,.28);border-radius:8px;font-size:11.5px;color:#c9d1dd;line-height:1.45"></div><div data-role="list" data-testid="inline-link-list" style="margin-top:8px;max-height:196px;overflow-y:auto;border:1px solid #3a3f4a;border-radius:8px;background:#141821"></div></div><div data-pane="url" style="display:${onPageTab ? "none" : "block"}"><label style="${labelCss()}">${L.linkUrl}</label><input data-testid="inline-link-url" data-role="url" placeholder="https://\u2026" style="${fieldCss()}"></div><label style="${labelCss()}">${L.linkText}</label><input data-testid="inline-link-text" data-role="text" placeholder="${L.linkTextAuto}" style="${fieldCss()}"><p data-role="hint" style="font-size:11.5px;color:#9aa3b2;margin:6px 0 0;line-height:1.5"></p><div data-role="live" style="display:flex;gap:8px;margin-top:12px;padding:9px 10px;background:rgba(0,178,255,.08);border:1px solid rgba(0,178,255,.28);border-radius:8px"><p style="margin:0;font-size:11.5px;color:#c9d1dd;line-height:1.55">${L.linkLiveHint}</p></div><div style="display:flex;gap:8px;align-items:center;margin-top:14px"><div data-role="remove"></div><div style="flex:1"></div><button type="button" data-testid="inline-link-cancel" data-role="cancel" style="${btnCss(false)}">${L.linkCancel}</button><button type="button" data-testid="inline-link-submit" data-role="submit" style="${btnCss(true)}" disabled>${editing ? L.linkSave : L.linkInsert}</button></div></div>`;
|
|
538
561
|
const q = (role) => d.querySelector(`[data-role="${role}"]`);
|
|
539
562
|
const text = q("text");
|
|
540
563
|
const urlIn = q("url");
|
|
@@ -589,6 +612,28 @@ function buildRemoveLink() {
|
|
|
589
612
|
wrap.appendChild(btn);
|
|
590
613
|
return wrap;
|
|
591
614
|
}
|
|
615
|
+
function resolveExistingRef(ref, pages) {
|
|
616
|
+
if (!ref) return null;
|
|
617
|
+
const [collection, ...rest] = ref.split(":");
|
|
618
|
+
const slug = rest.join(":");
|
|
619
|
+
if (!collection || !slug) return null;
|
|
620
|
+
return pages.find((p) => p.collection === collection && p.slug === slug) ?? null;
|
|
621
|
+
}
|
|
622
|
+
function renderCurrentRefLine(box, ref, pages) {
|
|
623
|
+
if (!ref) {
|
|
624
|
+
box.style.display = "none";
|
|
625
|
+
box.innerHTML = "";
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
const label = escapeHtml(uiLabels.linkCurrent);
|
|
629
|
+
const page = resolveExistingRef(ref, pages);
|
|
630
|
+
box.style.display = "block";
|
|
631
|
+
box.innerHTML = page ? `${label}: <strong>${escapeHtml(page.title)}</strong> <span style="color:#9aa3b2;font-family:ui-monospace,Menlo,monospace">${escapeHtml(page.path)}</span>` : `${label}: <span style="font-family:ui-monospace,Menlo,monospace">${escapeHtml(ref)}</span>`;
|
|
632
|
+
}
|
|
633
|
+
function paintCurrentRef(pages) {
|
|
634
|
+
const box = linkDialog?.querySelector('[data-role="current"]');
|
|
635
|
+
if (box) renderCurrentRefLine(box, linkEditing?.getAttribute("data-cms-ref"), pages ?? []);
|
|
636
|
+
}
|
|
592
637
|
function renderLinkList(filter) {
|
|
593
638
|
const d = linkDialog;
|
|
594
639
|
if (!d) return;
|
|
@@ -614,19 +659,21 @@ function renderLinkList(filter) {
|
|
|
614
659
|
syncLinkDialog();
|
|
615
660
|
};
|
|
616
661
|
list.appendChild(row);
|
|
662
|
+
if (on) row.scrollIntoView?.({ block: "nearest" });
|
|
617
663
|
});
|
|
618
664
|
};
|
|
665
|
+
const preselect = (pages) => {
|
|
666
|
+
if (!linkPicked) linkPicked = resolveExistingRef(linkEditing?.getAttribute("data-cms-ref"), pages);
|
|
667
|
+
paintCurrentRef(pages);
|
|
668
|
+
};
|
|
619
669
|
if (linkPages) {
|
|
670
|
+
preselect(linkPages);
|
|
620
671
|
paint(linkPages);
|
|
621
672
|
return;
|
|
622
673
|
}
|
|
623
674
|
list.innerHTML = `<div style="padding:10px;font-size:12.5px;color:#9aa3b2">${uiLabels.linkLoading}</div>`;
|
|
624
675
|
fetchLinkablePages().then((pages) => {
|
|
625
|
-
|
|
626
|
-
if (ref && !linkPicked) {
|
|
627
|
-
const [c, ...rest] = ref.split(":");
|
|
628
|
-
linkPicked = pages.find((p) => p.collection === c && p.slug === rest.join(":")) ?? null;
|
|
629
|
-
}
|
|
676
|
+
preselect(pages);
|
|
630
677
|
paint(pages);
|
|
631
678
|
syncLinkDialog();
|
|
632
679
|
}).catch(() => {
|
|
@@ -701,9 +748,7 @@ function toggleEmojiPicker(anchor) {
|
|
|
701
748
|
const sel = window.getSelection();
|
|
702
749
|
if (sel && sel.rangeCount > 0) savedRange = sel.getRangeAt(0).cloneRange();
|
|
703
750
|
const rect = anchor.getBoundingClientRect();
|
|
704
|
-
emojiPicker
|
|
705
|
-
emojiPicker.style.left = `${Math.min(rect.left, window.innerWidth - 240)}px`;
|
|
706
|
-
emojiPicker.style.display = "block";
|
|
751
|
+
positionPopover(emojiPicker, rect, 6, 230);
|
|
707
752
|
}
|
|
708
753
|
function hideEmojiPicker() {
|
|
709
754
|
if (emojiPicker) emojiPicker.style.display = "none";
|
|
@@ -836,7 +881,7 @@ function serializeBlockChildren(parent) {
|
|
|
836
881
|
const s = serializeBlock(node).trim();
|
|
837
882
|
if (s) blocks.push(s);
|
|
838
883
|
} else {
|
|
839
|
-
inlineRun
|
|
884
|
+
inlineRun = joinInline(inlineRun, serializeInlineNode(node));
|
|
840
885
|
}
|
|
841
886
|
});
|
|
842
887
|
flushInline();
|
|
@@ -916,10 +961,41 @@ function serializeList(listEl, ordered) {
|
|
|
916
961
|
function escapeAttr(value) {
|
|
917
962
|
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
918
963
|
}
|
|
964
|
+
function preservedLinkAttrs(el) {
|
|
965
|
+
const out = [];
|
|
966
|
+
for (const attr of Array.from(el.attributes)) {
|
|
967
|
+
const name = attr.name.toLowerCase();
|
|
968
|
+
if (name === "href") continue;
|
|
969
|
+
if (name.startsWith("on")) continue;
|
|
970
|
+
if (/^javascript:/i.test(attr.value.trim())) continue;
|
|
971
|
+
out.push(`${name}="${escapeAttr(attr.value)}"`);
|
|
972
|
+
}
|
|
973
|
+
return out;
|
|
974
|
+
}
|
|
975
|
+
var HARD_BREAK = " \n";
|
|
976
|
+
function edgeWhitespace(ws) {
|
|
977
|
+
if (!ws) return "";
|
|
978
|
+
return /\n/.test(ws) ? HARD_BREAK : " ";
|
|
979
|
+
}
|
|
980
|
+
function wrapEmphasis(inner, delimiter) {
|
|
981
|
+
const core = inner.trim();
|
|
982
|
+
if (!core) return "";
|
|
983
|
+
const lead = edgeWhitespace(inner.slice(0, inner.length - inner.trimStart().length));
|
|
984
|
+
const trail = edgeWhitespace(inner.slice(inner.trimEnd().length));
|
|
985
|
+
return lead + delimiter + core + delimiter + trail;
|
|
986
|
+
}
|
|
987
|
+
function joinInline(out, piece) {
|
|
988
|
+
if (!piece) return out;
|
|
989
|
+
const outTail = /\s*$/.exec(out)[0];
|
|
990
|
+
const pieceHead = /^\s*/.exec(piece)[0];
|
|
991
|
+
if (!outTail || !pieceHead) return out + piece;
|
|
992
|
+
const merged = /\n/.test(outTail + pieceHead) ? HARD_BREAK : " ";
|
|
993
|
+
return out.slice(0, out.length - outTail.length) + merged + piece.slice(pieceHead.length);
|
|
994
|
+
}
|
|
919
995
|
function serializeInline(node) {
|
|
920
996
|
let out = "";
|
|
921
997
|
node.childNodes.forEach((child) => {
|
|
922
|
-
out
|
|
998
|
+
out = joinInline(out, serializeInlineNode(child));
|
|
923
999
|
});
|
|
924
1000
|
return out;
|
|
925
1001
|
}
|
|
@@ -936,11 +1012,11 @@ function serializeInlineNode(child) {
|
|
|
936
1012
|
switch (tag) {
|
|
937
1013
|
case "strong":
|
|
938
1014
|
case "b":
|
|
939
|
-
out +=
|
|
1015
|
+
out += wrapEmphasis(inner, "**");
|
|
940
1016
|
break;
|
|
941
1017
|
case "em":
|
|
942
1018
|
case "i":
|
|
943
|
-
out +=
|
|
1019
|
+
out += wrapEmphasis(inner, "*");
|
|
944
1020
|
break;
|
|
945
1021
|
case "code":
|
|
946
1022
|
out += "`" + inner + "`";
|
|
@@ -950,12 +1026,9 @@ function serializeInlineNode(child) {
|
|
|
950
1026
|
break;
|
|
951
1027
|
case "a": {
|
|
952
1028
|
const href = el.getAttribute("href") || "";
|
|
953
|
-
const
|
|
954
|
-
if (
|
|
955
|
-
|
|
956
|
-
const label = el.getAttribute("data-cms-ref-label");
|
|
957
|
-
if (label) attrs.push(`data-cms-ref-label="${escapeAttr(label)}"`);
|
|
958
|
-
out += `<a ${attrs.join(" ")}>${inner}</a>`;
|
|
1029
|
+
const extras = preservedLinkAttrs(el);
|
|
1030
|
+
if (extras.length > 0) {
|
|
1031
|
+
out += `<a ${[`href="${escapeAttr(href)}"`, ...extras].join(" ")}>${inner}</a>`;
|
|
959
1032
|
} else {
|
|
960
1033
|
out += href ? `[${inner}](${href})` : inner;
|
|
961
1034
|
}
|
|
@@ -1090,6 +1163,9 @@ function injectStyles() {
|
|
|
1090
1163
|
getConnectedToken,
|
|
1091
1164
|
htmlToMarkdown,
|
|
1092
1165
|
initInlineEdit,
|
|
1093
|
-
|
|
1166
|
+
positionPopover,
|
|
1167
|
+
renderCurrentRefLine,
|
|
1168
|
+
rescanFields,
|
|
1169
|
+
resolveExistingRef
|
|
1094
1170
|
});
|
|
1095
1171
|
//# sourceMappingURL=index.cjs.map
|