This is an automated email from the ASF dual-hosted git repository. shuai pushed a commit to branch fix/editor-copy in repository https://gitbox.apache.org/repos/asf/answer.git
commit 92edff69f06c178b087cf7478259c6f6f764b22f Author: shuai <lishuail...@sifou.com> AuthorDate: Tue May 20 15:06:24 2025 +0800 fix: When copying text and images, can the images only appear at the end of the article --- ui/src/components/Editor/ToolBars/image.tsx | 74 +++++++++++++++++++++-------- ui/src/components/Editor/utils/index.ts | 10 ++++ 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/ui/src/components/Editor/ToolBars/image.tsx b/ui/src/components/Editor/ToolBars/image.tsx index 322da08d..766301f2 100644 --- a/ui/src/components/Editor/ToolBars/image.tsx +++ b/ui/src/components/Editor/ToolBars/image.tsx @@ -228,30 +228,64 @@ const Image = ({ editorInstance }) => { return; } event.preventDefault(); - - let innerText = ''; - const allPTag = new DOMParser() - .parseFromString( - htmlStr.replace( - /<img([\s\S]*?) src\s*=\s*(['"])([\s\S]*?)\2([^>]*)>/gi, - `<p>\n\n</p>`, - ), - 'text/html', - ) - .querySelectorAll('body p'); - - allPTag.forEach((p, index) => { - const text = p.textContent || ''; - if (text !== '') { - if (index === allPTag.length - 1) { - innerText += `${p.textContent}`; + const parser = new DOMParser(); + const doc = parser.parseFromString(htmlStr, 'text/html'); + const { body } = doc; + + let markdownText = ''; + + function traverse(node) { + if (node.nodeType === Node.TEXT_NODE) { + // text node + markdownText += node.textContent; + } else if (node.nodeType === Node.ELEMENT_NODE) { + // element node + const tagName = node.tagName.toLowerCase(); + + if (tagName === 'img') { + // img node + const src = node.getAttribute('src'); + const alt = node.getAttribute('alt') || t('image.text'); + markdownText += ``; + } else if (tagName === 'br') { + // br node + markdownText += '\n'; } else { - innerText += `${p.textContent}${text.endsWith('\n') ? '' : '\n\n'}`; + for (let i = 0; i < node.childNodes.length; i += 1) { + traverse(node.childNodes[i]); + } + } + + const blockLevelElements = [ + 'p', + 'div', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'ul', + 'ol', + 'li', + 'blockquote', + 'pre', + 'table', + 'thead', + 'tbody', + 'tr', + 'th', + 'td', + ]; + if (blockLevelElements.includes(tagName)) { + markdownText += '\n\n'; } } - }); + } + + traverse(body); - editor.replaceSelection(innerText); + editor.replaceSelection(markdownText); }; const handleClick = () => { if (!link.value) { diff --git a/ui/src/components/Editor/utils/index.ts b/ui/src/components/Editor/utils/index.ts index 3977367c..61e95fbb 100644 --- a/ui/src/components/Editor/utils/index.ts +++ b/ui/src/components/Editor/utils/index.ts @@ -172,6 +172,16 @@ export const useEditor = ({ placeholder(placeholderText), EditorView.lineWrapping, editableCompartment.of(EditorView.editable.of(true)), + EditorView.domEventHandlers({ + paste(event) { + const clipboard = event.clipboardData as DataTransfer; + const htmlStr = clipboard.getData('text/html'); + const imgRegex = + /<img([\s\S]*?) src\s*=\s*(['"])([\s\S]*?)\2([^>]*)>/; + + return Boolean(htmlStr.match(imgRegex)); + }, + }), ], });