From ab88f31eef49c211d145ed55f4dedf553be6dde4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C5=ABdolfs=20O=C5=A1i=C5=86=C5=A1?= Date: Wed, 25 Oct 2023 13:28:21 +0200 Subject: [PATCH] Improve attachment interactions on textareas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rūdolfs Ošiņš --- src/components/ExtendedTextarea.svelte | 130 ++++++++++++++++++------- src/components/IconButton.svelte | 7 +- src/components/Textarea.svelte | 17 +++- src/views/projects/Issue/New.svelte | 8 +- 4 files changed, 119 insertions(+), 43 deletions(-) diff --git a/src/components/ExtendedTextarea.svelte b/src/components/ExtendedTextarea.svelte index a03b1730f..3ccf733ce 100644 --- a/src/components/ExtendedTextarea.svelte +++ b/src/components/ExtendedTextarea.svelte @@ -28,6 +28,9 @@ let newEmbeds: EmbedWithOid[] = []; let selectionStart = 0; let selectionEnd = 0; + let inputFiles: FileList | undefined = undefined; + + const inputId = `input-label-${crypto.randomUUID()}`; const dispatch = createEventDispatcher<{ submit: { comment: string; embeds: Embed[] }; @@ -43,48 +46,79 @@ const MAX_BLOB_SIZE = 4_194_304; - function handleFileDrop(event: DragEvent) { + function handleFileDrop(event: { detail: DragEvent }) { + if (!enableAttachments) { + return; + } + + event.detail.preventDefault(); + if (event.detail.dataTransfer) { + attachEmbeds(event.detail.dataTransfer.files); + } + } + + function handleFilePaste(event: ClipboardEvent) { + // Always allow pasting text content. + if (event.clipboardData && event.clipboardData.files.length === 0) { + return; + } + if (!enableAttachments) { return; } event.preventDefault(); - if (event.dataTransfer) { - const embeds = Array.from(event.dataTransfer.files).map(embed); - void Promise.all(embeds).then(embeds => - embeds.forEach(embed => { - if (embed.content.length > MAX_BLOB_SIZE) { - modal.show({ - component: ErrorModal, - props: { - title: "File too large", - subtitle: [ - "The file you tried to upload is too large.", - "The maximum file size is 4MB.", - ], - error: { message: `File ${embed.name} is too large` }, - }, - }); - return; - } - newEmbeds = [ - ...newEmbeds, - { - oid: embed.oid, - name: embed.name, - content: embed.content, - }, - ]; - const embedText = `![${embed.name}](${embed.oid})\n`; - body = body - .slice(0, selectionStart) - .concat(embedText, body.slice(selectionEnd)); - selectionStart += embedText.length; - selectionEnd = selectionStart; - }), - ); + if (event.clipboardData) { + attachEmbeds(event.clipboardData.files); } } + + function handleFileSelect(event: Event) { + if (!enableAttachments) { + return; + } + + event.preventDefault(); + if (inputFiles) { + attachEmbeds(inputFiles); + } + } + + function attachEmbeds(files: FileList) { + const embeds = Array.from(files).map(embed); + void Promise.all(embeds).then(embeds => + embeds.forEach(embed => { + if (embed.content.length > MAX_BLOB_SIZE) { + modal.show({ + component: ErrorModal, + props: { + title: "File too large", + subtitle: [ + "The file you tried to upload is too large.", + "The maximum file size is 4MB.", + ], + error: { message: `File ${embed.name} is too large` }, + }, + }); + return; + } + newEmbeds = [ + ...newEmbeds, + { + oid: embed.oid, + name: embed.name, + content: embed.content, + }, + ]; + const embedText = `![${embed.name}](${embed.oid})\n`; + body = body + .slice(0, selectionStart) + .concat(embedText, body.slice(selectionEnd)); + selectionStart += embedText.length; + selectionEnd = selectionStart; + }), + ); + }
@@ -153,8 +194,16 @@
{:else} +