chat: add waiting screen, outsource agent view, add basic socket communication

This commit is contained in:
Felix Niklas 2015-11-02 16:48:16 +01:00
parent d67bae2005
commit 806ffb70c7
9 changed files with 489 additions and 98 deletions

View file

@ -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

View file

@ -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, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
};
}
(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, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
};
}
(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, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
};
}
(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('');
};

File diff suppressed because one or more lines are too long

View file

@ -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%;

View file

@ -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%;

View 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>

View file

@ -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>

View 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>

View 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>