kb / assets /js /components /select-dropdown-autocomplete.js
Xv Zan
ULFS
e4f4821
raw
history blame
9.29 kB
KB.component('select-dropdown-autocomplete', function(containerElement, options) {
var componentElement, inputElement, inputHiddenElement, chevronIconElement, loadingIconElement;
function onLoadingStart() {
KB.dom(loadingIconElement).show();
KB.dom(chevronIconElement).hide();
}
function onLoadingStop() {
KB.dom(loadingIconElement).hide();
KB.dom(chevronIconElement).show();
}
function onScroll() {
var menuElement = KB.find('#select-dropdown-menu');
if (menuElement) {
var componentPosition = componentElement.getBoundingClientRect();
menuElement.style('top', (document.body.scrollTop + componentPosition.bottom) + 'px');
}
}
function onKeyDown(e) {
switch (KB.utils.getKey(e)) {
case 'Escape':
inputElement.value = '';
destroyDropdownMenu();
break;
case 'ArrowUp':
e.preventDefault();
e.stopImmediatePropagation();
moveUp();
break;
case 'ArrowDown':
e.preventDefault();
e.stopImmediatePropagation();
moveDown();
break;
case 'Enter':
e.preventDefault();
e.stopImmediatePropagation();
insertSelectedItem();
break;
}
}
function onInputChanged() {
destroyDropdownMenu();
renderDropdownMenu();
}
function onItemMouseOver(element) {
if (KB.dom(element).hasClass('select-dropdown-menu-item')) {
KB.find('.select-dropdown-menu-item.active').removeClass('active');
KB.dom(element).addClass('active');
}
}
function onItemClick() {
insertSelectedItem();
}
function onDocumentClick(e) {
if (! containerElement.contains(e.target)) {
inputElement.value = '';
destroyDropdownMenu();
}
}
function toggleDropdownMenu() {
var menuElement = KB.find('#select-dropdown-menu');
if (menuElement === null) {
renderDropdownMenu();
} else {
destroyDropdownMenu();
}
}
function insertSelectedItem() {
var element = KB.find('.select-dropdown-menu-item.active');
var value = element.data('value');
inputHiddenElement.value = value;
inputElement.value = options.items[value];
destroyDropdownMenu();
if (options.redirect) {
window.location = options.redirect.url.replace(new RegExp(options.redirect.regex, 'g'), value);
} else if (options.replace) {
onLoadingStart();
KB.modal.replace(options.replace.url.replace(new RegExp(options.replace.regex, 'g'), value));
}
}
function resetSelection() {
var elements = document.querySelectorAll('.select-dropdown-menu-item');
for (var i = 0; i < elements.length; i++) {
if (KB.dom(elements[i]).hasClass('active')) {
KB.dom(elements[i]).removeClass('active');
break;
}
}
return {items: elements, index: i};
}
function moveUp() {
var result = resetSelection();
if (result.index > 0) {
result.index = result.index - 1;
}
KB.dom(result.items[result.index]).addClass('active');
}
function moveDown() {
var result = resetSelection();
if (result.index < result.items.length - 1) {
result.index++;
}
KB.dom(result.items[result.index]).addClass('active');
}
function buildItems(items) {
var elements = [];
for (var key in items) {
if (items.hasOwnProperty(key)) {
elements.push({
'class': 'select-dropdown-menu-item',
'text': items[key],
'data-label': items[key],
'data-value': key
});
}
}
if (options.sortByKeys) {
elements.sort(function (a, b) {
var value1 = a['data-value'].toLowerCase();
var value2 = b['data-value'].toLowerCase();
return value1 < value2 ? -1 : (value1 > value2 ? 1 : 0);
});
} else {
elements.sort(function (a, b) {
var value1 = a['data-label'].toLowerCase();
var value2 = b['data-label'].toLowerCase();
return value1 < value2 ? -1 : (value1 > value2 ? 1 : 0);
});
}
return elements;
}
function filterItems(text, items) {
var filteredItems = [];
var hasActiveItem = false;
for (var i = 0; i < items.length; i++) {
if (text.length === 0 || items[i]['data-label'].toLowerCase().indexOf(text.toLowerCase()) > -1) {
var item = items[i];
if (typeof options.defaultValue !== 'undefined' && String(options.defaultValue) === item['data-value']) {
item.class += ' active';
hasActiveItem = true;
}
filteredItems.push(item);
}
}
if (! hasActiveItem && filteredItems.length > 0) {
filteredItems[0].class += ' active';
}
return filteredItems;
}
function buildDropdownMenu() {
var itemElements = filterItems(inputElement.value, buildItems(options.items));
var componentPosition = componentElement.getBoundingClientRect();
var windowPosition = document.body.scrollTop || document.documentElement.scrollTop;
if (itemElements.length === 0) {
return null;
}
return KB.dom('ul')
.attr('id', 'select-dropdown-menu')
.style('top', (windowPosition + componentPosition.bottom) + 'px')
.style('left', componentPosition.left + 'px')
.style('width', componentPosition.width + 'px')
.style('maxHeight', (window.innerHeight - componentPosition.bottom - 20) + 'px')
.mouseover(onItemMouseOver)
.click(onItemClick)
.for('li', itemElements)
.build();
}
function destroyDropdownMenu() {
var menuElement = KB.find('#select-dropdown-menu');
if (menuElement !== null) {
menuElement.remove();
}
document.removeEventListener('keydown', onKeyDown, false);
document.removeEventListener('click', onDocumentClick, false);
}
function renderDropdownMenu() {
var element = buildDropdownMenu();
if (element !== null) {
document.body.appendChild(element);
}
document.addEventListener('keydown', onKeyDown, false);
document.addEventListener('click', onDocumentClick, false);
}
function getPlaceholderValue() {
if (options.defaultValue && options.defaultValue in options.items) {
return options.items[options.defaultValue];
}
if (options.placeholder) {
return options.placeholder;
}
return '';
}
function getAriaLabelValue() {
if (options.ariaLabel) {
return options.ariaLabel;
}
return '';
}
this.render = function () {
KB.on('select.dropdown.loading.start', onLoadingStart);
KB.on('select.dropdown.loading.stop', onLoadingStop);
KB.on('modal.close', function () {
KB.removeListener('select.dropdown.loading.start', onLoadingStart);
KB.removeListener('select.dropdown.loading.stop', onLoadingStop);
});
chevronIconElement = KB.dom('i')
.attr('class', 'fa fa-chevron-down select-dropdown-chevron')
.click(toggleDropdownMenu)
.build();
loadingIconElement = KB.dom('span')
.hide()
.addClass('select-loading-icon')
.add(KB.dom('i').attr('class', 'fa fa-spinner fa-pulse').build())
.build();
inputHiddenElement = KB.dom('input')
.attr('type', 'hidden')
.attr('name', options.name)
.attr('value', options.defaultValue || '')
.build();
inputElement = KB.dom('input')
.attr('type', 'text')
.attr('placeholder', getPlaceholderValue())
.attr('aria-label', getAriaLabelValue())
.addClass('select-dropdown-input')
.on('focus', toggleDropdownMenu)
.on('input', onInputChanged, true)
.build();
componentElement = KB.dom('div')
.addClass('select-dropdown-input-container')
.add(inputHiddenElement)
.add(inputElement)
.add(chevronIconElement)
.add(loadingIconElement)
.build();
containerElement.appendChild(componentElement);
if (options.onFocus) {
options.onFocus.forEach(function (eventName) {
KB.on(eventName, function() { inputElement.focus(); });
});
}
window.addEventListener('scroll', onScroll, false);
};
});