diff --git a/app/models/chat.rb b/app/models/chat.rb index 2bba381fd..a6e85984b 100644 --- a/app/models/chat.rb +++ b/app/models/chat.rb @@ -4,9 +4,17 @@ class Chat < ApplicationModel has_many :chat_topics validates :name, presence: true - def state + def customer_state(session_id = nil) return { state: 'chat_disabled' } if !Setting.get('chat') + if session_id + session = Chat.session_state(session_id) + return { + state: 'reconnect', + session: session, + } + end + if Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - 2.minutes).count > 0 if active_chat_count >= max_queue return { @@ -21,6 +29,15 @@ class Chat < ApplicationModel { state: 'offline' } end + def self.session_state(session_id) + session_attributes = [] + chat_session_id = Chat::Session.find_by(session_id: session_id) + Chat::Message.where(chat_session_id: chat_session_id.id).each { |message| + session_attributes.push message.attributes + } + session_attributes + end + def self.agent_state(user_id) return { state: 'chat_disabled' } if !Setting.get('chat') actice_sessions = [] diff --git a/lib/sessions/event/chat_status_customer.rb b/lib/sessions/event/chat_status_customer.rb index 8dbfb54d1..8dc46d567 100644 --- a/lib/sessions/event/chat_status_customer.rb +++ b/lib/sessions/event/chat_status_customer.rb @@ -13,9 +13,14 @@ class Sessions::Event::ChatStatusCustomer < Sessions::Event::ChatBase } end + # check if it's a chat sessin reconnect + session_id = nil + if @data['data']['session_id'] + session_id = @data['data']['session_id'] + end { event: 'chat_status_customer', - data: chat.state, + data: chat.customer_state(session_id), } end end diff --git a/public/assets/chat/chat.coffee b/public/assets/chat/chat.coffee index 2b6bc05c9..811518031 100644 --- a/public/assets/chat/chat.coffee +++ b/public/assets/chat/chat.coffee @@ -129,6 +129,9 @@ do($ = window.jQuery, window) -> @log 'debug', 'Zammad Chat: Chat is disabled' when 'no_seats_available' @log 'debug', 'Zammad Chat: Too many clients in queue. Clients in queue: ', pipe.data.queue + when 'reconnect' + # old messages + @log 'debug', 'old messages', pipe.data.session onReady: => if @options.show @@ -153,7 +156,8 @@ do($ = window.jQuery, window) -> # send typing start event if !@isTyping @isTyping = true - @send 'chat_session_typing', {session_id: @session_id} + @send 'chat_session_typing', + session_id: @session_id onTypingEnd: => @isTyping = false @@ -235,7 +239,8 @@ do($ = window.jQuery, window) -> @disconnect() @isOpen = false - @send 'chat_session_close', {session_id: @session_id} + @send 'chat_session_close', + session_id: @session_id hide: -> @el.removeClass('zammad-chat-is-visible') @@ -319,7 +324,8 @@ do($ = window.jQuery, window) -> @ws = new window.WebSocket(@host) @ws.onopen = => @log 'debug', 'ws connected' - @send 'chat_status_customer' + @send 'chat_status_customer', + session_id: @session_id @setAgentOnlineState(true) @ws.onmessage = @onWebSocketMessage diff --git a/public/assets/chat/chat.js b/public/assets/chat/chat.js index 7fca04e38..1e68a3480 100644 --- a/public/assets/chat/chat.js +++ b/public/assets/chat/chat.js @@ -1,68 +1,3 @@ -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(' '); - - __out.push(this.agentPhrase); - - __out.push('\n'); - - }).call(this); - - }).call(__obj); - __obj.safe = __objSafe, __obj.escape = __escape; - return __out.join(''); -}; - var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, slice = [].slice; @@ -267,6 +202,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); break; case 'no_seats_available': this.log('debug', 'Zammad Chat: Too many clients in queue. Clients in queue: ', pipe.data.queue); + break; + case 'reconnect': + this.log('debug', 'old messages', pipe.data.session); } } } @@ -479,7 +417,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); this.ws.onopen = (function(_this) { return function() { _this.log('debug', 'ws connected'); - _this.send('chat_status_customer'); + _this.send('chat_status_customer', { + session_id: _this.session_id + }); return _this.setAgentOnlineState(true); }; })(this); @@ -559,6 +499,71 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }); })(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(' '); + + __out.push(this.agentPhrase); + + __out.push('\n'); + + }).call(this); + + }).call(__obj); + __obj.safe = __objSafe, __obj.escape = __escape; + return __out.join(''); +}; + /*! * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): diff --git a/public/assets/chat/chat.min.js b/public/assets/chat/chat.min.js index 47cdc579a..9463bb798 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)}},slice=[].slice;!function(t,e){var n;return n=function(){function n(n,a){return 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.connect=bind(this.connect,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.close=bind(this.close,this),this.onOpenAnimationEnd=bind(this.onOpenAnimationEnd,this),this.open=bind(this.open,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.log=bind(this.log,this),this.T=bind(this.T,this),this.options=t.extend({},this.defaults,a),this.el=t(this.view("chat")(this.options)),this.options.target.append(this.el),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.el.find(".zammad-chat-input").on({keydown:this.checkForEnter,input:this.onInput}),this.session_id=void 0,e.WebSocket?(this.connect(),void this.onReady()):void this.log("notice","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.debug=!0,n.prototype.host="ws://localhost:6042",n.prototype.strings={Online:"Online",Offline:"Offline",Connecting:"Verbinden","Connection re-established":"Connection re-established",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.","":"","":"","":""},n.prototype.T=function(){var t,e,n,a,s,i;if(s=arguments[0],n=2<=arguments.length?slice.call(arguments,1):[],this.strings[s]||this.log("notice","Translation needed for '"+s+"'"),i=this.strings[s]||s,n)for(t=0,a=n.length;a>t;t++)e=n[t],i=i.replace(/%s/,e);return i},n.prototype.log=function(){var t,e;return t=arguments[0],e=2<=arguments.length?slice.call(arguments,1):[],this.debug||"debug"!==t?console.log(t,e):void 0},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 this.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),this.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_session_closed":this.onSessionClosed(a.data);break;case"chat_session_left":this.onSessionClosed(a.data);break;case"chat_status_customer":switch(a.data.state){case"online":this.onReady(),this.log("debug","Zammad Chat: ready");break;case"offline":this.log("debug","Zammad Chat: No agent online");break;case"chat_disabled":this.log("debug","Zammad Chat: Chat is disabled");break;case"no_seats_available":this.log("debug","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.open=function(){return this.isOpen?void 0:(this.showLoader(),this.el.addClass("zammad-chat-is-open").animate({bottom:0},500,this.onOpenAnimationEnd),this.isOpen=!0)},n.prototype.onOpenAnimationEnd=function(){return this.session_init()},n.prototype.close=function(t){var e;return t&&t.stopPropagation(),e=this.el.height()-this.el.find(".zammad-chat-header").outerHeight(),this.el.animate({bottom:-e},500,this.onCloseAnimationEnd)},n.prototype.onCloseAnimationEnd=function(){return this.el.removeClass("zammad-chat-is-open"),this.disconnect(),this.isOpen=!1,this.send("chat_session_close",{session_id:this.session_id})},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.disableInput=function(){return this.el.find(".zammad-chat-input").prop("disabled",!0),this.el.find(".zammad-chat-send").prop("disabled",!0)},n.prototype.enableInput=function(){return this.el.find(".zammad-chat-input").prop("disabled",!1),this.el.find(".zammad-chat-send").prop("disabled",!1)},n.prototype.onQueue=function(t){return this.log("notice","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.session_init=function(){return this.send("chat_session_init")},n.prototype.connect=function(){return this.log("notice","Connecting to "+this.host),this.ws=new e.WebSocket(this.host),this.ws.onopen=function(t){return function(){return t.log("debug","ws connected"),t.send("chat_status_customer"),t.setAgentOnlineState(!0)}}(this),this.ws.onmessage=this.onWebSocketMessage,this.ws.onclose=function(t){return function(e){return t.log("debug","close websocket connection"),t.reconnect(),t.setAgentOnlineState(!1)}}(this),this.ws.onerror=function(t){return function(e){return t.log("debug","ws:onerror",e)}}(this)},n.prototype.reconnect=function(){return this.log("notice","reconnecting"),this.disableInput(),this.lastAddedType="status",this.el.find(".zammad-chat-agent-status").attr("data-status","connecting").text(this.T("Reconnecting")),this.addStatus(this.T("Connection lost")),this.reconnectDelayId&&clearTimeout(this.reconnectDelayId),this.reconnectDelayId=setTimeout(this.connect,5e3)},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.onSessionClosed=function(t){return this.addStatus(this.T("Chat closed by %s",t.realname)),this.disableInput()},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.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.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.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=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.push(this.T("All colleges are busy.")),n.push("
\n "),n.push(this.T("You are on waiting list position %s.",this.position)),n.push("\n
\n
")}).call(this)}.call(t),t.safe=a,t.escape=s,n.join("")}; \ No newline at end of file +var bind=function(t,e){return function(){return t.apply(e,arguments)}},slice=[].slice;!function(t,e){var n;return n=function(){function n(n,s){return 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.connect=bind(this.connect,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.close=bind(this.close,this),this.onOpenAnimationEnd=bind(this.onOpenAnimationEnd,this),this.open=bind(this.open,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.log=bind(this.log,this),this.T=bind(this.T,this),this.options=t.extend({},this.defaults,s),this.el=t(this.view("chat")(this.options)),this.options.target.append(this.el),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.el.find(".zammad-chat-input").on({keydown:this.checkForEnter,input:this.onInput}),this.session_id=void 0,e.WebSocket?(this.connect(),void this.onReady()):void this.log("notice","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.debug=!0,n.prototype.host="ws://localhost:6042",n.prototype.strings={Online:"Online",Offline:"Offline",Connecting:"Verbinden","Connection re-established":"Connection re-established",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.","":"","":"","":""},n.prototype.T=function(){var t,e,n,s,a,i;if(a=arguments[0],n=2<=arguments.length?slice.call(arguments,1):[],this.strings[a]||this.log("notice","Translation needed for '"+a+"'"),i=this.strings[a]||a,n)for(t=0,s=n.length;s>t;t++)e=n[t],i=i.replace(/%s/,e);return i},n.prototype.log=function(){var t,e;return t=arguments[0],e=2<=arguments.length?slice.call(arguments,1):[],this.debug||"debug"!==t?console.log(t,e):void 0},n.prototype.view=function(t){return function(n){return function(s){return s||(s={}),s.T=n.T,e.zammadChatTemplates[t](s)}}(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 this.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,s,a;for(a=JSON.parse(t.data),this.log("debug","ws:onmessage",a),e=0,n=a.length;n>e;e++)switch(s=a[e],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();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_session_closed":this.onSessionClosed(s.data);break;case"chat_session_left":this.onSessionClosed(s.data);break;case"chat_status_customer":switch(s.data.state){case"online":this.onReady(),this.log("debug","Zammad Chat: ready");break;case"offline":this.log("debug","Zammad Chat: No agent online");break;case"chat_disabled":this.log("debug","Zammad Chat: Chat is disabled");break;case"no_seats_available":this.log("debug","Zammad Chat: Too many clients in queue. Clients in queue: ",s.data.queue);break;case"reconnect":this.log("debug","old messages",s.data.session)}}},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.open=function(){return this.isOpen?void 0:(this.showLoader(),this.el.addClass("zammad-chat-is-open").animate({bottom:0},500,this.onOpenAnimationEnd),this.isOpen=!0)},n.prototype.onOpenAnimationEnd=function(){return this.session_init()},n.prototype.close=function(t){var e;return t&&t.stopPropagation(),e=this.el.height()-this.el.find(".zammad-chat-header").outerHeight(),this.el.animate({bottom:-e},500,this.onCloseAnimationEnd)},n.prototype.onCloseAnimationEnd=function(){return this.el.removeClass("zammad-chat-is-open"),this.disconnect(),this.isOpen=!1,this.send("chat_session_close",{session_id:this.session_id})},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.disableInput=function(){return this.el.find(".zammad-chat-input").prop("disabled",!0),this.el.find(".zammad-chat-send").prop("disabled",!0)},n.prototype.enableInput=function(){return this.el.find(".zammad-chat-input").prop("disabled",!1),this.el.find(".zammad-chat-send").prop("disabled",!1)},n.prototype.onQueue=function(t){return this.log("notice","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.session_init=function(){return this.send("chat_session_init")},n.prototype.connect=function(){return this.log("notice","Connecting to "+this.host),this.ws=new e.WebSocket(this.host),this.ws.onopen=function(t){return function(){return t.log("debug","ws connected"),t.send("chat_status_customer",{session_id:t.session_id}),t.setAgentOnlineState(!0)}}(this),this.ws.onmessage=this.onWebSocketMessage,this.ws.onclose=function(t){return function(e){return t.log("debug","close websocket connection"),t.reconnect(),t.setAgentOnlineState(!1)}}(this),this.ws.onerror=function(t){return function(e){return t.log("debug","ws:onerror",e)}}(this)},n.prototype.reconnect=function(){return this.log("notice","reconnecting"),this.disableInput(),this.lastAddedType="status",this.el.find(".zammad-chat-agent-status").attr("data-status","connecting").text(this.T("Reconnecting")),this.addStatus(this.T("Connection lost")),this.reconnectDelayId&&clearTimeout(this.reconnectDelayId),this.reconnectDelayId=setTimeout(this.connect,5e3)},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.onSessionClosed=function(t){return this.addStatus(this.T("Chat closed by %s",t.realname)),this.disableInput()},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.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.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),window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.agent=function(t){t||(t={});var e,n=[],s=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},a=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(s(this.agent.name)),n.push(" "),n.push(this.agentPhrase),n.push("\n")}).call(this)}.call(t),t.safe=a,t.escape=i,n.join("")},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]},s=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())},a=function(){s(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=a,s(this)})},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.chat=function(t){t||(t={});var e,n=[],s=t.safe,a=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},a||(a=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.push(this.invitationPhrase),n.push('\n
\n
\n
\n
\n \n \n
\n
")}).call(this)}.call(t),t.safe=s,t.escape=a,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.loader=function(t){t||(t={});var e,n=[],s=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},a=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(s(this.T("Connecting"))),n.push("\n
")}).call(this)}.call(t),t.safe=a,t.escape=i,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.message=function(t){t||(t={});var e,n=[],s=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},a=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=a,t.escape=i,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.status=function(t){t||(t={});var e,n=[],s=function(t){return t&&t.ecoSafe?t:"undefined"!=typeof t&&null!=t?i(t):""},a=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(s(this.label)),n.push(" "),n.push(s(this.time)),n.push("
")}).call(this)}.call(t),t.safe=a,t.escape=i,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.typingIndicator=function(t){t||(t={});var e,n=[],s=t.safe,a=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},a||(a=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=s,t.escape=a,n.join("")},window.zammadChatTemplates||(window.zammadChatTemplates={}),window.zammadChatTemplates.waiting=function(t){t||(t={});var e,n=[],s=t.safe,a=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},a||(a=t.escape=function(t){return(""+t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}),function(){(function(){n.push('
\n
\n \n \n \n \n \n '),n.push(this.T("All colleges are busy.")),n.push("
\n "),n.push(this.T("You are on waiting list position %s.",this.position)),n.push("\n
\n
")}).call(this)}.call(t),t.safe=s,t.escape=a,n.join("")}; \ No newline at end of file