Improve same-window folder drops
This commit is contained in:
+40
-6
@@ -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;
|
||||
|
||||
@@ -255,6 +255,7 @@
|
||||
.u-nav .file-row:hover,
|
||||
.u-nav .file-row.selected,
|
||||
.u-nav .file-row.dragging,
|
||||
.u-nav .file-row.drop-candidate,
|
||||
.u-nav .file-row.drop-target {
|
||||
background: var(--surface-2);
|
||||
}
|
||||
@@ -262,10 +263,15 @@
|
||||
.u-nav .file-row:hover td,
|
||||
.u-nav .file-row.selected td,
|
||||
.u-nav .file-row.dragging td,
|
||||
.u-nav .file-row.drop-candidate td,
|
||||
.u-nav .file-row.drop-target td {
|
||||
background: var(--surface-2) !important;
|
||||
}
|
||||
|
||||
.u-nav .file-row.drop-candidate td:first-child {
|
||||
box-shadow: inset 3px 0 0 color-mix(in srgb, var(--accent) 72%, transparent);
|
||||
}
|
||||
|
||||
.u-nav .file-row {
|
||||
-webkit-user-drag: none;
|
||||
user-select: none;
|
||||
@@ -327,16 +333,22 @@
|
||||
.u-nav .icon-item:hover,
|
||||
.u-nav .icon-item.selected,
|
||||
.u-nav .icon-item.dragging,
|
||||
.u-nav .icon-item.drop-candidate,
|
||||
.u-nav .icon-item.drop-target {
|
||||
background: var(--surface-2);
|
||||
border-color: var(--line);
|
||||
}
|
||||
|
||||
.u-nav .icon-item.selected,
|
||||
.u-nav .icon-item.drop-candidate,
|
||||
.u-nav .icon-item.drop-target {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.u-nav .icon-item.drop-candidate {
|
||||
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent);
|
||||
}
|
||||
|
||||
.u-nav .file-icon {
|
||||
display: block;
|
||||
height: 52px;
|
||||
|
||||
Reference in New Issue
Block a user