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.
This commit is contained in:
@@ -300,13 +300,17 @@ async function restoreEntry(id, noToast) {
|
|||||||
async function toggleFavorite(id) {
|
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) {}
|
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) {
|
async function permanentDelete(id, silent) {
|
||||||
if (!confirm('Permanently delete?')) return;
|
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) { toast('🗑️ Permanently deleted'); await loadEntries(); playSound('error'); } } catch (e) { toast('⚠️ Error', 'error'); }
|
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() {
|
async function emptyTrash() {
|
||||||
if (!confirm('Delete ALL trashed entries?')) return;
|
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'); }
|
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) {
|
function timeAgo(dateStr) {
|
||||||
if (!dateStr) return '';
|
if (!dateStr) return '';
|
||||||
@@ -937,6 +941,36 @@ function showConfirm(btn, message, callback) {
|
|||||||
}, 10);
|
}, 10);
|
||||||
}
|
}
|
||||||
function entryPw(id) { const e = entries.find(x => x.id == id); return e ? e.password : ''; }
|
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 =
|
||||||
|
'<div class="confirm-text">' + message + '</div>' +
|
||||||
|
'<div class="confirm-btns">' +
|
||||||
|
'<button class="confirm-yes">Yes</button>' +
|
||||||
|
'<button class="confirm-no">No</button>' +
|
||||||
|
'</div>';
|
||||||
|
document.body.appendChild(confirm);
|
||||||
|
const yesBtn = confirm.querySelector('.confirm-yes');
|
||||||
|
const noBtn = confirm.querySelector('.confirm-no');
|
||||||
|
const cleanup = () => { confirm.remove(); document.removeEventListener('keydown', keyHandler); };
|
||||||
|
const keyHandler = (e) => {
|
||||||
|
if (e.key === 'Enter' || e.key === 'y' || e.key === 'Y') { e.preventDefault(); cleanup(); callback(); playSound('delete'); }
|
||||||
|
else if (e.key === 'Escape' || e.key === 'n' || e.key === 'N') { e.preventDefault(); cleanup(); }
|
||||||
|
};
|
||||||
|
yesBtn.onclick = () => { cleanup(); callback(); playSound('delete'); };
|
||||||
|
noBtn.onclick = () => cleanup();
|
||||||
|
confirm.tabIndex = 0; confirm.focus();
|
||||||
|
document.addEventListener('keydown', keyHandler);
|
||||||
|
setTimeout(() => {
|
||||||
|
document.addEventListener('click', function closeConfirm(e) {
|
||||||
|
if (!confirm.contains(e.target)) { cleanup(); document.removeEventListener('click', closeConfirm); }
|
||||||
|
});
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
function attachEvents() {
|
function attachEvents() {
|
||||||
document.querySelectorAll('.delete-btn').forEach(b => b.onclick = function(ev) { ev.stopPropagation(); if (showTrash) { permanentDelete(this.dataset.id); } else { showConfirm(this, 'Delete this entry?', id => delEntry(id)); } });
|
document.querySelectorAll('.delete-btn').forEach(b => b.onclick = function(ev) { ev.stopPropagation(); if (showTrash) { permanentDelete(this.dataset.id); } else { showConfirm(this, 'Delete this entry?', id => delEntry(id)); } });
|
||||||
document.querySelectorAll('.edit-btn').forEach(b => b.onclick = function(ev) { ev.stopPropagation(); openEdit(this.dataset.id); });
|
document.querySelectorAll('.edit-btn').forEach(b => b.onclick = function(ev) { ev.stopPropagation(); openEdit(this.dataset.id); });
|
||||||
@@ -1066,19 +1100,25 @@ function hideBatchBar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function batchDelete() {
|
async function batchDelete() {
|
||||||
if (!confirm(`Move ${selectedIds.size} entries to trash?`)) return;
|
|
||||||
const count = selectedIds.size;
|
const count = selectedIds.size;
|
||||||
|
showCenterConfirm('Move ' + count + ' entries to trash?', async () => {
|
||||||
for (const id of selectedIds) await delEntry(id, true);
|
for (const id of selectedIds) await delEntry(id, true);
|
||||||
toast('📦 Moved ' + count + ' entries to trash');
|
toast('📦 Moved ' + count + ' entries to trash');
|
||||||
playSound('delete');
|
playSound('delete');
|
||||||
clearSelection();
|
clearSelection();
|
||||||
await loadEntries();
|
await loadEntries();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function batchPermanentDelete() {
|
async function batchPermanentDelete() {
|
||||||
if (!confirm(`Permanently delete ${selectedIds.size} entries?`)) return;
|
const count = selectedIds.size;
|
||||||
for (const id of selectedIds) await permanentDelete(id);
|
showCenterConfirm('Permanently delete ' + count + ' entries?', async () => {
|
||||||
|
for (const id of selectedIds) await permanentDelete(id, true);
|
||||||
|
toast('🗑️ Permanently deleted ' + count + ' entries');
|
||||||
|
playSound('error');
|
||||||
clearSelection();
|
clearSelection();
|
||||||
|
await loadEntries();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function batchRestore() {
|
async function batchRestore() {
|
||||||
|
|||||||
Reference in New Issue
Block a user