salix/client/core/src/drop-down/drop-down.js

288 lines
9.0 KiB
JavaScript
Raw Normal View History

import {module} from '../module';
import './style.scss';
import validKey from '../lib/keyCodes';
export default class DropDown {
2017-09-14 11:40:55 +00:00
constructor($element, $filter, $timeout) {
this.$element = $element;
this.$filter = $filter;
2017-09-14 11:40:55 +00:00
this.$timeout = $timeout;
this._search = null;
this.itemsFiltered = [];
2017-09-14 11:40:55 +00:00
this._activeOption = -1;
2017-09-27 10:27:18 +00:00
this._focusingFilter = false;
this._tryToShow = 0;
2017-09-14 11:40:55 +00:00
}
get container() {
return this.$element[0].querySelector('ul.dropdown');
}
get show() {
return this._show;
}
set show(value) {
let oldValue = this.show;
2017-12-12 13:14:32 +00:00
// It wait up to 1 second if the dropdown opens but there is no data to show
if (value && !oldValue && !this.itemsFiltered.length && this._tryToShow < 4) {
this.$timeout(() => {
this._tryToShow++;
this.show = true;
if (this.activeOption === -1) {
this.activeOption = 0;
}
}, 250);
} else {
this._tryToShow = 0;
this._show = value;
this._toggleDropDown(value, oldValue);
}
}
2017-09-14 11:40:55 +00:00
get search() {
return this._search;
}
2017-09-14 11:40:55 +00:00
set search(value) {
let val = (value === undefined || value === '') ? null : value;
2017-09-14 11:40:55 +00:00
this._search = val;
if (this.filterAction)
this.onFilterRest();
else
this.filterItems();
}
2017-09-14 11:40:55 +00:00
get activeOption() {
return this._activeOption;
}
2017-09-14 11:40:55 +00:00
set activeOption(value) {
if (value < 0) {
value = 0;
2017-11-22 12:10:33 +00:00
} else if (value >= this.itemsFiltered.length) {
value = this.showLoadMore ? this.itemsFiltered.length : this.itemsFiltered.length - 1;
2017-09-14 11:40:55 +00:00
}
this.$timeout(() => {
this._activeOption = value;
2017-11-22 12:10:33 +00:00
if (value && value >= this.itemsFiltered.length - 3 && !this.removeLoadMore) {
this.loadItems();
}
2017-09-14 11:40:55 +00:00
});
}
_toggleDropDown(value, oldValue) {
this.$timeout(() => {
this._eventScroll(value);
this._calculatePosition(value, oldValue);
});
}
_eventScroll(add, num) {
let count = num || 0;
if (add) {
if (this.container) {
this.container.addEventListener('scroll', e => this.loadFromScroll(e));
// this.$timeout(() => { // falla al entrar por primera vez xq pierde el foco y cierra el dropdown
// this._setFocusInFilterInput();
// });
} else if (count < 4) {
count++;
this.$timeout(() => { // wait angular ngIf
this._eventScroll(add, count);
}, 250);
}
} else if (this.container) {
this.container.removeEventListener('scroll', e => this.loadFromScroll(e));
2017-11-22 12:10:33 +00:00
}
}
2017-12-12 13:14:32 +00:00
_setFocusInFilterInput() {
let inputFilterSearch = this.$element[0].querySelector('input');
this._focusingFilter = true;
if (inputFilterSearch)
this.$timeout(() => {
inputFilterSearch.focus();
this._focusingFilter = false;
}, 250);
}
_background(create) {
let el = document.getElementById('ddBack');
if (el) {
el.parentNode.removeChild(el);
}
if (create) {
el = document.createElement('div');
el.id = 'ddBack';
document.body.appendChild(el);
}
}
2017-11-22 12:10:33 +00:00
_calculatePosition(value, oldValue) {
if (value && !oldValue) {
2017-11-22 12:10:33 +00:00
if (this.parent === undefined) {
this.parent = this.$element.parent().parent();
}
let parentRect = this.parent.getBoundingClientRect();
let elemetRect = this.$element[0].getBoundingClientRect();
let instOffset = parentRect.bottom + elemetRect.height;
2017-11-22 12:10:33 +00:00
if (instOffset >= window.innerHeight) {
this._background(true);
this.$element.addClass('fixed-dropDown');
this.$element.css('top', `${(parentRect.top - elemetRect.height)}px`);
this.$element.css('left', `${(parentRect.x)}px`);
this.$element.css('height', `${elemetRect.height}px`);
}
} else if (!value && oldValue) {
this.$element.removeAttr('style');
if (this.itemWidth) {
this.$element.css('width', this.itemWidth + 'px');
2017-11-22 12:10:33 +00:00
}
this.$element.removeClass('fixed-dropDown');
this._background();
2017-11-22 12:10:33 +00:00
}
}
filterItems() {
this.itemsFiltered = this.search ? this.$filter('filter')(this.items, this.search) : this.items;
2017-06-29 06:13:30 +00:00
}
onFilterRest() {
if (this.filterAction) {
this.filterAction({search: this.search});
}
2017-06-29 06:13:30 +00:00
}
clearSearch() {
2017-09-14 11:40:55 +00:00
this.search = null;
}
selectOption() {
2017-09-20 09:50:53 +00:00
if (this.activeOption >= 0 && this.activeOption < this.items.length && this.items[this.activeOption]) {
2017-09-14 11:40:55 +00:00
this.selected = this.items[this.activeOption];
2017-09-20 09:50:53 +00:00
this.show = false;
2017-09-14 11:40:55 +00:00
this.clearSearch();
2017-09-20 09:50:53 +00:00
} else if (this.showLoadMore && this.activeOption === this.items.length) {
this.loadMore();
}
}
2017-09-14 11:40:55 +00:00
onKeydown(event) {
if (this.show) {
if (event.keyCode === 13) { // Enter
2017-09-14 11:40:55 +00:00
this.$timeout(() => {
this.selectOption();
});
event.preventDefault();
} else if (event.keyCode === 27) { // Escape
2017-09-14 11:40:55 +00:00
this.clearSearch();
} else if (event.keyCode === 38) { // Arrow up
2017-09-14 11:40:55 +00:00
this.activeOption--;
2017-09-20 09:50:53 +00:00
this.$timeout(() => {
this.setScrollPosition();
}, 100);
} else if (event.keyCode === 40) { // Arrow down
2017-09-14 11:40:55 +00:00
this.activeOption++;
2017-09-20 09:50:53 +00:00
this.$timeout(() => {
this.setScrollPosition();
}, 100);
} else if (event.keyCode === 35) { // End
2017-11-22 12:10:33 +00:00
this.activeOption = this.itemsFiltered.length - 1;
this.$timeout(() => {
this.setScrollPosition();
}, 100);
} else if (event.keyCode === 36) { // Start
2017-11-22 12:10:33 +00:00
this.activeOption = 0;
this.$timeout(() => {
this.setScrollPosition();
}, 100);
} else if (this.filter) {
let oldValue = this.search || '';
if (validKey(event)) {
this.search = oldValue + String.fromCharCode(event.keyCode);
} else if (event.keyCode === 8) { // backSpace
this.search = oldValue.slice(0, -1);
}
} /* else {
console.error(`Error: keyCode ${event.keyCode} not supported`);
} */
2017-09-14 11:40:55 +00:00
}
}
2017-09-20 09:50:53 +00:00
setScrollPosition() {
2017-11-22 12:10:33 +00:00
let child = this.$element[0].querySelector('ul.dropdown li.active');
if (child) {
let childRect = child.getBoundingClientRect();
let containerRect = this.container.getBoundingClientRect();
if (typeof child.scrollIntoView === 'function' && (childRect.top > containerRect.top + containerRect.height || childRect.top < containerRect.top)) {
child.scrollIntoView();
}
2017-09-20 09:50:53 +00:00
}
}
2017-09-20 11:52:53 +00:00
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;
}
2017-11-22 12:10:33 +00:00
loadFromScroll(e) {
let containerRect = e.target.getBoundingClientRect();
if (e.target.scrollHeight - e.target.scrollTop - containerRect.height <= 50) {
this.loadItems();
}
}
$onChanges(changesObj) {
if (changesObj.show && changesObj.itemWidth && changesObj.itemWidth.currentValue) {
this.$element.css('width', changesObj.itemWidth.currentValue + 'px');
}
if (changesObj.items) {
this.filterItems();
}
}
2017-09-14 11:40:55 +00:00
$onInit() {
if (this.parent)
this.parent.addEventListener('keydown', e => this.onKeydown(e));
}
$onDestroy() {
if (this.parent)
this.parent.removeEventListener('keydown', e => this.onKeydown(e));
}
}
2017-09-14 11:40:55 +00:00
DropDown.$inject = ['$element', '$filter', '$timeout'];
module.component('vnDropDown', {
template: require('./drop-down.html'),
controller: DropDown,
bindings: {
items: '<',
show: '<',
2017-06-21 11:16:37 +00:00
filter: '@?',
selected: '=',
2017-09-14 11:40:55 +00:00
search: '=?',
2017-06-29 06:13:30 +00:00
loadMore: '&?',
removeLoadMore: '<?',
filterAction: '&?',
2017-10-10 09:14:35 +00:00
showLoadMore: '<?',
2017-09-14 11:40:55 +00:00
itemWidth: '<?',
2017-09-20 11:52:53 +00:00
parent: '<?',
multiple: '<?'
2017-09-20 09:50:53 +00:00
},
transclude: {
vnItem: '?vnItem'
2017-06-21 11:16:37 +00:00
}
});