@broberg/cms-inline-edit 0.4.21 → 0.5.0
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/README.md +53 -0
- package/dist/index.cjs +311 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +311 -11
- package/dist/index.js.map +1 -1
- package/dist/server/index.cjs +29 -0
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +10 -1
- package/dist/server/index.d.ts +10 -1
- package/dist/server/index.js +28 -0
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -50,7 +50,27 @@ var DEFAULT_LABELS = {
|
|
|
50
50
|
done: "F\xE6rdig",
|
|
51
51
|
saving: "Gemmer\u2026",
|
|
52
52
|
saved: "Gemt \u2713",
|
|
53
|
-
error: "Fejl \u2014 pr\xF8v igen"
|
|
53
|
+
error: "Fejl \u2014 pr\xF8v igen",
|
|
54
|
+
link: "Link",
|
|
55
|
+
linkTabPage: "Side p\xE5 sitet",
|
|
56
|
+
linkTabUrl: "Fri adresse",
|
|
57
|
+
linkSearch: "S\xF8g efter en side\u2026",
|
|
58
|
+
linkText: "Linktekst",
|
|
59
|
+
linkTextAuto: "F\xF8lger sidens titel",
|
|
60
|
+
linkTextAutoHint: "<b>Tom = f\xF8lger sidens titel.</b> Omd\xF8bes siden, retter teksten sig selv. Skriver du din egen tekst, bliver den st\xE5ende.",
|
|
61
|
+
linkTextOwnHint: "Linket viser <b>din egen tekst</b>. Den bliver st\xE5ende, ogs\xE5 hvis siden omd\xF8bes.",
|
|
62
|
+
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.",
|
|
63
|
+
linkUrlHint: "En fri adresse peger pr\xE6cis d\xE9r, du skriver. Den f\xF8lger <b>ikke</b> med, hvis m\xE5let flytter sig.",
|
|
64
|
+
linkUrl: "Adresse",
|
|
65
|
+
linkInsert: "Inds\xE6t link",
|
|
66
|
+
linkSave: "Gem \xE6ndring",
|
|
67
|
+
linkCancel: "Annull\xE9r",
|
|
68
|
+
linkRemove: "Fjern link",
|
|
69
|
+
linkRemoveConfirm: "Fjern?",
|
|
70
|
+
linkYes: "Ja",
|
|
71
|
+
linkNo: "Nej",
|
|
72
|
+
linkEmpty: "Ingen sider fundet",
|
|
73
|
+
linkLoading: "Henter sider\u2026"
|
|
54
74
|
};
|
|
55
75
|
var uiLabels = DEFAULT_LABELS;
|
|
56
76
|
function resolveOptions(options) {
|
|
@@ -152,6 +172,7 @@ function isExpired(token) {
|
|
|
152
172
|
var SQUARE_PEN_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z"/></svg>';
|
|
153
173
|
var UL_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="8" x2="21" y1="6" y2="6"/><line x1="8" x2="21" y1="12" y2="12"/><line x1="8" x2="21" y1="18" y2="18"/><line x1="3" x2="3.01" y1="6" y2="6"/><line x1="3" x2="3.01" y1="12" y2="12"/><line x1="3" x2="3.01" y1="18" y2="18"/></svg>';
|
|
154
174
|
var OL_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="10" x2="21" y1="6" y2="6"/><line x1="10" x2="21" y1="12" y2="12"/><line x1="10" x2="21" y1="18" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/></svg>';
|
|
175
|
+
var LINK_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.5.5l3-3a5 5 0 0 0-7-7l-1.7 1.7"/><path d="M14 11a5 5 0 0 0-7.5-.5l-3 3a5 5 0 0 0 7 7l1.7-1.7"/></svg>';
|
|
155
176
|
function makeIcon() {
|
|
156
177
|
const icon = document.createElement("span");
|
|
157
178
|
icon.style.cssText = "display:inline-flex;line-height:0;flex:0 0 auto";
|
|
@@ -310,6 +331,7 @@ function deactivateRich() {
|
|
|
310
331
|
el.removeAttribute("contenteditable");
|
|
311
332
|
el.classList.remove("cms-rich-editing");
|
|
312
333
|
hideRichToolbar();
|
|
334
|
+
hideLinkDialog();
|
|
313
335
|
if (el.innerHTML !== originalHtml) {
|
|
314
336
|
const value = mode === "html" ? el.innerHTML : htmlToMarkdown(el.innerHTML);
|
|
315
337
|
void saveField(el, value, token, options);
|
|
@@ -355,6 +377,10 @@ function buildRichToolbar() {
|
|
|
355
377
|
t.appendChild(toolbarButton(UL_SVG, uiLabels.unorderedList, () => document.execCommand("insertUnorderedList")));
|
|
356
378
|
t.appendChild(toolbarButton(OL_SVG, uiLabels.orderedList, () => document.execCommand("insertOrderedList")));
|
|
357
379
|
t.appendChild(sep());
|
|
380
|
+
const linkBtn = toolbarButton(LINK_SVG, uiLabels.link, () => toggleLinkDialog(linkBtn));
|
|
381
|
+
linkBtn.setAttribute("data-testid", "inline-toolbar-link");
|
|
382
|
+
t.appendChild(linkBtn);
|
|
383
|
+
t.appendChild(sep());
|
|
358
384
|
const clrLabel = document.createElement("label");
|
|
359
385
|
clrLabel.style.cssText = "display:flex;align-items:center;gap:5px;color:#9aa4b2;font-size:12px;cursor:pointer;";
|
|
360
386
|
clrLabel.textContent = uiLabels.color;
|
|
@@ -388,6 +414,231 @@ var EMOJIS = "\u{1F600} \u{1F603} \u{1F604} \u{1F601} \u{1F606} \u{1F609} \u{1F6
|
|
|
388
414
|
);
|
|
389
415
|
var emojiPicker = null;
|
|
390
416
|
var savedRange = null;
|
|
417
|
+
var linkDialog = null;
|
|
418
|
+
var linkPages = null;
|
|
419
|
+
var linkPicked = null;
|
|
420
|
+
var linkEditing = null;
|
|
421
|
+
function hideLinkDialog() {
|
|
422
|
+
if (linkDialog) linkDialog.style.display = "none";
|
|
423
|
+
linkPicked = null;
|
|
424
|
+
linkEditing = null;
|
|
425
|
+
}
|
|
426
|
+
function anchorAtCaret() {
|
|
427
|
+
const sel = window.getSelection();
|
|
428
|
+
if (!sel || sel.rangeCount === 0) return null;
|
|
429
|
+
let node = sel.getRangeAt(0).startContainer;
|
|
430
|
+
while (node && node !== document.body) {
|
|
431
|
+
if (node.nodeType === Node.ELEMENT_NODE && node.tagName === "A") {
|
|
432
|
+
return node;
|
|
433
|
+
}
|
|
434
|
+
node = node.parentNode;
|
|
435
|
+
}
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
async function fetchLinkablePages() {
|
|
439
|
+
if (linkPages) return linkPages;
|
|
440
|
+
if (!richCtx) return [];
|
|
441
|
+
const { options, token } = richCtx;
|
|
442
|
+
const url = `${options.cmsBaseUrl}/api/inline-edit/pages?site=${encodeURIComponent(options.siteId)}`;
|
|
443
|
+
const res = await fetch(url, { headers: { Authorization: `Bearer ${token}` } });
|
|
444
|
+
if (!res.ok) throw new Error(`pages ${res.status}`);
|
|
445
|
+
const body = await res.json();
|
|
446
|
+
linkPages = body.pages ?? [];
|
|
447
|
+
return linkPages;
|
|
448
|
+
}
|
|
449
|
+
function toggleLinkDialog(anchor) {
|
|
450
|
+
if (linkDialog && linkDialog.style.display === "block") {
|
|
451
|
+
hideLinkDialog();
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
const sel = window.getSelection();
|
|
455
|
+
if (sel && sel.rangeCount > 0) savedRange = sel.getRangeAt(0).cloneRange();
|
|
456
|
+
linkEditing = anchorAtCaret();
|
|
457
|
+
if (!linkDialog) linkDialog = buildLinkDialog();
|
|
458
|
+
renderLinkDialog();
|
|
459
|
+
const rect = anchor.getBoundingClientRect();
|
|
460
|
+
linkDialog.style.top = `${rect.bottom + 8}px`;
|
|
461
|
+
linkDialog.style.left = `${Math.min(Math.max(8, rect.left - 180), window.innerWidth - 400)}px`;
|
|
462
|
+
linkDialog.style.display = "block";
|
|
463
|
+
}
|
|
464
|
+
function buildLinkDialog() {
|
|
465
|
+
const d = document.createElement("div");
|
|
466
|
+
d.setAttribute("data-cms-inline-edit-toolbar", "");
|
|
467
|
+
d.setAttribute("data-testid", "inline-link-dialog");
|
|
468
|
+
d.style.cssText = "position:fixed;z-index:2147483646;background:#1c2027;border:1px solid #3a3f4a;border-radius:10px;width:392px;display:none;box-shadow:0 8px 32px rgba(0,0,0,.5);font-family:system-ui,sans-serif;color:#fff;overflow:hidden;";
|
|
469
|
+
d.addEventListener("mousedown", (e) => {
|
|
470
|
+
const t = e.target;
|
|
471
|
+
if (t.tagName !== "INPUT") e.preventDefault();
|
|
472
|
+
e.stopPropagation();
|
|
473
|
+
});
|
|
474
|
+
document.body.appendChild(d);
|
|
475
|
+
return d;
|
|
476
|
+
}
|
|
477
|
+
function renderLinkDialog() {
|
|
478
|
+
const d = linkDialog;
|
|
479
|
+
if (!d) return;
|
|
480
|
+
const L = uiLabels;
|
|
481
|
+
const editing = !!linkEditing;
|
|
482
|
+
const existingRef = linkEditing?.getAttribute("data-cms-ref") ?? "";
|
|
483
|
+
const onPageTab = !editing || !!existingRef;
|
|
484
|
+
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>`;
|
|
485
|
+
const q = (role) => d.querySelector(`[data-role="${role}"]`);
|
|
486
|
+
const text = q("text");
|
|
487
|
+
const urlIn = q("url");
|
|
488
|
+
const search = q("search");
|
|
489
|
+
if (editing) {
|
|
490
|
+
text.value = linkEditing?.getAttribute("data-cms-ref-label") === "auto" ? "" : linkEditing?.textContent ?? "";
|
|
491
|
+
if (!existingRef) urlIn.value = linkEditing?.getAttribute("href") ?? "";
|
|
492
|
+
q("remove").appendChild(buildRemoveLink());
|
|
493
|
+
}
|
|
494
|
+
d.querySelectorAll("[data-tab]").forEach((btn) => {
|
|
495
|
+
btn.onclick = () => {
|
|
496
|
+
const page = btn.dataset.tab === "page";
|
|
497
|
+
d.querySelectorAll("[data-tab]").forEach((b) => {
|
|
498
|
+
b.setAttribute("style", tabCss(b.dataset.tab === "page" ? page : !page));
|
|
499
|
+
});
|
|
500
|
+
d.querySelector('[data-pane="page"]').style.display = page ? "block" : "none";
|
|
501
|
+
d.querySelector('[data-pane="url"]').style.display = page ? "none" : "block";
|
|
502
|
+
q("live").style.display = page ? "flex" : "none";
|
|
503
|
+
syncLinkDialog();
|
|
504
|
+
};
|
|
505
|
+
});
|
|
506
|
+
search.oninput = () => renderLinkList(search.value);
|
|
507
|
+
text.oninput = syncLinkDialog;
|
|
508
|
+
urlIn.oninput = syncLinkDialog;
|
|
509
|
+
q("cancel").onclick = hideLinkDialog;
|
|
510
|
+
q("submit").onclick = applyLink;
|
|
511
|
+
renderLinkList("");
|
|
512
|
+
syncLinkDialog();
|
|
513
|
+
}
|
|
514
|
+
function buildRemoveLink() {
|
|
515
|
+
const wrap = document.createElement("div");
|
|
516
|
+
const btn = document.createElement("button");
|
|
517
|
+
btn.type = "button";
|
|
518
|
+
btn.setAttribute("data-testid", "inline-link-remove");
|
|
519
|
+
btn.textContent = uiLabels.linkRemove;
|
|
520
|
+
btn.style.cssText = "background:none;border:none;color:#ff8a8a;font-size:12.5px;cursor:pointer;padding:0 2px;";
|
|
521
|
+
btn.onclick = () => {
|
|
522
|
+
wrap.innerHTML = `<span style="font-size:11.5px;color:#ff8a8a;font-weight:500;padding:0 2px">${uiLabels.linkRemoveConfirm}</span><button type="button" data-testid="inline-link-remove-yes" style="font-size:11px;padding:2px 8px;border-radius:4px;border:none;background:#c0392b;color:#fff;cursor:pointer;line-height:1.4;margin-left:6px">${uiLabels.linkYes}</button><button type="button" data-testid="inline-link-remove-no" style="font-size:11px;padding:2px 8px;border-radius:4px;border:1px solid #3a3f4a;background:none;color:#fff;cursor:pointer;line-height:1.4;margin-left:6px">${uiLabels.linkNo}</button>`;
|
|
523
|
+
wrap.querySelector('[data-testid="inline-link-remove-no"]').onclick = () => {
|
|
524
|
+
wrap.innerHTML = "";
|
|
525
|
+
wrap.appendChild(btn);
|
|
526
|
+
};
|
|
527
|
+
wrap.querySelector('[data-testid="inline-link-remove-yes"]').onclick = () => {
|
|
528
|
+
if (linkEditing) {
|
|
529
|
+
const parent = linkEditing.parentNode;
|
|
530
|
+
while (linkEditing.firstChild) parent?.insertBefore(linkEditing.firstChild, linkEditing);
|
|
531
|
+
parent?.removeChild(linkEditing);
|
|
532
|
+
}
|
|
533
|
+
hideLinkDialog();
|
|
534
|
+
};
|
|
535
|
+
};
|
|
536
|
+
wrap.appendChild(btn);
|
|
537
|
+
return wrap;
|
|
538
|
+
}
|
|
539
|
+
function renderLinkList(filter) {
|
|
540
|
+
const d = linkDialog;
|
|
541
|
+
if (!d) return;
|
|
542
|
+
const list = d.querySelector('[data-role="list"]');
|
|
543
|
+
if (!list) return;
|
|
544
|
+
const paint = (pages) => {
|
|
545
|
+
const f = filter.trim().toLowerCase();
|
|
546
|
+
const shown = pages.filter((p) => !f || `${p.title} ${p.path}`.toLowerCase().includes(f));
|
|
547
|
+
if (!shown.length) {
|
|
548
|
+
list.innerHTML = `<div style="padding:10px;font-size:12.5px;color:#9aa3b2">${uiLabels.linkEmpty}</div>`;
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
list.innerHTML = "";
|
|
552
|
+
shown.forEach((p) => {
|
|
553
|
+
const on = linkPicked?.collection === p.collection && linkPicked?.slug === p.slug;
|
|
554
|
+
const row = document.createElement("div");
|
|
555
|
+
row.setAttribute("data-testid", `inline-link-page-${p.collection}-${p.slug}`);
|
|
556
|
+
row.style.cssText = "display:flex;align-items:center;gap:10px;padding:8px 10px;cursor:pointer;border-bottom:1px solid #232833;" + (on ? "background:rgba(0,178,255,.14);" : "");
|
|
557
|
+
row.innerHTML = `<div style="min-width:0;flex:1"><div style="font-size:13.5px;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${escapeHtml(p.title)}</div><div style="font-size:11.5px;color:#9aa3b2;font-family:ui-monospace,Menlo,monospace;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${escapeHtml(p.path)}</div></div><span style="flex:none;font-size:10px;text-transform:uppercase;color:#9aa3b2;border:1px solid #3a3f4a;border-radius:4px;padding:2px 6px;white-space:nowrap">${escapeHtml(p.label)}</span>`;
|
|
558
|
+
row.onclick = () => {
|
|
559
|
+
linkPicked = p;
|
|
560
|
+
renderLinkList(filter);
|
|
561
|
+
syncLinkDialog();
|
|
562
|
+
};
|
|
563
|
+
list.appendChild(row);
|
|
564
|
+
});
|
|
565
|
+
};
|
|
566
|
+
if (linkPages) {
|
|
567
|
+
paint(linkPages);
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
list.innerHTML = `<div style="padding:10px;font-size:12.5px;color:#9aa3b2">${uiLabels.linkLoading}</div>`;
|
|
571
|
+
fetchLinkablePages().then((pages) => {
|
|
572
|
+
const ref = linkEditing?.getAttribute("data-cms-ref");
|
|
573
|
+
if (ref && !linkPicked) {
|
|
574
|
+
const [c, ...rest] = ref.split(":");
|
|
575
|
+
linkPicked = pages.find((p) => p.collection === c && p.slug === rest.join(":")) ?? null;
|
|
576
|
+
}
|
|
577
|
+
paint(pages);
|
|
578
|
+
syncLinkDialog();
|
|
579
|
+
}).catch(() => {
|
|
580
|
+
list.innerHTML = `<div style="padding:10px;font-size:12.5px;color:#ff8a8a">${uiLabels.error}</div>`;
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
function syncLinkDialog() {
|
|
584
|
+
const d = linkDialog;
|
|
585
|
+
if (!d) return;
|
|
586
|
+
const q = (role) => d.querySelector(`[data-role="${role}"]`);
|
|
587
|
+
const onPage = d.querySelector('[data-pane="page"]').style.display !== "none";
|
|
588
|
+
const own = q("text").value.trim();
|
|
589
|
+
q("hint").innerHTML = own ? uiLabels.linkTextOwnHint : onPage ? uiLabels.linkTextAutoHint : uiLabels.linkUrlHint;
|
|
590
|
+
q("live").style.display = onPage ? "flex" : "none";
|
|
591
|
+
q("submit").disabled = onPage ? !linkPicked : !q("url").value.trim();
|
|
592
|
+
}
|
|
593
|
+
function applyLink() {
|
|
594
|
+
const d = linkDialog;
|
|
595
|
+
if (!d || !richCtx) return;
|
|
596
|
+
const q = (role) => d.querySelector(`[data-role="${role}"]`);
|
|
597
|
+
const onPage = d.querySelector('[data-pane="page"]').style.display !== "none";
|
|
598
|
+
const own = q("text").value.trim();
|
|
599
|
+
const href = onPage ? linkPicked?.path ?? "" : q("url").value.trim();
|
|
600
|
+
if (!href) return;
|
|
601
|
+
const ref = onPage && linkPicked ? `${linkPicked.collection}:${linkPicked.slug}` : "";
|
|
602
|
+
const label = own || (onPage ? linkPicked?.title ?? href : href);
|
|
603
|
+
if (linkEditing) {
|
|
604
|
+
linkEditing.setAttribute("href", href);
|
|
605
|
+
if (ref) linkEditing.setAttribute("data-cms-ref", ref);
|
|
606
|
+
else linkEditing.removeAttribute("data-cms-ref");
|
|
607
|
+
if (ref && !own) linkEditing.setAttribute("data-cms-ref-label", "auto");
|
|
608
|
+
else linkEditing.removeAttribute("data-cms-ref-label");
|
|
609
|
+
linkEditing.textContent = label;
|
|
610
|
+
hideLinkDialog();
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
const a = document.createElement("a");
|
|
614
|
+
a.setAttribute("href", href);
|
|
615
|
+
if (ref) {
|
|
616
|
+
a.setAttribute("data-cms-ref", ref);
|
|
617
|
+
if (!own) a.setAttribute("data-cms-ref-label", "auto");
|
|
618
|
+
}
|
|
619
|
+
const sel = window.getSelection();
|
|
620
|
+
if (savedRange && sel) {
|
|
621
|
+
sel.removeAllRanges();
|
|
622
|
+
sel.addRange(savedRange);
|
|
623
|
+
const range = sel.getRangeAt(0);
|
|
624
|
+
a.textContent = own || range.toString() || label;
|
|
625
|
+
range.deleteContents();
|
|
626
|
+
range.insertNode(a);
|
|
627
|
+
sel.removeAllRanges();
|
|
628
|
+
} else {
|
|
629
|
+
a.textContent = label;
|
|
630
|
+
richCtx.el.appendChild(a);
|
|
631
|
+
}
|
|
632
|
+
savedRange = null;
|
|
633
|
+
hideLinkDialog();
|
|
634
|
+
}
|
|
635
|
+
function escapeHtml(v) {
|
|
636
|
+
return v.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
637
|
+
}
|
|
638
|
+
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;";
|
|
639
|
+
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;";
|
|
640
|
+
var labelCss = () => "font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:#9aa3b2;margin:12px 0 5px;display:block;";
|
|
641
|
+
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;");
|
|
391
642
|
function toggleEmojiPicker(anchor) {
|
|
392
643
|
if (!emojiPicker) emojiPicker = buildEmojiPicker();
|
|
393
644
|
if (emojiPicker.style.display === "block") {
|
|
@@ -497,12 +748,44 @@ function reattachOrphanListItems(container) {
|
|
|
497
748
|
}
|
|
498
749
|
}
|
|
499
750
|
}
|
|
751
|
+
var BLOCK_TAGS = /* @__PURE__ */ new Set([
|
|
752
|
+
"h1",
|
|
753
|
+
"h2",
|
|
754
|
+
"h3",
|
|
755
|
+
"h4",
|
|
756
|
+
"h5",
|
|
757
|
+
"h6",
|
|
758
|
+
"p",
|
|
759
|
+
"div",
|
|
760
|
+
"ul",
|
|
761
|
+
"ol",
|
|
762
|
+
"li",
|
|
763
|
+
"blockquote",
|
|
764
|
+
"pre",
|
|
765
|
+
"hr",
|
|
766
|
+
"table"
|
|
767
|
+
]);
|
|
768
|
+
function isBlockNode(node) {
|
|
769
|
+
return node.nodeType === Node.ELEMENT_NODE && BLOCK_TAGS.has(node.tagName.toLowerCase());
|
|
770
|
+
}
|
|
500
771
|
function serializeBlockChildren(parent) {
|
|
501
772
|
const blocks = [];
|
|
502
|
-
|
|
503
|
-
|
|
773
|
+
let inlineRun = "";
|
|
774
|
+
const flushInline = () => {
|
|
775
|
+
const s = inlineRun.trim();
|
|
504
776
|
if (s) blocks.push(s);
|
|
777
|
+
inlineRun = "";
|
|
778
|
+
};
|
|
779
|
+
parent.childNodes.forEach((node) => {
|
|
780
|
+
if (isBlockNode(node)) {
|
|
781
|
+
flushInline();
|
|
782
|
+
const s = serializeBlock(node).trim();
|
|
783
|
+
if (s) blocks.push(s);
|
|
784
|
+
} else {
|
|
785
|
+
inlineRun += serializeInlineNode(node);
|
|
786
|
+
}
|
|
505
787
|
});
|
|
788
|
+
flushInline();
|
|
506
789
|
return blocks.join("\n\n");
|
|
507
790
|
}
|
|
508
791
|
function serializeBlock(node) {
|
|
@@ -576,14 +859,23 @@ function serializeList(listEl, ordered) {
|
|
|
576
859
|
});
|
|
577
860
|
return items.join("\n");
|
|
578
861
|
}
|
|
862
|
+
function escapeAttr(value) {
|
|
863
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
864
|
+
}
|
|
579
865
|
function serializeInline(node) {
|
|
580
866
|
let out = "";
|
|
581
867
|
node.childNodes.forEach((child) => {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
868
|
+
out += serializeInlineNode(child);
|
|
869
|
+
});
|
|
870
|
+
return out;
|
|
871
|
+
}
|
|
872
|
+
function serializeInlineNode(child) {
|
|
873
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
874
|
+
return (child.textContent ?? "").replace(/\s+/g, " ");
|
|
875
|
+
}
|
|
876
|
+
if (child.nodeType !== Node.ELEMENT_NODE) return "";
|
|
877
|
+
{
|
|
878
|
+
let out = "";
|
|
587
879
|
const el = child;
|
|
588
880
|
const tag = el.tagName.toLowerCase();
|
|
589
881
|
const inner = serializeInline(el);
|
|
@@ -604,7 +896,15 @@ function serializeInline(node) {
|
|
|
604
896
|
break;
|
|
605
897
|
case "a": {
|
|
606
898
|
const href = el.getAttribute("href") || "";
|
|
607
|
-
|
|
899
|
+
const ref = el.getAttribute("data-cms-ref");
|
|
900
|
+
if (ref) {
|
|
901
|
+
const attrs = [`href="${escapeAttr(href)}"`, `data-cms-ref="${escapeAttr(ref)}"`];
|
|
902
|
+
const label = el.getAttribute("data-cms-ref-label");
|
|
903
|
+
if (label) attrs.push(`data-cms-ref-label="${escapeAttr(label)}"`);
|
|
904
|
+
out += `<a ${attrs.join(" ")}>${inner}</a>`;
|
|
905
|
+
} else {
|
|
906
|
+
out += href ? `[${inner}](${href})` : inner;
|
|
907
|
+
}
|
|
608
908
|
break;
|
|
609
909
|
}
|
|
610
910
|
case "img": {
|
|
@@ -625,8 +925,8 @@ function serializeInline(node) {
|
|
|
625
925
|
default:
|
|
626
926
|
out += inner;
|
|
627
927
|
}
|
|
628
|
-
|
|
629
|
-
|
|
928
|
+
return out;
|
|
929
|
+
}
|
|
630
930
|
}
|
|
631
931
|
async function saveField(el, value, token, options) {
|
|
632
932
|
const collection = el.dataset.cmsCollection;
|