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