Fixed timing issues, improved tests.
This commit is contained in:
parent
465ab3e6be
commit
f06348e843
7 changed files with 409 additions and 274 deletions
|
@ -291,7 +291,7 @@ class ChatWindow extends App.Controller
|
||||||
phrasesArray = phrases.split(';')
|
phrasesArray = phrases.split(';')
|
||||||
phrase = phrasesArray[_.random(0, phrasesArray.length-1)]
|
phrase = phrasesArray[_.random(0, phrasesArray.length-1)]
|
||||||
@input.html(phrase)
|
@input.html(phrase)
|
||||||
@sendMessage()
|
@sendMessage(1600)
|
||||||
|
|
||||||
focus: =>
|
focus: =>
|
||||||
@input.focus()
|
@input.focus()
|
||||||
|
@ -372,16 +372,27 @@ class ChatWindow extends App.Controller
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
@sendMessage()
|
@sendMessage()
|
||||||
|
|
||||||
sendMessage: =>
|
sendMessage: (delay) =>
|
||||||
content = @input.html()
|
content = @input.html()
|
||||||
return if !content
|
return if !content
|
||||||
|
|
||||||
|
send = =>
|
||||||
App.WebSocket.send(
|
App.WebSocket.send(
|
||||||
event:'chat_session_message'
|
event:'chat_session_message'
|
||||||
data:
|
data:
|
||||||
content: content
|
content: content
|
||||||
session_id: @session.session_id
|
session_id: @session.session_id
|
||||||
)
|
)
|
||||||
|
if !delay
|
||||||
|
send()
|
||||||
|
else
|
||||||
|
# show key enter and send phrase
|
||||||
|
App.WebSocket.send(
|
||||||
|
event:'chat_session_typing'
|
||||||
|
data:
|
||||||
|
session_id: @session.session_id
|
||||||
|
)
|
||||||
|
@delay(send, delay)
|
||||||
|
|
||||||
@addMessage content, 'agent'
|
@addMessage content, 'agent'
|
||||||
@input.html('')
|
@input.html('')
|
||||||
|
|
|
@ -73,7 +73,7 @@ do($ = window.jQuery, window) ->
|
||||||
|
|
||||||
stop: =>
|
stop: =>
|
||||||
return if !@intervallId
|
return if !@intervallId
|
||||||
@log.debug "Stop timeout of #{@options.timeout} minutes at"#, new Date
|
@log.debug "Stop timeout of #{@options.timeout} minutes"#, new Date
|
||||||
clearInterval(@intervallId)
|
clearInterval(@intervallId)
|
||||||
|
|
||||||
class Io extends Base
|
class Io extends Base
|
||||||
|
@ -89,30 +89,40 @@ do($ = window.jQuery, window) ->
|
||||||
@log.debug "Connecting to #{@options.host}"
|
@log.debug "Connecting to #{@options.host}"
|
||||||
@ws = new window.WebSocket("#{@options.host}")
|
@ws = new window.WebSocket("#{@options.host}")
|
||||||
@ws.onopen = (e) =>
|
@ws.onopen = (e) =>
|
||||||
@log.debug 'on open', e
|
@log.debug 'onOpen', e
|
||||||
@options.onOpen(e)
|
@options.onOpen(e)
|
||||||
|
|
||||||
@ws.onmessage = (e) =>
|
@ws.onmessage = (e) =>
|
||||||
pipes = JSON.parse(e.data)
|
pipes = JSON.parse(e.data)
|
||||||
@log.debug 'on message', e.data
|
@log.debug 'onMessage', e.data
|
||||||
if @options.onMessage
|
if @options.onMessage
|
||||||
@options.onMessage(pipes)
|
@options.onMessage(pipes)
|
||||||
|
|
||||||
@ws.onclose = (e) =>
|
@ws.onclose = (e) =>
|
||||||
@log.debug 'close websocket connection'
|
@log.debug 'close websocket connection', e
|
||||||
|
if @manualClose
|
||||||
|
@log.debug 'manual close, onClose callback'
|
||||||
|
@manualClose = false
|
||||||
if @options.onClose
|
if @options.onClose
|
||||||
@options.onClose(e)
|
@options.onClose(e)
|
||||||
|
else
|
||||||
|
@log.debug 'error close, onError callback'
|
||||||
|
if @options.onError
|
||||||
|
@options.onError('Connection lost...')
|
||||||
|
|
||||||
@ws.onerror = (e) =>
|
@ws.onerror = (e) =>
|
||||||
@log.debug 'onerror', e
|
@log.debug 'onError', e
|
||||||
if @options.onError
|
if @options.onError
|
||||||
@options.onError(e)
|
@options.onError(e)
|
||||||
|
|
||||||
close: =>
|
close: =>
|
||||||
|
@log.debug 'close websocket manually'
|
||||||
|
@manualClose = true
|
||||||
@ws.close()
|
@ws.close()
|
||||||
|
|
||||||
reconnect: =>
|
reconnect: =>
|
||||||
@ws.close()
|
@log.debug 'reconnect'
|
||||||
|
@close()
|
||||||
@connect()
|
@connect()
|
||||||
|
|
||||||
send: (event, data = {}) =>
|
send: (event, data = {}) =>
|
||||||
|
@ -137,7 +147,7 @@ do($ = window.jQuery, window) ->
|
||||||
buttonClass: 'open-zammad-chat'
|
buttonClass: 'open-zammad-chat'
|
||||||
inactiveClass: 'is-inactive'
|
inactiveClass: 'is-inactive'
|
||||||
title: '<strong>Chat</strong> with us!'
|
title: '<strong>Chat</strong> with us!'
|
||||||
idleTimeout: 8
|
idleTimeout: 6
|
||||||
idleTimeoutIntervallCheck: 0.5
|
idleTimeoutIntervallCheck: 0.5
|
||||||
inactiveTimeout: 8
|
inactiveTimeout: 8
|
||||||
inactiveTimeoutIntervallCheck: 0.5
|
inactiveTimeoutIntervallCheck: 0.5
|
||||||
|
@ -146,7 +156,7 @@ do($ = window.jQuery, window) ->
|
||||||
|
|
||||||
logPrefix: 'chat'
|
logPrefix: 'chat'
|
||||||
_messageCount: 0
|
_messageCount: 0
|
||||||
isOpen: true
|
isOpen: false
|
||||||
blinkOnlineInterval: null
|
blinkOnlineInterval: null
|
||||||
stopBlinOnlineStateTimeout: null
|
stopBlinOnlineStateTimeout: null
|
||||||
showTimeEveryXMinutes: 1
|
showTimeEveryXMinutes: 1
|
||||||
|
@ -232,12 +242,14 @@ do($ = window.jQuery, window) ->
|
||||||
@io = new Io(@options)
|
@io = new Io(@options)
|
||||||
@io.set(
|
@io.set(
|
||||||
onOpen: @render
|
onOpen: @render
|
||||||
onClose: @hide
|
onClose: @onWebSocketClose
|
||||||
onMessage: @onWebSocketMessage
|
onMessage: @onWebSocketMessage
|
||||||
|
onError: @onError
|
||||||
)
|
)
|
||||||
@io.connect()
|
@io.connect()
|
||||||
|
|
||||||
render: =>
|
render: =>
|
||||||
|
if !@el || !$('.zammad-chat').get(0)
|
||||||
@el = $(@view('chat')(
|
@el = $(@view('chat')(
|
||||||
title: @options.title
|
title: @options.title
|
||||||
))
|
))
|
||||||
|
@ -245,9 +257,7 @@ do($ = window.jQuery, window) ->
|
||||||
|
|
||||||
@input = @el.find('.zammad-chat-input')
|
@input = @el.find('.zammad-chat-input')
|
||||||
|
|
||||||
# disable open button
|
# start bindings
|
||||||
$(".#{ @options.buttonClass }").addClass @inactiveClass
|
|
||||||
|
|
||||||
@el.find('.js-chat-open').click @open
|
@el.find('.js-chat-open').click @open
|
||||||
@el.find('.js-chat-close').click @close
|
@el.find('.js-chat-close').click @close
|
||||||
@el.find('.zammad-chat-controls').on 'submit', @onSubmit
|
@el.find('.zammad-chat-controls').on 'submit', @onSubmit
|
||||||
|
@ -257,6 +267,14 @@ do($ = window.jQuery, window) ->
|
||||||
$(window).on('beforeunload', =>
|
$(window).on('beforeunload', =>
|
||||||
@onLeaveTemporary()
|
@onLeaveTemporary()
|
||||||
)
|
)
|
||||||
|
$(window).bind('hashchange', =>
|
||||||
|
return if @isOpen
|
||||||
|
@idleTimeout.start()
|
||||||
|
)
|
||||||
|
|
||||||
|
# disable open button
|
||||||
|
$(".#{ @options.buttonClass }").addClass @inactiveClass
|
||||||
|
|
||||||
@setAgentOnlineState 'online'
|
@setAgentOnlineState 'online'
|
||||||
|
|
||||||
@log.debug 'widget rendered'
|
@log.debug 'widget rendered'
|
||||||
|
@ -285,7 +303,7 @@ do($ = window.jQuery, window) ->
|
||||||
when 'chat_error'
|
when 'chat_error'
|
||||||
@log.notice pipe.data
|
@log.notice pipe.data
|
||||||
if pipe.data && pipe.data.state is 'chat_disabled'
|
if pipe.data && pipe.data.state is 'chat_disabled'
|
||||||
@destroy(hide: true)
|
@destroy(remove: true)
|
||||||
when 'chat_session_message'
|
when 'chat_session_message'
|
||||||
return if pipe.data.self_written
|
return if pipe.data.self_written
|
||||||
@receiveMessage pipe.data
|
@receiveMessage pipe.data
|
||||||
|
@ -307,21 +325,14 @@ do($ = window.jQuery, window) ->
|
||||||
@onReady()
|
@onReady()
|
||||||
when 'offline'
|
when 'offline'
|
||||||
@onError 'Zammad Chat: No agent online'
|
@onError 'Zammad Chat: No agent online'
|
||||||
@state = 'off'
|
|
||||||
@destroy(hide: true)
|
|
||||||
when 'chat_disabled'
|
when 'chat_disabled'
|
||||||
@onError 'Zammad Chat: Chat is disabled'
|
@onError 'Zammad Chat: Chat is disabled'
|
||||||
@state = 'off'
|
|
||||||
@destroy(hide: true)
|
|
||||||
when 'no_seats_available'
|
when 'no_seats_available'
|
||||||
@onError "Zammad Chat: Too many clients in queue. Clients in queue: #{pipe.data.queue}"
|
@onError "Zammad Chat: Too many clients in queue. Clients in queue: #{pipe.data.queue}"
|
||||||
@state = 'off'
|
|
||||||
@destroy(hide: true)
|
|
||||||
when 'reconnect'
|
when 'reconnect'
|
||||||
@log.debug 'old messages', pipe.data.session
|
@onReopenSession pipe.data
|
||||||
@reopenSession pipe.data
|
|
||||||
|
|
||||||
onReady: =>
|
onReady: ->
|
||||||
@log.debug 'widget ready for use'
|
@log.debug 'widget ready for use'
|
||||||
$(".#{ @options.buttonClass }").click(@open).removeClass(@inactiveClass)
|
$(".#{ @options.buttonClass }").click(@open).removeClass(@inactiveClass)
|
||||||
|
|
||||||
|
@ -330,9 +341,16 @@ do($ = window.jQuery, window) ->
|
||||||
|
|
||||||
onError: (message) =>
|
onError: (message) =>
|
||||||
@log.debug message
|
@log.debug message
|
||||||
|
@addStatus(message)
|
||||||
$(".#{ @options.buttonClass }").hide()
|
$(".#{ @options.buttonClass }").hide()
|
||||||
|
if @isOpen
|
||||||
|
@disableInput()
|
||||||
|
@destroy(remove: false)
|
||||||
|
else
|
||||||
|
@destroy(remove: true)
|
||||||
|
|
||||||
reopenSession: (data) =>
|
onReopenSession: (data) =>
|
||||||
|
@log.debug 'old messages', data.session
|
||||||
@inactiveTimeout.start()
|
@inactiveTimeout.start()
|
||||||
|
|
||||||
unfinishedMessage = sessionStorage.getItem 'unfinished_message'
|
unfinishedMessage = sessionStorage.getItem 'unfinished_message'
|
||||||
|
@ -436,9 +454,12 @@ do($ = window.jQuery, window) ->
|
||||||
@scrollToBottom()
|
@scrollToBottom()
|
||||||
|
|
||||||
open: =>
|
open: =>
|
||||||
@log.debug 'open widget'
|
|
||||||
if @isOpen
|
if @isOpen
|
||||||
@show()
|
@log.debug 'widget already open, block'
|
||||||
|
return
|
||||||
|
|
||||||
|
@isOpen = true
|
||||||
|
@log.debug 'open widget'
|
||||||
|
|
||||||
if !@sessionId
|
if !@sessionId
|
||||||
@showLoader()
|
@showLoader()
|
||||||
|
@ -447,27 +468,15 @@ do($ = window.jQuery, window) ->
|
||||||
|
|
||||||
if !@sessionId
|
if !@sessionId
|
||||||
@el.animate { bottom: 0 }, 500, @onOpenAnimationEnd
|
@el.animate { bottom: 0 }, 500, @onOpenAnimationEnd
|
||||||
|
@send('chat_session_init')
|
||||||
else
|
else
|
||||||
@el.css 'bottom', 0
|
@el.css 'bottom', 0
|
||||||
@onOpenAnimationEnd()
|
@onOpenAnimationEnd()
|
||||||
|
|
||||||
@isOpen = true
|
|
||||||
|
|
||||||
if !@sessionId
|
|
||||||
@send('chat_session_init')
|
|
||||||
|
|
||||||
onOpenAnimationEnd: =>
|
onOpenAnimationEnd: =>
|
||||||
@idleTimeout.stop()
|
@idleTimeout.stop()
|
||||||
|
|
||||||
close: (event) =>
|
sessionClose: =>
|
||||||
@log.debug 'close widget'
|
|
||||||
|
|
||||||
return @state if @state is 'off' or @state is 'unsupported'
|
|
||||||
event.stopPropagation() if event
|
|
||||||
|
|
||||||
# only close if session_id exists
|
|
||||||
return if !@sessionId
|
|
||||||
|
|
||||||
# send close
|
# send close
|
||||||
@send 'chat_session_close',
|
@send 'chat_session_close',
|
||||||
session_id: @sessionId
|
session_id: @sessionId
|
||||||
|
@ -483,12 +492,23 @@ do($ = window.jQuery, window) ->
|
||||||
if @onInitialQueueDelayId
|
if @onInitialQueueDelayId
|
||||||
clearTimeout(@onInitialQueueDelayId)
|
clearTimeout(@onInitialQueueDelayId)
|
||||||
|
|
||||||
if event
|
|
||||||
@closeWindow()
|
|
||||||
|
|
||||||
@setSessionId undefined
|
@setSessionId undefined
|
||||||
|
|
||||||
closeWindow: =>
|
close: (event) =>
|
||||||
|
if !@isOpen
|
||||||
|
@log.debug 'can\'t close widget, it\'s not open'
|
||||||
|
return
|
||||||
|
if !@sessionId
|
||||||
|
@log.debug 'can\'t close widget without sessionId'
|
||||||
|
return
|
||||||
|
|
||||||
|
@log.debug 'close widget'
|
||||||
|
|
||||||
|
event.stopPropagation() if event
|
||||||
|
|
||||||
|
@sessionClose()
|
||||||
|
|
||||||
|
# close window
|
||||||
@el.removeClass('zammad-chat-is-open')
|
@el.removeClass('zammad-chat-is-open')
|
||||||
remainerHeight = @el.height() - @el.find('.zammad-chat-header').outerHeight()
|
remainerHeight = @el.height() - @el.find('.zammad-chat-header').outerHeight()
|
||||||
@el.animate { bottom: -remainerHeight }, 500, @onCloseAnimationEnd
|
@el.animate { bottom: -remainerHeight }, 500, @onCloseAnimationEnd
|
||||||
|
@ -503,15 +523,15 @@ do($ = window.jQuery, window) ->
|
||||||
|
|
||||||
@isOpen = false
|
@isOpen = false
|
||||||
|
|
||||||
# restart connection
|
|
||||||
@io.reconnect()
|
@io.reconnect()
|
||||||
|
|
||||||
hide: ->
|
onWebSocketClose: =>
|
||||||
|
return if @isOpen
|
||||||
if @el
|
if @el
|
||||||
@el.removeClass('zammad-chat-is-shown')
|
@el.removeClass('zammad-chat-is-shown')
|
||||||
|
|
||||||
show: ->
|
show: ->
|
||||||
return @state if @state is 'off' or @state is 'unsupported'
|
return if @state is 'offline'
|
||||||
|
|
||||||
@el.addClass('zammad-chat-is-shown')
|
@el.addClass('zammad-chat-is-shown')
|
||||||
|
|
||||||
|
@ -600,6 +620,7 @@ do($ = window.jQuery, window) ->
|
||||||
@scrollToBottom()
|
@scrollToBottom()
|
||||||
|
|
||||||
updateLastTimestamp: (label, time) ->
|
updateLastTimestamp: (label, time) ->
|
||||||
|
return if !@el
|
||||||
@el.find('.zammad-chat-body')
|
@el.find('.zammad-chat-body')
|
||||||
.find('.zammad-chat-timestamp')
|
.find('.zammad-chat-timestamp')
|
||||||
.last()
|
.last()
|
||||||
|
@ -608,6 +629,7 @@ do($ = window.jQuery, window) ->
|
||||||
time: time
|
time: time
|
||||||
|
|
||||||
addStatus: (status) ->
|
addStatus: (status) ->
|
||||||
|
return if !@el
|
||||||
@maybeAddTimestamp()
|
@maybeAddTimestamp()
|
||||||
|
|
||||||
@el.find('.zammad-chat-body').append @view('status')
|
@el.find('.zammad-chat-body').append @view('status')
|
||||||
|
@ -619,30 +641,24 @@ do($ = window.jQuery, window) ->
|
||||||
@el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'))
|
@el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'))
|
||||||
|
|
||||||
destroy: (params = {}) =>
|
destroy: (params = {}) =>
|
||||||
@log.debug 'destroy widget'
|
@log.debug 'destroy widget', params
|
||||||
if params.hide
|
|
||||||
if @el
|
@setAgentOnlineState 'offline'
|
||||||
|
|
||||||
|
if params.remove && @el
|
||||||
@el.remove()
|
@el.remove()
|
||||||
|
|
||||||
# stop all timer
|
# stop all timer
|
||||||
|
if @waitingListTimeout
|
||||||
@waitingListTimeout.stop()
|
@waitingListTimeout.stop()
|
||||||
|
if @inactiveTimeout
|
||||||
@inactiveTimeout.stop()
|
@inactiveTimeout.stop()
|
||||||
|
if @idleTimeout
|
||||||
@idleTimeout.stop()
|
@idleTimeout.stop()
|
||||||
@wsReconnectStop()
|
|
||||||
|
|
||||||
# stop ws connection
|
# stop ws connection
|
||||||
@io.close()
|
@io.close()
|
||||||
|
|
||||||
wsReconnectStart: =>
|
|
||||||
@wsReconnectStop()
|
|
||||||
if @reconnectDelayId
|
|
||||||
clearTimeout(@reconnectDelayId)
|
|
||||||
@reconnectDelayId = setTimeout(@io.connect(), 5000)
|
|
||||||
|
|
||||||
wsReconnectStop: =>
|
|
||||||
if @reconnectDelayId
|
|
||||||
clearTimeout(@reconnectDelayId)
|
|
||||||
|
|
||||||
reconnect: =>
|
reconnect: =>
|
||||||
# set status to connecting
|
# set status to connecting
|
||||||
@log.notice 'reconnecting'
|
@log.notice 'reconnecting'
|
||||||
|
@ -702,24 +718,25 @@ do($ = window.jQuery, window) ->
|
||||||
@el.find('.zammad-chat-body').html @view('customer_timeout')
|
@el.find('.zammad-chat-body').html @view('customer_timeout')
|
||||||
agent: @agent.name
|
agent: @agent.name
|
||||||
delay: @options.inactiveTimeout
|
delay: @options.inactiveTimeout
|
||||||
@close()
|
|
||||||
reload = ->
|
reload = ->
|
||||||
location.reload()
|
location.reload()
|
||||||
@el.find('.js-restart').click reload
|
@el.find('.js-restart').click reload
|
||||||
|
@sessionClose()
|
||||||
|
|
||||||
showWaitingListTimeout: ->
|
showWaitingListTimeout: ->
|
||||||
@el.find('.zammad-chat-body').html @view('waiting_list_timeout')
|
@el.find('.zammad-chat-body').html @view('waiting_list_timeout')
|
||||||
delay: @options.watingListTimeout
|
delay: @options.watingListTimeout
|
||||||
@close()
|
|
||||||
reload = ->
|
reload = ->
|
||||||
location.reload()
|
location.reload()
|
||||||
@el.find('.js-restart').click reload
|
@el.find('.js-restart').click reload
|
||||||
|
@sessionClose()
|
||||||
|
|
||||||
showLoader: ->
|
showLoader: ->
|
||||||
@el.find('.zammad-chat-body').html @view('loader')()
|
@el.find('.zammad-chat-body').html @view('loader')()
|
||||||
|
|
||||||
setAgentOnlineState: (state) =>
|
setAgentOnlineState: (state) =>
|
||||||
@state = state
|
@state = state
|
||||||
|
return if !@el
|
||||||
capitalizedState = state.charAt(0).toUpperCase() + state.slice(1)
|
capitalizedState = state.charAt(0).toUpperCase() + state.slice(1)
|
||||||
@el
|
@el
|
||||||
.find('.zammad-chat-agent-status')
|
.find('.zammad-chat-agent-status')
|
||||||
|
@ -757,8 +774,7 @@ do($ = window.jQuery, window) ->
|
||||||
timeoutIntervallCheck: @options.idleTimeoutIntervallCheck
|
timeoutIntervallCheck: @options.idleTimeoutIntervallCheck
|
||||||
callback: =>
|
callback: =>
|
||||||
@log.debug 'Idle timeout reached, hide widget', new Date
|
@log.debug 'Idle timeout reached, hide widget', new Date
|
||||||
@state = 'off'
|
@destroy(remove: true)
|
||||||
@destroy(hide: true)
|
|
||||||
)
|
)
|
||||||
@inactiveTimeout = new Timeout(
|
@inactiveTimeout = new Timeout(
|
||||||
logPrefix: 'inactiveTimeout'
|
logPrefix: 'inactiveTimeout'
|
||||||
|
@ -767,10 +783,8 @@ do($ = window.jQuery, window) ->
|
||||||
timeoutIntervallCheck: @options.inactiveTimeoutIntervallCheck
|
timeoutIntervallCheck: @options.inactiveTimeoutIntervallCheck
|
||||||
callback: =>
|
callback: =>
|
||||||
@log.debug 'Inactive timeout reached, show timeout screen.', new Date
|
@log.debug 'Inactive timeout reached, show timeout screen.', new Date
|
||||||
@state = 'off'
|
|
||||||
@setAgentOnlineState 'offline'
|
|
||||||
@showCustomerTimeout()
|
@showCustomerTimeout()
|
||||||
@destroy(hide:false)
|
@destroy(remove: false)
|
||||||
)
|
)
|
||||||
@waitingListTimeout = new Timeout(
|
@waitingListTimeout = new Timeout(
|
||||||
logPrefix: 'waitingListTimeout'
|
logPrefix: 'waitingListTimeout'
|
||||||
|
@ -779,10 +793,8 @@ do($ = window.jQuery, window) ->
|
||||||
timeoutIntervallCheck: @options.waitingListTimeoutIntervallCheck
|
timeoutIntervallCheck: @options.waitingListTimeoutIntervallCheck
|
||||||
callback: =>
|
callback: =>
|
||||||
@log.debug 'Waiting list timeout reached, show timeout screen.', new Date
|
@log.debug 'Waiting list timeout reached, show timeout screen.', new Date
|
||||||
@state = 'off'
|
|
||||||
@setAgentOnlineState 'offline'
|
|
||||||
@showWaitingListTimeout()
|
@showWaitingListTimeout()
|
||||||
@destroy(hide:false)
|
@destroy(remove: false)
|
||||||
)
|
)
|
||||||
|
|
||||||
window.ZammadChat = ZammadChat
|
window.ZammadChat = ZammadChat
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
display: none;
|
display: none;
|
||||||
-webkit-flex-direction: column;
|
-webkit-flex-direction: column;
|
||||||
-ms-flex-direction: column;
|
-ms-flex-direction: column;
|
||||||
flex-direction: column; }
|
flex-direction: column;
|
||||||
|
z-index: 999; }
|
||||||
.zammad-chat.is-fullscreen {
|
.zammad-chat.is-fullscreen {
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -106,7 +107,7 @@
|
||||||
margin: 0 1em;
|
margin: 0 1em;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
padding: 0 0.7em;
|
padding: 0 .7em;
|
||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
background: rgba(0, 0, 0, 0.1);
|
background: rgba(0, 0, 0, 0.1);
|
||||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.04) inset; }
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.04) inset; }
|
||||||
|
@ -349,6 +350,10 @@
|
||||||
.zammad-chat-send {
|
.zammad-chat-send {
|
||||||
float: right; }
|
float: right; }
|
||||||
|
|
||||||
|
.zammad-chat-button:disabled,
|
||||||
|
.zammad-chat-input:disabled {
|
||||||
|
opacity: 0.3; }
|
||||||
|
|
||||||
.zammad-chat-is-hidden {
|
.zammad-chat-is-hidden {
|
||||||
display: none; }
|
display: none; }
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
if (!this.intervallId) {
|
if (!this.intervallId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.log.debug("Stop timeout of " + this.options.timeout + " minutes at");
|
this.log.debug("Stop timeout of " + this.options.timeout + " minutes");
|
||||||
return clearInterval(this.intervallId);
|
return clearInterval(this.intervallId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
this.ws = new window.WebSocket("" + this.options.host);
|
this.ws = new window.WebSocket("" + this.options.host);
|
||||||
this.ws.onopen = (function(_this) {
|
this.ws.onopen = (function(_this) {
|
||||||
return function(e) {
|
return function(e) {
|
||||||
_this.log.debug('on open', e);
|
_this.log.debug('onOpen', e);
|
||||||
return _this.options.onOpen(e);
|
return _this.options.onOpen(e);
|
||||||
};
|
};
|
||||||
})(this);
|
})(this);
|
||||||
|
@ -172,7 +172,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
return function(e) {
|
return function(e) {
|
||||||
var pipes;
|
var pipes;
|
||||||
pipes = JSON.parse(e.data);
|
pipes = JSON.parse(e.data);
|
||||||
_this.log.debug('on message', e.data);
|
_this.log.debug('onMessage', e.data);
|
||||||
if (_this.options.onMessage) {
|
if (_this.options.onMessage) {
|
||||||
return _this.options.onMessage(pipes);
|
return _this.options.onMessage(pipes);
|
||||||
}
|
}
|
||||||
|
@ -180,15 +180,24 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
})(this);
|
})(this);
|
||||||
this.ws.onclose = (function(_this) {
|
this.ws.onclose = (function(_this) {
|
||||||
return function(e) {
|
return function(e) {
|
||||||
_this.log.debug('close websocket connection');
|
_this.log.debug('close websocket connection', e);
|
||||||
|
if (_this.manualClose) {
|
||||||
|
_this.log.debug('manual close, onClose callback');
|
||||||
|
_this.manualClose = false;
|
||||||
if (_this.options.onClose) {
|
if (_this.options.onClose) {
|
||||||
return _this.options.onClose(e);
|
return _this.options.onClose(e);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
_this.log.debug('error close, onError callback');
|
||||||
|
if (_this.options.onError) {
|
||||||
|
return _this.options.onError('Connection lost...');
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
})(this);
|
})(this);
|
||||||
return this.ws.onerror = (function(_this) {
|
return this.ws.onerror = (function(_this) {
|
||||||
return function(e) {
|
return function(e) {
|
||||||
_this.log.debug('onerror', e);
|
_this.log.debug('onError', e);
|
||||||
if (_this.options.onError) {
|
if (_this.options.onError) {
|
||||||
return _this.options.onError(e);
|
return _this.options.onError(e);
|
||||||
}
|
}
|
||||||
|
@ -197,11 +206,14 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
Io.prototype.close = function() {
|
Io.prototype.close = function() {
|
||||||
|
this.log.debug('close websocket manually');
|
||||||
|
this.manualClose = true;
|
||||||
return this.ws.close();
|
return this.ws.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
Io.prototype.reconnect = function() {
|
Io.prototype.reconnect = function() {
|
||||||
this.ws.close();
|
this.log.debug('reconnect');
|
||||||
|
this.close();
|
||||||
return this.connect();
|
return this.connect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -238,7 +250,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
buttonClass: 'open-zammad-chat',
|
buttonClass: 'open-zammad-chat',
|
||||||
inactiveClass: 'is-inactive',
|
inactiveClass: 'is-inactive',
|
||||||
title: '<strong>Chat</strong> with us!',
|
title: '<strong>Chat</strong> with us!',
|
||||||
idleTimeout: 8,
|
idleTimeout: 6,
|
||||||
idleTimeoutIntervallCheck: 0.5,
|
idleTimeoutIntervallCheck: 0.5,
|
||||||
inactiveTimeout: 8,
|
inactiveTimeout: 8,
|
||||||
inactiveTimeoutIntervallCheck: 0.5,
|
inactiveTimeoutIntervallCheck: 0.5,
|
||||||
|
@ -250,7 +262,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
|
|
||||||
ZammadChat.prototype._messageCount = 0;
|
ZammadChat.prototype._messageCount = 0;
|
||||||
|
|
||||||
ZammadChat.prototype.isOpen = true;
|
ZammadChat.prototype.isOpen = false;
|
||||||
|
|
||||||
ZammadChat.prototype.blinkOnlineInterval = null;
|
ZammadChat.prototype.blinkOnlineInterval = null;
|
||||||
|
|
||||||
|
@ -336,26 +348,24 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
this.setSessionId = bind(this.setSessionId, this);
|
this.setSessionId = bind(this.setSessionId, this);
|
||||||
this.onConnectionReestablished = bind(this.onConnectionReestablished, this);
|
this.onConnectionReestablished = bind(this.onConnectionReestablished, this);
|
||||||
this.reconnect = bind(this.reconnect, this);
|
this.reconnect = bind(this.reconnect, this);
|
||||||
this.wsReconnectStop = bind(this.wsReconnectStop, this);
|
|
||||||
this.wsReconnectStart = bind(this.wsReconnectStart, this);
|
|
||||||
this.destroy = bind(this.destroy, this);
|
this.destroy = bind(this.destroy, this);
|
||||||
this.onLeaveTemporary = bind(this.onLeaveTemporary, this);
|
this.onLeaveTemporary = bind(this.onLeaveTemporary, this);
|
||||||
this.onAgentTypingEnd = bind(this.onAgentTypingEnd, this);
|
this.onAgentTypingEnd = bind(this.onAgentTypingEnd, this);
|
||||||
this.onAgentTypingStart = bind(this.onAgentTypingStart, this);
|
this.onAgentTypingStart = bind(this.onAgentTypingStart, this);
|
||||||
this.onQueue = bind(this.onQueue, this);
|
this.onQueue = bind(this.onQueue, this);
|
||||||
this.onQueueScreen = bind(this.onQueueScreen, this);
|
this.onQueueScreen = bind(this.onQueueScreen, this);
|
||||||
|
this.onWebSocketClose = bind(this.onWebSocketClose, this);
|
||||||
this.onCloseAnimationEnd = bind(this.onCloseAnimationEnd, this);
|
this.onCloseAnimationEnd = bind(this.onCloseAnimationEnd, this);
|
||||||
this.closeWindow = bind(this.closeWindow, this);
|
|
||||||
this.close = bind(this.close, this);
|
this.close = bind(this.close, this);
|
||||||
|
this.sessionClose = bind(this.sessionClose, this);
|
||||||
this.onOpenAnimationEnd = bind(this.onOpenAnimationEnd, this);
|
this.onOpenAnimationEnd = bind(this.onOpenAnimationEnd, this);
|
||||||
this.open = bind(this.open, this);
|
this.open = bind(this.open, this);
|
||||||
this.renderMessage = bind(this.renderMessage, this);
|
this.renderMessage = bind(this.renderMessage, this);
|
||||||
this.receiveMessage = bind(this.receiveMessage, this);
|
this.receiveMessage = bind(this.receiveMessage, this);
|
||||||
this.onSubmit = bind(this.onSubmit, this);
|
this.onSubmit = bind(this.onSubmit, this);
|
||||||
this.onInput = bind(this.onInput, this);
|
this.onInput = bind(this.onInput, this);
|
||||||
this.reopenSession = bind(this.reopenSession, this);
|
this.onReopenSession = bind(this.onReopenSession, this);
|
||||||
this.onError = bind(this.onError, this);
|
this.onError = bind(this.onError, this);
|
||||||
this.onReady = bind(this.onReady, this);
|
|
||||||
this.onWebSocketMessage = bind(this.onWebSocketMessage, this);
|
this.onWebSocketMessage = bind(this.onWebSocketMessage, this);
|
||||||
this.send = bind(this.send, this);
|
this.send = bind(this.send, this);
|
||||||
this.checkForEnter = bind(this.checkForEnter, this);
|
this.checkForEnter = bind(this.checkForEnter, this);
|
||||||
|
@ -393,19 +403,20 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
this.io = new Io(this.options);
|
this.io = new Io(this.options);
|
||||||
this.io.set({
|
this.io.set({
|
||||||
onOpen: this.render,
|
onOpen: this.render,
|
||||||
onClose: this.hide,
|
onClose: this.onWebSocketClose,
|
||||||
onMessage: this.onWebSocketMessage
|
onMessage: this.onWebSocketMessage,
|
||||||
|
onError: this.onError
|
||||||
});
|
});
|
||||||
this.io.connect();
|
this.io.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
ZammadChat.prototype.render = function() {
|
ZammadChat.prototype.render = function() {
|
||||||
|
if (!this.el || !$('.zammad-chat').get(0)) {
|
||||||
this.el = $(this.view('chat')({
|
this.el = $(this.view('chat')({
|
||||||
title: this.options.title
|
title: this.options.title
|
||||||
}));
|
}));
|
||||||
this.options.target.append(this.el);
|
this.options.target.append(this.el);
|
||||||
this.input = this.el.find('.zammad-chat-input');
|
this.input = this.el.find('.zammad-chat-input');
|
||||||
$("." + this.options.buttonClass).addClass(this.inactiveClass);
|
|
||||||
this.el.find('.js-chat-open').click(this.open);
|
this.el.find('.js-chat-open').click(this.open);
|
||||||
this.el.find('.js-chat-close').click(this.close);
|
this.el.find('.js-chat-close').click(this.close);
|
||||||
this.el.find('.zammad-chat-controls').on('submit', this.onSubmit);
|
this.el.find('.zammad-chat-controls').on('submit', this.onSubmit);
|
||||||
|
@ -418,6 +429,16 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
return _this.onLeaveTemporary();
|
return _this.onLeaveTemporary();
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
|
$(window).bind('hashchange', (function(_this) {
|
||||||
|
return function() {
|
||||||
|
if (_this.isOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return _this.idleTimeout.start();
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
}
|
||||||
|
$("." + this.options.buttonClass).addClass(this.inactiveClass);
|
||||||
this.setAgentOnlineState('online');
|
this.setAgentOnlineState('online');
|
||||||
this.log.debug('widget rendered');
|
this.log.debug('widget rendered');
|
||||||
this.startTimeoutObservers();
|
this.startTimeoutObservers();
|
||||||
|
@ -453,7 +474,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
this.log.notice(pipe.data);
|
this.log.notice(pipe.data);
|
||||||
if (pipe.data && pipe.data.state === 'chat_disabled') {
|
if (pipe.data && pipe.data.state === 'chat_disabled') {
|
||||||
this.destroy({
|
this.destroy({
|
||||||
hide: true
|
remove: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -489,28 +510,15 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
break;
|
break;
|
||||||
case 'offline':
|
case 'offline':
|
||||||
this.onError('Zammad Chat: No agent online');
|
this.onError('Zammad Chat: No agent online');
|
||||||
this.state = 'off';
|
|
||||||
this.destroy({
|
|
||||||
hide: true
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case 'chat_disabled':
|
case 'chat_disabled':
|
||||||
this.onError('Zammad Chat: Chat is disabled');
|
this.onError('Zammad Chat: Chat is disabled');
|
||||||
this.state = 'off';
|
|
||||||
this.destroy({
|
|
||||||
hide: true
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case 'no_seats_available':
|
case 'no_seats_available':
|
||||||
this.onError("Zammad Chat: Too many clients in queue. Clients in queue: " + pipe.data.queue);
|
this.onError("Zammad Chat: Too many clients in queue. Clients in queue: " + pipe.data.queue);
|
||||||
this.state = 'off';
|
|
||||||
this.destroy({
|
|
||||||
hide: true
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case 'reconnect':
|
case 'reconnect':
|
||||||
this.log.debug('old messages', pipe.data.session);
|
this.onReopenSession(pipe.data);
|
||||||
this.reopenSession(pipe.data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -526,11 +534,23 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
|
|
||||||
ZammadChat.prototype.onError = function(message) {
|
ZammadChat.prototype.onError = function(message) {
|
||||||
this.log.debug(message);
|
this.log.debug(message);
|
||||||
return $("." + this.options.buttonClass).hide();
|
this.addStatus(message);
|
||||||
|
$("." + this.options.buttonClass).hide();
|
||||||
|
if (this.isOpen) {
|
||||||
|
this.disableInput();
|
||||||
|
return this.destroy({
|
||||||
|
remove: false
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return this.destroy({
|
||||||
|
remove: true
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ZammadChat.prototype.reopenSession = function(data) {
|
ZammadChat.prototype.onReopenSession = function(data) {
|
||||||
var i, len, message, ref, unfinishedMessage;
|
var i, len, message, ref, unfinishedMessage;
|
||||||
|
this.log.debug('old messages', data.session);
|
||||||
this.inactiveTimeout.start();
|
this.inactiveTimeout.start();
|
||||||
unfinishedMessage = sessionStorage.getItem('unfinished_message');
|
unfinishedMessage = sessionStorage.getItem('unfinished_message');
|
||||||
if (data.agent) {
|
if (data.agent) {
|
||||||
|
@ -631,10 +651,12 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
ZammadChat.prototype.open = function() {
|
ZammadChat.prototype.open = function() {
|
||||||
this.log.debug('open widget');
|
|
||||||
if (this.isOpen) {
|
if (this.isOpen) {
|
||||||
this.show();
|
this.log.debug('widget already open, block');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
this.isOpen = true;
|
||||||
|
this.log.debug('open widget');
|
||||||
if (!this.sessionId) {
|
if (!this.sessionId) {
|
||||||
this.showLoader();
|
this.showLoader();
|
||||||
}
|
}
|
||||||
|
@ -643,13 +665,10 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
this.el.animate({
|
this.el.animate({
|
||||||
bottom: 0
|
bottom: 0
|
||||||
}, 500, this.onOpenAnimationEnd);
|
}, 500, this.onOpenAnimationEnd);
|
||||||
|
return this.send('chat_session_init');
|
||||||
} else {
|
} else {
|
||||||
this.el.css('bottom', 0);
|
this.el.css('bottom', 0);
|
||||||
this.onOpenAnimationEnd();
|
return this.onOpenAnimationEnd();
|
||||||
}
|
|
||||||
this.isOpen = true;
|
|
||||||
if (!this.sessionId) {
|
|
||||||
return this.send('chat_session_init');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -657,17 +676,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
return this.idleTimeout.stop();
|
return this.idleTimeout.stop();
|
||||||
};
|
};
|
||||||
|
|
||||||
ZammadChat.prototype.close = function(event) {
|
ZammadChat.prototype.sessionClose = function() {
|
||||||
this.log.debug('close widget');
|
|
||||||
if (this.state === 'off' || this.state === 'unsupported') {
|
|
||||||
return this.state;
|
|
||||||
}
|
|
||||||
if (event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
if (!this.sessionId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.send('chat_session_close', {
|
this.send('chat_session_close', {
|
||||||
session_id: this.sessionId
|
session_id: this.sessionId
|
||||||
});
|
});
|
||||||
|
@ -677,14 +686,24 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
if (this.onInitialQueueDelayId) {
|
if (this.onInitialQueueDelayId) {
|
||||||
clearTimeout(this.onInitialQueueDelayId);
|
clearTimeout(this.onInitialQueueDelayId);
|
||||||
}
|
}
|
||||||
if (event) {
|
|
||||||
this.closeWindow();
|
|
||||||
}
|
|
||||||
return this.setSessionId(void 0);
|
return this.setSessionId(void 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
ZammadChat.prototype.closeWindow = function() {
|
ZammadChat.prototype.close = function(event) {
|
||||||
var remainerHeight;
|
var remainerHeight;
|
||||||
|
if (!this.isOpen) {
|
||||||
|
this.log.debug('can\'t close widget, it\'s not open');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.sessionId) {
|
||||||
|
this.log.debug('can\'t close widget without sessionId');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.log.debug('close widget');
|
||||||
|
if (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
this.sessionClose();
|
||||||
this.el.removeClass('zammad-chat-is-open');
|
this.el.removeClass('zammad-chat-is-open');
|
||||||
remainerHeight = this.el.height() - this.el.find('.zammad-chat-header').outerHeight();
|
remainerHeight = this.el.height() - this.el.find('.zammad-chat-header').outerHeight();
|
||||||
return this.el.animate({
|
return this.el.animate({
|
||||||
|
@ -702,7 +721,10 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
return this.io.reconnect();
|
return this.io.reconnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
ZammadChat.prototype.hide = function() {
|
ZammadChat.prototype.onWebSocketClose = function() {
|
||||||
|
if (this.isOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.el) {
|
if (this.el) {
|
||||||
return this.el.removeClass('zammad-chat-is-shown');
|
return this.el.removeClass('zammad-chat-is-shown');
|
||||||
}
|
}
|
||||||
|
@ -710,8 +732,8 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
|
|
||||||
ZammadChat.prototype.show = function() {
|
ZammadChat.prototype.show = function() {
|
||||||
var remainerHeight;
|
var remainerHeight;
|
||||||
if (this.state === 'off' || this.state === 'unsupported') {
|
if (this.state === 'offline') {
|
||||||
return this.state;
|
return;
|
||||||
}
|
}
|
||||||
this.el.addClass('zammad-chat-is-shown');
|
this.el.addClass('zammad-chat-is-shown');
|
||||||
if (!this.inputInitialized) {
|
if (!this.inputInitialized) {
|
||||||
|
@ -809,6 +831,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
ZammadChat.prototype.updateLastTimestamp = function(label, time) {
|
ZammadChat.prototype.updateLastTimestamp = function(label, time) {
|
||||||
|
if (!this.el) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
return this.el.find('.zammad-chat-body').find('.zammad-chat-timestamp').last().replaceWith(this.view('timestamp')({
|
return this.el.find('.zammad-chat-body').find('.zammad-chat-timestamp').last().replaceWith(this.view('timestamp')({
|
||||||
label: label,
|
label: label,
|
||||||
time: time
|
time: time
|
||||||
|
@ -816,6 +841,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
ZammadChat.prototype.addStatus = function(status) {
|
ZammadChat.prototype.addStatus = function(status) {
|
||||||
|
if (!this.el) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.maybeAddTimestamp();
|
this.maybeAddTimestamp();
|
||||||
this.el.find('.zammad-chat-body').append(this.view('status')({
|
this.el.find('.zammad-chat-body').append(this.view('status')({
|
||||||
status: status
|
status: status
|
||||||
|
@ -831,33 +859,23 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
if (params == null) {
|
if (params == null) {
|
||||||
params = {};
|
params = {};
|
||||||
}
|
}
|
||||||
this.log.debug('destroy widget');
|
this.log.debug('destroy widget', params);
|
||||||
if (params.hide) {
|
this.setAgentOnlineState('offline');
|
||||||
if (this.el) {
|
if (params.remove && this.el) {
|
||||||
this.el.remove();
|
this.el.remove();
|
||||||
}
|
}
|
||||||
}
|
if (this.waitingListTimeout) {
|
||||||
this.waitingListTimeout.stop();
|
this.waitingListTimeout.stop();
|
||||||
|
}
|
||||||
|
if (this.inactiveTimeout) {
|
||||||
this.inactiveTimeout.stop();
|
this.inactiveTimeout.stop();
|
||||||
|
}
|
||||||
|
if (this.idleTimeout) {
|
||||||
this.idleTimeout.stop();
|
this.idleTimeout.stop();
|
||||||
this.wsReconnectStop();
|
}
|
||||||
return this.io.close();
|
return this.io.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
ZammadChat.prototype.wsReconnectStart = function() {
|
|
||||||
this.wsReconnectStop();
|
|
||||||
if (this.reconnectDelayId) {
|
|
||||||
clearTimeout(this.reconnectDelayId);
|
|
||||||
}
|
|
||||||
return this.reconnectDelayId = setTimeout(this.io.connect(), 5000);
|
|
||||||
};
|
|
||||||
|
|
||||||
ZammadChat.prototype.wsReconnectStop = function() {
|
|
||||||
if (this.reconnectDelayId) {
|
|
||||||
return clearTimeout(this.reconnectDelayId);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ZammadChat.prototype.reconnect = function() {
|
ZammadChat.prototype.reconnect = function() {
|
||||||
this.log.notice('reconnecting');
|
this.log.notice('reconnecting');
|
||||||
this.disableInput();
|
this.disableInput();
|
||||||
|
@ -920,11 +938,11 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
agent: this.agent.name,
|
agent: this.agent.name,
|
||||||
delay: this.options.inactiveTimeout
|
delay: this.options.inactiveTimeout
|
||||||
}));
|
}));
|
||||||
this.close();
|
|
||||||
reload = function() {
|
reload = function() {
|
||||||
return location.reload();
|
return location.reload();
|
||||||
};
|
};
|
||||||
return this.el.find('.js-restart').click(reload);
|
this.el.find('.js-restart').click(reload);
|
||||||
|
return this.sessionClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
ZammadChat.prototype.showWaitingListTimeout = function() {
|
ZammadChat.prototype.showWaitingListTimeout = function() {
|
||||||
|
@ -932,11 +950,11 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
this.el.find('.zammad-chat-body').html(this.view('waiting_list_timeout')({
|
this.el.find('.zammad-chat-body').html(this.view('waiting_list_timeout')({
|
||||||
delay: this.options.watingListTimeout
|
delay: this.options.watingListTimeout
|
||||||
}));
|
}));
|
||||||
this.close();
|
|
||||||
reload = function() {
|
reload = function() {
|
||||||
return location.reload();
|
return location.reload();
|
||||||
};
|
};
|
||||||
return this.el.find('.js-restart').click(reload);
|
this.el.find('.js-restart').click(reload);
|
||||||
|
return this.sessionClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
ZammadChat.prototype.showLoader = function() {
|
ZammadChat.prototype.showLoader = function() {
|
||||||
|
@ -946,6 +964,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
ZammadChat.prototype.setAgentOnlineState = function(state) {
|
ZammadChat.prototype.setAgentOnlineState = function(state) {
|
||||||
var capitalizedState;
|
var capitalizedState;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
|
if (!this.el) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
capitalizedState = state.charAt(0).toUpperCase() + state.slice(1);
|
capitalizedState = state.charAt(0).toUpperCase() + state.slice(1);
|
||||||
return this.el.find('.zammad-chat-agent-status').attr('data-status', state).text(this.T(capitalizedState));
|
return this.el.find('.zammad-chat-agent-status').attr('data-status', state).text(this.T(capitalizedState));
|
||||||
};
|
};
|
||||||
|
@ -986,9 +1007,8 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
callback: (function(_this) {
|
callback: (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
_this.log.debug('Idle timeout reached, hide widget', new Date);
|
_this.log.debug('Idle timeout reached, hide widget', new Date);
|
||||||
_this.state = 'off';
|
|
||||||
return _this.destroy({
|
return _this.destroy({
|
||||||
hide: true
|
remove: true
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
})(this)
|
})(this)
|
||||||
|
@ -1001,11 +1021,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
callback: (function(_this) {
|
callback: (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
_this.log.debug('Inactive timeout reached, show timeout screen.', new Date);
|
_this.log.debug('Inactive timeout reached, show timeout screen.', new Date);
|
||||||
_this.state = 'off';
|
|
||||||
_this.setAgentOnlineState('offline');
|
|
||||||
_this.showCustomerTimeout();
|
_this.showCustomerTimeout();
|
||||||
return _this.destroy({
|
return _this.destroy({
|
||||||
hide: false
|
remove: false
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
})(this)
|
})(this)
|
||||||
|
@ -1018,11 +1036,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
callback: (function(_this) {
|
callback: (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
_this.log.debug('Waiting list timeout reached, show timeout screen.', new Date);
|
_this.log.debug('Waiting list timeout reached, show timeout screen.', new Date);
|
||||||
_this.state = 'off';
|
|
||||||
_this.setAgentOnlineState('offline');
|
|
||||||
_this.showWaitingListTimeout();
|
_this.showWaitingListTimeout();
|
||||||
return _this.destroy({
|
return _this.destroy({
|
||||||
hide: false
|
remove: false
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
})(this)
|
})(this)
|
||||||
|
@ -1035,67 +1051,6 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
||||||
return window.ZammadChat = ZammadChat;
|
return window.ZammadChat = ZammadChat;
|
||||||
})(window.jQuery, window);
|
})(window.jQuery, window);
|
||||||
|
|
||||||
if (!window.zammadChatTemplates) {
|
|
||||||
window.zammadChatTemplates = {};
|
|
||||||
}
|
|
||||||
window.zammadChatTemplates["agent"] = function (__obj) {
|
|
||||||
if (!__obj) __obj = {};
|
|
||||||
var __out = [], __capture = function(callback) {
|
|
||||||
var out = __out, result;
|
|
||||||
__out = [];
|
|
||||||
callback.call(this);
|
|
||||||
result = __out.join('');
|
|
||||||
__out = out;
|
|
||||||
return __safe(result);
|
|
||||||
}, __sanitize = function(value) {
|
|
||||||
if (value && value.ecoSafe) {
|
|
||||||
return value;
|
|
||||||
} else if (typeof value !== 'undefined' && value != null) {
|
|
||||||
return __escape(value);
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}, __safe, __objSafe = __obj.safe, __escape = __obj.escape;
|
|
||||||
__safe = __obj.safe = function(value) {
|
|
||||||
if (value && value.ecoSafe) {
|
|
||||||
return value;
|
|
||||||
} else {
|
|
||||||
if (!(typeof value !== 'undefined' && value != null)) value = '';
|
|
||||||
var result = new String(value);
|
|
||||||
result.ecoSafe = true;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (!__escape) {
|
|
||||||
__escape = __obj.escape = function(value) {
|
|
||||||
return ('' + value)
|
|
||||||
.replace(/&/g, '&')
|
|
||||||
.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>')
|
|
||||||
.replace(/"/g, '"');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(function() {
|
|
||||||
(function() {
|
|
||||||
if (this.agent.avatar) {
|
|
||||||
__out.push('\n<img class="zammad-chat-agent-avatar" src="');
|
|
||||||
__out.push(__sanitize(this.agent.avatar));
|
|
||||||
__out.push('">\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
__out.push('\n<span class="zammad-chat-agent-sentence">\n <span class="zammad-chat-agent-name">');
|
|
||||||
|
|
||||||
__out.push(__sanitize(this.agent.name));
|
|
||||||
|
|
||||||
__out.push('</span>\n</span>');
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
|
||||||
}).call(__obj);
|
|
||||||
__obj.safe = __objSafe, __obj.escape = __escape;
|
|
||||||
return __out.join('');
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||||
|
@ -1181,6 +1136,67 @@ jQuery.fn.autoGrow = function(options) {
|
||||||
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
if (!window.zammadChatTemplates) {
|
||||||
|
window.zammadChatTemplates = {};
|
||||||
|
}
|
||||||
|
window.zammadChatTemplates["agent"] = function (__obj) {
|
||||||
|
if (!__obj) __obj = {};
|
||||||
|
var __out = [], __capture = function(callback) {
|
||||||
|
var out = __out, result;
|
||||||
|
__out = [];
|
||||||
|
callback.call(this);
|
||||||
|
result = __out.join('');
|
||||||
|
__out = out;
|
||||||
|
return __safe(result);
|
||||||
|
}, __sanitize = function(value) {
|
||||||
|
if (value && value.ecoSafe) {
|
||||||
|
return value;
|
||||||
|
} else if (typeof value !== 'undefined' && value != null) {
|
||||||
|
return __escape(value);
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}, __safe, __objSafe = __obj.safe, __escape = __obj.escape;
|
||||||
|
__safe = __obj.safe = function(value) {
|
||||||
|
if (value && value.ecoSafe) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
if (!(typeof value !== 'undefined' && value != null)) value = '';
|
||||||
|
var result = new String(value);
|
||||||
|
result.ecoSafe = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!__escape) {
|
||||||
|
__escape = __obj.escape = function(value) {
|
||||||
|
return ('' + value)
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(function() {
|
||||||
|
(function() {
|
||||||
|
if (this.agent.avatar) {
|
||||||
|
__out.push('\n<img class="zammad-chat-agent-avatar" src="');
|
||||||
|
__out.push(__sanitize(this.agent.avatar));
|
||||||
|
__out.push('">\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
__out.push('\n<span class="zammad-chat-agent-sentence">\n <span class="zammad-chat-agent-name">');
|
||||||
|
|
||||||
|
__out.push(__sanitize(this.agent.name));
|
||||||
|
|
||||||
|
__out.push('</span>\n</span>');
|
||||||
|
|
||||||
|
}).call(this);
|
||||||
|
|
||||||
|
}).call(__obj);
|
||||||
|
__obj.safe = __objSafe, __obj.escape = __escape;
|
||||||
|
return __out.join('');
|
||||||
|
};
|
||||||
|
|
||||||
if (!window.zammadChatTemplates) {
|
if (!window.zammadChatTemplates) {
|
||||||
window.zammadChatTemplates = {};
|
window.zammadChatTemplates = {};
|
||||||
}
|
}
|
||||||
|
|
4
public/assets/chat/chat.min.js
vendored
4
public/assets/chat/chat.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -11,6 +11,7 @@
|
||||||
will-change: bottom;
|
will-change: bottom;
|
||||||
display: none;
|
display: none;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
&.is-fullscreen {
|
&.is-fullscreen {
|
||||||
right: 0;
|
right: 0;
|
||||||
|
@ -351,6 +352,11 @@
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.zammad-chat-button:disabled,
|
||||||
|
.zammad-chat-input:disabled {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
.zammad-chat-is-hidden {
|
.zammad-chat-is-hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,6 +387,42 @@ class ChatTest < TestCase
|
||||||
css: '.zammad-chat',
|
css: '.zammad-chat',
|
||||||
value: 'Chat closed by',
|
value: 'Chat closed by',
|
||||||
)
|
)
|
||||||
|
click(
|
||||||
|
browser: customer,
|
||||||
|
css: '.zammad-chat .js-chat-close',
|
||||||
|
)
|
||||||
|
watch_for_disappear(
|
||||||
|
browser: customer,
|
||||||
|
css: '.zammad-chat-is-open',
|
||||||
|
)
|
||||||
|
agent.find_elements( { css: '.active .chat-window .js-close' } ).each(&:click)
|
||||||
|
sleep 2
|
||||||
|
click(
|
||||||
|
browser: customer,
|
||||||
|
css: '.js-chat-open',
|
||||||
|
)
|
||||||
|
exists(
|
||||||
|
browser: customer,
|
||||||
|
css: '.zammad-chat-is-shown',
|
||||||
|
)
|
||||||
|
watch_for(
|
||||||
|
browser: customer,
|
||||||
|
css: '.zammad-chat',
|
||||||
|
value: '(waiting|warte)',
|
||||||
|
)
|
||||||
|
click(
|
||||||
|
browser: agent,
|
||||||
|
css: '.active .js-acceptChat',
|
||||||
|
)
|
||||||
|
sleep 2
|
||||||
|
exists_not(
|
||||||
|
browser: agent,
|
||||||
|
css: '.active .chat-window .chat-status.is-modified',
|
||||||
|
)
|
||||||
|
exists(
|
||||||
|
browser: agent,
|
||||||
|
css: '.active .chat-window .chat-status',
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_basic_usecase3
|
def test_basic_usecase3
|
||||||
|
@ -579,7 +615,7 @@ class ChatTest < TestCase
|
||||||
browser: customer,
|
browser: customer,
|
||||||
css: '.zammad-chat',
|
css: '.zammad-chat',
|
||||||
value: '(takes longer|dauert länger)',
|
value: '(takes longer|dauert länger)',
|
||||||
timeout: 90,
|
timeout: 120,
|
||||||
)
|
)
|
||||||
|
|
||||||
# no customer action, show sorry screen
|
# no customer action, show sorry screen
|
||||||
|
@ -625,6 +661,55 @@ class ChatTest < TestCase
|
||||||
timeout: 150,
|
timeout: 150,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
agent.find_elements( { css: '.active .chat-window .js-close' } ).each(&:click)
|
||||||
|
sleep 2
|
||||||
|
click(
|
||||||
|
browser: customer,
|
||||||
|
css: '.js-restart',
|
||||||
|
)
|
||||||
|
sleep 5
|
||||||
|
click(
|
||||||
|
browser: customer,
|
||||||
|
css: '.js-chat-open',
|
||||||
|
)
|
||||||
|
exists(
|
||||||
|
browser: customer,
|
||||||
|
css: '.zammad-chat-is-shown',
|
||||||
|
)
|
||||||
|
watch_for(
|
||||||
|
browser: customer,
|
||||||
|
css: '.zammad-chat',
|
||||||
|
value: '(waiting|warte)',
|
||||||
|
)
|
||||||
|
click(
|
||||||
|
browser: agent,
|
||||||
|
css: '.active .js-acceptChat',
|
||||||
|
)
|
||||||
|
sleep 2
|
||||||
|
exists(
|
||||||
|
browser: agent,
|
||||||
|
css: '.active .chat-window .chat-status',
|
||||||
|
)
|
||||||
|
set(
|
||||||
|
browser: agent,
|
||||||
|
css: '.active .chat-window .js-customerChatInput',
|
||||||
|
value: 'my name is me',
|
||||||
|
)
|
||||||
|
click(
|
||||||
|
browser: agent,
|
||||||
|
css: '.active .chat-window .js-send',
|
||||||
|
)
|
||||||
|
watch_for(
|
||||||
|
browser: customer,
|
||||||
|
css: '.zammad-chat .zammad-chat-agent-status',
|
||||||
|
value: 'online',
|
||||||
|
)
|
||||||
|
watch_for(
|
||||||
|
browser: customer,
|
||||||
|
css: '.zammad-chat',
|
||||||
|
value: 'my name is me',
|
||||||
|
)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue