Bläddra i källkod

Allow the default paste handler to run

Blocking the native paste handler prevents the undo action from working.
Keith Maika 1 vecka sedan
förälder
incheckning
a6ef719b52
3 ändrade filer med 17 tillägg och 105 borttagningar
  1. 4 0
      CHANGES.md
  2. 0 25
      src/plugins/chatview/message-form.js
  3. 13 80
      src/plugins/chatview/tests/message-form.js

+ 4 - 0
CHANGES.md

@@ -1,5 +1,9 @@
 # Changelog
 
+## Next release
+
+- #3830: The message textarea blocks undo of the pasted text
+
 ## 12.0.0 (2025-08-28)
 
 - #3581: Don't unnecessarily regenerate pot and po files

+ 0 - 25
src/plugins/chatview/message-form.js

@@ -106,32 +106,7 @@ export default class MessageForm extends CustomElement {
             ev.stopPropagation();
             ev.preventDefault();
             this.model.sendFiles(Array.from(ev.clipboardData.files));
-            return;
-        }
-
-        const textarea = /** @type {HTMLTextAreaElement} */ (this.querySelector('.chat-textarea'));
-        if (!textarea) {
-            log.error('onPaste: could not find textarea to paste in to!');
-            return;
         }
-
-        ev.preventDefault();
-        ev.stopPropagation();
-
-        const draft = textarea.value ?? '';
-        const pasted_text = ev.clipboardData.getData('text/plain');
-        const cursor_pos = textarea.selectionStart;
-
-        // Insert text at cursor position
-        const before = draft.substring(0, cursor_pos);
-        const after = draft.substring(textarea.selectionEnd);
-        const separator = before.endsWith(' ') || before.length === 0 ? '' : ' ';
-        const end_separator = after.startsWith(' ') || after.length === 0 ? '' : ' ';
-        this.model.save({ draft: `${before}${separator}${pasted_text}${end_separator}${after}` });
-
-        // Set cursor position after the pasted text
-        const new_pos = before.length + separator.length + pasted_text.length + end_separator.length;
-        setTimeout(() => textarea.setSelectionRange(new_pos, new_pos), 0);
     }
 
     /**

+ 13 - 80
src/plugins/chatview/tests/message-form.js

@@ -3,94 +3,27 @@ const { sizzle, u } = converse.env;
 
 describe('A message form', function () {
     it(
-        'can have text pasted into it with automatic space handling',
+        'allows native paste if no files',
         mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
             await mock.waitForRoster(_converse, 'current', 1);
-
             const contact_jid = mock.cur_names[0].replace(/ /g, '.').toLowerCase() + '@montague.lit';
             await mock.openChatBoxFor(_converse, contact_jid);
             const view = _converse.chatboxviews.get(contact_jid);
             const textarea = view.querySelector('textarea.chat-textarea');
 
-            // Helper function to simulate paste with automatic space handling
-            function simulatePaste(text, cursorStart, cursorEnd, pastedText) {
-                textarea.value = text;
-                textarea.selectionStart = cursorStart;
-                textarea.selectionEnd = cursorEnd || cursorStart;
-
-                // Create a paste event with clipboard data
-                const pasteEvent = new Event('paste', { bubbles: true, cancelable: true });
-                Object.defineProperty(pasteEvent, 'clipboardData', {
-                    value: {
-                        files: [],
-                        getData: () => pastedText,
-                    },
-                });
-
-                // Dispatch the paste event
-                textarea.dispatchEvent(pasteEvent);
-
-                // Simulate the paste behavior with automatic space handling
-                const startPos = textarea.selectionStart;
-                const endPos = textarea.selectionEnd;
-                const textBeforeSelection = textarea.value.substring(0, startPos);
-                const textAfterSelection = textarea.value.substring(endPos);
-
-                // Add space before pasted text if needed
-                let resultText = textBeforeSelection;
-                if (resultText.length > 0 && !resultText.endsWith(' ') && pastedText.length > 0) {
-                    resultText += ' ';
-                }
-
-                // Add pasted text
-                resultText += pastedText;
-
-                // Add space after pasted text if needed
-                if (pastedText.length > 0 && textAfterSelection.length > 0 && !textAfterSelection.startsWith(' ')) {
-                    resultText += ' ';
-                }
-
-                resultText += textAfterSelection;
-                textarea.value = resultText;
-
-                // Update cursor position after paste
-                const newCursorPos = resultText.length - textAfterSelection.length;
-                textarea.selectionStart = textarea.selectionEnd = newCursorPos;
-
-                return resultText;
-            }
-
-            // Test case 1: Paste at the beginning
-            let result = simulatePaste('Hello world', 0, 0, 'PASTED');
-            expect(result).toBe('PASTED Hello world');
-
-            // Test case 2: Paste in the middle (no space before cursor)
-            result = simulatePaste('Helloworld', 5, 5, 'PASTED');
-            expect(result).toBe('Hello PASTED world');
-
-            // Test case 3: Paste in the middle (space already exists before cursor)
-            result = simulatePaste('Hello world', 6, 6, 'PASTED');
-            expect(result).toBe('Hello PASTED world');
-
-            // Test case 4: Paste at the end
-            result = simulatePaste('Hello world', 11, 11, 'PASTED');
-            expect(result).toBe('Hello world PASTED');
-
-            // Test case 5: Paste with text selection (should replace selected text with spaces)
-            result = simulatePaste('Hello world', 6, 11, 'PASTED');
-            expect(result).toBe('Hello PASTED');
-
-            // Test case 6: Paste with empty string
-            result = simulatePaste('Hello world', 5, 5, '');
-            expect(result).toBe('Hello world');
+            const clipboardData = new DataTransfer();
+            clipboardData.setData('text/plain', 'Hello');
 
-            // Test case 7: Paste into empty textarea
-            result = simulatePaste('', 0, 0, 'PASTED');
-            expect(result).toBe('PASTED');
+            // Create a paste event with clipboard data
+            const pasteEvent = new ClipboardEvent('paste', {
+                bubbles: true,
+                cancelable: true,
+                clipboardData,
+            });
 
-            // Test case 8: Paste with space in the pasted text
-            result = simulatePaste('Hello world', 5, 5, 'PASTED TEXT');
-            expect(result).toBe('Hello PASTED TEXT world');
-        })
+            // Dispatch the paste event
+            textarea.dispatchEvent(pasteEvent);
+            expect(pasteEvent.defaultPrevented).toBe(false);
+        }),
     );
 });