chat client: port scroll-hint from customer chat
This commit is contained in:
parent
21224200b4
commit
b7a2ba06f1
6 changed files with 186 additions and 74 deletions
|
@ -158,6 +158,7 @@ do($ = window.jQuery, window) ->
|
|||
buttonClass: 'open-zammad-chat'
|
||||
inactiveClass: 'is-inactive'
|
||||
title: '<strong>Chat</strong> with us!'
|
||||
scrollHint: 'Scrolle nach unten um neue Nachrichten zu sehen'
|
||||
idleTimeout: 6
|
||||
idleTimeoutIntervallCheck: 0.5
|
||||
inactiveTimeout: 8
|
||||
|
@ -180,6 +181,7 @@ do($ = window.jQuery, window) ->
|
|||
translations:
|
||||
de:
|
||||
'<strong>Chat</strong> with us!': '<strong>Chatte</strong> mit uns!'
|
||||
'Scroll down to see new messages': 'Scrolle nach unten um neue Nachrichten zu sehen'
|
||||
'Online': 'Online'
|
||||
'Online': 'Online'
|
||||
'Offline': 'Offline'
|
||||
|
@ -194,6 +196,8 @@ do($ = window.jQuery, window) ->
|
|||
'Since you didn\'t respond in the last %s minutes your conversation with <strong>%s</strong> got closed.': 'Da Sie in den letzten %s Minuten nichts geschrieben haben wurde Ihre Konversation mit <strong>%s</strong> geschlossen.'
|
||||
'Since you didn\'t respond in the last %s minutes your conversation got closed.': 'Da Sie in den letzten %s Minuten nichts geschrieben haben wurde Ihre Konversation geschlossen.'
|
||||
sessionId: undefined
|
||||
scrolledToBottom: true
|
||||
scrollSnapTolerance: 10
|
||||
|
||||
T: (string, items...) =>
|
||||
if @options.lang && @options.lang isnt 'en'
|
||||
|
@ -295,7 +299,8 @@ do($ = window.jQuery, window) ->
|
|||
|
||||
renderBase: ->
|
||||
@el = $(@view('chat')(
|
||||
title: @options.title
|
||||
title: @options.title,
|
||||
scrollHint: @options.scrollHint
|
||||
))
|
||||
@options.target.append @el
|
||||
|
||||
|
@ -305,6 +310,8 @@ do($ = window.jQuery, window) ->
|
|||
@el.find('.js-chat-open').click @open
|
||||
@el.find('.js-chat-toggle').click @toggle
|
||||
@el.find('.zammad-chat-controls').on 'submit', @onSubmit
|
||||
@el.find('.zammad-chat-body').on 'scroll', @detectScrolledtoBottom
|
||||
@el.find('.zammad-scroll-hint').click @onScrollHintClick
|
||||
@input.on
|
||||
keydown: @checkForEnter
|
||||
input: @onInput
|
||||
|
@ -503,11 +510,12 @@ do($ = window.jQuery, window) ->
|
|||
id: data.id
|
||||
from: 'agent'
|
||||
|
||||
@scrollToBottom showHint: true
|
||||
|
||||
renderMessage: (data) =>
|
||||
@lastAddedType = "message--#{ data.from }"
|
||||
data.unreadClass = if document.hidden then ' zammad-chat-message--unread' else ''
|
||||
@el.find('.zammad-chat-body').append @view('message')(data)
|
||||
@scrollToBottom()
|
||||
|
||||
open: =>
|
||||
if @isOpen
|
||||
|
@ -717,8 +725,25 @@ do($ = window.jQuery, window) ->
|
|||
|
||||
@scrollToBottom()
|
||||
|
||||
scrollToBottom: ->
|
||||
@el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'))
|
||||
detectScrolledtoBottom: =>
|
||||
scrollBottom = @el.find('.zammad-chat-body').scrollTop() + @el.find('.zammad-chat-body').outerHeight()
|
||||
@scrolledToBottom = Math.abs(scrollBottom - @el.find('.zammad-chat-body').prop('scrollHeight')) <= @scrollSnapTolerance
|
||||
@el.find('.zammad-scroll-hint').addClass('is-hidden') if @scrolledToBottom
|
||||
|
||||
showScrollHint: ->
|
||||
@el.find('.zammad-scroll-hint').removeClass('is-hidden')
|
||||
# compensate scroll
|
||||
@el.find('.zammad-chat-body').scrollTop(@el.find('.zammad-chat-body').scrollTop() + @el.find('.zammad-scroll-hint').outerHeight())
|
||||
|
||||
onScrollHintClick: =>
|
||||
# animate scroll
|
||||
@el.find('.zammad-chat-body').animate({scrollTop: @el.find('.zammad-chat-body').prop('scrollHeight')}, 300)
|
||||
|
||||
scrollToBottom: ({ showHint } = { showHint: false }) ->
|
||||
if @scrolledToBottom
|
||||
@el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'))
|
||||
else if showHint
|
||||
@showScrollHint()
|
||||
|
||||
destroy: (params = {}) =>
|
||||
@log.debug 'destroy widget', params
|
||||
|
|
|
@ -191,6 +191,25 @@
|
|||
margin-right: 8px;
|
||||
vertical-align: middle; }
|
||||
|
||||
.zammad-scroll-hint {
|
||||
background: #f9fafa;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
padding: 7px 10px 6px;
|
||||
color: #999999;
|
||||
cursor: pointer; }
|
||||
.zammad-scroll-hint.is-hidden {
|
||||
display: none; }
|
||||
|
||||
.zammad-scroll-hint-icon {
|
||||
fill: #c4c7ca;
|
||||
margin-right: 8px; }
|
||||
|
||||
.zammad-chat-body {
|
||||
padding: 0.5em 1em;
|
||||
overflow: auto;
|
||||
|
|
|
@ -271,6 +271,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
buttonClass: 'open-zammad-chat',
|
||||
inactiveClass: 'is-inactive',
|
||||
title: '<strong>Chat</strong> with us!',
|
||||
scrollHint: 'Scrolle nach unten um neue Nachrichten zu sehen',
|
||||
idleTimeout: 6,
|
||||
idleTimeoutIntervallCheck: 0.5,
|
||||
inactiveTimeout: 8,
|
||||
|
@ -306,6 +307,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
ZammadChat.prototype.translations = {
|
||||
de: {
|
||||
'<strong>Chat</strong> with us!': '<strong>Chatte</strong> mit uns!',
|
||||
'Scroll down to see new messages': 'Scrolle nach unten um neue Nachrichten zu sehen',
|
||||
'Online': 'Online',
|
||||
'Online': 'Online',
|
||||
'Offline': 'Offline',
|
||||
|
@ -324,6 +326,10 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
|
||||
ZammadChat.prototype.sessionId = void 0;
|
||||
|
||||
ZammadChat.prototype.scrolledToBottom = true;
|
||||
|
||||
ZammadChat.prototype.scrollSnapTolerance = 10;
|
||||
|
||||
ZammadChat.prototype.T = function() {
|
||||
var i, item, items, len, string, translations;
|
||||
string = arguments[0], items = 2 <= arguments.length ? slice.call(arguments, 1) : [];
|
||||
|
@ -371,6 +377,8 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
this.onConnectionReestablished = bind(this.onConnectionReestablished, this);
|
||||
this.reconnect = bind(this.reconnect, this);
|
||||
this.destroy = bind(this.destroy, this);
|
||||
this.onScrollHintClick = bind(this.onScrollHintClick, this);
|
||||
this.detectScrolledtoBottom = bind(this.detectScrolledtoBottom, this);
|
||||
this.onLeaveTemporary = bind(this.onLeaveTemporary, this);
|
||||
this.onAgentTypingEnd = bind(this.onAgentTypingEnd, this);
|
||||
this.onAgentTypingStart = bind(this.onAgentTypingStart, this);
|
||||
|
@ -471,13 +479,16 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
|
||||
ZammadChat.prototype.renderBase = function() {
|
||||
this.el = $(this.view('chat')({
|
||||
title: this.options.title
|
||||
title: this.options.title,
|
||||
scrollHint: this.options.scrollHint
|
||||
}));
|
||||
this.options.target.append(this.el);
|
||||
this.input = this.el.find('.zammad-chat-input');
|
||||
this.el.find('.js-chat-open').click(this.open);
|
||||
this.el.find('.js-chat-toggle').click(this.toggle);
|
||||
this.el.find('.zammad-chat-controls').on('submit', this.onSubmit);
|
||||
this.el.find('.zammad-chat-body').on('scroll', this.detectScrolledtoBottom);
|
||||
this.el.find('.zammad-scroll-hint').click(this.onScrollHintClick);
|
||||
this.input.on({
|
||||
keydown: this.checkForEnter,
|
||||
input: this.onInput
|
||||
|
@ -712,18 +723,20 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
this.inactiveTimeout.start();
|
||||
this.onAgentTypingEnd();
|
||||
this.maybeAddTimestamp();
|
||||
return this.renderMessage({
|
||||
this.renderMessage({
|
||||
message: data.message.content,
|
||||
id: data.id,
|
||||
from: 'agent'
|
||||
});
|
||||
return this.scrollToBottom({
|
||||
showHint: true
|
||||
});
|
||||
};
|
||||
|
||||
ZammadChat.prototype.renderMessage = function(data) {
|
||||
this.lastAddedType = "message--" + data.from;
|
||||
data.unreadClass = document.hidden ? ' zammad-chat-message--unread' : '';
|
||||
this.el.find('.zammad-chat-body').append(this.view('message')(data));
|
||||
return this.scrollToBottom();
|
||||
return this.el.find('.zammad-chat-body').append(this.view('message')(data));
|
||||
};
|
||||
|
||||
ZammadChat.prototype.open = function() {
|
||||
|
@ -955,8 +968,36 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
return this.scrollToBottom();
|
||||
};
|
||||
|
||||
ZammadChat.prototype.scrollToBottom = function() {
|
||||
return this.el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'));
|
||||
ZammadChat.prototype.detectScrolledtoBottom = function() {
|
||||
var scrollBottom;
|
||||
scrollBottom = this.el.find('.zammad-chat-body').scrollTop() + this.el.find('.zammad-chat-body').outerHeight();
|
||||
this.scrolledToBottom = Math.abs(scrollBottom - this.el.find('.zammad-chat-body').prop('scrollHeight')) <= this.scrollSnapTolerance;
|
||||
if (this.scrolledToBottom) {
|
||||
return this.el.find('.zammad-scroll-hint').addClass('is-hidden');
|
||||
}
|
||||
};
|
||||
|
||||
ZammadChat.prototype.showScrollHint = function() {
|
||||
this.el.find('.zammad-scroll-hint').removeClass('is-hidden');
|
||||
return this.el.find('.zammad-chat-body').scrollTop(this.el.find('.zammad-chat-body').scrollTop() + this.el.find('.zammad-scroll-hint').outerHeight());
|
||||
};
|
||||
|
||||
ZammadChat.prototype.onScrollHintClick = function() {
|
||||
return this.el.find('.zammad-chat-body').animate({
|
||||
scrollTop: this.el.find('.zammad-chat-body').prop('scrollHeight')
|
||||
}, 300);
|
||||
};
|
||||
|
||||
ZammadChat.prototype.scrollToBottom = function(arg) {
|
||||
var showHint;
|
||||
showHint = (arg != null ? arg : {
|
||||
showHint: false
|
||||
}).showHint;
|
||||
if (this.scrolledToBottom) {
|
||||
return this.el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'));
|
||||
} else if (showHint) {
|
||||
return this.showScrollHint();
|
||||
}
|
||||
};
|
||||
|
||||
ZammadChat.prototype.destroy = function(params) {
|
||||
|
@ -1234,67 +1275,6 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
|
|||
return window.ZammadChat = ZammadChat;
|
||||
})(window.jQuery, window);
|
||||
|
||||
if (!window.zammadChatTemplates) {
|
||||
window.zammadChatTemplates = {};
|
||||
}
|
||||
window.zammadChatTemplates["agent"] = function (__obj) {
|
||||
if (!__obj) __obj = {};
|
||||
var __out = [], __capture = function(callback) {
|
||||
var out = __out, result;
|
||||
__out = [];
|
||||
callback.call(this);
|
||||
result = __out.join('');
|
||||
__out = out;
|
||||
return __safe(result);
|
||||
}, __sanitize = function(value) {
|
||||
if (value && value.ecoSafe) {
|
||||
return value;
|
||||
} else if (typeof value !== 'undefined' && value != null) {
|
||||
return __escape(value);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}, __safe, __objSafe = __obj.safe, __escape = __obj.escape;
|
||||
__safe = __obj.safe = function(value) {
|
||||
if (value && value.ecoSafe) {
|
||||
return value;
|
||||
} else {
|
||||
if (!(typeof value !== 'undefined' && value != null)) value = '';
|
||||
var result = new String(value);
|
||||
result.ecoSafe = true;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
if (!__escape) {
|
||||
__escape = __obj.escape = function(value) {
|
||||
return ('' + value)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.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>\n</span>');
|
||||
|
||||
}).call(this);
|
||||
|
||||
}).call(__obj);
|
||||
__obj.safe = __objSafe, __obj.escape = __escape;
|
||||
return __out.join('');
|
||||
};
|
||||
|
||||
/*!
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
|
@ -1380,6 +1360,67 @@ 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>\n</span>');
|
||||
|
||||
}).call(this);
|
||||
|
||||
}).call(__obj);
|
||||
__obj.safe = __objSafe, __obj.escape = __escape;
|
||||
return __out.join('');
|
||||
};
|
||||
|
||||
if (!window.zammadChatTemplates) {
|
||||
window.zammadChatTemplates = {};
|
||||
}
|
||||
|
@ -1444,7 +1485,11 @@ window.zammadChatTemplates["chat"] = function (__obj) {
|
|||
|
||||
__out.push(this.T(this.title));
|
||||
|
||||
__out.push('</span>\n </div>\n </div>\n <div class="zammad-chat-modal"></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('</span>\n </div>\n </div>\n <div class="zammad-chat-modal"></div>\n <div class="zammad-scroll-hint is-hidden">\n <svg class="zammad-scroll-hint-icon" width="20" height="18" viewBox="0 0 20 18"><path d="M0,2.00585866 C0,0.898053512 0.898212381,0 1.99079514,0 L18.0092049,0 C19.1086907,0 20,0.897060126 20,2.00585866 L20,11.9941413 C20,13.1019465 19.1017876,14 18.0092049,14 L1.99079514,14 C0.891309342,14 0,13.1029399 0,11.9941413 L0,2.00585866 Z M10,14 L16,18 L16,14 L10,14 Z" fill-rule="evenodd"/></svg>\n ');
|
||||
|
||||
__out.push(this.T(this.scrollHint));
|
||||
|
||||
__out.push('\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...'));
|
||||
|
||||
|
|
4
public/assets/chat/chat.min.js
vendored
4
public/assets/chat/chat.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -200,6 +200,25 @@
|
|||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.zammad-scroll-hint {
|
||||
background: hsl(210,8%,98%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid hsl(0,0%,91%);
|
||||
padding: 7px 10px 6px;
|
||||
color: hsl(0,0%,60%);
|
||||
cursor: pointer;
|
||||
|
||||
&.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.zammad-scroll-hint-icon {
|
||||
fill: hsl(210,5%,78%);
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.zammad-chat-body {
|
||||
padding: 0.5em 1em;
|
||||
overflow: auto;
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="zammad-chat-modal"></div>
|
||||
<div class="zammad-scroll-hint is-hidden">
|
||||
<svg class="zammad-scroll-hint-icon" width="20" height="18" viewBox="0 0 20 18"><path d="M0,2.00585866 C0,0.898053512 0.898212381,0 1.99079514,0 L18.0092049,0 C19.1086907,0 20,0.897060126 20,2.00585866 L20,11.9941413 C20,13.1019465 19.1017876,14 18.0092049,14 L1.99079514,14 C0.891309342,14 0,13.1029399 0,11.9941413 L0,2.00585866 Z M10,14 L16,18 L16,14 L10,14 Z" fill-rule="evenodd"/></svg>
|
||||
<%- @T(@scrollHint) %>
|
||||
</div>
|
||||
<div class="zammad-chat-body"></div>
|
||||
<form class="zammad-chat-controls">
|
||||
<textarea class="zammad-chat-input" rows="1" placeholder="<%- @T('Compose your message...') %>"></textarea>
|
||||
|
|
Loading…
Reference in a new issue