From 1979376d215a08f44978148c6b48232ab50cbd14 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 11 Nov 2015 14:10:26 +0100 Subject: [PATCH] Fixed new message counter, fixed active/not active state of agent and refactoring of web socket event backends. --- .../javascripts/app/controllers/chat.coffee | 51 ++++++++++++++----- app/models/chat.rb | 22 +++++++- db/migrate/20151109000001_create_chat.rb | 7 --- lib/sessions/event.rb | 5 +- lib/sessions/event/chat_agent_state.rb | 20 ++------ lib/sessions/event/chat_base.rb | 25 +++++++++ lib/sessions/event/chat_session_close.rb | 18 ++----- lib/sessions/event/chat_session_init.rb | 24 +++------ lib/sessions/event/chat_session_message.rb | 29 +++-------- lib/sessions/event/chat_session_start.rb | 24 ++------- lib/sessions/event/chat_session_typing.rb | 27 +++------- lib/sessions/event/chat_status.rb | 31 ----------- lib/sessions/event/chat_status_agent.rb | 24 ++++----- lib/sessions/event/chat_status_customer.rb | 21 ++++++++ public/assets/chat/chat.coffee | 1 - public/assets/chat/chat.js | 19 +++---- public/assets/chat/chat.min.js | 2 +- 17 files changed, 163 insertions(+), 187 deletions(-) create mode 100644 lib/sessions/event/chat_base.rb delete mode 100644 lib/sessions/event/chat_status.rb create mode 100644 lib/sessions/event/chat_status_customer.rb diff --git a/app/assets/javascripts/app/controllers/chat.coffee b/app/assets/javascripts/app/controllers/chat.coffee index 9eb72f8ee..34cf3bd8c 100644 --- a/app/assets/javascripts/app/controllers/chat.coffee +++ b/app/assets/javascripts/app/controllers/chat.coffee @@ -32,6 +32,7 @@ class App.CustomerChat extends App.Controller (data) => @meta = data @updateMeta() + @interval(@pushState, 20000, 'pushState') ) App.Event.bind( 'chat_session_start' @@ -43,8 +44,6 @@ class App.CustomerChat extends App.Controller App.WebSocket.send(event:'chat_status_agent') - @interval(@pushState, 16000) - pushState: => App.WebSocket.send( event:'chat_agent_state' @@ -59,13 +58,23 @@ class App.CustomerChat extends App.Controller @navupdate '#customer_chat' counter: => - if @meta.waiting_chat_count - if @waitingChatCountLast isnt @meta.waiting_chat_count - @sounds.chat_new.play() - @waitingChatCountLast = @meta.waiting_chat_count + counter = 0 - return @messageCounter + @meta.waiting_chat_count - @messageCounter + # get count of controller messages + if @meta.waiting_chat_count + counter += @meta.waiting_chat_count + + # play on changes + if @lastWaitingChatCount isnt counter + @sounds.chat_new.play() + @lastWaitingChatCount = counter + + # collect chat window messages + for key, value of @chatWindows + if value + counter += value.unreadMessages() + + @messageCounter = counter switch: (state = undefined) => @@ -85,7 +94,7 @@ class App.CustomerChat extends App.Controller updateNavMenu: => delay = -> App.Event.trigger('menu:render') - @delay(delay, 200) + @delay(delay, 200, 'updateNavMenu') updateMeta: => if @meta.waiting_chat_count @@ -107,7 +116,8 @@ class App.CustomerChat extends App.Controller chat = new chatWindow name: "#{session.created_at}" session: session - callback: @removeChat + removeCallback: @removeChat + messageCallback: @updateNavMenu @on 'layout-has-changed', @propagateLayoutChange @@ -115,7 +125,6 @@ class App.CustomerChat extends App.Controller @chatWindows[session.session_id] = chat removeChat: (session_id) => - console.log('removeChat', session_id, @chatWindows[session_id]) delete @chatWindows[session_id] propagateLayoutChange: (event) => @@ -177,6 +186,7 @@ class chatWindow extends App.Controller @lastAddedType @isTyping = false @render() + @resetUnreadMessages() @on 'layout-change', @scrollToBottom @@ -231,8 +241,8 @@ class chatWindow extends App.Controller data: session_id: @session.session_id ) - if @callback - @callback(@session.session_id) + if @removeCallback + @removeCallback(@session.session_id) release: => @trigger 'closed' @@ -241,6 +251,7 @@ class chatWindow extends App.Controller clearUnread: => @$('.chat-message--new').removeClass('chat-message--new') @updateModified(false) + @resetUnreadMessages() onKeydown: (event) => TABKEY = 9; @@ -304,9 +315,23 @@ class chatWindow extends App.Controller @addMessage(message, 'customer', !isFocused) if !isFocused + @addUnreadMessages() @updateModified(true) @sounds.message.play() + unreadMessages: => + @unreadMessagesCounter + + addUnreadMessages: => + if @messageCallback + @messageCallback(@session.session_id) + @unreadMessagesCounter += 1 + + resetUnreadMessages: => + if @messageCallback + @messageCallback(@session.session_id) + @unreadMessagesCounter = 0 + addMessage: (message, sender, isNew) => @maybeAddTimestamp() diff --git a/app/models/chat.rb b/app/models/chat.rb index 8ec1536a9..afaca3180 100644 --- a/app/models/chat.rb +++ b/app/models/chat.rb @@ -24,7 +24,7 @@ class Chat < ApplicationModel def self.agent_state(user_id) return { state: 'chat_disabled' } if !Setting.get('chat') actice_sessions = [] - Chat::Session.where(state: 'running').order('created_at ASC').each {|session| + Chat::Session.where(state: 'running', user_id: user_id).order('created_at ASC').each {|session| session_attributes = session.attributes session_attributes['messages'] = [] Chat::Message.where(chat_session_id: session.id).each { |message| @@ -127,6 +127,26 @@ class Chat::Session < ApplicationModel def generate_session_id self.session_id = Digest::MD5.hexdigest(Time.zone.now.to_s + rand(99_999_999_999_999).to_s) end + + def add_recipient(client_id, store = false) + if !self.preferences[:participants] + self.preferences[:participants] = [] + end + return self.preferences[:participants] if self.preferences[:participants].include?(client_id) + self.preferences[:participants].push client_id + if store + self.save + end + self.preferences[:participants] + end + + def send_to_recipients(message, ignore_client_id) + self.preferences[:participants].each {|local_client_id| + next if local_client_id == ignore_client_id + Sessions.send(local_client_id, message) + } + true + end end class Chat::Message < ApplicationModel diff --git a/db/migrate/20151109000001_create_chat.rb b/db/migrate/20151109000001_create_chat.rb index d4658ceae..e4d3e6670 100644 --- a/db/migrate/20151109000001_create_chat.rb +++ b/db/migrate/20151109000001_create_chat.rb @@ -1,12 +1,5 @@ class CreateChat < ActiveRecord::Migration def up -=begin - ActiveRecord::Migration.drop_table :chats - ActiveRecord::Migration.drop_table :chat_topics - ActiveRecord::Migration.drop_table :chat_sessions - ActiveRecord::Migration.drop_table :chat_messages - ActiveRecord::Migration.drop_table :chat_agents -=end create_table :chats do |t| t.string :name, limit: 250, null: true t.integer :max_queue, null: false, default: 5 diff --git a/lib/sessions/event.rb b/lib/sessions/event.rb index 732e248e6..fcb06fffb 100644 --- a/lib/sessions/event.rb +++ b/lib/sessions/event.rb @@ -9,8 +9,11 @@ class Sessions::Event return { error: "No such event #{event}" } end + instance = backend.new(data, session, client_id) + result = instance.pre_check + return result if result ActiveRecord::Base.establish_connection - result = backend.run(data, session, client_id) + result = instance.run ActiveRecord::Base.remove_connection result end diff --git a/lib/sessions/event/chat_agent_state.rb b/lib/sessions/event/chat_agent_state.rb index f63900a90..a201b9c92 100644 --- a/lib/sessions/event/chat_agent_state.rb +++ b/lib/sessions/event/chat_agent_state.rb @@ -1,21 +1,11 @@ -class Sessions::Event::ChatAgentState +class Sessions::Event::ChatAgentState < Sessions::Event::ChatBase - def self.run(data, session, _client_id) - - # check if feature is enabled - if !Setting.get('chat') - return { - event: 'chat_agent_state', - data: { - state: 'chat_disabled', - }, - } - end + def run # only agents can do this chat_id = 1 chat = Chat.find_by(id: chat_id) - if !session['id'] + if !@session['id'] return { event: 'chat_agent_state', data: { @@ -25,13 +15,13 @@ class Sessions::Event::ChatAgentState } end - Chat::Agent.state(session['id'], data['data']['active']) + Chat::Agent.state(@session['id'], @data['data']['active']) { event: 'chat_agent_state', data: { state: 'ok', - active: data['data']['active'], + active: @data['data']['active'], }, } end diff --git a/lib/sessions/event/chat_base.rb b/lib/sessions/event/chat_base.rb new file mode 100644 index 000000000..6df4a7dcd --- /dev/null +++ b/lib/sessions/event/chat_base.rb @@ -0,0 +1,25 @@ +class Sessions::Event::ChatBase + + def initialize(data, session, client_id) + @data = data + @session = session + @client_id = client_id + + end + + def pre_check + + # check if feature is enabled + if !Setting.get('chat') + return { + event: 'chat_error', + data: { + state: 'chat_disabled', + }, + } + end + + false + end + +end diff --git a/lib/sessions/event/chat_session_close.rb b/lib/sessions/event/chat_session_close.rb index 6a5a0a535..99cafd22f 100644 --- a/lib/sessions/event/chat_session_close.rb +++ b/lib/sessions/event/chat_session_close.rb @@ -1,18 +1,8 @@ -class Sessions::Event::ChatSessionClose +class Sessions::Event::ChatSessionClose < Sessions::Event::ChatBase - def self.run(data, _session, _client_id) + def run - # check if feature is enabled - if !Setting.get('chat') - return { - event: 'chat_status_close', - data: { - state: 'chat_disabled', - }, - } - end - - if !data['data'] || !data['data']['session_id'] + if !@data['data'] || !@data['data']['session_id'] return { event: 'chat_status_close', data: { @@ -21,7 +11,7 @@ class Sessions::Event::ChatSessionClose } end - chat_session = Chat::Session.find_by(session_id: data['data']['session_id']) + chat_session = Chat::Session.find_by(session_id: @data['data']['session_id']) if !chat_session return { event: 'chat_status_close', diff --git a/lib/sessions/event/chat_session_init.rb b/lib/sessions/event/chat_session_init.rb index f2bd37068..298cbcd3d 100644 --- a/lib/sessions/event/chat_session_init.rb +++ b/lib/sessions/event/chat_session_init.rb @@ -1,16 +1,6 @@ -class Sessions::Event::ChatSessionInit +class Sessions::Event::ChatSessionInit < Sessions::Event::ChatBase - def self.run(data, _session, client_id) - - # check if feature is enabled - if !Setting.get('chat') - return { - event: 'chat_session_init', - data: { - state: 'chat_disabled', - }, - } - end + def run chat_id = 1 chat = Chat.find_by(id: chat_id) @@ -29,17 +19,17 @@ class Sessions::Event::ChatSessionInit name: '', state: 'waiting', preferences: { - participants: [client_id], + participants: [@client_id], }, ) - # send update to agents - User.where(active: true).each {|user| + # send broadcast to agents + Chat::Agent.where(active: true).each {|item| data = { event: 'chat_status_agent', - data: Chat.agent_state(user.id), + data: Chat.agent_state(item.updated_by_id), } - Sessions.send_to(user.id, data) + Sessions.send_to(item.updated_by_id, data) } # return new session diff --git a/lib/sessions/event/chat_session_message.rb b/lib/sessions/event/chat_session_message.rb index f410943cd..dc3071d1b 100644 --- a/lib/sessions/event/chat_session_message.rb +++ b/lib/sessions/event/chat_session_message.rb @@ -1,18 +1,8 @@ -class Sessions::Event::ChatSessionMessage +class Sessions::Event::ChatSessionMessage < Sessions::Event::ChatBase - def self.run(data, session, client_id) + def run - # check if feature is enabled - if !Setting.get('chat') - return { - event: 'chat_session_message', - data: { - state: 'chat_disabled', - }, - } - end - - if !data['data'] || !data['data']['session_id'] + if !@data['data'] || !@data['data']['session_id'] return { event: 'chat_session_message', data: { @@ -21,7 +11,7 @@ class Sessions::Event::ChatSessionMessage } end - chat_session = Chat::Session.find_by(session_id: data['data']['session_id']) + chat_session = Chat::Session.find_by(session_id: @data['data']['session_id']) if !chat_session return { event: 'chat_session_message', @@ -32,12 +22,12 @@ class Sessions::Event::ChatSessionMessage end user_id = nil - if session - user_id = session['id'] + if @session + user_id = @session['id'] end chat_message = Chat::Message.create( chat_session_id: chat_session.id, - content: data['data']['content'], + content: @data['data']['content'], created_by_id: user_id, ) message = { @@ -49,10 +39,7 @@ class Sessions::Event::ChatSessionMessage } # send to participents - chat_session.preferences[:participants].each {|local_client_id| - next if local_client_id == client_id - Sessions.send(local_client_id, message) - } + chat_session.send_to_recipients(message, @client_id) # send chat_session_init to agent { diff --git a/lib/sessions/event/chat_session_start.rb b/lib/sessions/event/chat_session_start.rb index c7880e259..c1b75e46e 100644 --- a/lib/sessions/event/chat_session_start.rb +++ b/lib/sessions/event/chat_session_start.rb @@ -1,16 +1,6 @@ -class Sessions::Event::ChatSessionStart +class Sessions::Event::ChatSessionStart < Sessions::Event::ChatBase - def self.run(data, session, client_id) - - # check if feature is enabled - if !Setting.get('chat') - return { - event: 'chat_session_start', - data: { - state: 'chat_disabled', - }, - } - end + def run # find first in waiting list chat_session = Chat::Session.where(state: 'waiting').order('created_at ASC').first @@ -23,9 +13,9 @@ class Sessions::Event::ChatSessionStart }, } end - chat_session.user_id = session['id'] + chat_session.user_id = @session['id'] chat_session.state = 'running' - chat_session.preferences[:participants].push client_id + chat_session.preferences[:participants] = chat_session.add_recipient(@client_id) chat_session.save # send chat_session_init to client @@ -42,11 +32,7 @@ class Sessions::Event::ChatSessionStart session_id: chat_session.session_id, }, } - - chat_session.preferences[:participants].each {|local_client_id| - next if local_client_id == client_id - Sessions.send(local_client_id, data) - } + chat_session.send_to_recipients(data, @client_id) # send chat_session_init to agent { diff --git a/lib/sessions/event/chat_session_typing.rb b/lib/sessions/event/chat_session_typing.rb index 660818c61..f8e72fa09 100644 --- a/lib/sessions/event/chat_session_typing.rb +++ b/lib/sessions/event/chat_session_typing.rb @@ -1,18 +1,8 @@ -class Sessions::Event::ChatSessionTyping +class Sessions::Event::ChatSessionTyping < Sessions::Event::ChatBase - def self.run(data, session, client_id) + def run - # check if feature is enabled - if !Setting.get('chat') - return { - event: 'chat_session_typing', - data: { - state: 'chat_disabled', - }, - } - end - - if !data['data'] || !data['data']['session_id'] + if !@data['data'] || !@data['data']['session_id'] return { event: 'chat_session_typing', data: { @@ -21,7 +11,7 @@ class Sessions::Event::ChatSessionTyping } end - chat_session = Chat::Session.find_by(session_id: data['data']['session_id']) + chat_session = Chat::Session.find_by(session_id: @data['data']['session_id']) if !chat_session return { event: 'chat_session_typing', @@ -32,8 +22,8 @@ class Sessions::Event::ChatSessionTyping end user_id = nil - if session - user_id = session['id'] + if @session + user_id = @session['id'] end message = { event: 'chat_session_typing', @@ -44,10 +34,7 @@ class Sessions::Event::ChatSessionTyping } # send to participents - chat_session.preferences[:participants].each {|local_client_id| - next if local_client_id == client_id - Sessions.send(local_client_id, message) - } + chat_session.send_to_recipients(message, @client_id) # send chat_session_init to agent { diff --git a/lib/sessions/event/chat_status.rb b/lib/sessions/event/chat_status.rb deleted file mode 100644 index 40576a53c..000000000 --- a/lib/sessions/event/chat_status.rb +++ /dev/null @@ -1,31 +0,0 @@ -class Sessions::Event::ChatStatus - - def self.run(_data, _session, _client_id) - - # check if feature is enabled - if !Setting.get('chat') - return { - event: 'chat_status', - data: { - state: 'chat_disabled', - }, - } - end - - chat_id = 1 - chat = Chat.find_by(id: chat_id) - if !chat - return { - event: 'chat_status', - data: { - state: 'no_such_chat', - }, - } - end - - { - event: 'chat_status', - data: chat.state, - } - end -end diff --git a/lib/sessions/event/chat_status_agent.rb b/lib/sessions/event/chat_status_agent.rb index 8890fddd7..884b47103 100644 --- a/lib/sessions/event/chat_status_agent.rb +++ b/lib/sessions/event/chat_status_agent.rb @@ -1,26 +1,22 @@ -class Sessions::Event::ChatStatusAgent +class Sessions::Event::ChatStatusAgent < Sessions::Event::ChatBase - def self.run(_data, session, _client_id) + def run # check if user has permissions - # check if feature is enabled - if !Setting.get('chat') - return { - event: 'chat_status_agent', - data: { - state: 'chat_disabled', - }, - } - end # renew timestamps - state = Chat::Agent.state(session['id']) - Chat::Agent.state(session['id'], state) + state = Chat::Agent.state(@session['id']) + Chat::Agent.state(@session['id'], state) + + # update recipients of existing sessions + Chat::Session.where(state: 'running', user_id: @session['id']).order('created_at ASC').each {|chat_session| + chat_session.add_recipient(@client_id, true) + } { event: 'chat_status_agent', - data: Chat.agent_state(session['id']), + data: Chat.agent_state(@session['id']), } end diff --git a/lib/sessions/event/chat_status_customer.rb b/lib/sessions/event/chat_status_customer.rb new file mode 100644 index 000000000..8dbfb54d1 --- /dev/null +++ b/lib/sessions/event/chat_status_customer.rb @@ -0,0 +1,21 @@ +class Sessions::Event::ChatStatusCustomer < Sessions::Event::ChatBase + + def run + + chat_id = 1 + chat = Chat.find_by(id: chat_id) + if !chat + return { + event: 'chat_status_customer', + data: { + state: 'no_such_chat', + }, + } + end + + { + event: 'chat_status_customer', + data: chat.state, + } + end +end diff --git a/public/assets/chat/chat.coffee b/public/assets/chat/chat.coffee index e61cd36fd..0beb91613 100644 --- a/public/assets/chat/chat.coffee +++ b/public/assets/chat/chat.coffee @@ -64,7 +64,6 @@ do($ = window.jQuery, window) -> console.log('ws connected') @send 'chat_status_customer' - @ws.onmessage = @onWebSocketMessage @ws.onclose = (e) => diff --git a/public/assets/chat/chat.js b/public/assets/chat/chat.js index 443cee98b..282cad7e7 100644 --- a/public/assets/chat/chat.js +++ b/public/assets/chat/chat.js @@ -162,7 +162,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); this.ws.onopen = (function(_this) { return function() { console.log('ws connected'); - return _this.send('chat_status'); + return _this.send('chat_status_customer'); }; })(this); this.ws.onmessage = this.onWebSocketMessage; @@ -196,7 +196,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; ZammadChat.prototype.onWebSocketMessage = function(e) { - var delay, i, len, pipe, pipes; + var i, len, pipe, pipes; pipes = JSON.parse(e.data); console.log('debug', 'ws:onmessage', pipes); for (i = 0, len = pipes.length; i < len; i++) { @@ -213,15 +213,6 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); return; } this.onAgentTypingStart(); - if (this.stopTypingId) { - clearTimeout(this.stopTypingId); - } - delay = (function(_this) { - return function() { - return _this.onAgentTypingEnd(); - }; - })(this); - this.stopTypingId = setTimeout(delay, 3000); break; case 'chat_session_start': switch (pipe.data.state) { @@ -239,7 +230,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); this.session_id = pipe.data.session_id; } break; - case 'chat_status': + case 'chat_status_customer': switch (pipe.data.state) { case 'online': this.onReady(); @@ -393,6 +384,10 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; ZammadChat.prototype.onAgentTypingStart = function() { + if (this.stopTypingId) { + clearTimeout(this.stopTypingId); + } + this.stopTypingId = setTimeout(this.onAgentTypingEnd, 3000); if (this.el.find('.zammad-chat-message--typing').size()) { return; } diff --git a/public/assets/chat/chat.min.js b/public/assets/chat/chat.min.js index 38c5ed0ac..c67880a11 100644 --- a/public/assets/chat/chat.min.js +++ b/public/assets/chat/chat.min.js @@ -1 +1 @@ -window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.agent=function(t){t||(t={});var e,n=[],a=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},s=t.safe,i=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},i||(i=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){this.agent.avatar&&(n.push('\n\n')),n.push('\n\n '),n.push(a(this.agent.name)),n.push(" "),n.push(this.agentPhrase),n.push("\n")}).call(this)}.call(t),t.safe=s,t.escape=i,n.join("")};var bind=function(t,e){return function(){return t.apply(e,arguments)}};!function(t,e){var n;return n=function(){function n(n,a){this.setAgentOnlineState=bind(this.setAgentOnlineState,this),this.onConnectionEstablished=bind(this.onConnectionEstablished,this),this.onConnectionReestablished=bind(this.onConnectionReestablished,this),this.reconnect=bind(this.reconnect,this),this.onAgentTypingEnd=bind(this.onAgentTypingEnd,this),this.onAgentTypingStart=bind(this.onAgentTypingStart,this),this.onQueue=bind(this.onQueue,this),this.onCloseAnimationEnd=bind(this.onCloseAnimationEnd,this),this.onOpenAnimationEnd=bind(this.onOpenAnimationEnd,this),this.toggle=bind(this.toggle,this),this.receiveMessage=bind(this.receiveMessage,this),this.onSubmit=bind(this.onSubmit,this),this.onTypingEnd=bind(this.onTypingEnd,this),this.onInput=bind(this.onInput,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.view=bind(this.view,this),this.T=bind(this.T,this);var s;return this.options=t.extend({},this.defaults,a),this.el=t(this.view("chat")(this.options)),this.options.target.append(this.el),this.setAgentOnlineState(this.isOnline),this.el.find(".zammad-chat-header").click(this.toggle),this.el.find(".zammad-chat-controls").on("submit",this.onSubmit),this.el.find(".zammad-chat-input").on({keydown:this.checkForEnter,input:this.onInput}),this.session_id=void 0,e.WebSocket?(s="ws://localhost:6042",this.ws=new e.WebSocket(s),console.log("Connecting to "+s),this.ws.onopen=function(t){return function(){return console.log("ws connected"),t.send("chat_status")}}(this),this.ws.onmessage=this.onWebSocketMessage,this.ws.onclose=function(t){return function(t){return console.log("debug","close websocket connection")}}(this),void(this.ws.onerror=function(t){return function(t){return console.log("debug","ws:onerror",t)}}(this))):void console.log("Zammad Chat: Browser not supported")}return n.prototype.defaults={invitationPhrase:"Chat with us!",agentPhrase:" is helping you",show:!0,target:t("body")},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.isOnline=!0,n.prototype.strings={Online:"Online",Offline:"Offline",Connecting:"Connecting","Connection re-established":"Connection re-established",Today:"Today"},n.prototype.T=function(t){return this.strings[t]},n.prototype.view=function(t){return function(n){return function(a){return a||(a={}),a.T=n.T,e.zammadChatTemplates[t](a)}}(this)},n.prototype.checkForEnter=function(t){return t.shiftKey||13!==t.keyCode?void 0:(t.preventDefault(),this.sendMessage())},n.prototype.send=function(t,e){var n;return console.log("debug","ws:send",t,e),n=JSON.stringify({event:t,data:e}),this.ws.send(n)},n.prototype.onWebSocketMessage=function(t){var e,n,a,s,i;for(i=JSON.parse(t.data),console.log("debug","ws:onmessage",i),n=0,a=i.length;a>n;n++)switch(s=i[n],s.event){case"chat_session_message":if(s.data.self_written)return;this.receiveMessage(s.data);break;case"chat_session_typing":if(s.data.self_written)return;this.onAgentTypingStart(),this.stopTypingId&&clearTimeout(this.stopTypingId),e=function(t){return function(){return t.onAgentTypingEnd()}}(this),this.stopTypingId=setTimeout(e,3e3);break;case"chat_session_start":switch(s.data.state){case"ok":this.onConnectionEstablished(s.data.agent)}break;case"chat_session_init":switch(s.data.state){case"ok":this.onConnectionEstablished(s.data.agent);break;case"queue":this.onQueue(s.data.position),this.session_id=s.data.session_id}break;case"chat_status":switch(s.data.state){case"online":this.onReady(),console.log("Zammad Chat: ready");break;case"offline":console.log("Zammad Chat: No agent online");break;case"chat_disabled":console.log("Zammad Chat: Chat is disabled");break;case"no_seats_available":console.log("Zammad Chat: Too many clients in queue. Clients in queue: ",s.data.queue)}}},n.prototype.onReady=function(){return this.options.show?(this.show(),this.el.find(".zammad-chat-input").autoGrow({extraLine:!1})):void 0},n.prototype.onInput=function(){return this.el.find(".zammad-chat-message--unread").removeClass("zammad-chat-message--unread"),this.onTypingStart()},n.prototype.onTypingStart=function(){return this.isTypingTimeout&&clearTimeout(this.isTypingTimeout),this.isTypingTimeout=setTimeout(this.onTypingEnd,1500),this.isTyping?void 0:(this.isTyping=!0,this.send("chat_session_typing",{session_id:this.session_id}))},n.prototype.onTypingEnd=function(){return this.isTyping=!1},n.prototype.onSubmit=function(t){return t.preventDefault(),this.sendMessage()},n.prototype.sendMessage=function(){var t,e;return(t=this.el.find(".zammad-chat-input").val())?(e=this.view("message")({message:t,from:"customer",id:this._messageCount++}),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.el.find(".zammad-chat-input").val(""),this.scrollToBottom(),this.isTyping=!1,this.send("chat_session_message",{content:t,id:this._messageCount,session_id:this.session_id})):void 0},n.prototype.receiveMessage=function(t){var e,n;return this.onAgentTypingEnd(),this.maybeAddTimestamp(),this.lastAddedType="message--agent",n=null!=(e=document.hidden)?e:{" zammad-chat-message--unread":""},this.el.find(".zammad-chat-body").append(this.view("message")({message:t.message.content,id:t.id,from:"agent"})),this.scrollToBottom()},n.prototype.toggle=function(){return this.isOpen?this.close():this.open()},n.prototype.open=function(){return this.showLoader(),this.el.addClass("zammad-chat-is-open").animate({bottom:0},500,this.onOpenAnimationEnd)},n.prototype.onOpenAnimationEnd=function(){return this.isOpen=!0,this.connect()},n.prototype.close=function(){var t;return 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-open"),this.disconnect(),this.isOpen=!1},n.prototype.hide=function(){return this.el.removeClass("zammad-chat-is-visible")},n.prototype.show=function(){var t;return this.el.addClass("zammad-chat-is-visible"),t=this.el.outerHeight()-this.el.find(".zammad-chat-header").outerHeight(),this.el.css("bottom",-t)},n.prototype.onQueue=function(t){return console.log("onQueue",t),this.inQueue=!0,this.el.find(".zammad-chat-body").html(this.view("waiting")({position:t}))},n.prototype.onAgentTypingStart=function(){return 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.maybeAddTimestamp=function(){var t,e,n;return n=Date.now(),!this.lastTimestamp||n-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=n):(this.addStatus(t,e),this.lastTimestamp=n,this.lastAddedType="timestamp")):void 0},n.prototype.updateLastTimestamp=function(t,e){return this.el.find(".zammad-chat-body").find(".zammad-chat-status").last().replaceWith(this.view("status")({label:t,time:e}))},n.prototype.addStatus=function(t,e){return this.el.find(".zammad-chat-body").append(this.view("status")({label:t,time:e}))},n.prototype.scrollToBottom=function(){return this.el.find(".zammad-chat-body").scrollTop(t(".zammad-chat-body").prop("scrollHeight"))},n.prototype.connect=function(){return this.send("chat_session_init")},n.prototype.reconnect=function(){return this.lastAddedType="status",this.el.find(".zammad-chat-agent-status").attr("data-status","connecting").text(this.T("Connecting")),this.addStatus(this.T("Connection lost"))},n.prototype.onConnectionReestablished=function(){return this.lastAddedType="status",this.el.find(".zammad-chat-agent-status").attr("data-status","online").text(this.T("Online")),this.addStatus(this.T("Connection re-established"))},n.prototype.disconnect=function(){return 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")},n.prototype.onConnectionEstablished=function(t){return this.inQueue=!1,this.agent=t,this.el.find(".zammad-chat-agent").html(this.view("agent")({agent:t})),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.el.find(".zammad-chat-input").focus()},n.prototype.showLoader=function(){return this.el.find(".zammad-chat-body").html(this.view("loader")())},n.prototype.setAgentOnlineState=function(t){return this.isOnline=t,this.el.find(".zammad-chat-agent-status").toggleClass("zammad-chat-is-online",t).text(t?this.T("Online"):this.T("Offline"))},n}(),t(document).ready(function(){return e.zammadChat=new n})}(window.jQuery,window),jQuery.fn.autoGrow=function(t){return this.each(function(){var e=jQuery.extend({extraLine:!0},t),n=function(t){return jQuery(t).after('
'),jQuery(t).next(".autogrow-textarea-mirror")[0]},a=function(t){i.innerHTML=String(t.value).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">").replace(/ /g," ").replace(/\n/g,"
")+(e.extraLine?".
.":""),jQuery(t).height()!=jQuery(i).height()&&jQuery(t).height(jQuery(i).height())},s=function(){a(this)},i=n(this);i.style.display="none",i.style.wordWrap="break-word",i.style.whiteSpace="normal",i.style.padding=jQuery(this).css("paddingTop")+" "+jQuery(this).css("paddingRight")+" "+jQuery(this).css("paddingBottom")+" "+jQuery(this).css("paddingLeft"),i.style.width=jQuery(this).css("width"),i.style.fontFamily=jQuery(this).css("font-family"),i.style.fontSize=jQuery(this).css("font-size"),i.style.lineHeight=jQuery(this).css("line-height"),this.style.overflow="hidden",this.style.minHeight=this.rows+"em",this.onkeyup=s,a(this)})},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.chat=function(t){t||(t={});var e,n=[],a=t.safe,s=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},s||(s=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
\n
\n
\n Online\n \n \n \n \n
\n
\n \n
\n
\n \n '),n.push(this.invitationPhrase),n.push('\n
\n
\n
\n
\n \n \n
\n
')}).call(this)}.call(t),t.safe=a,t.escape=s,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.loader=function(t){t||(t={});var e,n=[],a=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},s=t.safe,i=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},i||(i=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
\n \n \n \n \n \n '),n.push(a(this.T("Connecting"))),n.push("\n
")}).call(this)}.call(t),t.safe=s,t.escape=i,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.message=function(t){t||(t={});var e,n=[],a=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},s=t.safe,i=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},i||(i=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
\n '),n.push(this.message),n.push("\n
")}).call(this)}.call(t),t.safe=s,t.escape=i,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.status=function(t){t||(t={});var e,n=[],a=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},s=t.safe,i=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},i||(i=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
'),n.push(a(this.label)),n.push(" "),n.push(a(this.time)),n.push("
")}).call(this)}.call(t),t.safe=s,t.escape=i,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.typingIndicator=function(t){t||(t={});var e,n=[],a=t.safe,s=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},s||(s=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
\n \n \n \n \n \n \n \n
')}).call(this)}.call(t),t.safe=a,t.escape=s,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.waiting=function(t){t||(t={});var e,n=[],a=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},s=t.safe,i=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},i||(i=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
\n
\n \n \n \n \n \n Leider sind gerade alle Mitarbeiter belegt.
\n Warteliste-Position: '),n.push(a(this.position)),n.push("\n
\n
")}).call(this)}.call(t),t.safe=s,t.escape=i,n.join("")}; \ No newline at end of file +window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.agent=function(t){t||(t={});var e,n=[],a=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},s=t.safe,i=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},i||(i=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){this.agent.avatar&&(n.push('\n\n')),n.push('\n\n '),n.push(a(this.agent.name)),n.push(" "),n.push(this.agentPhrase),n.push("\n")}).call(this)}.call(t),t.safe=s,t.escape=i,n.join("")};var bind=function(t,e){return function(){return t.apply(e,arguments)}};!function(t,e){var n;return n=function(){function n(n,a){this.setAgentOnlineState=bind(this.setAgentOnlineState,this),this.onConnectionEstablished=bind(this.onConnectionEstablished,this),this.onConnectionReestablished=bind(this.onConnectionReestablished,this),this.reconnect=bind(this.reconnect,this),this.onAgentTypingEnd=bind(this.onAgentTypingEnd,this),this.onAgentTypingStart=bind(this.onAgentTypingStart,this),this.onQueue=bind(this.onQueue,this),this.onCloseAnimationEnd=bind(this.onCloseAnimationEnd,this),this.onOpenAnimationEnd=bind(this.onOpenAnimationEnd,this),this.toggle=bind(this.toggle,this),this.receiveMessage=bind(this.receiveMessage,this),this.onSubmit=bind(this.onSubmit,this),this.onTypingEnd=bind(this.onTypingEnd,this),this.onInput=bind(this.onInput,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.view=bind(this.view,this),this.T=bind(this.T,this);var s;return this.options=t.extend({},this.defaults,a),this.el=t(this.view("chat")(this.options)),this.options.target.append(this.el),this.setAgentOnlineState(this.isOnline),this.el.find(".zammad-chat-header").click(this.toggle),this.el.find(".zammad-chat-controls").on("submit",this.onSubmit),this.el.find(".zammad-chat-input").on({keydown:this.checkForEnter,input:this.onInput}),this.session_id=void 0,e.WebSocket?(s="ws://localhost:6042",this.ws=new e.WebSocket(s),console.log("Connecting to "+s),this.ws.onopen=function(t){return function(){return console.log("ws connected"),t.send("chat_status_customer")}}(this),this.ws.onmessage=this.onWebSocketMessage,this.ws.onclose=function(t){return function(t){return console.log("debug","close websocket connection")}}(this),void(this.ws.onerror=function(t){return function(t){return console.log("debug","ws:onerror",t)}}(this))):void console.log("Zammad Chat: Browser not supported")}return n.prototype.defaults={invitationPhrase:"Chat with us!",agentPhrase:" is helping you",show:!0,target:t("body")},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.isOnline=!0,n.prototype.strings={Online:"Online",Offline:"Offline",Connecting:"Connecting","Connection re-established":"Connection re-established",Today:"Today"},n.prototype.T=function(t){return this.strings[t]},n.prototype.view=function(t){return function(n){return function(a){return a||(a={}),a.T=n.T,e.zammadChatTemplates[t](a)}}(this)},n.prototype.checkForEnter=function(t){return t.shiftKey||13!==t.keyCode?void 0:(t.preventDefault(),this.sendMessage())},n.prototype.send=function(t,e){var n;return console.log("debug","ws:send",t,e),n=JSON.stringify({event:t,data:e}),this.ws.send(n)},n.prototype.onWebSocketMessage=function(t){var e,n,a,s;for(s=JSON.parse(t.data),console.log("debug","ws:onmessage",s),e=0,n=s.length;n>e;e++)switch(a=s[e],a.event){case"chat_session_message":if(a.data.self_written)return;this.receiveMessage(a.data);break;case"chat_session_typing":if(a.data.self_written)return;this.onAgentTypingStart();break;case"chat_session_start":switch(a.data.state){case"ok":this.onConnectionEstablished(a.data.agent)}break;case"chat_session_init":switch(a.data.state){case"ok":this.onConnectionEstablished(a.data.agent);break;case"queue":this.onQueue(a.data.position),this.session_id=a.data.session_id}break;case"chat_status_customer":switch(a.data.state){case"online":this.onReady(),console.log("Zammad Chat: ready");break;case"offline":console.log("Zammad Chat: No agent online");break;case"chat_disabled":console.log("Zammad Chat: Chat is disabled");break;case"no_seats_available":console.log("Zammad Chat: Too many clients in queue. Clients in queue: ",a.data.queue)}}},n.prototype.onReady=function(){return this.options.show?(this.show(),this.el.find(".zammad-chat-input").autoGrow({extraLine:!1})):void 0},n.prototype.onInput=function(){return this.el.find(".zammad-chat-message--unread").removeClass("zammad-chat-message--unread"),this.onTypingStart()},n.prototype.onTypingStart=function(){return this.isTypingTimeout&&clearTimeout(this.isTypingTimeout),this.isTypingTimeout=setTimeout(this.onTypingEnd,1500),this.isTyping?void 0:(this.isTyping=!0,this.send("chat_session_typing",{session_id:this.session_id}))},n.prototype.onTypingEnd=function(){return this.isTyping=!1},n.prototype.onSubmit=function(t){return t.preventDefault(),this.sendMessage()},n.prototype.sendMessage=function(){var t,e;return(t=this.el.find(".zammad-chat-input").val())?(e=this.view("message")({message:t,from:"customer",id:this._messageCount++}),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.el.find(".zammad-chat-input").val(""),this.scrollToBottom(),this.isTyping=!1,this.send("chat_session_message",{content:t,id:this._messageCount,session_id:this.session_id})):void 0},n.prototype.receiveMessage=function(t){var e,n;return this.onAgentTypingEnd(),this.maybeAddTimestamp(),this.lastAddedType="message--agent",n=null!=(e=document.hidden)?e:{" zammad-chat-message--unread":""},this.el.find(".zammad-chat-body").append(this.view("message")({message:t.message.content,id:t.id,from:"agent"})),this.scrollToBottom()},n.prototype.toggle=function(){return this.isOpen?this.close():this.open()},n.prototype.open=function(){return this.showLoader(),this.el.addClass("zammad-chat-is-open").animate({bottom:0},500,this.onOpenAnimationEnd)},n.prototype.onOpenAnimationEnd=function(){return this.isOpen=!0,this.connect()},n.prototype.close=function(){var t;return 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-open"),this.disconnect(),this.isOpen=!1},n.prototype.hide=function(){return this.el.removeClass("zammad-chat-is-visible")},n.prototype.show=function(){var t;return this.el.addClass("zammad-chat-is-visible"),t=this.el.outerHeight()-this.el.find(".zammad-chat-header").outerHeight(),this.el.css("bottom",-t)},n.prototype.onQueue=function(t){return console.log("onQueue",t),this.inQueue=!0,this.el.find(".zammad-chat-body").html(this.view("waiting")({position:t}))},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.maybeAddTimestamp=function(){var t,e,n;return n=Date.now(),!this.lastTimestamp||n-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=n):(this.addStatus(t,e),this.lastTimestamp=n,this.lastAddedType="timestamp")):void 0},n.prototype.updateLastTimestamp=function(t,e){return this.el.find(".zammad-chat-body").find(".zammad-chat-status").last().replaceWith(this.view("status")({label:t,time:e}))},n.prototype.addStatus=function(t,e){return this.el.find(".zammad-chat-body").append(this.view("status")({label:t,time:e}))},n.prototype.scrollToBottom=function(){return this.el.find(".zammad-chat-body").scrollTop(t(".zammad-chat-body").prop("scrollHeight"))},n.prototype.connect=function(){return this.send("chat_session_init")},n.prototype.reconnect=function(){return this.lastAddedType="status",this.el.find(".zammad-chat-agent-status").attr("data-status","connecting").text(this.T("Connecting")),this.addStatus(this.T("Connection lost"))},n.prototype.onConnectionReestablished=function(){return this.lastAddedType="status",this.el.find(".zammad-chat-agent-status").attr("data-status","online").text(this.T("Online")),this.addStatus(this.T("Connection re-established"))},n.prototype.disconnect=function(){return 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")},n.prototype.onConnectionEstablished=function(t){return this.inQueue=!1,this.agent=t,this.el.find(".zammad-chat-agent").html(this.view("agent")({agent:t})),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.el.find(".zammad-chat-input").focus()},n.prototype.showLoader=function(){return this.el.find(".zammad-chat-body").html(this.view("loader")())},n.prototype.setAgentOnlineState=function(t){return this.isOnline=t,this.el.find(".zammad-chat-agent-status").toggleClass("zammad-chat-is-online",t).text(t?this.T("Online"):this.T("Offline"))},n}(),t(document).ready(function(){return e.zammadChat=new n})}(window.jQuery,window),jQuery.fn.autoGrow=function(t){return this.each(function(){var e=jQuery.extend({extraLine:!0},t),n=function(t){return jQuery(t).after('
'),jQuery(t).next(".autogrow-textarea-mirror")[0]},a=function(t){i.innerHTML=String(t.value).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">").replace(/ /g," ").replace(/\n/g,"
")+(e.extraLine?".
.":""),jQuery(t).height()!=jQuery(i).height()&&jQuery(t).height(jQuery(i).height())},s=function(){a(this)},i=n(this);i.style.display="none",i.style.wordWrap="break-word",i.style.whiteSpace="normal",i.style.padding=jQuery(this).css("paddingTop")+" "+jQuery(this).css("paddingRight")+" "+jQuery(this).css("paddingBottom")+" "+jQuery(this).css("paddingLeft"),i.style.width=jQuery(this).css("width"),i.style.fontFamily=jQuery(this).css("font-family"),i.style.fontSize=jQuery(this).css("font-size"),i.style.lineHeight=jQuery(this).css("line-height"),this.style.overflow="hidden",this.style.minHeight=this.rows+"em",this.onkeyup=s,a(this)})},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.chat=function(t){t||(t={});var e,n=[],a=t.safe,s=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},s||(s=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
\n
\n
\n Online\n \n \n \n \n
\n
\n \n
\n
\n \n '),n.push(this.invitationPhrase),n.push('\n
\n
\n
\n
\n \n \n
\n
')}).call(this)}.call(t),t.safe=a,t.escape=s,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.loader=function(t){t||(t={});var e,n=[],a=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},s=t.safe,i=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},i||(i=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
\n \n \n \n \n \n '),n.push(a(this.T("Connecting"))),n.push("\n
")}).call(this)}.call(t),t.safe=s,t.escape=i,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.message=function(t){t||(t={});var e,n=[],a=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},s=t.safe,i=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},i||(i=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
\n '),n.push(this.message),n.push("\n
")}).call(this)}.call(t),t.safe=s,t.escape=i,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.status=function(t){t||(t={});var e,n=[],a=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},s=t.safe,i=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},i||(i=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
'),n.push(a(this.label)),n.push(" "),n.push(a(this.time)),n.push("
")}).call(this)}.call(t),t.safe=s,t.escape=i,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.typingIndicator=function(t){t||(t={});var e,n=[],a=t.safe,s=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},s||(s=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
\n \n \n \n \n \n \n \n
')}).call(this)}.call(t),t.safe=a,t.escape=s,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.waiting=function(t){t||(t={});var e,n=[],a=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},s=t.safe,i=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},i||(i=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
\n
\n \n \n \n \n \n Leider sind gerade alle Mitarbeiter belegt.
\n Warteliste-Position: '),n.push(a(this.position)),n.push("\n
\n
")}).call(this)}.call(t),t.safe=s,t.escape=i,n.join("")}; \ No newline at end of file