Added reconnecting of chat app. Improved logging of chat app.
This commit is contained in:
parent
74de560844
commit
ba68349789
11 changed files with 346 additions and 172 deletions
|
@ -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("<strong>#{ @options.name }</strong>'s connection got closed")
|
||||
#@addStatusMessage("<strong>#{ @options.name }</strong>'s connection got closed")
|
||||
@status.attr('data-status', 'offline')
|
||||
@el.addClass('is-offline')
|
||||
@input.attr('disabled', true)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 <strong>%s</strong>.': 'Sie sind in der Warteliste an der Position <strong>%s</strong>.'
|
||||
'': ''
|
||||
'': ''
|
||||
'': ''
|
||||
|
||||
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')
|
||||
|
|
|
@ -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, '>')
|
||||
.replace(/"/g, '"');
|
||||
};
|
||||
}
|
||||
(function() {
|
||||
(function() {
|
||||
if (this.agent.avatar) {
|
||||
__out.push('\n<img class="zammad-chat-agent-avatar" src="');
|
||||
__out.push(__sanitize(this.agent.avatar));
|
||||
__out.push('">\n');
|
||||
}
|
||||
|
||||
__out.push('\n<span class="zammad-chat-agent-sentence">\n <span class="zammad-chat-agent-name">');
|
||||
|
||||
__out.push(__sanitize(this.agent.name));
|
||||
|
||||
__out.push('</span> ');
|
||||
|
||||
__out.push(this.agentPhrase);
|
||||
|
||||
__out.push('\n</span>');
|
||||
|
||||
}).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 <strong>%s</strong>.': 'Sie sind in der Warteliste an der Position <strong>%s</strong>.',
|
||||
'': '',
|
||||
'': '',
|
||||
'': ''
|
||||
};
|
||||
|
||||
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, '>')
|
||||
.replace(/"/g, '"');
|
||||
};
|
||||
}
|
||||
(function() {
|
||||
(function() {
|
||||
if (this.agent.avatar) {
|
||||
__out.push('\n<img class="zammad-chat-agent-avatar" src="');
|
||||
__out.push(__sanitize(this.agent.avatar));
|
||||
__out.push('">\n');
|
||||
}
|
||||
|
||||
__out.push('\n<span class="zammad-chat-agent-sentence">\n <span class="zammad-chat-agent-name">');
|
||||
|
||||
__out.push(__sanitize(this.agent.name));
|
||||
|
||||
__out.push('</span> ');
|
||||
|
||||
__out.push(this.agentPhrase);
|
||||
|
||||
__out.push('\n</span>');
|
||||
|
||||
}).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('<div class="zammad-chat">\n <div class="zammad-chat-header js-chat-open">\n <div class="zammad-chat-header-controls">\n <span class="zammad-chat-agent-status zammad-chat-is-hidden" data-status="online">Online</span>\n <span class="zammad-chat-header-icon">\n <svg class="zammad-chat-header-icon-open" viewBox="0 0 13 7"><path d="M10.807 7l1.4-1.428-5-4.9L6.5-.02l-.7.7-4.9 4.9 1.414 1.413L6.5 2.886 10.807 7z" fill-rule="evenodd"/></svg>\n <svg class="zammad-chat-header-icon-close js-chat-close" viewBox="0 0 13 13"><path d="m2.241.12l-2.121 2.121 4.243 4.243-4.243 4.243 2.121 2.121 4.243-4.243 4.243 4.243 2.121-2.121-4.243-4.243 4.243-4.243-2.121-2.121-4.243 4.243-4.243-4.243" fill-rule="evenodd"/></svg>\n </span>\n </div>\n <div class="zammad-chat-agent zammad-chat-is-hidden">\n \n </div>\n <div class="zammad-chat-welcome">\n <svg class="zammad-chat-icon" viewBox="0 0 24 24"><path d="M2 5C2 4 3 3 4 3h16c1 0 2 1 2 2v10C22 16 21 17 20 17H4C3 17 2 16 2 15V5zM12 17l6 4v-4h-6z" fill-rule="evenodd"/></svg>\n <span class="zammad-chat-welcome-text">');
|
||||
__out.push('<div class="zammad-chat">\n <div class="zammad-chat-header js-chat-open">\n <div class="zammad-chat-header-controls">\n <span class="zammad-chat-agent-status zammad-chat-is-hidden" data-status="online">Online</span>\n <span class="zammad-chat-header-icon">\n <svg class="zammad-chat-header-icon-open" viewBox="0 0 13 7"><path d="M10.807 7l1.4-1.428-5-4.9L6.5-.02l-.7.7-4.9 4.9 1.414 1.413L6.5 2.886 10.807 7z" fill-rule="evenodd"/></svg>\n <svg class="zammad-chat-header-icon-close js-chat-close" viewBox="0 0 13 13"><path d="m2.241.12l-2.121 2.121 4.243 4.243-4.243 4.243 2.121 2.121 4.243-4.243 4.243 4.243 2.121-2.121-4.243-4.243 4.243-4.243-2.121-2.121-4.243 4.243-4.243-4.243" fill-rule="evenodd"/></svg>\n </span>\n </div>\n <div class="zammad-chat-agent zammad-chat-is-hidden">\n </div>\n <div class="zammad-chat-welcome">\n <svg class="zammad-chat-icon" viewBox="0 0 24 24"><path d="M2 5C2 4 3 3 4 3h16c1 0 2 1 2 2v10C22 16 21 17 20 17H4C3 17 2 16 2 15V5zM12 17l6 4v-4h-6z" fill-rule="evenodd"/></svg>\n <span class="zammad-chat-welcome-text">');
|
||||
|
||||
__out.push(this.invitationPhrase);
|
||||
|
||||
__out.push('</span>\n </div>\n </div>\n <div class="zammad-chat-body"></div>\n <form class="zammad-chat-controls">\n <textarea class="zammad-chat-input" rows="1" placeholder="Compose your message..."></textarea>\n <button type="submit" class="zammad-chat-send">Send</button>\n </form>\n</div>');
|
||||
__out.push('</span>\n </div>\n </div>\n <div class="zammad-chat-body"></div>\n <form class="zammad-chat-controls">\n <textarea class="zammad-chat-input" rows="1" placeholder="');
|
||||
|
||||
__out.push(this.T('Compose your message...'));
|
||||
|
||||
__out.push('"></textarea>\n <button type="submit" class="zammad-chat-send">');
|
||||
|
||||
__out.push(this.T('Send'));
|
||||
|
||||
__out.push('</button>\n </form>\n</div>');
|
||||
|
||||
}).call(this);
|
||||
|
||||
|
@ -887,11 +965,15 @@ window.zammadChatTemplates["waiting"] = function (__obj) {
|
|||
}
|
||||
(function() {
|
||||
(function() {
|
||||
__out.push('<div class="zammad-chat-modal">\n <div class="zammad-chat-modal-text">\n <span class="zammad-chat-loading-animation">\n <span class="zammad-chat-loading-circle"></span>\n <span class="zammad-chat-loading-circle"></span>\n <span class="zammad-chat-loading-circle"></span>\n </span>\n Leider sind gerade alle Mitarbeiter belegt.<br>\n Warteliste-Position: <strong>');
|
||||
__out.push('<div class="zammad-chat-modal">\n <div class="zammad-chat-modal-text">\n <span class="zammad-chat-loading-animation">\n <span class="zammad-chat-loading-circle"></span>\n <span class="zammad-chat-loading-circle"></span>\n <span class="zammad-chat-loading-circle"></span>\n </span>\n ');
|
||||
|
||||
__out.push(__sanitize(this.position));
|
||||
__out.push(this.T('All colleges are busy.'));
|
||||
|
||||
__out.push('</strong>\n </div>\n</div>');
|
||||
__out.push('<br>\n ');
|
||||
|
||||
__out.push(this.T('You are on waiting list position <strong>%s</strong>.', this.position));
|
||||
|
||||
__out.push('\n </div>\n</div>');
|
||||
|
||||
}).call(this);
|
||||
|
||||
|
|
2
public/assets/chat/chat.min.js
vendored
2
public/assets/chat/chat.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,6 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="zammad-chat-agent zammad-chat-is-hidden">
|
||||
|
||||
</div>
|
||||
<div class="zammad-chat-welcome">
|
||||
<svg class="zammad-chat-icon" viewBox="0 0 24 24"><path d="M2 5C2 4 3 3 4 3h16c1 0 2 1 2 2v10C22 16 21 17 20 17H4C3 17 2 16 2 15V5zM12 17l6 4v-4h-6z" fill-rule="evenodd"/></svg>
|
||||
|
@ -17,7 +16,7 @@
|
|||
</div>
|
||||
<div class="zammad-chat-body"></div>
|
||||
<form class="zammad-chat-controls">
|
||||
<textarea class="zammad-chat-input" rows="1" placeholder="Compose your message..."></textarea>
|
||||
<button type="submit" class="zammad-chat-send">Send</button>
|
||||
<textarea class="zammad-chat-input" rows="1" placeholder="<%- @T('Compose your message...') %>"></textarea>
|
||||
<button type="submit" class="zammad-chat-send"><%- @T('Send') %></button>
|
||||
</form>
|
||||
</div>
|
|
@ -5,7 +5,7 @@
|
|||
<span class="zammad-chat-loading-circle"></span>
|
||||
<span class="zammad-chat-loading-circle"></span>
|
||||
</span>
|
||||
Leider sind gerade alle Mitarbeiter belegt.<br>
|
||||
Warteliste-Position: <strong><%= @position %></strong>
|
||||
<%- @T('All colleges are busy.') %><br>
|
||||
<%- @T('You are on waiting list position <strong>%s</strong>.', @position) %>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in a new issue