From 30c26d7654285bdcf6873931f54c915fccaf1822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Mon, 11 Jan 2016 11:25:35 +0100 Subject: [PATCH] [IMP] mail: various UI improvements - don't add 'New message from' in the title of notifications when an author name is defined - use a simple O icon instead of the full Odoo logo when a notification is natively displayed - don't scroll to bottom if the thread is not already at bottom - don't mark a channel read if thread is not at the bottom - add # in front of channel name in chat windows and in invite dialog - accept anonymous names in channel (for ex, livechat channels) - always go to the next line with shift+enter - always send message with ctrl+enter - pressing enter sends message or go to next line depending of context - don't allow to detach mass mailing channels --- addons/mail/static/src/img/odoo_o.png | Bin 0 -> 556 bytes addons/mail/static/src/js/chat_manager.js | 8 +++-- addons/mail/static/src/js/chat_window.js | 9 ++---- addons/mail/static/src/js/client_action.js | 23 +++++++++++---- addons/mail/static/src/js/composer.js | 17 ++++++----- addons/mail/static/src/js/thread.js | 3 ++ addons/mail/static/src/js/window_manager.js | 29 ++++++++++++++----- addons/mail/static/src/less/chat_window.less | 6 ++-- 8 files changed, 62 insertions(+), 33 deletions(-) create mode 100644 addons/mail/static/src/img/odoo_o.png diff --git a/addons/mail/static/src/img/odoo_o.png b/addons/mail/static/src/img/odoo_o.png new file mode 100644 index 0000000000000000000000000000000000000000..d1839f6df41a5289173b44e8432fd10e79dd1201 GIT binary patch literal 556 zcmeAS@N?(olHy`uVBq!ia0vp^DImHwb**M1yeky|GkLQ{w)i_BHr zJ`)cDngdh}R50Q88QTNP{{R1f?bDlGFYh;BKc>HDe&or`PriLV@%EYb(KVlb|17<< zf8K-3Yo6RpKetosg`5J=*^DJYe!&b5&u)PHz?kIi?!wT)D(eB{a29w(7Bet#3xhBt z!>lJ#m)-61ytJV?MfZmC#QFZ0 zTo(y1_!8sgryZ?gljK~y)o7x|6FL2@zMSWhTmD8)Q4T3S(k$*BoY}2hQ+DJ 0) { + if (channel.unread_counter > 0 && channel.type !== 'static') { update_channel_unread_counter(channel, 0); channel_seen(channel); } diff --git a/addons/mail/static/src/js/chat_window.js b/addons/mail/static/src/js/chat_window.js index 9f94310f4ff..851c7fa56d2 100644 --- a/addons/mail/static/src/js/chat_window.js +++ b/addons/mail/static/src/js/chat_window.js @@ -33,7 +33,6 @@ return Widget.extend({ this.is_hidden = false; }, start: function () { - this.$content = this.$('.o_chat_content'); this.$input = this.$('.o_chat_input input'); this.thread = new ChatThread(this, { @@ -48,7 +47,7 @@ return Widget.extend({ if (this.folded) { this.$el.css('height', HEIGHT_FOLDED); } - var def = this.thread.appendTo(this.$content); + var def = this.thread.replace(this.$('.o_chat_content')); return $.when(this._super(), def); }, render: function (messages) { @@ -59,9 +58,6 @@ return Widget.extend({ this.unread_msgs = counter; this.$('.o_unread_counter').text(counter > 0 ? '(' + counter + ')' : ''); }, - scrollBottom: function () { - this.$content.scrollTop(this.$content[0].scrollHeight); - }, fold: function () { this.$el.animate({ height: this.folded ? HEIGHT_FOLDED : HEIGHT_OPEN @@ -70,8 +66,7 @@ return Widget.extend({ toggle_fold: function (fold) { this.folded = _.isBoolean(fold) ? fold : !this.folded; if (!this.folded) { - this.unread_msgs = 0; - this.trigger('messages_read'); + this.thread.scroll_to(); } this.fold(); }, diff --git a/addons/mail/static/src/js/client_action.js b/addons/mail/static/src/js/client_action.js index d0cee78fcef..46190c1dd0b 100644 --- a/addons/mail/static/src/js/client_action.js +++ b/addons/mail/static/src/js/client_action.js @@ -225,12 +225,17 @@ var ChatAction = Widget.extend(ControlPanelMixin, { chat_manager.bus.on('update_message', self, self.on_update_message); chat_manager.bus.on('new_channel', self, self.on_new_channel); chat_manager.bus.on('anyone_listening', self, function (channel, query) { - query.is_displayed = query.is_displayed || channel.id === self.channel.id; + query.is_displayed = query.is_displayed || (channel.id === self.channel.id && self.thread.is_at_bottom()); }); chat_manager.bus.on('unsubscribe_from_channel', self, self.render_sidebar); chat_manager.bus.on('update_needaction', self, self.throttled_render_sidebar); chat_manager.bus.on('update_channel_unread_counter', self, self.throttled_render_sidebar); chat_manager.bus.on('update_dm_presence', self, self.throttled_render_sidebar); + self.thread.$el.on("scroll", null, _.debounce(function () { + if (self.thread.is_at_bottom()) { + chat_manager.mark_channel_as_seen(self.channel); + } + }, 100)); }); }, @@ -353,7 +358,7 @@ var ChatAction = Widget.extend(ControlPanelMixin, { // Hide 'detach' button in static channels self.$buttons .find('.o_mail_chat_button_detach') - .toggle(channel.type !== "static"); + .toggle(channel.type !== "static" && !channel.mass_mailing); // Hide 'invite', 'unsubscribe' and 'settings' buttons in static channels and DM self.$buttons .find('.o_mail_chat_button_invite, .o_mail_chat_button_unsubscribe, .o_mail_chat_button_settings') @@ -506,9 +511,13 @@ var ChatAction = Widget.extend(ControlPanelMixin, { }, on_post_message: function (message) { + var self = this; var options = {channel_id: this.channel.id}; chat_manager .post_message(message, options) + .then(function() { + self.thread.scroll_to(); + }) .fail(function () { // todo: display notification }); @@ -516,11 +525,15 @@ var ChatAction = Widget.extend(ControlPanelMixin, { on_new_message: function (message) { var self = this; if (_.contains(message.channel_ids, this.channel.id)) { - if (this.channel.type !== 'static') { + if (this.channel.type !== 'static' && this.thread.is_at_bottom()) { chat_manager.mark_channel_as_seen(this.channel); } + + var should_scroll = this.thread.is_at_bottom(); this.fetch_and_render_thread().then(function () { - self.thread.scroll_to({id: message.id}); + if (should_scroll) { + self.thread.scroll_to({id: message.id}); + } }); } // Re-render sidebar to indicate that there is a new message in the corresponding channels @@ -556,7 +569,7 @@ var ChatAction = Widget.extend(ControlPanelMixin, { }, on_click_button_invite: function () { - var title = _.str.sprintf(_t('Invite people to %s'), this.channel.name); + var title = _.str.sprintf(_t('Invite people to #%s'), this.channel.name); new PartnerInviteDialog(this, title, this.channel.id).open(); }, on_click_button_detach: function () { diff --git a/addons/mail/static/src/js/composer.js b/addons/mail/static/src/js/composer.js index a02a3966333..7316ce09e07 100644 --- a/addons/mail/static/src/js/composer.js +++ b/addons/mail/static/src/js/composer.js @@ -443,8 +443,8 @@ var BasicComposer = Widget.extend({ /** * Send the message on ENTER, but go to new line on SHIFT+ENTER */ - prevent_send: function (event) { - return event.shiftKey; + should_send: function (event) { + return !event.shiftKey; }, on_keydown: function (event) { @@ -465,9 +465,12 @@ var BasicComposer = Widget.extend({ case $.ui.keyCode.ENTER: if (this.mention_manager.is_open()) { event.preventDefault(); - } else if (!this.prevent_send(event)) { - event.preventDefault(); - this.send_message(); + } else { + var send_message = event.ctrlKey || this.should_send(event); + if (send_message) { + event.preventDefault(); + this.send_message(); + } } break; } @@ -667,8 +670,8 @@ var ExtendedComposer = BasicComposer.extend({ }); }, - prevent_send: function () { - return true; + should_send: function () { + return false; }, }); diff --git a/addons/mail/static/src/js/thread.js b/addons/mail/static/src/js/thread.js index 99b4d6ba1c2..439b1a8beb3 100644 --- a/addons/mail/static/src/js/thread.js +++ b/addons/mail/static/src/js/thread.js @@ -165,6 +165,9 @@ var Thread = Widget.extend({ get_scrolltop: function () { return this.$el.scrollTop(); }, + is_at_bottom: function () { + return this.el.scrollHeight - this.$el.scrollTop() - this.$el.outerHeight() < 5; + }, }); Thread.ORDER = ORDER; diff --git a/addons/mail/static/src/js/window_manager.js b/addons/mail/static/src/js/window_manager.js index e76f4ef5cec..05afc816712 100644 --- a/addons/mail/static/src/js/window_manager.js +++ b/addons/mail/static/src/js/window_manager.js @@ -38,11 +38,12 @@ function open_chat (session) { } var chat_session = _.findWhere(chat_sessions, {id: session.id}); if (!chat_session) { + var prefix = !session.is_chat ? "#" : ""; chat_session = { id: session.id, uuid: session.uuid, name: session.name, - window: new ExtendedChatWindow(web_client, session.id, session.name, session.is_folded, session.unread_counter), + window: new ExtendedChatWindow(web_client, session.id, prefix + session.name, session.is_folded, session.unread_counter), }; chat_session.window.on("close_chat_session", null, function () { close_chat(chat_session); @@ -58,7 +59,11 @@ function open_chat (session) { chat_session.window.on("post_message", null, function (message, channel_id) { message.content = _.escape(message.content); - chat_manager.post_message(message, {channel_id: channel_id}); + chat_manager + .post_message(message, {channel_id: channel_id}) + .then(function () { + chat_session.window.thread.scroll_to(); + }); }); chat_session.window.on("messages_read", null, function () { chat_manager.mark_channel_as_seen(session); @@ -91,7 +96,14 @@ function open_chat (session) { return chat_manager.get_messages({channel_id: chat_session.id}); }).then(function (messages) { chat_session.window.render(messages); - chat_session.window.scrollBottom(); + chat_session.window.thread.scroll_to(); + setTimeout(function () { + chat_session.window.thread.$el.on("scroll", null, _.debounce(function () { + if (chat_session.window.thread.is_at_bottom()) { + chat_manager.mark_channel_as_seen(session); + } + }, 100)); + }, 0); // setTimeout to prevent to execute handler on first scroll_to, which is asynchronous if (!session.is_folded) { chat_manager.mark_channel_as_seen(session); } @@ -230,8 +242,8 @@ var reposition_windows = function (options) { function make_session_visible (session) { utils.swap(chat_sessions, session, chat_sessions[display_state.nb_slots-1]); - session.window.toggle_fold(false); reposition_windows(); + session.window.toggle_fold(false); } function render_hidden_sessions_dropdown () { @@ -254,13 +266,14 @@ function reposition_hidden_sessions_dropdown () { function update_sessions (message, scrollBottom) { _.each(chat_sessions, function (session) { if (_.contains(message.channel_ids, session.id)) { - if (!session.window.folded && !session.window.is_hidden) { + var message_visible = !session.window.folded && !session.window.is_hidden && session.window.thread.is_at_bottom(); + if (message_visible) { chat_manager.mark_channel_as_seen(chat_manager.get_channel(session.id)); } chat_manager.get_messages({channel_id: session.id}).then(function (messages) { session.window.render(messages); - if (scrollBottom) { - session.window.scrollBottom(); + if (scrollBottom && message_visible) { + session.window.thread.scroll_to(); } }); } @@ -288,7 +301,7 @@ core.bus.on('web_client_ready', null, function () { chat_manager.bus.on('anyone_listening', null, function (channel, query) { _.each(chat_sessions, function (session) { - if (channel.id === session.id) { + if (channel.id === session.id && session.window.thread.is_at_bottom()) { query.is_displayed = true; } }); diff --git a/addons/mail/static/src/less/chat_window.less b/addons/mail/static/src/less/chat_window.less index 1d5d3f086f0..a4024c93dc1 100644 --- a/addons/mail/static/src/less/chat_window.less +++ b/addons/mail/static/src/less/chat_window.less @@ -53,12 +53,12 @@ } } - .o_chat_content { + .o_mail_thread { .o-flex(1, 1, auto); overflow: auto; padding: 5px; - .o_mail_thread .o_thread_date_separator { + .o_thread_date_separator { margin-top: 0px; margin-bottom: 15px; border-color: lightgray; @@ -138,7 +138,7 @@ .o-flex(1, 1, 100%); } } - .o_chat_content { + .o_mail_thread { background-color: lightgray; } .o_chat_input {