Skip to content
Snippets Groups Projects
Unverified Commit 7147ff8a authored by xgui3783's avatar xgui3783 Committed by GitHub
Browse files

Merge pull request #754 from HumanBrainProject/bugfix_uiBugs

bugfix: h key no longer breaks UI
parents 7d1ffa61 25cd2308
No related branches found
No related tags found
No related merge requests found
......@@ -103,15 +103,16 @@ export class SigninBanner {
private keyListenerConfigBase = {
type: 'keydown',
stop: true,
prevent: true,
target: 'document',
}
public keyListenerConfig = [{
key: 'h',
capture: true,
...this.keyListenerConfigBase,
}, {
key: 'H',
capture: true,
...this.keyListenerConfigBase,
}, {
key: '?',
......
import { Directive, EventEmitter, HostListener, Input, Output } from "@angular/core";
const getFilterFn = (ev: KeyboardEvent, isDocument: boolean) => ({ type, key, target }: KeyListenerConfig): boolean => type === ev.type && ev.key === key && (target === 'document') === isDocument
import { Directive, ElementRef, EventEmitter, Inject, Input, OnChanges, OnDestroy, Output } from "@angular/core";
import { DOCUMENT } from '@angular/common'
import { fromEvent, merge, Subscription } from "rxjs";
@Directive({
selector: '[iav-key-listener]',
})
export class KeyListner {
export class KeyListner implements OnChanges, OnDestroy{
@Input('iav-key-listener')
public keydownConfig: KeyListenerConfig[] = []
......@@ -19,64 +19,72 @@ export class KeyListner {
return (tagName === 'SELECT' || tagName === 'INPUT' || tagName === 'TEXTAREA')
}
@HostListener('keydown', ['$event'])
public keydown(ev: KeyboardEvent) {
this.handleSelfListener(ev)
}
@HostListener('document:keydown', ['$event'])
public documentKeydown(ev: KeyboardEvent) {
this.handleDocumentListener(ev)
private subs: Subscription[] = []
ngOnChanges(){
if (this.keydownConfig) {
this.ngOnDestroy()
const documentEv = this.keydownConfig.filter(c => c.target === 'document')
const documentCaptureEv = documentEv.filter(c => c.capture)
const documentBubbleEv = documentEv.filter(c => !c.capture)
const selfEv = this.keydownConfig.filter(c => c.target !== 'document')
const selfCaptureEv = selfEv.filter(c => c.capture)
const selfBubbleEv = selfEv.filter(c => !c.capture)
this.subs.push(
merge(
fromEvent(this.document, 'keydown', { capture: true }),
fromEvent(this.document, 'keyup', { capture: true })
).subscribe(this.getEvHandler(documentCaptureEv).bind(this)),
merge(
fromEvent(this.document, 'keydown'),
fromEvent(this.document, 'keyup')
).subscribe(this.getEvHandler(documentBubbleEv).bind(this)),
merge(
fromEvent(this.el.nativeElement, 'keydown', { capture: true }),
fromEvent(this.el.nativeElement, 'keyup', { capture: true })
).subscribe(this.getEvHandler(selfCaptureEv).bind(this)),
merge(
fromEvent(this.el.nativeElement, 'keydown'),
fromEvent(this.el.nativeElement, 'keyup')
).subscribe(this.getEvHandler(selfBubbleEv).bind(this)),
)
}
}
@HostListener('keyup', ['$event'])
public keyup(ev: KeyboardEvent) {
this.handleSelfListener(ev)
ngOnDestroy(){
while(this.subs.length > 0) this.subs.pop().unsubscribe()
}
@HostListener('document:keyup', ['$event'])
public documentKeyup(ev: KeyboardEvent) {
this.handleDocumentListener(ev)
}
constructor(
private el: ElementRef,
@Inject(DOCUMENT) private document
){
private handleSelfListener(ev: KeyboardEvent) {
if (!this.keydownConfig) { return }
if (this.isTextField(ev)) { return }
const filteredConfig = this.keydownConfig
.filter(getFilterFn(ev, false))
.map(config => {
return {
config,
ev,
}
})
this.emitEv(filteredConfig)
}
private handleDocumentListener(ev: KeyboardEvent) {
if (!this.keydownConfig) { return }
if (this.isTextField(ev)) { return }
const filteredConfig = this.keydownConfig
.filter(getFilterFn(ev, true))
.map(config => {
return {
config,
ev,
}
})
this.emitEv(filteredConfig)
private getEvHandler(cfgs: KeyListenerConfig[]){
return (ev: KeyboardEvent) => {
if (this.isTextField(ev)) return
const filteredCfgs = cfgs.filter(c => c.key === ev.key && c.type === ev.type)
for (const cfg of filteredCfgs) {
if (cfg.stop) ev.stopPropagation()
}
this.emitEv(filteredCfgs.map(cfg => ({
config: cfg,
ev
})))
}
}
private emitEv(items: Array<{config: KeyListenerConfig, ev: KeyboardEvent}>) {
for (const item of items) {
const { config, ev } = item as {config: KeyListenerConfig, ev: KeyboardEvent}
const { stop, prevent } = config
if (stop) { ev.stopPropagation() }
if (prevent) { ev.preventDefault() }
this.keyEvent.emit({
config, ev,
})
......@@ -91,6 +99,8 @@ export interface KeyListenerConfig {
type: 'keydown' | 'keyup'
key: string
target?: 'document'
capture?: boolean
stop: boolean
prevent: boolean
// fromEvent seems to be a passive listener, wheather or not { passive: false } flag is set or not
// so preventDefault cannot be called anyway
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment