Improved handling of unsaved forms.

This commit is contained in:
Martin Edenhofer 2013-07-02 14:37:40 +02:00
parent c735187def
commit beb0efa9f7
6 changed files with 65 additions and 37 deletions

View file

@ -151,7 +151,7 @@ class App.TicketCreate extends App.Controller
render: (template = {}) -> render: (template = {}) ->
# set defaults # set defaults
defaults = template['options'] || @form_state || {} defaults = template['options'] || App.TaskManager.get(@task_key).state || {}
if !( 'ticket_state_id' of defaults ) if !( 'ticket_state_id' of defaults )
defaults['ticket_state_id'] = App.Collection.findByAttribute( 'TicketState', 'name', 'open' ).id defaults['ticket_state_id'] = App.Collection.findByAttribute( 'TicketState', 'name', 'open' ).id
if !( 'ticket_priority_id' of defaults ) if !( 'ticket_priority_id' of defaults )

View file

@ -31,7 +31,7 @@ class App.TicketZoom extends App.Controller
@log 'notice', 'TRY', data.updated_at, ticket.updated_at @log 'notice', 'TRY', data.updated_at, ticket.updated_at
if data.updated_at isnt ticket.updated_at if data.updated_at isnt ticket.updated_at
@fetch( @ticket_id, false ) @fetch( @ticket_id, false )
@delay( update, 2000, 'ticket-zoom-' + @ticket_id ) @delay( update, 1800, 'ticket-zoom-' + @ticket_id )
'ticket-zoom-' + @ticket_id 'ticket-zoom-' + @ticket_id
) )
@ -63,14 +63,18 @@ class App.TicketZoom extends App.Controller
autosave: => autosave: =>
@auto_save_key = 'zoom' + @id @auto_save_key = 'zoom' + @id
@autosaveLast = _.clone( @formDefault )
update = => update = =>
data = @formParam( @el.find('.ticket-update') ) currentData = @formParam( @el.find('.ticket-update') )
diff = difference( @autosaveLast, data ) diff = difference( @autosaveLast, currentData )
if !@autosaveLast || ( diff && !_.isEmpty( diff ) ) if !@autosaveLast || ( diff && !_.isEmpty( diff ) )
@autosaveLast = data @autosaveLast = currentData
@log 'notice', 'form hash changed', diff, data @log 'notice', 'form hash changed', diff, currentData
App.TaskManager.update( @task_key, { 'state': data }) @el.find('.ticket-update').parent().addClass('form-changed')
@interval( update, 10000, @id, @auto_save_key ) @el.find('.ticket-update').parent().parent().find('.reset-message').show()
App.TaskManager.update( @task_key, { 'state': currentData })
@interval( update, 1500, @id, @auto_save_key )
fetch: (ticket_id, force) -> fetch: (ticket_id, force) ->
@ -98,15 +102,15 @@ class App.TicketZoom extends App.Controller
if !_.isEmpty(diff) && data.ticket.updated_by_id isnt @Session.all().id if !_.isEmpty(diff) && data.ticket.updated_by_id isnt @Session.all().id
App.TaskManager.notify( @task_key ) App.TaskManager.notify( @task_key )
# rerender edit box
@editDone = false
# remember current data # remember current data
@dataLastCall = data @dataLastCall = data
@load(data, force) @load(data, force)
App.Store.write( @key, data ) App.Store.write( @key, data )
# start auto save
@autosave()
error: (xhr, status, error) => error: (xhr, status, error) =>
# do not close window if request is aborted # do not close window if request is aborted
@ -168,8 +172,14 @@ class App.TicketZoom extends App.Controller
@ArticleView() @ArticleView()
if force || !@editDone if force || !@editDone
# reset form on force reload
if force && _.isEmpty( App.TaskManager.get(@task_key).state )
App.TaskManager.update( @task_key, { 'state': {} })
@editDone = true @editDone = true
@Edit()
# rerender widget if it hasn't changed
if !@editWidget || _.isEmpty( App.TaskManager.get(@task_key).state )
@editWidget = @Edit()
# show text module UI # show text module UI
if !@isRole('Customer') if !@isRole('Customer')
@ -214,7 +224,6 @@ class App.TicketZoom extends App.Controller
new Edit( new Edit(
ticket: @ticket ticket: @ticket
el: @el.find('.edit') el: @el.find('.edit')
form_state: @form_state
edit_form: @edit_form edit_form: @edit_form
task_key: @task_key task_key: @task_key
ui: @ ui: @
@ -319,7 +328,8 @@ class TicketAction extends App.Controller
class Edit extends App.Controller class Edit extends App.Controller
events: events:
'click .submit': 'update' 'click .submit': 'update'
'click [data-type="reset"]': 'reset'
constructor: -> constructor: ->
super super
@ -332,6 +342,7 @@ class Edit extends App.Controller
@html App.view('ticket_zoom/edit')( @html App.view('ticket_zoom/edit')(
ticket: ticket ticket: ticket
isCustomer: @isRole('Customer') isCustomer: @isRole('Customer')
formChanged: !_.isEmpty( App.TaskManager.get(@task_key).state )
) )
@configure_attributes_ticket = [ @configure_attributes_ticket = [
@ -365,7 +376,9 @@ class Edit extends App.Controller
] ]
@form_id = App.ControllerForm.formId() @form_id = App.ControllerForm.formId()
defaults = @form_state || ticket defaults = ticket
if !_.isEmpty( App.TaskManager.get(@task_key).state )
defaults = App.TaskManager.get(@task_key).state
new App.ControllerForm( new App.ControllerForm(
el: @el.find('.form-ticket-update') el: @el.find('.form-ticket-update')
form_id: @form_id form_id: @form_id
@ -413,7 +426,10 @@ class Edit extends App.Controller
@el.find('textarea').elastic() @el.find('textarea').elastic()
# remember form defaults # remember form defaults
@formDefault = @formParam( @el.find('.ticket-update') ) @ui.formDefault = @formParam( @el.find('.ticket-update') )
# start auto save
@ui.autosave()
# enable user popups # enable user popups
@userPopups() @userPopups()
@ -498,6 +514,10 @@ class Edit extends App.Controller
errors = article.validate() errors = article.validate()
if errors if errors
@log 'error', 'update article', errors @log 'error', 'update article', errors
# reset form after save
App.TaskManager.update( @task_key, { 'state': {} })
article.save( article.save(
success: (r) => success: (r) =>
@ui.fetch( ticket.id, true ) @ui.fetch( ticket.id, true )
@ -505,11 +525,10 @@ class Edit extends App.Controller
@log 'error', 'update article', r @log 'error', 'update article', r
) )
else else
@ui.fetch( ticket.id, true ) # reset form after save
App.TaskManager.update( @task_key, { 'state': {} })
# reset form after save @ui.fetch( ticket.id, true )
App.TaskManager.update( @task_key, { 'state': undefined })
@ui.form_state = undefined
) )
# errors = article.validate() # errors = article.validate()
@ -517,6 +536,11 @@ class Edit extends App.Controller
# @formValidate( form: e.target, errors: errors ) # @formValidate( form: e.target, errors: errors )
return false return false
reset: (e) =>
e.preventDefault()
App.TaskManager.update( @task_key, { 'state': {} })
@render()
class ArticleView extends App.Controller class ArticleView extends App.Controller
events: events:

View file

@ -9,10 +9,10 @@ class App.TaskManager
_instance ?= new _taskManagerSingleton _instance ?= new _taskManagerSingleton
_instance.all() _instance.all()
@add: ( key, callback, params, to_not_show, state ) -> @add: ( key, callback, params, to_not_show ) ->
if _instance == undefined if _instance == undefined
_instance ?= new _taskManagerSingleton _instance ?= new _taskManagerSingleton
_instance.add( key, callback, params, to_not_show, state ) _instance.add( key, callback, params, to_not_show )
@get: ( key ) -> @get: ( key ) ->
if _instance == undefined if _instance == undefined
@ -120,14 +120,14 @@ class _taskManagerSingleton extends App.Controller
workerAll: -> workerAll: ->
@workers @workers
add: ( key, callback, params, to_not_show = false, state ) -> add: ( key, callback, params, to_not_show = false ) ->
active = true active = true
if to_not_show if to_not_show
active = false active = false
# create new task if not exists # create new task if not exists
task = @get( key ) task = @get( key )
# console.log('add', key, callback, params, to_not_show, state, task) # console.log('add', key, callback, params, to_not_show, task)
if !task if !task
task = new App.Taskbar task = new App.Taskbar
task.load( task.load(
@ -201,14 +201,14 @@ class _taskManagerSingleton extends App.Controller
@taskUpdate( task ) @taskUpdate( task )
# start worker for task if not exists # start worker for task if not exists
@startController(key, callback, params, state, to_not_show) @startController(key, callback, params, to_not_show)
App.Event.trigger 'task:render' App.Event.trigger 'task:render'
return key return key
startController: (key, callback, params, state, to_not_show) => startController: (key, callback, params, to_not_show) =>
# console.log('controller started...', callback, key, params, state) # console.log('controller started...', callback, key, params)
# activate controller # activate controller
worker = @worker( key ) worker = @worker( key )
@ -224,13 +224,6 @@ class _taskManagerSingleton extends App.Controller
params_app['el'] = $('#content_permanent_' + key ) params_app['el'] = $('#content_permanent_' + key )
params_app['task_key'] = key params_app['task_key'] = key
# check if we have old state there
if !state
oldTask = @get( key )
if oldTask
state = oldTask.state
params_app['form_state'] = state
if to_not_show if to_not_show
params_app['doNotLog'] = 1 params_app['doNotLog'] = 1
a = new App[callback]( params_app ) a = new App[callback]( params_app )
@ -359,7 +352,7 @@ class _taskManagerSingleton extends App.Controller
@delay( @delay(
=> =>
task = tasks.shift() task = tasks.shift()
@add(task.key, task.callback, task.params, true, task.state) @add(task.key, task.callback, task.params, true)
task_count * 300 task_count * 300
) )

View file

@ -2,7 +2,13 @@
<div class="avatar span1 thumbnails"> <div class="avatar span1 thumbnails">
<img class="thumbnail user-data" data-id="<%= @S('id') %>" src="<%- @S('image') %>" alt=""> <img class="thumbnail user-data" data-id="<%= @S('id') %>" src="<%- @S('image') %>" alt="">
</div> </div>
<div class="span8 well-muted article-message"> <div class="span8 well-muted article-message <% if @formChanged: %>form-changed<% end %>">
<div class="reset-message<% if !@formChanged: %> hide<% end %>">
<div>
<a href="#" data-type="reset"><%- @T('Discard your unsaved changes.') %></a> <href="#" class="icon-repeat" data-type="reset"></a>
</div>
<hr>
</div>
<form class="form-stacked pull-left ticket-update"> <form class="form-stacked pull-left ticket-update">
<div class="form-ticket-update"></div> <div class="form-ticket-update"></div>
<div class="form-article-update"></div> <div class="form-article-update"></div>

View file

@ -450,6 +450,11 @@ footer {
margin-left: 80px; margin-left: 80px;
} }
.form-changed {
border: 1px solid #fbeed5;
background-color: #fcf8e3;
}
#splash { #splash {
background-color: #eee; background-color: #eee;
position: absolute; position: absolute;

View file

@ -1808,7 +1808,7 @@ Translation.create_if_not_exists( :locale => 'de', :source => "Update Time", :ta
Translation.create_if_not_exists( :locale => 'de', :source => "Solution Time", :target => "Lösungszeit" ) Translation.create_if_not_exists( :locale => 'de', :source => "Solution Time", :target => "Lösungszeit" )
Translation.create_if_not_exists( :locale => 'de', :source => "Add Attribute", :target => "Attribut hinzufügen" ) Translation.create_if_not_exists( :locale => 'de', :source => "Add Attribute", :target => "Attribut hinzufügen" )
Translation.create_if_not_exists( :locale => 'de', :source => "Back to top", :target => "Nach oben" ) Translation.create_if_not_exists( :locale => 'de', :source => "Back to top", :target => "Nach oben" )
Translation.create_if_not_exists( :locale => 'de', :source => "Discard your unsaved changes.", :target => "Verwerfen der ungespeicherten Änderungen." )
#Translation.create_if_not_exists( :locale => 'de', :source => "", :target => "" ) #Translation.create_if_not_exists( :locale => 'de', :source => "", :target => "" )
# install all packages in auto_install # install all packages in auto_install