assets/js/romo/select_dropdown.js in romo-0.17.0 vs assets/js/romo/select_dropdown.js in romo-0.17.1

- old
+ new

@@ -3,18 +3,21 @@ return new RomoSelectDropdown(element, optionElemsParent); }); } var RomoSelectDropdown = function(element, optionElemsParent) { - this.elem = $(element); - this.itemSelector = 'LI[data-romo-select-item="opt"]:not(.disabled)'; - this.prevValue = ''; + this.elem = $(element); + this.prevValue = ''; - var optsParent = (optionElemsParent || this.elem.find('.romo-select-dropdown-options-parent')); - this.optionElems = optsParent.children(); - this.optionList = this._buildOptionList(this.optionElems); + this.filterHiddenClass = 'romo-select-filter-hidden'; + this.itemSelector = 'LI[data-romo-select-item="opt"]:not(.disabled):not(.'+this.filterHiddenClass+')'; + var optsParent = (optionElemsParent || this.elem.find('.romo-select-dropdown-options-parent')); + this.optionElems = optsParent.children(); + this.optionList = this._buildOptionList(this.optionElems); + this.optionFilter = undefined; + this.doInit(); this.doBindDropdown(); if (this.elem.attr('id') !== undefined) { $('label[for="'+this.elem.attr('id')+'"]').on('click', $.proxy(function(e) { @@ -42,19 +45,14 @@ RomoSelectDropdown.prototype.doBindDropdown = function() { this.romoDropdown = this.elem.romoDropdown()[0]; this.romoDropdown.doSetPopupZIndex(this.elem); this.romoDropdown.bodyElem.addClass('romo-select-option-list'); + this.romoDropdown.elem.on('dropdown:popupOpen', $.proxy(this.onPopupOpen, this)); this.romoDropdown.elem.on('dropdown:popupClose', $.proxy(this.onPopupClose, this)); - this.romoDropdown.elem.on('blur', $.proxy(function(e) { - this.blurTimeoutId = setTimeout($.proxy(function() { - if (this.popupMouseDown !== true) { - this.romoDropdown.elem.trigger('dropdown:triggerPopupClose', []); - } - }, this), 10); - }, this)); + this.romoDropdown.elem.on('keydown', $.proxy(this.onElemKeyDown, this)); this.romoDropdown.popupElem.on('keydown', $.proxy(this.onElemKeyDown, this)); this.romoDropdown.elem.on('dropdown:toggle', $.proxy(function(e, dropdown) { this.elem.trigger('selectDropdown:dropdown:toggle', [dropdown, this]); @@ -75,29 +73,138 @@ this.elem.on('selectDropdown:triggerPopupClose', $.proxy(function(e) { this.romoDropdown.elem.trigger('dropdown:triggerPopupClose', []); }, this)); this.romoDropdown.bodyElem.html(''); + + if (this.elem.data('romo-select-dropdown-no-filter') !== true) { + this.optionFilter = this._buildOptionFilter(); + var optionFilterWrapper = $('<div class="romo-select-dropdown-option-filter-wrapper"></div>'); + optionFilterWrapper.append(this.optionFilter); + this.romoDropdown.popupElem.prepend(optionFilterWrapper); + this.doBindDropdownOptionFilter(); + } + this.romoDropdown.bodyElem.append(this.optionList); this.romoDropdown.bodyElem.find(this.itemSelector).on('mouseenter', $.proxy(this.onItemEnter, this)); this.romoDropdown.bodyElem.find(this.itemSelector).on('click', $.proxy(this.onItemClick, this)); this.romoDropdown.popupElem.on('mousedown', $.proxy(this.onPopupMouseDown, this)); this.romoDropdown.popupElem.on('mouseup', $.proxy(this.onPopupMouseUp, this)); } +RomoSelectDropdown.prototype.doBindDropdownOptionFilter = function() { + this.optionFilter.romoIndicatorTextInput(); + this.optionFilter.romoOnkey(); + + this.romoDropdown.elem.on('focus', $.proxy(function(e) { + if (this.blurTimeoutId !== undefined) { + clearTimeout(this.blurTimeoutId); + } + // remove any manual elem focus when elem is actually focused + this.optionFilterFocused = false; + this.romoDropdown.elem.removeClass('romo-select-focus'); + }, this)); + this.romoDropdown.elem.on('blur', $.proxy(function(e) { + if (this.blurTimeoutId !== undefined) { + clearTimeout(this.blurTimeoutId); + } + // close the dropdown when elem is blurred + // remove any manual focus as well + this.romoDropdown.elem.removeClass('romo-select-focus'); + this.blurTimeoutId = setTimeout($.proxy(function() { + if (this.popupMouseDown !== true && this.optionFilterFocused !== true) { + this.romoDropdown.elem.trigger('dropdown:triggerPopupClose', []); + } + }, this), 10); + }, this)); + this.optionFilter.on('focus', $.proxy(function(e) { + if (this.blurTimeoutId !== undefined) { + clearTimeout(this.blurTimeoutId); + } + // manually make the elem focused when its filter is focused + this.optionFilterFocused = true; + this.romoDropdown.elem.addClass('romo-select-focus'); + }, this)); + this.optionFilter.on('blur', $.proxy(function(e) { + // remove any manual elem focus when its filter is blurred + this.optionFilterFocused = false; + this.romoDropdown.elem.removeClass('romo-select-focus'); + }, this)); + + this.romoDropdown.elem.on('dropdown:popupOpen', $.proxy(function(e, dropdown) { + this.optionFilter.trigger('indicatorTextInput:triggerPlaceIndicator'); + this.optionFilter.focus(); + this.doFilterOptionElems(); + }, this)); + this.romoDropdown.elem.on('dropdown:popupClose', $.proxy(function(e, dropdown) { + this.optionFilter.val(''); + }, this)); + this.romoDropdown.elem.on('dropdown:popupClosedByEsc', $.proxy(function(e, dropdown) { + this.romoDropdown.elem.focus(); + }, this)); + this.optionFilter.on('click', $.proxy(function(e) { + if (e !== undefined) { + e.stopPropagation(); + } + }, this)); + this.romoDropdown.popupElem.on('click', $.proxy(function(e) { + this.optionFilter.focus(); + }, this)); + + this.onkeySearchTimeout = undefined; + this.onkeySearchDelay = 100; // 0.1 secs, want it to be really responsive + + this.optionFilter.on('onkey:trigger', $.proxy(function(e, triggerEvent, onkey) { + // TODO: incorp this timeout logic into the onkey component so don't have to repeat it + clearTimeout(this.onkeySearchTimeout); + this.onkeySearchTimeout = setTimeout($.proxy(function() { + if (Romo.nonInputTextKeyCodes().indexOf(triggerEvent.keyCode) === -1 /* Input Text */) { + this.doFilterOptionElems(); + } + }, this), this.onkeySearchDelay); + }, this)); +} + +RomoSelectDropdown.prototype.doFilterOptionElems = function() { + var wbFilter = new RomoWordBoundaryFilter( + this.optionFilter.val(), + this.romoDropdown.bodyElem.find('LI[data-romo-select-item="opt"]'), + function(elem) { + return elem[0].textContent; + } + ); + + wbFilter.matchingElems.show(); + wbFilter.notMatchingElems.hide(); + wbFilter.matchingElems.removeClass(this.filterHiddenClass); + wbFilter.notMatchingElems.addClass(this.filterHiddenClass); + + this.romoDropdown.doPlacePopupElem(); + if (this.optionFilter.val() !== '') { + this._highlightItem(wbFilter.matchingElems.first()); + this._scrollTopToItem(wbFilter.matchingElems.first()); + } else { + this._highlightItem(this.selectedListing()); + this._scrollTopToItem(this.selectedListing()); + } +} + RomoSelectDropdown.prototype.doSelectHighlightedItem = function() { - var prevValue = this.prevValue; - var newValue = this.romoDropdown.bodyElem.find('LI.romo-select-highlight').data('romo-select-option-value'); + var curr = this._getHighlightedItem(); + if (curr.length !== 0) { + var prevValue = this.prevValue; + var newValue = curr.data('romo-select-option-value'); - this.romoDropdown.doPopupClose(); - this.elem.trigger('selectDropdown:itemSelected', [newValue, prevValue, this]); + this.romoDropdown.doPopupClose(); + this.elem.trigger('selectDropdown:itemSelected', [newValue, prevValue, this]); - if (newValue !== prevValue) { - this.doSetNewValue(newValue); - this.elem.trigger('selectDropdown:change', [newValue, prevValue, this]); + if (newValue !== prevValue) { + this.doSetNewValue(newValue); + this.elem.trigger('selectDropdown:change', [newValue, prevValue, this]); + } } } RomoSelectDropdown.prototype.onPopupOpen = function(e) { if (this.elem.hasClass('disabled') === false) { @@ -170,21 +277,34 @@ return false; } else if (e.keyCode === 13 /* Enter */ ) { this.doSelectHighlightedItem(); return false; + } else if (e.keyCode === 9 /* Tab */ ) { + e.preventDefault(); + return false; } else { return true; } } RomoSelectDropdown.prototype.onElemKeyDown = function(e) { if (this.elem.hasClass('disabled') === false) { if (this.romoDropdown.popupElem.hasClass('romo-dropdown-open') === false) { - if(e.keyCode === 40 /* Down */ ) { + if (e.keyCode === 40 /* Down */ || e.keyCode === 38 /* Up */) { this.romoDropdown.doPopupOpen(); return false; + } else if (this.optionFilter !== undefined && + Romo.nonInputTextKeyCodes().indexOf(e.keyCode) === -1 /* Input Text */) { + if (e.metaKey === false) { + // don't prevent default on Cmd-* keys (preserve Cmd-R refresh, etc) + e.preventDefault(); + } + e.stopPropagation(); + this.optionFilter.val(e.key); + this.romoDropdown.doPopupOpen(); + return true; } else { return true; } } } @@ -256,70 +376,75 @@ item.text(optgroup.attr('label')); return item; } -RomoSelectDropdown.prototype._nextListItem = function() { - var listOrItemSelector = 'UL, '+this.itemSelector; - var curr = this.romoDropdown.bodyElem.find('LI.romo-select-highlight'); - var next = this._nextAll(curr, listOrItemSelector).first(); +RomoSelectDropdown.prototype._buildOptionFilter = function() { + var filter = $('<input type="text" class="romo-select-dropdown-option-filter"></input>'); - if (next.size() === 0) { - next = this._nextAll(curr.closest('UL'), listOrItemSelector).first(); + if (this.elem.data('romo-select-dropdown-filter-placeholder') !== undefined) { + filter.attr('placeholder', this.elem.data('romo-select-dropdown-filter-placeholder')); } - if (next.size() !== 0 && next[0].tagName === 'UL') { - next = next.find(this.itemSelector).first() + filter.attr('data-romo-indicator-text-input-elem-display', "block"); + if (this.elem.data('romo-select-dropdown-filter-indicator') !== undefined) { + filter.attr('data-romo-indicator-text-input-indicator', this.elem.data('romo-select-dropdown-filter-indicator')); } - if (next.size() === 0) { - next = this.romoDropdown.bodyElem.find(this.itemSelector).first(); + if (this.elem.data('romo-select-dropdown-filter-indicator-width-px') !== undefined) { + filter.attr('data-romo-indicator-text-input-indicator-width-px', this.elem.data('romo-select-dropdown-filter-indicator-width-px')); } - return next; -} + filter.attr('data-romo-form-disable-enter-submit', "true"); + filter.attr('data-romo-onkey-on', "keydown"); -RomoSelectDropdown.prototype._prevListItem = function() { - var listOrItemSelector = 'UL, '+this.itemSelector; - var curr = this.romoDropdown.bodyElem.find('LI.romo-select-highlight'); - var prev = this._prevAll(curr, listOrItemSelector).last(); + filter.attr('autocomplete', 'off'); - if (prev.size() === 0) { - prev = this._prevAll(curr.closest('UL'), listOrItemSelector).last(); - } - if (prev.size() !== 0 && prev[0].tagName === 'UL') { - prev = prev.find(this.itemSelector).last() - } - if (prev.size() === 0) { - prev = this.romoDropdown.bodyElem.find(this.itemSelector).last(); - } - return prev; + return filter; } -RomoSelectDropdown.prototype._nextAll = function(elem, selector) { - var els = $(); - var el = elem.next(); - while( el.length ) { - if (selector === undefined || el.is(selector)) { - els = els.add(el); +RomoSelectDropdown.prototype._nextListItem = function() { + var curr = this._getHighlightedItem(); + if (curr.length === 0) { + return curr; + } + var currList = curr.closest('UL'); + var next = Romo.selectNext(curr, this.itemSelector); + + while (next.length === 0) { + currList = Romo.selectNext(currList, 'UL'); + if (currList.length !== 0) { + next = currList.find(this.itemSelector).first(); + } else { + next = this.romoDropdown.bodyElem.find(this.itemSelector).first(); } - el = el.next(); } - return els; + return next; } -RomoSelectDropdown.prototype._prevAll = function(elem, selector) { - var els = $(); - var el = elem.prev(); - while( el.length ) { - if (selector === undefined || el.is(selector)) { - els = els.add(el); +RomoSelectDropdown.prototype._prevListItem = function() { + var curr = this._getHighlightedItem(); + if (curr.length === 0) { + return curr; + } + var currList = curr.closest('UL'); + var prev = Romo.selectPrev(curr, this.itemSelector); + + while (prev.length === 0) { + currList = Romo.selectPrev(currList, 'UL'); + if (currList.length !== 0) { + prev = currList.find(this.itemSelector).last(); + } else { + prev = this.romoDropdown.bodyElem.find(this.itemSelector).last(); } - el = el.prev(); } - return els; + return prev; } RomoSelectDropdown.prototype._highlightItem = function(item) { - this.romoDropdown.bodyElem.find('LI.romo-select-highlight').removeClass('romo-select-highlight'); + this._getHighlightedItem().removeClass('romo-select-highlight'); item.addClass('romo-select-highlight'); +} + +RomoSelectDropdown.prototype._getHighlightedItem = function() { + return this.romoDropdown.bodyElem.find('LI.romo-select-highlight'); } Romo.onInitUI(function(e) { Romo.initUIElems(e, '[data-romo-select-dropdown-auto="true"]').romoSelectDropdown(); });