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
+1 -1
View File
@@ -2,7 +2,7 @@
set -eu
PLUGIN="u-navigator"
VERSION="2026.06.23.r014"
VERSION="2026.06.23.r015"
PKG_DIR="packages"
WORK_DIR=".plugin-build"
PKG_NAME="${PLUGIN}-${VERSION}.tgz"
Binary file not shown.
Binary file not shown.
+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;
+12
View File
@@ -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;
+2 -2
View File
@@ -1,7 +1,7 @@
<!DOCTYPE PLUGIN [
<!ENTITY name "u-navigator">
<!ENTITY author "michael">
<!ENTITY version "2026.06.23.r014">
<!ENTITY version "2026.06.23.r015">
<!ENTITY package "&name;-&version;.tgz">
]>
<PLUGIN name="&name;" author="&author;" version="&version;" pluginURL="https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/u-navigator.plg">
@@ -14,7 +14,7 @@
<FILE Name="/boot/config/plugins/&name;/&package;">
<URL>https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package;</URL>
<MD5>0100a8a8507d664658a9451a40881944</MD5>
<MD5>5dd13445e7847e581364f61f5fd26808</MD5>
</FILE>
<FILE Run="/bin/bash">