From 0a77eac3330705467549ab382262deba9c469822 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Tue, 6 Jan 2026 12:52:35 +0800 Subject: [PATCH] :recycle: https://github.com/siyuan-note/siyuan/issues/14800 --- app/src/boot/globalEvent/click.ts | 8 ++------ app/src/mobile/index.ts | 2 +- app/src/protyle/export/index.ts | 10 ++-------- app/src/protyle/gutter/index.ts | 14 +++----------- app/src/protyle/header/Title.ts | 2 +- app/src/protyle/util/nbsp2space.ts | 4 ---- app/src/protyle/util/normalizeText.ts | 10 ++++++++++ app/src/protyle/util/paste.ts | 9 ++++++--- app/src/protyle/wysiwyg/index.ts | 9 +++------ 9 files changed, 28 insertions(+), 40 deletions(-) delete mode 100644 app/src/protyle/util/nbsp2space.ts create mode 100644 app/src/protyle/util/normalizeText.ts diff --git a/app/src/boot/globalEvent/click.ts b/app/src/boot/globalEvent/click.ts index 60dd899fa..86ae3edef 100644 --- a/app/src/boot/globalEvent/click.ts +++ b/app/src/boot/globalEvent/click.ts @@ -7,7 +7,7 @@ import {isWindow} from "../../util/functions"; import {writeText} from "../../protyle/util/compatibility"; import {showMessage} from "../../dialog/message"; import {cancelDrag} from "./dragover"; -import {nbsp2space} from "../../protyle/util/nbsp2space"; +import {nbsp2space, removeZWJ} from "../../protyle/util/normalizeText"; export const globalClickHideMenu = (element: HTMLElement) => { if (!window.siyuan.menus.menu.element.contains(element) && !hasClosestByAttribute(element, "data-menu", "true")) { @@ -42,11 +42,7 @@ export const globalClick = (event: MouseEvent & { target: HTMLElement }) => { const copyElement = hasTopClosestByClassName(event.target, "protyle-action__copy"); if (copyElement) { - let text = copyElement.parentElement.nextElementSibling.textContent.replace(/\n$/, ""); - text = nbsp2space(text) // Replace non-breaking spaces with normal spaces when copying https://github.com/siyuan-note/siyuan/issues/9382 - // https://github.com/siyuan-note/siyuan/issues/14800 - text = text.replace(/\u200D```/g, "```"); - writeText(text); + writeText(removeZWJ(nbsp2space(copyElement.parentElement.nextElementSibling.textContent.replace(/\n$/, "")))); showMessage(window.siyuan.languages.copied, 2000); event.preventDefault(); return; diff --git a/app/src/mobile/index.ts b/app/src/mobile/index.ts index 639ef5d64..d0c91ea77 100644 --- a/app/src/mobile/index.ts +++ b/app/src/mobile/index.ts @@ -30,7 +30,7 @@ import {mobileKeydown} from "./util/keydown"; import {correctHotkey} from "../boot/globalEvent/commonHotkey"; import {processIOSPurchaseResponse} from "../util/iOSPurchase"; import {updateControlAlt} from "../protyle/util/hotKey"; -import {nbsp2space} from "../protyle/util/nbsp2space"; +import {nbsp2space} from "../protyle/util/normalizeText"; class App { public plugins: import("../plugin").Plugin[] = []; diff --git a/app/src/protyle/export/index.ts b/app/src/protyle/export/index.ts index f43fa96fd..d4522c65b 100644 --- a/app/src/protyle/export/index.ts +++ b/app/src/protyle/export/index.ts @@ -530,10 +530,7 @@ ${getIconScript(servePath)} return; } } else if (target.classList.contains("protyle-action__copy")) { - let text = target.parentElement.nextElementSibling.textContent.trimEnd(); - text = text.replace(/\u00A0/g, " "); // Replace non-breaking spaces with normal spaces when copying https://github.com/siyuan-note/siyuan/issues/9382 - text = text.replace(/\u200D\`\`\`/g, "\`\`\`"); - navigator.clipboard.writeText(text); + navigator.clipboard.writeText(target.parentElement.nextElementSibling.textContent.trimEnd().replace(/\u00A0/g, " ").replace(/\u200D\`\`\`/g, "\`\`\`")); event.preventDefault(); event.stopPropagation(); break; @@ -824,10 +821,7 @@ ${getIconScript(servePath)} Protyle.plantumlRender(previewElement, "stage/protyle"); document.querySelectorAll(".protyle-action__copy").forEach((item) => { item.addEventListener("click", (event) => { - let text = item.parentElement.nextElementSibling.textContent.trimEnd(); - text = text.replace(/\u00A0/g, " "); // Replace non-breaking spaces with normal spaces when copying - text = text.replace(/\u200D\`\`\`/g, "\`\`\`"); - navigator.clipboard.writeText(text); + navigator.clipboard.writeText(item.parentElement.nextElementSibling.textContent.trimEnd().replace(/\u00A0/g, " ").replace(/\u200D\`\`\`/g, "\`\`\`")); event.preventDefault(); event.stopPropagation(); }) diff --git a/app/src/protyle/gutter/index.ts b/app/src/protyle/gutter/index.ts index 8916eb4f8..0b2ff89c2 100644 --- a/app/src/protyle/gutter/index.ts +++ b/app/src/protyle/gutter/index.ts @@ -69,7 +69,7 @@ import {replaceLocalPath} from "../../editor/rename"; import {showMessage} from "../../dialog/message"; import {checkFold} from "../../util/noRelyPCFunction"; import {clearSelect} from "../util/clear"; -import {nbsp2space} from "../util/nbsp2space"; +import {nbsp2space} from "../util/normalizeText"; export class Gutter { public element: HTMLElement; @@ -779,10 +779,7 @@ export class Gutter { selectsElement.forEach((item: HTMLElement) => { html += getPlainText(item) + "\n"; }); - let plainText = html.trimEnd(); - // https://github.com/siyuan-note/siyuan/issues/14800 - plainText = plainText.replace(/\u200D```/g, "```"); - copyPlainText(plainText); + copyPlainText(html.trimEnd()); focusBlock(selectsElement[0]); } }, { @@ -1353,12 +1350,7 @@ export class Gutter { label: window.siyuan.languages.copyPlainText, accelerator: window.siyuan.config.keymap.editor.general.copyPlainText.custom, click() { - let plainText = getPlainText(nodeElement as HTMLElement).trimEnd(); - if (type === "NodeCodeBlock") { - // https://github.com/siyuan-note/siyuan/issues/14800 - plainText = plainText.replace(/\u200D```/g, "```"); - } - copyPlainText(plainText); + copyPlainText(getPlainText(nodeElement as HTMLElement).trimEnd()); focusBlock(nodeElement); } }, { diff --git a/app/src/protyle/header/Title.ts b/app/src/protyle/header/Title.ts index 7283125b6..3da8e6d9c 100644 --- a/app/src/protyle/header/Title.ts +++ b/app/src/protyle/header/Title.ts @@ -20,7 +20,7 @@ import {openFileById} from "../../editor/util"; import {setTitle} from "../../dialog/processSystem"; import {getContenteditableElement, getNoContainerElement} from "../wysiwyg/getBlock"; import {commonHotkey} from "../wysiwyg/commonHotkey"; -import {nbsp2space} from "../util/nbsp2space"; +import {nbsp2space} from "../util/normalizeText"; import {genEmptyElement} from "../../block/util"; import {transaction} from "../wysiwyg/transaction"; import {hideTooltip} from "../../dialog/tooltip"; diff --git a/app/src/protyle/util/nbsp2space.ts b/app/src/protyle/util/nbsp2space.ts deleted file mode 100644 index 704606471..000000000 --- a/app/src/protyle/util/nbsp2space.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const nbsp2space = (text: string) => { - // 非打断空格转换为空格 - return text.replace(/\u00A0/g, " "); -}; diff --git a/app/src/protyle/util/normalizeText.ts b/app/src/protyle/util/normalizeText.ts new file mode 100644 index 000000000..7d4c86688 --- /dev/null +++ b/app/src/protyle/util/normalizeText.ts @@ -0,0 +1,10 @@ +// https://github.com/siyuan-note/siyuan/issues/9382 +export const nbsp2space = (text: string) => { + // 非打断空格转换为空格 + return text.replace(/\u00A0/g, " "); +}; + +// https://github.com/siyuan-note/siyuan/issues/14800 +export const removeZWJ = (text: string) => { + return text.replace(/\u200D```/g, "```"); +}; diff --git a/app/src/protyle/util/paste.ts b/app/src/protyle/util/paste.ts index 4f8ef59ae..cb59b8a33 100644 --- a/app/src/protyle/util/paste.ts +++ b/app/src/protyle/util/paste.ts @@ -15,6 +15,7 @@ import {avRender} from "../render/av/render"; import {cellScrollIntoView, getCellText} from "../render/av/cell"; import {getCalloutInfo, getContenteditableElement} from "../wysiwyg/getBlock"; import {clearBlockElement} from "./clear"; +import {removeZWJ} from "./normalizeText"; export const getTextStar = (blockElement: HTMLElement, contentOnly = false) => { const dataType = blockElement.dataset.type; @@ -81,8 +82,10 @@ export const getPlainText = (blockElement: HTMLElement, isNested = false) => { } else if (blockElement.classList.contains("render-node")) { // 需在嵌入块后,代码块前 text += Lute.UnEscapeHTMLStr(blockElement.getAttribute("data-content")); - } else if (["NodeHeading", "NodeParagraph", "NodeCodeBlock"].includes(dataType)) { + } else if (["NodeHeading", "NodeParagraph"].includes(dataType)) { text += blockElement.querySelector("[spellcheck]").textContent; + } else if ("NodeCodeBlock" === dataType) { + text += removeZWJ(blockElement.querySelector("[spellcheck]").textContent); } else if (dataType === "NodeTable") { blockElement.querySelectorAll("th, td").forEach((item) => { text += item.textContent.trim() + "\t"; @@ -159,7 +162,7 @@ export const pasteAsPlainText = async (protyle: IProtyle) => { if (getSelection().rangeCount > 0) { const range = getSelection().getRangeAt(0); if (hasClosestByAttribute(range.startContainer, "data-type", "code") || hasClosestByClassName(range.startContainer, "hljs")) { - insertHTML(textPlain.replace(/```/g, "\u200D```"), protyle); + insertHTML(removeZWJ(textPlain).replace(/```/g, "\u200D```"), protyle); return; } } @@ -361,7 +364,7 @@ export const paste = async (protyle: IProtyle, event: (ClipboardEvent | DragEven if (nodeElement.getAttribute("data-type") === "NodeCodeBlock" || protyle.toolbar.getCurrentType(range).includes("code")) { // https://github.com/siyuan-note/siyuan/issues/13552 - insertHTML(textPlain.replace(/```/g, "\u200D```"), protyle); + insertHTML(removeZWJ(textPlain).replace(/```/g, "\u200D```"), protyle); return; } else if (siyuanHTML) { // 编辑器内部粘贴 diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts index 21dac5ef2..75fae5ef6 100644 --- a/app/src/protyle/wysiwyg/index.ts +++ b/app/src/protyle/wysiwyg/index.ts @@ -102,7 +102,7 @@ import {openGalleryItemMenu} from "../render/av/gallery/util"; import {clearSelect} from "../util/clear"; import {chartRender} from "../render/chartRender"; import {updateCalloutType} from "./callout"; -import {nbsp2space} from "../util/nbsp2space"; +import {nbsp2space, removeZWJ} from "../util/normalizeText"; export class WYSIWYG { public lastHTMLs: { [key: string]: string } = {}; @@ -470,8 +470,7 @@ export class WYSIWYG { if (isEndOfBlock(range)) { textPlain = textPlain.replace(/\n$/, ""); } - // https://github.com/siyuan-note/siyuan/issues/14800 - textPlain = textPlain.replace(/\u200D```/g, "```"); + textPlain = removeZWJ(textPlain); isInCodeBlock = true; } else if (hasClosestByTag(range.startContainer, "TD") || hasClosestByTag(range.startContainer, "TH")) { tempElement.innerHTML = tempElement.innerHTML.replace(/
/g, "\n").replace(//g, "\n"); @@ -2043,9 +2042,7 @@ export class WYSIWYG { // https://github.com/siyuan-note/siyuan/issues/10722 if (hasClosestByAttribute(range.startContainer, "data-type", "NodeCodeBlock") || hasClosestByTag(range.startContainer, "CODE")) { - textPlain = tempElement.textContent.replace(Constants.ZWSP, ""); - // https://github.com/siyuan-note/siyuan/issues/14800 - textPlain = textPlain.replace(/\u200D```/g, "```"); + textPlain = removeZWJ(tempElement.textContent.replace(Constants.ZWSP, "")); isInCodeBlock = true; } // https://github.com/siyuan-note/siyuan/issues/4321