From f06348e843ebf2f3b4a57662f2bdb6f92b63e954 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Tue, 8 Dec 2015 12:32:19 +0100 Subject: [PATCH] Fixed timing issues, improved tests. --- .../javascripts/app/controllers/chat.coffee | 27 +- public/assets/chat/chat.coffee | 186 ++++----- public/assets/chat/chat.css | 9 +- public/assets/chat/chat.js | 360 +++++++++--------- public/assets/chat/chat.min.js | 4 +- public/assets/chat/chat.scss | 10 +- test/browser/chat_test.rb | 87 ++++- 7 files changed, 409 insertions(+), 274 deletions(-) diff --git a/app/assets/javascripts/app/controllers/chat.coffee b/app/assets/javascripts/app/controllers/chat.coffee index 19ed5aba6..969f74674 100644 --- a/app/assets/javascripts/app/controllers/chat.coffee +++ b/app/assets/javascripts/app/controllers/chat.coffee @@ -291,7 +291,7 @@ class ChatWindow extends App.Controller phrasesArray = phrases.split(';') phrase = phrasesArray[_.random(0, phrasesArray.length-1)] @input.html(phrase) - @sendMessage() + @sendMessage(1600) focus: => @input.focus() @@ -372,16 +372,27 @@ class ChatWindow extends App.Controller event.preventDefault() @sendMessage() - sendMessage: => + sendMessage: (delay) => content = @input.html() return if !content - App.WebSocket.send( - event:'chat_session_message' - data: - content: content - session_id: @session.session_id - ) + send = => + App.WebSocket.send( + event:'chat_session_message' + data: + content: content + 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' @input.html('') diff --git a/public/assets/chat/chat.coffee b/public/assets/chat/chat.coffee index 525b965e2..05e4f96cb 100644 --- a/public/assets/chat/chat.coffee +++ b/public/assets/chat/chat.coffee @@ -73,7 +73,7 @@ do($ = window.jQuery, window) -> stop: => 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) class Io extends Base @@ -89,30 +89,40 @@ do($ = window.jQuery, window) -> @log.debug "Connecting to #{@options.host}" @ws = new window.WebSocket("#{@options.host}") @ws.onopen = (e) => - @log.debug 'on open', e + @log.debug 'onOpen', e @options.onOpen(e) @ws.onmessage = (e) => pipes = JSON.parse(e.data) - @log.debug 'on message', e.data + @log.debug 'onMessage', e.data if @options.onMessage @options.onMessage(pipes) @ws.onclose = (e) => - @log.debug 'close websocket connection' - if @options.onClose - @options.onClose(e) + @log.debug 'close websocket connection', e + if @manualClose + @log.debug 'manual close, onClose callback' + @manualClose = false + if @options.onClose + @options.onClose(e) + else + @log.debug 'error close, onError callback' + if @options.onError + @options.onError('Connection lost...') @ws.onerror = (e) => - @log.debug 'onerror', e + @log.debug 'onError', e if @options.onError @options.onError(e) close: => + @log.debug 'close websocket manually' + @manualClose = true @ws.close() reconnect: => - @ws.close() + @log.debug 'reconnect' + @close() @connect() send: (event, data = {}) => @@ -137,7 +147,7 @@ do($ = window.jQuery, window) -> buttonClass: 'open-zammad-chat' inactiveClass: 'is-inactive' title: 'Chat with us!' - idleTimeout: 8 + idleTimeout: 6 idleTimeoutIntervallCheck: 0.5 inactiveTimeout: 8 inactiveTimeoutIntervallCheck: 0.5 @@ -146,7 +156,7 @@ do($ = window.jQuery, window) -> logPrefix: 'chat' _messageCount: 0 - isOpen: true + isOpen: false blinkOnlineInterval: null stopBlinOnlineStateTimeout: null showTimeEveryXMinutes: 1 @@ -232,31 +242,39 @@ do($ = window.jQuery, window) -> @io = new Io(@options) @io.set( onOpen: @render - onClose: @hide + onClose: @onWebSocketClose onMessage: @onWebSocketMessage + onError: @onError ) @io.connect() render: => - @el = $(@view('chat')( - title: @options.title - )) - @options.target.append @el + if !@el || !$('.zammad-chat').get(0) + @el = $(@view('chat')( + title: @options.title + )) + @options.target.append @el - @input = @el.find('.zammad-chat-input') + @input = @el.find('.zammad-chat-input') + + # start bindings + @el.find('.js-chat-open').click @open + @el.find('.js-chat-close').click @close + @el.find('.zammad-chat-controls').on 'submit', @onSubmit + @input.on + keydown: @checkForEnter + input: @onInput + $(window).on('beforeunload', => + @onLeaveTemporary() + ) + $(window).bind('hashchange', => + return if @isOpen + @idleTimeout.start() + ) # disable open button $(".#{ @options.buttonClass }").addClass @inactiveClass - @el.find('.js-chat-open').click @open - @el.find('.js-chat-close').click @close - @el.find('.zammad-chat-controls').on 'submit', @onSubmit - @input.on - keydown: @checkForEnter - input: @onInput - $(window).on('beforeunload', => - @onLeaveTemporary() - ) @setAgentOnlineState 'online' @log.debug 'widget rendered' @@ -285,7 +303,7 @@ do($ = window.jQuery, window) -> when 'chat_error' @log.notice pipe.data if pipe.data && pipe.data.state is 'chat_disabled' - @destroy(hide: true) + @destroy(remove: true) when 'chat_session_message' return if pipe.data.self_written @receiveMessage pipe.data @@ -307,21 +325,14 @@ do($ = window.jQuery, window) -> @onReady() when 'offline' @onError 'Zammad Chat: No agent online' - @state = 'off' - @destroy(hide: true) when 'chat_disabled' @onError 'Zammad Chat: Chat is disabled' - @state = 'off' - @destroy(hide: true) when 'no_seats_available' @onError "Zammad Chat: Too many clients in queue. Clients in queue: #{pipe.data.queue}" - @state = 'off' - @destroy(hide: true) when 'reconnect' - @log.debug 'old messages', pipe.data.session - @reopenSession pipe.data + @onReopenSession pipe.data - onReady: => + onReady: -> @log.debug 'widget ready for use' $(".#{ @options.buttonClass }").click(@open).removeClass(@inactiveClass) @@ -330,9 +341,16 @@ do($ = window.jQuery, window) -> onError: (message) => @log.debug message + @addStatus(message) $(".#{ @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() unfinishedMessage = sessionStorage.getItem 'unfinished_message' @@ -436,9 +454,12 @@ do($ = window.jQuery, window) -> @scrollToBottom() open: => - @log.debug 'open widget' if @isOpen - @show() + @log.debug 'widget already open, block' + return + + @isOpen = true + @log.debug 'open widget' if !@sessionId @showLoader() @@ -447,27 +468,15 @@ do($ = window.jQuery, window) -> if !@sessionId @el.animate { bottom: 0 }, 500, @onOpenAnimationEnd + @send('chat_session_init') else @el.css 'bottom', 0 @onOpenAnimationEnd() - @isOpen = true - - if !@sessionId - @send('chat_session_init') - onOpenAnimationEnd: => @idleTimeout.stop() - close: (event) => - @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 - + sessionClose: => # send close @send 'chat_session_close', session_id: @sessionId @@ -483,12 +492,23 @@ do($ = window.jQuery, window) -> if @onInitialQueueDelayId clearTimeout(@onInitialQueueDelayId) - if event - @closeWindow() - @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') remainerHeight = @el.height() - @el.find('.zammad-chat-header').outerHeight() @el.animate { bottom: -remainerHeight }, 500, @onCloseAnimationEnd @@ -503,15 +523,15 @@ do($ = window.jQuery, window) -> @isOpen = false - # restart connection @io.reconnect() - hide: -> + onWebSocketClose: => + return if @isOpen if @el @el.removeClass('zammad-chat-is-shown') show: -> - return @state if @state is 'off' or @state is 'unsupported' + return if @state is 'offline' @el.addClass('zammad-chat-is-shown') @@ -600,6 +620,7 @@ do($ = window.jQuery, window) -> @scrollToBottom() updateLastTimestamp: (label, time) -> + return if !@el @el.find('.zammad-chat-body') .find('.zammad-chat-timestamp') .last() @@ -608,6 +629,7 @@ do($ = window.jQuery, window) -> time: time addStatus: (status) -> + return if !@el @maybeAddTimestamp() @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')) destroy: (params = {}) => - @log.debug 'destroy widget' - if params.hide - if @el - @el.remove() + @log.debug 'destroy widget', params + + @setAgentOnlineState 'offline' + + if params.remove && @el + @el.remove() # stop all timer - @waitingListTimeout.stop() - @inactiveTimeout.stop() - @idleTimeout.stop() - @wsReconnectStop() + if @waitingListTimeout + @waitingListTimeout.stop() + if @inactiveTimeout + @inactiveTimeout.stop() + if @idleTimeout + @idleTimeout.stop() # stop ws connection @io.close() - wsReconnectStart: => - @wsReconnectStop() - if @reconnectDelayId - clearTimeout(@reconnectDelayId) - @reconnectDelayId = setTimeout(@io.connect(), 5000) - - wsReconnectStop: => - if @reconnectDelayId - clearTimeout(@reconnectDelayId) - reconnect: => # set status to connecting @log.notice 'reconnecting' @@ -702,24 +718,25 @@ do($ = window.jQuery, window) -> @el.find('.zammad-chat-body').html @view('customer_timeout') agent: @agent.name delay: @options.inactiveTimeout - @close() reload = -> location.reload() @el.find('.js-restart').click reload + @sessionClose() showWaitingListTimeout: -> @el.find('.zammad-chat-body').html @view('waiting_list_timeout') delay: @options.watingListTimeout - @close() reload = -> location.reload() @el.find('.js-restart').click reload + @sessionClose() showLoader: -> @el.find('.zammad-chat-body').html @view('loader')() setAgentOnlineState: (state) => @state = state + return if !@el capitalizedState = state.charAt(0).toUpperCase() + state.slice(1) @el .find('.zammad-chat-agent-status') @@ -757,8 +774,7 @@ do($ = window.jQuery, window) -> timeoutIntervallCheck: @options.idleTimeoutIntervallCheck callback: => @log.debug 'Idle timeout reached, hide widget', new Date - @state = 'off' - @destroy(hide: true) + @destroy(remove: true) ) @inactiveTimeout = new Timeout( logPrefix: 'inactiveTimeout' @@ -767,10 +783,8 @@ do($ = window.jQuery, window) -> timeoutIntervallCheck: @options.inactiveTimeoutIntervallCheck callback: => @log.debug 'Inactive timeout reached, show timeout screen.', new Date - @state = 'off' - @setAgentOnlineState 'offline' @showCustomerTimeout() - @destroy(hide:false) + @destroy(remove: false) ) @waitingListTimeout = new Timeout( logPrefix: 'waitingListTimeout' @@ -779,10 +793,8 @@ do($ = window.jQuery, window) -> timeoutIntervallCheck: @options.waitingListTimeoutIntervallCheck callback: => @log.debug 'Waiting list timeout reached, show timeout screen.', new Date - @state = 'off' - @setAgentOnlineState 'offline' @showWaitingListTimeout() - @destroy(hide:false) + @destroy(remove: false) ) window.ZammadChat = ZammadChat diff --git a/public/assets/chat/chat.css b/public/assets/chat/chat.css index 9bdcc04e5..af4612dc0 100644 --- a/public/assets/chat/chat.css +++ b/public/assets/chat/chat.css @@ -12,7 +12,8 @@ display: none; -webkit-flex-direction: column; -ms-flex-direction: column; - flex-direction: column; } + flex-direction: column; + z-index: 999; } .zammad-chat.is-fullscreen { right: 0; width: 100%; @@ -106,7 +107,7 @@ margin: 0 1em; display: inline-block; line-height: 2em; - padding: 0 0.7em; + padding: 0 .7em; border-radius: 1em; background: rgba(0, 0, 0, 0.1); box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.04) inset; } @@ -349,6 +350,10 @@ .zammad-chat-send { float: right; } +.zammad-chat-button:disabled, +.zammad-chat-input:disabled { + opacity: 0.3; } + .zammad-chat-is-hidden { display: none; } diff --git a/public/assets/chat/chat.js b/public/assets/chat/chat.js index c663db28b..e569c49a0 100644 --- a/public/assets/chat/chat.js +++ b/public/assets/chat/chat.js @@ -128,7 +128,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); if (!this.intervallId) { 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); }; @@ -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.onopen = (function(_this) { return function(e) { - _this.log.debug('on open', e); + _this.log.debug('onOpen', e); return _this.options.onOpen(e); }; })(this); @@ -172,7 +172,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); return function(e) { var pipes; pipes = JSON.parse(e.data); - _this.log.debug('on message', e.data); + _this.log.debug('onMessage', e.data); if (_this.options.onMessage) { return _this.options.onMessage(pipes); } @@ -180,15 +180,24 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); })(this); this.ws.onclose = (function(_this) { return function(e) { - _this.log.debug('close websocket connection'); - if (_this.options.onClose) { - return _this.options.onClose(e); + _this.log.debug('close websocket connection', e); + if (_this.manualClose) { + _this.log.debug('manual close, onClose callback'); + _this.manualClose = false; + if (_this.options.onClose) { + return _this.options.onClose(e); + } + } else { + _this.log.debug('error close, onError callback'); + if (_this.options.onError) { + return _this.options.onError('Connection lost...'); + } } }; })(this); return this.ws.onerror = (function(_this) { return function(e) { - _this.log.debug('onerror', e); + _this.log.debug('onError', e); if (_this.options.onError) { 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() { + this.log.debug('close websocket manually'); + this.manualClose = true; return this.ws.close(); }; Io.prototype.reconnect = function() { - this.ws.close(); + this.log.debug('reconnect'); + this.close(); return this.connect(); }; @@ -238,7 +250,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); buttonClass: 'open-zammad-chat', inactiveClass: 'is-inactive', title: 'Chat with us!', - idleTimeout: 8, + idleTimeout: 6, idleTimeoutIntervallCheck: 0.5, inactiveTimeout: 8, 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.isOpen = true; + ZammadChat.prototype.isOpen = false; 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.onConnectionReestablished = bind(this.onConnectionReestablished, 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.onLeaveTemporary = bind(this.onLeaveTemporary, this); this.onAgentTypingEnd = bind(this.onAgentTypingEnd, this); this.onAgentTypingStart = bind(this.onAgentTypingStart, this); this.onQueue = bind(this.onQueue, this); this.onQueueScreen = bind(this.onQueueScreen, this); + this.onWebSocketClose = bind(this.onWebSocketClose, this); this.onCloseAnimationEnd = bind(this.onCloseAnimationEnd, this); - this.closeWindow = bind(this.closeWindow, this); this.close = bind(this.close, this); + this.sessionClose = bind(this.sessionClose, this); this.onOpenAnimationEnd = bind(this.onOpenAnimationEnd, this); this.open = bind(this.open, this); this.renderMessage = bind(this.renderMessage, this); this.receiveMessage = bind(this.receiveMessage, this); this.onSubmit = bind(this.onSubmit, 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.onReady = bind(this.onReady, this); this.onWebSocketMessage = bind(this.onWebSocketMessage, this); this.send = bind(this.send, this); this.checkForEnter = bind(this.checkForEnter, this); @@ -393,31 +403,42 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); this.io = new Io(this.options); this.io.set({ onOpen: this.render, - onClose: this.hide, - onMessage: this.onWebSocketMessage + onClose: this.onWebSocketClose, + onMessage: this.onWebSocketMessage, + onError: this.onError }); this.io.connect(); } ZammadChat.prototype.render = function() { - this.el = $(this.view('chat')({ - title: this.options.title - })); - this.options.target.append(this.el); - this.input = this.el.find('.zammad-chat-input'); + if (!this.el || !$('.zammad-chat').get(0)) { + this.el = $(this.view('chat')({ + title: this.options.title + })); + this.options.target.append(this.el); + this.input = this.el.find('.zammad-chat-input'); + this.el.find('.js-chat-open').click(this.open); + this.el.find('.js-chat-close').click(this.close); + this.el.find('.zammad-chat-controls').on('submit', this.onSubmit); + this.input.on({ + keydown: this.checkForEnter, + input: this.onInput + }); + $(window).on('beforeunload', (function(_this) { + return function() { + return _this.onLeaveTemporary(); + }; + })(this)); + $(window).bind('hashchange', (function(_this) { + return function() { + if (_this.isOpen) { + return; + } + return _this.idleTimeout.start(); + }; + })(this)); + } $("." + this.options.buttonClass).addClass(this.inactiveClass); - this.el.find('.js-chat-open').click(this.open); - this.el.find('.js-chat-close').click(this.close); - this.el.find('.zammad-chat-controls').on('submit', this.onSubmit); - this.input.on({ - keydown: this.checkForEnter, - input: this.onInput - }); - $(window).on('beforeunload', (function(_this) { - return function() { - return _this.onLeaveTemporary(); - }; - })(this)); this.setAgentOnlineState('online'); this.log.debug('widget rendered'); this.startTimeoutObservers(); @@ -453,7 +474,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); this.log.notice(pipe.data); if (pipe.data && pipe.data.state === 'chat_disabled') { this.destroy({ - hide: true + remove: true }); } break; @@ -489,28 +510,15 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); break; case 'offline': this.onError('Zammad Chat: No agent online'); - this.state = 'off'; - this.destroy({ - hide: true - }); break; case 'chat_disabled': this.onError('Zammad Chat: Chat is disabled'); - this.state = 'off'; - this.destroy({ - hide: true - }); break; case 'no_seats_available': this.onError("Zammad Chat: Too many clients in queue. Clients in queue: " + pipe.data.queue); - this.state = 'off'; - this.destroy({ - hide: true - }); break; case 'reconnect': - this.log.debug('old messages', pipe.data.session); - this.reopenSession(pipe.data); + this.onReopenSession(pipe.data); } } } @@ -526,11 +534,23 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); ZammadChat.prototype.onError = function(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; + this.log.debug('old messages', data.session); this.inactiveTimeout.start(); unfinishedMessage = sessionStorage.getItem('unfinished_message'); if (data.agent) { @@ -631,10 +651,12 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; ZammadChat.prototype.open = function() { - this.log.debug('open widget'); if (this.isOpen) { - this.show(); + this.log.debug('widget already open, block'); + return; } + this.isOpen = true; + this.log.debug('open widget'); if (!this.sessionId) { this.showLoader(); } @@ -643,13 +665,10 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); this.el.animate({ bottom: 0 }, 500, this.onOpenAnimationEnd); + return this.send('chat_session_init'); } else { this.el.css('bottom', 0); - this.onOpenAnimationEnd(); - } - this.isOpen = true; - if (!this.sessionId) { - return this.send('chat_session_init'); + return this.onOpenAnimationEnd(); } }; @@ -657,17 +676,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); return this.idleTimeout.stop(); }; - ZammadChat.prototype.close = function(event) { - this.log.debug('close widget'); - if (this.state === 'off' || this.state === 'unsupported') { - return this.state; - } - if (event) { - event.stopPropagation(); - } - if (!this.sessionId) { - return; - } + ZammadChat.prototype.sessionClose = function() { this.send('chat_session_close', { session_id: this.sessionId }); @@ -677,14 +686,24 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); if (this.onInitialQueueDelayId) { clearTimeout(this.onInitialQueueDelayId); } - if (event) { - this.closeWindow(); - } return this.setSessionId(void 0); }; - ZammadChat.prototype.closeWindow = function() { + ZammadChat.prototype.close = function(event) { 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'); remainerHeight = this.el.height() - this.el.find('.zammad-chat-header').outerHeight(); return this.el.animate({ @@ -702,7 +721,10 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); return this.io.reconnect(); }; - ZammadChat.prototype.hide = function() { + ZammadChat.prototype.onWebSocketClose = function() { + if (this.isOpen) { + return; + } if (this.el) { 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() { var remainerHeight; - if (this.state === 'off' || this.state === 'unsupported') { - return this.state; + if (this.state === 'offline') { + return; } this.el.addClass('zammad-chat-is-shown'); 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) { + if (!this.el) { + return; + } return this.el.find('.zammad-chat-body').find('.zammad-chat-timestamp').last().replaceWith(this.view('timestamp')({ label: label, time: time @@ -816,6 +841,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; ZammadChat.prototype.addStatus = function(status) { + if (!this.el) { + return; + } this.maybeAddTimestamp(); this.el.find('.zammad-chat-body').append(this.view('status')({ status: status @@ -831,33 +859,23 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); if (params == null) { params = {}; } - this.log.debug('destroy widget'); - if (params.hide) { - if (this.el) { - this.el.remove(); - } + this.log.debug('destroy widget', params); + this.setAgentOnlineState('offline'); + if (params.remove && this.el) { + this.el.remove(); + } + if (this.waitingListTimeout) { + this.waitingListTimeout.stop(); + } + if (this.inactiveTimeout) { + this.inactiveTimeout.stop(); + } + if (this.idleTimeout) { + this.idleTimeout.stop(); } - this.waitingListTimeout.stop(); - this.inactiveTimeout.stop(); - this.idleTimeout.stop(); - this.wsReconnectStop(); 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() { this.log.notice('reconnecting'); this.disableInput(); @@ -920,11 +938,11 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); agent: this.agent.name, delay: this.options.inactiveTimeout })); - this.close(); reload = function() { 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() { @@ -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')({ delay: this.options.watingListTimeout })); - this.close(); reload = function() { 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() { @@ -946,6 +964,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); ZammadChat.prototype.setAgentOnlineState = function(state) { var capitalizedState; this.state = state; + if (!this.el) { + return; + } capitalizedState = state.charAt(0).toUpperCase() + state.slice(1); 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) { return function() { _this.log.debug('Idle timeout reached, hide widget', new Date); - _this.state = 'off'; return _this.destroy({ - hide: true + remove: true }); }; })(this) @@ -1001,11 +1021,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); callback: (function(_this) { return function() { _this.log.debug('Inactive timeout reached, show timeout screen.', new Date); - _this.state = 'off'; - _this.setAgentOnlineState('offline'); _this.showCustomerTimeout(); return _this.destroy({ - hide: false + remove: false }); }; })(this) @@ -1018,11 +1036,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); callback: (function(_this) { return function() { _this.log.debug('Waiting list timeout reached, show timeout screen.', new Date); - _this.state = 'off'; - _this.setAgentOnlineState('offline'); _this.showWaitingListTimeout(); return _this.destroy({ - hide: false + remove: false }); }; })(this) @@ -1035,67 +1051,6 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); return window.ZammadChat = ZammadChat; })(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, '"'); - }; - } - (function() { - (function() { - if (this.agent.avatar) { - __out.push('\n\n'); - } - - __out.push('\n\n '); - - __out.push(__sanitize(this.agent.name)); - - __out.push('\n'); - - }).call(this); - - }).call(__obj); - __obj.safe = __objSafe, __obj.escape = __escape; - return __out.join(''); -}; - /*! * ---------------------------------------------------------------------------- * "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, '"'); + }; + } + (function() { + (function() { + if (this.agent.avatar) { + __out.push('\n\n'); + } + + __out.push('\n\n '); + + __out.push(__sanitize(this.agent.name)); + + __out.push('\n'); + + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}; + if (!window.zammadChatTemplates) { window.zammadChatTemplates = {}; } diff --git a/public/assets/chat/chat.min.js b/public/assets/chat/chat.min.js index 53c0ff652..57c277044 100644 --- a/public/assets/chat/chat.min.js +++ b/public/assets/chat/chat.min.js @@ -1,2 +1,2 @@ -var bind=function(t,e){return function(){return t.apply(e,arguments)}},slice=[].slice,extend=function(t,e){function s(){this.constructor=t}for(var i in e)hasProp.call(e,i)&&(t[i]=e[i]);return s.prototype=e.prototype,t.prototype=new s,t.__super__=e.prototype,t},hasProp={}.hasOwnProperty;!function(t,e){var s,i,n,o,a,r,h,d;return d=document.getElementsByTagName("script"),r=d[d.length-1],h=r.src.match(".*://([^:/]*).*")[1],s=function(){function e(e){this.options=t.extend({},this.defaults,e),this.log=new n({debug:this.options.debug,logPrefix:this.options.logPrefix||this.logPrefix})}return e.prototype.defaults={debug:!1},e}(),n=function(){function e(e){this.log=bind(this.log,this),this.error=bind(this.error,this),this.notice=bind(this.notice,this),this.debug=bind(this.debug,this),this.options=t.extend({},this.defaults,e)}return e.prototype.defaults={debug:!1},e.prototype.debug=function(){var t;return t=1<=arguments.length?slice.call(arguments,0):[],this.options.debug?this.log("debug",t):void 0},e.prototype.notice=function(){var t;return t=1<=arguments.length?slice.call(arguments,0):[],this.log("notice",t)},e.prototype.error=function(){var t;return t=1<=arguments.length?slice.call(arguments,0):[],this.log("error",t)},e.prototype.log=function(e,s){var i,n,o,a;if(s.unshift("||"),s.unshift(e),s.unshift(this.options.logPrefix),console.log.apply(console,s),this.options.debug){for(a="",i=0,o=s.length;o>i;i++)n=s[i],a+=" ",a+="object"==typeof n?JSON.stringify(n):n&&n.toString?n.toString():n;return t(".js-chatLogDisplay").prepend("
"+a+"
")}},e}(),o=function(t){function e(t){this.stop=bind(this.stop,this),this.start=bind(this.start,this),e.__super__.constructor.call(this,t)}return extend(e,t),e.prototype.timeoutStartedAt=null,e.prototype.logPrefix="timeout",e.prototype.defaults={debug:!1,timeout:4,timeoutIntervallCheck:.5},e.prototype.start=function(){var t,e;return this.stop(),e=new Date,t=function(t){return function(){var s;return s=new Date-new Date(e.getTime()+1e3*t.options.timeout*60),t.log.debug("Timeout check for "+t.options.timeout+" minutes (left "+s/1e3+" sec.)"),0>s?void 0:(t.stop(),t.options.callback())}}(this),this.log.debug("Start timeout in "+this.options.timeout+" minutes"),this.intervallId=setInterval(t,1e3*this.options.timeoutIntervallCheck*60)},e.prototype.stop=function(){return this.intervallId?(this.log.debug("Stop timeout of "+this.options.timeout+" minutes at"),clearInterval(this.intervallId)):void 0},e}(s),i=function(t){function s(t){this.send=bind(this.send,this),this.reconnect=bind(this.reconnect,this),this.close=bind(this.close,this),this.connect=bind(this.connect,this),this.set=bind(this.set,this),s.__super__.constructor.call(this,t)}return extend(s,t),s.prototype.logPrefix="io",s.prototype.set=function(t){var e,s,i;s=[];for(e in t)i=t[e],s.push(this.options[e]=i);return s},s.prototype.connect=function(){return this.log.debug("Connecting to "+this.options.host),this.ws=new e.WebSocket(""+this.options.host),this.ws.onopen=function(t){return function(e){return t.log.debug("on open",e),t.options.onOpen(e)}}(this),this.ws.onmessage=function(t){return function(e){var s;return s=JSON.parse(e.data),t.log.debug("on message",e.data),t.options.onMessage?t.options.onMessage(s):void 0}}(this),this.ws.onclose=function(t){return function(e){return t.log.debug("close websocket connection"),t.options.onClose?t.options.onClose(e):void 0}}(this),this.ws.onerror=function(t){return function(e){return t.log.debug("onerror",e),t.options.onError?t.options.onError(e):void 0}}(this)},s.prototype.close=function(){return this.ws.close()},s.prototype.reconnect=function(){return this.ws.close(),this.connect()},s.prototype.send=function(t,e){var s;return null==e&&(e={}),this.log.debug("send",t,e),s=JSON.stringify({event:t,data:e}),this.ws.send(s)},s}(s),a=function(s){function n(s){return this.startTimeoutObservers=bind(this.startTimeoutObservers,this),this.setAgentOnlineState=bind(this.setAgentOnlineState,this),this.onConnectionEstablished=bind(this.onConnectionEstablished,this),this.setSessionId=bind(this.setSessionId,this),this.onConnectionReestablished=bind(this.onConnectionReestablished,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.onLeaveTemporary=bind(this.onLeaveTemporary,this),this.onAgentTypingEnd=bind(this.onAgentTypingEnd,this),this.onAgentTypingStart=bind(this.onAgentTypingStart,this),this.onQueue=bind(this.onQueue,this),this.onQueueScreen=bind(this.onQueueScreen,this),this.onCloseAnimationEnd=bind(this.onCloseAnimationEnd,this),this.closeWindow=bind(this.closeWindow,this),this.close=bind(this.close,this),this.onOpenAnimationEnd=bind(this.onOpenAnimationEnd,this),this.open=bind(this.open,this),this.renderMessage=bind(this.renderMessage,this),this.receiveMessage=bind(this.receiveMessage,this),this.onSubmit=bind(this.onSubmit,this),this.onInput=bind(this.onInput,this),this.reopenSession=bind(this.reopenSession,this),this.onError=bind(this.onError,this),this.onReady=bind(this.onReady,this),this.onWebSocketMessage=bind(this.onWebSocketMessage,this),this.send=bind(this.send,this),this.checkForEnter=bind(this.checkForEnter,this),this.render=bind(this.render,this),this.view=bind(this.view,this),this.T=bind(this.T,this),this.options=t.extend({},this.defaults,s),n.__super__.constructor.call(this,this.options),t?e.WebSocket&&sessionStorage?this.options.chatId?(this.options.lang||(this.options.lang=t("html").attr("lang")),this.options.lang&&(this.options.lang=this.options.lang.replace(/-.+?$/,""),this.log.debug("lang: "+this.options.lang)),this.options.host||this.detectHost(),this.loadCss(),this.io=new i(this.options),this.io.set({onOpen:this.render,onClose:this.hide,onMessage:this.onWebSocketMessage}),void this.io.connect()):(this.state="unsupported",void this.log.error("Chat: need chatId as option!")):(this.state="unsupported",void this.log.notice("Chat: Browser not supported!")):(this.state="unsupported",void this.log.notice("Chat: no jquery found!"))}return extend(n,s),n.prototype.defaults={chatId:void 0,show:!0,target:t("body"),host:"",debug:!1,flat:!1,lang:void 0,cssAutoload:!0,cssUrl:void 0,fontSize:void 0,buttonClass:"open-zammad-chat",inactiveClass:"is-inactive",title:"Chat with us!",idleTimeout:8,idleTimeoutIntervallCheck:.5,inactiveTimeout:8,inactiveTimeoutIntervallCheck:.5,waitingListTimeout:4,waitingListTimeoutIntervallCheck:.5},n.prototype.logPrefix="chat",n.prototype._messageCount=0,n.prototype.isOpen=!0,n.prototype.blinkOnlineInterval=null,n.prototype.stopBlinOnlineStateTimeout=null,n.prototype.showTimeEveryXMinutes=1,n.prototype.lastTimestamp=null,n.prototype.lastAddedType=null,n.prototype.inputTimeout=null,n.prototype.isTyping=!1,n.prototype.state="offline",n.prototype.initialQueueDelay=1e4,n.prototype.translations={de:{"Chat with us!":"Chat mit uns!",Online:"Online",Online:"Online",Offline:"Offline",Connecting:"Verbinden","Connection re-established":"Verbindung wiederhergestellt",Today:"Heute",Send:"Senden","Compose your message...":"Ihre Nachricht...","All colleges are busy.":"Alle Kollegen sind belegt.","You are on waiting list position %s.":"Sie sind in der Warteliste an der Position %s.","Start new conversation":"Neue Konversation starten","Since you didn't respond in the last %s minutes your conversation with %s got closed.":"Da Sie in den letzten %s Minuten nichts geschrieben haben wurde Ihre Konversation mit %s geschlossen.","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."}},n.prototype.sessionId=void 0,n.prototype.T=function(){var t,e,s,i,n,o;if(n=arguments[0],s=2<=arguments.length?slice.call(arguments,1):[],this.options.lang&&"en"!==this.options.lang&&(this.translations[this.options.lang]?(o=this.translations[this.options.lang],o[n]||this.log.notice("Translation needed for '"+n+"'"),n=o[n]||n):this.log.notice("Translation '"+this.options.lang+"' needed!")),s)for(t=0,i=s.length;i>t;t++)e=s[t],n=n.replace(/%s/,e);return n},n.prototype.view=function(t){return function(s){return function(i){return i||(i={}),i.T=s.T,i.background=s.options.background,i.flat=s.options.flat,i.fontSize=s.options.fontSize,e.zammadChatTemplates[t](i)}}(this)},n.prototype.render=function(){return this.el=t(this.view("chat")({title:this.options.title})),this.options.target.append(this.el),this.input=this.el.find(".zammad-chat-input"),t("."+this.options.buttonClass).addClass(this.inactiveClass),this.el.find(".js-chat-open").click(this.open),this.el.find(".js-chat-close").click(this.close),this.el.find(".zammad-chat-controls").on("submit",this.onSubmit),this.input.on({keydown:this.checkForEnter,input:this.onInput}),t(e).on("beforeunload",function(t){return function(){return t.onLeaveTemporary()}}(this)),this.setAgentOnlineState("online"),this.log.debug("widget rendered"),this.startTimeoutObservers(),this.idleTimeout.start(),this.sessionId=sessionStorage.getItem("sessionId"),this.send("chat_status_customer",{session_id:this.sessionId})},n.prototype.checkForEnter=function(t){return t.shiftKey||13!==t.keyCode?void 0:(t.preventDefault(),this.sendMessage())},n.prototype.send=function(t,e){return null==e&&(e={}),e.chat_id=this.options.chatId,this.io.send(t,e)},n.prototype.onWebSocketMessage=function(t){var e,s,i;for(e=0,s=t.length;s>e;e++)switch(i=t[e],this.log.debug("ws:onmessage",i),i.event){case"chat_error":this.log.notice(i.data),i.data&&"chat_disabled"===i.data.state&&this.destroy({hide:!0});break;case"chat_session_message":if(i.data.self_written)return;this.receiveMessage(i.data);break;case"chat_session_typing":if(i.data.self_written)return;this.onAgentTypingStart();break;case"chat_session_start":this.onConnectionEstablished(i.data);break;case"chat_session_queue":this.onQueueScreen(i.data);break;case"chat_session_closed":this.onSessionClosed(i.data);break;case"chat_session_left":this.onSessionClosed(i.data);break;case"chat_status_customer":switch(i.data.state){case"online":this.sessionId=void 0,this.onReady();break;case"offline":this.onError("Zammad Chat: No agent online"),this.state="off",this.destroy({hide:!0});break;case"chat_disabled":this.onError("Zammad Chat: Chat is disabled"),this.state="off",this.destroy({hide:!0});break;case"no_seats_available":this.onError("Zammad Chat: Too many clients in queue. Clients in queue: "+i.data.queue),this.state="off",this.destroy({hide:!0});break;case"reconnect":this.log.debug("old messages",i.data.session),this.reopenSession(i.data)}}},n.prototype.onReady=function(){return this.log.debug("widget ready for use"),t("."+this.options.buttonClass).click(this.open).removeClass(this.inactiveClass),this.options.show?this.show():void 0},n.prototype.onError=function(e){return this.log.debug(e),t("."+this.options.buttonClass).hide()},n.prototype.reopenSession=function(t){var e,s,i,n,o;if(this.inactiveTimeout.start(),o=sessionStorage.getItem("unfinished_message"),t.agent){for(this.onConnectionEstablished(t),n=t.session,e=0,s=n.length;s>e;e++)i=n[e],this.renderMessage({message:i.content,id:i.id,from:i.created_by_id?"agent":"customer"});o&&this.input.val(o)}return t.position&&this.onQueue(t),this.show(),this.open(),this.scrollToBottom(),o?this.input.focus():void 0},n.prototype.onInput=function(){return this.el.find(".zammad-chat-message--unread").removeClass("zammad-chat-message--unread"),sessionStorage.setItem("unfinished_message",this.input.val()),this.onTyping()},n.prototype.onTyping=function(){return this.isTyping&&this.isTyping>new Date((new Date).getTime()-1500)?void 0:(this.isTyping=new Date,this.send("chat_session_typing",{session_id:this.sessionId}),this.inactiveTimeout.start())},n.prototype.onSubmit=function(t){return t.preventDefault(),this.sendMessage()},n.prototype.sendMessage=function(){var t,e;return(t=this.input.val())?(this.inactiveTimeout.start(),sessionStorage.removeItem("unfinished_message"),e=this.view("message")({message:t,from:"customer",id:this._messageCount++,unreadClass:""}),this.maybeAddTimestamp(),this.el.find(".zammad-chat-message--typing").size()?(this.lastAddedType="typing-placeholder",this.el.find(".zammad-chat-message--typing").before(e)):(this.lastAddedType="message--customer",this.el.find(".zammad-chat-body").append(e)),this.input.val(""),this.scrollToBottom(),this.send("chat_session_message",{content:t,id:this._messageCount,session_id:this.sessionId})):void 0},n.prototype.receiveMessage=function(t){return this.inactiveTimeout.start(),this.onAgentTypingEnd(),this.maybeAddTimestamp(),this.renderMessage({message:t.message.content,id:t.id,from:"agent"})},n.prototype.renderMessage=function(t){return this.lastAddedType="message--"+t.from,t.unreadClass=document.hidden?" zammad-chat-message--unread":"",this.el.find(".zammad-chat-body").append(this.view("message")(t)),this.scrollToBottom()},n.prototype.open=function(){return this.log.debug("open widget"),this.isOpen&&this.show(),this.sessionId||this.showLoader(),this.el.addClass("zammad-chat-is-open"),this.sessionId?(this.el.css("bottom",0),this.onOpenAnimationEnd()):this.el.animate({bottom:0},500,this.onOpenAnimationEnd),this.isOpen=!0,this.sessionId?void 0:this.send("chat_session_init")},n.prototype.onOpenAnimationEnd=function(){return this.idleTimeout.stop()},n.prototype.close=function(t){return this.log.debug("close widget"),"off"===this.state||"unsupported"===this.state?this.state:(t&&t.stopPropagation(),this.sessionId?(this.send("chat_session_close",{session_id:this.sessionId}),this.inactiveTimeout.stop(),this.waitingListTimeout.stop(),sessionStorage.removeItem("unfinished_message"),this.onInitialQueueDelayId&&clearTimeout(this.onInitialQueueDelayId),t&&this.closeWindow(),this.setSessionId(void 0)):void 0)},n.prototype.closeWindow=function(){var t;return this.el.removeClass("zammad-chat-is-open"),t=this.el.height()-this.el.find(".zammad-chat-header").outerHeight(),this.el.animate({bottom:-t},500,this.onCloseAnimationEnd)},n.prototype.onCloseAnimationEnd=function(){return this.el.removeClass("zammad-chat-is-visible"),this.showLoader(),this.el.find(".zammad-chat-welcome").removeClass("zammad-chat-is-hidden"),this.el.find(".zammad-chat-agent").addClass("zammad-chat-is-hidden"),this.el.find(".zammad-chat-agent-status").addClass("zammad-chat-is-hidden"),this.isOpen=!1,this.io.reconnect()},n.prototype.hide=function(){return this.el?this.el.removeClass("zammad-chat-is-shown"):void 0},n.prototype.show=function(){var t;return"off"===this.state||"unsupported"===this.state?this.state:(this.el.addClass("zammad-chat-is-shown"),this.inputInitialized||(this.inputInitialized=!0,this.input.autoGrow({extraLine:!1})),t=this.el.height()-this.el.find(".zammad-chat-header").outerHeight(),this.el.css("bottom",-t))},n.prototype.disableInput=function(){return this.input.prop("disabled",!0),this.el.find(".zammad-chat-send").prop("disabled",!0)},n.prototype.enableInput=function(){return this.input.prop("disabled",!1),this.el.find(".zammad-chat-send").prop("disabled",!1)},n.prototype.onQueueScreen=function(t){var e;return this.setSessionId(t.session_id),e=function(e){return function(){return e.onQueue(t),e.waitingListTimeout.start()}}(this),this.initialQueueDelay&&!this.onInitialQueueDelayId?void(this.onInitialQueueDelayId=setTimeout(e,this.initialQueueDelay)):(this.onInitialQueueDelayId&&clearTimeout(this.onInitialQueueDelayId),e())},n.prototype.onQueue=function(t){return this.log.notice("onQueue",t.position),this.inQueue=!0,this.el.find(".zammad-chat-body").html(this.view("waiting")({position:t.position}))},n.prototype.onAgentTypingStart=function(){return this.stopTypingId&&clearTimeout(this.stopTypingId),this.stopTypingId=setTimeout(this.onAgentTypingEnd,3e3),this.el.find(".zammad-chat-message--typing").size()?void 0:(this.maybeAddTimestamp(),this.el.find(".zammad-chat-body").append(this.view("typingIndicator")()),this.scrollToBottom())},n.prototype.onAgentTypingEnd=function(){return this.el.find(".zammad-chat-message--typing").remove()},n.prototype.onLeaveTemporary=function(){return this.sessionId?this.send("chat_session_leave_temporary",{session_id:this.sessionId}):void 0},n.prototype.maybeAddTimestamp=function(){var t,e,s;return s=Date.now(),!this.lastTimestamp||s-this.lastTimestamp>6e4*this.showTimeEveryXMinutes?(t=this.T("Today"),e=(new Date).toTimeString().substr(0,5),"timestamp"===this.lastAddedType?(this.updateLastTimestamp(t,e),this.lastTimestamp=s):(this.el.find(".zammad-chat-body").append(this.view("timestamp")({label:t,time:e})),this.lastTimestamp=s,this.lastAddedType="timestamp",this.scrollToBottom())):void 0},n.prototype.updateLastTimestamp=function(t,e){return this.el.find(".zammad-chat-body").find(".zammad-chat-timestamp").last().replaceWith(this.view("timestamp")({label:t,time:e}))},n.prototype.addStatus=function(t){return this.maybeAddTimestamp(),this.el.find(".zammad-chat-body").append(this.view("status")({status:t})),this.scrollToBottom()},n.prototype.scrollToBottom=function(){return this.el.find(".zammad-chat-body").scrollTop(t(".zammad-chat-body").prop("scrollHeight"))},n.prototype.destroy=function(t){return null==t&&(t={}),this.log.debug("destroy widget"),t.hide&&this.el&&this.el.remove(),this.waitingListTimeout.stop(),this.inactiveTimeout.stop(),this.idleTimeout.stop(),this.wsReconnectStop(),this.io.close()},n.prototype.wsReconnectStart=function(){return this.wsReconnectStop(),this.reconnectDelayId&&clearTimeout(this.reconnectDelayId),this.reconnectDelayId=setTimeout(this.io.connect(),5e3)},n.prototype.wsReconnectStop=function(){return this.reconnectDelayId?clearTimeout(this.reconnectDelayId):void 0},n.prototype.reconnect=function(){return this.log.notice("reconnecting"),this.disableInput(),this.lastAddedType="status",this.setAgentOnlineState("connecting"),this.addStatus(this.T("Connection lost"))},n.prototype.onConnectionReestablished=function(){return this.lastAddedType="status",this.setAgentOnlineState("online"),this.addStatus(this.T("Connection re-established"))},n.prototype.onSessionClosed=function(t){return this.addStatus(this.T("Chat closed by %s",t.realname)),this.disableInput(),this.setAgentOnlineState("offline"),this.inactiveTimeout.stop()},n.prototype.setSessionId=function(t){return this.sessionId=t,void 0===t?sessionStorage.removeItem("sessionId"):sessionStorage.setItem("sessionId",t)},n.prototype.onConnectionEstablished=function(t){return this.onInitialQueueDelayId&&clearTimeout(this.onInitialQueueDelayId),this.inQueue=!1,t.agent&&(this.agent=t.agent),t.session_id&&this.setSessionId(t.session_id),this.el.find(".zammad-chat-agent").html(this.view("agent")({agent:this.agent})),this.enableInput(),this.el.find(".zammad-chat-body").empty(),this.el.find(".zammad-chat-welcome").addClass("zammad-chat-is-hidden"),this.el.find(".zammad-chat-agent").removeClass("zammad-chat-is-hidden"),this.el.find(".zammad-chat-agent-status").removeClass("zammad-chat-is-hidden"),this.input.focus(),this.setAgentOnlineState("online"),this.waitingListTimeout.stop(),this.idleTimeout.stop(),this.inactiveTimeout.start()},n.prototype.showCustomerTimeout=function(){var t;return this.el.find(".zammad-chat-body").html(this.view("customer_timeout")({agent:this.agent.name,delay:this.options.inactiveTimeout})),this.close(),t=function(){return location.reload()},this.el.find(".js-restart").click(t)},n.prototype.showWaitingListTimeout=function(){var t;return this.el.find(".zammad-chat-body").html(this.view("waiting_list_timeout")({delay:this.options.watingListTimeout})),this.close(),t=function(){return location.reload()},this.el.find(".js-restart").click(t)},n.prototype.showLoader=function(){return this.el.find(".zammad-chat-body").html(this.view("loader")())},n.prototype.setAgentOnlineState=function(t){var e;return this.state=t,e=t.charAt(0).toUpperCase()+t.slice(1),this.el.find(".zammad-chat-agent-status").attr("data-status",t).text(this.T(e))},n.prototype.detectHost=function(){var t;return t="ws://","https:"===e.location.protocol&&(t="wss://"),this.options.host=""+t+h+"/ws"},n.prototype.loadCss=function(){var t,e,s;if(this.options.cssAutoload)return s=this.options.cssUrl,s||(s=this.options.host.replace(/^wss/i,"https").replace(/^ws/i,"http").replace(/\/ws/i,""),s+="/assets/chat/chat.css"),this.log.debug("load css from '"+s+"'"),e="@import url('"+s+"');",t=document.createElement("link"),t.rel="stylesheet",t.href="data:text/css,"+escape(e),document.getElementsByTagName("head")[0].appendChild(t)},n.prototype.startTimeoutObservers=function(){return this.idleTimeout=new o({logPrefix:"idleTimeout",debug:this.options.debug,timeout:this.options.idleTimeout,timeoutIntervallCheck:this.options.idleTimeoutIntervallCheck,callback:function(t){return function(){return t.log.debug("Idle timeout reached, hide widget",new Date),t.state="off",t.destroy({hide:!0})}}(this)}),this.inactiveTimeout=new o({logPrefix:"inactiveTimeout",debug:this.options.debug,timeout:this.options.inactiveTimeout,timeoutIntervallCheck:this.options.inactiveTimeoutIntervallCheck,callback:function(t){return function(){return t.log.debug("Inactive timeout reached, show timeout screen.",new Date),t.state="off",t.setAgentOnlineState("offline"),t.showCustomerTimeout(),t.destroy({hide:!1})}}(this)}),this.waitingListTimeout=new o({logPrefix:"waitingListTimeout",debug:this.options.debug,timeout:this.options.waitingListTimeout,timeoutIntervallCheck:this.options.waitingListTimeoutIntervallCheck,callback:function(t){return function(){return t.log.debug("Waiting list timeout reached, show timeout screen.",new Date),t.state="off",t.setAgentOnlineState("offline"),t.showWaitingListTimeout(),t.destroy({hide:!1})}}(this)})},n}(s),e.ZammadChat=a}(window.jQuery,window),window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.agent=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){this.agent.avatar&&(s.push('\n\n')),s.push('\n\n '),s.push(i(this.agent.name)),s.push("\n")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")},jQuery.fn.autoGrow=function(t){return this.each(function(){var e=jQuery.extend({extraLine:!0},t),s=function(t){return jQuery(t).after('
'),jQuery(t).next(".autogrow-textarea-mirror")[0]},i=function(t){if(o.innerHTML=String(t.value).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">").replace(/ /g," ").replace(/\n/g,"
")+(e.extraLine?".
.":""),jQuery(t).height()!=jQuery(o).height()){jQuery(t).height(jQuery(o).height());var s=parseInt(jQuery(t).css("max-height"),10),i=jQuery(o).height()>s?"":"hidden";jQuery(t).css("overflow",i)}},n=function(){i(this)},o=s(this);o.style.display="none",o.style.wordWrap="break-word",o.style.whiteSpace="normal",o.style.padding=jQuery(this).css("paddingTop")+" "+jQuery(this).css("paddingRight")+" "+jQuery(this).css("paddingBottom")+" "+jQuery(this).css("paddingLeft"),o.style.width=jQuery(this).css("width"),o.style.fontFamily=jQuery(this).css("font-family"),o.style.fontSize=jQuery(this).css("font-size"),o.style.lineHeight=jQuery(this).css("line-height"),this.style.overflow="hidden",this.style.minHeight=this.rows+"em",this.onkeyup=n,i(this)})},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.chat=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n
\n
\n \n \n \n \n \n
\n
\n
\n
\n \n '),s.push(this.T(this.title)),s.push('\n
\n
\n
\n
\n \n \n
\n
")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.customer_timeout=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n
\n '),this.agent?(s.push("\n "),s.push(this.T("Since you didn't respond in the last %s minutes your conversation with %s got closed.",this.delay,this.agent)),s.push("\n ")):(s.push("\n "),s.push(this.T("Since you didn't respond in the last %s minutes your conversation got closed.",this.delay)),s.push("\n ")),s.push('\n
\n
"),s.push(this.T("Start new conversation")),s.push("
\n
\n
")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.loader=function(t){t||(t={});var e,s=[],i=t.safe,n=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},n||(n=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n \n \n \n \n \n '),s.push(this.T("Connecting")),s.push("\n
")}).call(this)}.call(t),t.safe=i,t.escape=n,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.message=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n "),s.push(this.message),s.push("\n
")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.status=function(t){t||(t={});var e,s=[],i=t.safe,n=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},n||(n=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
'),s.push(this.status),s.push("
")}).call(this)}.call(t),t.safe=i,t.escape=n,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.timestamp=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
'),s.push(i(this.label)),s.push(" "),s.push(i(this.time)),s.push("
")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.typingIndicator=function(t){t||(t={});var e,s=[],i=t.safe,n=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},n||(n=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n \n \n \n \n \n \n \n
')}).call(this)}.call(t),t.safe=i,t.escape=n,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.waiting=function(t){t||(t={});var e,s=[],i=t.safe,n=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},n||(n=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n
\n \n \n \n \n \n '), -s.push(this.T("All colleges are busy.")),s.push("
\n "),s.push(this.T("You are on waiting list position %s.",this.position)),s.push("\n
\n
")}).call(this)}.call(t),t.safe=i,t.escape=n,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.waiting_list_timeout=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n
\n '),s.push(this.T("We are sorry, it takes longer as expected to get an empty slot. Please try again later or send us an email. Thank you!")),s.push('\n
\n
"),s.push(this.T("Start new conversation")),s.push("
\n
\n
")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")}; \ No newline at end of file +var bind=function(t,e){return function(){return t.apply(e,arguments)}},slice=[].slice,extend=function(t,e){function s(){this.constructor=t}for(var i in e)hasProp.call(e,i)&&(t[i]=e[i]);return s.prototype=e.prototype,t.prototype=new s,t.__super__=e.prototype,t},hasProp={}.hasOwnProperty;!function(t,e){var s,i,n,o,a,r,h,d;return d=document.getElementsByTagName("script"),r=d[d.length-1],h=r.src.match(".*://([^:/]*).*")[1],s=function(){function e(e){this.options=t.extend({},this.defaults,e),this.log=new n({debug:this.options.debug,logPrefix:this.options.logPrefix||this.logPrefix})}return e.prototype.defaults={debug:!1},e}(),n=function(){function e(e){this.log=bind(this.log,this),this.error=bind(this.error,this),this.notice=bind(this.notice,this),this.debug=bind(this.debug,this),this.options=t.extend({},this.defaults,e)}return e.prototype.defaults={debug:!1},e.prototype.debug=function(){var t;return t=1<=arguments.length?slice.call(arguments,0):[],this.options.debug?this.log("debug",t):void 0},e.prototype.notice=function(){var t;return t=1<=arguments.length?slice.call(arguments,0):[],this.log("notice",t)},e.prototype.error=function(){var t;return t=1<=arguments.length?slice.call(arguments,0):[],this.log("error",t)},e.prototype.log=function(e,s){var i,n,o,a;if(s.unshift("||"),s.unshift(e),s.unshift(this.options.logPrefix),console.log.apply(console,s),this.options.debug){for(a="",i=0,o=s.length;o>i;i++)n=s[i],a+=" ",a+="object"==typeof n?JSON.stringify(n):n&&n.toString?n.toString():n;return t(".js-chatLogDisplay").prepend("
"+a+"
")}},e}(),o=function(t){function e(t){this.stop=bind(this.stop,this),this.start=bind(this.start,this),e.__super__.constructor.call(this,t)}return extend(e,t),e.prototype.timeoutStartedAt=null,e.prototype.logPrefix="timeout",e.prototype.defaults={debug:!1,timeout:4,timeoutIntervallCheck:.5},e.prototype.start=function(){var t,e;return this.stop(),e=new Date,t=function(t){return function(){var s;return s=new Date-new Date(e.getTime()+1e3*t.options.timeout*60),t.log.debug("Timeout check for "+t.options.timeout+" minutes (left "+s/1e3+" sec.)"),0>s?void 0:(t.stop(),t.options.callback())}}(this),this.log.debug("Start timeout in "+this.options.timeout+" minutes"),this.intervallId=setInterval(t,1e3*this.options.timeoutIntervallCheck*60)},e.prototype.stop=function(){return this.intervallId?(this.log.debug("Stop timeout of "+this.options.timeout+" minutes"),clearInterval(this.intervallId)):void 0},e}(s),i=function(t){function s(t){this.send=bind(this.send,this),this.reconnect=bind(this.reconnect,this),this.close=bind(this.close,this),this.connect=bind(this.connect,this),this.set=bind(this.set,this),s.__super__.constructor.call(this,t)}return extend(s,t),s.prototype.logPrefix="io",s.prototype.set=function(t){var e,s,i;s=[];for(e in t)i=t[e],s.push(this.options[e]=i);return s},s.prototype.connect=function(){return this.log.debug("Connecting to "+this.options.host),this.ws=new e.WebSocket(""+this.options.host),this.ws.onopen=function(t){return function(e){return t.log.debug("onOpen",e),t.options.onOpen(e)}}(this),this.ws.onmessage=function(t){return function(e){var s;return s=JSON.parse(e.data),t.log.debug("onMessage",e.data),t.options.onMessage?t.options.onMessage(s):void 0}}(this),this.ws.onclose=function(t){return function(e){if(t.log.debug("close websocket connection",e),t.manualClose){if(t.log.debug("manual close, onClose callback"),t.manualClose=!1,t.options.onClose)return t.options.onClose(e)}else if(t.log.debug("error close, onError callback"),t.options.onError)return t.options.onError("Connection lost...")}}(this),this.ws.onerror=function(t){return function(e){return t.log.debug("onError",e),t.options.onError?t.options.onError(e):void 0}}(this)},s.prototype.close=function(){return this.log.debug("close websocket manually"),this.manualClose=!0,this.ws.close()},s.prototype.reconnect=function(){return this.log.debug("reconnect"),this.close(),this.connect()},s.prototype.send=function(t,e){var s;return null==e&&(e={}),this.log.debug("send",t,e),s=JSON.stringify({event:t,data:e}),this.ws.send(s)},s}(s),a=function(s){function n(s){return this.startTimeoutObservers=bind(this.startTimeoutObservers,this),this.setAgentOnlineState=bind(this.setAgentOnlineState,this),this.onConnectionEstablished=bind(this.onConnectionEstablished,this),this.setSessionId=bind(this.setSessionId,this),this.onConnectionReestablished=bind(this.onConnectionReestablished,this),this.reconnect=bind(this.reconnect,this),this.destroy=bind(this.destroy,this),this.onLeaveTemporary=bind(this.onLeaveTemporary,this),this.onAgentTypingEnd=bind(this.onAgentTypingEnd,this),this.onAgentTypingStart=bind(this.onAgentTypingStart,this),this.onQueue=bind(this.onQueue,this),this.onQueueScreen=bind(this.onQueueScreen,this),this.onWebSocketClose=bind(this.onWebSocketClose,this),this.onCloseAnimationEnd=bind(this.onCloseAnimationEnd,this),this.close=bind(this.close,this),this.sessionClose=bind(this.sessionClose,this),this.onOpenAnimationEnd=bind(this.onOpenAnimationEnd,this),this.open=bind(this.open,this),this.renderMessage=bind(this.renderMessage,this),this.receiveMessage=bind(this.receiveMessage,this),this.onSubmit=bind(this.onSubmit,this),this.onInput=bind(this.onInput,this),this.onReopenSession=bind(this.onReopenSession,this),this.onError=bind(this.onError,this),this.onWebSocketMessage=bind(this.onWebSocketMessage,this),this.send=bind(this.send,this),this.checkForEnter=bind(this.checkForEnter,this),this.render=bind(this.render,this),this.view=bind(this.view,this),this.T=bind(this.T,this),this.options=t.extend({},this.defaults,s),n.__super__.constructor.call(this,this.options),t?e.WebSocket&&sessionStorage?this.options.chatId?(this.options.lang||(this.options.lang=t("html").attr("lang")),this.options.lang&&(this.options.lang=this.options.lang.replace(/-.+?$/,""),this.log.debug("lang: "+this.options.lang)),this.options.host||this.detectHost(),this.loadCss(),this.io=new i(this.options),this.io.set({onOpen:this.render,onClose:this.onWebSocketClose,onMessage:this.onWebSocketMessage,onError:this.onError}),void this.io.connect()):(this.state="unsupported",void this.log.error("Chat: need chatId as option!")):(this.state="unsupported",void this.log.notice("Chat: Browser not supported!")):(this.state="unsupported",void this.log.notice("Chat: no jquery found!"))}return extend(n,s),n.prototype.defaults={chatId:void 0,show:!0,target:t("body"),host:"",debug:!1,flat:!1,lang:void 0,cssAutoload:!0,cssUrl:void 0,fontSize:void 0,buttonClass:"open-zammad-chat",inactiveClass:"is-inactive",title:"Chat with us!",idleTimeout:6,idleTimeoutIntervallCheck:.5,inactiveTimeout:8,inactiveTimeoutIntervallCheck:.5,waitingListTimeout:4,waitingListTimeoutIntervallCheck:.5},n.prototype.logPrefix="chat",n.prototype._messageCount=0,n.prototype.isOpen=!1,n.prototype.blinkOnlineInterval=null,n.prototype.stopBlinOnlineStateTimeout=null,n.prototype.showTimeEveryXMinutes=1,n.prototype.lastTimestamp=null,n.prototype.lastAddedType=null,n.prototype.inputTimeout=null,n.prototype.isTyping=!1,n.prototype.state="offline",n.prototype.initialQueueDelay=1e4,n.prototype.translations={de:{"Chat with us!":"Chat mit uns!",Online:"Online",Online:"Online",Offline:"Offline",Connecting:"Verbinden","Connection re-established":"Verbindung wiederhergestellt",Today:"Heute",Send:"Senden","Compose your message...":"Ihre Nachricht...","All colleges are busy.":"Alle Kollegen sind belegt.","You are on waiting list position %s.":"Sie sind in der Warteliste an der Position %s.","Start new conversation":"Neue Konversation starten","Since you didn't respond in the last %s minutes your conversation with %s got closed.":"Da Sie in den letzten %s Minuten nichts geschrieben haben wurde Ihre Konversation mit %s geschlossen.","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."}},n.prototype.sessionId=void 0,n.prototype.T=function(){var t,e,s,i,n,o;if(n=arguments[0],s=2<=arguments.length?slice.call(arguments,1):[],this.options.lang&&"en"!==this.options.lang&&(this.translations[this.options.lang]?(o=this.translations[this.options.lang],o[n]||this.log.notice("Translation needed for '"+n+"'"),n=o[n]||n):this.log.notice("Translation '"+this.options.lang+"' needed!")),s)for(t=0,i=s.length;i>t;t++)e=s[t],n=n.replace(/%s/,e);return n},n.prototype.view=function(t){return function(s){return function(i){return i||(i={}),i.T=s.T,i.background=s.options.background,i.flat=s.options.flat,i.fontSize=s.options.fontSize,e.zammadChatTemplates[t](i)}}(this)},n.prototype.render=function(){return this.el&&t(".zammad-chat").get(0)||(this.el=t(this.view("chat")({title:this.options.title})),this.options.target.append(this.el),this.input=this.el.find(".zammad-chat-input"),this.el.find(".js-chat-open").click(this.open),this.el.find(".js-chat-close").click(this.close),this.el.find(".zammad-chat-controls").on("submit",this.onSubmit),this.input.on({keydown:this.checkForEnter,input:this.onInput}),t(e).on("beforeunload",function(t){return function(){return t.onLeaveTemporary()}}(this)),t(e).bind("hashchange",function(t){return function(){return t.isOpen?void 0:t.idleTimeout.start()}}(this))),t("."+this.options.buttonClass).addClass(this.inactiveClass),this.setAgentOnlineState("online"),this.log.debug("widget rendered"),this.startTimeoutObservers(),this.idleTimeout.start(),this.sessionId=sessionStorage.getItem("sessionId"),this.send("chat_status_customer",{session_id:this.sessionId})},n.prototype.checkForEnter=function(t){return t.shiftKey||13!==t.keyCode?void 0:(t.preventDefault(),this.sendMessage())},n.prototype.send=function(t,e){return null==e&&(e={}),e.chat_id=this.options.chatId,this.io.send(t,e)},n.prototype.onWebSocketMessage=function(t){var e,s,i;for(e=0,s=t.length;s>e;e++)switch(i=t[e],this.log.debug("ws:onmessage",i),i.event){case"chat_error":this.log.notice(i.data),i.data&&"chat_disabled"===i.data.state&&this.destroy({remove:!0});break;case"chat_session_message":if(i.data.self_written)return;this.receiveMessage(i.data);break;case"chat_session_typing":if(i.data.self_written)return;this.onAgentTypingStart();break;case"chat_session_start":this.onConnectionEstablished(i.data);break;case"chat_session_queue":this.onQueueScreen(i.data);break;case"chat_session_closed":this.onSessionClosed(i.data);break;case"chat_session_left":this.onSessionClosed(i.data);break;case"chat_status_customer":switch(i.data.state){case"online":this.sessionId=void 0,this.onReady();break;case"offline":this.onError("Zammad Chat: No agent online");break;case"chat_disabled":this.onError("Zammad Chat: Chat is disabled");break;case"no_seats_available":this.onError("Zammad Chat: Too many clients in queue. Clients in queue: "+i.data.queue);break;case"reconnect":this.onReopenSession(i.data)}}},n.prototype.onReady=function(){return this.log.debug("widget ready for use"),t("."+this.options.buttonClass).click(this.open).removeClass(this.inactiveClass),this.options.show?this.show():void 0},n.prototype.onError=function(e){return this.log.debug(e),this.addStatus(e),t("."+this.options.buttonClass).hide(),this.isOpen?(this.disableInput(),this.destroy({remove:!1})):this.destroy({remove:!0})},n.prototype.onReopenSession=function(t){var e,s,i,n,o;if(this.log.debug("old messages",t.session),this.inactiveTimeout.start(),o=sessionStorage.getItem("unfinished_message"),t.agent){for(this.onConnectionEstablished(t),n=t.session,e=0,s=n.length;s>e;e++)i=n[e],this.renderMessage({message:i.content,id:i.id,from:i.created_by_id?"agent":"customer"});o&&this.input.val(o)}return t.position&&this.onQueue(t),this.show(),this.open(),this.scrollToBottom(),o?this.input.focus():void 0},n.prototype.onInput=function(){return this.el.find(".zammad-chat-message--unread").removeClass("zammad-chat-message--unread"),sessionStorage.setItem("unfinished_message",this.input.val()),this.onTyping()},n.prototype.onTyping=function(){return this.isTyping&&this.isTyping>new Date((new Date).getTime()-1500)?void 0:(this.isTyping=new Date,this.send("chat_session_typing",{session_id:this.sessionId}),this.inactiveTimeout.start())},n.prototype.onSubmit=function(t){return t.preventDefault(),this.sendMessage()},n.prototype.sendMessage=function(){var t,e;return(t=this.input.val())?(this.inactiveTimeout.start(),sessionStorage.removeItem("unfinished_message"),e=this.view("message")({message:t,from:"customer",id:this._messageCount++,unreadClass:""}),this.maybeAddTimestamp(),this.el.find(".zammad-chat-message--typing").size()?(this.lastAddedType="typing-placeholder",this.el.find(".zammad-chat-message--typing").before(e)):(this.lastAddedType="message--customer",this.el.find(".zammad-chat-body").append(e)),this.input.val(""),this.scrollToBottom(),this.send("chat_session_message",{content:t,id:this._messageCount,session_id:this.sessionId})):void 0},n.prototype.receiveMessage=function(t){return this.inactiveTimeout.start(),this.onAgentTypingEnd(),this.maybeAddTimestamp(),this.renderMessage({message:t.message.content,id:t.id,from:"agent"})},n.prototype.renderMessage=function(t){return this.lastAddedType="message--"+t.from,t.unreadClass=document.hidden?" zammad-chat-message--unread":"",this.el.find(".zammad-chat-body").append(this.view("message")(t)),this.scrollToBottom()},n.prototype.open=function(){return this.isOpen?void this.log.debug("widget already open, block"):(this.isOpen=!0,this.log.debug("open widget"),this.sessionId||this.showLoader(),this.el.addClass("zammad-chat-is-open"),this.sessionId?(this.el.css("bottom",0),this.onOpenAnimationEnd()):(this.el.animate({bottom:0},500,this.onOpenAnimationEnd),this.send("chat_session_init")))},n.prototype.onOpenAnimationEnd=function(){return this.idleTimeout.stop()},n.prototype.sessionClose=function(){return this.send("chat_session_close",{session_id:this.sessionId}),this.inactiveTimeout.stop(),this.waitingListTimeout.stop(),sessionStorage.removeItem("unfinished_message"),this.onInitialQueueDelayId&&clearTimeout(this.onInitialQueueDelayId),this.setSessionId(void 0)},n.prototype.close=function(t){var e;return this.isOpen?this.sessionId?(this.log.debug("close widget"),t&&t.stopPropagation(),this.sessionClose(),this.el.removeClass("zammad-chat-is-open"),e=this.el.height()-this.el.find(".zammad-chat-header").outerHeight(),this.el.animate({bottom:-e},500,this.onCloseAnimationEnd)):void this.log.debug("can't close widget without sessionId"):void this.log.debug("can't close widget, it's not open")},n.prototype.onCloseAnimationEnd=function(){return this.el.removeClass("zammad-chat-is-visible"),this.showLoader(),this.el.find(".zammad-chat-welcome").removeClass("zammad-chat-is-hidden"),this.el.find(".zammad-chat-agent").addClass("zammad-chat-is-hidden"),this.el.find(".zammad-chat-agent-status").addClass("zammad-chat-is-hidden"),this.isOpen=!1,this.io.reconnect()},n.prototype.onWebSocketClose=function(){return this.isOpen?void 0:this.el?this.el.removeClass("zammad-chat-is-shown"):void 0},n.prototype.show=function(){var t;if("offline"!==this.state)return this.el.addClass("zammad-chat-is-shown"),this.inputInitialized||(this.inputInitialized=!0,this.input.autoGrow({extraLine:!1})),t=this.el.height()-this.el.find(".zammad-chat-header").outerHeight(),this.el.css("bottom",-t)},n.prototype.disableInput=function(){return this.input.prop("disabled",!0),this.el.find(".zammad-chat-send").prop("disabled",!0)},n.prototype.enableInput=function(){return this.input.prop("disabled",!1),this.el.find(".zammad-chat-send").prop("disabled",!1)},n.prototype.onQueueScreen=function(t){var e;return this.setSessionId(t.session_id),e=function(e){return function(){return e.onQueue(t),e.waitingListTimeout.start()}}(this),this.initialQueueDelay&&!this.onInitialQueueDelayId?void(this.onInitialQueueDelayId=setTimeout(e,this.initialQueueDelay)):(this.onInitialQueueDelayId&&clearTimeout(this.onInitialQueueDelayId),e())},n.prototype.onQueue=function(t){return this.log.notice("onQueue",t.position),this.inQueue=!0,this.el.find(".zammad-chat-body").html(this.view("waiting")({position:t.position}))},n.prototype.onAgentTypingStart=function(){return this.stopTypingId&&clearTimeout(this.stopTypingId),this.stopTypingId=setTimeout(this.onAgentTypingEnd,3e3),this.el.find(".zammad-chat-message--typing").size()?void 0:(this.maybeAddTimestamp(),this.el.find(".zammad-chat-body").append(this.view("typingIndicator")()),this.scrollToBottom())},n.prototype.onAgentTypingEnd=function(){return this.el.find(".zammad-chat-message--typing").remove()},n.prototype.onLeaveTemporary=function(){return this.sessionId?this.send("chat_session_leave_temporary",{session_id:this.sessionId}):void 0},n.prototype.maybeAddTimestamp=function(){var t,e,s;return s=Date.now(),!this.lastTimestamp||s-this.lastTimestamp>6e4*this.showTimeEveryXMinutes?(t=this.T("Today"),e=(new Date).toTimeString().substr(0,5),"timestamp"===this.lastAddedType?(this.updateLastTimestamp(t,e),this.lastTimestamp=s):(this.el.find(".zammad-chat-body").append(this.view("timestamp")({label:t,time:e})),this.lastTimestamp=s,this.lastAddedType="timestamp",this.scrollToBottom())):void 0},n.prototype.updateLastTimestamp=function(t,e){return this.el?this.el.find(".zammad-chat-body").find(".zammad-chat-timestamp").last().replaceWith(this.view("timestamp")({label:t,time:e})):void 0},n.prototype.addStatus=function(t){return this.el?(this.maybeAddTimestamp(),this.el.find(".zammad-chat-body").append(this.view("status")({status:t})),this.scrollToBottom()):void 0},n.prototype.scrollToBottom=function(){return this.el.find(".zammad-chat-body").scrollTop(t(".zammad-chat-body").prop("scrollHeight"))},n.prototype.destroy=function(t){return null==t&&(t={}),this.log.debug("destroy widget",t),this.setAgentOnlineState("offline"),t.remove&&this.el&&this.el.remove(),this.waitingListTimeout&&this.waitingListTimeout.stop(),this.inactiveTimeout&&this.inactiveTimeout.stop(),this.idleTimeout&&this.idleTimeout.stop(),this.io.close()},n.prototype.reconnect=function(){return this.log.notice("reconnecting"),this.disableInput(),this.lastAddedType="status",this.setAgentOnlineState("connecting"),this.addStatus(this.T("Connection lost"))},n.prototype.onConnectionReestablished=function(){return this.lastAddedType="status",this.setAgentOnlineState("online"),this.addStatus(this.T("Connection re-established"))},n.prototype.onSessionClosed=function(t){return this.addStatus(this.T("Chat closed by %s",t.realname)),this.disableInput(),this.setAgentOnlineState("offline"),this.inactiveTimeout.stop()},n.prototype.setSessionId=function(t){return this.sessionId=t,void 0===t?sessionStorage.removeItem("sessionId"):sessionStorage.setItem("sessionId",t)},n.prototype.onConnectionEstablished=function(t){return this.onInitialQueueDelayId&&clearTimeout(this.onInitialQueueDelayId),this.inQueue=!1,t.agent&&(this.agent=t.agent),t.session_id&&this.setSessionId(t.session_id),this.el.find(".zammad-chat-agent").html(this.view("agent")({agent:this.agent})),this.enableInput(),this.el.find(".zammad-chat-body").empty(),this.el.find(".zammad-chat-welcome").addClass("zammad-chat-is-hidden"),this.el.find(".zammad-chat-agent").removeClass("zammad-chat-is-hidden"),this.el.find(".zammad-chat-agent-status").removeClass("zammad-chat-is-hidden"),this.input.focus(),this.setAgentOnlineState("online"),this.waitingListTimeout.stop(),this.idleTimeout.stop(),this.inactiveTimeout.start()},n.prototype.showCustomerTimeout=function(){var t;return this.el.find(".zammad-chat-body").html(this.view("customer_timeout")({agent:this.agent.name,delay:this.options.inactiveTimeout})),t=function(){return location.reload()},this.el.find(".js-restart").click(t),this.sessionClose()},n.prototype.showWaitingListTimeout=function(){var t;return this.el.find(".zammad-chat-body").html(this.view("waiting_list_timeout")({delay:this.options.watingListTimeout})),t=function(){return location.reload()},this.el.find(".js-restart").click(t),this.sessionClose()},n.prototype.showLoader=function(){return this.el.find(".zammad-chat-body").html(this.view("loader")())},n.prototype.setAgentOnlineState=function(t){var e;return this.state=t,this.el?(e=t.charAt(0).toUpperCase()+t.slice(1),this.el.find(".zammad-chat-agent-status").attr("data-status",t).text(this.T(e))):void 0},n.prototype.detectHost=function(){var t;return t="ws://","https:"===e.location.protocol&&(t="wss://"),this.options.host=""+t+h+"/ws"},n.prototype.loadCss=function(){var t,e,s;if(this.options.cssAutoload)return s=this.options.cssUrl,s||(s=this.options.host.replace(/^wss/i,"https").replace(/^ws/i,"http").replace(/\/ws/i,""),s+="/assets/chat/chat.css"),this.log.debug("load css from '"+s+"'"),e="@import url('"+s+"');",t=document.createElement("link"),t.rel="stylesheet",t.href="data:text/css,"+escape(e),document.getElementsByTagName("head")[0].appendChild(t)},n.prototype.startTimeoutObservers=function(){return this.idleTimeout=new o({logPrefix:"idleTimeout",debug:this.options.debug,timeout:this.options.idleTimeout,timeoutIntervallCheck:this.options.idleTimeoutIntervallCheck,callback:function(t){return function(){return t.log.debug("Idle timeout reached, hide widget",new Date),t.destroy({remove:!0})}}(this)}),this.inactiveTimeout=new o({logPrefix:"inactiveTimeout",debug:this.options.debug,timeout:this.options.inactiveTimeout,timeoutIntervallCheck:this.options.inactiveTimeoutIntervallCheck,callback:function(t){return function(){return t.log.debug("Inactive timeout reached, show timeout screen.",new Date),t.showCustomerTimeout(),t.destroy({remove:!1})}}(this)}),this.waitingListTimeout=new o({logPrefix:"waitingListTimeout",debug:this.options.debug,timeout:this.options.waitingListTimeout,timeoutIntervallCheck:this.options.waitingListTimeoutIntervallCheck,callback:function(t){return function(){return t.log.debug("Waiting list timeout reached, show timeout screen.",new Date),t.showWaitingListTimeout(),t.destroy({remove:!1})}}(this)})},n}(s),e.ZammadChat=a}(window.jQuery,window),jQuery.fn.autoGrow=function(t){return this.each(function(){var e=jQuery.extend({extraLine:!0},t),s=function(t){return jQuery(t).after('
'),jQuery(t).next(".autogrow-textarea-mirror")[0]},i=function(t){if(o.innerHTML=String(t.value).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">").replace(/ /g," ").replace(/\n/g,"
")+(e.extraLine?".
.":""),jQuery(t).height()!=jQuery(o).height()){jQuery(t).height(jQuery(o).height());var s=parseInt(jQuery(t).css("max-height"),10),i=jQuery(o).height()>s?"":"hidden";jQuery(t).css("overflow",i)}},n=function(){i(this)},o=s(this);o.style.display="none",o.style.wordWrap="break-word",o.style.whiteSpace="normal",o.style.padding=jQuery(this).css("paddingTop")+" "+jQuery(this).css("paddingRight")+" "+jQuery(this).css("paddingBottom")+" "+jQuery(this).css("paddingLeft"),o.style.width=jQuery(this).css("width"),o.style.fontFamily=jQuery(this).css("font-family"),o.style.fontSize=jQuery(this).css("font-size"),o.style.lineHeight=jQuery(this).css("line-height"),this.style.overflow="hidden",this.style.minHeight=this.rows+"em",this.onkeyup=n,i(this)})},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.agent=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){this.agent.avatar&&(s.push('\n\n')),s.push('\n\n '),s.push(i(this.agent.name)),s.push("\n")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.chat=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n
\n
\n \n \n \n \n \n
\n
\n
\n
\n \n '),s.push(this.T(this.title)),s.push('\n
\n
\n
\n
\n \n \n
\n
")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.customer_timeout=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n
\n '),this.agent?(s.push("\n "),s.push(this.T("Since you didn't respond in the last %s minutes your conversation with %s got closed.",this.delay,this.agent)),s.push("\n ")):(s.push("\n "),s.push(this.T("Since you didn't respond in the last %s minutes your conversation got closed.",this.delay)),s.push("\n ")),s.push('\n
\n
"),s.push(this.T("Start new conversation")),s.push("
\n
\n
")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.loader=function(t){t||(t={});var e,s=[],i=t.safe,n=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},n||(n=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n \n \n \n \n \n '),s.push(this.T("Connecting")),s.push("\n
")}).call(this)}.call(t),t.safe=i,t.escape=n,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.message=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n "),s.push(this.message),s.push("\n
")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.status=function(t){t||(t={});var e,s=[],i=t.safe,n=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},n||(n=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
'),s.push(this.status),s.push("
")}).call(this)}.call(t),t.safe=i,t.escape=n,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.timestamp=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
'),s.push(i(this.label)),s.push(" "),s.push(i(this.time)),s.push("
")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.typingIndicator=function(t){t||(t={});var e,s=[],i=t.safe,n=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},n||(n=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n \n \n \n \n \n \n \n
')}).call(this)}.call(t),t.safe=i,t.escape=n,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.waiting=function(t){t||(t={});var e,s=[],i=t.safe,n=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},n||(n=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,"""); +}),function(){(function(){s.push('
\n
\n \n \n \n \n \n '),s.push(this.T("All colleges are busy.")),s.push("
\n "),s.push(this.T("You are on waiting list position %s.",this.position)),s.push("\n
\n
")}).call(this)}.call(t),t.safe=i,t.escape=n,s.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.waiting_list_timeout=function(t){t||(t={});var e,s=[],i=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?o(t):""},n=t.safe,o=t.escape;return e=t.safe=function(t){if(t&&t.ecoSafe)return t;("undefined"==typeof t||null==t)&&(t="");var e=new String(t);return e.ecoSafe=!0,e},o||(o=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){s.push('
\n
\n '),s.push(this.T("We are sorry, it takes longer as expected to get an empty slot. Please try again later or send us an email. Thank you!")),s.push('\n
\n
"),s.push(this.T("Start new conversation")),s.push("
\n
\n
")}).call(this)}.call(t),t.safe=n,t.escape=o,s.join("")}; \ No newline at end of file diff --git a/public/assets/chat/chat.scss b/public/assets/chat/chat.scss index c6ed9c400..c40fa7739 100644 --- a/public/assets/chat/chat.scss +++ b/public/assets/chat/chat.scss @@ -11,6 +11,7 @@ will-change: bottom; display: none; flex-direction: column; + z-index: 999; &.is-fullscreen { right: 0; @@ -177,7 +178,7 @@ .zammad-chat-modal-text { font-size: 1.3em; line-height: 1.45; - + .zammad-chat-loading-animation { font-size: 0.7em; } @@ -198,7 +199,7 @@ overflow: auto; background: white; flex: 1; - + @media only screen and (max-width: 768px) { height: auto; flex: 1; @@ -351,6 +352,11 @@ float: right; } +.zammad-chat-button:disabled, +.zammad-chat-input:disabled { + opacity: 0.3; +} + .zammad-chat-is-hidden { display: none; } diff --git a/test/browser/chat_test.rb b/test/browser/chat_test.rb index c1ae8da29..bbcde82ff 100644 --- a/test/browser/chat_test.rb +++ b/test/browser/chat_test.rb @@ -387,6 +387,42 @@ class ChatTest < TestCase css: '.zammad-chat', 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 def test_basic_usecase3 @@ -579,7 +615,7 @@ class ChatTest < TestCase browser: customer, css: '.zammad-chat', value: '(takes longer|dauert länger)', - timeout: 90, + timeout: 120, ) # no customer action, show sorry screen @@ -625,6 +661,55 @@ class ChatTest < TestCase 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