diff options
author | Jacob Schatz <jschatz1@gmail.com> | 2016-04-05 22:41:22 +0300 |
---|---|---|
committer | Jacob Schatz <jschatz1@gmail.com> | 2016-04-05 22:41:22 +0300 |
commit | a1c794c5917e9dad414e54cdd4a6ae920c23dda2 (patch) | |
tree | 8a922440ee44e760047c0be11ff3c96f2e3615cf /app/assets/javascripts/gl_dropdown.js.coffee | |
parent | 4258589d95350c8c5483d12ae1665d9571614771 (diff) | |
parent | 8e3f5ebaa080bec65b35c21b8a70f84c7ed9fa63 (diff) |
Merge branch 'dropdown-arrow-support' into 'master'
Dropdown arrow support
When the dropdown is open, you can scroll through the list of items with the up & down arrow keys. When an item is focused, the enter triggers the click event for that row.
Closes #14455
See merge request !3385
Diffstat (limited to 'app/assets/javascripts/gl_dropdown.js.coffee')
-rw-r--r-- | app/assets/javascripts/gl_dropdown.js.coffee | 110 |
1 files changed, 92 insertions, 18 deletions
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 4f032a82e58..2a4811b8763 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -1,5 +1,6 @@ class GitLabDropdownFilter BLUR_KEYCODES = [27, 40] + ARROW_KEY_CODES = [38, 40] HAS_VALUE_CLASS = "has-value" constructor: (@input, @options) -> @@ -22,19 +23,23 @@ class GitLabDropdownFilter # Key events timeout = "" @input.on "keyup", (e) => + keyCode = e.which + + return if ARROW_KEY_CODES.indexOf(keyCode) >= 0 + if @input.val() isnt "" and !$inputContainer.hasClass HAS_VALUE_CLASS $inputContainer.addClass HAS_VALUE_CLASS else if @input.val() is "" and $inputContainer.hasClass HAS_VALUE_CLASS $inputContainer.removeClass HAS_VALUE_CLASS - if e.keyCode is 13 and @input.val() isnt "" + if keyCode is 13 and @input.val() isnt "" if @options.enterCallback @options.enterCallback() return clearTimeout timeout timeout = setTimeout => - blur_field = @shouldBlur e.keyCode + blur_field = @shouldBlur keyCode search_text = @input.val() if blur_field and @filterInputBlur @@ -96,6 +101,7 @@ class GitLabDropdown LOADING_CLASS = "is-loading" PAGE_TWO_CLASS = "is-page-two" ACTIVE_CLASS = "is-active" + currentIndex = -1 FILTER_INPUT = '.dropdown-input .dropdown-input-field' @@ -145,11 +151,11 @@ class GitLabDropdown data: => return @fullData callback: (data) => + currentIndex = -1 @parseData data - @highlightRow 1 enterCallback: => if @enterCallback - @selectFirstRow() + @selectRowAtIndex 0 # Event listeners @@ -218,6 +224,8 @@ class GitLabDropdown return true opened: => + @addArrowKeyEvent() + contentHtml = $('.dropdown-content', @dropdown).html() if @remote && contentHtml is "" @remote.execute() @@ -228,6 +236,7 @@ class GitLabDropdown @dropdown.trigger('shown.gl.dropdown') hidden: (e) => + @removeArrayKeyEvent() if @options.filterable @dropdown .find(".dropdown-input-field") @@ -307,11 +316,11 @@ class GitLabDropdown if @highlight text = @highlightTextMatches(text, @filterInput.val()) - html = "<li>" - html += "<a href='#{url}' class='#{cssClass}'>" - html += text - html += "</a>" - html += "</li>" + html = "<li> + <a href='#{url}' class='#{cssClass}'> + #{text} + </a> + </li>" return html @@ -322,11 +331,11 @@ class GitLabDropdown ).join('') noResults: -> - html = "<li>" - html += "<a class='dropdown-menu-empty-link is-focused'>" - html += "No matching results." - html += "</a>" - html += "</li>" + html = "<li class='dropdown-menu-empty-link'> + <a href='#' class='is-focused'> + No matching results. + </a> + </li>" highlightRow: (index) -> if @filterInput.val() isnt "" @@ -378,16 +387,81 @@ class GitLabDropdown return selectedObject - selectFirstRow: -> - selector = '.dropdown-content li:first-child a' + selectRowAtIndex: (index) -> + selector = ".dropdown-content li:not(.divider):eq(#{index}) a" + if @dropdown.find(".dropdown-toggle-page").length - selector = ".dropdown-page-one .dropdown-content li:first-child a" + selector = ".dropdown-page-one #{selector}" # simulate a click on the first link $(selector).trigger "click" + addArrowKeyEvent: -> + ARROW_KEY_CODES = [38, 40] + $input = @dropdown.find(".dropdown-input-field") + + selector = '.dropdown-content li:not(.divider)' + if @dropdown.find(".dropdown-toggle-page").length + selector = ".dropdown-page-one #{selector}" + + $('body').on 'keydown', (e) => + currentKeyCode = e.which + + if ARROW_KEY_CODES.indexOf(currentKeyCode) >= 0 + e.preventDefault() + e.stopImmediatePropagation() + + PREV_INDEX = currentIndex + $listItems = $(selector, @dropdown) + + # if @options.filterable + # $input.blur() + + if currentKeyCode is 40 + # Move down + currentIndex += 1 if currentIndex < ($listItems.length - 1) + else if currentKeyCode is 38 + # Move up + currentIndex -= 1 if currentIndex > 0 + + @highlightRowAtIndex($listItems, currentIndex) if currentIndex isnt PREV_INDEX + + return false + + if currentKeyCode is 13 + @selectRowAtIndex currentIndex + + removeArrayKeyEvent: -> + $('body').off 'keydown' + + highlightRowAtIndex: ($listItems, index) -> + # Remove the class for the previously focused row + $('.is-focused', @dropdown).removeClass 'is-focused' + + # Update the class for the row at the specific index + $listItem = $listItems.eq(index) + $listItem.find('a:first-child').addClass "is-focused" + + # Dropdown content scroll area + $dropdownContent = $listItem.closest('.dropdown-content') + dropdownScrollTop = $dropdownContent.scrollTop() + dropdownContentHeight = $dropdownContent.outerHeight() + dropdownContentTop = $dropdownContent.prop('offsetTop') + dropdownContentBottom = dropdownContentTop + dropdownContentHeight + + # Get the offset bottom of the list item + listItemHeight = $listItem.outerHeight() + listItemTop = $listItem.prop('offsetTop') + listItemBottom = listItemTop + listItemHeight + + if listItemBottom > dropdownContentBottom + dropdownScrollTop + # Scroll the dropdown content down + $dropdownContent.scrollTop(listItemBottom - dropdownContentBottom) + else if listItemTop < dropdownContentTop + dropdownScrollTop + # Scroll the dropdown content up + $dropdownContent.scrollTop(listItemTop - dropdownContentTop) + $.fn.glDropdown = (opts) -> return @.each -> if (!$.data @, 'glDropdown') $.data(@, 'glDropdown', new GitLabDropdown @, opts) - |