drop anywhere in folder

This commit is contained in:
vcoppe committed 2026-10-17 23:39:44 +02:00
1 parent a5c1f6ad33
commit 8fd47d8b18
2 files changed
+21 -8

No files matched your search

@@ -23,6 +23,7 @@
editableName, editableName,
explorerSelection, explorerSelection,
isWithin, isWithin,
parentOf,
renaming, renaming,
} from './state.svelte'; } from './state.svelte';
@@ -206,28 +207,34 @@
dragging.target = undefined; dragging.target = undefined;
} }
/** The folder where what is dropped on the row goes: the folder of a file, among its files. */
let dropFolder = $derived(kind === 'file' ? parentOf(path) : path);
function ondragover(event: DragEvent) { function ondragover(event: DragEvent) {
if (kind === 'file' || dragging.paths.length === 0) return; if (dragging.paths.length === 0) return;
// not into itself // not into itself, nor where it is already
if (dragging.paths.some((dragged) => isWithin(path, dragged))) return; if (dragging.paths.some((dragged) => isWithin(dropFolder, dragged))) return;
if (dragging.paths.every((dragged) => parentOf(dragged) === dropFolder)) return;
event.preventDefault(); event.preventDefault();
if (event.dataTransfer) { if (event.dataTransfer) {
event.dataTransfer.dropEffect = 'move'; event.dataTransfer.dropEffect = 'move';
} }
dragging.target = path; // the row of the folder shows it
dragging.target = dropFolder;
} }
function ondragleave(event: DragEvent) { function ondragleave(event: DragEvent) {
if (dragging.target === path && !row?.contains(event.relatedTarget as Node | null)) { // to another row, which tells where it would go (it was entered first)
dragging.target = undefined; const to = event.relatedTarget as Element | null;
} if (to?.closest?.('[data-explorer-path]')) return;
dragging.target = undefined;
} }
async function ondrop(event: DragEvent) { async function ondrop(event: DragEvent) {
event.preventDefault(); event.preventDefault();
const paths = dragging.paths; const paths = dragging.paths;
ondragend(); ondragend();
if (paths.length > 0 && !(await engine.movePaths(paths, path))) { if (paths.length > 0 && !(await engine.movePaths(paths, dropFolder))) {
showError(); showError();
} }
} }
@@ -33,6 +33,12 @@ function isSeparator(char: string | undefined) {
return char === '/' || char === '\\'; return char === '/' || char === '\\';
} }
/** The folder that holds `path`. */
export function parentOf(path: string): string {
const index = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
return index > 0 ? path.slice(0, index) : path;
}
/** Whether `path` is `folder` or something in it. */ /** Whether `path` is `folder` or something in it. */
export function isWithin(path: string, folder: string): boolean { export function isWithin(path: string, folder: string): boolean {
return path === folder || (path.startsWith(folder) && isSeparator(path[folder.length])); return path === folder || (path.startsWith(folder) && isSeparator(path[folder.length]));