trabajo-afectivo/public/assets/chat/chat.coffee

343 lines
9.6 KiB
CoffeeScript
Raw Normal View History

2015-10-15 09:14:19 +00:00
do($ = window.jQuery, window) ->
# Define the plugin class
class ZammadChat
defaults:
invitationPhrase: '<strong>Chat</strong> with us!'
agentPhrase: ' is helping you'
2015-10-15 09:14:19 +00:00
show: true
target: $('body')
_messageCount: 0
2015-10-15 09:14:19 +00:00
isOpen: false
blinkOnlineInterval: null
stopBlinOnlineStateTimeout: null
showTimeEveryXMinutes: 1
lastTimestamp: null
lastAddedType: null
inputTimeout: null
isTyping: false
isOnline: true
strings:
'Online': 'Online'
'Offline': 'Offline'
'Connecting': 'Connecting'
'Connection re-established': 'Connection re-established'
'Today': 'Today'
T: (string) =>
2015-10-15 09:14:19 +00:00
return @strings[string]
view: (name) =>
return (options) =>
if !options
options = {}
options.T = @T
return window.zammadChatTemplates[name](options)
2015-10-15 09:14:19 +00:00
constructor: (el, options) ->
@options = $.extend {}, @defaults, options
@el = $(@view('chat')(@options))
2015-10-15 09:14:19 +00:00
@options.target.append @el
@setAgentOnlineState @isOnline
2015-11-11 10:44:10 +00:00
@el.find('.js-chat-open').click @open
@el.find('.js-chat-close').click @close
2015-10-15 09:14:19 +00:00
@el.find('.zammad-chat-controls').on 'submit', @onSubmit
2015-11-11 09:48:54 +00:00
@el.find('.zammad-chat-input').on
2015-10-15 09:14:19 +00:00
keydown: @checkForEnter
input: @onInput
2015-11-10 14:01:04 +00:00
@session_id = undefined
2015-10-15 15:07:18 +00:00
if !window.WebSocket
console.log('Zammad Chat: Browser not supported')
2015-10-15 15:07:18 +00:00
return
zammad_host = 'ws://localhost:6042'
@ws = new window.WebSocket(zammad_host)
console.log("Connecting to #{zammad_host}")
2015-10-15 15:07:18 +00:00
@ws.onopen = =>
console.log('ws connected')
2015-11-11 10:24:19 +00:00
@send 'chat_status_customer'
@ws.onmessage = @onWebSocketMessage
2015-10-15 15:07:18 +00:00
@ws.onclose = (e) =>
console.log 'debug', 'close websocket connection'
@ws.onerror = (e) =>
console.log 'debug', 'ws:onerror', e
2015-11-11 10:44:10 +00:00
@onReady()
2015-10-15 09:14:19 +00:00
checkForEnter: (event) =>
if not event.shiftKey and event.keyCode is 13
event.preventDefault()
@sendMessage()
2015-11-10 14:01:04 +00:00
send: (event, data) =>
console.log 'debug', 'ws:send', event, data
pipe = JSON.stringify
2015-11-10 14:01:04 +00:00
event: event
data: data
@ws.send pipe
onWebSocketMessage: (e) =>
2015-11-10 14:01:04 +00:00
pipes = JSON.parse( e.data )
console.log 'debug', 'ws:onmessage', pipes
for pipe in pipes
switch pipe.event
when 'chat_session_message'
return if pipe.data.self_written
@receiveMessage pipe.data
when 'chat_session_typing'
return if pipe.data.self_written
@onAgentTypingStart()
when 'chat_session_start'
switch pipe.data.state
when 'ok'
@onConnectionEstablished pipe.data.agent
when 'chat_session_init'
switch pipe.data.state
when 'ok'
@onConnectionEstablished pipe.data.agent
when 'queue'
@onQueue pipe.data.position
@session_id = pipe.data.session_id
2015-11-11 10:24:19 +00:00
when 'chat_status_customer'
2015-11-10 14:01:04 +00:00
switch pipe.data.state
when 'online'
@onReady()
console.log 'Zammad Chat: ready'
when 'offline'
console.log 'Zammad Chat: No agent online'
when 'chat_disabled'
console.log 'Zammad Chat: Chat is disabled'
when 'no_seats_available'
console.log 'Zammad Chat: Too many clients in queue. Clients in queue: ', pipe.data.queue
onReady: =>
2015-11-11 09:48:54 +00:00
if @options.show
@show()
@el.find('.zammad-chat-input').autoGrow
extraLine: false
2015-10-15 09:14:19 +00:00
onInput: =>
# remove unread-state from messages
@el.find('.zammad-chat-message--unread')
.removeClass 'zammad-chat-message--unread'
2015-11-10 14:01:04 +00:00
@onTypingStart()
2015-10-15 09:14:19 +00:00
2015-11-10 14:01:04 +00:00
onTypingStart: ->
2015-10-15 09:14:19 +00:00
2015-11-10 14:01:04 +00:00
clearTimeout(@isTypingTimeout) if @isTypingTimeout
# fire typingEnd after 5 seconds
@isTypingTimeout = setTimeout @onTypingEnd, 1500
2015-10-15 09:14:19 +00:00
# send typing start event
2015-11-10 14:01:04 +00:00
if !@isTyping
@isTyping = true
@send 'chat_session_typing', {session_id: @session_id}
2015-10-15 09:14:19 +00:00
onTypingEnd: =>
@isTyping = false
onSubmit: (event) =>
event.preventDefault()
@sendMessage()
sendMessage: ->
message = @el.find('.zammad-chat-input').val()
if !message
return
2015-10-15 09:14:19 +00:00
messageElement = @view('message')
message: message
from: 'customer'
id: @_messageCount++
2015-10-15 09:14:19 +00:00
@maybeAddTimestamp()
2015-10-15 09:14:19 +00:00
# add message before message typing loader
if @el.find('.zammad-chat-message--typing').size()
@lastAddedType = 'typing-placeholder'
2015-11-11 10:24:19 +00:00
@el.find('.zammad-chat-message--typing').before messageElement
else
@lastAddedType = 'message--customer'
@el.find('.zammad-chat-body').append messageElement
2015-10-15 09:14:19 +00:00
@el.find('.zammad-chat-input').val('')
@scrollToBottom()
2015-10-15 09:14:19 +00:00
@isTyping = false
# send message event
2015-11-10 14:01:04 +00:00
@send 'chat_session_message',
content: message
id: @_messageCount
2015-11-10 14:01:04 +00:00
session_id: @session_id
receiveMessage: (data) =>
2015-10-15 09:14:19 +00:00
# hide writing indicator
@onAgentTypingEnd()
@maybeAddTimestamp()
@lastAddedType = 'message--agent'
unread = document.hidden ? " zammad-chat-message--unread" : ""
2015-10-15 09:26:56 +00:00
@el.find('.zammad-chat-body').append @view('message')
2015-11-10 14:01:04 +00:00
message: data.message.content
id: data.id
2015-10-15 09:26:56 +00:00
from: 'agent'
2015-10-15 09:14:19 +00:00
@scrollToBottom()
2015-11-11 10:44:10 +00:00
open: =>
return if @isOpen
2015-10-15 09:14:19 +00:00
@showLoader()
2015-10-15 09:14:19 +00:00
@el
.addClass('zammad-chat-is-open')
.animate { bottom: 0 }, 500, @onOpenAnimationEnd
@isOpen = true
2015-11-11 10:44:10 +00:00
onOpenAnimationEnd: =>
#setTimeout @onQueue, 1180
# setTimeout @onConnectionEstablished, 1180
# setTimeout @onAgentTypingStart, 2000
# setTimeout @receiveMessage, 5000, "Hello! How can I help you?"
2015-10-15 09:14:19 +00:00
@connect()
2015-11-11 10:44:10 +00:00
close: (event) =>
event.stopPropagation() if event
2015-10-15 09:14:19 +00:00
remainerHeight = @el.height() - @el.find('.zammad-chat-header').outerHeight()
2015-10-15 13:28:30 +00:00
@el.animate { bottom: -remainerHeight }, 500, @onCloseAnimationEnd
2015-10-15 09:14:19 +00:00
onCloseAnimationEnd: =>
@el.removeClass('zammad-chat-is-open')
@disconnect()
@isOpen = false
hide: ->
@el.removeClass('zammad-chat-is-visible')
show: ->
@el.addClass('zammad-chat-is-visible')
2015-10-15 13:28:30 +00:00
remainerHeight = @el.outerHeight() - @el.find('.zammad-chat-header').outerHeight()
2015-10-15 09:14:19 +00:00
@el.css 'bottom', -remainerHeight
onQueue: (position) =>
console.log "onQueue", position
@inQueue = true
@el.find('.zammad-chat-body').html @view('waiting')
position: position
2015-10-15 09:14:19 +00:00
onAgentTypingStart: =>
2015-11-11 10:24:19 +00:00
if @stopTypingId
clearTimeout(@stopTypingId)
@stopTypingId = setTimeout(@onAgentTypingEnd, 3000)
# never display two typing indicators
2015-10-15 09:14:19 +00:00
return if @el.find('.zammad-chat-message--typing').size()
@maybeAddTimestamp()
@el.find('.zammad-chat-body').append @view('typingIndicator')()
@scrollToBottom()
onAgentTypingEnd: =>
@el.find('.zammad-chat-message--typing').remove()
maybeAddTimestamp: ->
timestamp = Date.now()
2015-10-15 09:26:56 +00:00
if !@lastTimestamp or (timestamp - @lastTimestamp) > @showTimeEveryXMinutes * 60000
2015-10-15 09:14:19 +00:00
label = @T('Today')
time = new Date().toTimeString().substr 0,5
if @lastAddedType is 'timestamp'
# update last time
@updateLastTimestamp label, time
@lastTimestamp = timestamp
else
# add new timestamp
@addStatus label, time
@lastTimestamp = timestamp
@lastAddedType = 'timestamp'
updateLastTimestamp: (label, time) ->
@el.find('.zammad-chat-body')
.find('.zammad-chat-status')
.last()
.replaceWith @view('status')
label: label
time: time
addStatus: (label, time) ->
2015-10-15 09:26:56 +00:00
@el.find('.zammad-chat-body').append @view('status')
2015-10-15 09:14:19 +00:00
label: label
time: time
scrollToBottom: ->
@el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'))
connect: ->
2015-11-10 14:01:04 +00:00
@send('chat_session_init')
2015-10-15 09:14:19 +00:00
reconnect: =>
# set status to connecting
@lastAddedType = 'status'
@el.find('.zammad-chat-agent-status').attr('data-status', 'connecting').text @T('Connecting')
@addStatus @T('Connection lost')
onConnectionReestablished: =>
# set status back to online
@lastAddedType = 'status'
@el.find('.zammad-chat-agent-status').attr('data-status', 'online').text @T('Online')
@addStatus @T('Connection re-established')
disconnect: ->
@showLoader()
@el.find('.zammad-chat-welcome').removeClass('zammad-chat-is-hidden')
@el.find('.zammad-chat-agent').addClass('zammad-chat-is-hidden')
@el.find('.zammad-chat-agent-status').addClass('zammad-chat-is-hidden')
onConnectionEstablished: (agent) =>
@inQueue = false
@agent = agent
@el.find('.zammad-chat-agent').html @view('agent')
agent: agent
@el.find('.zammad-chat-body').empty()
@el.find('.zammad-chat-welcome').addClass('zammad-chat-is-hidden')
@el.find('.zammad-chat-agent').removeClass('zammad-chat-is-hidden')
@el.find('.zammad-chat-agent-status').removeClass('zammad-chat-is-hidden')
@el.find('.zammad-chat-input').focus()
showLoader: ->
@el.find('.zammad-chat-body').html @view('loader')()
2015-10-15 09:14:19 +00:00
setAgentOnlineState: (state) =>
@isOnline = state
@el
.find('.zammad-chat-agent-status')
.toggleClass('zammad-chat-is-online', state)
.text if state then @T('Online') else @T('Offline')
$(document).ready ->
window.zammadChat = new ZammadChat()