Improve same-window folder drops
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
PLUGIN="u-navigator"
|
PLUGIN="u-navigator"
|
||||||
VERSION="2026.06.23.r014"
|
VERSION="2026.06.23.r015"
|
||||||
PKG_DIR="packages"
|
PKG_DIR="packages"
|
||||||
WORK_DIR=".plugin-build"
|
WORK_DIR=".plugin-build"
|
||||||
PKG_NAME="${PLUGIN}-${VERSION}.tgz"
|
PKG_NAME="${PLUGIN}-${VERSION}.tgz"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+40
-6
@@ -727,6 +727,7 @@ function startItemPointerDrag(event, win, entry) {
|
|||||||
sourceWindowId: win.id,
|
sourceWindowId: win.id,
|
||||||
path: entry.path,
|
path: entry.path,
|
||||||
name: entry.name,
|
name: entry.name,
|
||||||
|
type: entry.type,
|
||||||
startX: event.clientX,
|
startX: event.clientX,
|
||||||
startY: event.clientY,
|
startY: event.clientY,
|
||||||
active: false,
|
active: false,
|
||||||
@@ -756,6 +757,7 @@ function updateItemPointerDrag(event) {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
document.body.classList.add('u-nav-dragging');
|
document.body.classList.add('u-nav-dragging');
|
||||||
markDraggingRow(drag.path, true);
|
markDraggingRow(drag.path, true);
|
||||||
|
markDropCandidates(drag.path, true);
|
||||||
updatePointerDropTarget(event);
|
updatePointerDropTarget(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -769,6 +771,7 @@ async function finishItemPointerDrag(event, move, up) {
|
|||||||
if (!drag) return;
|
if (!drag) return;
|
||||||
|
|
||||||
markDraggingRow(drag.path, false);
|
markDraggingRow(drag.path, false);
|
||||||
|
markDropCandidates(drag.path, false);
|
||||||
state.pointerDrag = null;
|
state.pointerDrag = null;
|
||||||
|
|
||||||
if (!drag.active) {
|
if (!drag.active) {
|
||||||
@@ -794,6 +797,9 @@ async function finishItemPointerDrag(event, move, up) {
|
|||||||
if (destination === drag.path) {
|
if (destination === drag.path) {
|
||||||
throw new Error('Quelle und Ziel sind identisch.');
|
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]);
|
await createJob(event.altKey ? 'copy' : 'move', drag.path, destination, [drag.sourceWindowId, target.windowId]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(error);
|
showError(error);
|
||||||
@@ -825,8 +831,10 @@ function clearPointerDropTarget() {
|
|||||||
|
|
||||||
function findPointerDropTarget(event) {
|
function findPointerDropTarget(event) {
|
||||||
let element;
|
let element;
|
||||||
|
let elements = [];
|
||||||
try {
|
try {
|
||||||
element = document.elementFromPoint(event.clientX, event.clientY);
|
element = document.elementFromPoint(event.clientX, event.clientY);
|
||||||
|
elements = document.elementsFromPoint ? document.elementsFromPoint(event.clientX, event.clientY) : [element];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
recordDebug('elementFromPoint.error', {
|
recordDebug('elementFromPoint.error', {
|
||||||
x: event.clientX,
|
x: event.clientX,
|
||||||
@@ -847,13 +855,30 @@ function findPointerDropTarget(event) {
|
|||||||
const win = state.windows.find((item) => item.id === windowEl.dataset.windowId);
|
const win = state.windows.find((item) => item.id === windowEl.dataset.windowId);
|
||||||
if (!win || win.kind !== 'explorer') return null;
|
if (!win || win.kind !== 'explorer') return null;
|
||||||
|
|
||||||
let row;
|
const drag = state.pointerDrag;
|
||||||
try {
|
let row = null;
|
||||||
row = element.closest?.('.file-row');
|
for (const candidate of elements) {
|
||||||
} catch (error) {
|
try {
|
||||||
recordDebug('closest.row.error', { error: serializeError(error), element: element?.tagName });
|
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 };
|
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) {
|
function lockExplorerScroll(win, body) {
|
||||||
win.data.lockScroll = true;
|
win.data.lockScroll = true;
|
||||||
win.data.lockScrollTop = body.scrollTop;
|
win.data.lockScrollTop = body.scrollTop;
|
||||||
|
|||||||
@@ -255,6 +255,7 @@
|
|||||||
.u-nav .file-row:hover,
|
.u-nav .file-row:hover,
|
||||||
.u-nav .file-row.selected,
|
.u-nav .file-row.selected,
|
||||||
.u-nav .file-row.dragging,
|
.u-nav .file-row.dragging,
|
||||||
|
.u-nav .file-row.drop-candidate,
|
||||||
.u-nav .file-row.drop-target {
|
.u-nav .file-row.drop-target {
|
||||||
background: var(--surface-2);
|
background: var(--surface-2);
|
||||||
}
|
}
|
||||||
@@ -262,10 +263,15 @@
|
|||||||
.u-nav .file-row:hover td,
|
.u-nav .file-row:hover td,
|
||||||
.u-nav .file-row.selected td,
|
.u-nav .file-row.selected td,
|
||||||
.u-nav .file-row.dragging td,
|
.u-nav .file-row.dragging td,
|
||||||
|
.u-nav .file-row.drop-candidate td,
|
||||||
.u-nav .file-row.drop-target td {
|
.u-nav .file-row.drop-target td {
|
||||||
background: var(--surface-2) !important;
|
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 {
|
.u-nav .file-row {
|
||||||
-webkit-user-drag: none;
|
-webkit-user-drag: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@@ -327,16 +333,22 @@
|
|||||||
.u-nav .icon-item:hover,
|
.u-nav .icon-item:hover,
|
||||||
.u-nav .icon-item.selected,
|
.u-nav .icon-item.selected,
|
||||||
.u-nav .icon-item.dragging,
|
.u-nav .icon-item.dragging,
|
||||||
|
.u-nav .icon-item.drop-candidate,
|
||||||
.u-nav .icon-item.drop-target {
|
.u-nav .icon-item.drop-target {
|
||||||
background: var(--surface-2);
|
background: var(--surface-2);
|
||||||
border-color: var(--line);
|
border-color: var(--line);
|
||||||
}
|
}
|
||||||
|
|
||||||
.u-nav .icon-item.selected,
|
.u-nav .icon-item.selected,
|
||||||
|
.u-nav .icon-item.drop-candidate,
|
||||||
.u-nav .icon-item.drop-target {
|
.u-nav .icon-item.drop-target {
|
||||||
border-color: var(--accent);
|
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 {
|
.u-nav .file-icon {
|
||||||
display: block;
|
display: block;
|
||||||
height: 52px;
|
height: 52px;
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE PLUGIN [
|
<!DOCTYPE PLUGIN [
|
||||||
<!ENTITY name "u-navigator">
|
<!ENTITY name "u-navigator">
|
||||||
<!ENTITY author "michael">
|
<!ENTITY author "michael">
|
||||||
<!ENTITY version "2026.06.23.r014">
|
<!ENTITY version "2026.06.23.r015">
|
||||||
<!ENTITY package "&name;-&version;.tgz">
|
<!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">
|
<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;">
|
<FILE Name="/boot/config/plugins/&name;/&package;">
|
||||||
<URL>https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package;</URL>
|
<URL>https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package;</URL>
|
||||||
<MD5>0100a8a8507d664658a9451a40881944</MD5>
|
<MD5>5dd13445e7847e581364f61f5fd26808</MD5>
|
||||||
</FILE>
|
</FILE>
|
||||||
|
|
||||||
<FILE Run="/bin/bash">
|
<FILE Run="/bin/bash">
|
||||||
|
|||||||
Reference in New Issue
Block a user