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 56450de6b..8b14bf64e 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee @@ -2,7 +2,11 @@ class App.ControllerForm extends App.Controller constructor: (params) -> for key, value of params @[key] = value - @attribute_count = 0 + + if !@handlers + @handlers = [] + @handlers.push @_showHideToggle + @handlers.push @_requiredMandantoryToggle if !@form @form = @formGen() @@ -23,37 +27,62 @@ class App.ControllerForm extends App.Controller fieldset = $('
') - for attribute_clean in @model.configure_attributes - attribute = _.clone( attribute_clean ) + # collect form attributes + @attributes = [] + if @model.attributesGet + attributesClean = @model.attributesGet(@screen) + else + attributesClean = App.Model.attributesGet(@screen, @model.configure_attributes ) - if !attribute.readonly && ( !@required || @required && attribute[@required] ) + for attributeName, attribute of attributesClean - @attribute_count = @attribute_count + 1 + # ignore read only attributes + if !attribute.readonly - # add item - item = @formGenItem( attribute, @model.className, fieldset ) - item.appendTo(fieldset) + # check generic filter + if @filter && !attribute.filter + if @filter[ attributeName ] + attribute.filter = @filter[ attributeName ] - # if password, add confirm password item - if attribute.type is 'password' + @attributes.push attribute - # set selected value passed on current params - if @params - if attribute.name of @params - attribute.value = @params[attribute.name] + attribute_count = 0 + className = @model.className + '_' + Math.floor( Math.random() * 999999 ).toString() - # rename display and name to _confirm - if !attribute.single - attribute.display = attribute.display + ' (confirm)' - attribute.name = attribute.name + '_confirm'; - item = @formGenItem( attribute, @model.className, fieldset ) - item.appendTo(fieldset) + for attribute in @attributes + attribute_count = attribute_count + 1 + + # add item + item = @formGenItem( attribute, className, fieldset, attribute_count ) + item.appendTo(fieldset) + + # if password, add confirm password item + if attribute.type is 'password' + + # set selected value passed on current params + if @params + if attribute.name of @params + attribute.value = @params[attribute.name] + + # rename display and name to _confirm + if !attribute.single + attribute.display = attribute.display + ' (confirm)' + attribute.name = attribute.name + '_confirm'; + item = @formGenItem( attribute, className, fieldset, attribute_count ) + item.appendTo(fieldset) if @fullForm if !@formClass @formClass = '' fieldset = $('').prepend( fieldset ) + # bind form events + if @events + for eventSelector, callback of @events + do (eventSelector, callback) => + evs = eventSelector.split(' ') + fieldset.find( evs[1] ).bind(evs[0], (e) => callback(e) ) + # return form return fieldset @@ -131,14 +160,14 @@ class App.ControllerForm extends App.Controller ### - formGenItem: (attribute_config, classname, form ) -> - attribute = _.clone( attribute_config ) + formGenItem: (attribute_config, classname, form, attribute_count ) -> + attribute = clone( attribute_config ) # create item id attribute.id = classname + '_' + attribute.name # set autofocus - if @autofocus && @attribute_count is 1 + if @autofocus && attribute_count is 1 attribute.autofocus = 'autofocus' # set required option @@ -234,6 +263,22 @@ class App.ControllerForm extends App.Controller else if attribute.tag is 'select' item = $( App.view('generic/select')( attribute: attribute ) ) + # date + else if attribute.tag is 'date' + attribute.type = 'text' + item = $( App.view('generic/date')( attribute: attribute ) ) + #item.datetimepicker({ + # format: 'Y.m.d' + #}); + + # date + else if attribute.tag is 'datetime' + attribute.type = 'text' + item = $( App.view('generic/date')( attribute: attribute ) ) + #item.datetimepicker({ + # format: 'Y.m.d H:i' + #}); + # timezone else if attribute.tag is 'timezone' attribute.options = [] @@ -717,7 +762,7 @@ class App.ControllerForm extends App.Controller b = (event, item) => # set html form attribute - $(local_attribute).val(item.id) + $(local_attribute).val(item.id).trigger('change') $(local_attribute + '_autocompletion_value_shown').val(item.value) # call calback @@ -738,8 +783,11 @@ class App.ControllerForm extends App.Controller } ) ### + source = attribute.source + if typeof(source) is 'string' + source = source.replace('#{@apiPath}', App.Config.get('api_path') ); $(local_attribute_full).autocomplete( - source: attribute.source, + source: source, minLength: attribute.minLengt || 3, select: ( event, ui ) => b(event, ui.item) @@ -1221,63 +1269,12 @@ class App.ControllerForm extends App.Controller else item = $( App.view('generic/input')( attribute: attribute ) ) - if attribute.onchange - if typeof attribute.onchange is 'function' - attribute.onchange(attribute) - else - for i of attribute.onchange - a = i.split(/__/) - if a[1] - if a[0] is attribute.name - @attribute = attribute - @classname = classname - @attributes_clean = attributes_clean - @change = a - b = => -# console.log 'aaa', @attribute - attribute = @attribute - change = @change - classname = @classname - attributes_clean = @attributes_clean - ui = @ - $( '#' + @attribute.id ).bind('change', -> - ui.log 'change', @, attribute, change - ui.log change[0] + ' has changed - changing ' + change[1] - - item = $( ui.formGenItem(attribute, classname, attributes_clean) ) - ui.log item, classname - ) - App.Delay.set( b, 100, undefined, 'form_change' ) -# if attribute.onchange[] - - ui = @ - item.bind('change', -> - if ui.form_data - params = App.ControllerForm.params(@) - for i of ui.form_data - a = i.split(/__/) - if a[1] && a[0] is attribute.name - newListAttribute = i - changedAttribute = a[0] - toChangeAttribute = a[1] - - # get new option list - newListAttributes = ui['form_data'][newListAttribute][ params['group_id'] ] - - # find element to replace - for item in ui.model.configure_attributes - if item.name is toChangeAttribute - item.display = false - item['filter'][toChangeAttribute] = newListAttributes - if params[changedAttribute] - item.default = params[toChangeAttribute] - if !item.default - delete item['default'] - newElement = ui.formGenItem( item, classname, form ) - - # replace new option list - form.find('[name="' + toChangeAttribute + '"]').replaceWith( newElement ) - ) + if @handlers + item.bind('change', (e) => + params = App.ControllerForm.params( $(e.target) ) + for handler in @handlers + handler(params, attribute, @attributes, classname, form, @) + ) # bind dependency if @dependency @@ -1339,6 +1336,44 @@ class App.ControllerForm extends App.Controller el.find('[name="' + key + '"]').parents('.form-group').addClass('hide') el.find('[name="' + key + '"]').addClass('is-hidden') + _mandantory: (name, el = @el) -> + if !_.isArray(name) + name = [name] + for key in name + el.find('[name="' + key + '"]').attr('required', true) + el.find('[name="' + key + '"]').parents('.form-group').find('label span').html('*') + + _optional: (name, el = @el) -> + if !_.isArray(name) + name = [name] + for key in name + el.find('[name="' + key + '"]').attr('required', false) + el.find('[name="' + key + '"]').parents('.form-group').find('label span').html('') + + _showHideToggle: (params, changedAttribute, attributes, classname, form, ui) => + for attribute in attributes + if attribute.shown_if + hit = false + for refAttribute, refValue of attribute.shown_if + if params[refAttribute] && params[refAttribute].toString() is refValue.toString() + hit = true + if hit + ui._show(attribute.name) + else + ui._hide(attribute.name) + + _requiredMandantoryToggle: (params, changedAttribute, attributes, classname, form, ui) => + for attribute in attributes + if attribute.required_if + hit = false + for refAttribute, refValue of attribute.required_if + if params[refAttribute] && params[refAttribute].toString() is refValue.toString() + hit = true + if hit + ui._mandantory(attribute.name) + else + ui._optional(attribute.name) + # sort attribute.options _sortOptions: (attribute) -> @@ -1399,6 +1434,7 @@ class App.ControllerForm extends App.Controller list = [] if attribute.filter + App.Log.debug 'ControllerForm', '_getRelationOptionList:filter', attribute.filter # function based filter @@ -1426,6 +1462,22 @@ class App.ControllerForm extends App.Controller if record['id'] is key list.push record + # data based filter + else if attribute.filter && _.isArray attribute.filter + + App.Log.debug 'ControllerForm', '_getRelationOptionList:filter-array', attribute.filter + + # check all records + for record in App[ attribute.relation ].search( sortBy: attribute.sortBy ) + + # check all filter attributes + for key in attribute.filter + + # check all filter values as array + # if it's matching, use it for selection + if record['id'] is key + list.push record + # no data filter matched else App.Log.debug 'ControllerForm', '_getRelationOptionList:filter-data no filter matched' @@ -1512,8 +1564,9 @@ class App.ControllerForm extends App.Controller validate: (params) -> App.Model.validate( - model: @model, - params: params, + model: @model + params: params + screen: @screen ) # get all params of the form @@ -1637,13 +1690,8 @@ class App.ControllerForm extends App.Controller # show new errors for key, msg of data.errors - $(data.form).parents().find('[name*="' + key + '"]').parents('div .form-group').addClass('has-error') - $(data.form).parents().find('[name*="' + key + '"]').parent().find('.help-inline').html(msg) + $(data.form).parents().find('[name="' + key + '"]').parents('div .form-group').addClass('has-error') + $(data.form).parents().find('[name="' + key + '"]').parent().find('.help-inline').html(msg) # set autofocus $(data.form).parents().find('.has-error').find('input, textarea').first().focus() - -# # enable form again -# if $(data.form).parents().find('.has-error').html() -# @formEnable(data.form) - diff --git a/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee index 259554e34..53eb612ce 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee @@ -7,11 +7,11 @@ class App.ControllerGenericNew extends App.ControllerModal @html App.view('generic/admin/new')( head: @pageData.object ) new App.ControllerForm( - el: @el.find('#object_new'), - model: App[ @genericObject ], - params: @item, - required: @required, - autofocus: true, + el: @el.find('#object_new') + model: App[ @genericObject ] + params: @item + screen: @screen || 'edit' + autofocus: true ) @modalShow() @@ -59,7 +59,7 @@ class App.ControllerGenericEdit extends App.ControllerModal el: @el.find('#object_edit') model: App[ @genericObject ] params: @item - required: @required + screen: @screen || 'edit' autofocus: true ) @modalShow() diff --git a/app/assets/javascripts/app/controllers/_application_controller_table.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_table.js.coffee index 263aeb88e..295ac7565 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_table.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_table.js.coffee @@ -99,6 +99,7 @@ class App.ControllerTable extends App.Controller data.model = {} overview = data.overview || data.model.configure_overview || [] attributes = data.attributes || data.model.configure_attributes || {} + attributes = App.Model.attributesGet(false, attributes) destroy = data.model.configure_delete # check if table is empty @@ -146,13 +147,13 @@ class App.ControllerTable extends App.Controller header = [] for item in overview headerFound = false - for attribute in attributes - if attribute.name is item + for attributeName, attribute of attributes + if attributeName is item headerFound = true header.push attribute else rowWithoutId = item + '_id' - if attribute.name is rowWithoutId + if attributeName is rowWithoutId headerFound = true header.push 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 5bb518847..828699b36 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee @@ -14,7 +14,7 @@ class App.TicketCreate extends App.Controller # set title @form_id = App.ControllerForm.formId() - @edit_form = undefined + @form_meta = undefined # set article attributes default_type = 'call_inbound' @@ -25,14 +25,17 @@ class App.TicketCreate extends App.Controller sender: 'Customer' article: 'phone' title: 'Call Inbound' + screen: 'create_phone_in' call_outbound: sender: 'Agent' article: 'phone' title: 'Call Outbound' + screen: 'create_phone_out' email: sender: 'Agent' article: 'email' title: 'Email' + screen: 'create_email_out' @article_attributes = article_sender_type_map[@type] # remember split info if exists @@ -57,9 +60,9 @@ class App.TicketCreate extends App.Controller meta: => text = App.i18n.translateInline( @article_attributes['title'] ) - subject = @el.find('[name=subject]').val() - if subject - text = "#{text}: #{subject}" + title = @el.find('[name=title]').val() + if title + text = "#{text}: #{title}" meta = url: @url() head: text @@ -100,7 +103,7 @@ class App.TicketCreate extends App.Controller if cache && !params.ticket_id && !params.article_id # get edit form attributes - @edit_form = cache.edit_form + @form_meta = cache.form_meta # load assets App.Collection.loadAssets( cache.assets ) @@ -108,7 +111,7 @@ class App.TicketCreate extends App.Controller @render() else @ajax( - id: 'ticket_create' + id: 'ticket_create' + @task_key type: 'GET' url: @apiPath + '/ticket_create' data: @@ -121,7 +124,7 @@ class App.TicketCreate extends App.Controller App.Store.write( 'ticket_create_attributes', data ) # get edit form attributes - @edit_form = data.edit_form + @form_meta = data.form_meta # load assets App.Collection.loadAssets( data.assets ) @@ -143,22 +146,6 @@ class App.TicketCreate extends App.Controller render: (template = {}) -> - # set defaults - defaults = - state_id: App.TicketState.findByAttribute( 'name', 'open' ).id - priority_id: App.TicketPriority.findByAttribute( 'name', '2 normal' ).id - - # generate form - configure_attributes = [ - { name: 'customer_id', display: 'Customer', tag: 'autocompletion', type: 'text', limit: 200, null: false, relation: 'User', class: 'span7', autocapitalize: false, help: 'Select the customer of the Ticket or create one.', helpLink: '»', callback: @localUserInfo, source: @apiPath + '/users/search', minLengt: 2 }, - { name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, filter: @edit_form, nulloption: true, relation: 'Group', default: defaults['group_id'], class: 'span7', }, - { name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: true, filter: @edit_form, nulloption: true, relation: 'User', default: defaults['owner_id'], class: 'span7', }, - { name: 'tags', display: 'Tags', tag: 'tag', type: 'text', null: true, default: defaults['tags'], class: 'span7', }, - { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 200, null: false, default: defaults['subject'], class: 'span7', }, - { name: 'body', display: 'Text', tag: 'textarea', rows: 8, null: false, default: defaults['body'], class: 'span7', upload: true }, - { name: 'state_id', display: 'State', tag: 'select', multiple: false, null: false, filter: @edit_form, relation: 'TicketState', default: defaults['state_id'], translate: true, class: 'medium' }, - { name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: false, filter: @edit_form, relation: 'TicketPriority', default: defaults['priority_id'], translate: true, class: 'medium' }, - ] @html App.view('agent_ticket_create')( head: 'New Ticket' title: @article_attributes['title'] @@ -172,14 +159,50 @@ class App.TicketCreate extends App.Controller else if App.TaskManager.get(@task_key) && !_.isEmpty( App.TaskManager.get(@task_key).state ) params = App.TaskManager.get(@task_key).state + formChanges = (params, attribute, attributes, classname, form, ui) => + if @form_meta.dependencies && @form_meta.dependencies[attribute.name] + dependency = @form_meta.dependencies[attribute.name][ parseInt(params[attribute.name]) ] + if dependency + + for fieldNameToChange of dependency + filter = [] + if dependency[fieldNameToChange] + filter = dependency[fieldNameToChange] + + # find element to replace + for item in attributes + if item.name is fieldNameToChange + item.display = false + item['filter'] = {} + item['filter'][ fieldNameToChange ] = filter + item.default = params[item.name] + #if !item.default + # delete item['default'] + newElement = ui.formGenItem( item, classname, form ) + + # replace new option list + form.find('[name="' + fieldNameToChange + '"]').replaceWith( newElement ) + new App.ControllerForm( - el: @el.find('.ticket_create') - form_id: @form_id - model: - configure_attributes: configure_attributes - className: 'create_' + @type + '_' + @id + el: @el.find('.ticket-form') + form_id: @form_id + model: App.Ticket + screen: @article_attributes['screen'] + events: + 'change [name=customer_id]': @localUserInfo + handlers: [ + formChanges + ] + filter: @form_meta.filter autofocus: true - form_data: @edit_form + params: params + ) + + new App.ControllerForm( + el: @el.find('.article-form') + form_id: @form_id + model: App.TicketArticle + screen: @article_attributes['screen'] params: params ) @@ -193,20 +216,23 @@ class App.TicketCreate extends App.Controller # show text module UI @textModule = new App.WidgetTextModule( - el: @el.find('.ticket-create').find('textarea') + el: @el.find('form').find('textarea') ) # start auto save @autosave() - localUserInfo: (params) => + localUserInfo: (e) => + + params = App.ControllerForm.params( $(e.target).closest('form') ) # update text module UI callback = (user) => - @textModule.reload( - ticket: - customer: user - ) + if @textModule + @textModule.reload( + ticket: + customer: user + ) @userInfo( user_id: params.customer_id @@ -234,7 +260,7 @@ class App.TicketCreate extends App.Controller params.title = params.subject # create ticket - object = new App.Ticket + ticket = new App.Ticket # find sender_id sender = App.TicketArticleSender.findByAttribute( 'name', @article_attributes['sender'] ) @@ -248,6 +274,7 @@ class App.TicketCreate extends App.Controller params['article'] = { to: (group && group.name) || '' from: params.customer_id_autocompletion + cc: params.cc subject: params.subject body: params.body type_id: type.id @@ -258,6 +285,7 @@ class App.TicketCreate extends App.Controller params['article'] = { from: (group && group.name) || '' to: params.customer_id_autocompletion + cc: params.cc subject: params.subject body: params.body type_id: type.id @@ -265,15 +293,30 @@ class App.TicketCreate extends App.Controller form_id: @form_id } - object.load(params) + ticket.load(params) # validate form - errors = object.validate() + ticketErrors = ticket.validate( + screen: @article_attributes['screen'] + ) + article = new App.TicketArticle + article.load(params['article']) + articleErrors = article.validate( + screen: @article_attributes['screen'] + ) + for key, value of articleErrors + if !ticketErrors + ticketErrors = {} + ticketErrors[key] = value # show errors in form - if errors - @log 'error', errors - @formValidate( form: e.target, errors: errors ) + if ticketErrors + @log 'error', ticketErrors + @formValidate( + form: e.target + errors: ticketErrors + screen: @article_attributes['screen'] + ) # save ticket, create article else @@ -281,7 +324,7 @@ class App.TicketCreate extends App.Controller # disable form @formDisable(e) ui = @ - object.save( + ticket.save( done: -> # notify UI @@ -322,10 +365,10 @@ class UserNew extends App.ControllerModal @html App.view('agent_user_create')( head: 'New User' ) new App.ControllerForm( - el: @el.find('#form-user'), - model: App.User, - required: 'quick', - autofocus: true, + el: @el.find('#form-user') + model: App.User + screen: 'edit' + autofocus: true ) @modalShow() diff --git a/app/assets/javascripts/app/controllers/customer_ticket_create.js.coffee b/app/assets/javascripts/app/controllers/customer_ticket_create.js.coffee index ce65556fb..96050555f 100644 --- a/app/assets/javascripts/app/controllers/customer_ticket_create.js.coffee +++ b/app/assets/javascripts/app/controllers/customer_ticket_create.js.coffee @@ -16,8 +16,6 @@ class Index extends App.ControllerContent @fetch(params) @navupdate '#customer_ticket_new' - @edit_form = undefined - # get data / in case also ticket data for split fetch: (params) -> @@ -26,9 +24,6 @@ class Index extends App.ControllerContent if cache - # get edit form attributes - @edit_form = cache.edit_form - # load assets App.Collection.loadAssets( cache.assets ) @@ -44,9 +39,6 @@ class Index extends App.ControllerContent # cache request App.Store.write( 'ticket_create_attributes', data ) - # get edit form attributes - @edit_form = data.edit_form - # load assets App.Collection.loadAssets( data.assets ) @@ -87,25 +79,25 @@ class Index extends App.ControllerContent return item if item && _.contains( group_ids, item.id.toString() ) ) - # generate form - configure_attributes = [ - { name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, filter: groupFilter, nulloption: true, relation: 'Group', default: defaults['group_id'], class: 'span7', }, -# { name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: true, filter: @edit_form, nulloption: true, relation: 'User', default: defaults['owner_id'], class: 'span7', }, - { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: false, default: defaults['subject'], class: 'span7', }, - { name: 'body', display: 'Text', tag: 'textarea', rows: 10, null: false, default: defaults['body'], class: 'span7', upload: true }, -# { name: 'state_id', display: 'State', tag: 'select', multiple: false, null: false, filter: @edit_form, relation: 'TicketState', default: defaults['state_id'], translate: true, class: 'medium' }, -# { name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: false, filter: @edit_form, relation: 'TicketPriority', default: defaults['priority_id'], translate: true, class: 'medium' }, - ] @html App.view('customer_ticket_create')( head: 'New Ticket' ) new App.ControllerForm( - el: @el.find('#form_create') - form_id: @form_id - model: - configure_attributes: configure_attributes - className: 'create' + el: @el.find('.ticket-form') + form_id: @form_id + model: App.Ticket + screen: 'create_web' autofocus: true - form_data: @edit_form + filter: + group_id: groupFilter + params: defaults + ) + + new App.ControllerForm( + el: @el.find('.article-form') + form_id: @form_id + model: App.TicketArticle + screen: 'create_web' + params: defaults ) new App.ControllerDrox( @@ -128,19 +120,21 @@ class Index extends App.ControllerContent params.customer_id = @Session.get('id') # set prio - priority = App.TicketPriority.findByAttribute( 'name', '2 normal' ) - params.priority_id = priority.id + if !params.priority_id + priority = App.TicketPriority.findByAttribute( 'name', '2 normal' ) + params.priority_id = priority.id # set state - state = App.TicketState.findByAttribute( 'name', 'new' ) - params.state_id = state.id + if !params.state_id + state = App.TicketState.findByAttribute( 'name', 'new' ) + params.state_id = state.id # fillup params if !params.title params.title = params.subject # create ticket - object = new App.Ticket + ticket = new App.Ticket @log 'CustomerTicketCreate', 'notice', 'updateAttributes', params # find sender_id @@ -160,16 +154,27 @@ class Index extends App.ControllerContent form_id: @form_id } - object.load(params) + ticket.load(params) # validate form - errors = object.validate() + ticketErrors = ticket.validate( + screen: 'create_web' + ) + article = new App.TicketArticle + article.load(params['article']) + articleErrors = article.validate( + screen: 'create_web' + ) + for key, value of articleErrors + if !ticketErrors + ticketErrors = {} + ticketErrors[key] = value # show errors in form - if errors - @log 'CustomerTicketCreate', 'error', 'can not create', errors + if ticketErrors + @log 'CustomerTicketCreate', 'error', 'can not create', ticketErrors - @formValidate( form: e.target, errors: errors ) + @formValidate( form: e.target, errors: ticketErrors ) # save ticket, create article else @@ -177,7 +182,7 @@ class Index extends App.ControllerContent # disable form @formDisable(e) ui = @ - object.save( + ticket.save( done: -> # redirect to zoom @@ -189,7 +194,4 @@ class Index extends App.ControllerContent ) App.Config.set( 'customer_ticket_new', Index, 'Routes' ) - -#App.Config.set( 'CustomerTicketNew', { prio: 1600, parent: '', name: 'New Ticket', target: '#customer_ticket_new', role: ['Customer'] }, 'NavBar' ) App.Config.set( 'CustomerTicketNew', { prio: 8000, parent: '', name: 'New', target: '#customer_ticket_new', role: ['Customer'] }, 'NavBarRight' ) - diff --git a/app/assets/javascripts/app/controllers/signup.js.coffee b/app/assets/javascripts/app/controllers/signup.js.coffee index a3da92107..35abfb2cc 100644 --- a/app/assets/javascripts/app/controllers/signup.js.coffee +++ b/app/assets/javascripts/app/controllers/signup.js.coffee @@ -32,7 +32,7 @@ class Index extends App.ControllerContent new App.ControllerForm( el: @el.find('#form-signup') model: App.User - required: 'signup' + screen: 'signup' autofocus: true ) diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee index 7006e03ef..dd8bbbcce 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee @@ -7,7 +7,7 @@ class App.TicketZoom extends App.Controller @navupdate '#' - @edit_form = undefined + @form_meta = undefined @ticket_id = params.ticket_id @article_id = params.article_id @signature = undefined @@ -111,7 +111,7 @@ class App.TicketZoom extends App.Controller @ticket_article_ids = data.ticket_article_ids # get edit form attributes - @edit_form = data.edit_form + @form_meta = data.form_meta # get signature @signature = data.signature @@ -181,7 +181,7 @@ class App.TicketZoom extends App.Controller new Edit( ticket: @ticket el: @el.find('.edit') - edit_form: @edit_form + form_meta: @form_meta task_key: @task_key ui: @ ) @@ -331,57 +331,55 @@ class Edit extends App.Controller formChanged: !_.isEmpty( App.TaskManager.get(@task_key).state ) ) - @configure_attributes_ticket = [ - { name: 'state_id', display: 'State', tag: 'select', multiple: false, null: true, relation: 'TicketState', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' }, - { name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: true, relation: 'TicketPriority', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' }, - { name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: true, relation: 'Group', filter: @edit_form, class: 'span2', item_class: 'pull-left' }, - { name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: true, relation: 'User', filter: @edit_form, nulloption: true, class: 'span2', item_class: 'pull-left' }, - ] - if @isRole('Customer') - @configure_attributes_ticket = [ - { name: 'state_id', display: 'State', tag: 'select', multiple: false, null: true, relation: 'TicketState', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' }, - { name: 'priority_id', display: 'Priority', tag: 'select', multiple: false, null: true, relation: 'TicketPriority', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' }, - ] - - @configure_attributes_article = [ - { name: 'type_id', display: 'Type', tag: 'select', multiple: false, null: true, relation: 'TicketArticleType', filter: @edit_form, default: '9', translate: true, class: 'medium' }, - { name: 'internal', display: 'Visibility', tag: 'select', null: true, options: { true: 'internal', false: 'public' }, class: 'medium', item_class: '', default: false }, - { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true }, - { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true }, -# { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true }, - { name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, - { name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true }, - ] - if @isRole('Customer') - @configure_attributes_article = [ - { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true }, - { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true }, -# { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true }, - { name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, - { name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true }, - ] - @form_id = App.ControllerForm.formId() - defaults = ticket + defaults = ticket.attributes() + if @isRole('Customer') + delete defaults['state_id'] + delete defaults['state'] if !_.isEmpty( App.TaskManager.get(@task_key).state ) defaults = App.TaskManager.get(@task_key).state - new App.ControllerForm( - el: @el.find('.form-ticket-update') - form_id: @form_id - model: - configure_attributes: @configure_attributes_ticket - className: 'update_ticket_' + ticket.id - params: defaults - form_data: @edit_form - ) + formChanges = (params, attribute, attributes, classname, form, ui) => + if @form_meta.dependencies && @form_meta.dependencies[attribute.name] + dependency = @form_meta.dependencies[attribute.name][ parseInt(params[attribute.name]) ] + if dependency + for fieldNameToChange of dependency + filter = [] + if dependency[fieldNameToChange] + filter = dependency[fieldNameToChange] + + # find element to replace + for item in attributes + if item.name is fieldNameToChange + item.display = false + item['filter'] = {} + item['filter'][ fieldNameToChange ] = filter + item.default = params[item.name] + #if !item.default + # delete item['default'] + newElement = ui.formGenItem( item, classname, form ) + + # replace new option list + form.find('[name="' + fieldNameToChange + '"]').replaceWith( newElement ) + + new App.ControllerForm( + el: @el.find('.form-ticket-update') + form_id: @form_id + model: App.Ticket + screen: 'edit' + handlers: [ + formChanges + ] + filter: @form_meta.filter + params: defaults + ) new App.ControllerForm( el: @el.find('.form-article-update') form_id: @form_id - model: - configure_attributes: @configure_attributes_article - className: 'update_ticket_' + ticket.id - form_data: @edit_form + model: App.TicketArticle + screen: 'edit' + filter: + type_id: [1,9,5] params: defaults dependency: [ { @@ -399,13 +397,24 @@ class Edit extends App.Controller bind: { name: 'type_id' relation: 'TicketArticleType' - value: ['note', 'twitter status', 'twitter direct-message'] + value: ['note', 'phone', 'twitter status'] }, change: { action: 'hide' name: ['to', 'cc'], }, }, + { + bind: { + name: 'type_id' + relation: 'TicketArticleType' + value: ['twitter direct-message'] + }, + change: { + action: 'show' + name: ['to'], + }, + }, ] ) @@ -453,10 +462,16 @@ class Edit extends App.Controller @autosaveStop() params = @formParam(e.target) + # get ticket ticket = App.Ticket.fullLocal( @ticket.id ) @log 'notice', 'update', params, ticket + # update local ticket + + # create local article + + # find sender_id if @isRole('Customer') sender = App.TicketArticleSender.findByAttribute( 'name', 'Customer' ) @@ -469,17 +484,16 @@ class Edit extends App.Controller params.sender_id = sender.id # update ticket - ticket_update = {} - for item in @configure_attributes_ticket - ticket_update[item.name] = params[item.name] + for key, value of params + ticket[key] = value # check owner assignment if !@isRole('Customer') - if !ticket_update['owner_id'] - ticket_update['owner_id'] = 1 + if !ticket['owner_id'] + ticket['owner_id'] = 1 # check if title exists - if !ticket_update['title'] && !ticket.title + if !ticket['title'] alert( App.i18n.translateContent('Title needed') ) return @@ -505,22 +519,32 @@ class Edit extends App.Controller @autosaveStart() return - ticket.load( ticket_update ) - @log 'notice', 'update ticket', ticket_update, ticket + # submit ticket & article + @log 'notice', 'update ticket', ticket # disable form @formDisable(e) # validate ticket - errors = ticket.validate() + errors = ticket.validate( + screen: 'edit' + ) if errors @log 'error', 'update', errors + + @log 'error', errors + @formValidate( + form: e.target + errors: errors + screen: 'edit' + ) @formEnable(e) @autosaveStart() return # validate article - if params['body'] + articleAttributes = App.TicketArticle.attributesGet( 'edit' ) + if params['body'] || ( articleAttributes['body'] && articleAttributes['body']['null'] is false ) article = new App.TicketArticle params.from = @Session.get( 'firstname' ) + ' ' + @Session.get( 'lastname' ) params.ticket_id = ticket.id @@ -534,6 +558,11 @@ class Edit extends App.Controller errors = article.validate() if errors @log 'error', 'update article', errors + @formValidate( + form: e.target + errors: errors + screen: 'edit' + ) @formEnable(e) @autosaveStart() return diff --git a/app/assets/javascripts/app/controllers/widget/user.js.coffee b/app/assets/javascripts/app/controllers/widget/user.js.coffee index ac8b48d0d..a6cdf4f7f 100644 --- a/app/assets/javascripts/app/controllers/widget/user.js.coffee +++ b/app/assets/javascripts/app/controllers/widget/user.js.coffee @@ -109,13 +109,12 @@ class App.WidgetUser extends App.ControllerDrox edit: (e) => e.preventDefault() new App.ControllerGenericEdit( - id: @user_id, - genericObject: 'User', - required: 'quick', - pageData: { - title: 'Users', - object: 'User', - objects: 'Users', - }, + id: @user_id + genericObject: 'User' + screen: 'edit' + pageData: + title: 'Users' + object: 'User' + objects: 'Users' callback: @render ) diff --git a/app/assets/javascripts/app/lib/app_post/auth.js.coffee b/app/assets/javascripts/app/lib/app_post/auth.js.coffee index 20e1bf495..a9bb71617 100644 --- a/app/assets/javascripts/app/lib/app_post/auth.js.coffee +++ b/app/assets/javascripts/app/lib/app_post/auth.js.coffee @@ -69,12 +69,26 @@ class App.Auth App.Event.trigger( 'auth:logout' ) App.Event.trigger( 'ui:rerender' ) + # update model definition + if data.models + for model, attributes of data.models + for attribute in attributes + App[model].attributes.push attribute.name + App[model].configure_attributes.push attribute + return false; # clear local store if type isnt 'check' App.Event.trigger( 'clearStore' ) + # update model definition + if data.models + for model, attributes of data.models + for attribute in attributes + App[model].attributes.push attribute.name + App[model].configure_attributes.push attribute + # update config for key, value of data.config App.Config.set( key, value ) @@ -129,4 +143,3 @@ class App.Auth App.Event.trigger( 'auth:logout' ) App.Event.trigger( 'ui:rerender' ) App.Event.trigger( 'clearStore' ) - diff --git a/app/assets/javascripts/app/models/_application_model.js.coffee b/app/assets/javascripts/app/models/_application_model.js.coffee index 2d4cfca2c..4eda4c77f 100644 --- a/app/assets/javascripts/app/models/_application_model.js.coffee +++ b/app/assets/javascripts/app/models/_application_model.js.coffee @@ -64,19 +64,17 @@ class App.Model extends Spine.Model return '???' @validate: ( data = {} ) -> - attributes = _.clone( data['model'].configure_attributes ) - return if !attributes - # check params of screen if screen is requested - if data['screen'] - for attribute in attributes - if attribute.screen - if attribute && attribute.screen && attribute.screen[ data['screen'] ] && !_.isEmpty(attribute.screen[ data['screen'] ]) - for item, value of attribute.screen[ data['screen'] ] - attribute[item] = value + # based on model attrbutes + if App[ data['model'] ] && App[ data['model'] ].attributesGet + attributes = App[ data['model'] ].attributesGet( data['screen'] ) + + # based on custom attributes + else if data['model'].configure_attributes + attributes = App.Model.attributesGet( data['screen'], data['model'].configure_attributes ) # check required_if attributes - for attribute in attributes + for attributeName, attribute of attributes if attribute['required_if'] for key, values of attribute['required_if'] @@ -98,7 +96,7 @@ class App.Model extends Spine.Model # check attributes/each attribute of object errors = {} - for attribute in attributes + for attributeName, attribute of attributes # only if attribute is not read only if !attribute.readonly @@ -111,25 +109,25 @@ class App.Model extends Spine.Model if parts[0] && !parts[1] # key exists not in hash || value is '' || value is undefined - if !( attribute.name of data['params'] ) || data['params'][attribute.name] is '' || data['params'][attribute.name] is undefined - errors[attribute.name] = 'is required' + if !( attributeName of data['params'] ) || data['params'][attributeName] is '' || data['params'][attributeName] is undefined + errors[attributeName] = 'is required' else if parts[0] && parts[1] && !parts[2] # key exists not in hash || value is '' || value is undefined if !data.params[parts[0]] || !( parts[1] of data.params[parts[0]] ) || data.params[parts[0]][parts[1]] is '' || data.params[parts[0]][parts[1]] is undefined - errors[attribute.name] = 'is required' + errors[attributeName] = 'is required' else throw "can't parse '#{attribute.name}'" # check confirm password - if attribute.type is 'password' && data['params'][attribute.name] && "#{attribute.name}_confirm" of data['params'] + if attribute.type is 'password' && data['params'][attributeName] && "#{attributeName}_confirm" of data['params'] # get confirm password - if data['params'][attribute.name] isnt data['params']["#{attribute.name}_confirm"] - errors[attribute.name] = 'didn\'t match' - errors["#{attribute.name}_confirm"] = '' + if data['params'][attributeName] isnt data['params']["#{attributeName}_confirm"] + errors[attributeName] = 'didn\'t match' + errors["#{attributeName}_confirm"] = '' # return error object if !_.isEmpty(errors) @@ -139,9 +137,41 @@ class App.Model extends Spine.Model # return no errors return + ### + + attributes = App.Model.attributesGet(optionalScreen, optionalAttributesList) + + ### + + @attributesGet: (screen = undefined, attributes = false) -> + if !attributes + attributes = clone( App[ @.className ].configure_attributes ) + else + attributes = clone( attributes ) + + # in case if no configure_attributes exist + return if !attributes + attributesNew = {} + + # check params of screen if screen is requested + if screen + for attribute in attributes + if attribute.screen + if attribute && attribute.screen && attribute.screen[ screen ] && !_.isEmpty( attribute.screen[ screen ] ) + for item, value of attribute.screen[ screen ] + attribute[item] = value + attributesNew[ attribute.name ] = attribute + + if !screen || _.isEmpty( attributesNew ) + console.log(attributesNew) + for attribute in attributes + attributesNew[ attribute.name ] = attribute + + attributesNew + validate: (params = {}) -> App.Model.validate( - model: @constructor + model: @constructor.className params: @ screen: params.screen ) diff --git a/app/assets/javascripts/app/models/user.js.coffee b/app/assets/javascripts/app/models/user.js.coffee index 1f93d32c9..6460efc0d 100644 --- a/app/assets/javascripts/app/models/user.js.coffee +++ b/app/assets/javascripts/app/models/user.js.coffee @@ -6,20 +6,20 @@ class App.User extends App.Model # @hasMany 'roles', 'App.Role' @configure_attributes = [ { name: 'login', display: 'Login', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', autocapitalize: false, signup: false, quick: false }, - { name: 'firstname', display: 'Firstname', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', signup: true, quick: true, info: true, invite_agent: true }, - { name: 'lastname', display: 'Lastname', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', signup: true, quick: true, info: true, invite_agent: true }, - { name: 'email', display: 'Email', tag: 'input', type: 'email', limit: 100, null: false, class: 'span4', signup: true, quick: true, info: true, invite_agent: true }, - { name: 'web', display: 'Web', tag: 'input', type: 'url', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true }, - { name: 'phone', display: 'Phone', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true }, - { name: 'mobile', display: 'Mobile', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true }, - { name: 'fax', display: 'Fax', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true }, - { name: 'organization_id', display: 'Organization', tag: 'select', multiple: false, nulloption: true, null: true, relation: 'Organization', class: 'span4', signup: false, quick: true, info: true }, - { name: 'department', display: 'Department', tag: 'input', type: 'text', limit: 200, null: true, class: 'span4', signup: false, quick: true, info: true }, - { name: 'street', display: 'Street', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true }, - { name: 'zip', display: 'Zip', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true }, - { name: 'city', display: 'City', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, quick: true, info: true }, - { name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 50, null: true, autocomplete: 'off', class: 'span4', signup: true, quick: false, }, - { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true, class: 'span4', quick: true, info: true }, + { name: 'firstname', display: 'Firstname', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', signup: true, info: true, invite_agent: true }, + { name: 'lastname', display: 'Lastname', tag: 'input', type: 'text', limit: 100, null: false, class: 'span4', signup: true, info: true, invite_agent: true }, + { name: 'email', display: 'Email', tag: 'input', type: 'email', limit: 100, null: false, class: 'span4', signup: true, info: true, invite_agent: true }, + { name: 'web', display: 'Web', tag: 'input', type: 'url', limit: 100, null: true, class: 'span4', signup: false, info: true }, + { name: 'phone', display: 'Phone', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, info: true }, + { name: 'mobile', display: 'Mobile', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, info: true }, + { name: 'fax', display: 'Fax', tag: 'input', type: 'phone', limit: 100, null: true, class: 'span4', signup: false, info: true }, + { name: 'organization_id', display: 'Organization', tag: 'select', multiple: false, nulloption: true, null: true, relation: 'Organization', class: 'span4', signup: false, info: true }, + { name: 'department', display: 'Department', tag: 'input', type: 'text', limit: 200, null: true, class: 'span4', signup: false, info: true }, + { name: 'street', display: 'Street', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, info: true }, + { name: 'zip', display: 'Zip', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, info: true }, + { name: 'city', display: 'City', tag: 'input', type: 'text', limit: 100, null: true, class: 'span4', signup: false, info: true }, + { name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 50, null: true, autocomplete: 'off', class: 'span4', signup: true, }, + { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true, class: 'span4', info: true }, { name: 'role_ids', display: 'Roles', tag: 'checkbox', multiple: true, null: false, relation: 'Role', class: 'span4' }, { name: 'group_ids', display: 'Groups', tag: 'checkbox', multiple: true, null: true, relation: 'Group', class: 'span4', invite_agent: true }, { name: 'active', display: 'Active', tag: 'boolean', default: true, null: true, class: 'span4' }, 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 2462ec549..c81bbfd77 100644 --- a/app/assets/javascripts/app/views/agent_ticket_create.jst.eco +++ b/app/assets/javascripts/app/views/agent_ticket_create.jst.eco @@ -14,8 +14,8 @@