select range with shift

This commit is contained in:
2025-09-04 16:59:31 +02:00
parent 76aedbaf96
commit cdd4151462
2 changed files with 90 additions and 4 deletions

View File

@@ -79,13 +79,79 @@ function onDrop(files: File[] | null, e: DragEvent) {
} }
} }
/**
* Returns whether the event was a selection event (so further execution can be stopped)
*/
function handleEntrySelectionClick(
selectedEntry: DirectoryEntry,
event: MouseEvent
): boolean {
if (!event.ctrlKey && !event.shiftKey) {
return false;
}
if (warrenStore.current == null || warrenStore.current.dir == null) {
return true;
}
if (event.ctrlKey || (event.shiftKey && warrenStore.selection.size === 0)) {
if (
warrenStore.toggleSelection(selectedEntry) ||
warrenStore.selectionRangeAnchor == null
) {
warrenStore.setSelectedRangeAnchor(selectedEntry);
}
return true;
}
if (!event.shiftKey) {
return false;
}
const anchor = warrenStore.selectionRangeAnchor;
if (anchor == null) {
return true;
}
const entries = warrenStore.current.dir.entries.toSorted((a, b) =>
a.name.localeCompare(b.name)
);
const anchorIndex = entries.findIndex(
(entry) => entry.name === anchor.name
);
const clickedIndex = entries.findIndex(
(e) => e.name === selectedEntry.name
);
// NOTE: This has to change if there are ever multiple sorting orders
const targetSelection = [];
if (clickedIndex > anchorIndex) {
for (let i = anchorIndex; i <= clickedIndex; i++) {
targetSelection.push(entries[i]);
}
} else {
for (let i = clickedIndex; i <= anchorIndex; i++) {
targetSelection.push(entries[i]);
}
}
warrenStore.setSelection(targetSelection);
return true;
}
async function onEntryClicked(entry: DirectoryEntry, event: MouseEvent) { async function onEntryClicked(entry: DirectoryEntry, event: MouseEvent) {
event.stopPropagation();
if (warrenStore.loading || warrenStore.current == null) { if (warrenStore.loading || warrenStore.current == null) {
return; return;
} }
if (event.ctrlKey) { if (handleEntrySelectionClick(entry, event)) {
warrenStore.toggleSelection(entry);
return; return;
} }
@@ -156,10 +222,14 @@ async function onEntryDelete(entry: DirectoryEntry, force: boolean) {
function onBack() { function onBack() {
warrenStore.backCurrentPath(); warrenStore.backCurrentPath();
} }
function onParentClick() {
warrenStore.clearSelection();
}
</script> </script>
<template> <template>
<div ref="dropZoneRef" class="grow"> <div ref="dropZoneRef" class="grow" @click="onParentClick">
<DirectoryListContextMenu class="w-full grow"> <DirectoryListContextMenu class="w-full grow">
<DirectoryList <DirectoryList
v-if=" v-if="

View File

@@ -18,6 +18,7 @@ export const useWarrenStore = defineStore('warrens', {
} | null; } | null;
} | null, } | null,
selection: new Set() as Set<DirectoryEntry>, selection: new Set() as Set<DirectoryEntry>,
selectionRangeAnchor: null as DirectoryEntry | null,
loading: false, loading: false,
}), }),
actions: { actions: {
@@ -86,19 +87,33 @@ export const useWarrenStore = defineStore('warrens', {
addToSelection(entry: DirectoryEntry) { addToSelection(entry: DirectoryEntry) {
this.selection.add(entry); this.selection.add(entry);
}, },
setSelection(entries: DirectoryEntry[]) {
this.selection = new Set(entries);
if (
this.selectionRangeAnchor != null &&
!this.selection.has(this.selectionRangeAnchor)
) {
this.selectionRangeAnchor = null;
}
},
addMultipleToSelection(entries: DirectoryEntry[]) { addMultipleToSelection(entries: DirectoryEntry[]) {
for (const entry of entries) { for (const entry of entries) {
this.selection.add(entry); this.selection.add(entry);
} }
}, },
setSelectedRangeAnchor(entry: DirectoryEntry) {
this.selectionRangeAnchor = entry;
},
removeFromSelection(entry: DirectoryEntry): boolean { removeFromSelection(entry: DirectoryEntry): boolean {
return this.selection.delete(entry); return this.selection.delete(entry);
}, },
toggleSelection(entry: DirectoryEntry) { toggleSelection(entry: DirectoryEntry): boolean {
if (this.selection.has(entry)) { if (this.selection.has(entry)) {
this.removeFromSelection(entry); this.removeFromSelection(entry);
return false;
} else { } else {
this.addToSelection(entry); this.addToSelection(entry);
return true;
} }
}, },
isSelected(entry: DirectoryEntry): boolean { isSelected(entry: DirectoryEntry): boolean {
@@ -110,6 +125,7 @@ export const useWarrenStore = defineStore('warrens', {
}, },
clearSelection() { clearSelection() {
this.selection.clear(); this.selection.clear();
this.selectionRangeAnchor = null;
}, },
}, },
}); });