[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.
This commit is contained in:
Aaron Bohy
2016-01-14 11:22:26 +01:00
parent b3868a613c
commit 916d90af35
10 changed files with 200 additions and 48 deletions
+7
View File
@@ -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
+31 -6
View File
@@ -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
+1 -1
View File
@@ -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);
},
});
+1 -18
View File
@@ -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
+4
View File
@@ -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);
+115 -19
View File
@@ -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();
}
});
},
});
});
@@ -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;
}
}
@@ -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 {
+11 -1
View File
@@ -17,6 +17,16 @@
</div>
</t>
<!-- FIXME: move this to its own file in master -->
<t t-name="mail.ExtendedChatWindow" t-extend="mail.ChatWindow">
<t t-jquery=".o_chat_header" t-operation="after">
<div t-if="widget.options.thread_less" class="o_chat_search_input">
<span> To: </span>
<input type="text"/>
</div>
</t>
</t>
<t t-name="mail.ChatWindowsDropdown">
<div t-attf-class="o_chat_window o_chat_window_dropdown dropup #{open ? 'open' : ''}">
<span class="o_chat_window_dropdown_toggler dropdown-toggle" data-toggle="dropdown">
@@ -29,7 +39,7 @@
<t t-foreach="sessions" t-as="session">
<li class="o_chat_header" t-att-data-session-id="session.id">
<t t-call="mail.ChatWindowHeaderContent">
<t t-set="title" t-value="session.name"/>
<t t-set="title" t-value="session.window.title"/>
<t t-set="unread_counter" t-value="session.window.unread_msgs"/>
</t>
</li>
+6 -3
View File
@@ -8,9 +8,12 @@
</a>
<ul class="o_mail_navbar_dropdown dropdown-menu" role="menu">
<li class="o_mail_navbar_dropdown_top">
<button type="button" class="btn btn-sm o_filter_button o_selected"> All </button>
<button type="button" class="btn btn-sm o_filter_button" data-filter='chat'> Chat </button>
<button type="button" class="btn btn-sm o_filter_button" data-filter='channels'> Channels </button>
<div>
<button type="button" class="btn btn-sm o_filter_button o_selected"> All </button>
<button type="button" class="btn btn-sm o_filter_button" data-filter='chat'> Chat </button>
<button type="button" class="btn btn-sm o_filter_button" data-filter='channels'> Channels </button>
</div>
<button type="button" class="btn btn-sm o_new_message"> New message </button>
</li>
<li class="o_mail_navbar_dropdown_channels"/>
<li class="o_mail_navbar_dropdown_bottom">