summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Schatz <jschatz1@gmail.com>2016-04-05 19:41:22 +0000
committerJacob Schatz <jschatz1@gmail.com>2016-04-05 19:41:22 +0000
commita1c794c5917e9dad414e54cdd4a6ae920c23dda2 (patch)
tree8a922440ee44e760047c0be11ff3c96f2e3615cf
parent4258589d95350c8c5483d12ae1665d9571614771 (diff)
parent8e3f5ebaa080bec65b35c21b8a70f84c7ed9fa63 (diff)
downloadgitlab-ce-a1c794c5917e9dad414e54cdd4a6ae920c23dda2.tar.gz
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
-rw-r--r--app/assets/javascripts/gl_dropdown.js.coffee110
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)
-