// fixtures/link-dialog.mjs — Ctrl+K. The dialog is server-rendered // (templates/editor.html: a labelled URL field and three named // buttons, every string from the catalog); this only opens it, waits // for the answer, and applies it to the view the key was pressed in. // // A and not window.prompt: a prompt's label is the browser's, // its one button cannot say "remove", and it cannot be styled to meet // the focus and target rules the rest of the page meets. import { linkAt, setLink, removeLink } from './text-keys.mjs' import { safeHref } from './schema.mjs' /** * Wraps the dialog. open(current) shows it with the field seeded and * resolves to {action, href} when it closes: action is the value of * the button that closed it ("insert", "remove"), or "cancel" for * Cancel and Escape alike. A second open() while the dialog is up * joins the first: both resolve to the one answer, and the field is * not reseeded under the person typing in it. */ export function mountLinkDialog (dialog) { if (!dialog) return null const input = dialog.querySelector('input[name="href"]') let pending = null dialog.addEventListener('close', () => { const done = pending pending = null if (done) done.resolve({ action: dialog.returnValue || 'cancel', href: input.value.trim() }) }) return { open (current) { if (pending) return pending.promise input.value = current || '' dialog.returnValue = '' dialog.showModal() input.select() let resolve const promise = new Promise(r => { resolve = r }) pending = { promise, resolve } return promise }, get isOpen () { return pending !== null } } } /** * Opens the dialog for view's selection and applies what comes back. * An address outside the allowlist is treated as no address: the * dialog closes and the text is left as it was (setLink would refuse * it anyway; checking here keeps the caret where it was too). */ export async function linkPrompt (view, dialog) { if (!dialog) return const { action, href } = await dialog.open(linkAt(view.state)) if (view.isDestroyed) return if (action === 'insert' && safeHref(href)) setLink(href)(view.state, view.dispatch) else if (action === 'remove') removeLink(view.state, view.dispatch) view.focus() }