diff --git a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee index f07430279..dfdc5ff0b 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee @@ -753,6 +753,11 @@ class App.ControllerForm extends App.Controller $('#' + attribute.id ).parent().css('height', 'auto') App.Delay.set( a, 120, undefined, 'tags' ) + # user + else if attribute.tag is 'user_autocompletion' + completion = new App.UserOrganizationAutocompletion( attribute: attribute ) + item = completion.element() + # autocompletion else if attribute.tag is 'autocompletion' item = $( App.view('generic/autocompletion')( attribute: attribute ) ) diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee index e837ce821..20516b27e 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee @@ -4,13 +4,9 @@ class App.TicketCreate extends App.Controller events: 'click .type-tabs .tab': 'changeFormType' - 'click .customer_new': 'userNew' 'submit form': 'submit' 'click .submit': 'submit' 'click .cancel': 'cancel' - 'hide.bs.dropdown .js-recipientDropdown': 'hideOrganisationMembers' - 'click .js-organisation': 'showOrganisationMembers' - 'click .js-back': 'hideOrganisationMembers' constructor: (params) -> super @@ -40,61 +36,6 @@ class App.TicketCreate extends App.Controller @log 'notice', 'error', defaults @render(defaults) - showOrganisationMembers: (e) => - e.stopPropagation() - - listEntry = $(e.currentTarget) - organisationId = listEntry.data('organisation') - - @recipientList = @$('.recipientList') - @organisationList = @$("##{ organisationId }") - - # move organisation-list to the right and slide it in - - $.Velocity.hook(@organisationList, 'translateX', '100%') - @organisationList.removeClass('hide') - - @organisationList.velocity - properties: - translateX: 0 - options: - speed: 300 - - # fade out list - - @recipientList.velocity - properties: - translateX: '-100%' - options: - speed: 300 - complete: => @recipientList.height(@organisationList.height()) - - hideOrganisationMembers: (e) => - e && e.stopPropagation() - - return if !@organisationList - - # fade list back in - - @recipientList.velocity - properties: - translateX: 0 - options: - speed: 300 - - # reset list height - - @recipientList.height('') - - # slide out organisation-list and hide it - - @organisationList.velocity - properties: - translateX: '100%' - options: - speed: 300 - complete: => @organisationList.addClass('hide') - changeFormType: (e) => type = $(e.target).data('type') if !type @@ -353,12 +294,6 @@ class App.TicketCreate extends App.Controller params: params ) - userNew: (e) => - e.preventDefault() - new UserNew( - create_screen: @ - ) - cancel: (e) -> e.preventDefault() @navigate '#' @@ -545,68 +480,6 @@ class Sidebar extends App.Controller items: items ) -class UserNew extends App.ControllerModal - constructor: -> - super - @head = 'New User' - @cancel = true - @button = true - - controller = new App.ControllerForm( - el: @el.find('#form-user') - model: App.User - screen: 'edit' - autofocus: true - ) - - @show( controller.form ) - - onSubmit: (e) -> - - e.preventDefault() - params = @formParam(e.target) - - # if no login is given, use emails as fallback - if !params.login && params.email - params.login = params.email - - # find role_id - if !params.role_ids || _.isEmpty( params.role_ids ) - role = App.Role.findByAttribute( 'name', 'Customer' ) - params.role_ids = role.id - @log 'notice', 'updateAttributes', params - - user = new App.User - user.load(params) - - errors = user.validate() - if errors - @log 'error', errors - @formValidate( form: e.target, errors: errors ) - return - - # save user - ui = @ - user.save( - done: -> - - # force to reload object - callbackReload = (user) -> - realname = user.displayName() - if user.email - realname = "#{ realname } <#{ user.email }>" - ui.create_screen.el.find('[name=customer_id]').val( user.id ) - ui.create_screen.el.find('[name=customer_id_autocompletion]').val( realname ) - - # start customer info controller - ui.userInfo( user_id: user.id ) - ui.hide() - App.User.full( @id, callbackReload , true ) - - fail: -> - ui.hide() - ) - class Router extends App.ControllerPermanent constructor: (params) -> super diff --git a/app/assets/javascripts/app/controllers/layout_ref.js.coffee b/app/assets/javascripts/app/controllers/layout_ref.js.coffee index bf0eca142..d5f91dfae 100644 --- a/app/assets/javascripts/app/controllers/layout_ref.js.coffee +++ b/app/assets/javascripts/app/controllers/layout_ref.js.coffee @@ -10,6 +10,11 @@ App.Config.set( 'layout_ref', Index, 'Routes' ) class Content extends App.ControllerContent + events: + 'hide.bs.dropdown .js-recipientDropdown': 'hideOrganisationMembers' + 'click .js-organisation': 'showOrganisationMembers' + 'click .js-back': 'hideOrganisationMembers' + constructor: -> super @render() @@ -35,6 +40,60 @@ class Content extends App.ControllerContent render: -> @html App.view('layout_ref/content')() + showOrganisationMembers: (e) => + e.stopPropagation() + + listEntry = $(e.currentTarget) + organisationId = listEntry.data('organisation-id') + + @recipientList = @$('.recipientList') + @organisationList = @$("##{ organisationId }") + + # move organisation-list to the right and slide it in + + $.Velocity.hook(@organisationList, 'translateX', '100%') + @organisationList.removeClass('hide') + + @organisationList.velocity + properties: + translateX: 0 + options: + speed: 300 + + # fade out list + + @recipientList.velocity + properties: + translateX: '-100%' + options: + speed: 300 + complete: => @recipientList.height(@organisationList.height()) + + hideOrganisationMembers: (e) => + e && e.stopPropagation() + + return if !@organisationList + + # fade list back in + + @recipientList.velocity + properties: + translateX: 0 + options: + speed: 300 + + # reset list height + + @recipientList.height('') + + # slide out organisation-list and hide it + @organisationList.velocity + properties: + translateX: '100%' + options: + speed: 300 + complete: => @organisationList.addClass('hide') + App.Config.set( 'layout_ref/content', Content, 'Routes' ) diff --git a/app/assets/javascripts/app/controllers/ticket_customer.js.coffee b/app/assets/javascripts/app/controllers/ticket_customer.js.coffee index 5d09a51b7..34fbded2e 100644 --- a/app/assets/javascripts/app/controllers/ticket_customer.js.coffee +++ b/app/assets/javascripts/app/controllers/ticket_customer.js.coffee @@ -2,15 +2,13 @@ class App.TicketCustomer extends App.ControllerModal constructor: -> super configure_attributes = [ - { name: 'customer_id', display: 'Customer', tag: 'autocompletion', type: 'text', limit: 100, null: false, relation: 'User', class: 'span5', autocapitalize: false, help: 'Select the new customer of the Ticket.', source: @apiPath + '/users/search', minLengt: 2 }, + { name: 'customer_id', display: 'Customer', tag: 'user_autocompletion', null: false, placeholder: 'Enter Person or Organisation/Company', minLengt: 2, disableCreateUser: true }, ] controller = new App.ControllerForm( - model: { + model: configure_attributes: configure_attributes, - className: 'update', - }, - autofocus: true, + autofocus: true ) @head = 'Change Customer' @close = true diff --git a/app/assets/javascripts/app/lib/app_post/user_organization_autocompletion.js.coffee b/app/assets/javascripts/app/lib/app_post/user_organization_autocompletion.js.coffee new file mode 100644 index 000000000..308f29d7c --- /dev/null +++ b/app/assets/javascripts/app/lib/app_post/user_organization_autocompletion.js.coffee @@ -0,0 +1,257 @@ +class App.UserOrganizationAutocompletion extends App.Controller + events: + 'hide.bs.dropdown .js-recipientDropdown': 'hideOrganisationMembers' + 'click .js-organisation': 'showOrganisationMembers' + 'click .js-back': 'hideOrganisationMembers' + 'click .js-user': 'selectUser' + 'click .js-user-new': 'newUser' + + constructor: (params) -> + super + + @key = Math.floor( Math.random() * 999999 ).toString() + + if !@attribute.source + @attribute.source = @apiPath + '/search_user_org' + @build() + + element: => + @el + + selectUser: (e) -> + userId = $(e.target).parents('.recipientList-entry').data('user-id') + if !userId + userId = $(e.target).data('user-id') + + @el.find('[name="' + @attribute.name + '"]').val( userId ).trigger('change') + + setUser: -> + userId = @el.find('[name="' + @attribute.name + '"]').val() + return if !userId + user = App.User.find(userId) + name = user.displayName() + if user.email + name += " <#{user.email}>" + @el.find('[name="' + @attribute.name + '_completion"]').val( name ).trigger('change') + + if @callback + @callback(userId) + + buildOrganizationItem: (organization) => + App.view('generic/user_search/item_organization')( + organization: organization + ) + + buildOrganizationMembers: (organization) => + organizationMemebers = $( App.view('generic/user_search/item_organization_members')( + organization: organization + ) ) + for userId in organization.member_ids + user = App.User.fullLocal(userId) + organizationMemebers.append( @buildUserItem(user) ) + + buildUserItem: (user) => + App.view('generic/user_search/item_user')( + user: user + ) + + buildUserNew: => + App.view('generic/user_search/new_user')() + + build: => + @el.html App.view('generic/user_search/input')( + attribute: @attribute + ) + @el.find('[name="' + @attribute.name + '"]').on( + 'change', + (e) => + @setUser() + ) + + @el.find('[name="' + @attribute.name + '_completion"]').on( + 'keyup', + (e) => + item = $(e.target).val() + + #@log('CC', e.keyCode, item) + + # clean input field on ESC + if e.keyCode is 27 + $(e.target).val('') + item = '' + + # ignore arrow keys + return if e.keyCode is 37 + return if e.keyCode is 38 + return if e.keyCode is 39 + return if e.keyCode is 40 + + # ignore shift + return if e.keyCode is 16 + + # ignore ctrl + return if e.keyCode is 17 + + # ignore alt + return if e.keyCode is 18 + + # hide dropdown + @el.find('.recipientList').html('') + @el.find('.recipientList-organisationMembers').remove() + if !item && !@attribute.disableCreateUser + @el.find('.recipientList').append( @buildUserNew() ) + + # show dropdown + if item && ( !@attribute.minLengt || @attribute.minLengt <= item.length ) + execute = => @searchUser(item) + @delay( execute, 400, 'userSearch' ) + ) + + searchUser: (term) => + + @ajax( + id: 'searchUser' + @key + type: 'GET' + url: @attribute.source + data: + query: term + processData: true + success: (data, status, xhr) => + # load assets + App.Collection.loadAssets( data.assets ) + + # build markup + for item in data.result + + # organization + if item.type is 'Organization' + organization = App.Organization.fullLocal( item.id ) + @el.find('.recipientList').append( @buildOrganizationItem(organization) ) + + # users of organization + if organization.member_ids + @el.find('.dropdown-menu').append( @buildOrganizationMembers(organization) ) + + # users + if item.type is 'User' + user = App.User.fullLocal( item.id ) + @el.find('.recipientList').append( @buildUserItem(user) ) + + if !@attribute.disableCreateUser + @el.find('.recipientList').append( @buildUserNew() ) + ) + + showOrganisationMembers: (e) => + e.stopPropagation() + + listEntry = $(e.currentTarget) + organisationId = listEntry.data('organisation-id') + + @recipientList = @$('.recipientList') + @organisationList = @$("##{ organisationId }") + + # move organisation-list to the right and slide it in + + $.Velocity.hook(@organisationList, 'translateX', '100%') + @organisationList.removeClass('hide') + + @organisationList.velocity + properties: + translateX: 0 + options: + speed: 300 + + # fade out list + @recipientList.velocity + properties: + translateX: '-100%' + options: + speed: 300 + complete: => @recipientList.height(@organisationList.height()) + + hideOrganisationMembers: (e) => + e && e.stopPropagation() + + return if !@organisationList + + # fade list back in + @recipientList.velocity + properties: + translateX: 0 + options: + speed: 300 + + # reset list height + + @recipientList.height('') + + # slide out organisation-list and hide it + @organisationList.velocity + properties: + translateX: '100%' + options: + speed: 300 + complete: => @organisationList.addClass('hide') + + newUser: (e) => + e.preventDefault() + new UserNew( + parent: @ + ) + +class UserNew extends App.ControllerModal + constructor: -> + super + @head = 'New User' + @cancel = true + @button = true + + controller = new App.ControllerForm( + el: @el.find('#form-user') + model: App.User + screen: 'edit' + autofocus: true + ) + + @show( controller.form ) + + onSubmit: (e) -> + + e.preventDefault() + params = @formParam(e.target) + + # if no login is given, use emails as fallback + if !params.login && params.email + params.login = params.email + + # find role_id + if !params.role_ids || _.isEmpty( params.role_ids ) + role = App.Role.findByAttribute( 'name', 'Customer' ) + params.role_ids = role.id + @log 'notice', 'updateAttributes', params + + user = new App.User + user.load(params) + + errors = user.validate() + if errors + @log 'error', errors + @formValidate( form: e.target, errors: errors ) + return + + # save user + ui = @ + user.save( + done: -> + + # force to reload object + callbackReload = (user) -> + ui.parent.el.find('[name=customer_id]').val( user.id ).trigger('change') + + # start customer info controller + ui.hide() + App.User.full( @id, callbackReload , true ) + + fail: -> + ui.hide() + ) \ No newline at end of file diff --git a/app/assets/javascripts/app/views/agent_ticket_create.jst.eco b/app/assets/javascripts/app/views/agent_ticket_create.jst.eco index 6cce00c13..3074bec7d 100644 --- a/app/assets/javascripts/app/views/agent_ticket_create.jst.eco +++ b/app/assets/javascripts/app/views/agent_ticket_create.jst.eco @@ -25,189 +25,7 @@