[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:
committed by
Aaron Bohy
parent
8397abd871
commit
30c26d7654
Binary file not shown.
|
After Width: | Height: | Size: 556 B |
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user