From da11e337aaf2e47b4599dd09221e262d55719b3e Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sun, 16 Feb 2025 18:04:03 +0800 Subject: [PATCH] :art: https://github.com/siyuan-note/siyuan/issues/14112 --- app/src/menus/protyle.ts | 14 ++++-- app/src/protyle/header/Title.ts | 12 ++++- app/src/protyle/toolbar/index.ts | 8 +-- app/src/protyle/util/compatibility.ts | 23 ++++++++- app/src/protyle/util/paste.ts | 72 ++++++--------------------- app/src/protyle/wysiwyg/index.ts | 8 +-- 6 files changed, 67 insertions(+), 70 deletions(-) diff --git a/app/src/menus/protyle.ts b/app/src/menus/protyle.ts index 407855f63..d8d6de0cb 100644 --- a/app/src/menus/protyle.ts +++ b/app/src/menus/protyle.ts @@ -24,11 +24,17 @@ import {transaction, updateTransaction} from "../protyle/wysiwyg/transaction"; import {openMenu} from "./commonMenuItem"; import {fetchPost, fetchSyncPost} from "../util/fetch"; import {Constants} from "../constants"; -import {copyPlainText, readText, setStorageVal, updateHotkeyTip, writeText} from "../protyle/util/compatibility"; +import { + copyPlainText, + readClipboard, + setStorageVal, + updateHotkeyTip, + writeText +} from "../protyle/util/compatibility"; import {preventScroll} from "../protyle/scroll/preventScroll"; import {onGet} from "../protyle/util/onGet"; import {getAllModels} from "../layout/getAll"; -import {pasteAsPlainText, pasteEscaped, pasteText} from "../protyle/util/paste"; +import {paste, pasteAsPlainText, pasteEscaped} from "../protyle/util/paste"; /// #if !MOBILE import {openFileById, updateBacklinkGraph} from "../editor/util"; import {openGlobalSearch} from "../search/util"; @@ -784,8 +790,8 @@ export const contentMenu = (protyle: IProtyle, nodeElement: Element) => { document.execCommand("paste"); } else { try { - const clipText = await readText(); - pasteText(protyle, clipText, nodeElement); + const text = await readClipboard(); + paste(protyle, Object.assign(text, {target: nodeElement as HTMLElement})); } catch (e) { console.log(e); } diff --git a/app/src/protyle/header/Title.ts b/app/src/protyle/header/Title.ts index 98b554af9..d41a91c2a 100644 --- a/app/src/protyle/header/Title.ts +++ b/app/src/protyle/header/Title.ts @@ -235,7 +235,17 @@ export class Title { accelerator: "⌘V", click: async () => { focusByRange(getEditorRange(this.editElement)); - document.execCommand("paste"); + if (document.queryCommandSupported("paste")) { + document.execCommand("paste"); + } else { + try { + const text = await readText(); + document.execCommand("insertText", false, replaceFileName(text)); + this.rename(protyle); + } catch (e) { + console.log(e); + } + } } }).element); window.siyuan.menus.menu.append(new MenuItem({ diff --git a/app/src/protyle/toolbar/index.ts b/app/src/protyle/toolbar/index.ts index 91a0aa940..10bd8f444 100644 --- a/app/src/protyle/toolbar/index.ts +++ b/app/src/protyle/toolbar/index.ts @@ -17,7 +17,7 @@ import {Link} from "./Link"; import {setPosition} from "../../util/setPosition"; import {updateTransaction} from "../wysiwyg/transaction"; import {Constants} from "../../constants"; -import {copyPlainText, openByMobile, readText, setStorageVal} from "../util/compatibility"; +import {copyPlainText, openByMobile, readClipboard, setStorageVal} from "../util/compatibility"; import {upDownHint} from "../../util/upDownHint"; import {highlightRender} from "../render/highlightRender"; import {getContenteditableElement, hasNextSibling, hasPreviousSibling} from "../wysiwyg/getBlock"; @@ -43,7 +43,7 @@ import {mathRender} from "../render/mathRender"; import {linkMenu} from "../../menus/protyle"; import {addScript} from "../util/addScript"; import {confirmDialog} from "../../dialog/confirmDialog"; -import {pasteAsPlainText, pasteEscaped, pasteText} from "../util/paste"; +import {paste, pasteAsPlainText, pasteEscaped} from "../util/paste"; import {escapeHtml} from "../../util/escape"; import {resizeSide} from "../../history/resizeSide"; @@ -1589,8 +1589,8 @@ ${item.name} document.execCommand("paste"); } else { try { - const clipText = await readText(); - pasteText(protyle, clipText, nodeElement); + const text = await readClipboard(); + paste(protyle, Object.assign(text, {target: nodeElement as HTMLElement})); } catch (e) { console.log(e); } diff --git a/app/src/protyle/util/compatibility.ts b/app/src/protyle/util/compatibility.ts index 63372a698..fb3d98ad8 100644 --- a/app/src/protyle/util/compatibility.ts +++ b/app/src/protyle/util/compatibility.ts @@ -39,6 +39,27 @@ export const readText = () => { return navigator.clipboard.readText(); }; +export const readClipboard = async () => { + const text: { textPlain?: string, textHTML?: string } = {} + if (isInAndroid()) { + text.textPlain = window.JSAndroid.readClipboard(); + } else if (isInHarmony()) { + text.textPlain = window.JSHarmony.readClipboard(); + } + const clipboardContents = await navigator.clipboard.read(); + for (const item of clipboardContents) { + if (item.types.includes("text/html")) { + const blob = await item.getType("text/html"); + text.textHTML = await blob.text(); + } + if (item.types.includes("text/plain")) { + const blob = await item.getType("text/plain"); + text.textPlain = await blob.text(); + } + } + return text; +} + export const writeText = (text: string) => { let range: Range; if (getSelection().rangeCount > 0) { @@ -145,7 +166,7 @@ export const isWin11 = async () => { const ua = await (navigator as any).userAgentData.getHighEntropyValues(["platformVersion"]); if ((navigator as any).userAgentData.platform === "Windows") { if (parseInt(ua.platformVersion.split(".")[0]) >= 13) { - return true; + return true; } } return false; diff --git a/app/src/protyle/util/paste.ts b/app/src/protyle/util/paste.ts index 65c8717ea..e68b8ae49 100644 --- a/app/src/protyle/util/paste.ts +++ b/app/src/protyle/util/paste.ts @@ -128,7 +128,7 @@ export const pasteEscaped = async (protyle: IProtyle, nodeElement: Element) => { .replace(/\|/g, "\\|") .replace(/\./g, "\\."); // 转义文本不能使用 DOM 结构 https://github.com/siyuan-note/siyuan/issues/11778 - pasteText(protyle, clipText, nodeElement, false); + paste(protyle, {textPlain: clipText, target: nodeElement as HTMLElement}); } catch (e) { console.log(e); } @@ -228,57 +228,6 @@ export const restoreLuteMarkdownSyntax = (protyle: IProtyle) => { protyle.lute.SetMark(window.siyuan.config.editor.markdown.inlineMark); }; -export const pasteText = async (protyle: IProtyle, textPlain: string, nodeElement: Element, toBlockDOM = true) => { - if (protyle && protyle.app && protyle.app.plugins) { - for (let i = 0; i < protyle.app.plugins.length; i++) { - const response: IObject = await new Promise((resolve) => { - const emitResult = protyle.app.plugins[i].eventBus.emit("paste", { - protyle, - resolve, - textHTML: textPlain, - textPlain, - siyuanHTML: textPlain, - files: [] - }); - if (emitResult) { - resolve(undefined); - } - }); - - if (response?.textPlain) { - textPlain = response.textPlain; - } - } - } - - 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 { - const linkDest = protyle.lute.GetLinkDest(textPlain); - if (linkDest) { - textPlain = `[${range.toString()}](${linkDest})`; - } - } - } - insertHTML(toBlockDOM ? protyle.lute.Md2BlockDOM(textPlain) : textPlain, protyle, false, false, true); - - blockRender(protyle, protyle.wysiwyg.element); - processRender(protyle.wysiwyg.element); - highlightRender(protyle.wysiwyg.element); - avRender(protyle.wysiwyg.element, protyle); - filterClipboardHint(protyle, textPlain); - scrollCenter(protyle, undefined, false, "smooth"); -}; - const readLocalFile = async (protyle: IProtyle, localFiles: string[]) => { if (protyle && protyle.app && protyle.app.plugins) { for (let i = 0; i < protyle.app.plugins.length; i++) { @@ -303,9 +252,16 @@ const readLocalFile = async (protyle: IProtyle, localFiles: string[]) => { uploadLocalFiles(localFiles, protyle, true); }; -export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEvent) & { target: HTMLElement }) => { - event.stopPropagation(); - event.preventDefault(); +export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEvent | { + textHTML?: string, + textPlain?: string, +}) & { + target: HTMLElement +}) => { + if ("clipboardData" in event || "dataTransfer" in event) { + event.stopPropagation(); + event.preventDefault(); + } let textHTML: string; let textPlain: string; let siyuanHTML: string; @@ -315,13 +271,16 @@ export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEven textPlain = event.clipboardData.getData("text/plain"); siyuanHTML = event.clipboardData.getData("text/siyuan"); files = event.clipboardData.files; - } else { + } else if ("dataTransfer" in event) { textHTML = event.dataTransfer.getData("text/html"); textPlain = event.dataTransfer.getData("text/plain"); siyuanHTML = event.dataTransfer.getData("text/siyuan"); if (event.dataTransfer.types[0] === "Files") { files = event.dataTransfer.items; } + } else { + textHTML = event.textHTML + textPlain = event.textPlain } // Improve the pasting of selected text in PDF rectangular annotation https://github.com/siyuan-note/siyuan/issues/11629 @@ -585,3 +544,4 @@ export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEven scrollCenter(protyle, undefined, false, "smooth"); } }; + diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts index c33469a38..35da7c722 100644 --- a/app/src/protyle/wysiwyg/index.ts +++ b/app/src/protyle/wysiwyg/index.ts @@ -1,4 +1,4 @@ -import {getTextStar, paste, pasteText} from "../util/paste"; +import {getTextStar, paste} from "../util/paste"; import { hasClosestBlock, hasClosestByAttribute, @@ -64,7 +64,7 @@ import {openGlobalSearch} from "../../search/util"; import {popSearch} from "../../mobile/menu/search"; /// #endif import {BlockPanel} from "../../block/Panel"; -import {isInIOS, isMac, isOnlyMeta, readText} from "../util/compatibility"; +import {isInIOS, isMac, isOnlyMeta, readClipboard} from "../util/compatibility"; import {MenuItem} from "../../menus/Menu"; import {fetchPost} from "../../util/fetch"; import {onGet} from "../util/onGet"; @@ -1330,8 +1330,8 @@ export class WYSIWYG { document.execCommand("paste"); } else if (tableBlockElement) { try { - const clipText = await readText(); - pasteText(protyle, clipText, tableBlockElement); + const text = await readClipboard(); + paste(protyle, Object.assign(text, {target: tableBlockElement as HTMLElement})); } catch (e) { console.log(e); }