Rewritten taskbar manager.

This commit is contained in:
Martin Edenhofer 2013-05-31 13:29:48 +02:00
parent 2dd3853e96
commit 6f278fa8f7
7 changed files with 173 additions and 196 deletions

View file

@ -89,7 +89,7 @@ class App.TicketCreate extends App.Controller
if !@autosaveLast || ( diff && !_.isEmpty( diff ) ) if !@autosaveLast || ( diff && !_.isEmpty( diff ) )
@autosaveLast = data @autosaveLast = data
console.log('form hash changed', diff, data) console.log('form hash changed', diff, data)
App.TaskManager.update( @task_key, { 'state': data }) App.TaskManager.update( 'TicketCreateScreen', @type + '-' + @id, { 'state': data })
@interval( update, 10000, @id, @auto_save_key ) @interval( update, 10000, @id, @auto_save_key )
# get data / in case also ticket data for split # get data / in case also ticket data for split
@ -302,7 +302,7 @@ class App.TicketCreate extends App.Controller
# create new create screen # create new create screen
# ui.render() # ui.render()
App.TaskManager.remove( ui.task_key ) App.TaskManager.remove( 'TicketCreateScreen', ui.type + '-' + ui.id )
# scroll to top # scroll to top
ui.scrollTo() ui.scrollTo()

View file

@ -133,7 +133,7 @@ class App.TicketMerge extends App.ControllerModal
msg: App.i18n.translateContent( 'Ticket %s merged!', data.slave_ticket['number'] ), msg: App.i18n.translateContent( 'Ticket %s merged!', data.slave_ticket['number'] ),
timeout: 4000, timeout: 4000,
App.TaskManager.remove( @task_key ) App.TaskManager.remove( 'Ticket', data.slave_ticket['id'] )
else else

View file

