A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1import {ToolbarItem} from "./ToolbarItem";
2import {linkMenu} from "../../menus/protyle";
3import {hasClosestBlock, hasClosestByAttribute} from "../util/hasClosest";
4import {readClipboard} from "../util/compatibility";
5import {Constants} from "../../constants";
6
7export class Link extends ToolbarItem {
8 public element: HTMLElement;
9
10 constructor(protyle: IProtyle, menuItem: IMenuItem) {
11 super(protyle, menuItem);
12 // 不能用 getEventName,否则会导致光标位置变动到点击的文档中
13 this.element.addEventListener("click", async (event: MouseEvent & { changedTouches: MouseEvent[] }) => {
14 protyle.toolbar.element.classList.add("fn__none");
15 event.stopPropagation();
16
17 const range = protyle.toolbar.range;
18 const nodeElement = hasClosestBlock(range.startContainer);
19 if (!nodeElement) {
20 return;
21 }
22 const aElement = hasClosestByAttribute(range.startContainer, "data-type", "a");
23 if (aElement) {
24 linkMenu(protyle, aElement);
25 return;
26 }
27
28 let dataHref = "";
29 let dataText = range.toString().trim().replace(Constants.ZWSP, "");
30 let showMenu = false;
31 try {
32 // 选中链接时需忽略剪切板内容 https://ld246.com/article/1643035329737
33 dataHref = protyle.lute.GetLinkDest(dataText);
34 if (!dataHref) {
35 const clipObject = await readClipboard();
36 const html = clipObject.textHTML || protyle.lute.Md2BlockDOM(clipObject.textPlain);
37 if (html) {
38 const tempElement = document.createElement("template");
39 tempElement.innerHTML = html;
40 const linkElement = tempElement.content.querySelector('span[data-type~="a"], a');
41 if (linkElement) {
42 dataText = dataText || linkElement.textContent;
43 dataHref = linkElement.getAttribute("data-href") || linkElement.getAttribute("href");
44 }
45 }
46 if (!dataHref) {
47 dataHref = protyle.lute.GetLinkDest(clipObject.textPlain);
48 }
49 if (!dataHref) {
50 // 360
51 const lastSpace = clipObject.textPlain.lastIndexOf(" ");
52 if (lastSpace > -1) {
53 dataHref = protyle.lute.GetLinkDest(clipObject.textPlain.substring(lastSpace));
54 if (dataHref && !dataText) {
55 dataText = clipObject.textPlain.substring(0, lastSpace);
56 }
57 }
58 }
59 // https://github.com/siyuan-note/siyuan/issues/12867
60 if (!dataHref && clipObject.textPlain.startsWith("assets/")) {
61 dataHref = clipObject.textPlain;
62 }
63 // https://github.com/siyuan-note/siyuan/issues/14704#issuecomment-2867555769 第一点 & https://github.com/siyuan-note/siyuan/issues/6798
64 if (dataHref && !dataText) {
65 dataText = decodeURIComponent(dataHref.replace("https://", "").replace("http://", ""));
66 if (dataHref.length > Constants.SIZE_LINK_TEXT_MAX) {
67 dataText = dataHref.substring(0, Constants.SIZE_LINK_TEXT_MAX) + "...";
68 }
69 showMenu = true;
70 }
71 }
72 } catch (e) {
73 console.log(e);
74 }
75 const linkElements = protyle.toolbar.setInlineMark(protyle, "a", "range", {
76 type: "a",
77 color: dataHref + (dataText ? Constants.ZWSP + dataText : "")
78 });
79 if (showMenu) {
80 linkMenu(protyle, linkElements[0] as HTMLElement, true);
81 }
82 });
83 }
84}