Commit a1c794c5 authored by Jacob Schatz's avatar Jacob Schatz

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
parents 4258589d 8e3f5eba
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)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment