Replace batch mode toggle with click/Shift/Ctrl selection
- Remove separate 'select mode' toggle and checkbox UI - Click any entry to select it (blue highlight border) - Shift+click for range selection between two entries - Ctrl/Cmd+click to toggle individual entries - Click entry background or press Escape to clear selection - Batch action bar appears automatically when items are selected - Selected entries get accent-color border and highlight - Single delEntry() cleans up selectedIds - Shortcut help updated with selection tips
This commit is contained in:
+2
-1
@@ -136,8 +136,9 @@ input:focus, select:focus { border-color:var(--accent); }
|
|||||||
#entriesContainer.table-view th { text-align:left; padding:0.4rem 0.6rem; color:var(--text2); font-size:0.75rem; border-bottom:1px solid var(--border); }
|
#entriesContainer.table-view th { text-align:left; padding:0.4rem 0.6rem; color:var(--text2); font-size:0.75rem; border-bottom:1px solid var(--border); }
|
||||||
#entriesContainer.table-view td { padding:0.4rem 0.6rem; font-size:0.8rem; border-bottom:1px solid rgba(255,255,255,0.03); }
|
#entriesContainer.table-view td { padding:0.4rem 0.6rem; font-size:0.8rem; border-bottom:1px solid rgba(255,255,255,0.03); }
|
||||||
|
|
||||||
.entry-card, .entry-row, .entry-compact, .table-row-drag { cursor:grab; user-select:none; }
|
.entry-card, .entry-row, .entry-compact, .table-row-drag { cursor:pointer; user-select:none; }
|
||||||
.entry-card.drag-over, .entry-row.drag-over, .entry-compact.drag-over, .table-row-drag.drag-over { border-color:var(--accent)!important; box-shadow:0 0 15px rgba(59,130,246,0.3); }
|
.entry-card.drag-over, .entry-row.drag-over, .entry-compact.drag-over, .table-row-drag.drag-over { border-color:var(--accent)!important; box-shadow:0 0 15px rgba(59,130,246,0.3); }
|
||||||
|
.entry-card.selected, .entry-row.selected, .entry-compact.selected, .table-row-drag.selected { border-color:var(--accent)!important; box-shadow:0 0 0 2px var(--accent); background:rgba(59,130,246,0.08); }
|
||||||
.entry-card { background:var(--card); border:1px solid var(--border); border-radius:0.8rem; padding:0.9rem 2.8rem 0.9rem 0.9rem; transition:0.2s; position:relative; word-break:break-word; }
|
.entry-card { background:var(--card); border:1px solid var(--border); border-radius:0.8rem; padding:0.9rem 2.8rem 0.9rem 0.9rem; transition:0.2s; position:relative; word-break:break-word; }
|
||||||
.entry-card:hover { border-color:rgba(255,255,255,0.15); transform:translateY(-2px); }
|
.entry-card:hover { border-color:rgba(255,255,255,0.15); transform:translateY(-2px); }
|
||||||
.card-site { font-weight:700; font-size:0.9rem; color:var(--text); margin-bottom:0.2rem; }
|
.card-site { font-weight:700; font-size:0.9rem; color:var(--text); margin-bottom:0.2rem; }
|
||||||
|
|||||||
@@ -155,7 +155,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="display:flex;gap:.4rem;align-items:center;flex-wrap:wrap">
|
<div style="display:flex;gap:.4rem;align-items:center;flex-wrap:wrap">
|
||||||
<button class="btn btn-outline btn-sm" id="trashBtn" onclick="toggleTrash()" title="Trash">🗑️</button>
|
<button class="btn btn-outline btn-sm" id="trashBtn" onclick="toggleTrash()" title="Trash">🗑️</button>
|
||||||
<button class="btn btn-outline btn-sm" id="selectBtn" onclick="toggleSelectMode()" title="Batch select">☐ Select</button>
|
|
||||||
<button class="btn btn-outline btn-sm" onclick="showShortcutsHelp()" title="Shortcuts">⌨️</button>
|
<button class="btn btn-outline btn-sm" onclick="showShortcutsHelp()" title="Shortcuts">⌨️</button>
|
||||||
<div class="view-toggle" id="viewToggle">
|
<div class="view-toggle" id="viewToggle">
|
||||||
<button class="view-btn active" data-view="grid">🟫 Grid</button>
|
<button class="view-btn active" data-view="grid">🟫 Grid</button>
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ let searchQuery = '';
|
|||||||
let idleT, warnT, countT;
|
let idleT, warnT, countT;
|
||||||
let draggedId = null;
|
let draggedId = null;
|
||||||
let showTrash = false;
|
let showTrash = false;
|
||||||
let selectMode = false;
|
|
||||||
let selectedIds = new Set();
|
let selectedIds = new Set();
|
||||||
|
let lastSelectedId = null;
|
||||||
|
|
||||||
// ==================== SOUND ====================
|
// ==================== SOUND ====================
|
||||||
let soundEnabled = localStorage.getItem('soundEnabled') !== 'false';
|
let soundEnabled = localStorage.getItem('soundEnabled') !== 'false';
|
||||||
@@ -657,7 +657,8 @@ function render() {
|
|||||||
if (view === 'table') {
|
if (view === 'table') {
|
||||||
let h = '<table><thead><tr><th></th><th>Site</th>' + (showMail ? '<th>User</th>' : '') + '<th>Password</th>' + (!showTrash ? '<th>Folder</th>' : '<th>Deleted</th>') + '<th>Actions</th></tr></thead><tbody>';
|
let h = '<table><thead><tr><th></th><th>Site</th>' + (showMail ? '<th>User</th>' : '') + '<th>Password</th>' + (!showTrash ? '<th>Folder</th>' : '<th>Deleted</th>') + '<th>Actions</th></tr></thead><tbody>';
|
||||||
filtered.forEach(e => {
|
filtered.forEach(e => {
|
||||||
h += '<tr class="table-row-drag' + (e.favorite ? ' favorite' : '') + '" draggable="true" data-id="' + e.id + '">' +
|
const sel = selectedIds.has(e.id);
|
||||||
|
h += '<tr class="table-row-drag' + (e.favorite ? ' favorite' : '') + (sel ? ' selected' : '') + '" draggable="true" data-id="' + e.id + '" onclick="toggleSelectEntry(' + e.id + ', event)">' +
|
||||||
'<td>' + (e.favorite ? '⭐' : '') + '</td>' +
|
'<td>' + (e.favorite ? '⭐' : '') + '</td>' +
|
||||||
'<td>🌐 ' + highlightText(e.site, searchQuery) + '</td>' +
|
'<td>🌐 ' + highlightText(e.site, searchQuery) + '</td>' +
|
||||||
(showMail ? '<td>👤 ' + highlightText(e.username, searchQuery) + '</td>' : '') +
|
(showMail ? '<td>👤 ' + highlightText(e.username, searchQuery) + '</td>' : '') +
|
||||||
@@ -665,7 +666,6 @@ function render() {
|
|||||||
if (!showTrash) {
|
if (!showTrash) {
|
||||||
h += '<td><span class="entry-folder">📁 ' + esc(e.folder || 'All') + '</span></td>' +
|
h += '<td><span class="entry-folder">📁 ' + esc(e.folder || 'All') + '</span></td>' +
|
||||||
'<td class="actions-cell">' +
|
'<td class="actions-cell">' +
|
||||||
(selectMode ? `<input type="checkbox" class="select-checkbox" style="position:static;margin-right:8px;" ${selectedIds.has(e.id) ? 'checked' : ''} onclick="event.stopPropagation();toggleSelectEntry(${e.id})">` : '') +
|
|
||||||
'<button class="star-btn" data-id="' + e.id + '">' + (e.favorite ? '⭐' : '☆') + '</button> ' +
|
'<button class="star-btn" data-id="' + e.id + '">' + (e.favorite ? '⭐' : '☆') + '</button> ' +
|
||||||
'<button class="icon-btn copy-p" data-id="' + e.id + '">📋</button> ' +
|
'<button class="icon-btn copy-p" data-id="' + e.id + '">📋</button> ' +
|
||||||
'<button class="edit-btn" data-id="' + e.id + '" style="position:static;display:inline-flex;vertical-align:middle;">✏️</button> ' +
|
'<button class="edit-btn" data-id="' + e.id + '" style="position:static;display:inline-flex;vertical-align:middle;">✏️</button> ' +
|
||||||
@@ -674,7 +674,6 @@ function render() {
|
|||||||
} else {
|
} else {
|
||||||
h += '<td><span class="trash-badge">🗑️ ' + timeAgo(e.deleted_at) + '</span></td>' +
|
h += '<td><span class="trash-badge">🗑️ ' + timeAgo(e.deleted_at) + '</span></td>' +
|
||||||
'<td class="actions-cell">' +
|
'<td class="actions-cell">' +
|
||||||
(selectMode ? `<input type="checkbox" class="select-checkbox" style="position:static;margin-right:8px;" ${selectedIds.has(e.id) ? 'checked' : ''} onclick="event.stopPropagation();toggleSelectEntry(${e.id})">` : '') +
|
|
||||||
'<button class="restore-btn" onclick="restoreEntry(' + e.id + ')">↩️</button> ' +
|
'<button class="restore-btn" onclick="restoreEntry(' + e.id + ')">↩️</button> ' +
|
||||||
'<button class="delete-btn" data-id="' + e.id + '" style="position:static;display:inline-flex;vertical-align:middle;">✕</button>' +
|
'<button class="delete-btn" data-id="' + e.id + '" style="position:static;display:inline-flex;vertical-align:middle;">✕</button>' +
|
||||||
'</td>';
|
'</td>';
|
||||||
@@ -695,10 +694,8 @@ function render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function gridC(e) {
|
function gridC(e) {
|
||||||
let html = '<div class="entry-card' + (e.favorite ? ' favorite' : '') + '" draggable="' + (!selectMode) + '" data-id="' + e.id + '">';
|
const sel = selectedIds.has(e.id);
|
||||||
if (selectMode) {
|
let html = '<div class="entry-card' + (e.favorite ? ' favorite' : '') + (sel ? ' selected' : '') + '" draggable="true" data-id="' + e.id + '" onclick="toggleSelectEntry(' + e.id + ', event)">';
|
||||||
html += `<input type="checkbox" class="select-checkbox" ${selectedIds.has(e.id) ? 'checked' : ''} onclick="event.stopPropagation();toggleSelectEntry(${e.id})">`;
|
|
||||||
}
|
|
||||||
html += '<div class="action-btns">';
|
html += '<div class="action-btns">';
|
||||||
if (showTrash) {
|
if (showTrash) {
|
||||||
html += '<button class="restore-btn" onclick="restoreEntry(' + e.id + ')">↩️</button>';
|
html += '<button class="restore-btn" onclick="restoreEntry(' + e.id + ')">↩️</button>';
|
||||||
@@ -722,10 +719,8 @@ function gridC(e) {
|
|||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
function listC(e) {
|
function listC(e) {
|
||||||
let html = '<div class="entry-row' + (e.favorite ? ' favorite' : '') + '" draggable="' + (!selectMode) + '" data-id="' + e.id + '">';
|
const sel = selectedIds.has(e.id);
|
||||||
if (selectMode) {
|
let html = '<div class="entry-row' + (e.favorite ? ' favorite' : '') + (sel ? ' selected' : '') + '" draggable="true" data-id="' + e.id + '" onclick="toggleSelectEntry(' + e.id + ', event)">';
|
||||||
html += `<input type="checkbox" class="select-checkbox" ${selectedIds.has(e.id) ? 'checked' : ''} onclick="event.stopPropagation();toggleSelectEntry(${e.id})">`;
|
|
||||||
}
|
|
||||||
html += '<div class="action-btns">';
|
html += '<div class="action-btns">';
|
||||||
if (showTrash) {
|
if (showTrash) {
|
||||||
html += '<button class="restore-btn" onclick="restoreEntry(' + e.id + ')">↩️</button>';
|
html += '<button class="restore-btn" onclick="restoreEntry(' + e.id + ')">↩️</button>';
|
||||||
@@ -749,10 +744,8 @@ function listC(e) {
|
|||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
function compC(e) {
|
function compC(e) {
|
||||||
let html = '<div class="entry-compact' + (e.favorite ? ' favorite' : '') + '" draggable="' + (!selectMode) + '" data-id="' + e.id + '">';
|
const sel = selectedIds.has(e.id);
|
||||||
if (selectMode) {
|
let html = '<div class="entry-compact' + (e.favorite ? ' favorite' : '') + (sel ? ' selected' : '') + '" draggable="true" data-id="' + e.id + '" onclick="toggleSelectEntry(' + e.id + ', event)">';
|
||||||
html += `<input type="checkbox" class="select-checkbox" ${selectedIds.has(e.id) ? 'checked' : ''} onclick="event.stopPropagation();toggleSelectEntry(${e.id})">`;
|
|
||||||
}
|
|
||||||
html += '<div class="action-btns">';
|
html += '<div class="action-btns">';
|
||||||
if (showTrash) {
|
if (showTrash) {
|
||||||
html += '<button class="restore-btn" onclick="restoreEntry(' + e.id + ')">↩️</button>';
|
html += '<button class="restore-btn" onclick="restoreEntry(' + e.id + ')">↩️</button>';
|
||||||
@@ -911,37 +904,42 @@ async function saveEdit() {
|
|||||||
else { const d = await r.json(); toast('❌ ' + (d.error || 'Failed'), 'error'); }
|
else { const d = await r.json(); toast('❌ ' + (d.error || 'Failed'), 'error'); }
|
||||||
} catch (e) { toast('⚠️ Error', 'error'); }
|
} catch (e) { toast('⚠️ Error', 'error'); }
|
||||||
}
|
}
|
||||||
//======================== batch operations ==========================
|
//======================== batch selection ==========================
|
||||||
function toggleSelectMode() {
|
function toggleSelectEntry(id, e) {
|
||||||
selectMode = !selectMode;
|
if (e?.shiftKey && lastSelectedId !== null) {
|
||||||
document.getElementById('selectBtn').textContent = selectMode ? '☑ Deselect' : '☐ Select';
|
const ids = getFilteredEntries().map(x => x.id);
|
||||||
document.getElementById('selectBtn').classList.toggle('active', selectMode);
|
const i1 = ids.indexOf(lastSelectedId);
|
||||||
if (!selectMode) {
|
const i2 = ids.indexOf(id);
|
||||||
selectedIds.clear();
|
if (i1 > -1 && i2 > -1) {
|
||||||
hideBatchBar();
|
const start = Math.min(i1, i2), end = Math.max(i1, i2);
|
||||||
|
for (let i = start; i <= end; i++) selectedIds.add(ids[i]);
|
||||||
|
}
|
||||||
|
} else if (e?.ctrlKey || e?.metaKey) {
|
||||||
|
if (selectedIds.has(id)) selectedIds.delete(id); else selectedIds.add(id);
|
||||||
|
} else {
|
||||||
|
if (selectedIds.size === 1 && selectedIds.has(id)) { selectedIds.clear(); }
|
||||||
|
else { selectedIds.clear(); selectedIds.add(id); }
|
||||||
}
|
}
|
||||||
|
lastSelectedId = id;
|
||||||
|
updateBatchBar();
|
||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleSelectEntry(id) {
|
function clearSelection() {
|
||||||
if (selectedIds.has(id)) {
|
selectedIds.clear();
|
||||||
selectedIds.delete(id);
|
lastSelectedId = null;
|
||||||
} else {
|
hideBatchBar();
|
||||||
selectedIds.add(id);
|
render();
|
||||||
}
|
|
||||||
updateBatchBar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBatchBar() {
|
function updateBatchBar() {
|
||||||
const existing = document.getElementById('batchBar');
|
const existing = document.getElementById('batchBar');
|
||||||
if (existing) existing.remove();
|
if (existing) existing.remove();
|
||||||
if (selectedIds.size === 0) return;
|
if (selectedIds.size === 0) return;
|
||||||
|
|
||||||
const bar = document.createElement('div');
|
const bar = document.createElement('div');
|
||||||
bar.id = 'batchBar';
|
bar.id = 'batchBar';
|
||||||
bar.className = 'batch-actions';
|
bar.className = 'batch-actions';
|
||||||
bar.innerHTML = `<span class="selected-count">${selectedIds.size} selected</span>`;
|
bar.innerHTML = `<span class="selected-count">${selectedIds.size} selected</span>`;
|
||||||
|
|
||||||
if (showTrash) {
|
if (showTrash) {
|
||||||
bar.innerHTML += `
|
bar.innerHTML += `
|
||||||
<button class="btn btn-sm restore-btn" onclick="batchRestore()">↩️ Restore All</button>
|
<button class="btn btn-sm restore-btn" onclick="batchRestore()">↩️ Restore All</button>
|
||||||
@@ -956,7 +954,7 @@ function updateBatchBar() {
|
|||||||
<button class="btn btn-sm btn-danger" onclick="batchDelete()">Delete</button>
|
<button class="btn btn-sm btn-danger" onclick="batchDelete()">Delete</button>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
bar.innerHTML += `<button class="btn btn-sm btn-outline" onclick="toggleSelectMode()">Cancel</button>`;
|
bar.innerHTML += `<button class="btn btn-sm btn-outline" onclick="clearSelection()">Clear</button>`;
|
||||||
document.body.appendChild(bar);
|
document.body.appendChild(bar);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,21 +966,18 @@ function hideBatchBar() {
|
|||||||
async function batchDelete() {
|
async function batchDelete() {
|
||||||
if (!confirm(`Move ${selectedIds.size} entries to trash?`)) return;
|
if (!confirm(`Move ${selectedIds.size} entries to trash?`)) return;
|
||||||
for (const id of selectedIds) await delEntry(id);
|
for (const id of selectedIds) await delEntry(id);
|
||||||
selectedIds.clear();
|
clearSelection();
|
||||||
hideBatchBar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function batchPermanentDelete() {
|
async function batchPermanentDelete() {
|
||||||
if (!confirm(`Permanently delete ${selectedIds.size} entries?`)) return;
|
if (!confirm(`Permanently delete ${selectedIds.size} entries?`)) return;
|
||||||
for (const id of selectedIds) await permanentDelete(id);
|
for (const id of selectedIds) await permanentDelete(id);
|
||||||
selectedIds.clear();
|
clearSelection();
|
||||||
hideBatchBar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function batchRestore() {
|
async function batchRestore() {
|
||||||
for (const id of selectedIds) await restoreEntry(id);
|
for (const id of selectedIds) await restoreEntry(id);
|
||||||
selectedIds.clear();
|
clearSelection();
|
||||||
hideBatchBar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function batchMove() {
|
async function batchMove() {
|
||||||
@@ -999,8 +994,7 @@ async function batchMove() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
selectedIds.clear();
|
clearSelection();
|
||||||
hideBatchBar();
|
|
||||||
loadEntries();
|
loadEntries();
|
||||||
}
|
}
|
||||||
// ==================== ADD / DELETE ====================
|
// ==================== ADD / DELETE ====================
|
||||||
@@ -1035,7 +1029,7 @@ async function addEntry() {
|
|||||||
async function delEntry(id) {
|
async function delEntry(id) {
|
||||||
try {
|
try {
|
||||||
const r = await fetch(API + '/entries/' + id, { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token, 'X-CSRF-Token': csrfToken } });
|
const r = await fetch(API + '/entries/' + id, { 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)); toast('📦 Moved to trash'); await loadEntries(); playSound('delete'); }
|
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'); }
|
} catch (e) { toast('Error', 'error'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1090,7 +1084,7 @@ function highlightText(text, query) {
|
|||||||
function showShortcutsHelp() {
|
function showShortcutsHelp() {
|
||||||
const overlay = document.createElement('div');
|
const overlay = document.createElement('div');
|
||||||
overlay.className = 'custom-modal-overlay show';
|
overlay.className = 'custom-modal-overlay show';
|
||||||
overlay.innerHTML = `<div class="custom-modal" style="min-width:360px"><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 / settings</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><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+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>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);
|
document.body.appendChild(overlay);
|
||||||
overlay.addEventListener('click', e => { if (e.target === overlay) overlay.remove(); });
|
overlay.addEventListener('click', e => { if (e.target === overlay) overlay.remove(); });
|
||||||
}
|
}
|
||||||
@@ -1123,6 +1117,7 @@ if (token && curUser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
['click', 'keypress', 'scroll', 'mousemove'].forEach(e => document.addEventListener(e, () => { if (token) resetIdle(); }));
|
['click', 'keypress', 'scroll', 'mousemove'].forEach(e => document.addEventListener(e, () => { if (token) resetIdle(); }));
|
||||||
|
document.getElementById('entriesContainer').addEventListener('click', function(e) { if (e.target === this || (selectedIds.size > 0 && !e.target.closest('.entry-card,.entry-row,.entry-compact,.table-row-drag'))) { clearSelection(); } });
|
||||||
document.addEventListener('keypress', e => { if (e.key === 'Enter') { if (document.getElementById('passwordInput') === document.activeElement) addEntry(); else if (document.getElementById('loginPassword') === document.activeElement) login(); else if (document.getElementById('regPassword') === document.activeElement) register(); } });
|
document.addEventListener('keypress', e => { if (e.key === 'Enter') { if (document.getElementById('passwordInput') === document.activeElement) addEntry(); else if (document.getElementById('loginPassword') === document.activeElement) login(); else if (document.getElementById('regPassword') === document.activeElement) register(); } });
|
||||||
document.getElementById('genModal').addEventListener('click', e => { if (e.target === e.currentTarget) closeGen(); });
|
document.getElementById('genModal').addEventListener('click', e => { if (e.target === e.currentTarget) closeGen(); });
|
||||||
document.getElementById('editModal').addEventListener('click', e => { if (e.target === e.currentTarget) closeEdit(); });
|
document.getElementById('editModal').addEventListener('click', e => { if (e.target === e.currentTarget) closeEdit(); });
|
||||||
@@ -1133,6 +1128,7 @@ document.addEventListener('keydown', function(e) {
|
|||||||
|
|
||||||
// Escape – close any open modal or settings
|
// Escape – close any open modal or settings
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
|
if (selectedIds.size > 0) { clearSelection(); return; }
|
||||||
if (!document.getElementById('settingsMenu').classList.contains('hidden')) {
|
if (!document.getElementById('settingsMenu').classList.contains('hidden')) {
|
||||||
document.getElementById('settingsMenu').classList.add('hidden');
|
document.getElementById('settingsMenu').classList.add('hidden');
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user