From 0d3dec71f3b35448603ec81f077d6fa2d51fa1f8 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Thu, 17 Jul 2025 17:26:58 +0800 Subject: [PATCH] :recycle: https://github.com/siyuan-note/siyuan/pull/15286 --- app/src/protyle/util/compatibility.ts | 45 +++++++++++---------------- app/src/protyle/util/paste.ts | 7 +---- app/src/protyle/wysiwyg/index.ts | 28 +++++++---------- app/src/types/index.d.ts | 7 +++++ 4 files changed, 38 insertions(+), 49 deletions(-) diff --git a/app/src/protyle/util/compatibility.ts b/app/src/protyle/util/compatibility.ts index 0c0fc11ef..16601362f 100644 --- a/app/src/protyle/util/compatibility.ts +++ b/app/src/protyle/util/compatibility.ts @@ -5,17 +5,22 @@ import {Constants} from "../../constants"; export const encodeBase64 = (text: string): string => { const encoder = new TextEncoder(); const bytes = encoder.encode(text); - const binaryString = String.fromCharCode(...bytes); - const base64 = btoa(binaryString); - return base64; + return btoa(String.fromCharCode(...bytes)); }; -export const decodeBase64 = (base64: string): string => { - const decoder = new TextDecoder(); - const binaryString = atob(base64); - const bytes = Uint8Array.from(binaryString, char => char.charCodeAt(0)); - const text = decoder.decode(bytes); - return text; +const getSiyuanHTML = (text: IClipboardData) => { + const siyuanMatch = text.textHTML.match(//); + if (siyuanMatch) { + try { + const decoder = new TextDecoder(); + const bytes = Uint8Array.from(atob(siyuanMatch[1]), char => char.charCodeAt(0)); + text.siyuanHTML = decoder.decode(bytes); + // 移除注释节点,保持原有的 text/html 内容 + text.textHTML = text.textHTML.replace(//, ""); + } catch (e) { + console.log("Failed to decode siyuan data from HTML comment:", e); + } + } }; export const openByMobile = (uri: string) => { @@ -71,30 +76,14 @@ export const readText = () => { }; export const readClipboard = async () => { - const text: { - textHTML?: string, - textPlain?: string, - siyuanHTML?: string, - files?: File[], - } = {textPlain: "", textHTML: "", siyuanHTML: ""}; + const text: IClipboardData = {textPlain: "", textHTML: "", siyuanHTML: ""}; try { 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(); - - // 从 text/html 中的注释节点提取 text/siyuan 数据 - const siyuanMatch = text.textHTML.match(//); - if (siyuanMatch) { - try { - text.siyuanHTML = decodeBase64(siyuanMatch[1]); - // 移除注释节点,保持原有的 text/html 内容 - text.textHTML = text.textHTML.replace(//, ""); - } catch (e) { - console.log("Failed to decode siyuan data from HTML comment:", e); - } - } + getSiyuanHTML(text); } if (item.types.includes("text/plain")) { const blob = await item.getType("text/plain"); @@ -110,9 +99,11 @@ export const readClipboard = async () => { if (isInAndroid()) { text.textPlain = window.JSAndroid.readClipboard(); text.textHTML = window.JSAndroid.readHTMLClipboard(); + getSiyuanHTML(text); } else if (isInHarmony()) { text.textPlain = window.JSHarmony.readClipboard(); text.textHTML = window.JSHarmony.readHTMLClipboard(); + getSiyuanHTML(text); } return text; } diff --git a/app/src/protyle/util/paste.ts b/app/src/protyle/util/paste.ts index 3959dc20a..26fc192b5 100644 --- a/app/src/protyle/util/paste.ts +++ b/app/src/protyle/util/paste.ts @@ -245,12 +245,7 @@ const readLocalFile = async (protyle: IProtyle, localFiles: string[]) => { uploadLocalFiles(localFiles, protyle, true); }; -export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEvent | { - textHTML?: string, - textPlain?: string, - siyuanHTML?: string, - files?: File[], -}) & { +export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEvent | IClipboardData) & { target: HTMLElement }) => { if ("clipboardData" in event || "dataTransfer" in event) { diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts index 489a26111..1a38c1522 100644 --- a/app/src/protyle/wysiwyg/index.ts +++ b/app/src/protyle/wysiwyg/index.ts @@ -442,17 +442,15 @@ export class WYSIWYG { // Remove ZWSP when copying inline elements https://github.com/siyuan-note/siyuan/issues/13882 .replace(new RegExp(Constants.ZWSP, "g"), ""); event.clipboardData.setData("text/plain", textPlain); - - // 获取 text/siyuan 数据 + + // 设置 text/siyuan 数据 enableLuteMarkdownSyntax(protyle); - const siyuanData = selectTableElement ? protyle.lute.HTML2BlockDOM(html) : html; - event.clipboardData.setData("text/siyuan", siyuanData); + const siyuanHTML = selectTableElement ? protyle.lute.HTML2BlockDOM(html) : html; + event.clipboardData.setData("text/siyuan", siyuanHTML); restoreLuteMarkdownSyntax(protyle); - + // 在 text/html 中插入注释节点,用于右键菜单粘贴时获取 text/siyuan 数据 - const textHTML = selectTableElement ? html : protyle.lute.BlockDOM2HTML(selectAVElement ? textPlain : html); - const siyuanComment = ``; - event.clipboardData.setData("text/html", siyuanComment + textHTML); + event.clipboardData.setData("text/html", `` + (selectTableElement ? html : protyle.lute.BlockDOM2HTML(selectAVElement ? textPlain : html))); }); this.element.addEventListener("mousedown", (event: MouseEvent) => { @@ -1947,17 +1945,15 @@ export class WYSIWYG { } textPlain = textPlain.replace(/\u00A0/g, " "); // Replace non-breaking spaces with normal spaces when copying https://github.com/siyuan-note/siyuan/issues/9382 event.clipboardData.setData("text/plain", textPlain); - - // 获取 text/siyuan 数据 + + // 设置 text/siyuan 数据 enableLuteMarkdownSyntax(protyle); - const siyuanData = selectTableElement ? protyle.lute.HTML2BlockDOM(html) : html; - event.clipboardData.setData("text/siyuan", siyuanData); + const siyuanHTML = selectTableElement ? protyle.lute.HTML2BlockDOM(html) : html; + event.clipboardData.setData("text/siyuan", siyuanHTML); restoreLuteMarkdownSyntax(protyle); - + // 在 text/html 中插入注释节点,用于右键菜单粘贴时获取 text/siyuan 数据 - const textHTML = selectTableElement ? html : protyle.lute.BlockDOM2HTML(selectAVElement ? textPlain : html); - const siyuanComment = ``; - event.clipboardData.setData("text/html", siyuanComment + textHTML); + event.clipboardData.setData("text/html", `` + (selectTableElement ? html : protyle.lute.BlockDOM2HTML(selectAVElement ? textPlain : html))); }); let beforeContextmenuRange: Range; diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index ff560f628..ac97d82fc 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -260,6 +260,13 @@ interface Window { destroyTheme(): Promise; } +interface IClipboardData { + textHTML?: string, + textPlain?: string, + siyuanHTML?: string, + files?: File[], +} + interface IRefDefs { refID: string, defIDs?: string[]