import {module} from '../module'; import './style.scss'; export default class DropDown { constructor($element, $filter, $timeout) { this.$element = $element; this.$filter = $filter; this.$timeout = $timeout; this.parent = this.parent || $element[0].parentNode; this._search = null; this.itemsFiltered = []; this._activeOption = -1; this._focusingFilter = false; } get show() { return this._show; } set show(value) { let oldValue = this.show; this._show = value; if (value && !this._focusingFilter && oldValue !== value && this.filter) { let inputFilterSearch = this.$element[0].querySelector('input'); this._focusingFilter = true; this.$timeout(() => { inputFilterSearch.focus(); this._focusingFilter = false; }, 250); } } get search() { return this._search; } set search(value) { let val = (value === undefined || value === '') ? null : value; this._search = val; if (this.filterAction) this.onFilterRest(); else this.filterItems(); } get activeOption() { return this._activeOption; } set activeOption(value) { if (value < 0) { value = 0; } else if (value >= this.items.length) { value = this.showLoadMore ? this.items.length : this.items.length - 1; } this.$timeout(() => { this._activeOption = value; // AutoLoad items with "scroll" (1st version): if (value && value >= this.items.length - 3 && !this.removeLoadMore) { this.loadItems(); } }); } filterItems() { this.itemsFiltered = this.search ? this.$filter('filter')(this.items, this.search) : this.items; } onFilterRest() { if (this.filterAction) { this.filterAction({search: this.search}); } } $onChanges(changesObj) { if (changesObj.show && changesObj.top && changesObj.top.currentValue) { this.$element.css('top', changesObj.top.currentValue + 'px'); } if (changesObj.show && changesObj.itemWidth && changesObj.itemWidth.currentValue) { this.$element.css('width', changesObj.itemWidth.currentValue + 'px'); } if (changesObj.items) { this.filterItems(); } } clearSearch() { this.search = null; } selectOption() { if (this.activeOption >= 0 && this.activeOption < this.items.length && this.items[this.activeOption]) { this.selected = this.items[this.activeOption]; this.show = false; this.clearSearch(); } else if (this.showLoadMore && this.activeOption === this.items.length) { this.loadMore(); } } onKeydown(event) { if (this.show) { switch (event.keyCode) { case 13: // Enter this.$timeout(() => { this.selectOption(); }); event.preventDefault(); break; case 27: // Escape this.clearSearch(); break; case 38: // Arrow up this.activeOption--; this.$timeout(() => { this.setScrollPosition(); }, 100); break; case 40: // Arrow down this.activeOption++; this.$timeout(() => { this.setScrollPosition(); }, 100); break; default: return; } } } setScrollPosition() { let dropdown = this.$element[0].querySelector('ul.dropdown'); let child = dropdown ? dropdown.childNodes[this.activeOption] : null; if (child && typeof child.scrollIntoView === 'function') { child.scrollIntoView(); } } selectItem(item) { this.selected = item; if (this.multiple) { item.checked = !item.checked; this.show = true; } else { this.show = false; } } loadItems() { if (this.showLoadMore && this.loadMore) { this.loadMore(); } this.show = true; } $onInit() { if (this.parent) this.parent.addEventListener('keydown', e => this.onKeydown(e)); } $onDestroy() { if (this.parent) this.parent.removeEventListener('keydown', e => this.onKeydown(e)); } } DropDown.$inject = ['$element', '$filter', '$timeout']; module.component('vnDropDown', { template: require('./drop-down.html'), controller: DropDown, bindings: { items: '<', show: '<', filter: '@?', selected: '=', search: '=?', loadMore: '&?', removeLoadMore: '