Fix batch toast spam and add Ctrl+A select all

Batch delete/restore now shows single toast with count instead of one per entry. delEntry() and restoreEntry() accept noToast param. Added Ctrl+A to select all visible entries. Updated keyboard shortcuts help.
This commit is contained in:
2026-05-09 17:44:12 +01:00
parent d50aea6845
commit 0b3f886337
+24 -9
View File
@@ -294,8 +294,8 @@ function toggleTrash() {
loadEntries();
playSound('click');
}
async function restoreEntry(id) {
try { const r = await fetch(API + '/entries/' + id + '/restore', { method: 'POST', headers: { 'Authorization': 'Bearer ' + token, 'X-CSRF-Token': csrfToken } }); if (r.ok) { toast('✅ Restored!'); await loadEntries(); playSound('success'); } } catch (e) { toast('⚠️ Error', 'error'); }
async function restoreEntry(id, noToast) {
try { const r = await fetch(API + '/entries/' + id + '/restore', { method: 'POST', headers: { 'Authorization': 'Bearer ' + token, 'X-CSRF-Token': csrfToken } }); if (r.ok) { if (!noToast) { toast('✅ Restored!'); await loadEntries(); playSound('success'); } } } catch (e) { if (!noToast) toast('⚠️ Error', 'error'); }
}
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) {}
@@ -1066,8 +1066,12 @@ function hideBatchBar() {
async function batchDelete() {
if (!confirm(`Move ${selectedIds.size} entries to trash?`)) return;
for (const id of selectedIds) await delEntry(id);
const count = selectedIds.size;
for (const id of selectedIds) await delEntry(id, true);
toast('📦 Moved ' + count + ' entries to trash');
playSound('delete');
clearSelection();
await loadEntries();
}
async function batchPermanentDelete() {
@@ -1077,8 +1081,12 @@ async function batchPermanentDelete() {
}
async function batchRestore() {
for (const id of selectedIds) await restoreEntry(id);
const count = selectedIds.size;
for (const id of selectedIds) await restoreEntry(id, true);
toast('✅ Restored ' + count + ' entries');
playSound('success');
clearSelection();
await loadEntries();
}
async function batchMove() {
@@ -1127,11 +1135,11 @@ async function addEntry() {
} catch (e) { toast('⚠️ Error', 'error'); }
finally { btn.disabled = false; }
}
async function delEntry(id) {
async function delEntry(id, noToast) {
try {
const r = await fetch(API + '/entries/' + id, { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token, 'X-CSRF-Token': csrfToken } });
if (r.ok) { selectedIds.delete(id); order = order.filter(x => x != id); localStorage.setItem('entryOrder', JSON.stringify(order)); toast('📦 Moved to trash'); await loadEntries(); playSound('delete'); }
} catch (e) { toast('Error', 'error'); }
if (r.ok) { selectedIds.delete(id); order = order.filter(x => x != id); localStorage.setItem('entryOrder', JSON.stringify(order)); if (!noToast) { toast('📦 Moved to trash'); await loadEntries(); playSound('delete'); } }
} catch (e) { if (!noToast) toast('Error', 'error'); }
}
// ==================== UTILS ====================
@@ -1185,7 +1193,7 @@ function highlightText(text, query) {
function showShortcutsHelp() {
const overlay = document.createElement('div');
overlay.className = 'custom-modal-overlay show';
overlay.innerHTML = `<div class="custom-modal" style="min-width:380px"><h3>⌨️ Keyboard Shortcuts</h3><div style="display:grid;grid-template-columns:auto 1fr;gap:0.5rem 1.2rem;font-size:0.85rem;margin-bottom:1rem"><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Ctrl+N</span><span>New entry</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Ctrl+F</span><span>Search</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Ctrl+T</span><span>Toggle trash</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Ctrl+L</span><span>Lock vault</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Ctrl+S</span><span>Save entry</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Esc</span><span>Close modal / deselect</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">◀ ▶</span><span>Detail view nav</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">?</span><span>Show this help</span></div><p style="color:var(--text2);font-size:0.8rem;margin-bottom:0.8rem">💡 Click any entry to select, Shift+click for range, Ctrl+click to toggle</p><div class="modal-actions"><button class="btn btn-sm" onclick="this.closest('.custom-modal-overlay').remove()">Got it</button></div></div>`;
overlay.innerHTML = `<div class="custom-modal" style="min-width:380px"><h3>⌨️ Keyboard Shortcuts</h3><div style="display:grid;grid-template-columns:auto 1fr;gap:0.5rem 1.2rem;font-size:0.85rem;margin-bottom:1rem"><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Ctrl+N</span><span>New entry</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Ctrl+A</span><span>Select all</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Ctrl+F</span><span>Search</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Ctrl+T</span><span>Toggle trash</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Ctrl+L</span><span>Lock vault</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Ctrl+S</span><span>Save entry</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">Esc</span><span>Close modal / deselect</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">◀ ▶</span><span>Detail view nav</span><span style="background:var(--input);padding:0.15rem 0.6rem;border-radius:0.4rem;font-family:monospace;text-align:center">?</span><span>Show this help</span></div><p style="color:var(--text2);font-size:0.8rem;margin-bottom:0.8rem">💡 Click any entry to select, Shift+click for range, Ctrl+click to toggle</p><div class="modal-actions"><button class="btn btn-sm" onclick="this.closest('.custom-modal-overlay').remove()">Got it</button></div></div>`;
document.body.appendChild(overlay);
overlay.addEventListener('click', e => { if (e.target === overlay) overlay.remove(); });
}
@@ -1352,7 +1360,7 @@ document.addEventListener('keydown', function(e) {
// Prevent browser defaults for ALL our shortcuts BEFORE dispatching
const code = e.code;
if (code === 'KeyN' || code === 'KeyF' || code === 'KeyT' || code === 'KeyL' || code === 'KeyS') {
if (code === 'KeyN' || code === 'KeyF' || code === 'KeyT' || code === 'KeyL' || code === 'KeyS' || code === 'KeyA') {
e.preventDefault();
}
@@ -1368,5 +1376,12 @@ document.addEventListener('keydown', function(e) {
} else if (code === 'KeyS') {
if (document.getElementById('addModal').classList.contains('show')) addEntry();
else if (document.getElementById('editModal').classList.contains('show')) saveEdit();
} else if (code === 'KeyA') {
if (!isInput && !document.getElementById('authSection').classList.contains('hidden')) {
getFilteredEntries(view === 'grouped' || view === 'detail').forEach(e => selectedIds.add(e.id));
updateBatchBar();
render();
playSound('click');
}
}
});