ticket_zoom.js.coffee 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. class App.TicketZoom extends App.Controller
  2. constructor: (params) ->
  3. super
  4. # check authentication
  5. return if !@authenticate()
  6. @navupdate '#'
  7. @edit_form = undefined
  8. @ticket_id = params.ticket_id
  9. @article_id = params.article_id
  10. @signature = undefined
  11. @doNotLog = params['doNotLog'] || 0
  12. @key = 'ticket::' + @ticket_id
  13. cache = App.Store.get( @key )
  14. if cache
  15. @load(cache)
  16. update = =>
  17. @fetch( @ticket_id, false )
  18. @interval( update, 300000, 'pull_check' )
  19. # fetch new data if triggered
  20. @bind(
  21. 'Ticket:updated'
  22. (data) =>
  23. update = =>
  24. if data.id.toString() is @ticket_id.toString()
  25. ticket = App.Ticket.find( @ticket_id )
  26. @log 'notice', 'TRY', data.updated_at, ticket.updated_at
  27. if data.updated_at isnt ticket.updated_at
  28. @fetch( @ticket_id, false )
  29. @delay( update, 1800, 'ticket-zoom-' + @ticket_id )
  30. )
  31. meta: =>
  32. meta =
  33. url: @url()
  34. id: @ticket_id
  35. if @ticket
  36. meta.head = @ticket.title
  37. meta.title = '#' + @ticket.number + ' - ' + @ticket.title
  38. meta
  39. url: =>
  40. '#ticket/zoom/' + @ticket_id
  41. activate: =>
  42. @navupdate '#'
  43. @el.find('textarea').elastic()
  44. changed: =>
  45. formCurrent = @formParam( @el.find('.ticket-update') )
  46. diff = difference( @formDefault, formCurrent )
  47. return false if !diff || _.isEmpty( diff )
  48. return true
  49. release: =>
  50. # nothing
  51. fetch: (ticket_id, force) ->
  52. return if !@Session.all()
  53. # get data
  54. @ajax(
  55. id: 'ticket_zoom_' + ticket_id
  56. type: 'GET'
  57. url: @apiPath + '/ticket_full/' + ticket_id + '?do_not_log=' + @doNotLog
  58. processData: true
  59. success: (data, status, xhr) =>
  60. # check if ticket has changed
  61. newTicketRaw = data.assets.tickets[ticket_id]
  62. if @ticketUpdatedAtLastCall && !force
  63. # return if ticket hasnt changed
  64. return if @ticketUpdatedAtLastCall is newTicketRaw.updated_at
  65. # notify if ticket changed not by my self
  66. if newTicketRaw.updated_by_id isnt @Session.all().id
  67. App.TaskManager.notify( @task_key )
  68. # rerender edit box
  69. @editDone = false
  70. # remember current data
  71. @ticketUpdatedAtLastCall = newTicketRaw.updated_at
  72. @load(data, force)
  73. App.Store.write( @key, data )
  74. error: (xhr, status, error) =>
  75. # do not close window if request is aborted
  76. return if status is 'abort'
  77. # do not close window on network error but if object is not found
  78. return if status is 'error' && error isnt 'Not Found'
  79. # remove task
  80. App.TaskManager.remove( @task_key )
  81. )
  82. @doNotLog = 1
  83. load: (data, force) =>
  84. # remember article ids
  85. @ticket_article_ids = data.ticket_article_ids
  86. # get edit form attributes
  87. @edit_form = data.edit_form
  88. # get signature
  89. @signature = data.signature
  90. # load collections
  91. App.Event.trigger 'loadAssets', data.assets
  92. # get data
  93. @ticket = App.Ticket.retrieve( @ticket_id )
  94. # render page
  95. @render(force)
  96. render: (force) =>
  97. # update taskbar with new meta data
  98. App.Event.trigger 'task:render'
  99. if !@renderDone
  100. @renderDone = true
  101. @html App.view('ticket_zoom')(
  102. ticket: @ticket
  103. nav: @nav
  104. isCustomer: @isRole('Customer')
  105. )
  106. # show frontend times
  107. @frontendTimeUpdate()
  108. @TicketTitle()
  109. @TicketWidgets()
  110. @TicketAction()
  111. @ArticleView()
  112. if force || !@editDone
  113. # reset form on force reload
  114. if force && _.isEmpty( App.TaskManager.get(@task_key).state )
  115. App.TaskManager.update( @task_key, { 'state': {} })
  116. @editDone = true
  117. # rerender widget if it hasn't changed
  118. if !@editWidget || _.isEmpty( App.TaskManager.get(@task_key).state )
  119. @editWidget = @Edit()
  120. # show text module UI
  121. if !@isRole('Customer')
  122. new App.WidgetTextModule(
  123. el: @el.find('textarea')
  124. data:
  125. ticket: @ticket
  126. )
  127. # scroll to article if given
  128. if @article_id && document.getElementById( 'article-' + @article_id )
  129. offset = document.getElementById( 'article-' + @article_id ).offsetTop
  130. offset = offset - 45
  131. scrollTo = ->
  132. @scrollTo( 0, offset )
  133. @delay( scrollTo, 100, false )
  134. TicketTitle: =>
  135. # show ticket title
  136. new TicketTitle(
  137. ticket: @ticket
  138. el: @el.find('.ticket-title')
  139. )
  140. ArticleView: =>
  141. # show article
  142. new ArticleView(
  143. ticket: @ticket
  144. ticket_article_ids: @ticket_article_ids
  145. el: @el.find('.article-view')
  146. ui: @
  147. )
  148. Edit: =>
  149. # show edit
  150. new Edit(
  151. ticket: @ticket
  152. el: @el.find('.edit')
  153. edit_form: @edit_form
  154. task_key: @task_key
  155. ui: @
  156. )
  157. TicketWidgets: =>
  158. # show ticket action row
  159. new TicketWidgets(
  160. ticket: @ticket
  161. task_key: @task_key
  162. el: @el.find('.ticket-widgets')
  163. ui: @
  164. )
  165. TicketAction: =>
  166. # start action controller
  167. if !@isRole('Customer')
  168. new TicketActionRow(
  169. el: @el.find('.ticket-action')
  170. ticket: @ticket
  171. ui: @
  172. )
  173. class TicketTitle extends App.Controller
  174. events:
  175. 'blur .ticket-title-update': 'update'
  176. constructor: ->
  177. super
  178. @render()
  179. render: ->
  180. @html App.view('ticket_zoom/title')(
  181. ticket: @ticket
  182. )
  183. update: (e) =>
  184. $this = $(e.target)
  185. title = $this.html()
  186. title = ('' + title)
  187. .replace(/<.+?>/g, '')
  188. title = ('' + title)
  189. .replace(/&nbsp;/g, ' ')
  190. .replace(/&amp;/g, '&')
  191. .replace(/&lt;/g, '<')
  192. .replace(/&gt;/g, '>')
  193. if title is '-'
  194. title = ''
  195. # update title
  196. ticket = App.Ticket.retrieve( @ticket.id )
  197. ticket.title = title
  198. ticket.load( title: title )
  199. ticket.save()
  200. # update taskbar with new meta data
  201. App.Event.trigger 'task:render'
  202. class TicketInfo extends App.ControllerDrox
  203. constructor: ->
  204. super
  205. @render()
  206. render: ->
  207. @html @template(
  208. file: 'ticket_zoom/info'
  209. header: '#' + @ticket.number
  210. params:
  211. ticket: @ticket
  212. )
  213. # start tag controller
  214. if !@isRole('Customer')
  215. new App.WidgetTag(
  216. el: @el.find('.tag_info')
  217. object_type: 'Ticket'
  218. object: @ticket
  219. )
  220. class TicketWidgets extends App.Controller
  221. constructor: ->
  222. super
  223. @render()
  224. render: ->
  225. @html App.view('ticket_zoom/widgets')()
  226. # show ticket info
  227. new TicketInfo(
  228. ticket: @ticket
  229. el: @el.find('.ticket_info')
  230. )
  231. # start customer info controller
  232. if !@isRole('Customer')
  233. new App.WidgetUser(
  234. el: @el.find('.customer_info')
  235. user_id: @ticket.customer_id
  236. ticket: @ticket
  237. )
  238. # start link info controller
  239. if !@isRole('Customer')
  240. new App.WidgetLink(
  241. el: @el.find('.link_info')
  242. object_type: 'Ticket'
  243. object: @ticket
  244. )
  245. class Edit extends App.Controller
  246. events:
  247. 'click .submit': 'update'
  248. 'click [data-type="reset"]': 'reset'
  249. constructor: ->
  250. super
  251. @render()
  252. release: =>
  253. @autosaveStop()
  254. render: ->
  255. ticket = App.Ticket.retrieve( @ticket.id )
  256. @html App.view('ticket_zoom/edit')(
  257. ticket: ticket
  258. isCustomer: @isRole('Customer')
  259. formChanged: !_.isEmpty( App.TaskManager.get(@task_key).state )
  260. )
  261. @configure_attributes_ticket = [
  262. { name: 'ticket_state_id', display: 'State', tag: 'select', multiple: false, null: true, relation: 'TicketState', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' },
  263. { name: 'ticket_priority_id', display: 'Priority', tag: 'select', multiple: false, null: true, relation: 'TicketPriority', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' },
  264. { name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: true, relation: 'Group', filter: @edit_form, class: 'span2', item_class: 'pull-left' },
  265. { name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: true, relation: 'User', filter: @edit_form, nulloption: true, class: 'span2', item_class: 'pull-left' },
  266. ]
  267. if @isRole('Customer')
  268. @configure_attributes_ticket = [
  269. { name: 'ticket_state_id', display: 'State', tag: 'select', multiple: false, null: true, relation: 'TicketState', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' },
  270. { name: 'ticket_priority_id', display: 'Priority', tag: 'select', multiple: false, null: true, relation: 'TicketPriority', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' },
  271. ]
  272. @configure_attributes_article = [
  273. { name: 'ticket_article_type_id', display: 'Type', tag: 'select', multiple: false, null: true, relation: 'TicketArticleType', filter: @edit_form, default: '9', translate: true, class: 'medium' },
  274. { name: 'internal', display: 'Visibility', tag: 'select', null: true, options: { true: 'internal', false: 'public' }, class: 'medium', item_class: '', default: false },
  275. { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
  276. { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
  277. # { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
  278. { name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
  279. { name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true },
  280. ]
  281. if @isRole('Customer')
  282. @configure_attributes_article = [
  283. { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
  284. { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
  285. # { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', hide: true },
  286. { name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' },
  287. { name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true },
  288. ]
  289. @form_id = App.ControllerForm.formId()
  290. defaults = ticket
  291. if !_.isEmpty( App.TaskManager.get(@task_key).state )
  292. defaults = App.TaskManager.get(@task_key).state
  293. new App.ControllerForm(
  294. el: @el.find('.form-ticket-update')
  295. form_id: @form_id
  296. model:
  297. configure_attributes: @configure_attributes_ticket
  298. className: 'update_ticket_' + ticket.id
  299. params: defaults
  300. form_data: @edit_form
  301. )
  302. new App.ControllerForm(
  303. el: @el.find('.form-article-update')
  304. form_id: @form_id
  305. model:
  306. configure_attributes: @configure_attributes_article
  307. className: 'update_ticket_' + ticket.id
  308. form_data: @edit_form
  309. params: defaults
  310. dependency: [
  311. {
  312. bind: {
  313. name: 'ticket_article_type_id'
  314. relation: 'TicketArticleType'
  315. value: ['email']
  316. },
  317. change: {
  318. action: 'show'
  319. name: ['to', 'cc'],
  320. },
  321. },
  322. {
  323. bind: {
  324. name: 'ticket_article_type_id'
  325. relation: 'TicketArticleType'
  326. value: ['note', 'twitter status', 'twitter direct-message']
  327. },
  328. change: {
  329. action: 'hide'
  330. name: ['to', 'cc'],
  331. },
  332. },
  333. ]
  334. )
  335. @el.find('textarea').elastic()
  336. # remember form defaults
  337. @ui.formDefault = @formParam( @el.find('.ticket-update') )
  338. # start auto save
  339. @autosaveStart()
  340. # enable user popups
  341. @userPopups()
  342. autosaveStop: =>
  343. @clearInterval( 'autosave' )
  344. autosaveStart: =>
  345. @autosaveLast = _.clone( @ui.formDefault )
  346. update = =>
  347. currentData = @formParam( @el.find('.ticket-update') )
  348. diff = difference( @autosaveLast, currentData )
  349. if !@autosaveLast || ( diff && !_.isEmpty( diff ) )
  350. @autosaveLast = currentData
  351. @log 'notice', 'form hash changed', diff, currentData
  352. @el.find('.edit-ticket').addClass('form-changed')
  353. @el.find('.edit-ticket').find('.reset-message').show()
  354. @el.find('.edit-ticket').find('.reset-message').removeClass('hide')
  355. App.TaskManager.update( @task_key, { 'state': currentData })
  356. @interval( update, 3000, 'autosave' )
  357. update: (e) =>
  358. e.preventDefault()
  359. @autosaveStop()
  360. params = @formParam(e.target)
  361. ticket = App.Ticket.retrieve( @ticket.id )
  362. @log 'notice', 'update', params, ticket
  363. # find sender_id
  364. if @isRole('Customer')
  365. sender = App.TicketArticleSender.findByAttribute( 'name', 'Customer' )
  366. article_type = App.TicketArticleType.findByAttribute( 'name', 'web' )
  367. params.ticket_article_type_id = article_type.id
  368. params.ticket_article_sender_id = sender.id
  369. else
  370. sender = App.TicketArticleSender.findByAttribute( 'name', 'Agent' )
  371. article_type = App.TicketArticleType.find( params['ticket_article_type_id'] )
  372. params.ticket_article_sender_id = sender.id
  373. # update ticket
  374. ticket_update = {}
  375. for item in @configure_attributes_ticket
  376. ticket_update[item.name] = params[item.name]
  377. # check owner assignment
  378. if !@isRole('Customer')
  379. if !ticket_update['owner_id']
  380. ticket_update['owner_id'] = 1
  381. # check if title exists
  382. if !ticket_update['title'] && !ticket.title
  383. alert( App.i18n.translateContent('Title needed') )
  384. return
  385. # validate email params
  386. if article_type.name is 'email'
  387. # check if recipient exists
  388. if !params['to'] && !params['cc']
  389. alert( App.i18n.translateContent('Need recipient in "To" or "Cc".') )
  390. return
  391. # check if message exists
  392. if !params['body']
  393. alert( App.i18n.translateContent('Text needed') )
  394. return
  395. # check attachment
  396. if params['body']
  397. attachmentTranslated = App.i18n.translateContent('Attachment')
  398. attachmentTranslatedRegExp = new RegExp( attachmentTranslated, 'i' )
  399. if params['body'].match(/attachment/i) || params['body'].match( attachmentTranslatedRegExp )
  400. if !confirm( App.i18n.translateContent('You use attachment in text but no attachment is attached. Do you want to continue?') )
  401. @autosaveStart()
  402. return
  403. ticket.load( ticket_update )
  404. @log 'notice', 'update ticket', ticket_update, ticket
  405. # disable form
  406. @formDisable(e)
  407. # validate ticket
  408. errors = ticket.validate()
  409. if errors
  410. @log 'error', 'update', errors
  411. @formEnable(e)
  412. @autosaveStart()
  413. return
  414. # validate article
  415. if params['body']
  416. article = new App.TicketArticle
  417. params.from = @Session.get( 'firstname' ) + ' ' + @Session.get( 'lastname' )
  418. params.ticket_id = ticket.id
  419. params.form_id = @form_id
  420. if !params['internal']
  421. params['internal'] = false
  422. @log 'notice', 'update article', params, sender
  423. article.load(params)
  424. errors = article.validate()
  425. if errors
  426. @log 'error', 'update article', errors
  427. @formEnable(e)
  428. @autosaveStart()
  429. return
  430. ticket.save(
  431. success: (r) =>
  432. # reset form after save
  433. if article
  434. article.save(
  435. success: (r) =>
  436. @ui.fetch( ticket.id, true )
  437. # reset form after save
  438. App.TaskManager.update( @task_key, { 'state': {} })
  439. error: (r) =>
  440. @log 'error', 'update article', r
  441. )
  442. else
  443. # reset form after save
  444. App.TaskManager.update( @task_key, { 'state': {} })
  445. @ui.fetch( ticket.id, true )
  446. )
  447. reset: (e) =>
  448. e.preventDefault()
  449. App.TaskManager.update( @task_key, { 'state': {} })
  450. @render()
  451. class ArticleView extends App.Controller
  452. events:
  453. 'click [data-type=public]': 'public_internal'
  454. 'click [data-type=internal]': 'public_internal'
  455. 'click .show_toogle': 'show_toogle'
  456. 'click [data-type=reply]': 'reply'
  457. # 'click [data-type=reply-all]': 'replyall'
  458. constructor: ->
  459. super
  460. @render()
  461. render: ->
  462. # get all articles
  463. @articles = []
  464. for article_id in @ticket_article_ids
  465. article = App.TicketArticle.retrieve( article_id )
  466. @articles.push article
  467. # rework articles
  468. for article in @articles
  469. new Article( article: article )
  470. @html App.view('ticket_zoom/article_view')(
  471. ticket: @ticket
  472. articles: @articles
  473. isCustomer: @isRole('Customer')
  474. )
  475. # show frontend times
  476. @frontendTimeUpdate()
  477. # enable user popups
  478. @userPopups()
  479. public_internal: (e) ->
  480. e.preventDefault()
  481. article_id = $(e.target).parents('[data-id]').data('id')
  482. # storage update
  483. article = App.TicketArticle.find(article_id)
  484. internal = true
  485. if article.internal == true
  486. internal = false
  487. article.updateAttributes(
  488. internal: internal
  489. )
  490. # runtime update
  491. for article in @articles
  492. if article_id is article.id
  493. article['internal'] = internal
  494. @render()
  495. show_toogle: (e) ->
  496. e.preventDefault()
  497. $(e.target).hide()
  498. if $(e.target).next('div')[0]
  499. $(e.target).next('div').removeClass('hide')
  500. else
  501. $(e.target).parent().next('div').removeClass('hide')
  502. checkIfSignatureIsNeeded: (article_type) =>
  503. # add signature
  504. if @ui.signature && @ui.signature.body && article_type.name is 'email'
  505. body = @ui.el.find('[name="body"]').val() || ''
  506. regexp = new RegExp( escapeRegExp( @ui.signature.body ) , 'i')
  507. if !body.match(regexp)
  508. body = body + "\n" + @ui.signature.body
  509. @ui.el.find('[name="body"]').val( body )
  510. # update textarea size
  511. @ui.el.find('[name="body"]').trigger('change')
  512. reply: (e) =>
  513. e.preventDefault()
  514. article_id = $(e.target).parents('[data-id]').data('id')
  515. article = App.TicketArticle.find( article_id )
  516. article_type = App.TicketArticleType.find( article.ticket_article_type_id )
  517. customer = App.User.find( article.created_by_id )
  518. # update form
  519. @checkIfSignatureIsNeeded(article_type)
  520. # preselect article type
  521. @ui.el.find('[name="ticket_article_type_id"]').find('option:selected').removeAttr('selected')
  522. @ui.el.find('[name="ticket_article_type_id"]').find('[value="' + article_type.id + '"]').attr('selected',true)
  523. @ui.el.find('[name="ticket_article_type_id"]').trigger('change')
  524. # empty form
  525. #@ui.el.find('[name="to"]').val('')
  526. #@ui.el.find('[name="cc"]').val('')
  527. #@ui.el.find('[name="subject"]').val('')
  528. @ui.el.find('[name="in_reply_to"]').val('')
  529. if article.message_id
  530. @ui.el.find('[name="in_reply_to"]').val(article.message_id)
  531. if article_type.name is 'twitter status'
  532. # set to in body
  533. to = customer.accounts['twitter'].username || customer.accounts['twitter'].uid
  534. @ui.el.find('[name="body"]').val('@' + to)
  535. else if article_type.name is 'twitter direct-message'
  536. # show to
  537. to = customer.accounts['twitter'].username || customer.accounts['twitter'].uid
  538. @ui.el.find('[name="to"]').val(to)
  539. else if article_type.name is 'email'
  540. @ui.el.find('[name="to"]').val(article.from)
  541. # add quoted text if needed
  542. selectedText = App.ClipBoard.getSelected()
  543. if selectedText
  544. body = @ui.el.find('[name="body"]').val() || ''
  545. selectedText = selectedText.replace /^(.*)$/mg, (match) =>
  546. '> ' + match
  547. body = selectedText + "\n" + body
  548. @ui.el.find('[name="body"]').val(body)
  549. # update textarea size
  550. @ui.el.find('[name="body"]').trigger('change')
  551. class Article extends App.Controller
  552. constructor: ->
  553. super
  554. # define actions
  555. @actionRow()
  556. # check attachments
  557. @attachments()
  558. # html rework
  559. @preview()
  560. preview: ->
  561. # build html body
  562. # cleanup body
  563. # @article['html'] = @article.body.trim()
  564. @article['html'] = $.trim( @article.body )
  565. @article['html'].replace( /\n\r/g, "\n" )
  566. @article['html'].replace( /\n\n\n/g, "\n\n" )
  567. # if body has more then x lines / else search for signature
  568. preview = 10
  569. preview_mode = false
  570. article_lines = @article['html'].split(/\n/)
  571. if article_lines.length > preview
  572. preview_mode = true
  573. if article_lines[preview] is ''
  574. article_lines.splice( preview, 0, '-----SEEMORE-----' )
  575. else
  576. article_lines.splice( preview - 1, 0, '-----SEEMORE-----' )
  577. @article['html'] = article_lines.join("\n")
  578. @article['html'] = window.linkify( @article['html'] )
  579. notify = '<a href="#" class="show_toogle">' + App.i18n.translateContent('See more') + '</a>'
  580. # preview mode
  581. if preview_mode
  582. @article_changed = false
  583. @article['html'] = @article['html'].replace /^-----SEEMORE-----\n/m, (match) =>
  584. @article_changed = true
  585. notify + '<div class="hide">'
  586. if @article_changed
  587. @article['html'] = @article['html'] + '</div>'
  588. # hide signatures and so on
  589. else
  590. @article_changed = false
  591. @article['html'] = @article['html'].replace /^\n{0,10}(--|__)/m, (match) =>
  592. @article_changed = true
  593. notify + '<div class="hide">' + match
  594. if @article_changed
  595. @article['html'] = @article['html'] + '</div>'
  596. actionRow: ->
  597. if @isRole('Customer')
  598. @article.actions = []
  599. return
  600. actions = []
  601. if @article.internal is true
  602. actions = [
  603. {
  604. name: 'set to public'
  605. type: 'public'
  606. }
  607. ]
  608. else
  609. actions = [
  610. {
  611. name: 'set to internal'
  612. type: 'internal'
  613. }
  614. ]
  615. if @article.article_type.name is 'note'
  616. # actions.push []
  617. else
  618. if @article.article_sender.name is 'Customer'
  619. actions.push {
  620. name: 'reply'
  621. type: 'reply'
  622. href: '#'
  623. }
  624. # actions.push {
  625. # name: 'reply all'
  626. # type: 'reply-all'
  627. # href: '#'
  628. # }
  629. actions.push {
  630. name: 'split'
  631. type: 'split'
  632. href: '#ticket_create/call_inbound/' + @article.ticket_id + '/' + @article.id
  633. }
  634. @article.actions = actions
  635. attachments: ->
  636. if @article.attachments
  637. for attachment in @article.attachments
  638. attachment.size = @humanFileSize(attachment.size)
  639. class TicketActionRow extends App.Controller
  640. events:
  641. 'click [data-type=history]': 'history_dialog'
  642. 'click [data-type=merge]': 'merge_dialog'
  643. 'click [data-type=customer]': 'customer_dialog'
  644. constructor: ->
  645. super
  646. @render()
  647. render: ->
  648. @html App.view('ticket_zoom/actions')()
  649. history_dialog: (e) ->
  650. e.preventDefault()
  651. new App.TicketHistory( ticket_id: @ticket.id )
  652. merge_dialog: (e) ->
  653. e.preventDefault()
  654. new App.TicketMerge( ticket_id: @ticket.id, task_key: @ui.task_key )
  655. customer_dialog: (e) ->
  656. e.preventDefault()
  657. new App.TicketCustomer( ticket_id: @ticket.id, ui: @ui )
  658. class TicketZoomRouter extends App.ControllerPermanent
  659. constructor: (params) ->
  660. super
  661. # cleanup params
  662. clean_params =
  663. ticket_id: params.ticket_id
  664. article_id: params.article_id
  665. nav: params.nav
  666. App.TaskManager.add( 'Ticket-' + @ticket_id, 'TicketZoom', clean_params )
  667. App.Config.set( 'ticket/zoom/:ticket_id', TicketZoomRouter, 'Routes' )
  668. App.Config.set( 'ticket/zoom/:ticket_id/nav/:nav', TicketZoomRouter, 'Routes' )
  669. App.Config.set( 'ticket/zoom/:ticket_id/:article_id', TicketZoomRouter, 'Routes' )