2016-03-07 15:37:35 +00:00
|
|
|
class GitLabDropdownFilter
|
|
|
|
BLUR_KEYCODES = [27, 40]
|
2016-03-18 16:53:15 +00:00
|
|
|
HAS_VALUE_CLASS = "has-value"
|
2016-03-07 15:37:35 +00:00
|
|
|
|
2016-03-22 10:17:03 +00:00
|
|
|
constructor: (@input, @options) ->
|
2016-03-11 19:59:50 +00:00
|
|
|
{
|
2016-03-14 21:14:29 +00:00
|
|
|
@filterInputBlur = true
|
2016-03-11 19:59:50 +00:00
|
|
|
} = @options
|
2016-03-07 15:37:35 +00:00
|
|
|
|
2016-03-18 16:53:15 +00:00
|
|
|
$inputContainer = @input.parent()
|
|
|
|
$clearButton = $inputContainer.find('.js-dropdown-input-clear')
|
|
|
|
|
|
|
|
# Clear click
|
|
|
|
$clearButton.on 'click', (e) =>
|
|
|
|
e.preventDefault()
|
|
|
|
e.stopPropagation()
|
|
|
|
@input
|
|
|
|
.val('')
|
|
|
|
.trigger('keyup')
|
|
|
|
.focus()
|
2016-03-07 15:37:35 +00:00
|
|
|
|
|
|
|
# Key events
|
2016-03-08 09:09:39 +00:00
|
|
|
timeout = ""
|
2016-03-07 15:37:35 +00:00
|
|
|
@input.on "keyup", (e) =>
|
2016-03-18 16:53:15 +00:00
|
|
|
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 ""
|
2016-03-08 16:53:31 +00:00
|
|
|
if @options.enterCallback
|
|
|
|
@options.enterCallback()
|
|
|
|
return
|
|
|
|
|
2016-03-08 09:09:39 +00:00
|
|
|
clearTimeout timeout
|
|
|
|
timeout = setTimeout =>
|
|
|
|
blur_field = @shouldBlur e.keyCode
|
|
|
|
search_text = @input.val()
|
2016-03-07 15:37:35 +00:00
|
|
|
|
2016-03-18 22:35:26 +00:00
|
|
|
if blur_field and @filterInputBlur
|
2016-03-08 09:09:39 +00:00
|
|
|
@input.blur()
|
2016-03-07 15:37:35 +00:00
|
|
|
|
2016-03-08 16:53:31 +00:00
|
|
|
if @options.remote
|
|
|
|
@options.query search_text, (data) =>
|
|
|
|
@options.callback(data)
|
2016-03-08 09:09:39 +00:00
|
|
|
else
|
|
|
|
@filter search_text
|
|
|
|
, 250
|
2016-03-07 15:37:35 +00:00
|
|
|
|
|
|
|
shouldBlur: (keyCode) ->
|
|
|
|
return BLUR_KEYCODES.indexOf(keyCode) >= 0
|
|
|
|
|
|
|
|
filter: (search_text) ->
|
2016-03-08 16:53:31 +00:00
|
|
|
data = @options.data()
|
2016-03-08 15:45:03 +00:00
|
|
|
results = data
|
|
|
|
|
|
|
|
if search_text isnt ""
|
|
|
|
results = fuzzaldrinPlus.filter(data, search_text,
|
2016-03-08 16:53:31 +00:00
|
|
|
key: @options.keys
|
2016-03-08 15:45:03 +00:00
|
|
|
)
|
2016-03-07 15:37:35 +00:00
|
|
|
|
2016-03-08 17:33:45 +00:00
|
|
|
@options.callback results
|
2016-03-07 15:37:35 +00:00
|
|
|
|
|
|
|
class GitLabDropdownRemote
|
|
|
|
constructor: (@dataEndpoint, @options) ->
|
|
|
|
|
|
|
|
execute: ->
|
|
|
|
if typeof @dataEndpoint is "string"
|
|
|
|
@fetchData()
|
|
|
|
else if typeof @dataEndpoint is "function"
|
|
|
|
if @options.beforeSend
|
|
|
|
@options.beforeSend()
|
|
|
|
|
|
|
|
# Fetch the data by calling the data funcfion
|
2016-03-08 09:09:39 +00:00
|
|
|
@dataEndpoint "", (data) =>
|
2016-03-07 15:37:35 +00:00
|
|
|
if @options.success
|
|
|
|
@options.success(data)
|
|
|
|
|
|
|
|
if @options.beforeSend
|
|
|
|
@options.beforeSend()
|
|
|
|
|
|
|
|
# Fetch the data through ajax if the data is a string
|
|
|
|
fetchData: ->
|
|
|
|
$.ajax(
|
|
|
|
url: @dataEndpoint,
|
|
|
|
dataType: @options.dataType,
|
|
|
|
beforeSend: =>
|
|
|
|
if @options.beforeSend
|
|
|
|
@options.beforeSend()
|
|
|
|
success: (data) =>
|
|
|
|
if @options.success
|
|
|
|
@options.success(data)
|
|
|
|
)
|
|
|
|
|
|
|
|
class GitLabDropdown
|
|
|
|
LOADING_CLASS = "is-loading"
|
2016-03-08 10:24:03 +00:00
|
|
|
PAGE_TWO_CLASS = "is-page-two"
|
2016-03-08 17:33:45 +00:00
|
|
|
ACTIVE_CLASS = "is-active"
|
2016-03-24 10:26:15 +00:00
|
|
|
CURRENT_INDEX = -1
|
2016-03-07 15:37:35 +00:00
|
|
|
|
2016-03-11 19:59:50 +00:00
|
|
|
FILTER_INPUT = '.dropdown-input .dropdown-input-field'
|
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
constructor: (@el, @options) ->
|
|
|
|
@dropdown = $(@el).parent()
|
2016-03-11 19:59:50 +00:00
|
|
|
|
|
|
|
# Set Defaults
|
|
|
|
{
|
|
|
|
# If no input is passed create a default one
|
2016-03-18 22:35:26 +00:00
|
|
|
@filterInput = @getElement(FILTER_INPUT)
|
2016-03-12 01:47:01 +00:00
|
|
|
@highlight = false
|
2016-03-14 21:14:29 +00:00
|
|
|
@filterInputBlur = true
|
2016-03-24 03:07:07 +00:00
|
|
|
@enterCallback = true
|
2016-03-11 19:59:50 +00:00
|
|
|
} = @options
|
|
|
|
|
|
|
|
self = @
|
|
|
|
|
|
|
|
# If selector was passed
|
|
|
|
if _.isString(@filterInput)
|
2016-03-18 22:35:26 +00:00
|
|
|
@filterInput = @getElement(@filterInput)
|
2016-03-11 19:59:50 +00:00
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
search_fields = if @options.search then @options.search.fields else [];
|
|
|
|
|
|
|
|
if @options.data
|
2016-03-11 18:18:38 +00:00
|
|
|
# If data is an array
|
|
|
|
if _.isArray @options.data
|
2016-03-11 19:59:50 +00:00
|
|
|
@fullData = @options.data
|
2016-03-11 18:18:38 +00:00
|
|
|
@parseData @options.data
|
|
|
|
else
|
|
|
|
# Remote data
|
|
|
|
@remote = new GitLabDropdownRemote @options.data, {
|
|
|
|
dataType: @options.dataType,
|
|
|
|
beforeSend: @toggleLoading.bind(@)
|
|
|
|
success: (data) =>
|
|
|
|
@fullData = data
|
2016-03-07 15:37:35 +00:00
|
|
|
|
2016-03-11 18:18:38 +00:00
|
|
|
@parseData @fullData
|
|
|
|
}
|
2016-03-07 15:37:35 +00:00
|
|
|
|
2016-03-19 02:43:26 +00:00
|
|
|
# Init filterable
|
2016-03-07 15:37:35 +00:00
|
|
|
if @options.filterable
|
2016-03-24 00:43:57 +00:00
|
|
|
@filter = new GitLabDropdownFilter @filterInput,
|
2016-03-14 21:14:29 +00:00
|
|
|
filterInputBlur: @filterInputBlur
|
2016-03-08 16:53:31 +00:00
|
|
|
remote: @options.filterRemote
|
|
|
|
query: @options.data
|
|
|
|
keys: @options.search.fields
|
|
|
|
data: =>
|
|
|
|
return @fullData
|
|
|
|
callback: (data) =>
|
|
|
|
@parseData data
|
2016-03-22 10:17:03 +00:00
|
|
|
@highlightRow 1
|
2016-03-08 16:53:31 +00:00
|
|
|
enterCallback: =>
|
2016-03-24 03:07:07 +00:00
|
|
|
if @enterCallback
|
|
|
|
@selectFirstRow()
|
2016-03-07 15:37:35 +00:00
|
|
|
|
|
|
|
# Event listeners
|
2016-03-17 13:14:46 +00:00
|
|
|
|
2016-03-08 10:24:03 +00:00
|
|
|
@dropdown.on "shown.bs.dropdown", @opened
|
|
|
|
@dropdown.on "hidden.bs.dropdown", @hidden
|
2016-03-17 19:15:47 +00:00
|
|
|
@dropdown.on "click", ".dropdown-menu, .dropdown-menu-close", @shouldPropagate
|
2016-03-08 10:24:03 +00:00
|
|
|
|
|
|
|
if @dropdown.find(".dropdown-toggle-page").length
|
|
|
|
@dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on "click", (e) =>
|
|
|
|
e.preventDefault()
|
|
|
|
e.stopPropagation()
|
|
|
|
|
|
|
|
@togglePage()
|
2016-03-07 15:37:35 +00:00
|
|
|
|
|
|
|
if @options.selectable
|
2016-03-08 11:23:54 +00:00
|
|
|
selector = ".dropdown-content a"
|
2016-03-08 10:24:03 +00:00
|
|
|
|
|
|
|
if @dropdown.find(".dropdown-toggle-page").length
|
2016-03-08 11:23:54 +00:00
|
|
|
selector = ".dropdown-page-one .dropdown-content a"
|
2016-03-08 10:24:03 +00:00
|
|
|
|
|
|
|
@dropdown.on "click", selector, (e) ->
|
2016-03-23 16:44:09 +00:00
|
|
|
selected = self.rowClicked $(@)
|
2016-03-07 15:37:35 +00:00
|
|
|
|
|
|
|
if self.options.clicked
|
2016-03-23 16:44:09 +00:00
|
|
|
self.options.clicked(selected)
|
2016-03-07 15:37:35 +00:00
|
|
|
|
2016-03-18 22:35:26 +00:00
|
|
|
# Finds an element inside wrapper element
|
|
|
|
getElement: (selector) ->
|
|
|
|
@dropdown.find selector
|
2016-03-11 19:59:50 +00:00
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
toggleLoading: ->
|
|
|
|
$('.dropdown-menu', @dropdown).toggleClass LOADING_CLASS
|
|
|
|
|
2016-03-08 10:24:03 +00:00
|
|
|
togglePage: ->
|
|
|
|
menu = $('.dropdown-menu', @dropdown)
|
|
|
|
|
|
|
|
if menu.hasClass(PAGE_TWO_CLASS)
|
|
|
|
if @remote
|
|
|
|
@remote.execute()
|
|
|
|
|
|
|
|
menu.toggleClass PAGE_TWO_CLASS
|
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
parseData: (data) ->
|
|
|
|
@renderedData = data
|
|
|
|
|
|
|
|
# Render each row
|
|
|
|
html = $.map data, (obj) =>
|
|
|
|
return @renderItem(obj)
|
|
|
|
|
|
|
|
if @options.filterable and data.length is 0
|
|
|
|
# render no matching results
|
|
|
|
html = [@noResults()]
|
|
|
|
|
|
|
|
# Render the full menu
|
|
|
|
full_html = @renderMenu(html.join(""))
|
|
|
|
|
|
|
|
@appendMenu(full_html)
|
|
|
|
|
2016-03-17 13:14:46 +00:00
|
|
|
shouldPropagate: (e) =>
|
|
|
|
if @options.multiSelect
|
2016-03-17 19:15:47 +00:00
|
|
|
$target = $(e.target)
|
|
|
|
if not $target.hasClass('dropdown-menu-close') and not $target.hasClass('dropdown-menu-close-icon')
|
|
|
|
e.stopPropagation()
|
|
|
|
return false
|
|
|
|
else
|
|
|
|
return true
|
2016-03-17 13:14:46 +00:00
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
opened: =>
|
2016-03-23 15:23:45 +00:00
|
|
|
@addArrowKeyEvent()
|
|
|
|
|
2016-03-08 15:18:01 +00:00
|
|
|
contentHtml = $('.dropdown-content', @dropdown).html()
|
|
|
|
if @remote && contentHtml is ""
|
2016-03-07 15:37:35 +00:00
|
|
|
@remote.execute()
|
|
|
|
|
2016-03-08 09:09:39 +00:00
|
|
|
if @options.filterable
|
2016-03-11 19:59:50 +00:00
|
|
|
@filterInput.focus()
|
2016-03-08 09:09:39 +00:00
|
|
|
|
2016-03-27 15:04:51 +00:00
|
|
|
@dropdown.trigger('shown.gl.dropdown')
|
|
|
|
|
2016-03-12 20:37:02 +00:00
|
|
|
hidden: (e) =>
|
2016-03-23 15:23:45 +00:00
|
|
|
@removeArrayKeyEvent()
|
2016-03-08 09:09:39 +00:00
|
|
|
if @options.filterable
|
2016-03-18 15:53:16 +00:00
|
|
|
@dropdown
|
|
|
|
.find(".dropdown-input-field")
|
|
|
|
.blur()
|
|
|
|
.val("")
|
|
|
|
.trigger("keyup")
|
2016-03-08 09:09:39 +00:00
|
|
|
|
2016-03-08 10:24:03 +00:00
|
|
|
if @dropdown.find(".dropdown-toggle-page").length
|
|
|
|
$('.dropdown-menu', @dropdown).removeClass PAGE_TWO_CLASS
|
|
|
|
|
2016-03-12 20:37:02 +00:00
|
|
|
if @options.hidden
|
|
|
|
@options.hidden.call(@,e)
|
|
|
|
|
2016-03-27 15:04:51 +00:00
|
|
|
@dropdown.trigger('hidden.gl.dropdown')
|
|
|
|
|
2016-03-08 10:24:03 +00:00
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
# Render the full menu
|
|
|
|
renderMenu: (html) ->
|
|
|
|
menu_html = ""
|
|
|
|
|
|
|
|
if @options.renderMenu
|
|
|
|
menu_html = @options.renderMenu(html)
|
|
|
|
else
|
|
|
|
menu_html = "<ul>#{html}</ul>"
|
|
|
|
|
|
|
|
return menu_html
|
|
|
|
|
|
|
|
# Append the menu into the dropdown
|
|
|
|
appendMenu: (html) ->
|
2016-03-08 10:24:03 +00:00
|
|
|
selector = '.dropdown-content'
|
|
|
|
if @dropdown.find(".dropdown-toggle-page").length
|
|
|
|
selector = ".dropdown-page-one .dropdown-content"
|
|
|
|
|
|
|
|
$(selector, @dropdown).html html
|
2016-03-07 15:37:35 +00:00
|
|
|
|
|
|
|
# Render the row
|
|
|
|
renderItem: (data) ->
|
|
|
|
html = ""
|
|
|
|
|
2016-03-24 22:13:09 +00:00
|
|
|
# Divider
|
2016-03-08 10:24:03 +00:00
|
|
|
return "<li class='divider'></li>" if data is "divider"
|
|
|
|
|
2016-03-24 22:13:09 +00:00
|
|
|
# Separator is a full-width divider
|
|
|
|
return "<li class='separator'></li>" if data is "separator"
|
|
|
|
|
2016-03-11 23:00:17 +00:00
|
|
|
# Header
|
|
|
|
return "<li class='dropdown-header'>#{data.header}</li>" if data.header?
|
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
if @options.renderRow
|
|
|
|
# Call the render function
|
|
|
|
html = @options.renderRow(data)
|
|
|
|
else
|
2016-03-15 05:06:14 +00:00
|
|
|
if not selected
|
|
|
|
value = if @options.id then @options.id(data) else data.id
|
|
|
|
fieldName = @options.fieldName
|
|
|
|
field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']")
|
|
|
|
if field.length
|
|
|
|
selected = true
|
|
|
|
|
2016-03-11 18:39:28 +00:00
|
|
|
# Set URL
|
|
|
|
if @options.url?
|
|
|
|
url = @options.url(data)
|
|
|
|
else
|
2016-03-15 03:04:22 +00:00
|
|
|
url = if data.url? then data.url else '#'
|
2016-03-11 18:39:28 +00:00
|
|
|
|
|
|
|
# Set Text
|
2016-03-11 18:18:38 +00:00
|
|
|
if @options.text?
|
|
|
|
text = @options.text(data)
|
|
|
|
else
|
2016-03-11 18:39:28 +00:00
|
|
|
text = if data.text? then data.text else ''
|
2016-03-11 18:18:38 +00:00
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
cssClass = "";
|
|
|
|
|
|
|
|
if selected
|
|
|
|
cssClass = "is-active"
|
|
|
|
|
2016-03-12 01:47:01 +00:00
|
|
|
if @highlight
|
|
|
|
text = @highlightTextMatches(text, @filterInput.val())
|
2016-03-12 01:38:19 +00:00
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
html = "<li>"
|
|
|
|
html += "<a href='#{url}' class='#{cssClass}'>"
|
|
|
|
html += text
|
|
|
|
html += "</a>"
|
|
|
|
html += "</li>"
|
|
|
|
|
|
|
|
return html
|
|
|
|
|
2016-03-12 01:38:19 +00:00
|
|
|
highlightTextMatches: (text, term) ->
|
|
|
|
occurrences = fuzzaldrinPlus.match(text, term)
|
2016-03-18 22:35:26 +00:00
|
|
|
text.split('').map((character, i) ->
|
|
|
|
if i in occurrences then "<b>#{character}</b>" else character
|
|
|
|
).join('')
|
2016-03-12 01:38:19 +00:00
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
noResults: ->
|
2016-03-23 15:23:45 +00:00
|
|
|
html = "<li class='dropdown-menu-empty-link is-focused'>"
|
|
|
|
html += "<a href='#'>"
|
2016-03-07 15:37:35 +00:00
|
|
|
html += "No matching results."
|
|
|
|
html += "</a>"
|
|
|
|
html += "</li>"
|
|
|
|
|
2016-03-22 10:17:03 +00:00
|
|
|
highlightRow: (index) ->
|
2016-03-24 00:44:24 +00:00
|
|
|
if @filterInput.val() isnt ""
|
2016-03-22 10:17:03 +00:00
|
|
|
selector = '.dropdown-content li:first-child a'
|
|
|
|
if @dropdown.find(".dropdown-toggle-page").length
|
|
|
|
selector = ".dropdown-page-one .dropdown-content li:first-child a"
|
|
|
|
|
2016-03-24 00:45:00 +00:00
|
|
|
@getElement(selector).addClass 'is-focused'
|
2016-03-22 10:17:03 +00:00
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
rowClicked: (el) ->
|
|
|
|
fieldName = @options.fieldName
|
2016-03-15 02:08:07 +00:00
|
|
|
selectedIndex = el.parent().index()
|
|
|
|
if @renderedData
|
|
|
|
selectedObject = @renderedData[selectedIndex]
|
|
|
|
value = if @options.id then @options.id(selectedObject, el) else selectedObject.id
|
|
|
|
field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']")
|
2016-03-23 15:23:45 +00:00
|
|
|
|
2016-03-08 17:33:45 +00:00
|
|
|
if el.hasClass(ACTIVE_CLASS)
|
2016-03-19 15:39:34 +00:00
|
|
|
el.removeClass(ACTIVE_CLASS)
|
2016-03-15 05:06:14 +00:00
|
|
|
field.remove()
|
2016-03-23 16:44:09 +00:00
|
|
|
|
|
|
|
# Toggle the dropdown label
|
|
|
|
if @options.toggleLabel
|
|
|
|
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel
|
2016-03-07 15:37:35 +00:00
|
|
|
else
|
2016-03-14 13:49:53 +00:00
|
|
|
if !value?
|
|
|
|
field.remove()
|
|
|
|
|
2016-03-15 05:06:14 +00:00
|
|
|
if not @options.multiSelect
|
2016-03-15 18:20:22 +00:00
|
|
|
@dropdown.find(".#{ACTIVE_CLASS}").removeClass ACTIVE_CLASS
|
2016-03-15 05:29:41 +00:00
|
|
|
@dropdown.parent().find("input[name='#{fieldName}']").remove()
|
2016-03-08 17:33:45 +00:00
|
|
|
|
|
|
|
# Toggle active class for the tick mark
|
2016-03-23 16:44:09 +00:00
|
|
|
el.addClass ACTIVE_CLASS
|
2016-03-08 17:33:45 +00:00
|
|
|
|
2016-03-15 18:20:22 +00:00
|
|
|
# Toggle the dropdown label
|
|
|
|
if @options.toggleLabel
|
|
|
|
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject)
|
2016-03-14 20:04:05 +00:00
|
|
|
if value?
|
2016-03-08 17:33:45 +00:00
|
|
|
if !field.length
|
|
|
|
# Create hidden input for form
|
2016-03-15 05:06:14 +00:00
|
|
|
input = "<input type='hidden' name='#{fieldName}' value='#{value}' />"
|
2016-03-23 16:44:09 +00:00
|
|
|
if @options.inputId?
|
2016-03-22 19:18:29 +00:00
|
|
|
input = $(input)
|
|
|
|
.attr('id', @options.inputId)
|
2016-03-08 17:33:45 +00:00
|
|
|
@dropdown.before input
|
2016-03-07 15:37:35 +00:00
|
|
|
|
2016-03-23 16:44:09 +00:00
|
|
|
return selectedObject
|
|
|
|
|
2016-03-08 16:53:31 +00:00
|
|
|
selectFirstRow: ->
|
|
|
|
selector = '.dropdown-content li:first-child a'
|
|
|
|
if @dropdown.find(".dropdown-toggle-page").length
|
|
|
|
selector = ".dropdown-page-one .dropdown-content li:first-child a"
|
|
|
|
|
2016-03-22 10:17:03 +00:00
|
|
|
# simulate a click on the first link
|
2016-03-08 16:53:31 +00:00
|
|
|
$(selector).trigger "click"
|
|
|
|
|
2016-03-23 15:23:45 +00:00
|
|
|
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.keyCode
|
|
|
|
|
|
|
|
if ARROW_KEY_CODES.indexOf(currentKeyCode) >= 0
|
|
|
|
e.preventDefault()
|
|
|
|
e.stopPropagation()
|
|
|
|
|
|
|
|
$listItems = $(selector, @dropdown)
|
|
|
|
|
|
|
|
if @options.filterable
|
|
|
|
$input.blur()
|
|
|
|
|
|
|
|
if currentKeyCode is 40
|
|
|
|
# Move down
|
2016-03-24 10:26:15 +00:00
|
|
|
CURRENT_INDEX += 1 if CURRENT_INDEX < ($listItems.length - 1)
|
2016-03-23 15:23:45 +00:00
|
|
|
else if currentKeyCode is 38
|
|
|
|
# Move up
|
|
|
|
CURRENT_INDEX -= 1 if CURRENT_INDEX > 0
|
|
|
|
|
|
|
|
@highlightRowAtIndex(CURRENT_INDEX)
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
removeArrayKeyEvent: ->
|
|
|
|
$('body').off 'keydown'
|
|
|
|
|
|
|
|
highlightRowAtIndex: (index, prevIndex) ->
|
|
|
|
# Remove the class for the previously focused row
|
|
|
|
$('.is-focused', @dropdown).removeClass 'is-focused'
|
|
|
|
|
|
|
|
# Update the class for the row at the specific index
|
|
|
|
selector = ".dropdown-content li:not(.divider):eq(#{index})"
|
|
|
|
if @dropdown.find(".dropdown-toggle-page").length
|
|
|
|
selector = ".dropdown-page-one #{selector}"
|
|
|
|
|
|
|
|
$listItem = $(selector, @dropdown)
|
|
|
|
$listItem.addClass "is-focused"
|
|
|
|
|
2016-03-24 10:26:15 +00:00
|
|
|
# Dropdown content scroll area
|
|
|
|
$dropdownContent = $listItem.closest('.dropdown-content')
|
|
|
|
dropdownContentBottom = $dropdownContent.prop('offsetTop') + $dropdownContent.prop('offsetHeight')
|
|
|
|
|
|
|
|
# Get the offset bottom of the list item
|
|
|
|
listItemBottom = $listItem.prop('offsetTop') + $listItem.prop('offsetHeight')
|
|
|
|
console.log listItemBottom, dropdownContentBottom
|
|
|
|
|
|
|
|
if listItemBottom > dropdownContentBottom
|
|
|
|
# Scroll the dropdown content down
|
|
|
|
$dropdownContent.scrollTop(listItemBottom - dropdownContentBottom)
|
|
|
|
|
2016-03-07 15:37:35 +00:00
|
|
|
$.fn.glDropdown = (opts) ->
|
|
|
|
return @.each ->
|
2016-03-19 02:43:26 +00:00
|
|
|
if (!$.data @, 'glDropdown')
|
|
|
|
$.data(@, 'glDropdown', new GitLabDropdown @, opts)
|