[FIX] mail, web: chat window and emojis
- Fix several contexts where the emoji popover was hidden by a webclient element (control panel / ...). To solve this bug, the design has been improved to not use popover but instead use custom design (better integrated with new chatter design) - Chat window is now still usable when a modal is opened - Simplify chatter LESS
This commit is contained in:
@@ -358,6 +358,10 @@ var BasicComposer = Widget.extend(chat_mixin, {
|
||||
"click .o_attachment_delete": "on_attachment_delete",
|
||||
"click .o_attachment_download": "_onAttachmentDownload",
|
||||
"click .o_attachment_view": "_onAttachmentView",
|
||||
'click .o_composer_button_emoji': '_onEmojiButtonClick',
|
||||
'focusout .o_composer_button_emoji': '_onEmojiButtonFocusout',
|
||||
'focus .o_mail_emoji_container .o_mail_emoji': '_onEmojiImageFocus',
|
||||
'click .o_mail_emoji_container .o_mail_emoji': '_onEmojiImageClick',
|
||||
},
|
||||
// RPCs done to fetch the mention suggestions are throttled with the following value
|
||||
MENTION_THROTTLE: 200,
|
||||
@@ -420,9 +424,6 @@ var BasicComposer = Widget.extend(chat_mixin, {
|
||||
});
|
||||
}
|
||||
|
||||
// Emojis
|
||||
this.emoji_container_classname = 'o_composer_emoji';
|
||||
|
||||
this.isMini = options.isMini;
|
||||
|
||||
this.avatarURL = session.uid > 0 ? session.url('/web/image', {
|
||||
@@ -448,23 +449,6 @@ var BasicComposer = Widget.extend(chat_mixin, {
|
||||
$(window).on(this.fileupload_id, this.on_attachment_loaded);
|
||||
this.on("change:attachment_ids", this, this.render_attachments);
|
||||
|
||||
// Emoji
|
||||
this.$('.o_composer_button_emoji').popover({
|
||||
placement: 'top',
|
||||
content: function() {
|
||||
if (!self.$emojis) { // lazy rendering
|
||||
self.$emojis = $(QWeb.render('mail.ChatComposer.emojis', {
|
||||
emojis: self._getEmojis(),
|
||||
}));
|
||||
self.$emojis.filter('.o_mail_emoji').on('click', self, self.on_click_emoji_img);
|
||||
}
|
||||
return self.$emojis;
|
||||
},
|
||||
html: true,
|
||||
container: '.' + self.emoji_container_classname,
|
||||
trigger: 'focus',
|
||||
});
|
||||
|
||||
// Mention
|
||||
this.mention_manager.prependTo(this.$('.o_composer'));
|
||||
|
||||
@@ -529,11 +513,6 @@ var BasicComposer = Widget.extend(chat_mixin, {
|
||||
this.$input.focus();
|
||||
},
|
||||
|
||||
on_click_emoji_img: function(event) {
|
||||
this.$input.val(this.$input.val() + " " + $(event.currentTarget).data('emoji') + " ");
|
||||
this.$input.focus();
|
||||
},
|
||||
|
||||
setState: function (state) {
|
||||
this.set('attachment_ids', state.attachments);
|
||||
this.$input.val(state.text);
|
||||
@@ -775,6 +754,20 @@ var BasicComposer = Widget.extend(chat_mixin, {
|
||||
focus: function () {
|
||||
this.$input.focus();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Hides the emojis container.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_hideEmojis: function () {
|
||||
this.$emojisContainer.remove();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -798,6 +791,56 @@ var BasicComposer = Widget.extend(chat_mixin, {
|
||||
attachmentViewer.appendTo($('body'));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Called when the emoji button is clicked -> opens/hides the emoji panel.
|
||||
* Also, this method is in charge of the rendering of this panel the first
|
||||
* time it is opened.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onEmojiButtonClick: function () {
|
||||
if (!this.$emojisContainer) { // lazy rendering
|
||||
this.$emojisContainer = $(QWeb.render('mail.ChatComposer.emojis', {
|
||||
emojis: this._getEmojis(),
|
||||
}));
|
||||
}
|
||||
if (this.$emojisContainer.parent().length) {
|
||||
this._hideEmojis();
|
||||
} else {
|
||||
this.$emojisContainer.appendTo(this.$('.o_composer'));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Called when the emoji button is blurred -> closes the emoji panel. The
|
||||
* closing is scheduled to be done at the end of the current execution
|
||||
* stack to allow stoping this closing if the button was focusout to select
|
||||
* an emoji (for example).
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onEmojiButtonFocusout: function () {
|
||||
this._hideEmojisTimeout = setTimeout(this._hideEmojis.bind(this), 0);
|
||||
},
|
||||
/**
|
||||
* Called when an emoji is focused -> @see _onEmojiButtonFocusout
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onEmojiImageFocus: function () {
|
||||
clearTimeout(this._hideEmojisTimeout);
|
||||
},
|
||||
/**
|
||||
* Called when an emoji is clicked -> adds it in the <input/>, focuses the
|
||||
* <input/> and closes the emoji panel.
|
||||
*
|
||||
* @private
|
||||
* @param {Event} ev
|
||||
*/
|
||||
_onEmojiImageClick: function (ev) {
|
||||
this.$input.val(this.$input.val() + " " + $(ev.currentTarget).data('emoji') + " ");
|
||||
this.$input.focus();
|
||||
this._hideEmojis();
|
||||
},
|
||||
});
|
||||
|
||||
var ExtendedComposer = BasicComposer.extend({
|
||||
@@ -807,7 +850,6 @@ var ExtendedComposer = BasicComposer.extend({
|
||||
});
|
||||
this._super(parent, options);
|
||||
this.extended = true;
|
||||
this.emoji_container_classname = 'o_extended_composer_emoji';
|
||||
},
|
||||
|
||||
start: function () {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
@o-mail-chatter-gap: 10px; // has to be defined here as this file is both in
|
||||
// backend and other assets (livechat)
|
||||
@o-chat-header-height: 46px;
|
||||
@o-chat-window-zindex: 1101; // blockUI's z-index is 1100 > @zindex-modal
|
||||
|
||||
.o_chat_window {
|
||||
.o-flex-display();
|
||||
@@ -15,7 +16,7 @@
|
||||
font-size: 12px;
|
||||
background-color: @o-chat-window-bg;
|
||||
border-radius: 6px 6px 0 0;
|
||||
z-index: 3;
|
||||
z-index: @o-chat-window-zindex;
|
||||
box-shadow: -5px -5px 10px fade(black, 18%);
|
||||
|
||||
@media (max-width: @screen-xs-max) {
|
||||
@@ -143,9 +144,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.o_ui_blocked .o_chat_window {
|
||||
z-index: 1101; // blockUI's z-index is 1100
|
||||
}
|
||||
.o_no_chat_window .o_chat_window {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
position: relative;
|
||||
.o-flex(0, 0, auto);
|
||||
.o-flex-display();
|
||||
.o-align-items(flex-start);
|
||||
margin: 1px 0;
|
||||
border-top: none;
|
||||
background: @gray-lighter;
|
||||
@@ -59,6 +58,18 @@
|
||||
color: @odoo-brand-optional;
|
||||
}
|
||||
}
|
||||
|
||||
.o_mail_emoji_container {
|
||||
padding: 0 @o-mail-chatter-gap @o-mail-chatter-gap 0;
|
||||
border: 1px solid @gray-lighter-dark;
|
||||
border-width: 1px 0 0 0;
|
||||
background-color: @gray-lighter;
|
||||
|
||||
.o_mail_emoji {
|
||||
margin: @o-mail-chatter-gap 0 0 @o-mail-chatter-gap;
|
||||
cursor: pointer; // only in the popover
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Both inline and not-inline design. Mini-composer disabled.
|
||||
@@ -72,10 +83,6 @@
|
||||
.o-position-absolute(0, @left: -@mail-thread-avatar-size - @o-mail-chatter-gap);
|
||||
}
|
||||
|
||||
.o_composer_container, .o_composer_send {
|
||||
.o-flex-display();
|
||||
}
|
||||
|
||||
.o_chatter_composer_info, .o_composer_suggested_partners {
|
||||
.o-flex(0, 0, 100%);
|
||||
margin-bottom: @o-mail-chatter-gap*0.5;
|
||||
@@ -83,7 +90,6 @@
|
||||
|
||||
.o_composer_container {
|
||||
position: relative;
|
||||
.o-flex-flow(column, nowrap);
|
||||
}
|
||||
|
||||
.o_composer {
|
||||
@@ -91,6 +97,10 @@
|
||||
textarea {
|
||||
padding-right: @grid-gutter-width; // avoid overlaps betwenn textarea and o_composer_button_full_composer
|
||||
}
|
||||
|
||||
.o_mail_emoji_container {
|
||||
margin: 0 -@o-mail-chatter-gap;
|
||||
}
|
||||
}
|
||||
|
||||
.o_composer, .o_composer_subject {
|
||||
@@ -129,9 +139,14 @@
|
||||
.o-flex(1, 0, auto);
|
||||
}
|
||||
.o_composer {
|
||||
padding: @o-mail-chatter-gap @o-mail-chatter-gap*0.5 0 @o-mail-chatter-gap;
|
||||
padding: @o-mail-chatter-gap @o-mail-chatter-gap 0 @o-mail-chatter-gap;
|
||||
border-radius: 2px 0 0 2px;
|
||||
border-right: 0;
|
||||
border-right-width: 0;
|
||||
|
||||
.o_mail_emoji_container {
|
||||
text-align: right;
|
||||
border-right-width: 1px;
|
||||
}
|
||||
}
|
||||
.o_composer_input {
|
||||
.o-flex-display();
|
||||
@@ -157,7 +172,6 @@
|
||||
}
|
||||
|
||||
.o_composer_button_send {
|
||||
.o-flex(0, 0, auto);
|
||||
border-radius: 0 3px 3px 0;
|
||||
// Make the button appear as the same size as the subject input
|
||||
padding: 10px @padding-base-horizontal;
|
||||
@@ -173,6 +187,12 @@
|
||||
border-top: 1px solid @gray-lighter-dark;
|
||||
width: 100%;
|
||||
}
|
||||
.o_composer {
|
||||
.o_mail_emoji_container {
|
||||
.o-position-absolute(auto, 0, 100%, 0);
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
}
|
||||
.o_composer_input {
|
||||
.o-flex-display();
|
||||
.o-flex-flow(row, nowrap);
|
||||
@@ -206,22 +226,13 @@
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
padding: 0;
|
||||
|
||||
> img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.o_composer_emoji {
|
||||
.popover-content {
|
||||
padding: @o-mail-chatter-gap*0.3 0;
|
||||
}
|
||||
.o_mail_emoji {
|
||||
margin: @o-mail-chatter-gap*0.6;
|
||||
cursor: pointer; // only in the popover
|
||||
}
|
||||
}
|
||||
|
||||
// Attachment Icons (common for chat thread and chat composer)
|
||||
// ------------------------------------------------------------------
|
||||
@-webkit-keyframes oe_mail_attach_loading_anim {
|
||||
@@ -391,7 +402,7 @@
|
||||
.arrow-left {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
|
||||
.arrow-right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@@ -32,16 +32,15 @@
|
||||
<input type="hidden" name="session_id" t-att-value="widget.getSession().session_id"/>
|
||||
</t>
|
||||
</span>
|
||||
<span t-att-class="widget.emoji_container_classname"></span>
|
||||
</div>
|
||||
|
||||
<t t-name="mail.ChatComposer.emojis">
|
||||
<div t-name="mail.ChatComposer.emojis" class="o_mail_emoji_container">
|
||||
<t t-foreach="emojis" t-as="emoji">
|
||||
<span t-att-data-emoji="emoji.source" class="o_mail_emoji" t-att-title="emoji.description">
|
||||
<button t-att-data-emoji="emoji.source" class="btn btn-link o_mail_emoji" t-att-title="emoji.description">
|
||||
<t t-raw="emoji.substitution"/>
|
||||
</span>
|
||||
</button>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<t t-name="mail.AbstractMentionSuggestions">
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMailMentionMenu">
|
||||
|
||||
@@ -106,16 +106,12 @@ QUnit.module('mail', {}, function () {
|
||||
var chatWindow = new ChatWindow(parent, 1, "user", false, [], {});
|
||||
chatWindow.appendTo($dom);
|
||||
|
||||
// Simulate clicking: 1) the focus event is fired, 2) we remove the
|
||||
// 'fade' class of the generated popover so that animations do not break
|
||||
// the test, 3) fire the click event which was the cause of the problem
|
||||
var $emojiButton = chatWindow.$('.o_composer_button_emoji');
|
||||
$emojiButton.trigger('focusin').focus();
|
||||
var $popover = chatWindow.$('.o_composer_emoji .popover');
|
||||
$popover.removeClass('fade');
|
||||
$emojiButton.click();
|
||||
$emojiButton.trigger('focusin').focus().click();
|
||||
var $popover = chatWindow.$('.o_mail_emoji_container');
|
||||
|
||||
var done = assert.async();
|
||||
// Async is needed as the popover focusout hiding is deferred
|
||||
setTimeout(function () {
|
||||
assert.ok($popover.is(':visible'), "emoji popover should have stayed opened");
|
||||
parent.destroy();
|
||||
|
||||
@@ -54,19 +54,17 @@ if ($.blockUI) {
|
||||
|
||||
var throbbers = [];
|
||||
|
||||
function blockUI () {
|
||||
function blockUI() {
|
||||
var tmp = $.blockUI.apply($, arguments);
|
||||
var throbber = new Throbber();
|
||||
throbbers.push(throbber);
|
||||
throbber.appendTo($(".oe_blockui_spin_container"));
|
||||
$('body').addClass('o_ui_blocked');
|
||||
return tmp;
|
||||
}
|
||||
|
||||
function unblockUI () {
|
||||
function unblockUI() {
|
||||
_.invoke(throbbers, 'destroy');
|
||||
throbbers = [];
|
||||
$('body').removeClass('o_ui_blocked');
|
||||
return $.unblockUI.apply($, arguments);
|
||||
}
|
||||
|
||||
@@ -104,7 +102,7 @@ function redirect (url, wait) {
|
||||
// * Client action to reload the whole interface.
|
||||
// * If params.menu_id, it opens the given menu entry.
|
||||
// * If params.wait, reload will wait the openerp server to be reachable before reloading
|
||||
|
||||
|
||||
function Reload(parent, action) {
|
||||
var params = action.params || {};
|
||||
var menu_id = params.menu_id || false;
|
||||
|
||||
Reference in New Issue
Block a user