From 916d90af35ca9d9e57ce50421d6a3aeaa0698ddd Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Fri, 8 Jan 2016 11:51:58 +0100 Subject: [PATCH] [IMP] mail: open dm shortcut from in navbar dropdown Allows to directly open a dm channel from a chat window, without coming back to Discuss. --- addons/mail/models/mail_channel.py | 7 + addons/mail/static/src/js/chat_manager.js | 37 ++++- addons/mail/static/src/js/chat_window.js | 2 +- addons/mail/static/src/js/client_action.js | 19 +-- addons/mail/static/src/js/systray.js | 4 + addons/mail/static/src/js/window_manager.js | 134 +++++++++++++++--- addons/mail/static/src/less/chat_window.less | 21 +++ .../mail/static/src/less/client_action.less | 3 + addons/mail/static/src/xml/chat_window.xml | 12 +- addons/mail/static/src/xml/systray.xml | 9 +- 10 files changed, 200 insertions(+), 48 deletions(-) diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py index e9ddbfd2e61..5bf0a830d9f 100644 --- a/addons/mail/models/mail_channel.py +++ b/addons/mail/models/mail_channel.py @@ -398,6 +398,13 @@ class Channel(models.Model): return channel.channel_info()[0] return False + @api.model + def channel_get_and_minimize(self, partners_to): + channel = self.channel_get(partners_to) + if channel: + self.channel_minimize(channel['uuid']) + return channel + @api.model def channel_fold(self, uuid, state=None): """ Update the fold_state of the given session. In order to syncronize web browser diff --git a/addons/mail/static/src/js/chat_manager.js b/addons/mail/static/src/js/chat_manager.js index c5b510ce8ad..a16633ebce0 100644 --- a/addons/mail/static/src/js/chat_manager.js +++ b/addons/mail/static/src/js/chat_manager.js @@ -16,6 +16,7 @@ var preview_msg_max_size = 350; // optimal for native english speakers var MessageModel = new Model('mail.message', session.context); var ChannelModel = new Model('mail.channel', session.context); var UserModel = new Model('res.users', session.context); +var PartnerModel = new Model('res.partner', session.context); // Private model //---------------------------------------------------------------------------------- @@ -621,7 +622,7 @@ function on_chat_session_notification (chat_session) { } function on_presence_notification (data) { - var dm = _.findWhere(channels, {direct_partner_id: data.id}); + var dm = chat_manager.get_dm_from_partner_id(data.id); if (dm) { dm.status = data.im_status; chat_manager.bus.trigger('update_dm_presence', dm); @@ -748,6 +749,10 @@ var chat_manager = { return _.findWhere(channels, {id: id}); }, + get_dm_from_partner_id: function (partner_id) { + return _.findWhere(channels, {direct_partner_id: partner_id}); + }, + all_history_loaded: function (channel, domain) { return get_channel_cache(channel, domain).all_history_loaded; }, @@ -824,6 +829,9 @@ var chat_manager = { } return channel_defs[channel_id]; }, + open_and_detach_dm: function (partner_id) { + return ChannelModel.call('channel_get_and_minimize', [[partner_id]]).then(add_channel); + }, unsubscribe: function (channel) { var def; @@ -840,11 +848,14 @@ var chat_manager = { var channel = this.get_channel(channel_id); ChannelModel.call("channel_fold", [], {uuid : channel.uuid, state : "closed"}); }, - fold_channel: function (channel_id) { - var channel = this.get_channel(channel_id); - return ChannelModel.call("channel_fold", [], {uuid : channel.uuid}).then(function () { - channel.is_folded = !channel.is_folded; - }); + fold_channel: function (channel_id, folded) { + var args = { + uuid: this.get_channel(channel_id).uuid, + }; + if (_.isBoolean(folded)) { + args.state = folded ? 'folded' : 'open'; + } + return ChannelModel.call("channel_fold", [], args); }, /** * Special redirection handling for given model and id @@ -918,6 +929,20 @@ var chat_manager = { get_message_body_preview: function (message_body) { return parse_and_transform(message_body, inline); }, + + search_partner: function (search_val) { + return PartnerModel.call('im_search', [search_val, 20]).then(function(result) { + var values = []; + _.each(result, function(user) { + var escaped_name = _.escape(user.name); + values.push(_.extend(user, { + 'value': escaped_name, + 'label': escaped_name, + })); + }); + return values; + }); + }, }; // Initialization diff --git a/addons/mail/static/src/js/chat_window.js b/addons/mail/static/src/js/chat_window.js index e76e2405b43..44304b81cda 100644 --- a/addons/mail/static/src/js/chat_window.js +++ b/addons/mail/static/src/js/chat_window.js @@ -107,8 +107,8 @@ return Widget.extend({ this.trigger("close_chat_session"); }, on_click_fold: function () { - this.trigger("fold_channel", this.channel_id); this.toggle_fold(); + this.trigger("fold_channel", this.channel_id, this.folded); }, }); diff --git a/addons/mail/static/src/js/client_action.js b/addons/mail/static/src/js/client_action.js index a1882fa2773..d0cee78fcef 100644 --- a/addons/mail/static/src/js/client_action.js +++ b/addons/mail/static/src/js/client_action.js @@ -272,9 +272,7 @@ var ChatAction = Widget.extend(ControlPanelMixin, { this.$('.o_mail_add_channel[data-type=dm]').find("input").autocomplete({ source: function(request, response) { self.last_search_val = _.escape(request.term); - self.do_search_partner(self.last_search_val).done(function(result){ - response(result); - }); + chat_manager.search_partner(self.last_search_val).done(response); }, select: function(event, ui) { var partner_id = ui.item.id; @@ -319,21 +317,6 @@ var ChatAction = Widget.extend(ControlPanelMixin, { }); }, - do_search_partner: function (search_val) { - var Partner = new Model("res.partner"); - return Partner.call('im_search', [search_val, 20]).then(function(result){ - var values = []; - _.each(result, function(user){ - var escaped_name = _.escape(user.name); - values.push(_.extend(user, { - 'value': escaped_name, - 'label': escaped_name, - })); - }); - return values; - }); - }, - set_channel: function (channel) { var self = this; // Store scroll position of previous channel diff --git a/addons/mail/static/src/js/systray.js b/addons/mail/static/src/js/systray.js index 342167bfed2..8334c41221e 100644 --- a/addons/mail/static/src/js/systray.js +++ b/addons/mail/static/src/js/systray.js @@ -22,6 +22,7 @@ var MessagingMenu = Widget.extend({ events: { "click": "on_click", "click .o_filter_button": "on_click_filter_button", + "click .o_new_message": "on_click_new_message", "click .o_mail_channel_preview": "on_click_channel", "click .o_redirect_to_discuss": "on_click_redirect_to_discuss", }, @@ -99,6 +100,9 @@ var MessagingMenu = Widget.extend({ this.filter = $target.data('filter'); this.render_channels_preview(); }, + on_click_new_message: function () { + chat_manager.bus.trigger('open_chat'); + }, on_click_channel: function (event) { var channel_id = $(event.currentTarget).data('channel_id'); var channel = chat_manager.get_channel(channel_id); diff --git a/addons/mail/static/src/js/window_manager.js b/addons/mail/static/src/js/window_manager.js index 0459e13f4b7..393903b751e 100644 --- a/addons/mail/static/src/js/window_manager.js +++ b/addons/mail/static/src/js/window_manager.js @@ -2,18 +2,20 @@ odoo.define('mail.window_manager', function (require) { "use strict"; var chat_manager = require('mail.chat_manager'); -var ChatWindow = require('mail.ChatWindow'); +var ExtendedChatWindow = require('mail.ExtendedChatWindow'); var core = require('web.core'); var utils = require('web.utils'); var web_client = require('web.web_client'); +var _t = core._t; var QWeb = core.qweb; // chat window management //---------------------------------------------------------------- var CHAT_WINDOW_WIDTH = 300 + 5; // 5 pixels between windows var chat_sessions = []; +var new_chat_session; var display_state = { hidden_sessions: [], hidden_unread_counter: 0, // total number of unread msgs in hidden chat windows @@ -22,14 +24,24 @@ var display_state = { windows_dropdown_is_open: false, // used to keep dropdown open when closing chat windows }; +function add_chat_session (chat_session) { + // adds chat_session such that it will be the left-most visible window + compute_available_slots(chat_sessions.length+1); + chat_sessions.splice(display_state.nb_slots-1, 0, chat_session); +} + function open_chat (session) { + if (!session) { + open_chat_without_session(); + return; + } var chat_session = _.findWhere(chat_sessions, {id: session.id}); if (!chat_session) { chat_session = { id: session.id, uuid: session.uuid, name: session.name, - window: new ChatWindow(web_client, session.id, session.name, session.is_folded, session.unread_counter), + window: new ExtendedChatWindow(web_client, session.id, session.name, session.is_folded, session.unread_counter), }; chat_session.window.on("close_chat_session", null, function () { close_chat(chat_session); @@ -39,8 +51,8 @@ function open_chat (session) { chat_manager.toggle_star_status(message_id); }); - chat_session.window.on("fold_channel", null, function (channel_id) { - chat_manager.fold_channel(channel_id); + chat_session.window.on("fold_channel", null, function (channel_id, folded) { + chat_manager.fold_channel(channel_id, folded); }); chat_session.window.on("post_message", null, function (message, channel_id) { @@ -64,13 +76,17 @@ function open_chat (session) { } }); - // insert chat_session such that it will be the right-most visible window - compute_available_slots(chat_sessions.length+1); - chat_sessions.splice(display_state.nb_slots-1, 0, chat_session); + var remove_new_chat = false; + if (new_chat_session && new_chat_session.partner_id && new_chat_session.partner_id === session.direct_partner_id) { + chat_sessions[_.indexOf(chat_sessions, new_chat_session)] = chat_session; + remove_new_chat = true; + } else { + add_chat_session(chat_session); + } chat_session.window.appendTo($('body')) - .then(reposition_windows) .then(function () { + reposition_windows({remove_new_chat: remove_new_chat}); return chat_manager.get_messages({channel_id: chat_session.id}); }).then(function (messages) { chat_session.window.render(messages); @@ -88,19 +104,60 @@ function open_chat (session) { } } -function close_chat (chat_session) { - var session = _.find(chat_sessions, {id: chat_session.id}); - if (session) { - chat_sessions = _.without(chat_sessions, session); - session.window.destroy(); - reposition_windows(); +function open_chat_without_session () { + if (!new_chat_session) { + new_chat_session = { + id: '_open', + window: new ExtendedChatWindow(web_client, undefined, _t('New message'), false, 0, {thread_less: true}), + }; + new_chat_session.window.on("close_chat_session", null, close_new_chat); + new_chat_session.window.on('open_dm_session', null, function (partner_id) { + new_chat_session.partner_id = partner_id; + var dm = chat_manager.get_dm_from_partner_id(partner_id); + if (!dm) { + chat_manager.open_and_detach_dm(partner_id); + } else { + var dm_session = _.findWhere(chat_sessions, {id: dm.id}); + if (!dm_session) { + chat_manager.detach_channel(dm); + } else { + close_chat(dm_session); + dm.is_folded = false; + open_chat(dm); + } + } + }); + add_chat_session(new_chat_session); + new_chat_session.window.appendTo($('body')).then(reposition_windows); + } else { + if (new_chat_session.window.is_hidden) { + make_session_visible(new_chat_session); + } else if (new_chat_session.window.folded) { + new_chat_session.window.toggle_fold(false); + } } } +function close_chat (chat_session) { + chat_sessions = _.without(chat_sessions, chat_session); + chat_session.window.destroy(); + reposition_windows(); +} + +function close_new_chat () { + chat_sessions = _.without(chat_sessions, new_chat_session); + reposition_windows({remove_new_chat: true}); +} + +function destroy_new_chat () { + new_chat_session.window.destroy(); + new_chat_session = undefined; +} + function toggle_fold_chat (channel) { var session = _.find(chat_sessions, {id: channel.id}); if (session) { - session.window.toggle_fold(); + session.window.toggle_fold(channel.is_folded); } } @@ -116,7 +173,10 @@ function compute_available_slots (nb_windows) { display_state.space_left = space_left; } -var reposition_windows = _.debounce(function () { +var reposition_windows = function (options) { + if (options && options.remove_new_chat) { + destroy_new_chat(); + } compute_available_slots(chat_sessions.length); var hidden_sessions = []; var hidden_unread_counter = 0; @@ -161,7 +221,7 @@ var reposition_windows = _.debounce(function () { } }); } -}, 100); +}; function make_session_visible (session) { utils.swap(chat_sessions, session, chat_sessions[display_state.nb_slots-1]); @@ -205,7 +265,12 @@ function update_sessions (message, scrollBottom) { core.bus.on('web_client_ready', null, function () { chat_manager.bus.on('open_chat', null, open_chat); - chat_manager.bus.on('close_chat', null, close_chat); + chat_manager.bus.on('close_chat', null, function (channel) { + var session = _.find(chat_sessions, {id: channel.id}); + if (session) { + close_chat(session); + } + }); chat_manager.bus.on('channel_toggle_fold', null, toggle_fold_chat); chat_manager.bus.on('new_message', null, function (message) { @@ -265,7 +330,38 @@ core.bus.on('web_client_ready', null, function () { } }); - core.bus.on('resize', null, reposition_windows); + core.bus.on('resize', null, _.debounce(reposition_windows, 100)); +}); + +}); + +// FIXME: move this to its own file in master +odoo.define('mail.ExtendedChatWindow', function (require) { +"use strict"; + +var chat_manager = require('mail.chat_manager'); +var ChatWindow = require('mail.ChatWindow'); + +return ChatWindow.extend({ + template: "mail.ExtendedChatWindow", + start: function () { + var self = this; + return this._super().then(function () { + if (self.options.thread_less) { + self.$el.addClass('o_thread_less'); + self.$('.o_chat_search_input input') + .autocomplete({ + source: function(request, response) { + chat_manager.search_partner(request.term).done(response); + }, + select: function(event, ui) { + self.trigger('open_dm_session', ui.item.id); + }, + }) + .focus(); + } + }); + }, }); }); diff --git a/addons/mail/static/src/less/chat_window.less b/addons/mail/static/src/less/chat_window.less index bd9a2452113..51ff38fcef0 100644 --- a/addons/mail/static/src/less/chat_window.less +++ b/addons/mail/static/src/less/chat_window.less @@ -109,3 +109,24 @@ } } } + +// FIXME: move this to its own file in master +.o_chat_window.o_thread_less { + .o_chat_search_input { + .o-flex-display(); + padding: 5px; + > span { + .o-flex(0, 0, auto); + } + > input { + margin-left: 5px; + .o-flex(1, 1, 100%); + } + } + .o_chat_content { + background-color: lightgray; + } + .o_chat_input { + display: none; + } +} diff --git a/addons/mail/static/src/less/client_action.less b/addons/mail/static/src/less/client_action.less index 117047a527d..7f5c03b82df 100644 --- a/addons/mail/static/src/less/client_action.less +++ b/addons/mail/static/src/less/client_action.less @@ -279,13 +279,16 @@ } .o_filter_button, + .o_new_message, .o_redirect_to_discuss { .btn-link; padding: 5px; } .o_mail_navbar_dropdown_top { + .o-flex-display(); .o-flex(0, 0, auto); + justify-content: space-between; border-bottom: 1px solid lightgray; .o_filter_button { diff --git a/addons/mail/static/src/xml/chat_window.xml b/addons/mail/static/src/xml/chat_window.xml index 58d04c19838..f5c7273d832 100644 --- a/addons/mail/static/src/xml/chat_window.xml +++ b/addons/mail/static/src/xml/chat_window.xml @@ -17,6 +17,16 @@ + + + +
+ To: + +
+
+
+
@@ -29,7 +39,7 @@
  • - +
  • diff --git a/addons/mail/static/src/xml/systray.xml b/addons/mail/static/src/xml/systray.xml index f818969db98..247096b3b6e 100644 --- a/addons/mail/static/src/xml/systray.xml +++ b/addons/mail/static/src/xml/systray.xml @@ -8,9 +8,12 @@