Improved navigation by keyboard.
This commit is contained in:
parent
a70377558f
commit
6c7d9bcb4d
3 changed files with 123 additions and 93 deletions
|
@ -9,13 +9,16 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
'focus input': 'open'
|
'focus input': 'open'
|
||||||
'click': 'stopPropagation'
|
'click': 'stopPropagation'
|
||||||
|
|
||||||
|
elements:
|
||||||
|
'.recipientList': 'recipientList'
|
||||||
|
|
||||||
constructor: (params) ->
|
constructor: (params) ->
|
||||||
super
|
super
|
||||||
|
|
||||||
@key = Math.floor( Math.random() * 999999 ).toString()
|
@key = Math.floor( Math.random() * 999999 ).toString()
|
||||||
|
|
||||||
if !@attribute.source
|
if !@attribute.source
|
||||||
@attribute.source = @apiPath + '/search/user-organization'
|
@attribute.source = "#{@apiPath}/search/user-organization"
|
||||||
@build()
|
@build()
|
||||||
|
|
||||||
# set current value
|
# set current value
|
||||||
|
@ -31,13 +34,14 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
open: =>
|
open: =>
|
||||||
@clearDelay('close')
|
@clearDelay('close')
|
||||||
@el.addClass('open')
|
@el.addClass('open')
|
||||||
|
|
||||||
$(window).on 'click.UserOrganizationAutocompletion', @close
|
$(window).on 'click.UserOrganizationAutocompletion', @close
|
||||||
|
$(window).on 'keydown.UserOrganizationAutocompletion', @navigateByKeyboard
|
||||||
|
|
||||||
close: =>
|
close: =>
|
||||||
|
$(window).off 'keydown.UserOrganizationAutocompletion'
|
||||||
execute = =>
|
execute = =>
|
||||||
@el.removeClass('open')
|
@el.removeClass('open')
|
||||||
@delay(execute, 200, 'close')
|
@delay(execute, 50, 'close')
|
||||||
|
|
||||||
$(window).off 'click.UserOrganizationAutocompletion'
|
$(window).off 'click.UserOrganizationAutocompletion'
|
||||||
|
|
||||||
|
@ -64,6 +68,98 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
if @callback
|
if @callback
|
||||||
@callback(userId)
|
@callback(userId)
|
||||||
|
|
||||||
|
navigateByKeyboard: (e) =>
|
||||||
|
|
||||||
|
# clean input field on ESC
|
||||||
|
if e.keyCode is 27
|
||||||
|
|
||||||
|
# if org member selection is shown, go back to member list
|
||||||
|
if !@recipientList.hasClass('is-shown')
|
||||||
|
@hideOrganizationMembers()
|
||||||
|
return
|
||||||
|
|
||||||
|
# empty user selection and close
|
||||||
|
$(e.target).val('').trigger('change')
|
||||||
|
|
||||||
|
# if tab / close recipientList
|
||||||
|
if e.keyCode is 9
|
||||||
|
@close()
|
||||||
|
|
||||||
|
# ignore arrow keys
|
||||||
|
if e.keyCode is 37
|
||||||
|
return
|
||||||
|
|
||||||
|
if e.keyCode is 39
|
||||||
|
return
|
||||||
|
|
||||||
|
# up / select upper item
|
||||||
|
if e.keyCode is 38
|
||||||
|
e.preventDefault()
|
||||||
|
if @recipientList.hasClass('is-shown')
|
||||||
|
if @recipientList.find('li.is-active').length is 0
|
||||||
|
@recipientList.find('li').last().addClass('is-active')
|
||||||
|
else
|
||||||
|
if @recipientList.find('li.is-active').prev().length isnt 0
|
||||||
|
@recipientList.find('li.is-active').removeClass('is-active').prev().addClass('is-active')
|
||||||
|
return
|
||||||
|
recipientListOrgMemeber = @$('.recipientList-organizationMembers').not('.hide')
|
||||||
|
if recipientListOrgMemeber.not('.hide').find('li.is-active').length is 0
|
||||||
|
recipientListOrgMemeber.not('.hide').find('li').last().addClass('is-active')
|
||||||
|
else
|
||||||
|
if recipientListOrgMemeber.not('.hide').find('li.is-active').prev().length isnt 0
|
||||||
|
recipientListOrgMemeber.not('.hide').find('li.is-active').removeClass('is-active').prev().addClass('is-active')
|
||||||
|
return
|
||||||
|
|
||||||
|
# down / select lower item
|
||||||
|
if e.keyCode is 40
|
||||||
|
e.preventDefault()
|
||||||
|
if @recipientList.hasClass('is-shown')
|
||||||
|
if @recipientList.find('li.is-active').length is 0
|
||||||
|
@recipientList.find('li').first().addClass('is-active')
|
||||||
|
else
|
||||||
|
if @recipientList.find('li.is-active').next().length isnt 0
|
||||||
|
@recipientList.find('li.is-active').removeClass('is-active').next().addClass('is-active')
|
||||||
|
return
|
||||||
|
recipientListOrgMemeber = @$('.recipientList-organizationMembers').not('.hide')
|
||||||
|
if recipientListOrgMemeber.not('.hide').find('li.is-active').length is 0
|
||||||
|
recipientListOrgMemeber.find('li').first().addClass('is-active')
|
||||||
|
else
|
||||||
|
if recipientListOrgMemeber.not('.hide').find('li.is-active').next().length isnt 0
|
||||||
|
recipientListOrgMemeber.not('.hide').find('li.is-active').removeClass('is-active').next().addClass('is-active')
|
||||||
|
return
|
||||||
|
|
||||||
|
# enter / take item
|
||||||
|
if e.keyCode is 13
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
|
||||||
|
# nav by org member selection
|
||||||
|
if !@recipientList.hasClass('is-shown')
|
||||||
|
recipientListOrganizationMembers = @$('.recipientList-organizationMembers').not('.hide')
|
||||||
|
if recipientListOrganizationMembers.find('.js-back.is-active').get(0)
|
||||||
|
@hideOrganizationMembers()
|
||||||
|
return
|
||||||
|
userId = recipientListOrganizationMembers.find('li.is-active').data('user-id')
|
||||||
|
return if !userId
|
||||||
|
@setUser(userId)
|
||||||
|
@close()
|
||||||
|
return
|
||||||
|
|
||||||
|
# nav by user list selection
|
||||||
|
userId = @recipientList.find('li.is-active').data('user-id')
|
||||||
|
if userId
|
||||||
|
if userId is 'new'
|
||||||
|
@newUser()
|
||||||
|
else
|
||||||
|
@setUser(userId)
|
||||||
|
@close()
|
||||||
|
return
|
||||||
|
|
||||||
|
organizationId = @recipientList.find('li.is-active').data('organization-id')
|
||||||
|
return if !organizationId
|
||||||
|
@showOrganizationMembers(undefined, @recipientList.find('li.is-active'))
|
||||||
|
|
||||||
|
|
||||||
buildOrganizationItem: (organization) ->
|
buildOrganizationItem: (organization) ->
|
||||||
App.view('generic/user_search/item_organization')(
|
App.view('generic/user_search/item_organization')(
|
||||||
organization: organization
|
organization: organization
|
||||||
|
@ -86,11 +182,11 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
App.view('generic/user_search/new_user')()
|
App.view('generic/user_search/new_user')()
|
||||||
|
|
||||||
build: =>
|
build: =>
|
||||||
@el.html App.view('generic/user_search/input')(
|
@html App.view('generic/user_search/input')(
|
||||||
attribute: @attribute
|
attribute: @attribute
|
||||||
)
|
)
|
||||||
if !@attribute.disableCreateUser
|
if !@attribute.disableCreateUser
|
||||||
@el.find('.recipientList').append( @buildUserNew() )
|
@recipientList.append(@buildUserNew())
|
||||||
|
|
||||||
@el.find('[name="' + @attribute.name + '"]').on(
|
@el.find('[name="' + @attribute.name + '"]').on(
|
||||||
'change',
|
'change',
|
||||||
|
@ -98,79 +194,6 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
@executeCallback()
|
@executeCallback()
|
||||||
)
|
)
|
||||||
|
|
||||||
# navigate in result list
|
|
||||||
@el.find('[name="' + @attribute.name + '_completion"]').on(
|
|
||||||
'keydown',
|
|
||||||
(e) =>
|
|
||||||
item = $(e.target).val().trim()
|
|
||||||
|
|
||||||
#@log('CC', e.keyCode, item)
|
|
||||||
|
|
||||||
# clean input field on ESC
|
|
||||||
if e.keyCode is 27
|
|
||||||
|
|
||||||
# if org member selection is shown, go back to member list
|
|
||||||
if @$('.recipientList-backClickArea').is(':visible')
|
|
||||||
@$('.recipientList-backClickArea').click()
|
|
||||||
return
|
|
||||||
|
|
||||||
# empty user selection and close
|
|
||||||
$(e.target).val('')
|
|
||||||
item = ''
|
|
||||||
@close()
|
|
||||||
|
|
||||||
# if tab / close recipientList
|
|
||||||
if e.keyCode is 9
|
|
||||||
@close()
|
|
||||||
|
|
||||||
# ignore arrow keys
|
|
||||||
if e.keyCode is 37
|
|
||||||
return
|
|
||||||
|
|
||||||
if e.keyCode is 39
|
|
||||||
return
|
|
||||||
|
|
||||||
# up / select upper item
|
|
||||||
if e.keyCode is 38
|
|
||||||
e.preventDefault()
|
|
||||||
recipientList = @$('.recipientList')
|
|
||||||
if recipientList.find('li.is-active').length is 0
|
|
||||||
recipientList.find('li').last().addClass('is-active')
|
|
||||||
else
|
|
||||||
if recipientList.find('li.is-active').prev().length isnt 0
|
|
||||||
recipientList.find('li.is-active').removeClass('is-active').prev().addClass('is-active')
|
|
||||||
return
|
|
||||||
|
|
||||||
# down / select lower item
|
|
||||||
if e.keyCode is 40
|
|
||||||
e.preventDefault()
|
|
||||||
recipientList = @$('.recipientList')
|
|
||||||
if recipientList.find('li.is-active').length is 0
|
|
||||||
recipientList.find('li').first().addClass('is-active')
|
|
||||||
else
|
|
||||||
if recipientList.find('li.is-active').next().length isnt 0
|
|
||||||
recipientList.find('li.is-active').removeClass('is-active').next().addClass('is-active')
|
|
||||||
return
|
|
||||||
|
|
||||||
# enter / take item
|
|
||||||
if e.keyCode is 13
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
userId = @$('.recipientList').find('li.is-active').data('user-id')
|
|
||||||
if !userId
|
|
||||||
organizationId = @$('.recipientList').find('li.is-active').data('organization-id')
|
|
||||||
if !organizationId
|
|
||||||
return
|
|
||||||
@showOrganizationMembers(undefined, @$('.recipientList').find('li.is-active'))
|
|
||||||
return
|
|
||||||
if userId is 'new'
|
|
||||||
@newUser()
|
|
||||||
else
|
|
||||||
@setUser(userId)
|
|
||||||
@close()
|
|
||||||
return
|
|
||||||
)
|
|
||||||
|
|
||||||
# start search
|
# start search
|
||||||
@searchTerm = ''
|
@searchTerm = ''
|
||||||
@el.find('[name="' + @attribute.name + '_completion"]').on(
|
@el.find('[name="' + @attribute.name + '_completion"]').on(
|
||||||
|
@ -180,10 +203,12 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
return if @searchTerm is term
|
return if @searchTerm is term
|
||||||
@searchTerm = term
|
@searchTerm = term
|
||||||
|
|
||||||
|
@hideOrganizationMembers()
|
||||||
|
|
||||||
# hide dropdown
|
# hide dropdown
|
||||||
if !term && !@attribute.disableCreateUser
|
if !term && !@attribute.disableCreateUser
|
||||||
@emptyResultList()
|
@emptyResultList()
|
||||||
@$('.recipientList').append(@buildUserNew())
|
@recipientList.append(@buildUserNew())
|
||||||
|
|
||||||
# show dropdown
|
# show dropdown
|
||||||
if term && ( !@attribute.minLengt || @attribute.minLengt <= term.length )
|
if term && ( !@attribute.minLengt || @attribute.minLengt <= term.length )
|
||||||
|
@ -193,7 +218,7 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
|
|
||||||
searchUser: (term) =>
|
searchUser: (term) =>
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'searchUser' + @key
|
id: "searchUser#{@key}"
|
||||||
type: 'GET'
|
type: 'GET'
|
||||||
url: @attribute.source
|
url: @attribute.source
|
||||||
data:
|
data:
|
||||||
|
@ -211,7 +236,7 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
# organization
|
# organization
|
||||||
if item.type is 'Organization'
|
if item.type is 'Organization'
|
||||||
organization = App.Organization.fullLocal(item.id)
|
organization = App.Organization.fullLocal(item.id)
|
||||||
@$('.recipientList').append(@buildOrganizationItem(organization))
|
@recipientList.append(@buildOrganizationItem(organization))
|
||||||
|
|
||||||
# users of organization
|
# users of organization
|
||||||
if organization.member_ids
|
if organization.member_ids
|
||||||
|
@ -220,14 +245,14 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
# users
|
# users
|
||||||
if item.type is 'User'
|
if item.type is 'User'
|
||||||
user = App.User.fullLocal(item.id)
|
user = App.User.fullLocal(item.id)
|
||||||
@$('.recipientList').append(@buildUserItem(user))
|
@recipientList.append(@buildUserItem(user))
|
||||||
|
|
||||||
if !@attribute.disableCreateUser
|
if !@attribute.disableCreateUser
|
||||||
@$('.recipientList').append(@buildUserNew())
|
@recipientList.append(@buildUserNew())
|
||||||
)
|
)
|
||||||
|
|
||||||
emptyResultList: =>
|
emptyResultList: =>
|
||||||
@$('.recipientList').empty()
|
@recipientList.empty()
|
||||||
@$('.recipientList-organizationMembers').remove()
|
@$('.recipientList-organizationMembers').remove()
|
||||||
|
|
||||||
showOrganizationMembers: (e,listEntry) =>
|
showOrganizationMembers: (e,listEntry) =>
|
||||||
|
@ -237,11 +262,14 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
|
|
||||||
organizationId = listEntry.data('organization-id')
|
organizationId = listEntry.data('organization-id')
|
||||||
|
|
||||||
@recipientList = @$('.recipientList')
|
@organizationList = @$("[organization-id=#{ organizationId }]")
|
||||||
@organizationList = @$("##{ organizationId }")
|
|
||||||
|
return if !@organizationList.get(0)
|
||||||
|
|
||||||
|
@recipientList.removeClass('is-shown')
|
||||||
|
@$('.recipientList-organizationMembers').addClass('is-shown')
|
||||||
|
|
||||||
# move organization-list to the right and slide it in
|
# move organization-list to the right and slide it in
|
||||||
|
|
||||||
$.Velocity.hook(@organizationList, 'translateX', '100%')
|
$.Velocity.hook(@organizationList, 'translateX', '100%')
|
||||||
@organizationList.removeClass('hide')
|
@organizationList.removeClass('hide')
|
||||||
|
|
||||||
|
@ -262,6 +290,9 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
hideOrganizationMembers: (e) =>
|
hideOrganizationMembers: (e) =>
|
||||||
e && e.stopPropagation()
|
e && e.stopPropagation()
|
||||||
|
|
||||||
|
@recipientList.addClass('is-shown')
|
||||||
|
@$('.recipientList-organizationMembers').removeClass('is-shown')
|
||||||
|
|
||||||
return if !@organizationList
|
return if !@organizationList
|
||||||
|
|
||||||
# fade list back in
|
# fade list back in
|
||||||
|
@ -272,7 +303,6 @@ class App.UserOrganizationAutocompletion extends App.Controller
|
||||||
speed: 300
|
speed: 300
|
||||||
|
|
||||||
# reset list height
|
# reset list height
|
||||||
|
|
||||||
@recipientList.height('')
|
@recipientList.height('')
|
||||||
|
|
||||||
# slide out organization-list and hide it
|
# slide out organization-list and hide it
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<ul class="recipientList-organizationMembers hide" id="<%- @organization.id %>">
|
<ul class="recipientList-organizationMembers hide" organization-id="<%- @organization.id %>">
|
||||||
<li class="recipientList-controls js-back">
|
<li class="recipientList-controls js-back">
|
||||||
<div class="btn btn--action btn--onDark">
|
<div class="btn btn--action btn--onDark">
|
||||||
<%- @Icon('arrow-left') %>
|
<%- @Icon('arrow-left') %>
|
||||||
|
|
|
@ -5879,7 +5879,7 @@ footer {
|
||||||
.recipientList-controls:hover {
|
.recipientList-controls:hover {
|
||||||
@extend .u-clickable;
|
@extend .u-clickable;
|
||||||
padding: 0 10px !important;
|
padding: 0 10px !important;
|
||||||
background: hsl(206,7%,28%) !important;
|
background: hsl(206,7%,28%);
|
||||||
|
|
||||||
& + li {
|
& + li {
|
||||||
box-shadow: 0 1px rgba(255,255,255,.13) inset;
|
box-shadow: 0 1px rgba(255,255,255,.13) inset;
|
||||||
|
|
Loading…
Reference in a new issue