diff --git a/app/assets/javascripts/app/controllers/chat.coffee b/app/assets/javascripts/app/controllers/chat.coffee
index 34cf3bd8c..8050ef8f8 100644
--- a/app/assets/javascripts/app/controllers/chat.coffee
+++ b/app/assets/javascripts/app/controllers/chat.coffee
@@ -27,20 +27,25 @@ class App.CustomerChat extends App.Controller
@render()
- App.Event.bind(
+ @bind(
'chat_status_agent'
(data) =>
@meta = data
@updateMeta()
@interval(@pushState, 20000, 'pushState')
)
- App.Event.bind(
+ @bind(
'chat_session_start'
(data) =>
App.WebSocket.send(event:'chat_status_agent')
if data.session
@addChat(data.session)
)
+ @bind(
+ 'ws:login'
+ ->
+ App.WebSocket.send(event:'chat_status_agent')
+ )
App.WebSocket.send(event:'chat_status_agent')
@@ -190,20 +195,28 @@ class chatWindow extends App.Controller
@on 'layout-change', @scrollToBottom
- App.Event.bind(
+ @bind(
'chat_session_typing'
(data) =>
return if data.session_id isnt @session.session_id
return if data.self_written
@showWritingLoader()
)
- App.Event.bind(
+ @bind(
'chat_session_message'
(data) =>
return if data.session_id isnt @session.session_id
return if data.self_written
@receiveMessage(data.message.content)
)
+ @bind(
+ 'chat_session_left chat_session_closed'
+ (data) =>
+ return if data.session_id isnt @session.session_id
+ return if data.self_written
+ @addStatusMessage("#{data.realname} was leaving the conversation")
+ @goOffline()
+ )
render: ->
@html App.view('layout_ref/customer_chat_window')
@@ -223,7 +236,7 @@ class chatWindow extends App.Controller
@addMessage message.content, 'customer'
# set focus
- @input.get(0).focus()
+ #@input.get(0).focus()
onTransitionend: (event) =>
# chat window is done with animation - adjust scroll-bars
@@ -246,6 +259,7 @@ class chatWindow extends App.Controller
release: =>
@trigger 'closed'
+ @el.remove()
super
clearUnread: =>
@@ -360,7 +374,7 @@ class chatWindow extends App.Controller
@$('.js-loader').remove()
goOffline: =>
- @addStatusMessage("#{ @options.name } 's connection got closed")
+ #@addStatusMessage("#{ @options.name } 's connection got closed")
@status.attr('data-status', 'offline')
@el.addClass('is-offline')
@input.attr('disabled', true)
diff --git a/app/models/chat.rb b/app/models/chat.rb
index afaca3180..2bba381fd 100644
--- a/app/models/chat.rb
+++ b/app/models/chat.rb
@@ -46,7 +46,7 @@ class Chat < ApplicationModel
end
def self.running_chat_count
- Chat::Session.where(state: ['waiting']).count
+ Chat::Session.where(state: ['running']).count
end
def active_chat_count
@@ -129,19 +129,19 @@ class Chat::Session < ApplicationModel
end
def add_recipient(client_id, store = false)
- if !self.preferences[:participants]
- self.preferences[:participants] = []
+ if !preferences[:participants]
+ preferences[:participants] = []
end
- return self.preferences[:participants] if self.preferences[:participants].include?(client_id)
- self.preferences[:participants].push client_id
+ return preferences[:participants] if preferences[:participants].include?(client_id)
+ preferences[:participants].push client_id
if store
- self.save
+ save
end
- self.preferences[:participants]
+ preferences[:participants]
end
def send_to_recipients(message, ignore_client_id)
- self.preferences[:participants].each {|local_client_id|
+ preferences[:participants].each {|local_client_id|
next if local_client_id == ignore_client_id
Sessions.send(local_client_id, message)
}
diff --git a/lib/sessions/event/chat_base.rb b/lib/sessions/event/chat_base.rb
index 6df4a7dcd..66a35b44b 100644
--- a/lib/sessions/event/chat_base.rb
+++ b/lib/sessions/event/chat_base.rb
@@ -7,7 +7,7 @@ class Sessions::Event::ChatBase
end
- def pre_check
+ def pre
# check if feature is enabled
if !Setting.get('chat')
@@ -22,4 +22,8 @@ class Sessions::Event::ChatBase
false
end
+ def post
+ false
+ end
+
end
diff --git a/lib/sessions/event/chat_session_close.rb b/lib/sessions/event/chat_session_close.rb
index 99cafd22f..4856dfe63 100644
--- a/lib/sessions/event/chat_session_close.rb
+++ b/lib/sessions/event/chat_session_close.rb
@@ -16,15 +16,41 @@ class Sessions::Event::ChatSessionClose < Sessions::Event::ChatBase
return {
event: 'chat_status_close',
data: {
- state: "No such session id #{data['data']['session_id']}",
+ state: "No such session id #{@data['data']['session_id']}",
},
}
end
- chat_session.state = 'closed'
- chat_session.save
+ realname = 'anonymous'
+ if @session && @session['id']
+ realname = User.find(@session['id']).fullname
+ end
- # return new session
+ # notify about "leaving"
+ if @session && chat_session.user_id == @session['id']
+ message = {
+ event: 'chat_session_closed',
+ data: {
+ session_id: chat_session.session_id,
+ realname: realname,
+ },
+ }
+
+ # close session if host is closing it
+ chat_session.state = 'closed'
+ chat_session.save
+ else
+ message = {
+ event: 'chat_session_left',
+ data: {
+ session_id: chat_session.session_id,
+ realname: realname,
+ },
+ }
+ end
+ chat_session.send_to_recipients(message, @client_id)
+
+ # notifiy participients
{
event: 'chat_status_close',
data: {
diff --git a/lib/sessions/event/chat_session_start.rb b/lib/sessions/event/chat_session_start.rb
index c1b75e46e..13eed93f7 100644
--- a/lib/sessions/event/chat_session_start.rb
+++ b/lib/sessions/event/chat_session_start.rb
@@ -20,9 +20,13 @@ class Sessions::Event::ChatSessionStart < Sessions::Event::ChatBase
# send chat_session_init to client
chat_user = User.find(chat_session.user_id)
+ url = nil
+ if chat_user.image && chat_user.image != 'none'
+ url = "/api/v1/users/image/#{chat_user.image}"
+ end
user = {
name: chat_user.fullname,
- avatar: chat_user.image,
+ avatar: url,
}
data = {
event: 'chat_session_start',
diff --git a/lib/sessions/event/chat_status_agent.rb b/lib/sessions/event/chat_status_agent.rb
index 884b47103..7e723a118 100644
--- a/lib/sessions/event/chat_status_agent.rb
+++ b/lib/sessions/event/chat_status_agent.rb
@@ -4,12 +4,10 @@ class Sessions::Event::ChatStatusAgent < Sessions::Event::ChatBase
# check if user has permissions
-
# renew timestamps
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)
diff --git a/public/assets/chat/chat.coffee b/public/assets/chat/chat.coffee
index 4843b9208..2b6bc05c9 100644
--- a/public/assets/chat/chat.coffee
+++ b/public/assets/chat/chat.coffee
@@ -19,15 +19,35 @@ do($ = window.jQuery, window) ->
inputTimeout: null
isTyping: false
isOnline: true
+ debug: true
+ host: 'ws://localhost:6042'
strings:
'Online': 'Online'
'Offline': 'Offline'
- 'Connecting': 'Connecting'
+ 'Connecting': 'Verbinden'
'Connection re-established': 'Connection re-established'
- 'Today': 'Today'
+ '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 .'
+ '': ''
+ '': ''
+ '': ''
- T: (string) =>
- return @strings[string]
+ T: (string, items...) =>
+ if !@strings[string]
+ @log 'notice', "Translation needed for '#{string}'"
+ translation = @strings[string] || string
+ if items
+ for item in items
+ translation = translation.replace(/%s/, item)
+
+ translation
+
+ log: (level, string...) =>
+ return if !@debug && level is 'debug'
+ console.log level, string
view: (name) =>
return (options) =>
@@ -42,8 +62,6 @@ do($ = window.jQuery, window) ->
@el = $(@view('chat')(@options))
@options.target.append @el
- @setAgentOnlineState @isOnline
-
@el.find('.js-chat-open').click @open
@el.find('.js-chat-close').click @close
@el.find('.zammad-chat-controls').on 'submit', @onSubmit
@@ -54,24 +72,10 @@ do($ = window.jQuery, window) ->
@session_id = undefined
if !window.WebSocket
- console.log('Zammad Chat: Browser not supported')
+ @log 'notice', 'Chat: Browser not supported!'
return
- zammad_host = 'ws://localhost:6042'
- @ws = new window.WebSocket(zammad_host)
- console.log("Connecting to #{zammad_host}")
-
- @ws.onopen = =>
- console.log('ws connected')
- @send 'chat_status_customer'
-
- @ws.onmessage = @onWebSocketMessage
-
- @ws.onclose = (e) =>
- console.log 'debug', 'close websocket connection'
-
- @ws.onerror = (e) =>
- console.log 'debug', 'ws:onerror', e
+ @connect()
@onReady()
@@ -81,7 +85,7 @@ do($ = window.jQuery, window) ->
@sendMessage()
send: (event, data) =>
- console.log 'debug', 'ws:send', event, data
+ @log 'debug', 'ws:send', event, data
pipe = JSON.stringify
event: event
data: data
@@ -89,7 +93,7 @@ do($ = window.jQuery, window) ->
onWebSocketMessage: (e) =>
pipes = JSON.parse( e.data )
- console.log 'debug', 'ws:onmessage', pipes
+ @log 'debug', 'ws:onmessage', pipes
for pipe in pipes
switch pipe.event
@@ -110,17 +114,21 @@ do($ = window.jQuery, window) ->
when 'queue'
@onQueue pipe.data.position
@session_id = pipe.data.session_id
+ when 'chat_session_closed'
+ @onSessionClosed pipe.data
+ when 'chat_session_left'
+ @onSessionClosed pipe.data
when 'chat_status_customer'
switch pipe.data.state
when 'online'
@onReady()
- console.log 'Zammad Chat: ready'
+ @log 'debug', 'Zammad Chat: ready'
when 'offline'
- console.log 'Zammad Chat: No agent online'
+ @log 'debug', 'Zammad Chat: No agent online'
when 'chat_disabled'
- console.log 'Zammad Chat: Chat is disabled'
+ @log 'debug', 'Zammad Chat: Chat is disabled'
when 'no_seats_available'
- console.log 'Zammad Chat: Too many clients in queue. Clients in queue: ', pipe.data.queue
+ @log 'debug', 'Zammad Chat: Too many clients in queue. Clients in queue: ', pipe.data.queue
onReady: =>
if @options.show
@@ -157,8 +165,7 @@ do($ = window.jQuery, window) ->
sendMessage: ->
message = @el.find('.zammad-chat-input').val()
- if !message
- return
+ return if !message
messageElement = @view('message')
message: message
@@ -216,7 +223,7 @@ do($ = window.jQuery, window) ->
# setTimeout @onConnectionEstablished, 1180
# setTimeout @onAgentTypingStart, 2000
# setTimeout @receiveMessage, 5000, "Hello! How can I help you?"
- @connect()
+ @session_init()
close: (event) =>
event.stopPropagation() if event
@@ -228,6 +235,8 @@ do($ = window.jQuery, window) ->
@disconnect()
@isOpen = false
+ @send 'chat_session_close', {session_id: @session_id}
+
hide: ->
@el.removeClass('zammad-chat-is-visible')
@@ -238,8 +247,16 @@ do($ = window.jQuery, window) ->
@el.css 'bottom', -remainerHeight
+ disableInput: ->
+ @el.find('.zammad-chat-input').prop('disabled', true)
+ @el.find('.zammad-chat-send').prop('disabled', true)
+
+ enableInput: ->
+ @el.find('.zammad-chat-input').prop('disabled', false)
+ @el.find('.zammad-chat-send').prop('disabled', false)
+
onQueue: (position) =>
- console.log "onQueue", position
+ @log 'notice', 'onQueue', position
@inQueue = true
@el.find('.zammad-chat-body').html @view('waiting')
@@ -294,21 +311,49 @@ do($ = window.jQuery, window) ->
scrollToBottom: ->
@el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'))
- connect: ->
+ session_init: ->
@send('chat_session_init')
+ connect: =>
+ @log 'notice', "Connecting to #{@host}"
+ @ws = new window.WebSocket(@host)
+ @ws.onopen = =>
+ @log 'debug', 'ws connected'
+ @send 'chat_status_customer'
+ @setAgentOnlineState(true)
+
+ @ws.onmessage = @onWebSocketMessage
+
+ @ws.onclose = (e) =>
+ @log 'debug', 'close websocket connection'
+ @reconnect()
+ @setAgentOnlineState(false)
+
+ @ws.onerror = (e) =>
+ @log 'debug', 'ws:onerror', e
+
reconnect: =>
# set status to connecting
+ @log 'notice', 'reconnecting'
+ @disableInput()
@lastAddedType = 'status'
- @el.find('.zammad-chat-agent-status').attr('data-status', 'connecting').text @T('Connecting')
+ @el.find('.zammad-chat-agent-status').attr('data-status', 'connecting').text @T('Reconnecting')
@addStatus @T('Connection lost')
+ if @reconnectDelayId
+ clearTimeout(@reconnectDelayId)
+ @reconnectDelayId = setTimeout(@connect, 5000)
+
onConnectionReestablished: =>
# set status back to online
@lastAddedType = 'status'
@el.find('.zammad-chat-agent-status').attr('data-status', 'online').text @T('Online')
@addStatus @T('Connection re-established')
+ onSessionClosed: (data) ->
+ @addStatus @T('Chat closed by %s', data.realname)
+ @disableInput()
+
disconnect: ->
@showLoader()
@el.find('.zammad-chat-welcome').removeClass('zammad-chat-is-hidden')
@@ -322,6 +367,8 @@ do($ = window.jQuery, window) ->
@el.find('.zammad-chat-agent').html @view('agent')
agent: agent
+ @enableInput()
+
@el.find('.zammad-chat-body').empty()
@el.find('.zammad-chat-welcome').addClass('zammad-chat-is-hidden')
@el.find('.zammad-chat-agent').removeClass('zammad-chat-is-hidden')
diff --git a/public/assets/chat/chat.js b/public/assets/chat/chat.js
index 4603c0f90..7fca04e38 100644
--- a/public/assets/chat/chat.js
+++ b/public/assets/chat/chat.js
@@ -1,4 +1,70 @@
-var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+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;
(function($, window) {
var ZammadChat;
@@ -30,16 +96,48 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
ZammadChat.prototype.isOnline = true;
+ ZammadChat.prototype.debug = true;
+
+ ZammadChat.prototype.host = 'ws://localhost:6042';
+
ZammadChat.prototype.strings = {
'Online': 'Online',
'Offline': 'Offline',
- 'Connecting': 'Connecting',
+ 'Connecting': 'Verbinden',
'Connection re-established': 'Connection re-established',
- 'Today': 'Today'
+ '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 .',
+ '': '',
+ '': '',
+ '': ''
};
- ZammadChat.prototype.T = function(string) {
- return this.strings[string];
+ ZammadChat.prototype.T = function() {
+ var i, item, items, len, string, translation;
+ string = arguments[0], items = 2 <= arguments.length ? slice.call(arguments, 1) : [];
+ if (!this.strings[string]) {
+ this.log('notice', "Translation needed for '" + string + "'");
+ }
+ translation = this.strings[string] || string;
+ if (items) {
+ for (i = 0, len = items.length; i < len; i++) {
+ item = items[i];
+ translation = translation.replace(/%s/, item);
+ }
+ }
+ return translation;
+ };
+
+ ZammadChat.prototype.log = function() {
+ var level, string;
+ level = arguments[0], string = 2 <= arguments.length ? slice.call(arguments, 1) : [];
+ if (!this.debug && level === 'debug') {
+ return;
+ }
+ return console.log(level, string);
};
ZammadChat.prototype.view = function(name) {
@@ -59,6 +157,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
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);
@@ -75,12 +174,11 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
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);
- var zammad_host;
this.options = $.extend({}, this.defaults, options);
this.el = $(this.view('chat')(this.options));
this.options.target.append(this.el);
- this.setAgentOnlineState(this.isOnline);
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);
@@ -90,29 +188,10 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
});
this.session_id = void 0;
if (!window.WebSocket) {
- console.log('Zammad Chat: Browser not supported');
+ this.log('notice', 'Chat: Browser not supported!');
return;
}
- zammad_host = 'ws://localhost:6042';
- this.ws = new window.WebSocket(zammad_host);
- console.log("Connecting to " + zammad_host);
- this.ws.onopen = (function(_this) {
- return function() {
- console.log('ws connected');
- return _this.send('chat_status_customer');
- };
- })(this);
- this.ws.onmessage = this.onWebSocketMessage;
- this.ws.onclose = (function(_this) {
- return function(e) {
- return console.log('debug', 'close websocket connection');
- };
- })(this);
- this.ws.onerror = (function(_this) {
- return function(e) {
- return console.log('debug', 'ws:onerror', e);
- };
- })(this);
+ this.connect();
this.onReady();
}
@@ -125,7 +204,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
ZammadChat.prototype.send = function(event, data) {
var pipe;
- console.log('debug', 'ws:send', event, data);
+ this.log('debug', 'ws:send', event, data);
pipe = JSON.stringify({
event: event,
data: data
@@ -136,7 +215,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
ZammadChat.prototype.onWebSocketMessage = function(e) {
var i, len, pipe, pipes;
pipes = JSON.parse(e.data);
- console.log('debug', 'ws:onmessage', pipes);
+ this.log('debug', 'ws:onmessage', pipes);
for (i = 0, len = pipes.length; i < len; i++) {
pipe = pipes[i];
switch (pipe.event) {
@@ -168,20 +247,26 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
this.session_id = pipe.data.session_id;
}
break;
+ case 'chat_session_closed':
+ this.onSessionClosed(pipe.data);
+ break;
+ case 'chat_session_left':
+ this.onSessionClosed(pipe.data);
+ break;
case 'chat_status_customer':
switch (pipe.data.state) {
case 'online':
this.onReady();
- console.log('Zammad Chat: ready');
+ this.log('debug', 'Zammad Chat: ready');
break;
case 'offline':
- console.log('Zammad Chat: No agent online');
+ this.log('debug', 'Zammad Chat: No agent online');
break;
case 'chat_disabled':
- console.log('Zammad Chat: Chat is disabled');
+ this.log('debug', 'Zammad Chat: Chat is disabled');
break;
case 'no_seats_available':
- console.log('Zammad Chat: Too many clients in queue. Clients in queue: ', pipe.data.queue);
+ this.log('debug', 'Zammad Chat: Too many clients in queue. Clients in queue: ', pipe.data.queue);
}
}
}
@@ -280,7 +365,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
};
ZammadChat.prototype.onOpenAnimationEnd = function() {
- return this.connect();
+ return this.session_init();
};
ZammadChat.prototype.close = function(event) {
@@ -297,7 +382,10 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
ZammadChat.prototype.onCloseAnimationEnd = function() {
this.el.removeClass('zammad-chat-is-open');
this.disconnect();
- return this.isOpen = false;
+ this.isOpen = false;
+ return this.send('chat_session_close', {
+ session_id: this.session_id
+ });
};
ZammadChat.prototype.hide = function() {
@@ -311,8 +399,18 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
return this.el.css('bottom', -remainerHeight);
};
+ ZammadChat.prototype.disableInput = function() {
+ this.el.find('.zammad-chat-input').prop('disabled', true);
+ return this.el.find('.zammad-chat-send').prop('disabled', true);
+ };
+
+ ZammadChat.prototype.enableInput = function() {
+ this.el.find('.zammad-chat-input').prop('disabled', false);
+ return this.el.find('.zammad-chat-send').prop('disabled', false);
+ };
+
ZammadChat.prototype.onQueue = function(position) {
- console.log("onQueue", position);
+ this.log('notice', 'onQueue', position);
this.inQueue = true;
return this.el.find('.zammad-chat-body').html(this.view('waiting')({
position: position
@@ -371,14 +469,45 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
return this.el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'));
};
- ZammadChat.prototype.connect = function() {
+ ZammadChat.prototype.session_init = function() {
return this.send('chat_session_init');
};
+ ZammadChat.prototype.connect = function() {
+ this.log('notice', "Connecting to " + this.host);
+ this.ws = new window.WebSocket(this.host);
+ this.ws.onopen = (function(_this) {
+ return function() {
+ _this.log('debug', 'ws connected');
+ _this.send('chat_status_customer');
+ return _this.setAgentOnlineState(true);
+ };
+ })(this);
+ this.ws.onmessage = this.onWebSocketMessage;
+ this.ws.onclose = (function(_this) {
+ return function(e) {
+ _this.log('debug', 'close websocket connection');
+ _this.reconnect();
+ return _this.setAgentOnlineState(false);
+ };
+ })(this);
+ return this.ws.onerror = (function(_this) {
+ return function(e) {
+ return _this.log('debug', 'ws:onerror', e);
+ };
+ })(this);
+ };
+
ZammadChat.prototype.reconnect = function() {
+ this.log('notice', 'reconnecting');
+ this.disableInput();
this.lastAddedType = 'status';
- this.el.find('.zammad-chat-agent-status').attr('data-status', 'connecting').text(this.T('Connecting'));
- return this.addStatus(this.T('Connection lost'));
+ this.el.find('.zammad-chat-agent-status').attr('data-status', 'connecting').text(this.T('Reconnecting'));
+ this.addStatus(this.T('Connection lost'));
+ if (this.reconnectDelayId) {
+ clearTimeout(this.reconnectDelayId);
+ }
+ return this.reconnectDelayId = setTimeout(this.connect, 5000);
};
ZammadChat.prototype.onConnectionReestablished = function() {
@@ -387,6 +516,11 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
return this.addStatus(this.T('Connection re-established'));
};
+ ZammadChat.prototype.onSessionClosed = function(data) {
+ this.addStatus(this.T('Chat closed by %s', data.realname));
+ return this.disableInput();
+ };
+
ZammadChat.prototype.disconnect = function() {
this.showLoader();
this.el.find('.zammad-chat-welcome').removeClass('zammad-chat-is-hidden');
@@ -400,6 +534,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
this.el.find('.zammad-chat-agent').html(this.view('agent')({
agent: 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');
@@ -501,71 +636,6 @@ 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(' ');
-
- __out.push(this.agentPhrase);
-
- __out.push('\n ');
-
- }).call(this);
-
- }).call(__obj);
- __obj.safe = __objSafe, __obj.escape = __escape;
- return __out.join('');
-};
-
if (!window.zammadChatTemplates) {
window.zammadChatTemplates = {};
}
@@ -608,11 +678,19 @@ window.zammadChatTemplates["chat"] = function (__obj) {
}
(function() {
(function() {
- __out.push('
');
}).call(this);
@@ -887,11 +965,15 @@ window.zammadChatTemplates["waiting"] = function (__obj) {
}
(function() {
(function() {
- __out.push('\n
\n
\n \n \n \n \n Leider sind gerade alle Mitarbeiter belegt.
\n Warteliste-Position:
');
+ __out.push('\n
\n \n \n \n \n \n ');
- __out.push(__sanitize(this.position));
+ __out.push(this.T('All colleges are busy.'));
- __out.push('\n
\n
');
+ __out.push(' \n ');
+
+ __out.push(this.T('You are on waiting list position %s .', this.position));
+
+ __out.push('\n \n
');
}).call(this);
diff --git a/public/assets/chat/chat.min.js b/public/assets/chat/chat.min.js
index 63ee42a06..47cdc579a 100644
--- a/public/assets/chat/chat.min.js
+++ b/public/assets/chat/chat.min.js
@@ -1 +1 @@
-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.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.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(".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?(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),this.ws.onerror=function(t){return function(t){return console.log("debug","ws:onerror",t)}}(this),void this.onReady()):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.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.connect()},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},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),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("")},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('')}).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)}},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
\n \n '),n.push(this.T("Send")),n.push(" \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
diff --git a/public/assets/chat/views/chat.eco b/public/assets/chat/views/chat.eco
index 7aa234ec7..480aef2f4 100644
--- a/public/assets/chat/views/chat.eco
+++ b/public/assets/chat/views/chat.eco
@@ -8,7 +8,6 @@
-
-
- Send
+
+ <%- @T('Send') %>
\ No newline at end of file
diff --git a/public/assets/chat/views/waiting.eco b/public/assets/chat/views/waiting.eco
index b7513edc9..63170af5a 100644
--- a/public/assets/chat/views/waiting.eco
+++ b/public/assets/chat/views/waiting.eco
@@ -5,7 +5,7 @@
- Leider sind gerade alle Mitarbeiter belegt.
- Warteliste-Position: <%= @position %>
+ <%- @T('All colleges are busy.') %>
+ <%- @T('You are on waiting list position %s .', @position) %>
\ No newline at end of file