summaryrefslogtreecommitdiff
path: root/addons/mail/static/src
diff options
context:
space:
mode:
authorHarry (OpenERP) <hmo@tinyerp.com>2012-09-13 11:14:24 +0530
committerHarry (OpenERP) <hmo@tinyerp.com>2012-09-13 11:14:24 +0530
commit635d3cf9649ca7b9fb27ec85eb0ddf6b3065802e (patch)
tree9d4ba0d0fa1e4a064664b9f30115af41729498ee /addons/mail/static/src
parentee061a25f1348ce6b5ea110e28125c74ed2a4653 (diff)
parent74df8d0147b79a61fcf961231be8b82a5f86ef99 (diff)
[MERGE]
bzr revid: hmo@tinyerp.com-20120913054424-g3c2cykmxwhv34g3
Diffstat (limited to 'addons/mail/static/src')
-rw-r--r--addons/mail/static/src/css/mail.css70
-rw-r--r--addons/mail/static/src/css/mail_group.css1
-rw-r--r--addons/mail/static/src/js/mail.js401
-rw-r--r--addons/mail/static/src/js/mail_followers.js2
-rw-r--r--addons/mail/static/src/xml/mail.xml89
5 files changed, 314 insertions, 249 deletions
diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css
index 240627c9e6c..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,34 +349,20 @@
text-decoration: none;
}
-.openerp .oe_mail_msg_subtitle {
- margin: 0 0 .5em 0;
-}
-.openerp .oe_mail_msg_footer,
-.openerp .oe_mail_msg_subtitle {
- 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_body span.oe_mail_msg_tail {
+.openerp .oe_mail_msg .oe_mail_msg_body pre {
+ font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif;
+ margin: 0px;
+ white-space: pre-wrap;
display: inline;
}
-.openerp .oe_mail_oe_bold {
- font-weight: bold;
-}
-
/* Read more/less link */
-.openerp .oe_mail_msg_content .oe_mail_reduce {
+.openerp .oe_mail_msg span.oe_mail_reduce {
position: absolute;
right: 0;
}
@@ -367,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;
@@ -384,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 a5a64a59a8b..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,
- 'default_id': record.res_id,
+ 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.options.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);
},
@@ -484,13 +526,13 @@ openerp.mail = function(session) {
var body = comment_node.val();
comment_node.val('');
}
- return this.ds_post.call('message_post', [
- [this.options.context.res_id], body, false, 'comment', this.options.context.parent_id]
- ).then(this.proxy('message_fetch'));
+ return this.ds_thread.call('message_post', [
+ [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,14 +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,
- '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'));
},
});
@@ -597,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);
@@ -620,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);
},
/**
@@ -644,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 () {
@@ -653,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
@@ -670,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 f6be765c603..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 &amp; 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&amp;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&amp;id=#{record.id}" >Details</a></li>
</ul>
</span>
<!-- message itself -->
@@ -118,39 +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=#{params.res_model}&amp;id=#{params.res_id}" t-if="(params.thread_level > 0) &amp; (!record.subject)"><t t-raw="record.record_name"/></a>
- <t t-raw="record.body"/>
- </div>
+ <t t-if="options.show_record_name &amp; (!record.subject) &amp; (options.thread_level > 0)">
+ <a t-attf-href="#model=#{record.model}&amp;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 &amp; params.thread_level > 0"><a t-attf-href="#model=#{params.res_model}&amp;id=#{params.res_id}"><t t-raw="record.record_name"/></a></li>
- <li><a t-attf-href="#model=res.partner&amp;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 &amp; record.subject &amp; options.thread_level > 0">
+ <a t-attf-href="#model=#{record.model}&amp;id=#{record.res_id}"><t t-raw="record.record_name"/></a>
+ </li>
+ <li><a t-attf-href="#model=res.partner&amp;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>