[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
This commit is contained in:
Géry Debongnie
2016-01-14 11:22:26 +01:00
committed by Aaron Bohy
parent 8397abd871
commit 30c26d7654
8 changed files with 62 additions and 33 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

+5 -3
View File
@@ -53,7 +53,7 @@ bus.on("window_focus", null, function() {
function notify_incoming_message (msg, options) {
var title = _t('New message');
if (msg.author_id[1]) {
title += _t(' from ') + _.escape(msg.author_id[1]);
title = _.escape(msg.author_id[1]);
}
var content = parse_and_transform(msg.body, strip_html).substr(0, preview_msg_max_size);
@@ -68,7 +68,7 @@ function notify_incoming_message (msg, options) {
if (Notification && Notification.permission === "granted") {
if (bus.is_master) {
new Notification(title, {body: content, icon: "/web/static/src/img/odoo.png", silent: false});
new Notification(title, {body: content, icon: "/mail/static/src/img/odoo_o.png", silent: false});
}
} else {
web_client.do_notify(title, content);
@@ -325,6 +325,8 @@ function make_channel (data, options) {
channel.status = data.direct_partner[0].im_status;
pinned_dm_partners.push(channel.direct_partner_id);
bus.update_option('bus_presence_partner_ids', pinned_dm_partners);
} else if ('anonymous_name' in data) {
channel.name = data.anonymous_name;
}
channel.is_chat = !channel.type.match(/^(public|private|static)$/);
if (data.message_unread_counter) {
@@ -735,7 +737,7 @@ var chat_manager = {
return MessageModel.call('mark_as_unread', [message_ids, [channel.id]]);
},
mark_channel_as_seen: function (channel) {
if (channel.unread_counter > 0) {
if (channel.unread_counter > 0 && channel.type !== 'static') {
update_channel_unread_counter(channel, 0);
channel_seen(channel);
}
+2 -7
View File
@@ -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();
},
+18 -5
View File
@@ -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 () {
+10 -7
View File
@@ -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;
},
});
+3
View File
@@ -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;
+21 -8
View File
@@ -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;
}
});
+3 -3
View File
@@ -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 {