diff --git a/TEST_SCENARIOS.md b/TEST_SCENARIOS.md index acb5074..0a8a5c8 100644 --- a/TEST_SCENARIOS.md +++ b/TEST_SCENARIOS.md @@ -62,11 +62,11 @@ Préparer : 3 entrées `A`, `B`, `C`, dont `A` dans le dossier `Work` avec le ta ### A9 · favori / épingle pendant l'édition (non-régression) - **ACTION** : `A` ouverte + dirty → cliquer ★ et 📌 sur la ligne `A` → Save -- **ATTENDU** : l'entrée reste favorite et épinglée (ces colonnes ne sont pas dans le PUT de l'éditeur). +- **ATTENDU** : l'entrée reste favorite et épinglée (ces colonnes ne sont pas dans le PUT de l'éditeur).✅ ### A10 · icône / pièce jointe pendant l'édition (non-régression) - **ACTION** : `A` ouverte + dirty → Settings → *Fetch missing* favicons (ou upload d'icône) → Save -- **ATTENDU** : l'icône survit au Save (endpoint dédié, hors payload éditeur). +- **ATTENDU** : l'icône survit au Save (endpoint dédié, hors payload éditeur).✅ icon not refreshed in edit ### A11 · sync / import pendant que l'éditeur est ouvert — **trou connu** - **ACTION** : `A` ouverte + dirty → lancer *Sync now* (ou importer un JSON en mode overwrite) qui met `A` à jour → Save diff --git a/js/app.js b/js/app.js index 0680c57..e65aae6 100644 --- a/js/app.js +++ b/js/app.js @@ -5592,7 +5592,9 @@ function openFolderModal(existing) { const old = document.getElementById('folderModal'); if (old) old.remove(); - const modal = el('div', { id: 'folderModal', class: 'modal' }); + // data-dynamic: built at runtime, so the Esc fallback may close it by + // removing the node (static modals must only ever be hidden). + const modal = el('div', { id: 'folderModal', class: 'modal', 'data-dynamic': '1' }); const backdrop = el('div', { class: 'modal-backdrop' }); backdrop.addEventListener('click', () => modal.remove()); modal.appendChild(backdrop); @@ -8003,14 +8005,28 @@ async function init() { closeGen(); return; } - // Any other open modal — the folder modal is built dynamically and - // has no id in this list, so without this Esc fell through to the - // slideover close below and shut the editor behind it. Closing a - // stray .modal is just .remove() (how its backdrop click closes). - // The static modals above never reach here (their id checks return - // first), so this only ever catches the dynamic ones. - const strayModal = document.querySelector('.modal:not(.is-hidden)'); - if (strayModal) { strayModal.remove(); return; } + if (!$('#reauthModal').classList.contains('is-hidden')) { + closeReauth(false); + return; + } + if (!$('#autofillPickerModal').classList.contains('is-hidden')) { + closeAutofillPicker(); + return; + } + if (!$('#quickSearchModal').classList.contains('is-hidden')) { + // Reachable when focus left the search input (clicked a row), + // so the input's own Esc handler doesn't fire. + closeQuickSearchModal(); + return; + } + // Modals built at runtime (the folder modal) have no id to test + // here, and without this Esc fell through to the slideover close + // below and shut the editor behind them. Removing the node IS how + // they close — their backdrop click does the same. Scoped to + // [data-dynamic] so it can never delete a static modal from the + // DOM, which would break that feature until the app restarts. + const dynModal = document.querySelector('.modal[data-dynamic]:not(.is-hidden)'); + if (dynModal) { dynModal.remove(); return; } if ($('#slideover').classList.contains('is-open')) { requestCloseSlideOver(); return;