|
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); |
|
}; |
|
}); |
|
|