Fix duplicate trash drop listener and rectangle selection bugs
- Move trash button drop listener out of setupDrag() to an IIFE so it only registers once (was accumulating listeners on every render() call, causing multiple toast messages on single drop). - Fix rectangle selection mousedown handler: use optional chaining on closest() for safety with text nodes; avoid calling render() inside mousedown (which would detach the event target's children mid-handler) and instead just remove .selected class directly from the DOM.
This commit is contained in:
@@ -869,21 +869,6 @@ function setupDrag() {
|
|||||||
el.ondragleave = function(e) { this.classList.remove('drag-over'); };
|
el.ondragleave = function(e) { this.classList.remove('drag-over'); };
|
||||||
el.ondrop = function(e) { e.preventDefault(); e.stopPropagation(); this.classList.remove('drag-over'); const fromId = parseInt(e.dataTransfer.getData('text/plain')); const toId = parseInt(this.dataset.id); if (!fromId || !toId) return; const ids = selectedIds.has(fromId) && selectedIds.size > 1 ? [...selectedIds] : [fromId]; if (ids.length === 1 && ids[0] === toId) return; const base = order.length > 0 ? order : entries.filter(e => e).map(e => e.id); const filtered = base.filter(id => !ids.includes(id)); const idx = filtered.indexOf(toId); idx > -1 ? filtered.splice(idx, 0, ...ids) : filtered.push(...ids); order = filtered; localStorage.setItem('entryOrder', JSON.stringify(order)); const map = new Map(entries.filter(e => e).map(e => [e.id, e])); entries = order.map(id => map.get(id)).filter(e => e); entries.sort((a, b) => (b.favorite || 0) - (a.favorite || 0)); render(); };
|
el.ondrop = function(e) { e.preventDefault(); e.stopPropagation(); this.classList.remove('drag-over'); const fromId = parseInt(e.dataTransfer.getData('text/plain')); const toId = parseInt(this.dataset.id); if (!fromId || !toId) return; const ids = selectedIds.has(fromId) && selectedIds.size > 1 ? [...selectedIds] : [fromId]; if (ids.length === 1 && ids[0] === toId) return; const base = order.length > 0 ? order : entries.filter(e => e).map(e => e.id); const filtered = base.filter(id => !ids.includes(id)); const idx = filtered.indexOf(toId); idx > -1 ? filtered.splice(idx, 0, ...ids) : filtered.push(...ids); order = filtered; localStorage.setItem('entryOrder', JSON.stringify(order)); const map = new Map(entries.filter(e => e).map(e => [e.id, e])); entries = order.map(id => map.get(id)).filter(e => e); entries.sort((a, b) => (b.favorite || 0) - (a.favorite || 0)); render(); };
|
||||||
});
|
});
|
||||||
// Trash button as drop target for multi-delete
|
|
||||||
const trashBtn = document.getElementById('trashBtn');
|
|
||||||
if (trashBtn) {
|
|
||||||
trashBtn.addEventListener('dragover', e => { if (!showTrash) { e.preventDefault(); trashBtn.classList.add('drag-over'); } });
|
|
||||||
trashBtn.addEventListener('dragleave', () => trashBtn.classList.remove('drag-over'));
|
|
||||||
trashBtn.addEventListener('drop', async function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.classList.remove('drag-over');
|
|
||||||
const id = parseInt(e.dataTransfer.getData('text/plain'));
|
|
||||||
if (!id) return;
|
|
||||||
const ids = selectedIds.has(id) && selectedIds.size > 1 ? [...selectedIds] : [id];
|
|
||||||
for (const sid of ids) await delEntry(sid);
|
|
||||||
clearSelection();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== EDIT ====================
|
// ==================== EDIT ====================
|
||||||
@@ -1138,16 +1123,38 @@ 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(); }));
|
||||||
|
// Trash button as drop target (set up once, outside setupDrag to avoid duplicates)
|
||||||
|
(function() {
|
||||||
|
const trashBtn = document.getElementById('trashBtn');
|
||||||
|
if (trashBtn) {
|
||||||
|
trashBtn.addEventListener('dragover', e => { if (!showTrash) { e.preventDefault(); trashBtn.classList.add('drag-over'); } });
|
||||||
|
trashBtn.addEventListener('dragleave', () => trashBtn.classList.remove('drag-over'));
|
||||||
|
trashBtn.addEventListener('drop', async function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.classList.remove('drag-over');
|
||||||
|
const id = parseInt(e.dataTransfer.getData('text/plain'));
|
||||||
|
if (!id) return;
|
||||||
|
const ids = selectedIds.has(id) && selectedIds.size > 1 ? [...selectedIds] : [id];
|
||||||
|
for (const sid of ids) await delEntry(sid);
|
||||||
|
clearSelection();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
// Rectangle selection
|
// Rectangle selection
|
||||||
document.getElementById('entriesContainer').addEventListener('mousedown', function(e) {
|
document.getElementById('entriesContainer').addEventListener('mousedown', function(e) {
|
||||||
if (rectState.active || e.button !== 0) return;
|
if (rectState.active || e.button !== 0) return;
|
||||||
if (e.target.closest('[draggable="true"]') || e.target.closest('.action-btns')) return;
|
if (e.target?.closest?.('[draggable="true"]') || e.target?.closest?.('.action-btns')) return;
|
||||||
rectState.active = true;
|
rectState.active = true;
|
||||||
rectState.startX = e.clientX;
|
rectState.startX = e.clientX;
|
||||||
rectState.startY = e.clientY;
|
rectState.startY = e.clientY;
|
||||||
rectState.started = false;
|
rectState.started = false;
|
||||||
rectState.el = null;
|
rectState.el = null;
|
||||||
clearSelection();
|
// Clear selection without full re-render to avoid detaching event target
|
||||||
|
selectedIds.clear();
|
||||||
|
lastSelectedId = null;
|
||||||
|
hideBatchBar();
|
||||||
|
document.getElementById('entriesContainer')?.querySelectorAll('.selected').forEach(el => el.classList.remove('selected'));
|
||||||
});
|
});
|
||||||
document.addEventListener('mousemove', function(e) {
|
document.addEventListener('mousemove', function(e) {
|
||||||
if (!rectState.active) return;
|
if (!rectState.active) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user