// Angular // import { Directive, ElementRef, OnInit, AfterViewInit, OnChanges, SimpleChanges, SimpleChange, Output, Input, EventEmitter, HostListener } from '@angular/core'; // RXJS // import { Subject } from 'rxjs/Subject'; // Other // import * as statics from '@fb/statics'; /** * Gör det möjligt att sätta och byta val genom piltangenter och enter. * Användning: * Direktivet sätts på ett ul-emenemnt som innehåller val i form av li-element. Dessa li element * markeras genom att sätta klassen fb-highlight på det valda elementet. Användaren kan sedan * använda upp och nedåt piltangent för att byta vilket val som är aktivt. Enter väljer det * aktiva valet. * * @param keyEventSubject ett subject som berättar när användaren gjort ett knapptryck och vilket * @param optionList en lista över de val som kan göras * @param onItemSelect Output på vilket val från optionList som görs * */ @Directive({ selector: '[fbKeySelectListItem]' }) export class FbKeySelectListItemDirective implements OnInit, AfterViewInit, OnChanges { @Input() keyEventSubject: Subject; @Input() optionList: any[]; @Output() onItemSelect: EventEmitter = new EventEmitter(); private readonly element: HTMLElement; private itemList: HTMLCollection; private highlightedElementId: number = 0; constructor(elemntRef: ElementRef) { this.element = elemntRef.nativeElement; } ngOnInit(): void { this.checkAttributesBeforeInit(); } ngAfterViewInit(): void { this.getLiElements(); this.initHighlightElement(); this.keyEventSubject.subscribe((keyboardEvent: KeyboardEvent) => { this.keypressHandler(keyboardEvent); }); } ngOnChanges(changes: SimpleChanges): void { const optionListChanges: SimpleChange = changes.optionList; if (statics.isDefined(optionListChanges) && !optionListChanges.firstChange && this.arrayLengthHasChanged(optionListChanges)) { this.onOptionListChange(); } } @HostListener('mousemove') onMousemove(): void { this.removeAllHighlights(); } private arrayLengthHasChanged(changedArraySimpleChange: SimpleChange): boolean { return changedArraySimpleChange.previousValue.length !== changedArraySimpleChange.currentValue.length; } private onOptionListChange(): void { setTimeout(() => { this.getLiElements(); if (this.itemList.length > 0) { const id: number = this.highlightedElementId < this.itemList.length ? this.highlightedElementId : this.itemList.length - 1; this.highlightItem(id); } }); } private keypressHandler(keyboardEvent: KeyboardEvent): void { switch (keyboardEvent.keyCode) { case fb.FasITDomain.KeyCode.enterKeyCode: this.selectOptionItem(); break; case fb.FasITDomain.KeyCode.upKeyCode: this.goPreviousOptionItem(); break; case fb.FasITDomain.KeyCode.downKeyCode: this.goNextOptionItem(); break; } } private getLiElements(): void { this.itemList = this.element.children; } private initHighlightElement(): void { if (this.itemList.length > 0) { this.highlightItem(0); } } private highlightItem(id: number): void { this.removeAllHighlights(); this.highlightedElementId = id; this.itemList[id].classList.add('fb-highlight'); } private removeAllHighlights(): void { /* tslint:disable */ for (let i: number = 0; i < this.itemList.length; i++) { this.itemList[i].classList.remove('fb-highlight'); } /* tslint:enable */ } private checkAttributesBeforeInit(): void { let errorString: string = ''; if (statics.isUndefined(this.keyEventSubject)) { errorString += 'Missing required parameter: keyEventSubject are required \n'; } if (statics.isUndefined(this.optionList)) { errorString += 'Missing required parameter: optionList are required \n'; } if (errorString !== '') { throw new Error(errorString); } } private selectOptionItem(): void { if (statics.isDefined(this.optionList[this.highlightedElementId])) { this.onItemSelect.emit(this.optionList[this.highlightedElementId]); } } private goNextOptionItem(): void { if (this.highlightedElementId < this.itemList.length - 1) { this.highlightItem(this.highlightedElementId + 1); } } private goPreviousOptionItem(): void { if (this.highlightedElementId > 0) { this.highlightItem(this.highlightedElementId - 1); } } }