Skip to content

Commit 20e0d86

Browse files
committed
feat(ui): enhance paste handling to support mixed content and improve image uploads
1 parent 6871e9b commit 20e0d86

1 file changed

Lines changed: 46 additions & 18 deletions

File tree

src/static/js/components/acb-compose-shell.js

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,29 +61,57 @@
6161
}
6262

6363
async handlePaste(e) {
64-
e.preventDefault();
65-
const items = e.clipboardData?.items;
66-
if (!items) return;
64+
const clipboard = e.clipboardData;
65+
const items = clipboard?.items;
66+
if (!items || items.length === 0) return;
6767

68+
const imageFiles = [];
6869
for (const item of items) {
69-
if (item.type.startsWith('image/')) {
70+
if (item.type && item.type.startsWith('image/')) {
7071
const file = item.getAsFile();
71-
if (file) await this.uploadImage(file);
72-
} else if (item.type === 'text/plain') {
73-
const text = await item.getAsString();
74-
const input = document.getElementById("compose-input");
75-
if (input) {
76-
// Insert text directly into contenteditable
77-
const textNode = document.createTextNode(text);
78-
if (input.childNodes.length === 0) {
79-
input.appendChild(textNode);
80-
} else {
81-
input.appendChild(textNode);
82-
}
83-
input.focus();
84-
}
72+
if (file) imageFiles.push(file);
8573
}
8674
}
75+
76+
// Only intercept when images exist; otherwise keep native text paste behavior.
77+
if (imageFiles.length === 0) {
78+
return;
79+
}
80+
81+
e.preventDefault();
82+
83+
for (const file of imageFiles) {
84+
await this.uploadImage(file);
85+
}
86+
87+
// For mixed clipboard content, keep text by inserting plain text manually.
88+
const text = clipboard.getData('text/plain');
89+
if (text) {
90+
this.insertTextAtCursor(text);
91+
}
92+
}
93+
94+
insertTextAtCursor(text) {
95+
const input = this.querySelector('#compose-input');
96+
if (!input || !text) return;
97+
98+
input.focus();
99+
const selection = window.getSelection();
100+
if (!selection || selection.rangeCount === 0) {
101+
input.appendChild(document.createTextNode(text));
102+
return;
103+
}
104+
105+
const range = selection.getRangeAt(0);
106+
range.deleteContents();
107+
const textNode = document.createTextNode(text);
108+
range.insertNode(textNode);
109+
110+
// Move caret to after inserted text.
111+
range.setStartAfter(textNode);
112+
range.collapse(true);
113+
selection.removeAllRanges();
114+
selection.addRange(range);
87115
}
88116

89117
handleDrop(e) {

0 commit comments

Comments
 (0)