diff options
| author | Vidhin Mehta (OpenERP) <vme@tinyerp.com> | 2012-09-13 12:04:49 +0530 |
|---|---|---|
| committer | Vidhin Mehta (OpenERP) <vme@tinyerp.com> | 2012-09-13 12:04:49 +0530 |
| commit | dc97de0e27bb1ce5d1e1ef44f4b09b48764a01f2 (patch) | |
| tree | 6b6d7763cc79163175edbe96b455a8577c0b5c9b /addons/mail/static/src | |
| parent | 881b1ed7cc4396ded4937975be110d1ac59b0fa0 (diff) | |
| parent | 74df8d0147b79a61fcf961231be8b82a5f86ef99 (diff) | |
[MERGE]TRUNk.
bzr revid: vme@tinyerp.com-20120913063449-t6hftj16o25onju0
Diffstat (limited to 'addons/mail/static/src')
| -rw-r--r-- | addons/mail/static/src/css/mail.css | 63 | ||||
| -rw-r--r-- | addons/mail/static/src/css/mail_group.css | 1 | ||||
| -rw-r--r-- | addons/mail/static/src/js/mail.js | 396 | ||||
| -rw-r--r-- | addons/mail/static/src/js/mail_followers.js | 2 | ||||
| -rw-r--r-- | addons/mail/static/src/xml/mail.xml | 88 |
5 files changed, 309 insertions, 241 deletions
diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 815f0ec92c4..92ead6f2432 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -230,6 +230,10 @@ clear: both; } +.openerp .oe_mail_msg_content a { + cursor: pointer; +} + .openerp img.oe_mail_icon { width: 50px; height: 50px; @@ -307,6 +311,29 @@ padding: 1px; } +/* attachment button: override of openerp values */ +.openerp .oe_mail_msg_content .oe_mail_compose_message_icons div.oe_hidden_input_file { + display: inline-block; + width: 24px; + height: 24px; + margin: 2px; +} +.openerp .oe_mail_msg_content .oe_mail_compose_message_icons div.oe_hidden_input_file button { + margin: 0px; +} +.openerp .oe_mail_msg_content .oe_mail_compose_message_icons input.oe_form_binary_file { + bottom: 0px; + top: auto; + left: auto; + right: 28px; + height: 26px; + width: 26px; + min-width: 22px; + font-size: 0px; + margin: 0px; + padding: 0px; +} + /* ------------------------------------------------------------ */ /* Messages layout /* ------------------------------------------------------------ */ @@ -322,31 +349,20 @@ text-decoration: none; } -.openerp .oe_mail_msg_footer { - color: #888; -} - -.openerp .oe_mail_msg_footer li { - float: left; - margin-right: 3px; -} - -.openerp .oe_mail_msg_body { +.openerp .oe_mail_msg .oe_mail_msg_body { margin-bottom: .5em; text-align: justify; } -.openerp .oe_mail_msg_record_body pre { +.openerp .oe_mail_msg .oe_mail_msg_body pre { font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif; margin: 0px; -} - -.openerp .oe_mail_msg_body span.oe_mail_msg_tail { + white-space: pre-wrap; display: inline; } /* Read more/less link */ -.openerp .oe_mail_msg_content .oe_mail_reduce { +.openerp .oe_mail_msg span.oe_mail_reduce { position: absolute; right: 0; } @@ -364,16 +380,23 @@ border-top: 4px solid #404040; } -.openerp .oe_mail_msg_footer li:after { +/* Message footer */ +.openerp .oe_mail_msg .oe_mail_msg_footer { + color: #888; +} +.openerp .oe_mail_msg .oe_mail_msg_footer li { + float: left; + margin-right: 3px; +} +.openerp .oe_mail_msg .oe_mail_msg_footer li:after { content: " ยท "; } - -.openerp .oe_mail_msg_footer li:last-child:after { +.openerp .oe_mail_msg .oe_mail_msg_footer li:last-child:after { content: ""; } /* Attachments list */ -.openerp ul.oe_mail_msg_attachments { +.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments { display: none; width: 100%; border-top: 1px solid #CCC; @@ -381,7 +404,7 @@ padding: .5em 0; list-style-position: inside; } -.openerp ul.oe_mail_msg_attachments li { +.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments li { float: none; margin: 0; padding: 0; diff --git a/addons/mail/static/src/css/mail_group.css b/addons/mail/static/src/css/mail_group.css index 8f4ca61d531..b700cb8c80f 100644 --- a/addons/mail/static/src/css/mail_group.css +++ b/addons/mail/static/src/css/mail_group.css @@ -12,7 +12,6 @@ min-height: 0px; max-height: none; padding: 0px 18px; - max-width: 80%; } /* Resize footer width */ diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index e8d8e25e684..71665bc69fb 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -17,19 +17,13 @@ openerp.mail = function(session) { */ session.web.FormView = session.web.FormView.extend({ - // TDE FIXME TODO: CHECK WITH NEW BRANCH do_action: function(action, on_close) { if (action.res_model == 'mail.compose.message' && - this.fields && this.fields.message_ids && - this.fields.message_ids.view.get("actual_mode") != 'create') { - // debug - console.groupCollapsed('FormView do_action on mail.compose.message'); - console.log('message_ids field:', this.fields.message_ids); - console.groupEnd(); - var record_thread = this.fields.message_ids; - var thread = record_thread.thread; - thread.instantiate_composition_form('comment', true, false, 0, action.context); - return false; + action.context && action.context.redirect == true && + this.fields && this.fields.message_ids && this.fields.message_ids.view.get("actual_mode") != 'create') { + var thread = this.fields.message_ids.thread; + thread.refresh_composition_form(action.context); + return true; } else { return this._super(action, on_close); @@ -37,35 +31,32 @@ openerp.mail = function(session) { }, }); + /** * ------------------------------------------------------------ * ChatterUtils * ------------------------------------------------------------ * - * This class holds a few tools method that will be used by - * the various Chatter widgets. - * + * This class holds a few tools method for Chatter. * Some regular expressions not used anymore, kept because I want to * - (^|\s)@((\w|@|\.)*): @login@log.log - * 1. '(void)' - * 2. login@log.log * - (^|\s)\[(\w+).(\w+),(\d)\|*((\w|[@ .,])*)\]: [ir.attachment,3|My Label], * for internal links - * 1. '(void)' - * 2. 'ir' - * 3. 'attachment' - * 4. '3' - * 5. 'My Label' */ mail.ChatterUtils = { - /** get an image in /web/binary/image?... */ - get_image: function(session_prefix, session_id, model, field, id) { - return session_prefix + '/web/binary/image?session_id=' + session_id + '&model=' + model + '&field=' + field + '&id=' + (id || ''); + /** Get an image in /web/binary/image?... */ + get_image: function(session, model, field, id) { + return session.prefix + '/web/binary/image?session_id=' + session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || ''); + }, + + /** Get the url of an attachment {'id': id} */ + get_attachment_url: function (session, attachment) { + return session.origin + '/web/binary/saveas?session_id=' + session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id=' + attachment['id']; }, - /** check if the current user is the message author */ + /** Check if the current user is the message author */ is_author: function (widget, message_user_id) { return (widget.session && widget.session.uid != 0 && widget.session.uid == message_user_id); }, @@ -111,21 +102,19 @@ openerp.mail = function(session) { init: function (parent, options) { var self = this; this._super(parent); + this.attachment_ids = []; // options this.options = options || {}; this.options.context = options.context || {}; this.options.form_xml_id = options.form_xml_id || 'email_compose_message_wizard_form_chatter'; this.options.form_view_id = options.form_view_id || false; - // debug - // console.groupCollapsed('New ComposeMessage: model', this.options.context.default_res_model, ', id', this.options.context.default_res_id); - // console.log('context:', this.options.context); - // console.groupEnd(); + this.show_attachment_delete = true; }, start: function () { this._super.apply(this, arguments); // customize display: add avatar, clean previous content - var user_avatar = mail.ChatterUtils.get_image(this.session.prefix, this.session.session_id, 'res.users', 'image_small', this.session.uid); + var user_avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid); this.$el.find('img.oe_mail_icon').attr('src', user_avatar); this.$el.find('div.oe_mail_msg_content').empty(); // create a context for the dataset and default_get of the wizard @@ -156,10 +145,52 @@ openerp.mail = function(session) { }); // add the form, bind events, activate the form var msg_node = this.$el.find('div.oe_mail_msg_content'); - return $.when(this.form_view.appendTo(msg_node)).pipe(function() { - self.bind_events(); - self.form_view.do_show(); - }); + return $.when(this.form_view.appendTo(msg_node)).pipe(this.proxy('postprocess_create_form_view')); + }, + + postprocess_create_form_view: function () { + // handle attachment button + this.fileupload_id = _.uniqueId('oe_fileupload'); + var button_attach = this.$el.find('button.oe_mail_compose_message_attachment'); + var rendered = session.web.qweb.render('mail.compose_message.add_attachment', {'widget': this}); + $(rendered).insertBefore(button_attach); + // move the button inside div.oe_hidden_input_file + var input_node = this.$el.find('input[name=ufile]'); + button_attach.detach().insertAfter(input_node); + // set the function called when attachments are added + this.$el.find('input.oe_form_binary_file').change(this.on_attachment_change); + this.bind_events(); + this.form_view.do_show(); + }, + + on_attachment_change: function (event) { + var $target = $(event.target); + if ($target.val() !== '') { + this.$el.find('form.oe_form_binary_form').submit(); + session.web.blockUI(); + } + }, + + on_attachment_delete: function (event) { + if (event.target.dataset && event.target.dataset.id) { + var attachment_id = parseInt(event.target.dataset.id); + var idx = _.pluck(this.attachment_ids, 'id').indexOf(attachment_id); + if (idx == -1) return false; + new session.web.DataSetSearch(this, 'ir.attachment').unlink(attachment_id); + this.attachment_ids.splice(idx, 1); + this.display_attachments(); + } + }, + + display_attachments: function () { + var attach_node = this.$el.find('div.oe_mail_compose_message_attachments'); + var rendered = session.web.qweb.render('mail.thread.message.attachments', {'record': this}); + attach_node.empty(); + $(rendered).appendTo(attach_node); + this.$el.find('.oe_mail_msg_attachments').show(); + var composer_attachment_ids = _.pluck(this.attachment_ids, 'id'); + var onchange_like = {'value': {'attachment_ids': composer_attachment_ids}} + this.form_view.on_processed_onchange(onchange_like, []); }, /** @@ -170,13 +201,18 @@ openerp.mail = function(session) { refresh: function (new_context) { if (! this.form_view) return; var self = this; + this.attachments = []; this.options.context = _.extend(this.options.context, new_context || {}); this.ds_compose.context = _.extend(this.ds_compose.context, this.options.context); return this.ds_compose.call('default_get', [ - ['subject', 'body_text', 'body', 'attachment_ids', 'partner_ids', 'composition_mode', - 'model', 'res_id', 'parent_id', 'content_subtype'], + ['subject', 'body_text', 'body', 'partner_ids', 'composition_mode', + 'use_template', 'template_id', 'model', 'res_id', 'parent_id', 'content_subtype'], this.ds_compose.get_context(), - ]).then( function (result) { self.form_view.on_processed_onchange({'value': result}, []); }); + ]).then( function (result) { + self.form_view.on_processed_onchange({'value': result}, []); + self.attachment_ids = []; + self.display_attachments(); + }); }, /** @@ -184,11 +220,17 @@ openerp.mail = function(session) { * in the function. */ bind_events: function() { var self = this; - // event: click on 'Attachment' icon-link that opens the dialog to - // add an attachment. - this.$el.on('click', 'button.oe_mail_compose_message_attachment', function (event) { - event.stopImmediatePropagation(); + // event: add a new attachment + $(window).on(this.fileupload_id, function() { + var args = [].slice.call(arguments).slice(1); + var attachment = args[0]; + attachment['url'] = mail.ChatterUtils.get_attachment_url(self.session, attachment); + self.attachment_ids.push(attachment); + self.display_attachments(); + session.web.unblockUI(); }); + // event: delete an attachment + this.$el.on('click', '.oe_mail_attachment_delete', self.on_attachment_delete); }, }), @@ -210,47 +252,48 @@ openerp.mail = function(session) { /** * @param {Object} parent parent - * @param {Object} [options] - * @param {Object} [options.context] context of the thread. It should + * @param {Array} [domain] + * @param {Object} [context] context of the thread. It should contain at least default_model, default_res_id. Please refer to the ComposeMessage widget for more information about it. - * @param {Number} [options.thread_level=0] number of thread levels + * @param {Object} [options] * @param {Number} [options.message_ids=null] ids for message_fetch * @param {Number} [options.message_data=null] already formatted message data, for subthreads getting data from their parent - * @param {Boolean} [options.composer] use the advanced composer, or + * @param {Number} [options.thread_level=0] number of thread levels + * @param {Boolean} [options.use_composer] use the advanced composer, or the default basic textarea if not set * @param {Number} [options.truncate_limit=250] number of character to * display before having a "show more" link; note that the text * will not be truncated if it does not have 110% of the parameter */ - init: function(parent, options) { + init: function(parent, domain, context, options) { this._super(parent); - // options - this.options = options || {}; - this.options.domain = options.domain || []; - this.options.context = _.extend({ + this.domain = domain || []; + this.context = _.extend({ default_model: 'mail.thread', default_res_id: 0, - default_parent_id: false }, options.context || {}); - this.options.thread_level = options.thread_level || 0; - this.options.composer = options.composer || false; - this.options.message_ids = options.message_ids || null; - this.options.message_data = options.message_data || null; - // datasets and internal vars - this.ds_thread = new session.web.DataSetSearch(this, this.options.context.default_model); - this.ds_notification = new session.web.DataSetSearch(this, 'mail.notification'); - this.ds_message = new session.web.DataSetSearch(this, 'mail.message'); - // display customization vars - this.display = { - truncate_limit: options.truncate_limit || 250, - show_header_compose: options.show_header_compose || false, + default_parent_id: false }, context || {}); + // options + this.options = { + message_ids: options.message_ids || null, + message_data: options.message_data || null, + thread_level: options.thread_level || 0, + use_composer: options.use_composer || false, + show_header_compose: options.show_header_compose != undefined ? options.show_header_compose: true, + show_record_name: options.show_record_name != undefined ? options.show_record_name: true, show_reply: options.show_reply || false, - show_delete: options.show_delete || false, - show_hide: options.show_hide || false, show_reply_by_email: options.show_reply_by_email || false, + show_dd_reply_by_email:options.show_dd_reply_by_email != undefined ? options.show_dd_reply_by_email: true, + show_dd_delete: options.show_dd_delete || false, + show_dd_hide: options.show_dd_hide || false, show_more: options.show_more || false, + truncate_limit: options.truncate_limit || 250, } + // datasets and internal vars + this.ds_thread = new session.web.DataSetSearch(this, this.context.default_model); + this.ds_notification = new session.web.DataSetSearch(this, 'mail.notification'); + this.ds_message = new session.web.DataSetSearch(this, 'mail.message'); }, start: function() { @@ -260,7 +303,7 @@ openerp.mail = function(session) { // fetch and display message, using message_ids if set var display_done = $.when(this.message_fetch(true, [], {})).then(this.proxy('do_customize_display')); // add message composition form view - if (this.display.show_header_compose && this.options.composer) { + if (this.options.show_header_compose && this.options.use_composer) { var compose_done = this.instantiate_composition_form(); } return display_done && compose_done; @@ -270,7 +313,9 @@ openerp.mail = function(session) { * - show_header_compose: show the composition form in the header */ do_customize_display: function() { this.display_user_avatar(); - if (this.display.show_header_compose) { this.$el.find('div.oe_mail_thread_action').eq(0).show(); } + if (this.options.show_header_compose) { + this.$el.find('div.oe_mail_thread_action').eq(0).show(); + } }, /** @@ -278,10 +323,8 @@ openerp.mail = function(session) { * in the function. */ bind_events: function() { var self = this; - // event: click on 'more' at bottom of thread - this.$el.find('button.oe_mail_button_more').click(function () { - self.do_message_fetch(); - }); + // event: click on 'More' at bottom of thread + this.$el.on('click', 'button.oe_mail_button_more', this.do_message_fetch_more); // event: writing in basic textarea of composition form (quick reply) this.$el.find('textarea.oe_mail_compose_textarea').keyup(function (event) { var charCode = (event.which) ? event.which : window.event.keyCode; @@ -290,41 +333,21 @@ openerp.mail = function(session) { }); // event: click on 'Reply' in msg this.$el.on('click', 'a.oe_mail_msg_reply', function (event) { - event.preventDefault(); - event.stopPropagation(); var act_dom = $(this).parents('li.oe_mail_thread_msg').eq(0).find('div.oe_mail_thread_action:first'); act_dom.toggle(); }); - // event: click on 'attachment(s)' in msg + // event: click on 'Attachment(s)' in msg this.$el.on('click', 'a.oe_mail_msg_view_attachments', function (event) { - event.preventDefault(); - event.stopPropagation(); var act_dom = $(this).parent().parent().parent().find('.oe_mail_msg_attachments'); act_dom.toggle(); }); // event: click on 'Delete' in msg side menu - this.$el.on('click', 'a.oe_mail_msg_delete', function (event) { - event.preventDefault(); - event.stopPropagation(); - if (! confirm(_t("Do you really want to delete this message?"))) { return false; } - var msg_id = event.srcElement.dataset.id; - if (! msg_id) return false; - $(event.srcElement).parents('li.oe_mail_thread_msg').eq(0).remove(); - return self.ds_msg.unlink([parseInt(msg_id)]); - }); + this.$el.on('click', 'a.oe_mail_msg_delete', this.on_message_delete); // event: click on 'Hide' in msg side menu - this.$el.on('click', 'a.oe_mail_msg_hide', function (event) { - event.preventDefault(); - event.stopPropagation(); - var msg_id = event.srcElement.dataset.id; - if (! msg_id) return false; - $(event.srcElement).parents('li.oe_mail_thread_msg').eq(0).remove(); - return self.ds_notif.call('set_message_read', [parseInt(msg_id)]); - }); - // event: click on "Reply by email" in msg side menu (email style) + this.$el.on('click', 'a.oe_mail_msg_hide', this.on_message_read); + // event: click on 'Reply by email' in msg side menu this.$el.on('click', 'a.oe_mail_msg_reply_by_email', function (event) { - event.preventDefault(); - event.stopPropagation(); + if (! self.compose_message_widget) return true; var msg_id = event.srcElement.dataset.msg_id; if (! msg_id) return false; self.compose_message_widget.refresh({ @@ -334,20 +357,37 @@ openerp.mail = function(session) { }); }, + on_message_delete: function (event) { + if (! confirm(_t("Do you really want to delete this message?"))) { return false; } + var msg_id = event.srcElement.dataset.id; + if (! msg_id) return false; + $(event.srcElement).parents('li.oe_mail_thread_msg').eq(0).remove(); + return this.ds_message.unlink([parseInt(msg_id)]); + }, + + on_message_read: function (event) { + //TDE: TODO + var msg_id = event.srcElement.dataset.id; + if (! msg_id) return false; + $(event.srcElement).parents('li.oe_mail_thread_msg').eq(0).remove(); + return this.ds_notification.call('set_message_read', [parseInt(msg_id)]); + }, + /** * Override-hack of do_action: automatically reload the chatter. * Normally it should be called only when clicking on 'Post/Send' * in the composition form. */ do_action: function(action, on_close) { + //TDE: TODO: instead of reloading, push the message ? this.message_clean(); this.message_fetch(); if (this.compose_message_widget) { this.compose_message_widget.refresh({ 'default_composition_mode': 'comment', - 'default_parent_id': this.options.default_parent_id, + 'default_parent_id': this.context.default_parent_id, 'default_content_subtype': 'plain'} ); } - return this._super(action, on_close); + // return this._super(action, on_close); }, /** Instantiate the composition form, with every parameters in context @@ -357,7 +397,7 @@ openerp.mail = function(session) { this.compose_message_widget.destroy(); } this.compose_message_widget = new mail.ComposeMessage(this, { - 'context': _.extend(context || {}, this.options.context), + 'context': _.extend(context || {}, this.context), }); var composition_node = this.$el.find('div.oe_mail_thread_action'); composition_node.empty(); @@ -365,6 +405,11 @@ openerp.mail = function(session) { return compose_done; }, + refresh_composition_form: function (context) { + if (! this.compose_message_widget) return; + return this.compose_message_widget.refresh(context); + }, + /** Clean the thread */ message_clean: function() { this.$el.find('div.oe_mail_thread_display').empty(); @@ -374,20 +419,20 @@ openerp.mail = function(session) { * @param {Bool} initial_mode: initial mode: try to use message_data or * message_ids, if nothing available perform a message_read; otherwise * directly perform a message_read - * @param {Array} additional_domain: added to options.domain - * @param {Object} additional_context: added to options.context + * @param {Array} additional_domain: added to this.domain + * @param {Object} additional_context: added to this.context */ message_fetch: function (initial_mode, additional_domain, additional_context) { var self = this; // domain and context: options + additional - fetch_domain = _.flatten([this.options.domain, additional_domain || []], true) - fetch_context = _.extend(this.options.context, additional_context || {}) - // if message_ids is set: try to use it + fetch_domain = _.flatten([this.domain, additional_domain || []], true) + fetch_context = _.extend(this.context, additional_context || {}) + // initial mode: try to use message_data or message_ids if (initial_mode && this.options.message_data) { return this.message_display(this.options.message_data); } - return this.ds_message.call('message_read', - [(initial_mode && this.options.message_ids) || false, fetch_domain, this.options.thread_level, undefined, fetch_context] + message_ids = initial_mode && this.options.message_ids != null && this.options.message_ids || false; + return this.ds_message.call('message_read', [message_ids, fetch_domain, this.options.thread_level, undefined, fetch_context] ).then(this.proxy('message_display')); }, @@ -407,19 +452,19 @@ openerp.mail = function(session) { } else { self.display_record(record); - // if (self.options.thread_level >= 0) { - self.thread = new mail.Thread(self, { - 'context': { - 'default_model': record.model, + self.thread = new mail.Thread(self, self.domain, + { 'default_model': record.model, 'default_res_id': record.res_id, 'default_parent_id': record.id }, - 'message_data': record.child_ids, 'thread_level': self.options.thread_level-1, - 'show_header_compose': false, 'show_reply': self.options.thread_level > 1, - 'show_hide': self.display.show_hide, 'show_delete': self.display.show_delete, - }); + { 'message_data': record.child_ids, + 'thread_level': self.options.thread_level - 1, + 'show_header_compose': false, + 'show_reply': self.options.show_reply && self.options.thread_level > 1, + 'show_reply_by_email': self.options.show_reply_by_email, + 'show_dd_hide': self.options.show_dd_hide, + 'show_dd_delete': self.options.show_dd_delete }); self.$el.find('li.oe_mail_thread_msg:last').append('<div class="oe_mail_thread_subthread"/>'); self.thread.appendTo(self.$el.find('div.oe_mail_thread_subthread:last')); - // } } }); if (! _expendable) { @@ -431,7 +476,7 @@ openerp.mail = function(session) { * - record.date: formatting according to the user timezone * - record.timerelative: relative time givein by timeago lib * - record.avatar: image url - * - record.attachments[].url: url of each attachment + * - record.attachment_ids[].url: url of each attachment * - record.is_author: is the current user the author of the record */ display_record: function (record) { // formatting and additional fields @@ -440,21 +485,18 @@ openerp.mail = function(session) { if (record.type == 'email') { record.avatar = ('/mail/static/src/img/email_icon.png'); } else { - record.avatar = mail.ChatterUtils.get_image(this.session.prefix, this.session.session_id, 'res.partner', 'image_small', record.author_id[0]); + record.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', record.author_id[0]); } - //TDE: FIX - if (record.attachments) { - for (var l in record.attachments) { - var url = self.session.origin + '/web/binary/saveas?session_id=' + self.session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id='+records[k].attachments[l].id; - record.attachments[l].url = url; - } + for (var l in record.attachment_ids) { + var attach = record.attachment_ids[l]; + attach['url'] = mail.ChatterUtils.get_attachment_url(this.session, attach); } record.is_author = mail.ChatterUtils.is_author(this, record.author_user_id[0]); // render, add the expand feature - var rendered = session.web.qweb.render('mail.thread.message', {'record': record, 'thread': this, 'params': this.options, 'display': this.display}); + var rendered = session.web.qweb.render('mail.thread.message', {'record': record, 'thread': this, 'options': this.options}); $(rendered).appendTo(this.$el.children('div.oe_mail_thread_display:first')); - this.$el.find('div.oe_mail_msg_record_body').expander({ - slicePoint: this.options.msg_more_limit, + this.$el.find('div.oe_mail_msg_body').expander({ + slicePoint: this.options.truncate_limit, expandText: 'read more', userCollapseText: '[^]', detailClass: 'oe_mail_msg_tail', @@ -473,7 +515,7 @@ openerp.mail = function(session) { }, display_user_avatar: function () { - var avatar = mail.ChatterUtils.get_image(this.session.prefix, this.session.session_id, 'res.users', 'image_small', this.session.uid); + var avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid); return this.$el.find('img.oe_mail_icon').attr('src', avatar); }, @@ -485,12 +527,12 @@ openerp.mail = function(session) { comment_node.val(''); } return this.ds_thread.call('message_post', [ - [this.options.context.default_res_id], body, false, 'comment', this.options.context.default_parent_id, undefined] + [this.context.default_res_id], body, false, 'comment', this.context.default_parent_id, undefined] ).then(self.message_fetch()); }, /** Action: 'shows more' to fetch new messages */ - do_message_fetch: function () { + do_message_fetch_more: function () { return this.message_fetch(false, this.fetch_more_domain, this.fetch_more_context); }, @@ -533,13 +575,11 @@ openerp.mail = function(session) { * mail_thread Widget * ------------------------------------------------------------ * - * This widget handles the display of the Chatter on documents. + * This widget handles the display of messages on a document. Its main + * use is to receive a context and a domain, and to delegate the message + * fetching and displaying to the Thread widget. */ - - /* Add mail_thread widget to registry */ session.web.form.widgets.add('mail_thread', 'openerp.mail.RecordThread'); - - /** mail_thread widget: thread of comments */ mail.RecordThread = session.web.form.AbstractField.extend({ template: 'mail.record_thread', @@ -548,13 +588,11 @@ openerp.mail = function(session) { this.options.domain = this.options.domain || []; this.options.context = {'default_model': 'mail.thread', 'default_res_id': false}; this.options.thread_level = this.options.thread_level || 0; - this.thread_list = []; }, start: function() { this._super.apply(this, arguments); - // NB: all the widget should be modified to check the actual_mode property on view, not use - // any other method to know if the view is in create mode anymore + // NB: check the actual_mode property on view to know if the view is in create mode anymore this.view.on("change:actual_mode", this, this._check_visibility); this._check_visibility(); }, @@ -563,11 +601,6 @@ openerp.mail = function(session) { this.$el.toggle(this.view.get("actual_mode") !== "create"); }, - destroy: function() { - for (var i in this.thread_list) { this.thread_list[i].destroy(); } - this._super.apply(this, arguments); - }, - set_value: function() { var self = this; this._super.apply(this, arguments); @@ -579,15 +612,15 @@ openerp.mail = function(session) { _.extend(this.options.context, { default_res_id: this.view.datarecord.id, default_model: this.view.model }); + // update domain + var domain = this.options.domain.concat([['model', '=', this.view.model], ['res_id', '=', this.view.datarecord.id]]); // create and render Thread widget this.$el.find('div.oe_mail_recthread_main').empty(); - for (var i in this.thread_list) { this.thread_list[i].destroy(); } - var thread = new mail.Thread(self, { - 'context': this.options.context, - 'thread_level': this.options.thread_level, 'show_header_compose': true, - 'message_ids': this.get_value(), - 'show_delete': true, 'composer': true }); - this.thread_list.push(thread); + var thread = new mail.Thread(self, domain, this.options.context, + { 'thread_level': this.options.thread_level, + 'use_composer': true, + 'show_dd_delete': true, + 'show_reply_by_email': true }); return thread.appendTo(this.$el.find('div.oe_mail_recthread_main')); }, }); @@ -598,22 +631,22 @@ openerp.mail = function(session) { * Wall Widget * ------------------------------------------------------------ * - * This widget handles the display of the Chatter on the Wall. + * This widget handles the display of messages on a Wall. Its main + * use is to receive a context and a domain, and to delegate the message + * fetching and displaying to the Thread widget. */ - - /* Add WallView widget to registry */ session.web.client_actions.add('mail.wall', 'session.mail.Wall'); - - /* WallView widget: a wall of messages */ mail.Wall = session.web.Widget.extend({ template: 'mail.wall', /** * @param {Object} parent parent * @param {Object} [options] - * @param {Number} [options.domain] domain on the Wall, is an array. - * @param {Number} [options.domain] context, is an object. It should + * @param {Array} [options.domain] domain on the Wall + * @param {Object} [options.context] context, is an object. It should * contain default_model, default_res_id, to give it to the threads. + * @param {Number} [options.thread_level] number of thread levels to display + * 0 being flat. */ init: function (parent, options) { this._super(parent); @@ -621,23 +654,15 @@ openerp.mail = function(session) { this.options.domain = options.domain || []; this.options.context = options.context || {}; this.options.thread_level = options.thread_level || 1; - this.thread_list = []; - this.ds_msg = new session.web.DataSetSearch(this, 'mail.message'); - // for search view - this.search = {'domain': [], 'context': {}, 'groupby': {}} this.search_results = {'domain': [], 'context': {}, 'groupby': {}} + this.ds_msg = new session.web.DataSetSearch(this, 'mail.message'); }, start: function () { this._super.apply(this, arguments); - var search_view_ready = this.load_search_view({}, false); - var thread_displayed = this.message_display(); - return (search_view_ready && thread_displayed); - }, - - destroy: function () { - for (var i in this.thread_list) { this.thread_list[i].destroy(); } - this._super.apply(this, arguments); + var searchview_ready = this.load_searchview({}, false); + var thread_displayed = this.message_render(); + return (searchview_ready && thread_displayed); }, /** @@ -645,7 +670,7 @@ openerp.mail = function(session) { * @param {Object} defaults ?? * @param {Boolean} hidden some kind of trick we do not care here */ - load_search_view: function (defaults, hidden) { + load_searchview: function (defaults, hidden) { var self = this; this.searchview = new session.web.SearchView(this, this.ds_msg, false, defaults || {}, hidden || false); return this.searchview.appendTo(this.$el.find('.oe_view_manager_view_search')).then(function () { @@ -654,9 +679,8 @@ openerp.mail = function(session) { }, /** - * Aggregate the domains, contexts and groupbys in parameter - * with those from search form, and then calls fetch_comments - * to actually fetch comments + * Get the domains, contexts and groupbys in parameter from search + * view, then render the filtered threads. * @param {Array} domains * @param {Array} contexts * @param {Array} groupbys @@ -671,30 +695,24 @@ openerp.mail = function(session) { self.search_results['context'] = results.context; self.search_results['domain'] = results.domain; self.search_results['groupby'] = results.group_by; - self.message_clean(); - return self.message_display(); + return self.message_render(); }); }, - /** Clean the wall */ - message_clean: function() { + /** Clean and display the threads */ + message_render: function () { this.$el.find('ul.oe_mail_wall_threads').empty(); - }, - - /** Display the Wall threads */ - message_display: function () { + var domain = this.options.domain.concat(this.search_results['domain']); var render_res = session.web.qweb.render('mail.wall_thread_container', {}); - $('<li class="oe_mail_wall_thread">').html(render_res).appendTo(this.$el.find('ul.oe_mail_wall_threads')); - var thread = new mail.Thread(this, { - 'domain': this.options.domain, 'context': this.options.context, - 'thread_level': this.options.thread_level, 'composer': true, - // display options - 'show_header_compose': true, 'show_reply': this.options.thread_level > 0, - 'show_hide': true, 'show_reply_by_email': true, + $(render_res).appendTo(this.$el.find('ul.oe_mail_wall_threads')); + var thread = new mail.Thread(this, domain, this.options.context, + { 'thread_level': this.options.thread_level, + 'use_composer': true, + 'show_reply': this.options.thread_level > 0, + 'show_dd_hide': true, } ); - thread.appendTo(this.$el.find('li.oe_mail_wall_thread:last')); - this.thread_list.push(thread); + return thread.appendTo(this.$el.find('li.oe_mail_wall_thread:last')); }, }); }; diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index e5d216ed3d2..34976269285 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -79,7 +79,7 @@ openerp_mail_followers = function(session, mail) { var node_user_list = this.$el.find('ul.oe_mail_followers_display').empty(); this.$el.find('div.oe_mail_recthread_followers h4').html(this.options.title + ' (' + records.length + ')'); _(records).each(function (record) { - record.avatar_url = mail.ChatterUtils.get_image(self.session.prefix, self.session.session_id, 'res.partner', 'image_small', record.id); + record.avatar_url = mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record.id); $(session.web.qweb.render('mail.followers.partner', {'record': record})).appendTo(node_user_list); }); if (this.message_is_follower) { diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 66b82d5a36c..4d3b56cf62f 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -39,8 +39,8 @@ wall_thread_container template for the wall Each discussion thread is contained inside this template --> - <t t-name="mail.wall_thread_container"> - </t> + <li t-name="mail.wall_thread_container" class="oe_mail_wall_thread"> + </li> <!-- record_thread main template @@ -74,6 +74,20 @@ </t> <!-- + mail.compose_message.add_attachment template + Small template to be inserted in the composition form to add attachments + --> + <t t-name="mail.compose_message.add_attachment"> + <t t-call="HiddenInputFile"> + <t t-set="fileupload_id" t-value="widget.fileupload_id"/> + <t t-set="fileupload_action">/web/binary/upload_attachment</t> + <input type="hidden" name="model" t-att-value="widget.form_view.model"/> + <input type="hidden" name="id" t-att-value="widget.form_view.datarecord.id || 0"/> + <input type="hidden" name="session_id" t-att-value="widget.session.session_id"/> + </t> + </t> + + <!-- thread template This template holds a thread of comments. It begins with an actions container, holding the composition form. Then come the various @@ -100,16 +114,14 @@ <!-- dropdown menu with message options and actions --> <span class="oe_dropdown_toggle oe_dropdown_arrow"> <ul class="oe_dropdown_menu"> - <t t-if="record.is_author"> - <li t-if="display['show_delete']"><a href="#" class="oe_mail_msg_delete" t-attf-data-id='{record.id}'>Delete</a></li> - </t> - <li t-if="display['show_hide']"><a href="#" class="oe_mail_msg_hide" t-attf-data-id='{record.id}'>Remove notification</a></li> + <li t-if="record.is_author & options.show_dd_delete"><a class="oe_mail_msg_delete" t-attf-data-id='{record.id}'>Delete</a></li> + <li t-if="options.show_dd_hide"><a class="oe_mail_msg_hide" t-attf-data-id='{record.id}'>Remove notification</a></li> <!-- Uncomment when adding subtype hiding <li t-if="display['show_hide']"> <a href="#" class="oe_mail_msg_hide_type" t-attf-data-subtype='{record.subtype}'>Hide '<t t-esc="record.subtype"/>' for this document</a> </li> --> - <li><a href="#" t-attf-data-msg_id="{record.id}" class="oe_mail_msg_reply_by_email">Quote and reply</a></li> - <li t-if="record.type == 'email'"><a t-attf-href="#model=mail.message&id=#{record.id}" class="oe_mail_msg_details">Details</a></li> + <li t-if="options.show_dd_reply_by_email"><a class="oe_mail_msg_reply_by_email" t-attf-data-msg_id="{record.id}">Quote and reply</a></li> + <li t-if="record.type == 'email'"><a class="oe_mail_msg_details" t-attf-href="#model=mail.message&id=#{record.id}" >Details</a></li> </ul> </span> <!-- message itself --> @@ -118,38 +130,54 @@ <t t-raw="record.subject"/> </h1> <div class="oe_mail_msg_body"> - <div class="oe_mail_msg_record_body"> - <a t-attf-href="#model=#{record.model}&id=#{record.res_id}" t-if="(params.thread_level > 0) & (!record.subject)"><t t-raw="record.record_name"/></a> - <t t-raw="record.body"/> - </div> + <t t-if="options.show_record_name & (!record.subject) & (options.thread_level > 0)"> + <a t-attf-href="#model=#{record.model}&id=#{record.res_id}"><t t-raw="record.record_name"/></a> + </t> + <t t-raw="record.body"/> </div> <div class="oe_clear"/> <ul class="oe_mail_msg_footer"> - <li t-if="record.subject & params.thread_level > 0"><a t-attf-href="#model=#{record.model}&id=#{record.res_id}"><t t-raw="record.record_name"/></a></li> - <li><a t-attf-href="#model=res.partner&id=#{record.author_id[0]}"><t t-raw="record.author_id[1]"/></a></li> - <li><span t-att-title="record.date"><t t-raw="record.timerelative"/></span></li> - <li t-if="display['show_reply']"><a href="#" class="oe_mail_msg_reply">Reply</a></li> - <!-- uncomment when merging vote - <li><a href="#">Like</a></li> - --> - <li t-if="record.attachment_ids.length > 0"> - <a href="#" class="oe_mail_msg_view_attachments"> - <t t-if="record.attachment_ids.length == 1">1 Attachment</t> - <t t-if="record.attachment_ids.length > 1"><t t-raw="record.attachment_ids.length"/> Attachments</t> - </a> - </li> + <li t-if="options.show_record_name & record.subject & options.thread_level > 0"> + <a t-attf-href="#model=#{record.model}&id=#{record.res_id}"><t t-raw="record.record_name"/></a> + </li> + <li><a t-attf-href="#model=res.partner&id=#{record.author_id[0]}"><t t-raw="record.author_id[1]"/></a></li> + <li><span t-att-title="record.date"><t t-raw="record.timerelative"/></span></li> + <li t-if="options.show_reply"><a class="oe_mail_msg_reply">Reply</a></li> + <li t-if="options.show_reply_by_email"><a class="oe_mail_msg_reply_by_email" t-attf-data-msg_id="{record.id}">Reply</a></li> + <!-- uncomment when merging vote + <li><a href="#">Like</a></li> + --> + <li t-if="record.attachment_ids.length > 0"> + <a class="oe_mail_msg_view_attachments"> + <t t-if="record.attachment_ids.length == 1">1 Attachment</t> + <t t-if="record.attachment_ids.length > 1"><t t-raw="record.attachment_ids.length"/> Attachments</t> + </a> + </li> </ul> <t t-if="record.attachment_ids.length > 0"> <div class="oe_clear"></div> - <ul class="oe_mail_msg_attachments"> - <t t-foreach="record.attachments" t-as="attachment"> - <li> <a t-att-href="attachment.url"><t t-raw="attachment.name"/></a> </li> - </t> - </ul> + <t t-call="mail.thread.message.attachments"/> </t> </div> </div> </div> </li> + <!-- + mail.thread.message.attachments template + Template used to display attachments in a mail.message + --> + <t t-name="mail.thread.message.attachments"> + <ul class="oe_mail_msg_attachments"> + <t t-foreach="record.attachment_ids" t-as="attachment"> + <li> + <a t-att-href="attachment.url"><t t-raw="attachment.name || attachment.filename"/></a> + <t t-if="record.show_attachment_delete"> + <a class="oe_right oe_mail_attachment_delete" title="Delete this attachmentt" t-attf-data-id="{attachment.id}">x</a> + </t> + </li> + </t> + </ul> + </t> + </template> |
