diff options
author | Frederic Guillot <fred@kanboard.net> | 2016-12-11 15:46:54 -0500 |
---|---|---|
committer | Frederic Guillot <fred@kanboard.net> | 2016-12-11 15:46:54 -0500 |
commit | ffb392617895095b824a35150e620a68920f9260 (patch) | |
tree | 25bee1b1833e9f9bde608c38c3f46fb4e291c2b4 /assets/js/components | |
parent | a2b44371e050aca123e0e16c3458c7af2f11b48f (diff) |
Replace Chosen jQuery plugin by custom UI component
Diffstat (limited to 'assets/js/components')
-rw-r--r-- | assets/js/components/keyboard-shortcuts.js | 4 | ||||
-rw-r--r-- | assets/js/components/select-dropdown-autocomplete.js | 240 |
2 files changed, 244 insertions, 0 deletions
diff --git a/assets/js/components/keyboard-shortcuts.js b/assets/js/components/keyboard-shortcuts.js new file mode 100644 index 00000000..49524a76 --- /dev/null +++ b/assets/js/components/keyboard-shortcuts.js @@ -0,0 +1,4 @@ +// Open board selector: "b" +KB.onKey(98, function () { + KB.trigger('board.selector.open'); +}); diff --git a/assets/js/components/select-dropdown-autocomplete.js b/assets/js/components/select-dropdown-autocomplete.js new file mode 100644 index 00000000..565be21d --- /dev/null +++ b/assets/js/components/select-dropdown-autocomplete.js @@ -0,0 +1,240 @@ +KB.component('select-dropdown-autocomplete', function(containerElement, options) { + var componentElement, inputElement, inputHiddenElement; + + function onKeyDown(e) { + switch (e.keyCode) { + case 27: + inputElement.value = ''; + destroyDropdownMenu(); + break; + case 38: + e.preventDefault(); + e.stopImmediatePropagation(); + moveUp(); + break; + case 40: + e.preventDefault(); + e.stopImmediatePropagation(); + moveDown(); + break; + case 13: + 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) { + var regex = new RegExp(options.redirect.regex, 'g'); + window.location = options.redirect.url.replace(regex, 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 = []; + var keys = Object.keys(items); + + if (options.sortByKeys) { + keys.sort(); + } + + for (var i = 0; i < keys.length; i++) { + elements.push({ + 'class': 'select-dropdown-menu-item', + 'text': items[keys[i]], + 'data-label': items[keys[i]], + 'data-value': keys[i] + }); + } + + 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()) === 0) { + 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(); + + if (itemElements.length === 0) { + return null; + } + + return KB.dom('ul') + .attr('id', 'select-dropdown-menu') + .style('top', componentPosition.bottom + 'px') + .style('left', componentPosition.left + 'px') + .style('width', componentPosition.width + '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 ''; + } + + this.render = function () { + var dropdownIconElement = KB.dom('i') + .attr('class', 'fa fa-chevron-down select-dropdown-chevron') + .click(toggleDropdownMenu) + .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()) + .addClass('select-dropdown-input') + .style('width', (containerElement.offsetWidth - 30) + 'px') + .on('focus', toggleDropdownMenu) + .on('input', onInputChanged, true) + .build(); + + componentElement = KB.dom('div') + .addClass('select-dropdown-input-container') + .add(inputHiddenElement) + .add(inputElement) + .add(dropdownIconElement) + .build(); + + containerElement.appendChild(componentElement); + + if (options.onFocus) { + options.onFocus.forEach(function (eventName) { + KB.on(eventName, function() { inputElement.focus(); }); + }); + } + }; +}); |