select range with shift
This commit is contained in:
@@ -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="
|
||||||
|
|||||||
@@ -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;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user