@ -11,7 +11,7 @@ class App.TicketZoom extends App.Controller
constructor: (params) -> constructor: (params) ->
super super
@log 'zoom', params # console.log 'zoom', params
# check authentication # check authentication
return if !@authenticate() return if !@authenticate()
@ -31,7 +31,7 @@ class App.TicketZoom extends App.Controller
if cache if cache
@load(cache) @load(cache)
update = => update = =>
@fetch( @ticket_id, false) @fetch( @ticket_id, false )
@interval( update, 30000, @key, 'ticket_zoom' ) @interval( update, 30000, @key, 'ticket_zoom' )
# start auto save # start auto save
@ -73,7 +73,7 @@ class App.TicketZoom extends App.Controller
if !@autosaveLast || ( diff && !_.isEmpty( diff ) ) if !@autosaveLast || ( diff && !_.isEmpty( diff ) )
@autosaveLast = data @autosaveLast = data
console.log('form hash changed', diff, data) console.log('form hash changed', diff, data)
App.TaskManager.update( @task_key, { 'state': data }) App.TaskManager.update( 'Ticket', @ticket_id, { 'state': data })
@interval( update, 10000, @id, @auto_save_key ) @interval( update, 10000, @id, @auto_save_key )
fetch: (ticket_id, force) -> fetch: (ticket_id, force) ->
@ -93,7 +93,7 @@ class App.TicketZoom extends App.Controller
return if _.isEqual( @dataLastCall.ticket, data.ticket) return if _.isEqual( @dataLastCall.ticket, data.ticket)
diff = difference( @dataLastCall.ticket, data.ticket ) diff = difference( @dataLastCall.ticket, data.ticket )
console.log('diff', diff) console.log('diff', diff)
App.TaskManager.notify(@task_key) App.TaskManager.notify( 'Ticket', @ticket_id )
if $('[name="body"]').val() if $('[name="body"]').val()
App.Event.trigger 'notify', { App.Event.trigger 'notify', {
type: 'success' type: 'success'
@ -293,7 +293,6 @@ class App.TicketZoom extends App.Controller
internal = true internal = true
if article.internal == true if article.internal == true
internal = false internal = false
article.updateAttributes( article.updateAttributes(
internal: internal internal: internal
) )

View file

@ -10,37 +10,31 @@ class App.TaskWidget extends App.Controller
App.Event.bind 'ui:rerender', (data) => App.Event.bind 'ui:rerender', (data) =>
@render() @render()
# rebuild chat widget # rebuild taskbar widget
App.Event.bind 'auth', (user) => App.Event.bind 'auth', (user) =>
App.TaskManager.reset() App.TaskManager.reset()
@el.html('') @el.html('')
sync = =>
App.TaskManager.sync()
@delay( sync, 3000, 'task-widget' )
@delay( sync, 5000, 'task-widget' )
render: -> render: ->
return if _.isEmpty( @Session.all() ) return if _.isEmpty( @Session.all() )
tasks = App.TaskManager.all() tasks = App.TaskManager.all()
item_list = [] item_list = []
for key, task of tasks for task in tasks
data = data =
url: '#' url: '#'
id: false id: false
title: App.i18n.translateInline('Loading...') title: App.i18n.translateInline('Loading...')
head: App.i18n.translateInline('Loading...') head: App.i18n.translateInline('Loading...')
if task.worker worker = App.TaskManager.worker( task.type, task.type_id )
meta = task.worker.meta() if worker
meta = worker.meta()
if meta if meta
data = meta data = meta
data.title = App.i18n.escape( data.title ) data.title = App.i18n.escape( data.title )
data.head = App.i18n.escape( data.head ) data.head = App.i18n.escape( data.head )
item = {} item = {}
item.key = key
item.task = task item.task = task
item.data = data item.data = data
item_list.push item item_list.push item
@ -52,34 +46,41 @@ class App.TaskWidget extends App.Controller
remove: (e) => remove: (e) =>
e.preventDefault() e.preventDefault()
key = $(e.target).parent().data('id') type_id = $(e.target).parent().data('type-id')
type = $(e.target).parent().data('type')
if !type_id && !type
throw "No such type and type-id attributes found for task item"
# check if input has changed # check if input has changed
task = App.TaskManager.get( key ) worker = App.TaskManager.worker( type, type_id )
if task.worker && task.worker.changed if worker && worker.changed
if task.worker.changed() if worker.changed()
return if !window.confirm( App.i18n.translateInline('Tab has changed, you really want to close it?') ) return if !window.confirm( App.i18n.translateInline('Tab has changed, you really want to close it?') )
# check if active task is closed # check if active task is closed
task_last = undefined currentTask = App.TaskManager.get( type, type_id )
tasks_all = App.TaskManager.all() tasks = App.TaskManager.all()
active_is_closed = false active_is_closed = false
for task_key, task of tasks_all for task in tasks
if task.active && task_key.toString() is key.toString() if currentTask.active && task.type is type && task.type_id.toString() is type_id.toString()
active_is_closed = true active_is_closed = true
# remove task # remove task
App.TaskManager.remove( key ) App.TaskManager.remove( type, type_id )
@render() @render()
# navigate to next task if needed # navigate to next task if needed
if active_is_closed && !_.isEmpty( tasks_all ) tasks = App.TaskManager.all()
for key, task of tasks_all if active_is_closed && !_.isEmpty( tasks )
task_last = undefined
for task in tasks
task_last = task task_last = task
if task_last if task_last
@navigate task_last.worker.url() worker = App.TaskManager.worker( task_last.type, task_last.type_id )
if worker
@navigate worker.url()
return return
if _.isEmpty( tasks_all ) if _.isEmpty( tasks )
@navigate '#' @navigate '#'
_getTaskActions: -> _getTaskActions: ->

View file

@ -14,240 +14,216 @@ class App.TaskManager
_instance ?= new _Singleton _instance ?= new _Singleton
_instance.add( type, type_id, callback, params, to_not_show, state ) _instance.add( type, type_id, callback, params, to_not_show, state )
@get: ( key ) -> @get: ( type, type_id ) ->
if _instance == undefined if _instance == undefined
_instance ?= new _Singleton _instance ?= new _Singleton
_instance.get( key ) _instance.get( type, type_id )
@update: ( key, params ) -> @update: ( type, type_id, params ) ->
if _instance == undefined if _instance == undefined
_instance ?= new _Singleton _instance ?= new _Singleton
_instance.update( key, params ) _instance.update( type, type_id, params )
@remove: ( key ) -> @remove: ( type, type_id ) ->
if _instance == undefined if _instance == undefined
_instance ?= new _Singleton _instance ?= new _Singleton
_instance.remove( key ) _instance.remove( type, type_id )
@notify: ( key ) -> @notify: ( type, type_id ) ->
if _instance == undefined if _instance == undefined
_instance ?= new _Singleton _instance ?= new _Singleton
_instance.notify( key ) _instance.notify( type, type_id )
@reset: -> @reset: ->
if _instance == undefined if _instance == undefined
_instance ?= new _Singleton _instance ?= new _Singleton
_instance.reset() _instance.reset()
@syncInitial: -> @worker: ( type, type_id ) ->
if _instance == undefined if _instance == undefined
_instance ?= new _Singleton _instance ?= new _Singleton
_instance.syncTasksInitial() _instance.worker( type, type_id )
@syncSave: -> @workerAll: ->
if _instance == undefined if _instance == undefined
_instance ?= new _Singleton _instance ?= new _Singleton
_instance.syncSave() _instance.workerAll()
@sync: ->
if _instance == undefined
_instance ?= new _Singleton
_instance.syncTasks()
class _Singleton extends App.Controller class _Singleton extends App.Controller
@include App.Log @include App.Log
constructor: -> constructor: ->
@tasks = {} @workers = {}
@task_count = 0 @workersStarted = {}
@syncTasksInitial() @activeTask = undefined
@tasksInitial()
all: -> all: ->
@tasks App.Taskbar.all()
worker: ( type, type_id ) ->
key = @keyGenerate(type, type_id)
return @workers[ key ] if @workers[ key ]
return
workerAll: ->
@workers
add: ( type, type_id, callback, params, to_not_show = false, state ) -> add: ( type, type_id, callback, params, to_not_show = false, state ) ->
for key, task of @tasks
if task.type is type && task.type_id is type_id
return key if to_not_show
$('#content').empty()
$('.content_permanent').hide()
$('.content_permanent').removeClass('active')
$('#content_permanent_' + key ).show()
$('#content_permanent_' + key ).addClass('active')
@tasks[key].worker.activate()
@tasks[key].notify = false
for task_key, task of @tasks
if task_key isnt key
task.active = false
else
task.active = true
App.Event.trigger 'ui:rerender'
App.Event.trigger 'ui:rerender:content'
return key
@task_count++
if !to_not_show
for task_key, task of @tasks
task.active = false
active = true active = true
if to_not_show if to_not_show
active = false active = false
# create new task if not exists
task = @get( type, type_id )
# console.log('add', type, type_id, callback, params, to_not_show, state, task)
if !task
task = new App.Taskbar
task.load(
type: type
type_id: type_id
params: params
callback: callback
notify: false
active: active
)
task.save()
tasks = @all()
# empty static content if task is shown
key = @keyGenerate(type, type_id)
if active if active
@activeTask = key
$('#content').empty() $('#content').empty()
$('#content_permanent').append('<div id="content_permanent_' + @task_count + '" class="content_permanent"></div>') # hide all tasks
if active
$('.content_permanent').hide() $('.content_permanent').hide()
$('.content_permanent').removeClass('active') $('.content_permanent').removeClass('active')
$('#content_permanent_' + @task_count ).show()
$('#content_permanent_' + @task_count ).addClass('active') # create div for task if not exists
if !$("#content_permanent_#{key}")[0]
$('#content_permanent').append('<div id="content_permanent_' + key + '" class="content_permanent"></div>')
# set task to shown and active
if @activeTask is key
$('#content_permanent_' + key ).show()
$('#content_permanent_' + key ).addClass('active')
else else
$('#content_permanent_' + @task_count ).removeClass('active') $('#content_permanent_' + key ).hide()
$('#content_permanent_' + @task_count ).hide() $('#content_permanent_' + key ).removeClass('active')
# set all tasks to active false, only new/selected one to active
if active
for task in tasks
task_key = @keyGenerate(task.type, task.type_id)
if task_key isnt key
task.active = false
else
task.active = true
task.save()
else
for task in tasks
task_key = @keyGenerate(task.type, task.type_id)
if @activeTask isnt task_key
if task.active
task.active = false
task.save()
# start worker for task if not exists
@startController(type, type_id, callback, params, state, key, to_not_show)
App.Event.trigger 'ui:rerender'
App.Event.trigger 'ui:rerender:content'
return key
startController: (type, type_id, callback, params, state, key, to_not_show) =>
# console.log('controller started...', callback, type, type_id, params, state)
# activate controller
worker = @worker( type, type_id )
if worker && worker.activate
worker.activate()
# return if controller is alreary started
return if @workersStarted[key]
@workersStarted[key] = true
# create new controller instanz # create new controller instanz
params_app = _.clone(params) params_app = _.clone(params)
params_app['el'] = $('#content_permanent_' + @task_count ) params_app['el'] = $('#content_permanent_' + key )
params_app['task_key'] = @task_count params_app['task_key'] = key
# check if we have old state there # check if we have old state there
if !state if !state
oldTask = @get_by_type( type, type_id ) oldTask = @get( type, type_id )
if oldTask if oldTask
state = oldTask.state state = oldTask.state
params_app['form_state'] = 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 )
@workers[ key ] = a
# remember new controller / prepare for task storage
task =
type: type
type_id: type_id
params: params
callback: callback
worker: a
active: active
@tasks[@task_count] = task
# activate controller # activate controller
if !to_not_show if !to_not_show
a.activate() a.activate()
App.Event.trigger 'ui:rerender' return a
# add new controller to task storage get: ( type, type_id ) =>
if !to_not_show tasks = App.Taskbar.all()
@syncAdd(task) for task in tasks
return task if task.type is type && task.type_id.toString() is type_id.toString()
return
# throw "No such task with '#{type}' and '#{type_id}'"
@task_count update: ( type, type_id, params ) =>
task = @get( type, type_id )
get: ( key ) => if !task
return @tasks[key] throw "No such task with '#{type}' and '#{type_id}' to update"
update: ( key, params ) =>
return false if !@tasks[key]
for item, value of params for item, value of params
@tasks[key][item] = value task.updateAttribute(item, value)
@syncSave() # task.save()
remove: ( key, to_not_show = false ) => remove: ( type, type_id, to_not_show = false ) =>
if @tasks[key] task = @get( type, type_id )
@tasks[key].worker.release() if !task
if !to_not_show throw "No such task with '#{type}' and '#{type_id}' to remove"
@syncRemove( @tasks[key] )
delete @tasks[key] worker = @worker( type, type_id )
if worker && worker.release
worker.release()
@workersStarted[ @keyGenerate(type, type_id) ] = false
task.destroy()
App.Event.trigger 'ui:rerender' App.Event.trigger 'ui:rerender'
notify: ( key ) => notify: ( type, type_id ) =>
@tasks[key].notify = true task = @get( type, type_id )
if !task
throw "No such task with '#{type}' and '#{type_id}' to notify"
task.notify = true
reset: => reset: =>
@tasks = {} App.Taskbar.deleteAll()
App.Event.trigger 'ui:rerender' App.Event.trigger 'ui:rerender'
get_by_type: (type, type_id) => tasksInitial: =>
store = @syncLoad() || []
for item in store
return item if item.type is type && item.type_id is type_id
syncAdd: (task) =>
store = @syncLoad() || []
for item in store
return if item.type is task.type && item.type_id is task.type_id
item =
type: task.type
type_id: task.type_id
params: task.params
callback: task.callback
store.push item
App.Store.write( 'tasks', store )
syncRemove: (task) =>
store = @syncLoad() || []
storeNew = []
for item in store
if item.type isnt task.type || item.type_id isnt task.type_id
storeNew.push item
App.Store.write( 'tasks', storeNew )
syncSave: =>
store = @syncLoad() || []
storeNew = []
for item in store
for key, task of @tasks
if task.type is item.type && task.type_id is item.type_id
console.log('MATCH', item)
if @tasks[key]['state']
item['state'] = @tasks[key]['state']
storeNew.push item
# if @tasks[key]
# @tasks[key].worker.release()
#
# storeNew.push item
# item =
# type: task.type
# type_id: task.type_id
# params: task.params
# callback: task.callback
App.Store.write( 'tasks', storeNew )
syncLoad: =>
App.Store.get( 'tasks' )
syncTasksInitial: =>
# reopen tasks # reopen tasks
store = _.clone(@syncLoad()) App.Taskbar.fetch()
return if !store tasks = @all()
return if !tasks
task_count = 0 task_count = 0
for task in store for task in tasks
task_count += 1 task_count += 1
@delay( @delay(
=> =>
task = store.shift() task = tasks.shift()
@add(task.type, task.type_id, task.callback, task.params, true, task.state) @add(task.type, task.type_id, task.callback, task.params, true, task.state)
task_count * 500 task_count * 500
) )
syncTasks: => keyGenerate: ( type, type_id )->
store = @syncLoad() || [] "#{type}_#{type_id}"
# open tasks
for item in store
existsLocal = false
for task_key, task of @tasks
if item.type is task.type && item.type_id is task.type_id
# also open here
existsLocal = true
if !existsLocal
@add(item.type, item.type_id, item.callback, item.params, true)
# close tasks
for task_key, task of @tasks
onlyLocal = true
for item in store
if item.type is task.type && item.type_id is task.type_id
onlyLocal = false
if onlyLocal
@remove( task_key, true )

View file

@ -1,6 +1,6 @@
<div class="well taskbar"> <div class="taskbar">
<% for item in @item_list: %> <% for item in @item_list: %>
<a href="<%- item.data.url %>" title="<%= item.data.title %>" class="btn btn-mini <% if item.task.active: %>active btn-success<% else if item.task.notify: %>active btn-warning<% else: %>btn-default<% end %>" data-id="<%- item.key %>"><span class="task"><%- item.data.head %></span><span data-type="close" class="icon-remove-circle" title="<%- @T('close') %>"></a> <a href="<%- item.data.url %>" title="<%= item.data.title %>" class="btn btn-mini <% if item.task.active: %>active btn-success<% else if item.task.notify: %>active btn-warning<% else: %>btn-default<% end %>" data-type="<%- item.task.type %>" data-type-id="<%- item.task.type_id %>"><span class="task"><%- item.data.head %></span><span data-type="close" class="icon-remove-circle" title="<%- @T('close') %>"></a>
<% end %> <% end %>
<% if !_.isEmpty( @taskBarActions ): %> <% if !_.isEmpty( @taskBarActions ): %>
<div class="taskbar-new"> <div class="taskbar-new">

View file

@ -12,6 +12,7 @@
//not_used= require_tree ./app/lib/spine //not_used= require_tree ./app/lib/spine
//= require ./app/lib/spine/spine.js //= require ./app/lib/spine/spine.js
//= require ./app/lib/spine/ajax.js //= require ./app/lib/spine/ajax.js
//= require ./app/lib/spine/local.js
//= require ./app/lib/spine/route.js //= require ./app/lib/spine/route.js
//= require ./app/lib/flot/jquery.flot.js //= require ./app/lib/flot/jquery.flot.js