import {Constants} from "../../constants"; import {uploadFiles, uploadLocalFiles} from "../upload"; import {processPasteCode, processRender} from "./processCode"; import {writeText} from "./compatibility"; /// #if !BROWSER import {clipboard} from "electron"; import {getCurrentWindow} from "@electron/remote"; /// #endif import {hasClosestBlock} from "./hasClosest"; import {focusByWbr, getEditorRange} from "./selection"; import {blockRender} from "../markdown/blockRender"; import {highlightRender} from "../markdown/highlightRender"; import {updateTransaction} from "../wysiwyg/transaction"; import {fetchPost, fetchSyncPost} from "../../util/fetch"; import {isDynamicRef, isFileAnnotation} from "../../util/functions"; import {insertHTML} from "./insertHTML"; import {scrollCenter} from "../../util/highlightById"; import {hideElements} from "../ui/hideElements"; const filterClipboardHint = (protyle: IProtyle, textPlain: string) => { let needRender = true; protyle.options.hint.extend.find(item => { if (item.key === textPlain) { needRender = false; return true; } }); if (needRender) { protyle.hint.render(protyle); } }; export const pasteAsPlainText = async (protyle: IProtyle) => { /// #if !BROWSER let localFiles: string[] = []; if ("darwin" === window.siyuan.config.system.os) { const xmlString = clipboard.read("NSFilenamesPboardType"); const domParser = new DOMParser(); const xmlDom = domParser.parseFromString(xmlString, "application/xml"); Array.from(xmlDom.getElementsByTagName("string")).forEach(item => { localFiles.push(item.childNodes[0].nodeValue); }); } else { const xmlString = await fetchSyncPost("/api/clipboard/readFilePaths", {}); if (xmlString.data.length > 0) { localFiles = xmlString.data; } } if (localFiles.length > 0) { uploadLocalFiles(localFiles, protyle, false); writeText(""); } /// #else getCurrentWindow().webContents.pasteAndMatchStyle(); /// #endif }; export const pasteText = (protyle: IProtyle, textPlain: string, nodeElement: Element) => { const range = getEditorRange(protyle.wysiwyg.element); if (nodeElement.getAttribute("data-type") === "NodeCodeBlock") { // 粘贴在代码位置 insertHTML(textPlain, protyle); return; } if (range.toString() !== "") { if (isDynamicRef(textPlain)) { textPlain = textPlain.replace(/'.+'\)\)$/, ` "${range.toString()}"))`); } else if (isFileAnnotation(textPlain)) { textPlain = textPlain.replace(/".+">>$/, `"${range.toString()}">>`); } else if (protyle.lute.IsValidLinkDest(textPlain)) { textPlain = `[${range.toString()}](${textPlain})`; } } insertHTML(protyle.lute.Md2BlockDOM(textPlain), protyle); blockRender(protyle, protyle.wysiwyg.element); processRender(protyle.wysiwyg.element); highlightRender(protyle.wysiwyg.element); filterClipboardHint(protyle, textPlain); scrollCenter(protyle); }; export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEvent) & { target: HTMLElement }) => { event.stopPropagation(); event.preventDefault(); let textHTML; let textPlain; let files; if ("clipboardData" in event) { textHTML = event.clipboardData.getData("text/html"); textPlain = event.clipboardData.getData("text/plain"); files = event.clipboardData.files; } else { textHTML = event.dataTransfer.getData("text/html"); textPlain = event.dataTransfer.getData("text/plain"); if (event.dataTransfer.types[0] === "Files") { files = event.dataTransfer.items; } } // 复制标题及其下方块使用 writeText,需将 textPLain 转换为 textHTML if (textPlain.endsWith(Constants.ZWSP) && !textHTML) { textHTML = textPlain; } /// #if !BROWSER // 不再支持 PC 浏览器 https://github.com/siyuan-note/siyuan/issues/7206 if (!textHTML && !textPlain && ("clipboardData" in event)) { if ("darwin" === window.siyuan.config.system.os) { const xmlString = clipboard.read("NSFilenamesPboardType"); const domParser = new DOMParser(); const xmlDom = domParser.parseFromString(xmlString, "application/xml"); const localFiles: string[] = []; Array.from(xmlDom.getElementsByTagName("string")).forEach(item => { localFiles.push(item.childNodes[0].nodeValue); }); if (localFiles.length > 0) { uploadLocalFiles(localFiles, protyle, true); writeText(""); return; } } else { const xmlString = await fetchSyncPost("/api/clipboard/readFilePaths", {}); if (xmlString.data.length > 0) { uploadLocalFiles(xmlString.data, protyle, true); writeText(""); return; } } } /// #endif // 浏览器地址栏拷贝处理 if (textHTML.replace(/&/g, "&").replace(/<(|\/)(html|body|meta)[^>]*?>/ig, "").trim() === `${textPlain}` || textHTML.replace(/&/g, "&").replace(/<(|\/)(html|body|meta)[^>]*?>/ig, "").trim() === `${textPlain}`) { textHTML = ""; } // 剪切复制中首位包含空格或仅有空格 https://github.com/siyuan-note/siyuan/issues/5667 if (!textHTML.endsWith(Constants.ZWSP) && !textHTML.startsWith(Constants.ZWSP)) { // process word const doc = new DOMParser().parseFromString(textHTML, "text/html"); if (doc.body && doc.body.innerHTML) { textHTML = doc.body.innerHTML; } // windows 剪切板 if (textHTML.startsWith("\n") && textHTML.endsWith("\n\n")) { textHTML = doc.body.innerHTML.trim().replace("", "").replace("", ""); } } textHTML = Lute.Sanitize(textHTML); const nodeElement = hasClosestBlock(event.target); if (!nodeElement) { if (files && files.length > 0) { uploadFiles(protyle, files); } return; } hideElements(["select"], protyle); protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--hl").forEach(item => { item.classList.remove("protyle-wysiwyg--hl"); }); const code = processPasteCode(textHTML, textPlain); const range = getEditorRange(protyle.wysiwyg.element); // process code if (nodeElement.getAttribute("data-type") === "NodeCodeBlock") { // 粘贴在代码位置 insertHTML(textPlain, protyle); return; } else if (code) { if (!code.startsWith('