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>![${t('image.text')}]($3)\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 += `![${alt}](${src})`;
+        } 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));
+          },
+        }),
       ],
     });
 

Reply via email to