summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/js
diff options
context:
space:
mode:
authorThibault Delavallée <tde@openerp.com>2013-03-01 11:11:22 +0100
committerThibault Delavallée <tde@openerp.com>2013-03-01 11:11:22 +0100
commitecd14f2181f06966eefd7a3f9c4e399830c6518a (patch)
tree60c74d186d0a128eff9afbc0fb0217492df42bde /addons/mail/static/src/js
parentd48f07fef165db921a85db77b5a3c114d71c5e38 (diff)
parenteb799b5e49d31d6f38817f73a3c8a27b63cdf4b3 (diff)
[MERGE] Chatter and CRM: usability fixes and improvements
Chatter: - now displays the 'To' of messages, aka notified people, - now allows to Send a message or to Log a note, that is a message not pushed to anyone; however users that see the document still see the log message, - fixed suggested recipient behavior: canceling the partner creation popup now correctly avoids creating a partner, - moved 'Advanced wizard' button on top-right, - unfollowing or removing someone from followers now displays a warning, CRM, Recruitment, Issues: - better management of customers/applicants: Chatter suggests to notify and add as follower the customer, or to create a partner based on the email_from, CRM, Recruitment, Tasks, Issues: - changing the user_id (salesman, responsible) still adds the related partner as follower; but now an unread notification is pushed, with the first email or first message if no email, - updated and added if missing message_summary in kanban views, now displayed only when having unread messages, and the related number, to be more visible, CRM: - crm_partner_assign: fixed forward-to-partner wizard, - crm_partner_assign: geo localization now also sets salesteam along with salesman, - crm: fixed opportunity email_template, - crm: removed 'Send mail' button, as the functionality should be covered by Chatter (but the code of the action is left untouched to avoid errors), Mail: - merged message_post and message_post_user_api because there was an opportunity to avoid doing similar things in two different methods, - fixed email_from of incoming email not always stored, - followers: authors of discussion messages are now added as followers, this is not only limited to incoming emails, - followers: recipients of emails coming through the mail gateway are not automatically added as followers of the target documents, - followers: slightly updated _notify, to be able to notify a partner of a specific message; the notification process is therefore accessible outside of the mail_message.create() process bzr revid: tde@openerp.com-20130301101122-l18mr6hb0j5k4atv
Diffstat (limited to 'addons/mail/static/src/js')
-rw-r--r--addons/mail/static/src/js/mail.js292
-rw-r--r--addons/mail/static/src/js/mail_followers.js28
2 files changed, 231 insertions, 89 deletions
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js
index 0872d049162..4e58ca48bb1 100644
--- a/addons/mail/static/src/js/mail.js
+++ b/addons/mail/static/src/js/mail.js
@@ -21,6 +21,19 @@ openerp.mail = function (session) {
mail.ChatterUtils = {
+ /** parse text to find email: Tagada <address@mail.fr> -> [Tagada, address@mail.fr] or False */
+ parse_email: function (text) {
+ var result = text.match(/(.*)<(.*@.*)>/);
+ if (result) {
+ return [_.str.trim(result[1]), _.str.trim(result[2])];
+ }
+ result = text.match(/(.*@.*)/);
+ if (result) {
+ return [_.str.trim(result[1]), _.str.trim(result[1])];
+ }
+ return [text, false];
+ },
+
/* Get an image in /web/binary/image?... */
get_image: function (session, model, field, id, resize) {
var r = resize ? encodeURIComponent(resize) : '';
@@ -255,11 +268,15 @@ openerp.mail = function (session) {
this.avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid);
}
if (this.author_id && this.author_id[1]) {
- var email = this.author_id[1].match(/(.*)<(.*@.*)>/);
- if (!email) {
- this.author_id.push(_.str.escapeHTML(this.author_id[1]), '', this.author_id[1]);
- } else {
- this.author_id.push(_.str.escapeHTML(email[0]), _.str.trim(email[1]), email[2]);
+ var parsed_email = mail.ChatterUtils.parse_email(this.author_id[1]);
+ this.author_id.push(parsed_email[0], parsed_email[1]);
+ }
+ if (this.partner_ids && this.partner_ids.length > 3) {
+ this.extra_partners_nbr = this.partner_ids.length - 3;
+ this.extra_partners_str = ''
+ var extra_partners = this.partner_ids.slice(3);
+ for (var key in extra_partners) {
+ this.extra_partners_str += extra_partners[key][1];
}
}
},
@@ -371,14 +388,24 @@ openerp.mail = function (session) {
* @param {Object} [context] context passed to the
* mail.compose.message DataSetSearch. Please refer to this model
* for more details about fields and default values.
+ * @param {Object} recipients = [
+ {
+ 'email_address': [str],
+ 'partner_id': False/[int],
+ 'name': [str],
+ 'full_name': name<email_address>,
+ },
+ { ... },
+ ]
*/
init: function (parent, datasets, options) {
this._super(parent, datasets, options);
this.show_compact_message = false;
this.show_delete_attachment = true;
- this.emails_from = [];
- this.partners_from = [];
+ this.is_log = false;
+ this.recipients = [];
+ this.recipient_ids = [];
},
start: function () {
@@ -479,15 +506,13 @@ openerp.mail = function (session) {
bind_events: function () {
var self = this;
-
- this.$('.oe_compact').on('click', _.bind( this.on_compose_expandable, this));
-
- // set the function called when attachments are added
- this.$('input.oe_form_binary_file').on('change', _.bind( this.on_attachment_change, this) );
-
- this.$('.oe_cancel').on('click', _.bind( this.on_cancel, this) );
- this.$('.oe_post').on('click', _.bind( this.on_message_post, this) );
- this.$('.oe_full').on('click', _.bind( this.on_compose_fullmail, this, this.id ? 'reply' : 'comment') );
+ this.$('.oe_compact_inbox').on('click', self.on_toggle_quick_composer);
+ this.$('.oe_compose_post').on('click', self.on_toggle_quick_composer);
+ this.$('.oe_compose_log').on('click', self.on_toggle_quick_composer);
+ this.$('input.oe_form_binary_file').on('change', _.bind( this.on_attachment_change, this));
+ this.$('.oe_cancel').on('click', _.bind( this.on_cancel, this));
+ this.$('.oe_post').on('click', self.on_message_post);
+ this.$('.oe_full').on('click', _.bind( this.on_compose_fullmail, this, this.id ? 'reply' : 'comment'));
/* stack for don't close the compose form if the user click on a button */
this.$('.oe_msg_left, .oe_msg_center').on('mousedown', _.bind( function () { this.stay_open = true; }, this));
this.$('.oe_msg_left, .oe_msg_content').on('mouseup', _.bind( function () { this.$('textarea').focus(); }, this));
@@ -497,13 +522,12 @@ openerp.mail = function (session) {
this.$('textarea').autosize();
// auto close
- this.$('textarea').on('blur', _.bind( this.on_compose_expandable, this));
+ this.$('textarea').on('blur', self.on_toggle_quick_composer);
// event: delete child attachments off the oe_msg_attachment_list box
this.$(".oe_msg_attachment_list").on('click', '.oe_delete', this.on_attachment_delete);
- this.$(".oe_emails_from").on('change', 'input', this.on_checked_email_from);
- this.$(".oe_partners_from").on('change', 'input', this.on_checked_partner_from);
+ this.$(".oe_recipients").on('change', 'input', this.on_checked_recipient);
},
on_compose_fullmail: function (default_composition_mode) {
@@ -511,16 +535,26 @@ openerp.mail = function (session) {
if(!this.do_check_attachment_upload()) {
return false;
}
-
- // create list of new partners
- this.check_recipient_partners().done(function (partner_ids) {
+ var recipient_done = $.Deferred();
+ if (this.is_log) {
+ recipient_done.resolve([]);
+ }
+ else {
+ recipient_done = this.check_recipient_partners();
+ }
+ $.when(recipient_done).done(function (partner_ids) {
var context = {
'default_composition_mode': default_composition_mode,
'default_parent_id': self.id,
'default_body': mail.ChatterUtils.get_text2html(self.$el ? (self.$el.find('textarea:not(.oe_compact)').val() || '') : ''),
'default_attachment_ids': self.attachment_ids,
'default_partner_ids': partner_ids,
+ 'mail_post_autofollow': true,
+ 'mail_post_autofollow_partner_ids': partner_ids,
};
+ if (self.is_log) {
+ _.extend(context, {'mail_compose_log': true});
+ }
if (default_composition_mode != 'reply' && self.context.default_model && self.context.default_res_id) {
context.default_model = self.context.default_model;
context.default_res_id = self.context.default_res_id;
@@ -573,68 +607,122 @@ openerp.mail = function (session) {
check_recipient_partners: function () {
var self = this;
- var partners_from = [];
- var emails = [];
- _.each(this.emails_from, function (email_from) {
- if (email_from[1] && !_.find(emails, function (email) {return email == email_from[0][4];})) {
- emails.push(email_from[0][1]);
- }
- });
- var deferred_check = $.Deferred();
- if (emails.length == 0) {
- return deferred_check.resolve(partners_from);
- }
- self.parent_thread.ds_thread._model.call('message_create_partners_from_emails', [emails]).then(function (partners) {
- partners_from = _.clone(partners.partner_ids);
- var deferreds = [];
- _.each(partners.new_partner_ids, function (id) {
+ var check_done = $.Deferred();
+ var recipients = _.filter(this.recipients, function (recipient) { return recipient.checked });
+ var recipients_to_find = _.filter(recipients, function (recipient) { return (! recipient.partner_id) });
+ var names_to_find = _.pluck(recipients_to_find, 'full_name');
+ var recipients_to_check = _.filter(recipients, function (recipient) { return (recipient.partner_id && ! recipient.email_address) });
+ var recipient_ids = _.pluck(_.filter(recipients, function (recipient) { return recipient.partner_id && recipient.email_address }), 'partner_id');
+ var names_to_remove = [];
+ var recipient_ids_to_remove = [];
+
+ // have unknown names -> call message_get_partner_info_from_emails to try to find partner_id
+ var find_done = $.Deferred();
+ if (names_to_find.length > 0) {
+ find_done = self.parent_thread.ds_thread._model.call('message_get_partner_info_from_emails', [names_to_find]);
+ }
+ else {
+ find_done.resolve([]);
+ }
+
+ // for unknown names + incomplete partners -> open popup - cancel = remove from recipients
+ $.when(find_done).pipe(function (result) {
+ var emails_deferred = [];
+ var recipient_popups = result.concat(recipients_to_check);
+
+ _.each(recipient_popups, function (partner_info) {
var deferred = $.Deferred()
- deferreds.push(deferred);
- var pop = new session.web.form.FormOpenPopup(this);
+ emails_deferred.push(deferred);
+
+ var partner_name = partner_info.full_name;
+ var partner_id = partner_info.partner_id;
+ var parsed_email = mail.ChatterUtils.parse_email(partner_name);
+
+ var pop = new session.web.form.FormOpenPopup(this);
pop.show_element(
'res.partner',
- id,
- {
- 'force_email': true,
+ partner_id,
+ { 'force_email': true,
'ref': "compound_context",
- },
- {
+ 'default_name': parsed_email[0],
+ 'default_email': parsed_email[1],
+ }, {
title: _t("Please complete partner's informations"),
}
);
pop.on('closed', self, function () {
deferred.resolve();
});
- partners_from.push(id);
+ pop.view_form.on('on_button_cancel', self, function () {
+ names_to_remove.push(partner_name);
+ if (partner_id) {
+ recipient_ids_to_remove.push(partner_id);
+ }
+ });
});
- $.when.apply( $, deferreds ).then(function () {
- deferred_check.resolve(partners_from);
+
+ $.when.apply($, emails_deferred).then(function () {
+ var new_names_to_find = _.difference(names_to_find, names_to_remove);
+ find_done = $.Deferred();
+ if (new_names_to_find.length > 0) {
+ find_done = self.parent_thread.ds_thread._model.call('message_get_partner_info_from_emails', [new_names_to_find, true]);
+ }
+ else {
+ find_done.resolve([]);
+ }
+ $.when(find_done).pipe(function (result) {
+ var recipient_popups = result.concat(recipients_to_check);
+ _.each(recipient_popups, function (partner_info) {
+ if (partner_info.partner_id && _.indexOf(partner_info.partner_id, recipient_ids_to_remove) == -1) {
+ recipient_ids.push(partner_info.partner_id);
+ }
+ });
+ }).pipe(function () {
+ check_done.resolve(recipient_ids);
+ });
});
});
- return deferred_check;
+
+ return check_done;
},
on_message_post: function (event) {
var self = this;
if (this.do_check_attachment_upload() && (this.attachment_ids.length || this.$('textarea').val().match(/\S+/))) {
- // create list of new partners
- this.check_recipient_partners().done(function (partner_ids) {
- self.do_send_message_post(partner_ids);
- });
+ if (this.is_log) {
+ this.do_send_message_post([], this.is_log);
+ }
+ else {
+ this.check_recipient_partners().done(function (partner_ids) {
+ self.do_send_message_post(partner_ids, self.is_log);
+ });
+ }
}
},
- /*do post a message and fetch the message*/
- do_send_message_post: function (partner_ids) {
+ /* do post a message and fetch the message */
+ do_send_message_post: function (partner_ids, log) {
var self = this;
- this.parent_thread.ds_thread._model.call('message_post_user_api', [this.context.default_res_id], {
+ var values = {
'body': this.$('textarea').val(),
'subject': false,
'parent_id': this.context.default_parent_id,
'attachment_ids': _.map(this.attachment_ids, function (file) {return file.id;}),
'partner_ids': partner_ids,
- 'context': this.parent_thread.context,
- }).done(function (message_id) {
+ 'context': _.extend(this.parent_thread.context, {
+ 'mail_post_autofollow': true,
+ 'mail_post_autofollow_partner_ids': partner_ids,
+ }),
+ 'type': 'comment',
+ 'content_subtype': 'plaintext',
+ };
+ if (log) {
+ values['subtype'] = false;
+ }
+ else {
+ values['subtype'] = 'mail.mt_comment';
+ }
+ this.parent_thread.ds_thread._model.call('message_post', [this.context.default_res_id], values).done(function (message_id) {
var thread = self.parent_thread;
var root = thread == self.options.root_thread;
if (self.options.display_indented_thread < self.thread_level && thread.parent_message) {
@@ -650,18 +738,55 @@ openerp.mail = function (session) {
});
},
- /* convert the compact mode into the compose message
- */
- on_compose_expandable: function (event) {
- this.get_emails_from();
- if ((!this.stay_open || (event && event.type == 'click')) && (!this.show_composer || !this.$('textarea:not(.oe_compact)').val().match(/\S+/) && !this.attachment_ids.length)) {
- this.show_composer = !this.show_composer || this.stay_open;
- this.reinit();
+ /* Quick composer: toggle minimal / expanded mode
+ * - toggle minimal (one-liner) / expanded (textarea, buttons) mode
+ * - when going into expanded mode:
+ * - call `message_get_suggested_recipients` to have a list of partners to add
+ * - compute email_from list (list of unknown email_from to propose to create partners)
+ */
+ on_toggle_quick_composer: function (event) {
+ var self = this;
+ var $input = $(event.target);
+ this.compute_emails_from();
+ var email_addresses = _.pluck(this.recipients, 'email_address');
+ var suggested_partners = $.Deferred();
+
+ // if clicked: call for suggested recipients
+ if (event.type == 'click') {
+ this.is_log = $input.hasClass('oe_compose_log');
+ suggested_partners = this.parent_thread.ds_thread.call('message_get_suggested_recipients', [[this.context.default_res_id]]).done(function (additional_recipients) {
+ var thread_recipients = additional_recipients[self.context.default_res_id];
+ _.each(thread_recipients, function (recipient) {
+ var parsed_email = mail.ChatterUtils.parse_email(recipient[1]);
+ if (_.indexOf(email_addresses, parsed_email[1]) == -1) {
+ self.recipients.push({
+ 'checked': true,
+ 'partner_id': recipient[0],
+ 'full_name': recipient[1],
+ 'name': parsed_email[0],
+ 'email_address': parsed_email[1],
+ 'reason': recipient[2],
+ })
+ }
+ });
+ });
}
- if (!this.stay_open && this.show_composer && (!event || event.type != 'blur')) {
- this.$('textarea:not(.oe_compact):first').focus();
+ else {
+ suggested_partners.resolve({});
}
- return true;
+
+ // when call for suggested partners finished: re-render the widget
+ $.when(suggested_partners).pipe(function (additional_recipients) {
+ if ((!self.stay_open || (event && event.type == 'click')) && (!self.show_composer || !self.$('textarea:not(.oe_compact)').val().match(/\S+/) && !self.attachment_ids.length)) {
+ self.show_composer = !self.show_composer || self.stay_open;
+ self.reinit();
+ }
+ if (!self.stay_open && self.show_composer && (!event || event.type != 'blur')) {
+ self.$('textarea:not(.oe_compact):first').focus();
+ }
+ });
+
+ return suggested_partners;
},
do_hide_compact: function () {
@@ -678,7 +803,10 @@ openerp.mail = function (session) {
}
},
- get_emails_from: function () {
+ /** Compute the list of unknown email_from the the given thread
+ * TDE FIXME: seems odd to delegate to the composer
+ * TDE TODO: please de-obfuscate and comment your code */
+ compute_emails_from: function () {
var self = this;
var messages = [];
@@ -691,22 +819,28 @@ openerp.mail = function (session) {
// get all wall messages if is not a mail.Wall
_.each(this.options.root_thread.messages, function (msg) {messages.push(msg); messages.concat(msg.get_childs());});
}
-
+
_.each(messages, function (thread) {
if (thread.author_id && !thread.author_id[0] &&
- !_.find(self.emails_from, function (from) {return from[0][4] == thread.author_id[4];})) {
- self.emails_from.push([thread.author_id, true]);
+ !_.find(self.recipients, function (recipient) {return recipient.email_address == thread.author_id[3];})) {
+ self.recipients.push({ 'full_name': thread.author_id[1],
+ 'name': thread.author_id[2],
+ 'email_address': thread.author_id[3],
+ 'partner_id': false,
+ 'checked': true,
+ 'reason': 'Incoming email author'
+ });
}
});
- return self.emails_from;
+ return self.recipients;
},
- on_checked_email_from: function (event) {
+ on_checked_recipient: function (event) {
var $input = $(event.target);
var email = $input.attr("data");
- _.each(this.emails_from, function (email_from) {
- if (email_from[0][4] == email) {
- email_from[1] = $input.is(":checked");
+ _.each(this.recipients, function (recipient) {
+ if (recipient.email_address == email) {
+ recipient.checked = $input.is(":checked");
}
});
},
@@ -1236,12 +1370,12 @@ openerp.mail = function (session) {
/**
*If compose_message doesn't exist, instantiate the compose message.
- * Call the on_compose_expandable method to allow the user to write his message.
+ * Call the on_toggle_quick_composer method to allow the user to write his message.
* (Is call when a user click on "Reply" button)
*/
on_compose_message: function (event) {
this.instantiate_compose_message();
- this.compose_message.on_compose_expandable(event);
+ this.compose_message.on_toggle_quick_composer(event);
return false;
},
@@ -1810,7 +1944,7 @@ openerp.mail = function (session) {
};
session.client.action_manager.do_action(action);
});
- this.$(".oe_write_onwall").click(function(){ self.root.thread.on_compose_message(); });
+ this.$(".oe_write_onwall").click(function (event) { self.root.thread.on_compose_message(event); });
}
});
diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js
index 41634fd2135..5dfc1946587 100644
--- a/addons/mail/static/src/js/mail_followers.js
+++ b/addons/mail/static/src/js/mail_followers.js
@@ -106,9 +106,12 @@ openerp_mail_followers = function(session, mail) {
on_remove_follower: function (event) {
var partner_id = $(event.target).data('id');
- var context = new session.web.CompoundContext(this.build_context(), {});
- return this.ds_model.call('message_unsubscribe', [[this.view.datarecord.id], [partner_id], context])
- .then(this.proxy('read_value'));
+ var name = $(event.target).parent().find("a").html();
+ if (confirm(_.str.sprintf(_t("Warning! \n %s won't be notified of any email or discussion on this document. Do you really want to remove him from the followers ?"), name))) {
+ var context = new session.web.CompoundContext(this.build_context(), {});
+ return this.ds_model.call('message_unsubscribe', [[this.view.datarecord.id], [partner_id], context])
+ .then(this.proxy('read_value'));
+ }
},
read_value: function () {
@@ -248,12 +251,15 @@ openerp_mail_followers = function(session, mail) {
},
do_unfollow: function () {
- _(this.$('.oe_msg_subtype_check')).each(function (record) {
- $(record).attr('checked',false);
- });
- var context = new session.web.CompoundContext(this.build_context(), {});
- return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context])
- .then(this.proxy('read_value'));
+ if (confirm(_t("Warning! \nYou won't be notified of any email or discussion on this document. Do you really want to unfollow this document ?"))) {
+ _(this.$('.oe_msg_subtype_check')).each(function (record) {
+ $(record).attr('checked',false);
+ });
+ var context = new session.web.CompoundContext(this.build_context(), {});
+ return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context])
+ .then(this.proxy('read_value'));
+ }
+ return false;
},
do_update_subscription: function (event) {
@@ -267,7 +273,9 @@ openerp_mail_followers = function(session, mail) {
});
if (!checklist.length) {
- this.do_unfollow();
+ if (!this.do_unfollow()) {
+ $(event.target).attr("checked", "checked");
+ }
} else {
var context = new session.web.CompoundContext(this.build_context(), {});
return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], checklist, context])