diff --git a/addons/mail/static/src/js/composer.js b/addons/mail/static/src/js/composer.js
index e46225a8f65..d76fafb34e9 100644
--- a/addons/mail/static/src/js/composer.js
+++ b/addons/mail/static/src/js/composer.js
@@ -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 , focuses the
+ * 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 () {
diff --git a/addons/mail/static/src/less/chat_window.less b/addons/mail/static/src/less/chat_window.less
index 0c7c48ef685..d615cc69b89 100644
--- a/addons/mail/static/src/less/chat_window.less
+++ b/addons/mail/static/src/less/chat_window.less
@@ -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;
}
diff --git a/addons/mail/static/src/less/composer.less b/addons/mail/static/src/less/composer.less
index cc95a0ddd21..ec3b156af2a 100644
--- a/addons/mail/static/src/less/composer.less
+++ b/addons/mail/static/src/less/composer.less
@@ -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;
}
diff --git a/addons/mail/static/src/xml/composer.xml b/addons/mail/static/src/xml/composer.xml
index a7b2e7cb02f..b46af297928 100644
--- a/addons/mail/static/src/xml/composer.xml
+++ b/addons/mail/static/src/xml/composer.xml
@@ -32,16 +32,15 @@
-
-
+
-
+
+
-
+
diff --git a/addons/mail/static/tests/chat_window_test.js b/addons/mail/static/tests/chat_window_test.js
index 832b9fa4fe8..ac224a69994 100644
--- a/addons/mail/static/tests/chat_window_test.js
+++ b/addons/mail/static/tests/chat_window_test.js
@@ -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();
diff --git a/addons/web/static/src/js/core/misc.js b/addons/web/static/src/js/core/misc.js
index 5f50ff27c6e..64ebeeb1794 100644
--- a/addons/web/static/src/js/core/misc.js
+++ b/addons/web/static/src/js/core/misc.js
@@ -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;