task_manager.coffee 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. class App.TaskManager
  2. _instance = undefined
  3. @init: (params) ->
  4. _instance ?= new _taskManagerSingleton(params)
  5. @all: ->
  6. _instance.all()
  7. @allWithMeta: ->
  8. _instance.allWithMeta()
  9. @execute: (params) ->
  10. _instance.execute(params)
  11. @get: (key) ->
  12. _instance.get(key)
  13. @update: (key, params) ->
  14. _instance.update(key, params)
  15. @remove: (key) ->
  16. _instance.remove(key)
  17. @notify: (key) ->
  18. _instance.notify(key)
  19. @mute: (key) ->
  20. _instance.mute(key)
  21. @reorder: (order) ->
  22. _instance.reorder(order)
  23. @touch: (key) ->
  24. _instance.touch(key)
  25. @reset: ->
  26. _instance.reset()
  27. @worker: (key) ->
  28. _instance.worker(key)
  29. @nextTaskUrl: ->
  30. _instance.nextTaskUrl()
  31. @TaskbarId: ->
  32. _instance.TaskbarId()
  33. @hideAll: ->
  34. _instance.showControllerHideOthers()
  35. class _taskManagerSingleton extends App.Controller
  36. @include App.LogInclude
  37. constructor: (params = {}) ->
  38. super
  39. if params.el
  40. @el = params.el
  41. else
  42. @el = $('#app')
  43. @offlineModus = params.offlineModus
  44. @tasksInitial()
  45. # render on login
  46. App.Event.bind('auth:login', =>
  47. @tasksInitial()
  48. 'task'
  49. )
  50. # render on logout
  51. App.Event.bind('auth:logout', =>
  52. @reset()
  53. 'task'
  54. )
  55. # send updates to server
  56. App.Interval.set(@taskUpdateLoop, 2500, 'check_update_to_server_pending', 'task')
  57. init: ->
  58. @workers = {}
  59. @allTasksByKey = {}
  60. @tasksToUpdate = {}
  61. @activeTaskHistory = []
  62. @queue = []
  63. @queueRunning = false
  64. all: ->
  65. # sort by prio
  66. byPrios = []
  67. for key, task of @allTasksByKey
  68. byPrios.push task
  69. _.sortBy(byPrios, (task) ->
  70. return task.prio
  71. )
  72. allWithMeta: ->
  73. all = @all()
  74. for task in all
  75. task = @getMeta(task)
  76. all
  77. getMeta: (task) ->
  78. # collect meta data of task for task bar item
  79. meta =
  80. url: '#'
  81. id: false
  82. iconClass: 'loading'
  83. title: App.i18n.translateInline('Loading...')
  84. head: App.i18n.translateInline('Loading...')
  85. worker = App.TaskManager.worker(task.key)
  86. if worker
  87. data = worker.meta()
  88. # apply meta data of controller
  89. if data
  90. for key, value of data
  91. meta[key] = value
  92. task.meta = meta
  93. task
  94. newPrio: ->
  95. prio = 1
  96. for task in @all()
  97. if task.prio && task.prio > prio
  98. prio = task.prio
  99. prio++
  100. prio
  101. # generate dom id for task
  102. domID: (key) ->
  103. "content_permanent_#{key}"
  104. worker: (key) ->
  105. return @workers[ key ] if @workers[ key ]
  106. return
  107. execute: (params) ->
  108. @queue.push params
  109. @run()
  110. run: ->
  111. return if !@queue[0]
  112. return if @queueRunning
  113. @queueRunning = true
  114. loop
  115. param = @queue.shift()
  116. @executeSingel(param)
  117. if !@queue[0]
  118. @queueRunning = false
  119. break
  120. executeSingel: (params) ->
  121. # input validation
  122. params.key = App.Utils.htmlAttributeCleanup(params.key)
  123. # in case an init execute arrives later but is aleady executed, ignore it
  124. if params.init && @workers[params.key]
  125. return
  126. # if we have init task startups, let the controller know this
  127. if params.init
  128. params.params.init = true
  129. # modify shown param for controller
  130. if params.params
  131. if !params.show
  132. delete params.params.shown
  133. else
  134. params.params.shown = true
  135. # remember latest active controller
  136. if params.show
  137. @activeTaskHistory.push _.clone(params)
  138. # check if task already exists in storage / e. g. from last session
  139. task = @get(params.key)
  140. # create new online task if not exists and if not persistent
  141. if !task && !@workers[params.key] && !params.persistent
  142. task = new App.Taskbar
  143. task.load(
  144. key: params.key
  145. params: params.params
  146. callback: params.controller
  147. client_id: 123
  148. prio: @newPrio()
  149. notify: false
  150. active: params.show
  151. )
  152. @allTasksByKey[params.key] = task.attributes()
  153. @touch(params.key)
  154. # save new task and update task collection
  155. ui = @
  156. task.save(
  157. done: ->
  158. ui.allTasksByKey[params.key] = @attributes()
  159. for taskPosition of ui.allTasks
  160. if ui.allTasks[taskPosition] && ui.allTasks[taskPosition]['key'] is @key
  161. task = @attributes()
  162. ui.allTasks[taskPosition] = task
  163. )
  164. # empty static content if task is shown
  165. if params.show
  166. @el.find('#content').empty()
  167. # hide all tasks
  168. @el.find('.content').addClass('hide').removeClass('active')
  169. # create div for task if not exists
  170. if !@el.find("##{@domID(params.key)}")[0]
  171. @el.append("<div id=\"#{@domID(params.key)}\" class=\"content horizontal flex\"></div>")
  172. # set all tasks to active false, only new/selected one to active
  173. if params.show
  174. for key, task of @allTasksByKey
  175. if key isnt params.key
  176. if task.active
  177. task.active = false
  178. @taskUpdate(task)
  179. else
  180. changed = false
  181. if !task.active
  182. changed = true
  183. task.active = true
  184. if task.notify
  185. changed = true
  186. task.notify = false
  187. if changed
  188. @taskUpdate(task)
  189. # start worker for task if not exists
  190. @startController(params)
  191. startController: (params) =>
  192. @log 'debug', 'controller start try...', params
  193. # create clean params
  194. params_app = _.clone(params.params)
  195. params_app['el'] = $("##{@domID(params.key)}")
  196. params_app['task_key'] = params.key
  197. if !params.show
  198. params_app['doNotLog'] = 1
  199. # start controller if not already started
  200. if !@workers[params.key]
  201. @workers[params.key] = new App[params.controller](params_app)
  202. # if controller is started hidden, call hide of controller
  203. if !params.show
  204. @hide(params.key)
  205. # hide all other controller / show current controller
  206. else
  207. @showControllerHideOthers(params.key, params_app)
  208. showControllerHideOthers: (thisKey, params_app) =>
  209. for key of @workers
  210. if key is thisKey
  211. @show(key, params_app)
  212. else
  213. @hide(key)
  214. # show task content
  215. show: (key, params_app) ->
  216. @el.find("##{@domID(key)}").removeClass('hide').addClass('active')
  217. controller = @workers[ key ]
  218. return false if !controller
  219. # set controller state to active
  220. if controller.active && _.isFunction(controller.active)
  221. controller.active(true)
  222. # execute controllers show
  223. if controller.show && _.isFunction(controller.show)
  224. controller.show(params_app)
  225. true
  226. # hide task content
  227. hide: (key) ->
  228. @el.find("##{@domID(key)}").addClass('hide').removeClass('active')
  229. controller = @workers[ key ]
  230. return false if !controller
  231. # set controller state to active
  232. if controller.active && _.isFunction(controller.active)
  233. controller.active(false)
  234. # execute controllers hide
  235. if controller.hide && _.isFunction(controller.hide)
  236. controller.hide()
  237. true
  238. # get task
  239. get: (key) =>
  240. @allTasksByKey[key]
  241. # get task
  242. getWithMeta: (key) =>
  243. task = @get(key)
  244. return if !task
  245. @getMeta(task)
  246. # update task
  247. update: (key, params) =>
  248. task = @get(key)
  249. if !task
  250. throw "No such task with '#{key}' to update"
  251. for item, value of params
  252. task[item] = value
  253. # mute rerender on state attribute updates
  254. mute = false
  255. if Object.keys(params).length is 1 && params.state
  256. mute = true
  257. @taskUpdate(task, mute)
  258. # remove task certain task from tasks
  259. remove: (key) =>
  260. task = @allTasksByKey[key]
  261. delete @allTasksByKey[key]
  262. # rerender taskbar
  263. App.Event.trigger('taskRemove', [task])
  264. # destroy in backend storage
  265. @taskDestroy(task)
  266. # release task from dom and destroy controller
  267. @release(key)
  268. # set notify of task
  269. notify: (key) =>
  270. task = @get(key)
  271. if !task
  272. throw "No such task with '#{key}' to notify"
  273. return if task.notify
  274. task.notify = true
  275. @taskUpdate(task)
  276. # unset notify of task
  277. mute: (key) =>
  278. task = @get(key)
  279. if !task
  280. throw "No such task with '#{key}' to mute"
  281. return if !task.notify
  282. task.notify = false
  283. @taskUpdate(task)
  284. # set new order of tasks (needed for dnd)
  285. reorder: (order) =>
  286. prio = 0
  287. for key in order
  288. task = @get(key)
  289. if !task
  290. throw "No such task with '#{key}' of order"
  291. prio++
  292. if task.prio isnt prio
  293. task.prio = prio
  294. @taskUpdate(task, true)
  295. App.Event.trigger('taskCollectionOrderSet', order)
  296. # release one task
  297. release: (key) =>
  298. try
  299. @el.find("##{@domID(key)}").html('')
  300. @el.find("##{@domID(key)}").remove()
  301. catch
  302. @log 'notice', "invalid key '#{key}'"
  303. delete @workers[ key ]
  304. # reset while tasks
  305. reset: =>
  306. # release touch tasks
  307. for key, task of @allTasksByKey
  308. @release(key)
  309. # release persistent tasks
  310. for key, controller of @workers
  311. @release(key)
  312. # clear instance vars
  313. @init()
  314. # clear in mem tasks
  315. App.Taskbar.deleteAll()
  316. # rerender task bar
  317. App.Event.trigger('taskInit')
  318. nextTaskUrl: =>
  319. # activate latest controller based on history
  320. loop
  321. controllerParams = @activeTaskHistory.pop()
  322. break if !controllerParams
  323. break if !controllerParams.key
  324. controller = @workers[ controllerParams.key ]
  325. if controller && controller.url
  326. return controller.url()
  327. # activate latest controller with highest prio
  328. tasks = @all()
  329. taskNext = tasks[tasks.length-1]
  330. if taskNext
  331. controller = @workers[ taskNext.key ]
  332. if controller && controller.url
  333. return controller.url()
  334. false
  335. TaskbarId: =>
  336. if !@TaskbarIdInt
  337. @TaskbarIdInt = Math.floor( Math.random() * 99999999 )
  338. @TaskbarIdInt
  339. taskUpdate: (task, mute = false) ->
  340. @log 'debug', 'UPDATE task', task, mute
  341. @tasksToUpdate[ task.key ] = 'toUpdate'
  342. return if mute
  343. @touch(task.key)
  344. touch: (key) ->
  345. delay = =>
  346. task = @getWithMeta(key)
  347. return if !task
  348. # throw "No such task with '#{key}' to touch"
  349. # update title
  350. if task.active && task.meta
  351. @title task.meta.title
  352. App.Event.trigger('taskUpdate', [task])
  353. App.Delay.set(delay, 20, "task-#{key}")
  354. taskUpdateLoop: =>
  355. return if @offlineModus
  356. for key of @tasksToUpdate
  357. continue if !key
  358. task = @get(key)
  359. continue if !task
  360. if @tasksToUpdate[ task.key ] is 'toUpdate'
  361. @tasksToUpdate[ task.key ] = 'inProgress'
  362. taskUpdate = new App.Taskbar
  363. taskUpdate.load(task)
  364. if taskUpdate.isOnline()
  365. ui = @
  366. taskUpdate.save(
  367. done: ->
  368. if ui.tasksToUpdate[ @key ] is 'inProgress'
  369. delete ui.tasksToUpdate[ @key ]
  370. fail: ->
  371. ui.log 'error', "can't update task", @
  372. if ui.tasksToUpdate[ @key ] is 'inProgress'
  373. delete ui.tasksToUpdate[ @key ]
  374. )
  375. taskDestroy: (task) ->
  376. # check if update is still in process
  377. if @tasksToUpdate[ task.key ] is 'inProgress'
  378. App.Delay.set(
  379. => @taskDestroy(task)
  380. 800
  381. undefined
  382. 'task'
  383. )
  384. return
  385. # destory task in backend
  386. delete @tasksToUpdate[ task.key ]
  387. # if task isnt already stored on backend
  388. return if !task.id
  389. App.Taskbar.destroy(task.id)
  390. tasksInitial: =>
  391. @init()
  392. # set taskbar collection stored in database
  393. tasks = App.Taskbar.all()
  394. for task in tasks
  395. task.active = false
  396. @allTasksByKey[task.key] = task.attributes()
  397. # reopen tasks
  398. App.Event.trigger 'taskbar:init'
  399. # initial load of permanent tasks
  400. authentication = App.Session.get('id')
  401. permanentTask = App.Config.get('permanentTask')
  402. task_count = 0
  403. if permanentTask
  404. for key, config of permanentTask
  405. if !config.authentication || (config.authentication && authentication)
  406. task_count += 1
  407. do (key, config, task_count) =>
  408. App.Delay.set(
  409. =>
  410. @execute(
  411. key: key
  412. controller: config.controller
  413. params: {}
  414. show: false
  415. persistent: true
  416. init: true
  417. )
  418. task_count * 450
  419. undefined
  420. 'task'
  421. )
  422. # initial load of taskbar collection
  423. for key, task of @allTasksByKey
  424. task_count += 1
  425. do (task, task_count) =>
  426. App.Delay.set(
  427. =>
  428. @execute(
  429. key: task.key
  430. controller: task.callback
  431. params: task.params
  432. show: false
  433. persistent: false
  434. init: true
  435. )
  436. task_count * 450
  437. undefined
  438. 'task'
  439. )
  440. App.Event.trigger 'taskbar:ready'