summaryrefslogtreecommitdiff
path: root/addons/mail/static/src
diff options
context:
space:
mode:
authorOlivier Dony <odo@openerp.com>2016-02-03 17:15:37 +0100
committerOlivier Dony <odo@openerp.com>2016-02-03 17:19:16 +0100
commitd67d24d8b46e27df126429abc7572dcd455c03f4 (patch)
treea17fa6b8a46e2a0204653f40d4299f685112ddef /addons/mail/static/src
parent9c89f83d21b6b64f0ae05fad7aaaa3e885ab8b38 (diff)
parent93e8bf8ccfb405a79377d1abaac0043f3d7f9157 (diff)
[MERGE] Forward-port 9.0 up to 93e8bf8ccfb405a79377d1abaac0043f3d7f9157
Diffstat (limited to 'addons/mail/static/src')
-rw-r--r--addons/mail/static/src/js/chat_manager.js3
-rw-r--r--addons/mail/static/src/js/chat_window.js1
-rw-r--r--addons/mail/static/src/js/client_action.js74
-rw-r--r--addons/mail/static/src/js/composer.js12
-rw-r--r--addons/mail/static/src/js/thread.js56
-rw-r--r--addons/mail/static/src/less/client_action.less17
-rw-r--r--addons/mail/static/src/less/thread.less9
-rw-r--r--addons/mail/static/src/xml/client_action.xml7
-rw-r--r--addons/mail/static/src/xml/thread.xml5
9 files changed, 148 insertions, 36 deletions
diff --git a/addons/mail/static/src/js/chat_manager.js b/addons/mail/static/src/js/chat_manager.js
index 5e37bf237d8..a1272cea1ec 100644
--- a/addons/mail/static/src/js/chat_manager.js
+++ b/addons/mail/static/src/js/chat_manager.js
@@ -694,6 +694,9 @@ var chat_manager = {
}
},
+ get_message: function (id) {
+ return _.findWhere(messages, {id: id});
+ },
get_messages: function (options) {
var channel;
diff --git a/addons/mail/static/src/js/chat_window.js b/addons/mail/static/src/js/chat_window.js
index 0e0289c394e..1a9c0fa93ea 100644
--- a/addons/mail/static/src/js/chat_window.js
+++ b/addons/mail/static/src/js/chat_window.js
@@ -29,6 +29,7 @@ return Widget.extend({
this.folded = is_folded;
this.options = _.defaults(options || {}, {
display_stars: true,
+ display_reply_icon: false,
placeholder: _t("Say something"),
input_less: false,
});
diff --git a/addons/mail/static/src/js/client_action.js b/addons/mail/static/src/js/client_action.js
index a2b4a400a1b..7b4024f66d0 100644
--- a/addons/mail/static/src/js/client_action.js
+++ b/addons/mail/static/src/js/client_action.js
@@ -116,7 +116,7 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
chat_manager.undo_mark_as_read(msgs_ids, channel);
});
},
- "click .o_mail_annoying_notification_bar .fa-close": function (event) {
+ "click .o_mail_annoying_notification_bar .fa-close": function () {
this.$(".o_mail_annoying_notification_bar").slideUp();
},
"click .o_mail_request_permission": function (event) {
@@ -124,6 +124,11 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
this.$(".o_mail_annoying_notification_bar").slideUp();
window.Notification.requestPermission();
},
+ "keydown": function (event) {
+ if (event.which === $.ui.keyCode.ESCAPE && this.selected_message) {
+ this.unselect_message();
+ }
+ },
},
on_attach_callback: function () {
@@ -144,6 +149,7 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
this.channels_scrolltop = {};
this.throttled_render_sidebar = _.throttle(this.render_sidebar.bind(this), 100, { leading: false });
this.notification_bar = (window.Notification && window.Notification.permission === "default");
+ this.selected_message = null;
},
willStart: function () {
@@ -206,6 +212,9 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
this.thread.on('toggle_star_status', this, function (message_id) {
chat_manager.toggle_star_status(message_id);
});
+ this.thread.on('select_message', this, this.select_message);
+ this.thread.on('unselect_message', this, this.unselect_message);
+
this.basic_composer.on('post_message', this, this.on_post_message);
this.basic_composer.on('input_focused', this, this.on_composer_input_focused);
this.extended_composer.on('post_message', this, this.on_post_message);
@@ -241,6 +250,31 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
});
},
+ select_message: function(message_id) {
+ this.$el.addClass('o_mail_selection_mode');
+ var message = chat_manager.get_message(message_id);
+ this.selected_message = message;
+ var subject = "Re: " + message.record_name;
+ this.extended_composer.set_subject(subject);
+ if (this.channel.type !== 'static') {
+ this.basic_composer.toggle(false);
+ }
+ this.extended_composer.toggle(true);
+ this.thread.scroll_to({id: message_id, duration: 200, only_if_necessary: true});
+ this.extended_composer.focus('body');
+ },
+
+ unselect_message: function() {
+ if (this.channel.type !== 'static' && !this.channel.mass_mailing) {
+ this.basic_composer.toggle(true);
+ this.basic_composer.focus();
+ }
+ this.$el.removeClass('o_mail_selection_mode');
+ this.extended_composer.toggle(this.channel.mass_mailing);
+ this.thread.unselect();
+ this.selected_message = null;
+ },
+
render_sidebar: function () {
var self = this;
var $sidebar = $(QWeb.render("mail.chat.Sidebar", {
@@ -299,14 +333,16 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
});
},
- render_snackbar: function (nb_needactions) {
- this.$snackbar = $(QWeb.render('mail.chat.UndoSnackbar', {
- nb_needactions: nb_needactions,
- }));
+ render_snackbar: function (template, context, timeout) {
+ if (this.$snackbar) {
+ this.$snackbar.remove();
+ }
+ timeout = timeout || 20000;
+ this.$snackbar = $(QWeb.render(template, context));
this.$('.o_mail_chat_content').append(this.$snackbar);
- // Hide snackbar after 20s
+ // Hide snackbar after [timeout] milliseconds (by default, 20s)
var $snackbar = this.$snackbar;
- setTimeout(function() { $snackbar.fadeOut(); }, 20000);
+ setTimeout(function() { $snackbar.fadeOut(); }, timeout);
},
do_search_channel: function(search_val){
@@ -349,7 +385,9 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
if (channel.type !== 'static') {
// Display snackbar if needactions have been cleared
if (channel.needaction_counter > 0) {
- self.render_snackbar(channel.needaction_counter);
+ self.render_snackbar('mail.chat.MessageSentSnackbar', {
+ nb_needactions: channel.needaction_counter,
+ });
}
chat_manager.mark_channel_as_seen(channel);
self.clear_needactions_def = chat_manager.mark_all_as_read(channel);
@@ -374,6 +412,7 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
self.basic_composer.toggle(channel.type !== 'static' && !channel.mass_mailing);
self.extended_composer.toggle(channel.type !== 'static' && channel.mass_mailing);
+ self.$el.removeClass('o_mail_selection_mode');
self.$('.o_mail_chat_channel_item')
.removeClass('o_active')
@@ -439,6 +478,7 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
display_empty_channel: !messages.length && !this.domain.length,
display_no_match: !messages.length && this.domain.length,
display_subject: this.channel.mass_mailing || this.channel.id === "channel_inbox",
+ display_reply_icon: true,
};
},
@@ -512,11 +552,25 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
on_post_message: function (message) {
var self = this;
- var options = {channel_id: this.channel.id};
+ var options = this.selected_message ? {} : {channel_id: this.channel.id};
+ if (this.selected_message) {
+ message.subtype = 'mail.mt_comment';
+ message.subtype_id = false;
+ message.message_type = 'comment';
+ message.content_subtype = 'html';
+
+ options.model = this.selected_message.model;
+ options.res_id = this.selected_message.res_id;
+ }
chat_manager
.post_message(message, options)
.then(function() {
- self.thread.scroll_to();
+ if (self.selected_message) {
+ self.render_snackbar('mail.chat.MessageSentSnackbar', {record_name: self.selected_message.record_name}, 5000);
+ self.unselect_message();
+ } else {
+ self.thread.scroll_to();
+ }
})
.fail(function () {
// todo: display notification
diff --git a/addons/mail/static/src/js/composer.js b/addons/mail/static/src/js/composer.js
index 92bac153267..6ffd2bc63c3 100644
--- a/addons/mail/static/src/js/composer.js
+++ b/addons/mail/static/src/js/composer.js
@@ -698,9 +698,15 @@ var ExtendedComposer = BasicComposer.extend({
should_send: function () {
return false;
},
-
- focus: function () {
- this.$subject_input.focus();
+ focus: function (target) {
+ if (target === 'body') {
+ this.$input.focus();
+ } else {
+ this.$subject_input.focus();
+ }
+ },
+ set_subject: function(subject) {
+ this.$('.o_composer_subject input').val(subject);
},
});
diff --git a/addons/mail/static/src/js/thread.js b/addons/mail/static/src/js/thread.js
index aee712ea905..dc2467d3862 100644
--- a/addons/mail/static/src/js/thread.js
+++ b/addons/mail/static/src/js/thread.js
@@ -21,27 +21,36 @@ var Thread = Widget.extend({
"click strong": "on_click_redirect",
"click .o_thread_show_more": "on_click_show_more",
"click .o_thread_message_needaction": function (event) {
- event.stopPropagation();
var message_id = $(event.currentTarget).data('message-id');
this.trigger("mark_as_read", message_id);
},
"click .o_thread_message_star": function (event) {
- event.stopPropagation();
var message_id = $(event.currentTarget).data('message-id');
this.trigger("toggle_star_status", message_id);
},
- "click .o_thread_message": function (event) {
- var selected = $(event.currentTarget).hasClass('o_thread_selected_message');
+ "click .o_thread_message_reply": function (event) {
+ this.selected_id = $(event.currentTarget).data('message-id');
this.$('.o_thread_message').removeClass('o_thread_selected_message');
- $(event.currentTarget).toggleClass('o_thread_selected_message', !selected);
+ this.$('.o_thread_message[data-message-id=' + this.selected_id + ']')
+ .addClass('o_thread_selected_message');
+ this.trigger('select_message', this.selected_id);
+ event.stopPropagation();
},
"click .oe_mail_expand": function (event) {
event.preventDefault();
- event.stopPropagation();
var $message = $(event.currentTarget).parents('.o_thread_message');
$message.addClass('o_message_expanded');
this.expanded_msg_ids.push($message.data('message-id'));
},
+ "click .o_thread_message": function (event) {
+ $(event.currentTarget).toggleClass('o_thread_selected_message');
+ },
+ "click": function () {
+ if (this.selected_id) {
+ this.unselect();
+ this.trigger('unselect_message');
+ }
+ },
},
init: function (parent, options) {
@@ -54,8 +63,10 @@ var Thread = Widget.extend({
display_avatar: true,
shorten_messages: true,
squash_close_messages: true,
+ display_reply_icon: false,
});
this.expanded_msg_ids = [];
+ this.selected_id = null;
},
render: function (messages, options) {
@@ -69,11 +80,14 @@ var Thread = Widget.extend({
// Hide avatar and info of a message if that message and the previous
// one are both comments wrote by the same author at the same minute
+ // and in the same document (users can now post message in documents
+ // directly from a channel that follows it)
var prev_msg;
_.each(msgs, function (msg) {
if (!prev_msg || (Math.abs(msg.date.diff(prev_msg.date)) > 60000) ||
prev_msg.message_type !== 'comment' || msg.message_type !== 'comment' ||
- (prev_msg.author_id[0] !== msg.author_id[0])) {
+ (prev_msg.author_id[0] !== msg.author_id[0]) || prev_msg.model !== msg.model ||
+ prev_msg.res_id !== msg.res_id) {
msg.display_author = true;
} else {
msg.display_author = !options.squash_close_messages;
@@ -138,6 +152,7 @@ var Thread = Widget.extend({
}
msg.display_subject = message.subject && !message.is_system_notification;
+ msg.is_selected = msg.id === this.selected_id;
return msg;
},
@@ -159,18 +174,23 @@ var Thread = Widget.extend({
/**
* Scrolls the thread to a given message or offset if any, to bottom otherwise
- * @param {int} [target.id] optional: the id of the message to scroll to
- * @param {int} [target.offset] optional: the number of pixels to scroll
+ * @param {int} [options.id] optional: the id of the message to scroll to
+ * @param {int} [options.offset] optional: the number of pixels to scroll
*/
- scroll_to: function (target) {
- target = target || {};
- if (target.id !== undefined) {
- var $target = this.$('.o_thread_message[data-message-id=' + target.id + ']');
- if ($target.length) {
+ scroll_to: function (options) {
+ options = options || {};
+ if (options.id !== undefined) {
+ var $target = this.$('.o_thread_message[data-message-id=' + options.id + ']');
+ if (options.only_if_necessary) {
+ var delta = $target.parent().height() - $target.height();
+ var offset = delta < 0 ? 0 : delta - ($target.offset().top - $target.offsetParent().offset().top);
+ offset = - Math.min(offset, 0);
+ this.$el.scrollTo("+=" + offset + "px", options);
+ } else if ($target.length) {
this.$el.scrollTo($target);
}
- } else if (target.offset !== undefined) {
- this.$el.scrollTop(target.offset);
+ } else if (options.offset !== undefined) {
+ this.$el.scrollTop(options.offset);
} else {
this.$el.scrollTop(this.el.scrollHeight);
}
@@ -181,6 +201,10 @@ var Thread = Widget.extend({
is_at_bottom: function () {
return this.el.scrollHeight - this.$el.scrollTop() - this.$el.outerHeight() < 5;
},
+ unselect: function () {
+ this.$('.o_thread_message').removeClass('o_thread_selected_message');
+ this.selected_id = null;
+ },
});
Thread.ORDER = ORDER;
diff --git a/addons/mail/static/src/less/client_action.less b/addons/mail/static/src/less/client_action.less
index c4b28874358..ecf4785f03e 100644
--- a/addons/mail/static/src/less/client_action.less
+++ b/addons/mail/static/src/less/client_action.less
@@ -112,6 +112,9 @@
height: 100%;
margin-left: @mail-chat-sidebar-width;
position: relative;
+ @media (min-width: @screen-sm-min) {
+ overflow: auto;
+ }
@media (max-width: @screen-xs-max) {
margin-left: 0;
@@ -120,8 +123,7 @@
.o_mail_thread {
.o-flex(1, 0, 0);
overflow: auto;
- .o-webclient-padding();
- padding-bottom: 15px;
+ padding: 0 0 15px 0;
.o_chat_help_message {
padding: 25px 0;
@@ -253,6 +255,17 @@
}
}
}
+
+ &.o_mail_selection_mode {
+ .o_thread_message {
+ opacity: 0.5;
+ &.o_thread_selected_message {
+ padding: 4px @odoo-horizontal-padding;
+ opacity: 1;
+ background-color: lightgray;
+ }
+ }
+ }
}
// User status bullet (in Discuss sidebar and Invite dialog)
diff --git a/addons/mail/static/src/less/thread.less b/addons/mail/static/src/less/thread.less
index 7f0f144ffd8..7da1a13802e 100644
--- a/addons/mail/static/src/less/thread.less
+++ b/addons/mail/static/src/less/thread.less
@@ -40,7 +40,8 @@
.o_thread_message {
.o-flex-display();
- padding: 4px 0;
+ padding: 4px @odoo-horizontal-padding;
+ margin-bottom: 0px;
.o_thread_message_sidebar {
.o-flex(0, 0, @mail-thread-avatar-size);
@@ -69,7 +70,7 @@
}
}
- i.o_thread_message_star, i.o_thread_message_needaction {
+ i.o_thread_message_star, i.o_thread_message_needaction, i.o_thread_message_reply {
cursor: pointer;
opacity: 0;
&.fa-star {
@@ -83,7 +84,7 @@
opacity: @mail-thread-side-date-opacity;
}
- i.o_thread_message_star, i.o_thread_message_needaction {
+ i.o_thread_message_star, i.o_thread_message_needaction, i.o_thread_message_reply {
opacity: @mail-thread-icon-opacity;
&:hover {
opacity: 1;
@@ -141,7 +142,7 @@
}
}
- .o_thread_message_star, .o_thread_message_needaction {
+ .o_thread_message_star, .o_thread_message_needaction, .o_thread_message_reply {
padding: 4px;
}
}
diff --git a/addons/mail/static/src/xml/client_action.xml b/addons/mail/static/src/xml/client_action.xml
index 78371340e36..15eadb00626 100644
--- a/addons/mail/static/src/xml/client_action.xml
+++ b/addons/mail/static/src/xml/client_action.xml
@@ -118,6 +118,13 @@
</div>
</t>
+ <t t-name="mail.chat.MessageSentSnackbar">
+ <div class="alert o_mail_snackbar" data-dismiss="alert" role="alert">
+ Message sent in "<t t-esc="record_name"/>".
+ </div>
+ </t>
+
+
<!-- Buttons of the Control Panel -->
<t t-name="mail.chat.ControlButtons">
<div>
diff --git a/addons/mail/static/src/xml/thread.xml b/addons/mail/static/src/xml/thread.xml
index ca863d9ad8f..6ed0700be11 100644
--- a/addons/mail/static/src/xml/thread.xml
+++ b/addons/mail/static/src/xml/thread.xml
@@ -46,7 +46,7 @@
</t>
<t t-name="mail.ChatThread.Message">
- <div t-att-class="'o_thread_message' + (message.expanded ? ' o_message_expanded' : '')" t-att-data-message-id="message.id">
+ <div t-att-class="'o_thread_message' + (message.expanded ? ' o_message_expanded ' : ' ') + (message.is_selected ? 'o_thread_selected_message' : '')" t-att-data-message-id="message.id">
<div t-if="options.display_avatar" class="o_thread_message_sidebar">
<t t-if="!message.mailto &amp;&amp; message.author_id[0]">
<img t-if="message.avatar_src &amp;&amp; message.display_author"
@@ -103,6 +103,9 @@
<i t-if="message.is_needaction &amp;&amp; options.display_needactions"
class="fa fa-check o_thread_message_needaction"
t-att-data-message-id="message.id" title="Mark as Read"/>
+ <i t-if="message.record_name &amp;&amp; message.model != 'mail.channel' &amp;&amp; options.display_reply_icon"
+ class="fa fa-reply o_thread_message_reply"
+ t-att-data-message-id="message.id" title="Reply"/>
</span>
</p>
<t t-if="message.tracking_value_ids &amp;&amp; message.tracking_value_ids.length &gt; 0">