Files
outline/shared/editor/commands/createAndInsertLink.ts
2024-01-05 23:25:05 -05:00

89 lines
2.0 KiB
TypeScript

import { Node } from "prosemirror-model";
import { EditorView } from "prosemirror-view";
import { toast } from "sonner";
import type { Dictionary } from "~/hooks/useDictionary";
function findPlaceholderLink(doc: Node, href: string) {
let result: { pos: number; node: Node } | undefined;
doc.descendants((node: Node, pos = 0) => {
// get text nodes
if (node.type.name === "text") {
// get marks for text nodes
node.marks.forEach((mark) => {
// any of the marks links?
if (mark.type.name === "link") {
// any of the links to other docs?
if (mark.attrs.href === href) {
result = { node, pos };
}
}
});
return false;
}
if (!node.content.size) {
return false;
}
return true;
});
return result;
}
const createAndInsertLink = async function (
view: EditorView,
title: string,
href: string,
options: {
dictionary: Dictionary;
nested?: boolean;
onCreateLink: (title: string, nested?: boolean) => Promise<string>;
}
) {
const { dispatch, state } = view;
const { onCreateLink } = options;
try {
const url = await onCreateLink(title, options.nested);
const result = findPlaceholderLink(view.state.doc, href);
if (!result) {
return;
}
dispatch(
view.state.tr
.removeMark(
result.pos,
result.pos + result.node.nodeSize,
state.schema.marks.link
)
.addMark(
result.pos,
result.pos + result.node.nodeSize,
state.schema.marks.link.create({ href: url })
)
);
} catch (err) {
const result = findPlaceholderLink(view.state.doc, href);
if (!result) {
return;
}
dispatch(
view.state.tr.removeMark(
result.pos,
result.pos + result.node.nodeSize,
state.schema.marks.link
)
);
toast.error(options.dictionary.createLinkError);
}
};
export default createAndInsertLink;