From 131bb91cd2c50d7d28dd0fbda08573ccbd514500 Mon Sep 17 00:00:00 2001 From: Zaki <18zaki18@gmail.com> Date: Sat, 9 May 2026 18:20:06 +0100 Subject: [PATCH] Replace standard confirm() with custom centered confirm dialog Add showCenterConfirm() function for dialogs without button anchor. Replaced all standard confirm() calls in batchDelete, batchPermanentDelete, permanentDelete, emptyTrash. Batch permanent delete shows single custom confirm with entry count, no nested dialogs. permanentDelete() accepts silent param to suppress UI for batch operations. Order cleanup added to permanentDelete. --- js/app.js | 68 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/js/app.js b/js/app.js index 75735c8..5d2b37c 100644 --- a/js/app.js +++ b/js/app.js @@ -300,13 +300,17 @@ async function restoreEntry(id, noToast) { async function toggleFavorite(id) { try { await fetch(API + '/entries/' + id + '/favorite', { method: 'POST', headers: { 'Authorization': 'Bearer ' + token, 'X-CSRF-Token': csrfToken } }); const e = entries.find(x => x.id == id); if (e) e.favorite = e.favorite ? 0 : 1; renderFolders(); render(); playSound('click'); } catch (e) {} } -async function permanentDelete(id) { - if (!confirm('Permanently delete?')) return; - try { const r = await fetch(API + '/entries/' + id + '?permanent=1', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token, 'X-CSRF-Token': csrfToken } }); if (r.ok) { toast('🗑️ Permanently deleted'); await loadEntries(); playSound('error'); } } catch (e) { toast('⚠️ Error', 'error'); } +async function permanentDelete(id, silent) { + const doDelete = async () => { + try { const r = await fetch(API + '/entries/' + id + '?permanent=1', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token, 'X-CSRF-Token': csrfToken } }); if (r.ok) { order = order.filter(x => x != id); localStorage.setItem('entryOrder', JSON.stringify(order)); if (!silent) { toast('🗑️ Permanently deleted'); await loadEntries(); playSound('error'); } } } catch (e) { if (!silent) toast('⚠️ Error', 'error'); } + }; + if (silent) { await doDelete(); return; } + showCenterConfirm('Permanently delete?', doDelete); } async function emptyTrash() { - if (!confirm('Delete ALL trashed entries?')) return; - try { const r = await fetch(API + '/entries/trash/empty', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token, 'X-CSRF-Token': csrfToken } }); if (r.ok) { toast('🗑️ Trash emptied'); await loadEntries(); playSound('error'); } } catch (e) { toast('⚠️ Error', 'error'); } + showCenterConfirm('Delete ALL trashed entries?', async () => { + try { const r = await fetch(API + '/entries/trash/empty', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token, 'X-CSRF-Token': csrfToken } }); if (r.ok) { toast('🗑️ Trash emptied'); await loadEntries(); playSound('error'); } } catch (e) { toast('⚠️ Error', 'error'); } + }); } function timeAgo(dateStr) { if (!dateStr) return ''; @@ -937,6 +941,36 @@ function showConfirm(btn, message, callback) { }, 10); } function entryPw(id) { const e = entries.find(x => x.id == id); return e ? e.password : ''; } +function showCenterConfirm(message, callback) { + const existing = document.querySelector('.custom-confirm'); + if (existing) existing.remove(); + const confirm = document.createElement('div'); + confirm.className = 'custom-confirm show'; + confirm.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:10000;'; + confirm.innerHTML = + '