From 7fd81140b626469cdb246cffc464995da4c5c4e3 Mon Sep 17 00:00:00 2001 From: trivernis Date: Wed, 8 Dec 2021 20:09:23 +0100 Subject: [PATCH] Add file shortcuts - select with arrow keys - shift select with arrow keys - ctrl select with arrow keys - ctrl a - ctrl shift a TG-15 ready-for-test Signed-off-by: trivernis --- .../file-gallery/file-gallery.component.ts | 35 +++++--- .../file-grid/file-grid.component.ts | 90 ++++++++++++++++--- 2 files changed, 103 insertions(+), 22 deletions(-) diff --git a/mediarepo-ui/src/app/components/shared/file/file-multiview/file-gallery/file-gallery.component.ts b/mediarepo-ui/src/app/components/shared/file/file-multiview/file-gallery/file-gallery.component.ts index ba58e47..718953f 100644 --- a/mediarepo-ui/src/app/components/shared/file/file-multiview/file-gallery/file-gallery.component.ts +++ b/mediarepo-ui/src/app/components/shared/file/file-multiview/file-gallery/file-gallery.component.ts @@ -36,6 +36,7 @@ export class FileGalleryComponent implements OnChanges, OnInit { public fileContentUrl: SafeResourceUrl | undefined; private scrollTimeout: number | undefined; + private escapeCount = 0; constructor(private tabService: TabService, private fileService: FileService) { tabService.selectedTab.subscribe(() => this.adjustElementSizes()); @@ -153,6 +154,27 @@ export class FileGalleryComponent implements OnChanges, OnInit { } } + + private getPreselectedEntry(): Selectable | undefined { + if (this.preselectedFile) { + const entry = this.entries.find( + e => e.data.id === this.preselectedFile?.id); + if (entry) { + return entry; + } + } + return undefined; + } + + private onEscapeClick(): void { + if (this.escapeCount === 1) { + this.closeEvent.emit(this); + } else { + this.escapeCount++; + setTimeout(() => this.escapeCount--, 500); + } + } + @HostListener("window:keydown", ["$event"]) private async handleKeydownEvent(event: KeyboardEvent) { switch (event.key) { @@ -162,17 +184,10 @@ export class FileGalleryComponent implements OnChanges, OnInit { case "ArrowLeft": await this.previousItem(); break; + case "Escape": + this.onEscapeClick(); + break; } } - private getPreselectedEntry(): Selectable | undefined { - if (this.preselectedFile) { - const entry = this.entries.find( - e => e.data.id === this.preselectedFile?.id); - if (entry) { - return entry; - } - } - return undefined; - } } diff --git a/mediarepo-ui/src/app/components/shared/file/file-multiview/file-grid/file-grid.component.ts b/mediarepo-ui/src/app/components/shared/file/file-multiview/file-grid/file-grid.component.ts index c7a9dd1..9af092e 100644 --- a/mediarepo-ui/src/app/components/shared/file/file-multiview/file-grid/file-grid.component.ts +++ b/mediarepo-ui/src/app/components/shared/file/file-multiview/file-grid/file-grid.component.ts @@ -140,6 +140,8 @@ export class FileGridComponent implements OnChanges, OnInit { private handleShiftSelect(clickedEntry: Selectable): void { const lastEntry = this.selectedEntries[this.selectedEntries.length - 1]; let found = false; + + if (clickedEntry == lastEntry) { return; } @@ -161,27 +163,91 @@ export class FileGridComponent implements OnChanges, OnInit { } } + private selectAll() { + this.selectedEntries = this.gridEntries; + this.gridEntries.forEach(g => g.select()); + } + + private selectNone() { + this.selectedEntries = []; + this.gridEntries.forEach(g => g.unselect()); + } + + private handleArrowSelect(direction: "up" | "down" | "left" | "right") { + if (this.gridEntries.length === 0) { + return; + } + const lastSelectedEntry = this.selectedEntries[this.selectedEntries.length - 1] ?? this.gridEntries[0]; + let selectedIndex = this.gridEntries.indexOf(lastSelectedEntry); + + if (this.selectedEntries.length > 0) { + switch (direction) { + case "up": + selectedIndex -= this.columns; + break; + case "down": + selectedIndex += this.columns; + break; + case "left": + selectedIndex --; + break; + case "right": + selectedIndex++ + break; + } + while (selectedIndex < 0) { + selectedIndex = this.gridEntries.length + selectedIndex + } + if (selectedIndex > this.gridEntries.length) { + selectedIndex %= this.gridEntries.length; + } + } + + this.setSelectedFile(this.gridEntries[selectedIndex]); + + if (this.virtualScroll) { + this.virtualScroll.scrollToIndex(Math.floor(selectedIndex / this.columns) - 1); + } + } + @HostListener("window:keydown", ["$event"]) private handleKeydownEvent(event: KeyboardEvent) { + this.shiftClicked ||= event.shiftKey; + this.ctrlClicked ||= event.ctrlKey; + switch (event.key) { - case "Shift": - this.shiftClicked = true; + case "ArrowRight": + this.handleArrowSelect("right"); + break; + case "ArrowLeft": + this.handleArrowSelect("left"); + break; + case "ArrowDown": + this.handleArrowSelect("down"); + break; + case "ArrowUp": + this.handleArrowSelect("up"); break; - case "Control": - this.ctrlClicked = true; + case "a": + case "A": + if (this.shiftClicked && this.ctrlClicked) { + this.selectNone(); + } else if (this.ctrlClicked) { + event.preventDefault(); + this.selectAll(); + } + break; + case "Enter": + if (this.selectedEntries.length === 1) { + this.fileOpenEvent.emit(this.selectedEntries[0].data) + } break; } } @HostListener("window:keyup", ["$event"]) private handleKeyupEvent(event: KeyboardEvent) { - switch (event.key) { - case "Shift": - this.shiftClicked = false; - break; - case "Control": - this.ctrlClicked = false; - break; - } + this.shiftClicked = event.shiftKey? false : this.shiftClicked; + this.ctrlClicked = event.ctrlKey? false : this.ctrlClicked; } }