chat: add waiting screen, outsource agent view, add basic socket communication
This commit is contained in:
parent
d67bae2005
commit
806ffb70c7
9 changed files with 489 additions and 98 deletions
|
@ -5,10 +5,11 @@ do($ = window.jQuery, window) ->
|
|||
|
||||
defaults:
|
||||
invitationPhrase: '<strong>Chat</strong> with us!'
|
||||
agentPhrase: '%%agent%% is helping you'
|
||||
agentPhrase: ' is helping you'
|
||||
show: true
|
||||
target: $('body')
|
||||
|
||||
_messageCount: 0
|
||||
isOpen: false
|
||||
blinkOnlineInterval: null
|
||||
stopBlinOnlineStateTimeout: null
|
||||
|
@ -25,15 +26,20 @@ do($ = window.jQuery, window) ->
|
|||
'Connection re-established': 'Connection re-established'
|
||||
'Today': 'Today'
|
||||
|
||||
T: (string) ->
|
||||
T: (string) =>
|
||||
return @strings[string]
|
||||
|
||||
view: (name) ->
|
||||
return window.zammadChatTemplates[name]
|
||||
view: (name) =>
|
||||
return (options) =>
|
||||
if !options
|
||||
options = {}
|
||||
|
||||
options.T = @T
|
||||
return window.zammadChatTemplates[name](options)
|
||||
|
||||
constructor: (el, options) ->
|
||||
@options = $.extend {}, @defaults, options
|
||||
@el = $(@view('chat')())
|
||||
@el = $(@view('chat')(@options))
|
||||
@options.target.append @el
|
||||
|
||||
@setAgentOnlineState @isOnline
|
||||
|
@ -46,19 +52,18 @@ do($ = window.jQuery, window) ->
|
|||
).autoGrow { extraLine: false }
|
||||
|
||||
if !window.WebSocket
|
||||
console.log('no websockets available')
|
||||
console.log('Zammad Chat: Browser not supported')
|
||||
return
|
||||
|
||||
zammad_host = 'ws://localhost:6042'
|
||||
@ws = new window.WebSocket(zammad_host)
|
||||
console.log("connecting ws #{zammad_host}")
|
||||
console.log("Connecting to #{zammad_host}")
|
||||
|
||||
@ws.onopen = =>
|
||||
console.log('ws connected')
|
||||
@send "chat_status"
|
||||
|
||||
@ws.onmessage = (e) =>
|
||||
pipe = JSON.parse( e.data )
|
||||
console.log 'debug', 'ws:onmessage', pipe
|
||||
@ws.onmessage = @onWebSocketMessage
|
||||
|
||||
@ws.onclose = (e) =>
|
||||
console.log 'debug', 'close websocket connection'
|
||||
|
@ -71,6 +76,44 @@ do($ = window.jQuery, window) ->
|
|||
event.preventDefault()
|
||||
@sendMessage()
|
||||
|
||||
send: (action, data) =>
|
||||
pipe = JSON.stringify
|
||||
action: action
|
||||
data: data
|
||||
|
||||
@ws.send pipe
|
||||
|
||||
onWebSocketMessage: (e) =>
|
||||
pipe = JSON.parse( e.data )
|
||||
console.log 'debug', 'ws:onmessage', pipe
|
||||
|
||||
switch pipe.action
|
||||
when 'message'
|
||||
@receiveMessage pipe.data
|
||||
when 'typing_start'
|
||||
@onAgentTypingStart()
|
||||
when 'typing_end'
|
||||
@onAgentTypingEnd()
|
||||
when 'chat_init'
|
||||
switch pipe.data.state
|
||||
when 'ok'
|
||||
@onConnectionEstablished pipe.data.agent
|
||||
when 'queue'
|
||||
@onQueue pipe.data.position
|
||||
when 'chat_status'
|
||||
switch pipe.data.state
|
||||
when 'ok'
|
||||
@onReady()
|
||||
when 'offline'
|
||||
console.log 'Zammad Chat: No agent online'
|
||||
when 'chat_disabled'
|
||||
console.log 'Zammad Chat: Chat is disabled'
|
||||
when 'no_seats_available'
|
||||
console.log 'Zammad Chat: Too many clients in queue. Clients in queue: ', pipe.data.queue
|
||||
|
||||
onReady: =>
|
||||
@show() if @options.show
|
||||
|
||||
onInput: =>
|
||||
# remove unread-state from messages
|
||||
@el.find('.zammad-chat-message--unread')
|
||||
|
@ -86,10 +129,12 @@ do($ = window.jQuery, window) ->
|
|||
onTypingStart: ->
|
||||
# send typing start event
|
||||
@isTyping = true
|
||||
@send 'typing_start'
|
||||
|
||||
onTypingEnd: =>
|
||||
# send typing end event
|
||||
@isTyping = false
|
||||
@send 'typing_end'
|
||||
|
||||
onSubmit: (event) =>
|
||||
event.preventDefault()
|
||||
|
@ -98,28 +143,35 @@ do($ = window.jQuery, window) ->
|
|||
sendMessage: ->
|
||||
message = @el.find('.zammad-chat-input').val()
|
||||
|
||||
if message
|
||||
messageElement = @view('message')
|
||||
message: message
|
||||
from: 'customer'
|
||||
if !message
|
||||
return
|
||||
|
||||
@maybeAddTimestamp()
|
||||
messageElement = @view('message')
|
||||
message: message
|
||||
from: 'customer'
|
||||
id: @_messageCount++
|
||||
|
||||
# add message before message typing loader
|
||||
if @el.find('.zammad-chat-message--typing').size()
|
||||
@lastAddedType = 'typing-placeholder'
|
||||
@el.find('.zammad-chat-message--typing').before messageElement
|
||||
else
|
||||
@lastAddedType = 'message--customer'
|
||||
@el.find('.zammad-chat-body').append messageElement
|
||||
@maybeAddTimestamp()
|
||||
|
||||
@el.find('.zammad-chat-input').val('')
|
||||
@scrollToBottom()
|
||||
# add message before message typing loader
|
||||
if @el.find('.zammad-chat-message--typing').size()
|
||||
@lastAddedType = 'typing-placeholder'
|
||||
@el.find('.zammad-chat-message--typing').before messageElement
|
||||
else
|
||||
@lastAddedType = 'message--customer'
|
||||
@el.find('.zammad-chat-body').append messageElement
|
||||
|
||||
@isTyping = false
|
||||
# send message event
|
||||
@el.find('.zammad-chat-input').val('')
|
||||
@scrollToBottom()
|
||||
|
||||
receiveMessage: (message) =>
|
||||
@isTyping = false
|
||||
|
||||
# send message event
|
||||
@send 'message',
|
||||
body: message
|
||||
id: @_messageCount
|
||||
|
||||
receiveMessage: (data) =>
|
||||
# hide writing indicator
|
||||
@onAgentTypingEnd()
|
||||
|
||||
|
@ -128,7 +180,8 @@ do($ = window.jQuery, window) ->
|
|||
@lastAddedType = 'message--agent'
|
||||
unread = document.hidden ? " zammad-chat-message--unread" : ""
|
||||
@el.find('.zammad-chat-body').append @view('message')
|
||||
message: message
|
||||
message: data.body
|
||||
id: data.id
|
||||
from: 'agent'
|
||||
@scrollToBottom()
|
||||
|
||||
|
@ -136,15 +189,18 @@ do($ = window.jQuery, window) ->
|
|||
if @isOpen then @close() else @open()
|
||||
|
||||
open: ->
|
||||
@showLoader()
|
||||
|
||||
@el
|
||||
.addClass('zammad-chat-is-open')
|
||||
.animate { bottom: 0 }, 500, @onOpenAnimationEnd
|
||||
|
||||
onOpenAnimationEnd: =>
|
||||
@isOpen = true
|
||||
setTimeout @onConnectionEstablished, 1180
|
||||
setTimeout @onAgentTypingStart, 2000
|
||||
setTimeout @receiveMessage, 5000, "Hello! How can I help you?"
|
||||
#setTimeout @onQueue, 1180
|
||||
# setTimeout @onConnectionEstablished, 1180
|
||||
# setTimeout @onAgentTypingStart, 2000
|
||||
# setTimeout @receiveMessage, 5000, "Hello! How can I help you?"
|
||||
@connect()
|
||||
|
||||
close: ->
|
||||
|
@ -166,8 +222,15 @@ do($ = window.jQuery, window) ->
|
|||
|
||||
@el.css 'bottom', -remainerHeight
|
||||
|
||||
onQueue: (position) =>
|
||||
console.log "onQueue", position
|
||||
@inQueue = true
|
||||
|
||||
@el.find('.zammad-chat-body').html @view('waiting')
|
||||
position: position
|
||||
|
||||
onAgentTypingStart: =>
|
||||
# never display two loaders
|
||||
# never display two typing indicators
|
||||
return if @el.find('.zammad-chat-message--typing').size()
|
||||
|
||||
@maybeAddTimestamp()
|
||||
|
@ -212,7 +275,7 @@ do($ = window.jQuery, window) ->
|
|||
@el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'))
|
||||
|
||||
connect: ->
|
||||
|
||||
@send('chat_init')
|
||||
|
||||
reconnect: =>
|
||||
# set status to connecting
|
||||
|
@ -227,17 +290,26 @@ do($ = window.jQuery, window) ->
|
|||
@addStatus @T('Connection re-established')
|
||||
|
||||
disconnect: ->
|
||||
@el.find('.zammad-chat-loader').removeClass('zammad-chat-is-hidden');
|
||||
@el.find('.zammad-chat-welcome').removeClass('zammad-chat-is-hidden');
|
||||
@el.find('.zammad-chat-agent').addClass('zammad-chat-is-hidden');
|
||||
@el.find('.zammad-chat-agent-status').addClass('zammad-chat-is-hidden');
|
||||
@showLoader()
|
||||
@el.find('.zammad-chat-welcome').removeClass('zammad-chat-is-hidden')
|
||||
@el.find('.zammad-chat-agent').addClass('zammad-chat-is-hidden')
|
||||
@el.find('.zammad-chat-agent-status').addClass('zammad-chat-is-hidden')
|
||||
|
||||
onConnectionEstablished: =>
|
||||
@el.find('.zammad-chat-loader').addClass('zammad-chat-is-hidden');
|
||||
@el.find('.zammad-chat-welcome').addClass('zammad-chat-is-hidden');
|
||||
@el.find('.zammad-chat-agent').removeClass('zammad-chat-is-hidden');
|
||||
@el.find('.zammad-chat-agent-status').removeClass('zammad-chat-is-hidden');
|
||||
@el.find('.zammad-chat-input').focus();
|
||||
onConnectionEstablished: (agent) =>
|
||||
@inQueue = false
|
||||
@agent = agent
|
||||
|
||||
@el.find('.zammad-chat-agent').html @view('agent')
|
||||
agent: agent
|
||||
|
||||
@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')
|
||||
@el.find('.zammad-chat-agent-status').removeClass('zammad-chat-is-hidden')
|
||||
@el.find('.zammad-chat-input').focus()
|
||||
|
||||
showLoader: ->
|
||||
@el.find('.zammad-chat-body').html @view('loader')()
|
||||
|
||||
setAgentOnlineState: (state) =>
|
||||
@isOnline = state
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
if (!window.zammadChatTemplates) {
|
||||
window.zammadChatTemplates = {};
|
||||
}
|
||||
window.zammadChatTemplates["chat"] = function (__obj) {
|
||||
window.zammadChatTemplates["agent"] = function (__obj) {
|
||||
if (!__obj) __obj = {};
|
||||
var __out = [], __capture = function(callback) {
|
||||
var out = __out, result;
|
||||
|
@ -40,7 +40,19 @@ window.zammadChatTemplates["chat"] = function (__obj) {
|
|||
}
|
||||
(function() {
|
||||
(function() {
|
||||
__out.push('<div class="zammad-chat">\n <div class="zammad-chat-header">\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-toggle">\n <svg class="zammad-chat-toggle-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-toggle-icon-close" viewBox="0 0 13 7"><path d="M6.554 4.214L2.246 0l-1.4 1.428 5 4.9.708.693.7-.7 4.9-4.9L10.74.008 6.553 4.214z" fill-rule="evenodd"/></svg>\n </span>\n </div>\n <div class="zammad-chat-agent zammad-chat-is-hidden">\n <img class="zammad-chat-agent-avatar" src="https://s3.amazonaws.com/uifaces/faces/twitter/joshaustin/128.jpg">\n <span class="zammad-chat-agent-sentence">\n <span class="zammad-chat-agent-name">Adam</span> is helping you.\n </span>\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"><strong>Chat</strong> with us!</span>\n </div>\n </div>\n <div class="zammad-chat-loader">\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 <span class="zammad-chat-loader-text">Connecting</span>\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('<img class="zammad-chat-agent-avatar" src="');
|
||||
|
||||
__out.push(__sanitize(this.agent.avatar));
|
||||
|
||||
__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);
|
||||
|
||||
|
@ -56,11 +68,13 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
ZammadChat = (function() {
|
||||
ZammadChat.prototype.defaults = {
|
||||
invitationPhrase: '<strong>Chat</strong> with us!',
|
||||
agentPhrase: '%%agent%% is helping you',
|
||||
agentPhrase: ' is helping you',
|
||||
show: true,
|
||||
target: $('body')
|
||||
};
|
||||
|
||||
ZammadChat.prototype._messageCount = 0;
|
||||
|
||||
ZammadChat.prototype.isOpen = false;
|
||||
|
||||
ZammadChat.prototype.blinkOnlineInterval = null;
|
||||
|
@ -92,7 +106,15 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
};
|
||||
|
||||
ZammadChat.prototype.view = function(name) {
|
||||
return window.zammadChatTemplates[name];
|
||||
return (function(_this) {
|
||||
return function(options) {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
options.T = _this.T;
|
||||
return window.zammadChatTemplates[name](options);
|
||||
};
|
||||
})(this);
|
||||
};
|
||||
|
||||
function ZammadChat(el, options) {
|
||||
|
@ -102,6 +124,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
this.reconnect = bind(this.reconnect, this);
|
||||
this.onAgentTypingEnd = bind(this.onAgentTypingEnd, this);
|
||||
this.onAgentTypingStart = bind(this.onAgentTypingStart, this);
|
||||
this.onQueue = bind(this.onQueue, this);
|
||||
this.onCloseAnimationEnd = bind(this.onCloseAnimationEnd, this);
|
||||
this.onOpenAnimationEnd = bind(this.onOpenAnimationEnd, this);
|
||||
this.toggle = bind(this.toggle, this);
|
||||
|
@ -109,9 +132,15 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
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 zammad_host;
|
||||
this.options = $.extend({}, this.defaults, options);
|
||||
this.el = $(this.view('chat')());
|
||||
this.el = $(this.view('chat')(this.options));
|
||||
this.options.target.append(this.el);
|
||||
this.setAgentOnlineState(this.isOnline);
|
||||
this.el.find('.zammad-chat-header').click(this.toggle);
|
||||
|
@ -122,6 +151,30 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
}).autoGrow({
|
||||
extraLine: false
|
||||
});
|
||||
if (!window.WebSocket) {
|
||||
console.log('Zammad 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");
|
||||
};
|
||||
})(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);
|
||||
}
|
||||
|
||||
ZammadChat.prototype.checkForEnter = function(event) {
|
||||
|
@ -131,6 +184,54 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
}
|
||||
};
|
||||
|
||||
ZammadChat.prototype.send = function(action, data) {
|
||||
var pipe;
|
||||
pipe = JSON.stringify({
|
||||
action: action,
|
||||
data: data
|
||||
});
|
||||
return this.ws.send(pipe);
|
||||
};
|
||||
|
||||
ZammadChat.prototype.onWebSocketMessage = function(e) {
|
||||
var pipe;
|
||||
pipe = JSON.parse(e.data);
|
||||
console.log('debug', 'ws:onmessage', pipe);
|
||||
switch (pipe.action) {
|
||||
case 'message':
|
||||
return this.receiveMessage(pipe.data);
|
||||
case 'typing_start':
|
||||
return this.onAgentTypingStart();
|
||||
case 'typing_end':
|
||||
return this.onAgentTypingEnd();
|
||||
case 'chat_init':
|
||||
switch (pipe.data.state) {
|
||||
case 'ok':
|
||||
return this.onConnectionEstablished(pipe.data.agent);
|
||||
case 'queue':
|
||||
return this.onQueue(pipe.data.position);
|
||||
}
|
||||
break;
|
||||
case 'chat_status':
|
||||
switch (pipe.data.state) {
|
||||
case 'ok':
|
||||
return this.onReady();
|
||||
case 'offline':
|
||||
return console.log('Zammad Chat: No agent online');
|
||||
case 'chat_disabled':
|
||||
return console.log('Zammad Chat: Chat is disabled');
|
||||
case 'no_seats_available':
|
||||
return console.log('Zammad Chat: Too many clients in queue. Clients in queue: ', pipe.data.queue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ZammadChat.prototype.onReady = function() {
|
||||
if (this.options.show) {
|
||||
return this.show();
|
||||
}
|
||||
};
|
||||
|
||||
ZammadChat.prototype.onInput = function() {
|
||||
this.el.find('.zammad-chat-message--unread').removeClass('zammad-chat-message--unread');
|
||||
if (this.inputTimeout) {
|
||||
|
@ -143,11 +244,13 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
};
|
||||
|
||||
ZammadChat.prototype.onTypingStart = function() {
|
||||
return this.isTyping = true;
|
||||
this.isTyping = true;
|
||||
return this.send('typing_start');
|
||||
};
|
||||
|
||||
ZammadChat.prototype.onTypingEnd = function() {
|
||||
return this.isTyping = false;
|
||||
this.isTyping = false;
|
||||
return this.send('typing_end');
|
||||
};
|
||||
|
||||
ZammadChat.prototype.onSubmit = function(event) {
|
||||
|
@ -158,26 +261,32 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
ZammadChat.prototype.sendMessage = function() {
|
||||
var message, messageElement;
|
||||
message = this.el.find('.zammad-chat-input').val();
|
||||
if (message) {
|
||||
messageElement = this.view('message')({
|
||||
message: message,
|
||||
from: 'customer'
|
||||
});
|
||||
this.maybeAddTimestamp();
|
||||
if (this.el.find('.zammad-chat-message--typing').size()) {
|
||||
this.lastAddedType = 'typing-placeholder';
|
||||
this.el.find('.zammad-chat-message--typing').before(messageElement);
|
||||
} else {
|
||||
this.lastAddedType = 'message--customer';
|
||||
this.el.find('.zammad-chat-body').append(messageElement);
|
||||
}
|
||||
this.el.find('.zammad-chat-input').val('');
|
||||
this.scrollToBottom();
|
||||
return this.isTyping = false;
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
messageElement = this.view('message')({
|
||||
message: message,
|
||||
from: 'customer',
|
||||
id: this._messageCount++
|
||||
});
|
||||
this.maybeAddTimestamp();
|
||||
if (this.el.find('.zammad-chat-message--typing').size()) {
|
||||
this.lastAddedType = 'typing-placeholder';
|
||||
this.el.find('.zammad-chat-message--typing').before(messageElement);
|
||||
} else {
|
||||
this.lastAddedType = 'message--customer';
|
||||
this.el.find('.zammad-chat-body').append(messageElement);
|
||||
}
|
||||
this.el.find('.zammad-chat-input').val('');
|
||||
this.scrollToBottom();
|
||||
this.isTyping = false;
|
||||
return this.send('message', {
|
||||
body: message,
|
||||
id: this._messageCount
|
||||
});
|
||||
};
|
||||
|
||||
ZammadChat.prototype.receiveMessage = function(message) {
|
||||
ZammadChat.prototype.receiveMessage = function(data) {
|
||||
var ref, unread;
|
||||
this.onAgentTypingEnd();
|
||||
this.maybeAddTimestamp();
|
||||
|
@ -186,7 +295,8 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
" zammad-chat-message--unread": ""
|
||||
};
|
||||
this.el.find('.zammad-chat-body').append(this.view('message')({
|
||||
message: message,
|
||||
message: data.body,
|
||||
id: data.id,
|
||||
from: 'agent'
|
||||
}));
|
||||
return this.scrollToBottom();
|
||||
|
@ -201,6 +311,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
};
|
||||
|
||||
ZammadChat.prototype.open = function() {
|
||||
this.showLoader();
|
||||
return this.el.addClass('zammad-chat-is-open').animate({
|
||||
bottom: 0
|
||||
}, 500, this.onOpenAnimationEnd);
|
||||
|
@ -208,9 +319,6 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
|
||||
ZammadChat.prototype.onOpenAnimationEnd = function() {
|
||||
this.isOpen = true;
|
||||
setTimeout(this.onConnectionEstablished, 1180);
|
||||
setTimeout(this.onAgentTypingStart, 2000);
|
||||
setTimeout(this.receiveMessage, 5000, "Hello! How can I help you?");
|
||||
return this.connect();
|
||||
};
|
||||
|
||||
|
@ -239,6 +347,14 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
return this.el.css('bottom', -remainerHeight);
|
||||
};
|
||||
|
||||
ZammadChat.prototype.onQueue = function(position) {
|
||||
console.log("onQueue", position);
|
||||
this.inQueue = true;
|
||||
return this.el.find('.zammad-chat-body').html(this.view('waiting')({
|
||||
position: position
|
||||
}));
|
||||
};
|
||||
|
||||
ZammadChat.prototype.onAgentTypingStart = function() {
|
||||
if (this.el.find('.zammad-chat-message--typing').size()) {
|
||||
return;
|
||||
|
@ -287,7 +403,9 @@ 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.connect = function() {
|
||||
return this.send('chat_init');
|
||||
};
|
||||
|
||||
ZammadChat.prototype.reconnect = function() {
|
||||
this.lastAddedType = 'status';
|
||||
|
@ -302,20 +420,29 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
};
|
||||
|
||||
ZammadChat.prototype.disconnect = function() {
|
||||
this.el.find('.zammad-chat-loader').removeClass('zammad-chat-is-hidden');
|
||||
this.showLoader();
|
||||
this.el.find('.zammad-chat-welcome').removeClass('zammad-chat-is-hidden');
|
||||
this.el.find('.zammad-chat-agent').addClass('zammad-chat-is-hidden');
|
||||
return this.el.find('.zammad-chat-agent-status').addClass('zammad-chat-is-hidden');
|
||||
};
|
||||
|
||||
ZammadChat.prototype.onConnectionEstablished = function() {
|
||||
this.el.find('.zammad-chat-loader').addClass('zammad-chat-is-hidden');
|
||||
ZammadChat.prototype.onConnectionEstablished = function(agent) {
|
||||
this.inQueue = false;
|
||||
this.agent = agent;
|
||||
this.el.find('.zammad-chat-agent').html(this.view('agent')({
|
||||
agent: agent
|
||||
}));
|
||||
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');
|
||||
return this.el.find('.zammad-chat-input').focus();
|
||||
};
|
||||
|
||||
ZammadChat.prototype.showLoader = function() {
|
||||
return this.el.find('.zammad-chat-body').html(this.view('loader')());
|
||||
};
|
||||
|
||||
ZammadChat.prototype.setAgentOnlineState = function(state) {
|
||||
this.isOnline = state;
|
||||
return this.el.find('.zammad-chat-agent-status').toggleClass('zammad-chat-is-online', state).text(state ? this.T('Online') : this.T('Offline'));
|
||||
|
@ -406,6 +533,116 @@ jQuery.fn.autoGrow = function(options) {
|
|||
|
||||
});
|
||||
};
|
||||
if (!window.zammadChatTemplates) {
|
||||
window.zammadChatTemplates = {};
|
||||
}
|
||||
window.zammadChatTemplates["chat"] = 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() {
|
||||
__out.push('<div class="zammad-chat">\n <div class="zammad-chat-header">\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-toggle">\n <svg class="zammad-chat-toggle-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-toggle-icon-close" viewBox="0 0 13 7"><path d="M6.554 4.214L2.246 0l-1.4 1.428 5 4.9.708.693.7-.7 4.9-4.9L10.74.008 6.553 4.214z" 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(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>');
|
||||
|
||||
}).call(this);
|
||||
|
||||
}).call(__obj);
|
||||
__obj.safe = __objSafe, __obj.escape = __escape;
|
||||
return __out.join('');
|
||||
};
|
||||
|
||||
if (!window.zammadChatTemplates) {
|
||||
window.zammadChatTemplates = {};
|
||||
}
|
||||
window.zammadChatTemplates["loader"] = 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() {
|
||||
__out.push('<div class="zammad-chat-modal">\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 <span class="zammad-chat-modal-text">');
|
||||
|
||||
__out.push(__sanitize(this.T('Connecting')));
|
||||
|
||||
__out.push('</span>\n</div>');
|
||||
|
||||
}).call(this);
|
||||
|
||||
}).call(__obj);
|
||||
__obj.safe = __objSafe, __obj.escape = __escape;
|
||||
return __out.join('');
|
||||
};
|
||||
|
||||
if (!window.zammadChatTemplates) {
|
||||
window.zammadChatTemplates = {};
|
||||
}
|
||||
|
@ -574,3 +811,58 @@ window.zammadChatTemplates["typingIndicator"] = function (__obj) {
|
|||
__obj.safe = __objSafe, __obj.escape = __escape;
|
||||
return __out.join('');
|
||||
};
|
||||
|
||||
if (!window.zammadChatTemplates) {
|
||||
window.zammadChatTemplates = {};
|
||||
}
|
||||
window.zammadChatTemplates["waiting"] = 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() {
|
||||
__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(__sanitize(this.position));
|
||||
|
||||
__out.push('</strong>\n </div>\n</div>');
|
||||
|
||||
}).call(this);
|
||||
|
||||
}).call(__obj);
|
||||
__obj.safe = __objSafe, __obj.escape = __escape;
|
||||
return __out.join('');
|
||||
};
|
||||
|
|
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
|
@ -123,7 +123,7 @@
|
|||
-webkit-transform: scale(1);
|
||||
transform: scale(1); } }
|
||||
|
||||
.zammad-chat-loader {
|
||||
.zammad-chat-modal {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
@ -144,12 +144,15 @@
|
|||
-ms-flex-pack: center;
|
||||
justify-content: center; }
|
||||
|
||||
.zammad-chat-loader-text {
|
||||
font-size: 1.3em; }
|
||||
.zammad-chat-modal-text {
|
||||
font-size: 1.3em;
|
||||
line-height: 1.45; }
|
||||
.zammad-chat-modal-text .zammad-chat-loading-animation {
|
||||
font-size: 0.7em; }
|
||||
|
||||
.zammad-chat-loader .zammad-chat-loading-animation {
|
||||
.zammad-chat-modal .zammad-chat-loading-animation {
|
||||
margin-right: 8px;
|
||||
margin-left: -19px; }
|
||||
vertical-align: middle; }
|
||||
|
||||
.zammad-chat-body {
|
||||
padding: 0.5em 1em;
|
||||
|
@ -192,6 +195,9 @@
|
|||
.zammad-chat-message--typing .zammad-chat-message-body {
|
||||
white-space: normal; }
|
||||
|
||||
.zammad-chat-loading-animation {
|
||||
display: inline-block; }
|
||||
|
||||
.zammad-chat-loading-circle {
|
||||
background: #c5dded;
|
||||
border-radius: 100%;
|
||||
|
|
|
@ -154,7 +154,7 @@ $baseTextColor: if($luminance < 0.2, white, black);
|
|||
to { opacity: 1; transform: scale(1); }
|
||||
}
|
||||
|
||||
.zammad-chat-loader {
|
||||
.zammad-chat-modal {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
@ -170,13 +170,18 @@ $baseTextColor: if($luminance < 0.2, white, black);
|
|||
justify-content: center;
|
||||
}
|
||||
|
||||
.zammad-chat-loader-text {
|
||||
.zammad-chat-modal-text {
|
||||
font-size: 1.3em;
|
||||
line-height: 1.45;
|
||||
|
||||
.zammad-chat-loading-animation {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
}
|
||||
|
||||
.zammad-chat-loader .zammad-chat-loading-animation {
|
||||
.zammad-chat-modal .zammad-chat-loading-animation {
|
||||
margin-right: 8px;
|
||||
margin-left: -19px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.zammad-chat-body {
|
||||
|
@ -232,6 +237,10 @@ $baseTextColor: if($luminance < 0.2, white, black);
|
|||
white-space: normal;
|
||||
}
|
||||
|
||||
.zammad-chat-loading-animation {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.zammad-chat-loading-circle {
|
||||
background: desaturate(lightenMax($themeColor, 50%, 85%), 15%);
|
||||
border-radius: 100%;
|
||||
|
|
4
public/assets/chat/views/agent.eco
Normal file
4
public/assets/chat/views/agent.eco
Normal file
|
@ -0,0 +1,4 @@
|
|||
<img class="zammad-chat-agent-avatar" src="<%= @agent.avatar %>">
|
||||
<span class="zammad-chat-agent-sentence">
|
||||
<span class="zammad-chat-agent-name"><%= @agent.name %></span> <%- @agentPhrase %>
|
||||
</span>
|
|
@ -8,24 +8,13 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="zammad-chat-agent zammad-chat-is-hidden">
|
||||
<img class="zammad-chat-agent-avatar" src="https://s3.amazonaws.com/uifaces/faces/twitter/joshaustin/128.jpg">
|
||||
<span class="zammad-chat-agent-sentence">
|
||||
<span class="zammad-chat-agent-name">Adam</span> is helping you.
|
||||
</span>
|
||||
|
||||
</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>
|
||||
<span class="zammad-chat-welcome-text"><strong>Chat</strong> with us!</span>
|
||||
<span class="zammad-chat-welcome-text"><%- @invitationPhrase %></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zammad-chat-loader">
|
||||
<span class="zammad-chat-loading-animation">
|
||||
<span class="zammad-chat-loading-circle"></span>
|
||||
<span class="zammad-chat-loading-circle"></span>
|
||||
<span class="zammad-chat-loading-circle"></span>
|
||||
</span>
|
||||
<span class="zammad-chat-loader-text">Connecting</span>
|
||||
</div>
|
||||
<div class="zammad-chat-body"></div>
|
||||
<form class="zammad-chat-controls">
|
||||
<textarea class="zammad-chat-input" rows="1" placeholder="Compose your message..."></textarea>
|
||||
|
|
8
public/assets/chat/views/loader.eco
Normal file
8
public/assets/chat/views/loader.eco
Normal file
|
@ -0,0 +1,8 @@
|
|||
<div class="zammad-chat-modal">
|
||||
<span class="zammad-chat-loading-animation">
|
||||
<span class="zammad-chat-loading-circle"></span>
|
||||
<span class="zammad-chat-loading-circle"></span>
|
||||
<span class="zammad-chat-loading-circle"></span>
|
||||
</span>
|
||||
<span class="zammad-chat-modal-text"><%= @T('Connecting') %></span>
|
||||
</div>
|
11
public/assets/chat/views/waiting.eco
Normal file
11
public/assets/chat/views/waiting.eco
Normal file
|
@ -0,0 +1,11 @@
|
|||
<div class="zammad-chat-modal">
|
||||
<div class="zammad-chat-modal-text">
|
||||
<span class="zammad-chat-loading-animation">
|
||||
<span class="zammad-chat-loading-circle"></span>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in a new issue