A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
at lambda-fork/main 84 lines 4.1 kB view raw
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}