Improve same-window folder drops

This commit is contained in:
Mikei386
2026-06-23 09:26:32 +02:00
parent 53e25c4641
commit d81fa7cef7
6 changed files with 55 additions and 9 deletions
+40 -6
View File
@@ -727,6 +727,7 @@ function startItemPointerDrag(event, win, entry) {
sourceWindowId: win.id,
path: entry.path,
name: entry.name,
type: entry.type,
startX: event.clientX,
startY: event.clientY,
active: false,
@@ -756,6 +757,7 @@ function updateItemPointerDrag(event) {
event.preventDefault();
document.body.classList.add('u-nav-dragging');
markDraggingRow(drag.path, true);
markDropCandidates(drag.path, true);
updatePointerDropTarget(event);
}
@@ -769,6 +771,7 @@ async function finishItemPointerDrag(event, move, up) {
if (!drag) return;
markDraggingRow(drag.path, false);
markDropCandidates(drag.path, false);
state.pointerDrag = null;
if (!drag.active) {
@@ -794,6 +797,9 @@ async function finishItemPointerDrag(event, move, up) {
if (destination === drag.path) {
throw new Error('Quelle und Ziel sind identisch.');
}
if (drag.type === 'directory' && target.path.startsWith(`${drag.path.replace(/\/$/, '')}/`)) {
throw new Error('Ein Ordner kann nicht in sich selbst verschoben werden.');
}
await createJob(event.altKey ? 'copy' : 'move', drag.path, destination, [drag.sourceWindowId, target.windowId]);
} catch (error) {
showError(error);
@@ -825,8 +831,10 @@ function clearPointerDropTarget() {
function findPointerDropTarget(event) {
let element;
let elements = [];
try {
element = document.elementFromPoint(event.clientX, event.clientY);
elements = document.elementsFromPoint ? document.elementsFromPoint(event.clientX, event.clientY) : [element];
} catch (error) {
recordDebug('elementFromPoint.error', {
x: event.clientX,
@@ -847,13 +855,30 @@ function findPointerDropTarget(event) {
const win = state.windows.find((item) => item.id === windowEl.dataset.windowId);
if (!win || win.kind !== 'explorer') return null;
let row;
try {
row = element.closest?.('.file-row');
} catch (error) {
recordDebug('closest.row.error', { error: serializeError(error), element: element?.tagName });
const drag = state.pointerDrag;
let row = null;
for (const candidate of elements) {
try {
const candidateRow = candidate.closest?.('.file-row');
if (!candidateRow || candidateRow.dataset.type !== 'directory') {
continue;
}
if (candidateRow.dataset.path === drag?.path) {
continue;
}
if (drag?.type === 'directory' && candidateRow.dataset.path.startsWith(`${drag.path.replace(/\/$/, '')}/`)) {
continue;
}
if (candidateRow.closest?.('.window') !== windowEl) {
continue;
}
row = candidateRow;
break;
} catch (error) {
recordDebug('closest.row.error', { error: serializeError(error), element: candidate?.tagName });
}
}
if (row?.dataset.type === 'directory') {
if (row) {
return { windowId: win.id, path: row.dataset.path, row };
}
@@ -868,6 +893,15 @@ function markDraggingRow(path, dragging) {
}
}
function markDropCandidates(sourcePath, active) {
const source = state.pointerDrag;
for (const row of workspace.querySelectorAll('.file-row[data-type="directory"]')) {
const path = row.dataset.path || '';
const valid = path !== sourcePath && !(source?.type === 'directory' && path.startsWith(`${sourcePath.replace(/\/$/, '')}/`));
row.classList.toggle('drop-candidate', active && valid);
}
}
function lockExplorerScroll(win, body) {
win.data.lockScroll = true;
win.data.lockScrollTop = body.scrollTop;