import { Directive , ElementRef , Renderer2 , HostListener , HostBinding } from '@angular/core' ; import { uniqueId , trapEvent } from '../util/util' ; import { DOWN_ARROW , ENTER , ESCAPE } from '@angular/cdk/keycodes' ; import { Observable , fromEvent } from 'rxjs' ; import { buffer , debounceTime , map } from 'rxjs/operators' ; import { NglComboboxService } from './combobox.service' ; const MAX_INTERVAL_BETWEEN_KEYSTROKES = 300 ; @ Directive ( { selector : 'input[nglCombobox]' , } ) export class NglComboboxInput { keyboardBuffer$ : Observable < string > ; @ HostBinding ( 'readOnly' ) get isReadonly ( ) { return this . service . combobox . variant === 'base' || this . service . combobox . hasLookupSingleSelection ; } @ HostBinding ( 'attr.aria-autocomplete' ) get ariaAutocomplete ( ) { return this . service . combobox . isLookup ? 'list' : null ; } @ HostBinding ( 'class.slds-combobox__input-value' ) get hasReadonlyValue ( ) { return this . service . combobox . hasLookupSingleSelection ; } get id ( ) { return this . el . nativeElement . id ; } constructor ( private service , private el , private renderer ) { const { nativeElement } = this . el ; this . renderer . addClass ( nativeElement , 'slds-input' ) ; this . renderer . addClass ( nativeElement , 'slds-combobox__input' ) ; this . renderer . setAttribute ( nativeElement , 'autoComplete' , 'off' ) ; this . renderer . setAttribute ( nativeElement , 'role' , 'textbox' ) ; this . renderer . setAttribute ( nativeElement , 'aria-controls' , this . service . combobox . uid ) ; if ( ! nativeElement . id ) { this . renderer . setAttribute ( nativeElement , 'id' , uniqueId ( 'combobox-input' ) ) ; } const keyboardEvent$ = fromEvent ( nativeElement , 'keypress' ) . pipe ( map ( ( e ) => e . keyCode ) ) ; this . keyboardBuffer$ = keyboardEvent$ . pipe ( buffer ( keyboardEvent$ . pipe ( debounceTime ( MAX_INTERVAL_BETWEEN_KEYSTROKES ) ) ) , map ( ( keyCodes ) => keyCodes . map ( ( c ) => String . fromCharCode ( c ) ) . join ( '' ) ) ) ; } setAriaActiveDescendant ( uid ) { if ( uid ) { this . renderer . setAttribute ( this . el . nativeElement , 'aria-activedescendant' , uid ) ; } else { this . renderer . removeAttribute ( this . el . nativeElement , 'aria-activedescendant' ) ; } } setValue ( value ) { this . renderer . setProperty ( this . el . nativeElement , 'value' , value !== null ? value : '' ) ; } focus ( ) { this . el . nativeElement . focus ( ) ; } @ HostListener ( 'click' ) onMouseInteraction ( ) { if ( this . service . combobox . hasLookupSingleSelection || ( this . service . combobox . open && this . service . combobox . isLookup ) ) { return ; } this . service . combobox . openChange . emit ( ! this . service . combobox . open ) ; } @ HostListener ( 'blur' ) onBlur ( ) { this . service . combobox . openChange . emit ( false ) ; } @ HostListener ( 'keydown' , [ '$event' ] ) onKeyboard ( evt ) { const keyCode = evt . keyCode ; if ( keyCode === ESCAPE ) { return ; } if ( this . service . combobox . open ) { switch ( keyCode ) { case ENTER : trapEvent ( evt ) ; this . service . combobox . onOptionSelection ( ) ; return ; default : this . service . combobox . keyManager . onKeydown ( evt ) ; return ; } } else { if ( this . service . combobox . hasLookupSingleSelection ) { return ; } if ( keyCode === DOWN_ARROW || keyCode === ENTER ) { trapEvent ( evt ) ; this . service . combobox . openChange . emit ( true ) ; return ; } if ( this . service . combobox . isLookup ) { setTimeout ( ( ) => this . service . combobox . openChange . emit ( true ) , 0 ) ; } } } }