UNPKG

igniteui-angular-sovn

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

307 lines (275 loc) 8.23 kB
import { Input, HostBinding, ElementRef, QueryList, Output, EventEmitter, ChangeDetectorRef, Optional, Inject, Directive } from '@angular/core'; import { Navigate, ISelectionEventArgs } from './drop-down.common'; import { IDropDownList } from './drop-down.common'; import { DropDownActionKey } from './drop-down.common'; import { IgxDropDownItemBaseDirective } from './drop-down-item.base'; import { DisplayDensityBase, DisplayDensityToken, IDisplayDensityOptions } from '../core/density'; let NEXT_ID = 0; /** * An abstract class, defining a drop-down component, with: * Properties for display styles and classes * A collection items of type `IgxDropDownItemBaseDirective` * Properties and methods for navigating (highlighting/focusing) items from the collection * Properties and methods for selecting items from the collection */ @Directive() export abstract class IgxDropDownBaseDirective extends DisplayDensityBase implements IDropDownList { /** * Emitted when item selection is changing, before the selection completes * * ```html * <igx-drop-down (selectionChanging)='handleSelection()'></igx-drop-down> * ``` */ @Output() public selectionChanging = new EventEmitter<ISelectionEventArgs>(); /** * Gets/Sets the width of the drop down * * ```typescript * // get * let myDropDownCurrentWidth = this.dropdown.width; * ``` * ```html * <!--set--> * <igx-drop-down [width]='160px'></igx-drop-down> * ``` */ @Input() public width: string; /** * Gets/Sets the height of the drop down * * ```typescript * // get * let myDropDownCurrentHeight = this.dropdown.height; * ``` * ```html * <!--set--> * <igx-drop-down [height]='400px'></igx-drop-down> * ``` */ @Input() public height: string; /** * Gets/Sets the drop down's id * * ```typescript * // get * let myDropDownCurrentId = this.dropdown.id; * ``` * ```html * <!--set--> * <igx-drop-down [id]='newDropDownId'></igx-drop-down> * ``` */ @Input() public get id(): string { return this._id; } public set id(value: string) { this._id = value; } /** * Gets/Sets the drop down's container max height. * * ```typescript * // get * let maxHeight = this.dropdown.maxHeight; * ``` * ```html * <!--set--> * <igx-drop-down [maxHeight]='200px'></igx-drop-down> * ``` */ @Input() @HostBinding('style.maxHeight') public maxHeight = null; /** * @hidden @internal */ @HostBinding('class.igx-drop-down') public cssClass = true; /** * Get all non-header items * * ```typescript * let myDropDownItems = this.dropdown.items; * ``` */ public get items(): IgxDropDownItemBaseDirective[] { const items: IgxDropDownItemBaseDirective[] = []; if (this.children !== undefined) { for (const child of this.children.toArray()) { if (!child.isHeader) { items.push(child); } } } return items; } /** * Get all header items * * ```typescript * let myDropDownHeaderItems = this.dropdown.headers; * ``` */ public get headers(): IgxDropDownItemBaseDirective[] { const headers: IgxDropDownItemBaseDirective[] = []; if (this.children !== undefined) { for (const child of this.children.toArray()) { if (child.isHeader) { headers.push(child); } } } return headers; } /** * Get dropdown html element * * ```typescript * let myDropDownElement = this.dropdown.element; * ``` */ public get element() { return this.elementRef.nativeElement; } /** * @hidden @internal * Get dropdown's html element of its scroll container */ public get scrollContainer(): HTMLElement { return this.element; } /** * @hidden * @internal */ public children: QueryList<IgxDropDownItemBaseDirective>; protected _width; protected _height; protected _focusedItem: any = null; protected _id = `igx-drop-down-${NEXT_ID++}`; /** * Gets if the dropdown is collapsed */ public abstract readonly collapsed: boolean; constructor( protected elementRef: ElementRef, protected cdr: ChangeDetectorRef, @Optional() @Inject(DisplayDensityToken) protected _displayDensityOptions: IDisplayDensityOptions) { super(_displayDensityOptions); } /** Keydown Handler */ public onItemActionKey(key: DropDownActionKey, event?: Event) { switch (key) { case DropDownActionKey.ENTER: case DropDownActionKey.SPACE: this.selectItem(this.focusedItem, event); break; case DropDownActionKey.ESCAPE: } } /** * Emits selectionChanging with the target item & event * * @hidden @internal * @param newSelection the item selected * @param event the event that triggered the call */ public selectItem(newSelection?: IgxDropDownItemBaseDirective, event?: Event) { // eslint-disable-line this.selectionChanging.emit({ newSelection, oldSelection: null, cancel: false }); } /** * @hidden @internal */ public get focusedItem(): IgxDropDownItemBaseDirective { return this._focusedItem; } /** * @hidden @internal */ public set focusedItem(item: IgxDropDownItemBaseDirective) { this._focusedItem = item; } /** * Navigates to the item on the specified index * * @param newIndex number - the index of the item in the `items` collection */ public navigateItem(newIndex: number) { if (newIndex !== -1) { const oldItem = this._focusedItem; const newItem = this.items[newIndex]; if (oldItem) { oldItem.focused = false; } this.focusedItem = newItem; this.scrollToHiddenItem(newItem); this.focusedItem.focused = true; } } /** * @hidden @internal */ public navigateFirst() { this.navigate(Navigate.Down, -1); } /** * @hidden @internal */ public navigateLast() { this.navigate(Navigate.Up, this.items.length); } /** * @hidden @internal */ public navigateNext() { this.navigate(Navigate.Down); } /** * @hidden @internal */ public navigatePrev() { this.navigate(Navigate.Up); } protected scrollToHiddenItem(newItem: IgxDropDownItemBaseDirective) { const elementRect = newItem.element.nativeElement.getBoundingClientRect(); const parentRect = this.scrollContainer.getBoundingClientRect(); if (parentRect.top > elementRect.top) { this.scrollContainer.scrollTop -= (parentRect.top - elementRect.top); } if (parentRect.bottom < elementRect.bottom) { this.scrollContainer.scrollTop += (elementRect.bottom - parentRect.bottom); } } protected navigate(direction: Navigate, currentIndex?: number) { let index = -1; if (this._focusedItem) { index = currentIndex ? currentIndex : this.focusedItem.itemIndex; } const newIndex = this.getNearestSiblingFocusableItemIndex(index, direction); this.navigateItem(newIndex); } protected getNearestSiblingFocusableItemIndex(startIndex: number, direction: Navigate): number { let index = startIndex; const items = this.items; while (items[index + direction] && items[index + direction].disabled) { index += direction; } index += direction; if (index >= 0 && index < items.length) { return index; } else { return -1; } } }