silverbullet/plugs/editor/link.ts

100 lines
2.5 KiB
TypeScript
Raw Normal View History

2024-02-29 22:23:05 +08:00
import { nodeAtPos } from "../../plug-api/lib/tree.ts";
import {
editor,
events,
markdown,
} from "@silverbulletmd/silverbullet/syscalls";
2024-02-24 20:16:04 +08:00
import { extractYoutubeVideoId } from "./embed.ts";
type UnfurlOption = {
id: string;
name: string;
};
export async function unfurlCommand() {
2022-10-14 21:11:33 +08:00
const mdTree = await markdown.parseMarkdown(await editor.getText());
2024-02-24 20:16:04 +08:00
const cursorPos = await editor.getCursor();
let nakedUrlNode = nodeAtPos(mdTree, cursorPos);
if (nakedUrlNode?.type !== "NakedURL") {
nakedUrlNode = nodeAtPos(mdTree, cursorPos - 1);
}
if (nakedUrlNode?.type !== "NakedURL") {
await editor.flashNotification("No URL found under cursor", "error");
return;
}
2022-10-14 21:11:33 +08:00
const url = nakedUrlNode!.children![0].text!;
console.log("Got URL to unfurl", url);
2022-10-14 21:11:33 +08:00
const optionResponses = await events.dispatchEvent("unfurl:options", url);
const options: UnfurlOption[] = [];
for (const resp of optionResponses) {
options.push(...resp);
}
2022-10-14 21:11:33 +08:00
const selectedUnfurl: any = await editor.filterBox(
"Unfurl",
options,
2022-10-12 17:47:13 +08:00
"Select the unfurl strategy of your choice",
);
if (!selectedUnfurl) {
return;
}
try {
const replacement = await events.dispatchEvent(
`unfurl:${selectedUnfurl.id}`,
2022-10-12 17:47:13 +08:00
url,
);
if (replacement.length === 0) {
throw new Error("Unfurl failed");
}
2022-10-14 21:11:33 +08:00
await editor.replaceRange(
nakedUrlNode?.from!,
nakedUrlNode?.to!,
replacement[0],
2022-10-14 21:11:33 +08:00
);
} catch (e: any) {
2022-10-14 21:11:33 +08:00
await editor.flashNotification(e.message, "error");
}
}
2022-10-14 21:11:33 +08:00
export function titleUnfurlOptions(): UnfurlOption[] {
return [
{
id: "title-unfurl",
name: "Extract title",
},
];
}
const titleRegex = /<title[^>]*>\s*([^<]+)\s*<\/title\s*>/i;
export async function titleUnfurl(url: string): Promise<string> {
2022-10-14 21:11:33 +08:00
const response = await fetch(url);
if (response.status < 200 || response.status >= 300) {
console.error("Unfurl failed", await response.text());
throw new Error(`Failed to fetch: ${response.statusText}`);
}
2022-10-14 21:11:33 +08:00
const body = await response.text();
const match = titleRegex.exec(body);
if (match) {
return `[${match[1]}](${url})`;
} else {
throw new Error("No title found");
}
}
2024-02-24 20:16:04 +08:00
export function youtubeUnfurlOptions(url: string): UnfurlOption[] {
if (extractYoutubeVideoId(url)) {
return [
{
id: "youtube-unfurl",
name: "Embed video",
},
];
} else {
return [];
}
}
export function youtubeUnfurl(url: string): string {
return "```embed\nurl: " + url + "\n```";
}