@broberg/cms-inline-edit 0.5.5 → 0.6.1
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 +83 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +81 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -29,7 +29,8 @@ __export(index_exports, {
|
|
|
29
29
|
positionPopover: () => positionPopover,
|
|
30
30
|
renderCurrentRefLine: () => renderCurrentRefLine,
|
|
31
31
|
rescanFields: () => rescanFields,
|
|
32
|
-
resolveExistingRef: () => resolveExistingRef
|
|
32
|
+
resolveExistingRef: () => resolveExistingRef,
|
|
33
|
+
setLinkTarget: () => setLinkTarget
|
|
33
34
|
});
|
|
34
35
|
module.exports = __toCommonJS(index_exports);
|
|
35
36
|
|
|
@@ -43,6 +44,30 @@ function applyFieldSlice(current, original, next) {
|
|
|
43
44
|
return current.slice(0, first) + next + current.slice(first + original.length);
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
// src/link-target.ts
|
|
48
|
+
function isSchemeless(raw) {
|
|
49
|
+
const v = (raw || "").trim();
|
|
50
|
+
if (!v) return false;
|
|
51
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(v)) return false;
|
|
52
|
+
if (v.startsWith("//")) return false;
|
|
53
|
+
if (v.startsWith("/")) return false;
|
|
54
|
+
if (v.startsWith("#")) return false;
|
|
55
|
+
if (v.startsWith("?")) return false;
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
function withHttps(raw) {
|
|
59
|
+
return `https://${(raw || "").trim().replace(/^\/+/, "")}`;
|
|
60
|
+
}
|
|
61
|
+
function isExternalHost(raw, currentHost) {
|
|
62
|
+
const v = (raw || "").trim();
|
|
63
|
+
if (!/^https?:\/\//i.test(v)) return false;
|
|
64
|
+
try {
|
|
65
|
+
return new URL(v).host.toLowerCase() !== (currentHost || "").toLowerCase();
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
46
71
|
// src/token-safe.ts
|
|
47
72
|
var TEXT_NODE = 3;
|
|
48
73
|
var ELEMENT_NODE = 1;
|
|
@@ -97,6 +122,9 @@ var DEFAULT_LABELS = {
|
|
|
97
122
|
linkLiveHint: "Linket peger p\xE5 <b>siden</b> \u2014 ikke p\xE5 en adresse. Flyttes siden, eller f\xE5r den et nyt navn, retter linket sig selv.",
|
|
98
123
|
linkUrlHint: "En fri adresse peger pr\xE6cis d\xE9r, du skriver. Den f\xF8lger <b>ikke</b> med, hvis m\xE5let flytter sig.",
|
|
99
124
|
linkUrl: "Adresse",
|
|
125
|
+
linkNewTab: "\xC5bn i ny fane",
|
|
126
|
+
linkSchemeless: "<b>{v}</b> l\xE6ses som en side p\xE5 <b>dette</b> site \u2014 ikke som en adresse ude p\xE5 nettet.",
|
|
127
|
+
linkSchemelessFix: "Tilf\xF8j https://",
|
|
100
128
|
linkInsert: "Inds\xE6t link",
|
|
101
129
|
linkSave: "Gem \xE6ndring",
|
|
102
130
|
linkCancel: "Annull\xE9r",
|
|
@@ -299,10 +327,12 @@ function showIdlePill() {
|
|
|
299
327
|
removeIdlePill();
|
|
300
328
|
const wrap = document.createElement("div");
|
|
301
329
|
wrap.setAttribute("data-cms-inline-edit-idle", "");
|
|
330
|
+
wrap.setAttribute("data-testid", "inline-edit-idle");
|
|
302
331
|
wrap.style.cssText = "position:fixed;bottom:16px;left:16px;display:inline-flex;align-items:stretch;z-index:2147483647;box-shadow:0 4px 16px rgba(0,0,0,.3);border-radius:999px;overflow:hidden;";
|
|
303
332
|
const edit = document.createElement("button");
|
|
304
333
|
edit.type = "button";
|
|
305
334
|
edit.setAttribute("data-cms-inline-edit-enter", "");
|
|
335
|
+
edit.setAttribute("data-testid", "inline-edit-enter");
|
|
306
336
|
edit.style.cssText = "display:inline-flex;align-items:center;gap:7px;background:#1c2027;color:#fff;font:600 12px system-ui,sans-serif;padding:8px 14px;border:none;cursor:pointer;";
|
|
307
337
|
const editText = document.createElement("span");
|
|
308
338
|
editText.textContent = options.connectLabel;
|
|
@@ -311,6 +341,7 @@ function showIdlePill() {
|
|
|
311
341
|
const out = document.createElement("button");
|
|
312
342
|
out.type = "button";
|
|
313
343
|
out.setAttribute("data-cms-inline-edit-logout", "");
|
|
344
|
+
out.setAttribute("data-testid", "inline-edit-logout");
|
|
314
345
|
out.textContent = options.logoutLabel;
|
|
315
346
|
out.style.cssText = "background:#141821;color:#9aa4b2;font:600 11px system-ui,sans-serif;padding:8px 12px;border:none;border-left:1px solid rgba(255,255,255,.12);cursor:pointer;";
|
|
316
347
|
out.addEventListener("click", () => {
|
|
@@ -474,6 +505,8 @@ var savedRange = null;
|
|
|
474
505
|
var linkDialog = null;
|
|
475
506
|
var linkPages = null;
|
|
476
507
|
var linkPicked = null;
|
|
508
|
+
var linkNewTab = false;
|
|
509
|
+
var linkNewTabTouched = false;
|
|
477
510
|
var linkEditing = null;
|
|
478
511
|
function hideLinkDialog() {
|
|
479
512
|
if (linkDialog) linkDialog.style.display = "none";
|
|
@@ -555,9 +588,13 @@ function renderLinkDialog() {
|
|
|
555
588
|
if (!d) return;
|
|
556
589
|
const L = uiLabels;
|
|
557
590
|
const editing = !!linkEditing;
|
|
591
|
+
if (!editing) {
|
|
592
|
+
linkNewTab = false;
|
|
593
|
+
linkNewTabTouched = false;
|
|
594
|
+
}
|
|
558
595
|
const existingRef = linkEditing?.getAttribute("data-cms-ref") ?? "";
|
|
559
596
|
const onPageTab = !editing || !!existingRef;
|
|
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>`;
|
|
597
|
+
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 data-role="schemeless" data-testid="inline-link-schemeless" style="display:none;margin-top:8px;padding:8px 10px;background:rgba(255,176,32,.10);border:1px solid rgba(255,176,32,.34);border-radius:8px"><p data-role="schemeless-text" style="margin:0;font-size:11.5px;color:#e8d6b0;line-height:1.5"></p><button type="button" data-testid="inline-link-add-scheme" data-role="add-scheme" style="${btnCss(false)};margin-top:7px;height:26px;font-size:12px">${L.linkSchemelessFix}</button></div></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><button type="button" data-role="newtab" data-testid="inline-link-newtab" aria-pressed="false" style="display:flex;align-items:center;gap:8px;margin-top:12px;background:none;border:none;padding:0;cursor:pointer;font-family:inherit;font-size:12.5px;color:#c9d1dd"><span data-role="newtab-box" style="${checkboxCss(false)}"></span><span>${L.linkNewTab}</span></button><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>`;
|
|
561
598
|
const q = (role) => d.querySelector(`[data-role="${role}"]`);
|
|
562
599
|
const text = q("text");
|
|
563
600
|
const urlIn = q("url");
|
|
@@ -565,6 +602,8 @@ function renderLinkDialog() {
|
|
|
565
602
|
if (editing) {
|
|
566
603
|
text.value = linkEditing?.getAttribute("data-cms-ref-label") === "auto" ? "" : linkEditing?.textContent ?? "";
|
|
567
604
|
if (!existingRef) urlIn.value = linkEditing?.getAttribute("href") ?? "";
|
|
605
|
+
linkNewTab = linkEditing?.getAttribute("target") === "_blank";
|
|
606
|
+
linkNewTabTouched = true;
|
|
568
607
|
q("remove").appendChild(buildRemoveLink());
|
|
569
608
|
}
|
|
570
609
|
d.querySelectorAll("[data-tab]").forEach((btn) => {
|
|
@@ -584,6 +623,16 @@ function renderLinkDialog() {
|
|
|
584
623
|
urlIn.oninput = syncLinkDialog;
|
|
585
624
|
q("cancel").onclick = hideLinkDialog;
|
|
586
625
|
q("submit").onclick = applyLink;
|
|
626
|
+
q("newtab").onclick = () => {
|
|
627
|
+
linkNewTab = !linkNewTab;
|
|
628
|
+
linkNewTabTouched = true;
|
|
629
|
+
syncLinkDialog();
|
|
630
|
+
};
|
|
631
|
+
q("add-scheme").onclick = () => {
|
|
632
|
+
urlIn.value = withHttps(urlIn.value);
|
|
633
|
+
urlIn.focus();
|
|
634
|
+
syncLinkDialog();
|
|
635
|
+
};
|
|
587
636
|
renderLinkList("");
|
|
588
637
|
syncLinkDialog();
|
|
589
638
|
}
|
|
@@ -689,6 +738,30 @@ function syncLinkDialog() {
|
|
|
689
738
|
q("hint").innerHTML = own ? uiLabels.linkTextOwnHint : onPage ? uiLabels.linkTextAutoHint : uiLabels.linkUrlHint;
|
|
690
739
|
q("live").style.display = onPage ? "flex" : "none";
|
|
691
740
|
q("submit").disabled = onPage ? !linkPicked : !q("url").value.trim();
|
|
741
|
+
const raw = q("url").value;
|
|
742
|
+
const doubtful = !onPage && isSchemeless(raw);
|
|
743
|
+
q("schemeless").style.display = doubtful ? "block" : "none";
|
|
744
|
+
if (doubtful) {
|
|
745
|
+
q("schemeless-text").innerHTML = uiLabels.linkSchemeless.replace(
|
|
746
|
+
"{v}",
|
|
747
|
+
escapeHtml(raw.trim())
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
if (!onPage && !linkNewTabTouched) {
|
|
751
|
+
linkNewTab = isExternalHost(raw, typeof location !== "undefined" ? location.host : "");
|
|
752
|
+
}
|
|
753
|
+
const box = q("newtab-box");
|
|
754
|
+
if (box) box.setAttribute("style", checkboxCss(linkNewTab));
|
|
755
|
+
q("newtab").setAttribute("aria-pressed", String(linkNewTab));
|
|
756
|
+
}
|
|
757
|
+
function setLinkTarget(el, newTab) {
|
|
758
|
+
if (newTab) {
|
|
759
|
+
el.setAttribute("target", "_blank");
|
|
760
|
+
el.setAttribute("rel", "noopener");
|
|
761
|
+
} else {
|
|
762
|
+
el.removeAttribute("target");
|
|
763
|
+
el.removeAttribute("rel");
|
|
764
|
+
}
|
|
692
765
|
}
|
|
693
766
|
function applyLink() {
|
|
694
767
|
const d = linkDialog;
|
|
@@ -700,18 +773,21 @@ function applyLink() {
|
|
|
700
773
|
if (!href) return;
|
|
701
774
|
const ref = onPage && linkPicked ? `${linkPicked.collection}:${linkPicked.slug}` : "";
|
|
702
775
|
const label = own || (onPage ? linkPicked?.title ?? href : href);
|
|
776
|
+
const applyTarget = (el) => setLinkTarget(el, linkNewTab);
|
|
703
777
|
if (linkEditing) {
|
|
704
778
|
linkEditing.setAttribute("href", href);
|
|
705
779
|
if (ref) linkEditing.setAttribute("data-cms-ref", ref);
|
|
706
780
|
else linkEditing.removeAttribute("data-cms-ref");
|
|
707
781
|
if (ref && !own) linkEditing.setAttribute("data-cms-ref-label", "auto");
|
|
708
782
|
else linkEditing.removeAttribute("data-cms-ref-label");
|
|
783
|
+
applyTarget(linkEditing);
|
|
709
784
|
linkEditing.textContent = label;
|
|
710
785
|
hideLinkDialog();
|
|
711
786
|
return;
|
|
712
787
|
}
|
|
713
788
|
const a = document.createElement("a");
|
|
714
789
|
a.setAttribute("href", href);
|
|
790
|
+
applyTarget(a);
|
|
715
791
|
if (ref) {
|
|
716
792
|
a.setAttribute("data-cms-ref", ref);
|
|
717
793
|
if (!own) a.setAttribute("data-cms-ref-label", "auto");
|
|
@@ -736,6 +812,7 @@ function escapeHtml(v) {
|
|
|
736
812
|
return v.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
737
813
|
}
|
|
738
814
|
var tabCss = (on) => "flex:1;background:" + (on ? "#2a2f38" : "none") + ";border:1px solid " + (on ? "#3a3f4a" : "transparent") + ";color:" + (on ? "#fff" : "#9aa3b2") + ";height:32px;border-radius:7px;font-size:13px;cursor:pointer;font-weight:500;font-family:inherit;";
|
|
815
|
+
var checkboxCss = (on) => "width:16px;height:16px;flex:0 0 16px;border-radius:4px;box-sizing:border-box;display:inline-block;" + (on ? `background:#00b2ff;border:1px solid #00b2ff;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4 8.5l2.6 2.6L12 5.8' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");background-size:100% 100%;` : "background:#141821;border:1px solid #3a3f4a;");
|
|
739
816
|
var fieldCss = () => "width:100%;background:#141821;border:1px solid #3a3f4a;color:#fff;height:34px;border-radius:7px;padding:0 10px;font-size:13.5px;outline:none;font-family:inherit;box-sizing:border-box;";
|
|
740
817
|
var labelCss = () => "font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:#9aa3b2;margin:12px 0 5px;display:block;";
|
|
741
818
|
var btnCss = (primary) => "height:33px;border-radius:7px;font-size:13px;cursor:pointer;padding:0 14px;font-weight:600;font-family:inherit;" + (primary ? "background:#00b2ff;color:#04121b;border:none;" : "background:none;border:1px solid #3a3f4a;color:#fff;font-weight:500;");
|
|
@@ -1099,6 +1176,7 @@ function showPill(el, state) {
|
|
|
1099
1176
|
if (!pill) {
|
|
1100
1177
|
pill = document.createElement("span");
|
|
1101
1178
|
pill.setAttribute("data-cms-inline-edit-pill", "");
|
|
1179
|
+
pill.setAttribute("data-testid", "inline-edit-pill");
|
|
1102
1180
|
document.body.appendChild(pill);
|
|
1103
1181
|
pills.set(el, pill);
|
|
1104
1182
|
}
|
|
@@ -1126,6 +1204,7 @@ function showActiveBadge(options) {
|
|
|
1126
1204
|
const badge = document.createElement("button");
|
|
1127
1205
|
badge.type = "button";
|
|
1128
1206
|
badge.setAttribute("data-cms-inline-edit-badge", "");
|
|
1207
|
+
badge.setAttribute("data-testid", "inline-edit-badge");
|
|
1129
1208
|
badge.style.cssText = "position:fixed;bottom:16px;left:16px;display:inline-flex;align-items:center;gap:7px;background:#1c2027;color:#fff;font:600 12px system-ui,sans-serif;padding:8px 14px;border-radius:999px;z-index:2147483647;box-shadow:0 4px 16px rgba(0,0,0,.3);border:none;cursor:pointer;opacity:.9;transition:opacity .15s;";
|
|
1130
1209
|
const text = document.createElement("span");
|
|
1131
1210
|
text.textContent = options.disconnectLabel;
|
|
@@ -1166,6 +1245,7 @@ function injectStyles() {
|
|
|
1166
1245
|
positionPopover,
|
|
1167
1246
|
renderCurrentRefLine,
|
|
1168
1247
|
rescanFields,
|
|
1169
|
-
resolveExistingRef
|
|
1248
|
+
resolveExistingRef,
|
|
1249
|
+
setLinkTarget
|
|
1170
1250
|
});
|
|
1171
1251
|
//# sourceMappingURL=index.cjs.map
|