From 1638246a539edc9eb325f9a59c9720ecf738d3b5 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Sat, 25 Jul 2026 16:10:19 +0100 Subject: [PATCH] fix(editor): a programmatic click is not a click-outside Import with an open, dirty editor showed "Discard unsaved changes?" stacked on top of the native file dialog. doImport appends its hidden file input to and calls .click(); that synthetic click bubbles to the document handler, which sees a target outside .slideover and fires requestCloseSlideOver. Same latent bug on the attachment download web-fallback (an appended to , then .click()ed). Gate the handler on e.isTrusted: only a real user click can mean "clicked away". Fixes both and any future programmatic click, at the shared choke point. File inputs living inside the slideover (icon upload, attachment picker) were already safe via closest('.slideover'). Co-Authored-By: Claude Opus 4.8 --- js/app.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/js/app.js b/js/app.js index f58f865..842b2ea 100644 --- a/js/app.js +++ b/js/app.js @@ -7197,6 +7197,12 @@ async function init() { }, true); document.addEventListener('click', e => { if (!$('#slideover').classList.contains('is-open')) return; + // Only a real click can mean "the user clicked away". A programmatic + // .click() — the hidden file input behind Import, the + // behind an attachment save — is appended to , so it bubbles up + // here looking exactly like an outside click and popped the discard + // prompt on top of the native file dialog. isTrusted tells them apart. + if (!e.isTrusted) return; if (_slideoverMouseDownInside) { _slideoverMouseDownInside = false; return; } if (e.target.closest('.slideover')) return; if (e.target.closest('.entry-card')) return;