From ad99ff4976ae11898eb5b7d9314e8ab9d66914bf Mon Sep 17 00:00:00 2001 From: kaishi00 Date: Tue, 16 Jun 2026 20:46:05 -0400 Subject: [PATCH] fix(composer): attach image AND paste text when clipboard carries both MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The paste handler (boot.js) bailed entirely when the clipboard contained both text and image items, preventing image attachment in the most common real-world scenario: right-click → Copy Image from browsers, Notes, Slack, etc. — these almost always carry a text/html or text/plain representation alongside the image. Previous behavior (from #1620 fix): - clipboard has text only → normal text paste (correct) - clipboard has image only → attach image (correct) - clipboard has BOTH → text pasted, image silently dropped (wrong) New behavior: - clipboard has text only → normal text paste (unchanged) - clipboard has image only → preventDefault + attach image (unchanged) - clipboard has BOTH → let text paste normally AND attach image The key change: preventDefault() is now only called when no text is present (true screenshot paste), so the browser handles text insertion naturally while addFiles() runs regardless. Fixes the regression introduced by the #1620 fix. Closes #1620. --- static/boot.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/static/boot.js b/static/boot.js index 7c00b946..3233638d 100644 --- a/static/boot.js +++ b/static/boot.js @@ -1531,16 +1531,15 @@ document.addEventListener('keydown',async e=>{ }); $('msg').addEventListener('paste',e=>{ const items=Array.from(e.clipboardData?.items||[]); - // When the clipboard carries BOTH text and an image (common from Notes, - // Word, browsers, Slack — the OS attaches a rendered preview alongside - // the plain text), prefer the text and let the browser paste normally. - // Only intercept when the clipboard is image-only (true screenshot paste). - // Tighten the image filter to kind==='file' so string items advertising an - // image MIME (e.g. text/html with an embedded data URI) are not misclassified. - const hasText=items.some(i=>i.kind==='string'&&(i.type==='text/plain'||i.type==='text/html')); + // Extract image items (kind==='file' filter avoids misclassifying text/html + // with embedded data URIs as images). const imageItems=items.filter(i=>i.kind==='file'&&i.type.startsWith('image/')); - if(!imageItems.length||hasText)return; - e.preventDefault(); + if(!imageItems.length)return; + // If text is also present (common when copying images from browsers, Notes, + // Slack, etc.), let the browser paste the text normally AND attach the image. + // Only preventDefault when the clipboard is image-only (true screenshot paste). + const hasText=items.some(i=>i.kind==='string'&&(i.type==='text/plain'||i.type==='text/html')); + if(!hasText)e.preventDefault(); const pasteTs=Date.now(); const files=imageItems.map((i,idx)=>{ const blob=i.getAsFile();