chat.coffee 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. do($ = window.jQuery, window) ->
  2. scripts = document.getElementsByTagName('script')
  3. myScript = scripts[scripts.length - 1]
  4. scriptHost = myScript.src.match('.*://([^:/]*).*')[1]
  5. # Define the plugin class
  6. class Base
  7. defaults:
  8. debug: false
  9. constructor: (options) ->
  10. @options = $.extend {}, @defaults, options
  11. @log = new Log(debug: @options.debug, logPrefix: @options.logPrefix || @logPrefix)
  12. class Log
  13. defaults:
  14. debug: false
  15. constructor: (options) ->
  16. @options = $.extend {}, @defaults, options
  17. debug: (items...) =>
  18. return if !@options.debug
  19. @log('debug', items)
  20. notice: (items...) =>
  21. @log('notice', items)
  22. error: (items...) =>
  23. @log('error', items)
  24. log: (level, items) =>
  25. items.unshift('||')
  26. items.unshift(level)
  27. items.unshift(@options.logPrefix)
  28. console.log.apply console, items
  29. return if !@options.debug
  30. logString = ''
  31. for item in items
  32. logString += ' '
  33. if typeof item is 'object'
  34. logString += JSON.stringify(item)
  35. else if item && item.toString
  36. logString += item.toString()
  37. else
  38. logString += item
  39. $('.js-chatLogDisplay').prepend('<div>' + logString + '</div>')
  40. class Timeout extends Base
  41. timeoutStartedAt: null
  42. logPrefix: 'timeout'
  43. defaults:
  44. debug: false
  45. timeout: 4
  46. timeoutIntervallCheck: 0.5
  47. constructor: (options) ->
  48. super(options)
  49. start: =>
  50. @stop()
  51. timeoutStartedAt = new Date
  52. check = =>
  53. timeLeft = new Date - new Date(timeoutStartedAt.getTime() + @options.timeout * 1000 * 60)
  54. @log.debug "Timeout check for #{@options.timeout} minutes (left #{timeLeft/1000} sec.)"#, new Date
  55. return if timeLeft < 0
  56. @stop()
  57. @options.callback()
  58. @log.debug "Start timeout in #{@options.timeout} minutes"#, new Date
  59. @intervallId = setInterval(check, @options.timeoutIntervallCheck * 1000 * 60)
  60. stop: =>
  61. return if !@intervallId
  62. @log.debug "Stop timeout of #{@options.timeout} minutes"#, new Date
  63. clearInterval(@intervallId)
  64. class Io extends Base
  65. logPrefix: 'io'
  66. constructor: (options) ->
  67. super(options)
  68. set: (params) =>
  69. for key, value of params
  70. @options[key] = value
  71. connect: =>
  72. @log.debug "Connecting to #{@options.host}"
  73. @ws = new window.WebSocket("#{@options.host}")
  74. @ws.onopen = (e) =>
  75. @log.debug 'onOpen', e
  76. @options.onOpen(e)
  77. @ws.onmessage = (e) =>
  78. pipes = JSON.parse(e.data)
  79. @log.debug 'onMessage', e.data
  80. if @options.onMessage
  81. @options.onMessage(pipes)
  82. @ws.onclose = (e) =>
  83. @log.debug 'close websocket connection', e
  84. if @manualClose
  85. @log.debug 'manual close, onClose callback'
  86. @manualClose = false
  87. if @options.onClose
  88. @options.onClose(e)
  89. else
  90. @log.debug 'error close, onError callback'
  91. if @options.onError
  92. @options.onError('Connection lost...')
  93. @ws.onerror = (e) =>
  94. @log.debug 'onError', e
  95. if @options.onError
  96. @options.onError(e)
  97. close: =>
  98. @log.debug 'close websocket manually'
  99. @manualClose = true
  100. @ws.close()
  101. reconnect: =>
  102. @log.debug 'reconnect'
  103. @close()
  104. @connect()
  105. send: (event, data = {}) =>
  106. @log.debug 'send', event, data
  107. msg = JSON.stringify
  108. event: event
  109. data: data
  110. @ws.send msg
  111. class ZammadChat extends Base
  112. defaults:
  113. chatId: undefined
  114. show: true
  115. target: $('body')
  116. host: ''
  117. debug: false
  118. flat: false
  119. lang: undefined
  120. cssAutoload: true
  121. cssUrl: undefined
  122. fontSize: undefined
  123. buttonClass: 'open-zammad-chat'
  124. inactiveClass: 'is-inactive'
  125. title: '<strong>Chat</strong> with us!'
  126. idleTimeout: 6
  127. idleTimeoutIntervallCheck: 0.5
  128. inactiveTimeout: 8
  129. inactiveTimeoutIntervallCheck: 0.5
  130. waitingListTimeout: 4
  131. waitingListTimeoutIntervallCheck: 0.5
  132. logPrefix: 'chat'
  133. _messageCount: 0
  134. isOpen: false
  135. blinkOnlineInterval: null
  136. stopBlinOnlineStateTimeout: null
  137. showTimeEveryXMinutes: 1
  138. lastTimestamp: null
  139. lastAddedType: null
  140. inputTimeout: null
  141. isTyping: false
  142. state: 'offline'
  143. initialQueueDelay: 10000
  144. translations:
  145. de:
  146. '<strong>Chat</strong> with us!': '<strong>Chat</strong> mit uns!'
  147. 'Online': 'Online'
  148. 'Online': 'Online'
  149. 'Offline': 'Offline'
  150. 'Connecting': 'Verbinden'
  151. 'Connection re-established': 'Verbindung wiederhergestellt'
  152. 'Today': 'Heute'
  153. 'Send': 'Senden'
  154. 'Compose your message...': 'Ihre Nachricht...'
  155. 'All colleges are busy.': 'Alle Kollegen sind belegt.'
  156. 'You are on waiting list position <strong>%s</strong>.': 'Sie sind in der Warteliste an der Position <strong>%s</strong>.'
  157. 'Start new conversation': 'Neue Konversation starten'
  158. 'Since you didn\'t respond in the last %s minutes your conversation with <strong>%s</strong> got closed.': 'Da Sie in den letzten %s Minuten nichts geschrieben haben wurde Ihre Konversation mit <strong>%s</strong> geschlossen.'
  159. 'Since you didn\'t respond in the last %s minutes your conversation got closed.': 'Da Sie in den letzten %s Minuten nichts geschrieben haben wurde Ihre Konversation geschlossen.'
  160. sessionId: undefined
  161. T: (string, items...) =>
  162. if @options.lang && @options.lang isnt 'en'
  163. if !@translations[@options.lang]
  164. @log.notice "Translation '#{@options.lang}' needed!"
  165. else
  166. translations = @translations[@options.lang]
  167. if !translations[string]
  168. @log.notice "Translation needed for '#{string}'"
  169. string = translations[string] || string
  170. if items
  171. for item in items
  172. string = string.replace(/%s/, item)
  173. string
  174. view: (name) =>
  175. return (options) =>
  176. if !options
  177. options = {}
  178. options.T = @T
  179. options.background = @options.background
  180. options.flat = @options.flat
  181. options.fontSize = @options.fontSize
  182. return window.zammadChatTemplates[name](options)
  183. constructor: (options) ->
  184. @options = $.extend {}, @defaults, options
  185. super(@options)
  186. # check prerequisites
  187. if !$
  188. @state = 'unsupported'
  189. @log.notice 'Chat: no jquery found!'
  190. return
  191. if !window.WebSocket or !sessionStorage
  192. @state = 'unsupported'
  193. @log.notice 'Chat: Browser not supported!'
  194. return
  195. if !@options.chatId
  196. @state = 'unsupported'
  197. @log.error 'Chat: need chatId as option!'
  198. return
  199. # detect language
  200. if !@options.lang
  201. @options.lang = $('html').attr('lang')
  202. if @options.lang
  203. @options.lang = @options.lang.replace(/-.+?$/, '') # replace "-xx" of xx-xx
  204. @log.debug "lang: #{@options.lang}"
  205. # detect host
  206. @detectHost() if !@options.host
  207. @loadCss()
  208. @io = new Io(@options)
  209. @io.set(
  210. onOpen: @render
  211. onClose: @onWebSocketClose
  212. onMessage: @onWebSocketMessage
  213. onError: @onError
  214. )
  215. @io.connect()
  216. render: =>
  217. if !@el || !$('.zammad-chat').get(0)
  218. @el = $(@view('chat')(
  219. title: @options.title
  220. ))
  221. @options.target.append @el
  222. @input = @el.find('.zammad-chat-input')
  223. # start bindings
  224. @el.find('.js-chat-open').click @open
  225. @el.find('.js-chat-close').click @close
  226. @el.find('.zammad-chat-controls').on 'submit', @onSubmit
  227. @input.on
  228. keydown: @checkForEnter
  229. input: @onInput
  230. $(window).on('beforeunload', =>
  231. @onLeaveTemporary()
  232. )
  233. $(window).bind('hashchange', =>
  234. return if @isOpen
  235. @idleTimeout.start()
  236. )
  237. # disable open button
  238. $(".#{ @options.buttonClass }").addClass @inactiveClass
  239. @setAgentOnlineState 'online'
  240. @log.debug 'widget rendered'
  241. @startTimeoutObservers()
  242. @idleTimeout.start()
  243. # get current chat status
  244. @sessionId = sessionStorage.getItem('sessionId')
  245. @send 'chat_status_customer',
  246. session_id: @sessionId
  247. checkForEnter: (event) =>
  248. if not event.shiftKey and event.keyCode is 13
  249. event.preventDefault()
  250. @sendMessage()
  251. send: (event, data = {}) =>
  252. data.chat_id = @options.chatId
  253. @io.send(event, data)
  254. onWebSocketMessage: (pipes) =>
  255. for pipe in pipes
  256. @log.debug 'ws:onmessage', pipe
  257. switch pipe.event
  258. when 'chat_error'
  259. @log.notice pipe.data
  260. if pipe.data && pipe.data.state is 'chat_disabled'
  261. @destroy(remove: true)
  262. when 'chat_session_message'
  263. return if pipe.data.self_written
  264. @receiveMessage pipe.data
  265. when 'chat_session_typing'
  266. return if pipe.data.self_written
  267. @onAgentTypingStart()
  268. when 'chat_session_start'
  269. @onConnectionEstablished pipe.data
  270. when 'chat_session_queue'
  271. @onQueueScreen pipe.data
  272. when 'chat_session_closed'
  273. @onSessionClosed pipe.data
  274. when 'chat_session_left'
  275. @onSessionClosed pipe.data
  276. when 'chat_status_customer'
  277. switch pipe.data.state
  278. when 'online'
  279. @sessionId = undefined
  280. @onReady()
  281. when 'offline'
  282. @onError 'Zammad Chat: No agent online'
  283. when 'chat_disabled'
  284. @onError 'Zammad Chat: Chat is disabled'
  285. when 'no_seats_available'
  286. @onError "Zammad Chat: Too many clients in queue. Clients in queue: #{pipe.data.queue}"
  287. when 'reconnect'
  288. @onReopenSession pipe.data
  289. onReady: ->
  290. @log.debug 'widget ready for use'
  291. $(".#{ @options.buttonClass }").click(@open).removeClass(@inactiveClass)
  292. if @options.show
  293. @show()
  294. onError: (message) =>
  295. @log.debug message
  296. @addStatus(message)
  297. $(".#{ @options.buttonClass }").hide()
  298. if @isOpen
  299. @disableInput()
  300. @destroy(remove: false)
  301. else
  302. @destroy(remove: true)
  303. onReopenSession: (data) =>
  304. @log.debug 'old messages', data.session
  305. @inactiveTimeout.start()
  306. unfinishedMessage = sessionStorage.getItem 'unfinished_message'
  307. # rerender chat history
  308. if data.agent
  309. @onConnectionEstablished(data)
  310. for message in data.session
  311. @renderMessage
  312. message: message.content
  313. id: message.id
  314. from: if message.created_by_id then 'agent' else 'customer'
  315. if unfinishedMessage
  316. @input.val unfinishedMessage
  317. # show wait list
  318. if data.position
  319. @onQueue data
  320. @show()
  321. @open()
  322. @scrollToBottom()
  323. if unfinishedMessage
  324. @input.focus()
  325. onInput: =>
  326. # remove unread-state from messages
  327. @el.find('.zammad-chat-message--unread')
  328. .removeClass 'zammad-chat-message--unread'
  329. sessionStorage.setItem 'unfinished_message', @input.val()
  330. @onTyping()
  331. onTyping: ->
  332. # send typing start event only every 1.5 seconds
  333. return if @isTyping && @isTyping > new Date(new Date().getTime() - 1500)
  334. @isTyping = new Date()
  335. @send 'chat_session_typing',
  336. session_id: @sessionId
  337. @inactiveTimeout.start()
  338. onSubmit: (event) =>
  339. event.preventDefault()
  340. @sendMessage()
  341. sendMessage: ->
  342. message = @input.val()
  343. return if !message
  344. @inactiveTimeout.start()
  345. sessionStorage.removeItem 'unfinished_message'
  346. messageElement = @view('message')
  347. message: message
  348. from: 'customer'
  349. id: @_messageCount++
  350. unreadClass: ''
  351. @maybeAddTimestamp()
  352. # add message before message typing loader
  353. if @el.find('.zammad-chat-message--typing').size()
  354. @lastAddedType = 'typing-placeholder'
  355. @el.find('.zammad-chat-message--typing').before messageElement
  356. else
  357. @lastAddedType = 'message--customer'
  358. @el.find('.zammad-chat-body').append messageElement
  359. @input.val('')
  360. @scrollToBottom()
  361. # send message event
  362. @send 'chat_session_message',
  363. content: message
  364. id: @_messageCount
  365. session_id: @sessionId
  366. receiveMessage: (data) =>
  367. @inactiveTimeout.start()
  368. # hide writing indicator
  369. @onAgentTypingEnd()
  370. @maybeAddTimestamp()
  371. @renderMessage
  372. message: data.message.content
  373. id: data.id
  374. from: 'agent'
  375. renderMessage: (data) =>
  376. @lastAddedType = "message--#{ data.from }"
  377. data.unreadClass = if document.hidden then ' zammad-chat-message--unread' else ''
  378. @el.find('.zammad-chat-body').append @view('message')(data)
  379. @scrollToBottom()
  380. open: =>
  381. if @isOpen
  382. @log.debug 'widget already open, block'
  383. return
  384. @isOpen = true
  385. @log.debug 'open widget'
  386. if !@sessionId
  387. @showLoader()
  388. @el.addClass('zammad-chat-is-open')
  389. if !@sessionId
  390. @el.animate { bottom: 0 }, 500, @onOpenAnimationEnd
  391. @send('chat_session_init')
  392. else
  393. @el.css 'bottom', 0
  394. @onOpenAnimationEnd()
  395. onOpenAnimationEnd: =>
  396. @idleTimeout.stop()
  397. sessionClose: =>
  398. # send close
  399. @send 'chat_session_close',
  400. session_id: @sessionId
  401. # stop timer
  402. @inactiveTimeout.stop()
  403. @waitingListTimeout.stop()
  404. # delete input store
  405. sessionStorage.removeItem 'unfinished_message'
  406. # stop delay of initial queue position
  407. if @onInitialQueueDelayId
  408. clearTimeout(@onInitialQueueDelayId)
  409. @setSessionId undefined
  410. close: (event) =>
  411. if !@isOpen
  412. @log.debug 'can\'t close widget, it\'s not open'
  413. return
  414. if !@sessionId
  415. @log.debug 'can\'t close widget without sessionId'
  416. return
  417. @log.debug 'close widget'
  418. event.stopPropagation() if event
  419. @sessionClose()
  420. # close window
  421. @el.removeClass('zammad-chat-is-open')
  422. remainerHeight = @el.height() - @el.find('.zammad-chat-header').outerHeight()
  423. @el.animate { bottom: -remainerHeight }, 500, @onCloseAnimationEnd
  424. onCloseAnimationEnd: =>
  425. @el.removeClass('zammad-chat-is-visible')
  426. @showLoader()
  427. @el.find('.zammad-chat-welcome').removeClass('zammad-chat-is-hidden')
  428. @el.find('.zammad-chat-agent').addClass('zammad-chat-is-hidden')
  429. @el.find('.zammad-chat-agent-status').addClass('zammad-chat-is-hidden')
  430. @isOpen = false
  431. @io.reconnect()
  432. onWebSocketClose: =>
  433. return if @isOpen
  434. if @el
  435. @el.removeClass('zammad-chat-is-shown')
  436. show: ->
  437. return if @state is 'offline'
  438. @el.addClass('zammad-chat-is-shown')
  439. if !@inputInitialized
  440. @inputInitialized = true
  441. @input.autoGrow
  442. extraLine: false
  443. remainerHeight = @el.height() - @el.find('.zammad-chat-header').outerHeight()
  444. @el.css 'bottom', -remainerHeight
  445. disableInput: ->
  446. @input.prop('disabled', true)
  447. @el.find('.zammad-chat-send').prop('disabled', true)
  448. enableInput: ->
  449. @input.prop('disabled', false)
  450. @el.find('.zammad-chat-send').prop('disabled', false)
  451. onQueueScreen: (data) =>
  452. @setSessionId data.session_id
  453. # delay initial queue position, show connecting first
  454. show = =>
  455. @onQueue data
  456. @waitingListTimeout.start()
  457. if @initialQueueDelay && !@onInitialQueueDelayId
  458. @onInitialQueueDelayId = setTimeout(show, @initialQueueDelay)
  459. return
  460. # stop delay of initial queue position
  461. if @onInitialQueueDelayId
  462. clearTimeout(@onInitialQueueDelayId)
  463. # show queue position
  464. show()
  465. onQueue: (data) =>
  466. @log.notice 'onQueue', data.position
  467. @inQueue = true
  468. @el.find('.zammad-chat-body').html @view('waiting')
  469. position: data.position
  470. onAgentTypingStart: =>
  471. if @stopTypingId
  472. clearTimeout(@stopTypingId)
  473. @stopTypingId = setTimeout(@onAgentTypingEnd, 3000)
  474. # never display two typing indicators
  475. return if @el.find('.zammad-chat-message--typing').size()
  476. @maybeAddTimestamp()
  477. @el.find('.zammad-chat-body').append @view('typingIndicator')()
  478. @scrollToBottom()
  479. onAgentTypingEnd: =>
  480. @el.find('.zammad-chat-message--typing').remove()
  481. onLeaveTemporary: =>
  482. return if !@sessionId
  483. @send 'chat_session_leave_temporary',
  484. session_id: @sessionId
  485. maybeAddTimestamp: ->
  486. timestamp = Date.now()
  487. if !@lastTimestamp or (timestamp - @lastTimestamp) > @showTimeEveryXMinutes * 60000
  488. label = @T('Today')
  489. time = new Date().toTimeString().substr 0,5
  490. if @lastAddedType is 'timestamp'
  491. # update last time
  492. @updateLastTimestamp label, time
  493. @lastTimestamp = timestamp
  494. else
  495. # add new timestamp
  496. @el.find('.zammad-chat-body').append @view('timestamp')
  497. label: label
  498. time: time
  499. @lastTimestamp = timestamp
  500. @lastAddedType = 'timestamp'
  501. @scrollToBottom()
  502. updateLastTimestamp: (label, time) ->
  503. return if !@el
  504. @el.find('.zammad-chat-body')
  505. .find('.zammad-chat-timestamp')
  506. .last()
  507. .replaceWith @view('timestamp')
  508. label: label
  509. time: time
  510. addStatus: (status) ->
  511. return if !@el
  512. @maybeAddTimestamp()
  513. @el.find('.zammad-chat-body').append @view('status')
  514. status: status
  515. @scrollToBottom()
  516. scrollToBottom: ->
  517. @el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'))
  518. destroy: (params = {}) =>
  519. @log.debug 'destroy widget', params
  520. @setAgentOnlineState 'offline'
  521. if params.remove && @el
  522. @el.remove()
  523. # stop all timer
  524. if @waitingListTimeout
  525. @waitingListTimeout.stop()
  526. if @inactiveTimeout
  527. @inactiveTimeout.stop()
  528. if @idleTimeout
  529. @idleTimeout.stop()
  530. # stop ws connection
  531. @io.close()
  532. reconnect: =>
  533. # set status to connecting
  534. @log.notice 'reconnecting'
  535. @disableInput()
  536. @lastAddedType = 'status'
  537. @setAgentOnlineState 'connecting'
  538. @addStatus @T('Connection lost')
  539. onConnectionReestablished: =>
  540. # set status back to online
  541. @lastAddedType = 'status'
  542. @setAgentOnlineState 'online'
  543. @addStatus @T('Connection re-established')
  544. onSessionClosed: (data) ->
  545. @addStatus @T('Chat closed by %s', data.realname)
  546. @disableInput()
  547. @setAgentOnlineState 'offline'
  548. @inactiveTimeout.stop()
  549. setSessionId: (id) =>
  550. @sessionId = id
  551. if id is undefined
  552. sessionStorage.removeItem 'sessionId'
  553. else
  554. sessionStorage.setItem 'sessionId', id
  555. onConnectionEstablished: (data) =>
  556. # stop delay of initial queue position
  557. if @onInitialQueueDelayId
  558. clearTimeout @onInitialQueueDelayId
  559. @inQueue = false
  560. if data.agent
  561. @agent = data.agent
  562. if data.session_id
  563. @setSessionId data.session_id
  564. @el.find('.zammad-chat-agent').html @view('agent')
  565. agent: @agent
  566. @enableInput()
  567. @el.find('.zammad-chat-body').empty()
  568. @el.find('.zammad-chat-welcome').addClass('zammad-chat-is-hidden')
  569. @el.find('.zammad-chat-agent').removeClass('zammad-chat-is-hidden')
  570. @el.find('.zammad-chat-agent-status').removeClass('zammad-chat-is-hidden')
  571. @input.focus()
  572. @setAgentOnlineState 'online'
  573. @waitingListTimeout.stop()
  574. @idleTimeout.stop()
  575. @inactiveTimeout.start()
  576. showCustomerTimeout: ->
  577. @el.find('.zammad-chat-body').html @view('customer_timeout')
  578. agent: @agent.name
  579. delay: @options.inactiveTimeout
  580. reload = ->
  581. location.reload()
  582. @el.find('.js-restart').click reload
  583. @sessionClose()
  584. showWaitingListTimeout: ->
  585. @el.find('.zammad-chat-body').html @view('waiting_list_timeout')
  586. delay: @options.watingListTimeout
  587. reload = ->
  588. location.reload()
  589. @el.find('.js-restart').click reload
  590. @sessionClose()
  591. showLoader: ->
  592. @el.find('.zammad-chat-body').html @view('loader')()
  593. setAgentOnlineState: (state) =>
  594. @state = state
  595. return if !@el
  596. capitalizedState = state.charAt(0).toUpperCase() + state.slice(1)
  597. @el
  598. .find('.zammad-chat-agent-status')
  599. .attr('data-status', state)
  600. .text @T(capitalizedState)
  601. detectHost: ->
  602. protocol = 'ws://'
  603. if window.location.protocol is 'https:'
  604. protocol = 'wss://'
  605. @options.host = "#{ protocol }#{ scriptHost }/ws"
  606. loadCss: ->
  607. return if !@options.cssAutoload
  608. url = @options.cssUrl
  609. if !url
  610. url = @options.host
  611. .replace(/^wss/i, 'https')
  612. .replace(/^ws/i, 'http')
  613. .replace(/\/ws/i, '')
  614. url += '/assets/chat/chat.css'
  615. @log.debug "load css from '#{url}'"
  616. styles = "@import url('#{url}');"
  617. newSS = document.createElement('link')
  618. newSS.rel = 'stylesheet'
  619. newSS.href = 'data:text/css,' + escape(styles)
  620. document.getElementsByTagName('head')[0].appendChild(newSS)
  621. startTimeoutObservers: =>
  622. @idleTimeout = new Timeout(
  623. logPrefix: 'idleTimeout'
  624. debug: @options.debug
  625. timeout: @options.idleTimeout
  626. timeoutIntervallCheck: @options.idleTimeoutIntervallCheck
  627. callback: =>
  628. @log.debug 'Idle timeout reached, hide widget', new Date
  629. @destroy(remove: true)
  630. )
  631. @inactiveTimeout = new Timeout(
  632. logPrefix: 'inactiveTimeout'
  633. debug: @options.debug
  634. timeout: @options.inactiveTimeout
  635. timeoutIntervallCheck: @options.inactiveTimeoutIntervallCheck
  636. callback: =>
  637. @log.debug 'Inactive timeout reached, show timeout screen.', new Date
  638. @showCustomerTimeout()
  639. @destroy(remove: false)
  640. )
  641. @waitingListTimeout = new Timeout(
  642. logPrefix: 'waitingListTimeout'
  643. debug: @options.debug
  644. timeout: @options.waitingListTimeout
  645. timeoutIntervallCheck: @options.waitingListTimeoutIntervallCheck
  646. callback: =>
  647. @log.debug 'Waiting list timeout reached, show timeout screen.', new Date
  648. @showWaitingListTimeout()
  649. @destroy(remove: false)
  650. )
  651. window.ZammadChat = ZammadChat