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
This commit is contained in:
commit
a1c794c591
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue