Hotkey service
This commit is contained in:
parent
4ee76f4edf
commit
5bb577ab20
@ -150,12 +150,12 @@ describe('GlobalSearchComponent', () => {
|
||||
|
||||
it('should handle keyboard nav', () => {
|
||||
const focusSpy = jest.spyOn(component.searchInput.nativeElement, 'focus')
|
||||
component.handleKeyboardEvent(
|
||||
document.dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'k', ctrlKey: true })
|
||||
)
|
||||
expect(focusSpy).toHaveBeenCalled()
|
||||
// coverage
|
||||
component.handleKeyboardEvent(
|
||||
document.dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'k', metaKey: true })
|
||||
)
|
||||
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
ViewChildren,
|
||||
QueryList,
|
||||
HostListener,
|
||||
OnInit,
|
||||
} from '@angular/core'
|
||||
import { Router } from '@angular/router'
|
||||
import { NgbDropdown, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
||||
@ -39,13 +40,14 @@ import { StoragePathEditDialogComponent } from '../../common/edit-dialog/storage
|
||||
import { TagEditDialogComponent } from '../../common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component'
|
||||
import { UserEditDialogComponent } from '../../common/edit-dialog/user-edit-dialog/user-edit-dialog.component'
|
||||
import { WorkflowEditDialogComponent } from '../../common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component'
|
||||
import { HotKeyService } from 'src/app/services/hot-key.service'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-global-search',
|
||||
templateUrl: './global-search.component.html',
|
||||
styleUrl: './global-search.component.scss',
|
||||
})
|
||||
export class GlobalSearchComponent {
|
||||
export class GlobalSearchComponent implements OnInit {
|
||||
public DataType = DataType
|
||||
public query: string
|
||||
public queryDebounce: Subject<string>
|
||||
@ -60,13 +62,6 @@ export class GlobalSearchComponent {
|
||||
@ViewChildren('primaryButton') primaryButtons: QueryList<ElementRef>
|
||||
@ViewChildren('secondaryButton') secondaryButtons: QueryList<ElementRef>
|
||||
|
||||
@HostListener('document:keydown', ['$event'])
|
||||
handleKeyboardEvent(event: KeyboardEvent) {
|
||||
if (event.key === 'k' && (event.ctrlKey || event.metaKey)) {
|
||||
this.searchInput.nativeElement.focus()
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
private searchService: SearchService,
|
||||
private router: Router,
|
||||
@ -74,7 +69,8 @@ export class GlobalSearchComponent {
|
||||
private documentService: DocumentService,
|
||||
private documentListViewService: DocumentListViewService,
|
||||
private permissionsService: PermissionsService,
|
||||
private toastService: ToastService
|
||||
private toastService: ToastService,
|
||||
private hotkeyService: HotKeyService
|
||||
) {
|
||||
this.queryDebounce = new Subject<string>()
|
||||
|
||||
@ -90,6 +86,15 @@ export class GlobalSearchComponent {
|
||||
})
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.hotkeyService.addShortcut({ keys: 'meta.k' }).subscribe(() => {
|
||||
this.searchInput.nativeElement.focus()
|
||||
})
|
||||
this.hotkeyService.addShortcut({ keys: 'control.k' }).subscribe(() => {
|
||||
this.searchInput.nativeElement.focus()
|
||||
})
|
||||
}
|
||||
|
||||
private search(query: string) {
|
||||
this.loading = true
|
||||
this.searchService.globalSearch(query).subscribe((results) => {
|
||||
|
41
src-ui/src/app/services/hot-key.service.spec.ts
Normal file
41
src-ui/src/app/services/hot-key.service.spec.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { EventManager } from '@angular/platform-browser'
|
||||
import { DOCUMENT } from '@angular/common'
|
||||
|
||||
import { HotKeyService } from './hot-key.service'
|
||||
|
||||
describe('HotKeyService', () => {
|
||||
let service: HotKeyService
|
||||
let eventManager: EventManager
|
||||
let document: Document
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [HotKeyService, EventManager],
|
||||
})
|
||||
service = TestBed.inject(HotKeyService)
|
||||
eventManager = TestBed.inject(EventManager)
|
||||
document = TestBed.inject(DOCUMENT)
|
||||
})
|
||||
|
||||
it('should support adding a shortcut', () => {
|
||||
const callback = jest.fn()
|
||||
const addEventListenerSpy = jest.spyOn(eventManager, 'addEventListener')
|
||||
|
||||
const observable = service
|
||||
.addShortcut({ keys: 'control.a' })
|
||||
.subscribe(() => {
|
||||
callback()
|
||||
})
|
||||
|
||||
expect(addEventListenerSpy).toHaveBeenCalled()
|
||||
|
||||
document.dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'a', ctrlKey: true })
|
||||
)
|
||||
expect(callback).toHaveBeenCalled()
|
||||
|
||||
//coverage
|
||||
observable.unsubscribe()
|
||||
})
|
||||
})
|
45
src-ui/src/app/services/hot-key.service.ts
Normal file
45
src-ui/src/app/services/hot-key.service.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { DOCUMENT } from '@angular/common'
|
||||
import { Inject, Injectable } from '@angular/core'
|
||||
import { EventManager } from '@angular/platform-browser'
|
||||
import { Observable } from 'rxjs'
|
||||
|
||||
export interface ShortcutOptions {
|
||||
element?: any
|
||||
keys: string
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class HotKeyService {
|
||||
defaults: Partial<ShortcutOptions> = {
|
||||
element: this.document,
|
||||
}
|
||||
|
||||
constructor(
|
||||
private eventManager: EventManager,
|
||||
@Inject(DOCUMENT) private document: Document
|
||||
) {}
|
||||
|
||||
addShortcut(options: ShortcutOptions) {
|
||||
const merged = { ...this.defaults, ...options }
|
||||
const event = `keydown.${merged.keys}`
|
||||
|
||||
return new Observable((observer) => {
|
||||
const handler = (e) => {
|
||||
e.preventDefault()
|
||||
observer.next(e)
|
||||
}
|
||||
|
||||
const dispose = this.eventManager.addEventListener(
|
||||
merged.element,
|
||||
event,
|
||||
handler
|
||||
)
|
||||
|
||||
return () => {
|
||||
dispose()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user