_application_controller.js.coffee 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. class App.Controller extends Spine.Controller
  2. # add @title methode to set title
  3. title: (name) ->
  4. # $('html head title').html( Config.product_name + ' - ' + Ti(name) )
  5. document.title = Config.product_name + ' - ' + Ti(name)
  6. # add @notify methode to create notification
  7. notify: (data) ->
  8. Spine.trigger 'notify', data
  9. # add @navupdate methode to update navigation
  10. navupdate: (url) ->
  11. Spine.trigger 'navupdate', url
  12. scrollTo: ( x = 0, y = 0 ) ->
  13. a = ->
  14. console.log('scollTo', x, y )
  15. window.scrollTo( x, y )
  16. @delay( a, 0 )
  17. reBind: (name, callback) =>
  18. Spine.one name, (data) =>
  19. @log 'rebind', name, data
  20. callback(data)
  21. @reBind(name, callback)
  22. isRole: (name) ->
  23. return false if !window.Session.roles
  24. for role in window.Session.roles
  25. return true if role.name is name
  26. return false
  27. # get all params of the form
  28. formParam: (form) ->
  29. App.ControllerForm.params(form)
  30. formDisable: (form) ->
  31. App.ControllerForm.disable(form)
  32. formEnable: (form) ->
  33. App.ControllerForm.enable(form)
  34. formValidate: (data) ->
  35. App.ControllerForm.validate(data)
  36. ###
  37. table = @table(
  38. header: ['Host', 'User', 'Adapter', 'Active'],
  39. overview: ['host', 'user', 'adapter', 'active'],
  40. model: App.Channel,
  41. objects: data,
  42. )
  43. table = @table(
  44. overview_extended: [
  45. { name: 'number', link: true },
  46. { name: 'title', link: true },
  47. { name: 'customer', class: 'user-data', data: { id: true } },
  48. { name: 'ticket_state', translate: true },
  49. { name: 'ticket_priority', translate: true },
  50. { name: 'group' },
  51. { name: 'owner', class: 'user-data', data: { id: true } },
  52. { name: 'created_at', callback: @frontendTime },
  53. { name: 'last_contact', callback: @frontendTime },
  54. { name: 'last_contact_agent', callback: @frontendTime },
  55. { name: 'last_contact_customer', callback: @frontendTime },
  56. { name: 'first_response', callback: @frontendTime },
  57. { name: 'close_time', callback: @frontendTime },
  58. ],
  59. model: App.Ticket,
  60. objects: tickets,
  61. )
  62. ###
  63. table: (data) ->
  64. overview = data.overview || data.model.configure_overview || []
  65. attributes = data.attributes || data.model.configure_attributes || {}
  66. header = data.header
  67. # define normal header
  68. if !header
  69. header = []
  70. for row in overview
  71. if attributes
  72. for attribute in attributes
  73. if row is attribute.name
  74. header.push( attribute.display )
  75. else
  76. rowWithoutId = row + '_id'
  77. if rowWithoutId is attribute.name
  78. header.push( attribute.display )
  79. dataTypesForCols = []
  80. for row in overview
  81. dataTypesForCols.push {
  82. name: row,
  83. link: true,
  84. }
  85. # extended table format
  86. if data.overview_extended
  87. if !header
  88. header = []
  89. for row in data.overview_extended
  90. for attribute in attributes
  91. if row.name is attribute.name
  92. header.push( attribute.display )
  93. else
  94. rowWithoutId = row.name + '_id'
  95. if rowWithoutId is attribute.name
  96. header.push( attribute.display )
  97. dataTypesForCols = data.overview_extended
  98. # generate content data
  99. objects = _.clone( data.objects )
  100. for object in objects
  101. # check if info for each col. is already there
  102. for row in dataTypesForCols
  103. # execute callback on content
  104. if row.callback
  105. object[row.name] = row.callback( object[row.name] )
  106. # lookup relation
  107. if !object[row.name]
  108. rowWithoutId = row.name + '_id'
  109. for attribute in attributes
  110. if rowWithoutId is attribute.name
  111. if attribute.relation && App[attribute.relation]
  112. record = App.Collection.find( attribute.relation, object[rowWithoutId] )
  113. object[row.name] = record.name
  114. @log 'table', 'header', header, 'overview', dataTypesForCols, 'objects', objects
  115. table = App.view('generic/table')(
  116. header: header,
  117. overview: dataTypesForCols,
  118. objects: objects,
  119. checkbox: data.checkbox,
  120. )
  121. # @log 'ttt', $(table).find('span')
  122. # $(table).find('span').bind('click', ->
  123. # console.log('----------click---------')
  124. # )
  125. # convert to jquery object
  126. table = $(table)
  127. # enable checkbox bulk selection
  128. if data.checkbox
  129. table.delegate('[name="bulk_all"]', 'click', (e) ->
  130. if $(e.target).attr('checked')
  131. $(e.target).parents().find('[name="bulk"]').attr( 'checked', true );
  132. else
  133. $(e.target).parents().find('[name="bulk"]').attr( 'checked', false );
  134. )
  135. return table
  136. ticketTableAttributes: (attributes) =>
  137. all_attributes = [
  138. { name: 'number', link: true },
  139. { name: 'title', link: true },
  140. { name: 'customer', class: 'user-data', data: { id: true } },
  141. { name: 'ticket_state', translate: true },
  142. { name: 'ticket_priority', translate: true },
  143. { name: 'group' },
  144. { name: 'owner', class: 'user-data', data: { id: true } },
  145. { name: 'created_at', callback: @frontendTime },
  146. { name: 'last_contact', callback: @frontendTime },
  147. { name: 'last_contact_agent', callback: @frontendTime },
  148. { name: 'last_contact_customer', callback: @frontendTime },
  149. { name: 'first_response', callback: @frontendTime },
  150. { name: 'close_time', callback: @frontendTime },
  151. ]
  152. shown_all_attributes = []
  153. for all_attribute in all_attributes
  154. for attribute in attributes
  155. if all_attribute['name'] is attribute
  156. shown_all_attributes.push all_attribute
  157. break
  158. return shown_all_attributes
  159. # redirectToLogin: (data) ->
  160. #
  161. # human readable file size
  162. humanFileSize: (size) =>
  163. if size > ( 1024 * 1024 )
  164. size = Math.round( size / ( 1024 * 1024 ) ) + ' MBytes'
  165. else if size > 1024
  166. size = Math.round( size / 1024 ) + ' KBytes'
  167. else
  168. size = size + ' Bytes'
  169. return size
  170. # human readable time
  171. humanTime: (time) =>
  172. current = new Date()
  173. created = new Date(time)
  174. string = ''
  175. diff = ( current - created ) / 1000
  176. if diff >= 86400
  177. unit = Math.round( ( diff / 86400 ) )
  178. # if unit > 1
  179. # return unit + ' ' + T('days')
  180. # else
  181. # return unit + ' ' + T('day')
  182. string = unit + ' ' + T('d')
  183. if diff >= 3600
  184. unit = Math.round( ( diff / 3600 ) % 24 )
  185. # if unit > 1
  186. # return unit + ' ' + T('hours')
  187. # else
  188. # return unit + ' ' + T('hour')
  189. if string isnt ''
  190. string = string + ' ' + unit + ' ' + T('h')
  191. return string
  192. else
  193. string = unit + ' ' + T('h')
  194. if diff <= 86400
  195. unit = Math.round( ( diff / 60 ) % 60 )
  196. # if unit > 1
  197. # return unit + ' ' + T('minutes')
  198. # else
  199. # return unit + ' ' + T('minute')
  200. if string isnt ''
  201. string = string + ' ' + unit + ' ' + T('m')
  202. return string
  203. else
  204. string = unit + ' ' + T('m')
  205. return string
  206. userInfo: (data) =>
  207. # start customer info controller
  208. new App.UserInfo(
  209. el: data.el || $('#customer_info'),
  210. user_id: data.user_id,
  211. )
  212. authenticate: ->
  213. console.log 'authenticate', window.Session
  214. # return rtue if session exists
  215. return true if window.Session['id']
  216. # remember requested url
  217. window.Config['requested_url'] = window.location.hash
  218. # redirect to login
  219. @navigate '#login'
  220. return false
  221. frontendTime: (timestamp) ->
  222. '<span class="humanTimeFromNow" data-time="' + timestamp + '">?</span>'
  223. frontendTimeUpdate: ->
  224. update = =>
  225. ui = @
  226. $('.humanTimeFromNow').each( ->
  227. # console.log('rewrite frontendTimeUpdate', this)
  228. timestamp = $(this).data('time')
  229. time = ui.humanTime( timestamp )
  230. $(this).attr( 'title', Ts(timestamp) )
  231. $(this).text( time )
  232. )
  233. @interval( update, 30000, 'frontendTimeUpdate' )
  234. clearInterval: (interval_id) =>
  235. # check global var
  236. if !@intervalID
  237. @intervalID = {}
  238. clearInterval( @intervalID[interval_id] ) if @intervalID[interval_id]
  239. interval: (callback, interval, interval_id) =>
  240. # check global var
  241. if !@intervalID
  242. @intervalID = {}
  243. callback()
  244. # auto save
  245. every = (ms, cb) -> setInterval cb, ms
  246. # clear auto save
  247. clearInterval( @intervalID[interval_id] ) if @intervalID[interval_id]
  248. # request new data
  249. @intervalID[interval_id] = every interval, () =>
  250. callback()
  251. userPopups: (position = 'right') ->
  252. # remove old popovers
  253. $('.popover-inner').parent().remove()
  254. # show user popup
  255. $('.user-data').popover(
  256. delay: { show: 500, hide: 1200 },
  257. # placement: 'bottom',
  258. placement: position,
  259. title: ->
  260. user_id = $(@).data('id')
  261. user = App.Collection.find( 'User', user_id )
  262. user.realname
  263. content: ->
  264. user_id = $(@).data('id')
  265. user = App.Collection.find( 'User', user_id )
  266. # get display data
  267. data = []
  268. for item in App.User.configure_attributes
  269. if user[item.name]
  270. if item.name isnt 'firstname'
  271. if item.name isnt 'lastname'
  272. if item.info #&& ( @user[item.name] || item.name isnt 'note' )
  273. data.push item
  274. # insert data
  275. App.view('user_info_small')(
  276. user: user,
  277. data: data,
  278. )
  279. )
  280. userTicketPopups: (data) ->
  281. # remove old popovers
  282. $('.popover-inner').parent().remove()
  283. # get data
  284. tickets = {}
  285. App.Com.ajax(
  286. type: 'GET',
  287. url: '/api/ticket_customer',
  288. data: {
  289. customer_id: data.user_id,
  290. }
  291. processData: true,
  292. success: (data, status, xhr) =>
  293. tickets = data.tickets
  294. )
  295. if !data.position
  296. data.position = 'left'
  297. # show user popup
  298. controller = @
  299. $(data.selector).popover(
  300. delay: { show: 500, hide: 5200 },
  301. placement: data.position,
  302. title: ->
  303. $(@).find('[title="*"]').val()
  304. content: ->
  305. type = $(@).filter('[data-type]').data('type')
  306. data = tickets[type] || []
  307. # set human time
  308. for ticket in data
  309. ticket.humanTime = controller.humanTime(ticket.created_at)
  310. # insert data
  311. App.view('user_ticket_info_small')(
  312. tickets: data,
  313. )
  314. )
  315. ws_send: (data) ->
  316. Spine.trigger( 'ws:send', JSON.stringify(data) )
  317. class App.ControllerModal extends App.Controller
  318. className: 'modal hide fade',
  319. tag: 'div',
  320. events:
  321. 'submit form': 'submit',
  322. 'click .submit': 'submit',
  323. 'click .cancel': 'modalHide',
  324. 'click .close': 'modalHide',
  325. constructor: (options) ->
  326. # do not use @el, because it's inserted by js
  327. if options
  328. delete options.el
  329. # callbacks
  330. # @callback = {}
  331. # if options.success
  332. # @callback.success = options.success
  333. # if options.error
  334. # @callback.error = options.error
  335. super(options)
  336. modalShow: (params) =>
  337. defaults = {
  338. backdrop: true,
  339. keyboard: true,
  340. show: true,
  341. }
  342. data = $.extend({}, defaults, params)
  343. @el.modal(data)
  344. @el.bind('hidden', =>
  345. # navigate back to home page
  346. if @pageData && @pageData.home
  347. @navigate @pageData.home
  348. # navigate back
  349. if params && params.navigateBack
  350. window.history.back()
  351. # remove modal from dom
  352. $('.modal').remove();
  353. )
  354. modalHide: (e) =>
  355. if e
  356. e.preventDefault()
  357. @el.modal('hide')
  358. submit: (e) =>
  359. e.preventDefault()
  360. @log 'You need to implement your own "submit" method!'
  361. class App.ErrorModal extends App.ControllerModal
  362. constructor: ->
  363. super
  364. @render()
  365. render: ->
  366. @html App.view('error')(
  367. message: @message
  368. )
  369. @modalShow(
  370. backdrop: false,
  371. keyboard: false,
  372. )