import { ListenerResult } from './enums' ; import { ShouldHandleEventFunction , ShortcutID , ListenerOptions } from './types' ; import Shortcut from './shortcut' ; import Utils from './utils' ; class Listener { private options : ListenerOptions ; private capture : boolean ; private target : Node ; private shouldHandleEvent : ShouldHandleEventFunction ; private lastKeydownID : number = - 1 ; private currentKeydownShortcutID : ShortcutID = [ ] ; private currentKeypressShortcutID : ShortcutID = [ ] ; private currentKeyupShortcutID : ShortcutID = [ ] ; private resetNextKeydownShortcutID : boolean = false ; private triggeredNextKeypress : boolean = true ; private ignoreNextKeypress : boolean = false ; private listening : boolean = false ; constructor ( options ) { this . options = options ; this . capture = ! ! options . capture ; this . target = options . target || document ; this . shouldHandleEvent = options . shouldHandleEvent || ( event => ! event . defaultPrevented ) ; } on ( ) { if ( this . listening ) return ; this . listening = true ; this . target . addEventListener ( 'keydown' , this . handler , { capture : this . capture } ) ; this . target . addEventListener ( 'keypress' , this . handler , { capture : this . capture } ) ; this . target . addEventListener ( 'keyup' , this . handler , { capture : this . capture } ) ; } off ( ) { if ( ! this . listening ) return ; this . listening = false ; this . target . removeEventListener ( 'keydown' , this . handler , { capture : this . capture } ) ; this . target . removeEventListener ( 'keypress' , this . handler , { capture : this . capture } ) ; this . target . removeEventListener ( 'keyup' , this . handler , { capture : this . capture } ) ; } isListening ( ) { return this . listening ; } handler = ( event ) : void => { if ( ! this . shouldHandleEvent ( event ) ) return ; const { type } = event , isKeydown = ( type === 'keydown' ) , isKeypress = ( type === 'keypress' ) , isKeyup = ( type === 'keyup' ) ; if ( isKeydown ) { this . ignoreNextKeypress = false ; } if ( isKeypress && this . ignoreNextKeypress ) { this . triggeredNextKeypress = true ; return ; } const id = Shortcut . event2id ( event ) , triggerKey = Shortcut . getTriggerKey ( id ) ; if ( isKeydown ) { this . lastKeydownID = id ; } if ( isKeyup && ( triggerKey || id !== this . lastKeydownID ) ) { this . currentKeyupShortcutID . length = 0 ; return ; } if ( ! isKeyup && ! triggerKey ) return ; const shortcutID = isKeydown ? this . currentKeydownShortcutID : ( isKeyup ? this . currentKeyupShortcutID : this . currentKeypressShortcutID ) ; if ( isKeydown && ! this . resetNextKeydownShortcutID && ! this . triggeredNextKeypress ) { this . currentKeypressShortcutID . push ( this . currentKeydownShortcutID [ this . currentKeydownShortcutID . length - 1 ] ) ; } if ( isKeydown && this . resetNextKeydownShortcutID ) { shortcutID . length = 0 ; this . resetNextKeydownShortcutID = false ; } shortcutID . push ( id ) ; if ( isKeypress && Utils . isEqual ( this . currentKeydownShortcutID , shortcutID ) ) { if ( this . resetNextKeydownShortcutID ) { this . currentKeypressShortcutID . length = 0 ; } this . triggeredNextKeypress = true ; return ; } const result = this . options . handler ( shortcutID , event ) ; if ( result === ListenerResult . HANDLED ) { this . resetNextKeydownShortcutID = true ; this . currentKeypressShortcutID . length = 0 ; this . currentKeyupShortcutID . length = 0 ; } else if ( result === ListenerResult . UNHANDLEABLE ) { if ( isKeydown ) { this . resetNextKeydownShortcutID = true ; } else if ( isKeypress ) { this . currentKeypressShortcutID . length = 0 ; } else if ( isKeyup ) { this . currentKeyupShortcutID . length = 0 ; } } else if ( typeof result === 'object' ) { shortcutID . splice ( 0 , Infinity , ... result ) ; } if ( ! isKeyup ) { this . ignoreNextKeypress = isKeydown && result === ListenerResult . HANDLED ; this . triggeredNextKeypress = isKeypress ; } } ; } export default Listener ;