diff options
| author | Olivier Dony <odo@openerp.com> | 2016-02-03 17:15:37 +0100 |
|---|---|---|
| committer | Olivier Dony <odo@openerp.com> | 2016-02-03 17:19:16 +0100 |
| commit | d67d24d8b46e27df126429abc7572dcd455c03f4 (patch) | |
| tree | a17fa6b8a46e2a0204653f40d4299f685112ddef /addons/mail/static/src | |
| parent | 9c89f83d21b6b64f0ae05fad7aaaa3e885ab8b38 (diff) | |
| parent | 93e8bf8ccfb405a79377d1abaac0043f3d7f9157 (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.js | 3 | ||||
| -rw-r--r-- | addons/mail/static/src/js/chat_window.js | 1 | ||||
| -rw-r--r-- | addons/mail/static/src/js/client_action.js | 74 | ||||
| -rw-r--r-- | addons/mail/static/src/js/composer.js | 12 | ||||
| -rw-r--r-- | addons/mail/static/src/js/thread.js | 56 | ||||
| -rw-r--r-- | addons/mail/static/src/less/client_action.less | 17 | ||||
| -rw-r--r-- | addons/mail/static/src/less/thread.less | 9 | ||||
| -rw-r--r-- | addons/mail/static/src/xml/client_action.xml | 7 | ||||
| -rw-r--r-- | addons/mail/static/src/xml/thread.xml | 5 |
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 && message.author_id[0]"> <img t-if="message.avatar_src && message.display_author" @@ -103,6 +103,9 @@ <i t-if="message.is_needaction && 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 && message.model != 'mail.channel' && 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 && message.tracking_value_ids.length > 0"> |
