diff --git a/mail_base/__openerp__.py b/mail_base/__openerp__.py
index ce01512..8e963c7 100644
--- a/mail_base/__openerp__.py
+++ b/mail_base/__openerp__.py
@@ -4,7 +4,7 @@
"summary": """Makes Mail extendable""",
"category": "Discuss",
"images": [],
- "version": "1.0.2",
+ "version": "1.0.3",
"author": "IT-Projects LLC, Pavel Romanchenko",
"support": "apps@it-projects.info",
diff --git a/mail_base/doc/changelog.rst b/mail_base/doc/changelog.rst
index e50183c..8c7df58 100644
--- a/mail_base/doc/changelog.rst
+++ b/mail_base/doc/changelog.rst
@@ -1,3 +1,8 @@
+`1.0.3`
+-------
+
+- **PORT**: ported to Odoo 11.0
+
`1.0.2`
-------
diff --git a/mail_base/static/lib/base.js b/mail_base/static/lib/base.js
index 1e825de..a32d63e 100644
--- a/mail_base/static/lib/base.js
+++ b/mail_base/static/lib/base.js
@@ -4,31 +4,21 @@ odoo.define('mail_base.base', function (require) {
var bus = require('bus.bus').bus;
var utils = require('mail.utils');
var config = require('web.config');
+var Bus = require('web.Bus');
var core = require('web.core');
-var data = require('web.data');
var session = require('web.session');
var time = require('web.time');
var web_client = require('web.web_client');
-
-var composer = require('mail.composer');
-var config = require('web.config');
-var Chatter = require('mail.Chatter');
-var view_dialogs = require('web.view_dialogs');
+var Class = require('web.Class');
+var Mixins = require('web.mixins');
+var ServicesMixin = require('web.ServicesMixin');
var _t = core._t;
var _lt = core._lt;
-var LIMIT = 100;
+var LIMIT = 25;
var preview_msg_max_size = 350; // optimal for native english speakers
var ODOOBOT_ID = "ODOOBOT";
-
-/* TODO: update or remove
-var MessageModel = new Model('mail.message', session.context);
-var ChannelModel = new Model('mail.channel', session.context);
-var UserModel = new Model('res.users', session.context);
-var PartnerModel = new Model('res.partner', session.context);
-*/
var chat_manager = require('mail.chat_manager');
-
// Private model
//----------------------------------------------------------------------------------
var messages = [];
@@ -39,6 +29,7 @@ var chat_unread_counter = 0;
var unread_conversation_counter = 0;
var emojis = [];
var emoji_substitutions = {};
+var emoji_unicodes = {};
var needaction_counter = 0;
var starred_counter = 0;
var mention_partner_suggestions = [];
@@ -49,1078 +40,833 @@ var global_unread_counter = 0;
var pinned_dm_partners = []; // partner_ids we have a pinned DM with
var client_action_open = false;
+// Global unread counter and notifications
+//----------------------------------------------------------------------------------
bus.on("window_focus", null, function() {
global_unread_counter = 0;
web_client.set_title_part("_chat");
});
-var channel_seen = _.throttle(function (channel) {
- return ChannelModel.call('channel_seen', [[channel.id]], {}, {shadow: true});
-}, 3000);
-
-var ChatAction = core.action_registry.get('mail.chat.instant_messaging');
-ChatAction.include({
- init: function(parent, action, options) {
- this._super.apply(this, arguments);
- this.channels_show_send_button = ['channel_inbox'];
- this.channels_display_subject = [];
- },
- start: function() {
- var result = this._super.apply(this, arguments);
-
- var search_defaults = {};
- var context = this.action ? this.action.context : [];
- _.each(context, function (value, key) {
- var match = /^search_default_(.*)$/.exec(key);
- if (match) {
- search_defaults[match[1]] = value;
- }
- });
- this.searchview.defaults = search_defaults;
+chat_manager.notify_incoming_message = function (msg, options) {
+ if (bus.is_odoo_focused() && options.is_displayed) {
+ // no need to notify
+ return;
+ }
+ var title = _t('New message');
+ if (msg.author_id[1]) {
+ title = _.escape(msg.author_id[1]);
+ }
+ var content = utils.parse_and_transform(msg.body, utils.strip_html).substr(0, preview_msg_max_size);
- var self = this;
- return $.when(result).done(function() {
- $('.oe_leftbar').toggle(false);
- self.searchview.do_search();
- });
- },
- destroy: function() {
- var result = this._super.apply(this, arguments);
- $('.oe_leftbar .oe_secondary_menu').each(function(){
- if ($(this).css('display') == 'block'){
- if ($(this).children().length > 0) {
- $('.oe_leftbar').toggle(true);
+ if (!bus.is_odoo_focused()) {
+ global_unread_counter++;
+ var tab_title = _.str.sprintf(_t("%d Messages"), global_unread_counter);
+ web_client.set_title_part("_chat", tab_title);
+ }
+
+ utils.send_notification(web_client, title, content);
+}
+
+// Message and channel manipulation helpers
+//----------------------------------------------------------------------------------
+
+// options: channel_id, silent
+chat_manager.add_message = function (data, options) {
+ options = options || {};
+ var msg = _.findWhere(messages, { id: data.id });
+
+ if (!msg) {
+ msg = chat_manager.make_message(data);
+ // Keep the array ordered by id when inserting the new message
+ messages.splice(_.sortedIndex(messages, msg, 'id'), 0, msg);
+ _.each(msg.channel_ids, function (channel_id) {
+ var channel = chat_manager.get_channel(channel_id);
+ if (channel) {
+ // update the channel's last message (displayed in the channel
+ // preview, in mobile)
+ if (!channel.last_message || msg.id > channel.last_message.id) {
+ channel.last_message = msg;
+ }
+ chat_manager.add_to_cache(msg, []);
+ if (options.domain && options.domain !== []) {
+ chat_manager.add_to_cache(msg, options.domain);
+ }
+ if (channel.hidden) {
+ channel.hidden = false;
+ chat_manager.bus.trigger('new_channel', channel);
+ }
+ if (channel.type !== 'static' && !msg.is_author && !msg.is_system_notification) {
+ if (options.increment_unread) {
+ chat_manager.update_channel_unread_counter(channel, channel.unread_counter+1);
+ }
+ if (channel.is_chat && options.show_notification) {
+ if (!client_action_open && !config.device.isMobile) {
+ // automatically open chat window
+ chat_manager.bus.trigger('open_chat', channel, { passively: true });
+ }
+ var query = {is_displayed: false};
+ chat_manager.bus.trigger('anyone_listening', channel, query);
+ chat_manager.notify_incoming_message(msg, query);
+ }
}
- return false;
}
});
- return result;
- },
- set_channel: function(channel){
- var result = this._super.apply(this, arguments);
- var self = this;
- return $.when(result).done(function() {
- self.$buttons
- .find('.o_mail_chat_button_new_message')
- .toggle(self.channels_show_send_button.indexOf(channel.id) != -1);
- });
- },
- get_thread_rendering_options: function (messages) {
- var options = this._super.apply(this, arguments);
- options.display_subject = options.display_subject || this.channels_display_subject.indexOf(this.channel.id) != -1;
- return options;
- },
- update_message_on_current_channel: function(current_channel_id, message){
- var starred = current_channel_id === "channel_starred" && !message.is_starred;
- var inbox = current_channel_id === "channel_inbox" && !message.is_needaction;
- return starred || inbox;
- },
- on_update_message: function (message) {
- var self = this;
- var current_channel_id = this.channel.id;
- if (this.update_message_on_current_channel(current_channel_id, message)) {
- chat_manager.get_messages({channel_id: this.channel.id, domain: this.domain}).then(function (messages) {
- var options = self.get_thread_rendering_options(messages);
- self.thread.remove_message_and_render(message.id, messages, options).then(function () {
- self.update_button_status(messages.length === 0);
- });
- });
- } else if (_.contains(message.channel_ids, current_channel_id)) {
- this.fetch_and_render_thread();
+ if (!options.silent) {
+ chat_manager.bus.trigger('new_message', msg);
}
+ } else if (options.domain && options.domain !== []) {
+ chat_manager.add_to_cache(msg, options.domain);
}
-});
-
-var MailComposer = composer.BasicComposer.extend({
- template: 'mail.chatter.ChatComposer',
-
- init: function (parent, dataset, options) {
- this._super(parent, options);
- this.thread_dataset = dataset;
- this.suggested_partners = [];
- this.options = _.defaults(this.options, {
- display_mode: 'textarea',
- record_name: false,
- is_log: false,
- });
- if (this.options.is_log) {
- this.options.send_text = _t('Log');
- }
- this.events = _.extend(this.events, {
- 'click .o_composer_button_full_composer': 'on_open_full_composer',
- });
- },
+ return msg;
+}
- willStart: function () {
- if (this.options.is_log) {
- return this._super.apply(this, arguments);
- }
- return $.when(this._super.apply(this, arguments), this.message_get_suggested_recipients());
- },
-
- should_send: function () {
- return false;
- },
-
- preprocess_message: function () {
- var self = this;
- var def = $.Deferred();
- this._super().then(function (message) {
- message = _.extend(message, {
- subtype: 'mail.mt_comment',
- message_type: 'comment',
- content_subtype: 'html',
- context: self.context,
- });
+chat_manager.get_channel_array = function(msg){
+ return [ msg.channel_ids, 'channel_inbox', 'channel_starred' ];
+}
- // Subtype
- if (self.options.is_log) {
- message.subtype = 'mail.mt_note';
- }
+chat_manager.get_properties = function(msg){
+ return {
+ is_starred: chat_manager.property_descr("channel_starred", msg, chat_manager),
+ is_needaction: chat_manager.property_descr("channel_inbox", msg, chat_manager)
+ };
+}
- // Partner_ids
- if (!self.options.is_log) {
- var checked_suggested_partners = self.get_checked_suggested_partners();
- self.check_suggested_partners(checked_suggested_partners).done(function (partner_ids) {
- message.partner_ids = (message.partner_ids || []).concat(partner_ids);
- // update context
- message.context = _.defaults({}, message.context, {
- mail_post_autofollow: true,
- });
- def.resolve(message);
- });
+chat_manager.property_descr = function (channel, msg, self) {
+ return {
+ enumerable: true,
+ get: function () {
+ return _.contains(msg.channel_ids, channel);
+ },
+ set: function (bool) {
+ if (bool) {
+ chat_manager.add_channel_to_message(msg, channel);
} else {
- def.resolve(message);
+ msg.channel_ids = _.without(msg.channel_ids, channel);
}
+ }
+ };
+}
- });
+chat_manager.set_channel_flags = function(data, msg){
+ if (_.contains(data.needaction_partner_ids, session.partner_id)) {
+ msg.is_needaction = true;
+ }
+ if (_.contains(data.starred_partner_ids, session.partner_id)) {
+ msg.is_starred = true;
+ }
+ return msg;
+}
- return def;
- },
+chat_manager.make_message = function (data) {
+ var msg = {
+ id: data.id,
+ author_id: data.author_id,
+ body: data.body || "",
+ date: moment(time.str_to_datetime(data.date)),
+ message_type: data.message_type,
+ subtype_description: data.subtype_description,
+ is_author: data.author_id && data.author_id[0] === session.partner_id,
+ is_note: data.is_note,
+ is_system_notification: (data.message_type === 'notification' && data.model === 'mail.channel')
+ || data.info === 'transient_message',
+ attachment_ids: data.attachment_ids || [],
+ subject: data.subject,
+ email_from: data.email_from,
+ customer_email_status: data.customer_email_status,
+ customer_email_data: data.customer_email_data,
+ record_name: data.record_name,
+ tracking_value_ids: data.tracking_value_ids,
+ channel_ids: data.channel_ids,
+ model: data.model,
+ res_id: data.res_id,
+ url: session.url("/mail/view?message_id=" + data.id),
+ module_icon:data.module_icon,
+ };
- /**
- * Send the message on SHIFT+ENTER, but go to new line on ENTER
- */
- prevent_send: function (event) {
- return !event.shiftKey;
- },
-
- message_get_suggested_recipients: function () {
- var self = this;
- var email_addresses = _.pluck(this.suggested_partners, 'email_address');
- return this.thread_dataset
- .call('message_get_suggested_recipients', [[this.context.default_res_id], this.context])
- .done(function (suggested_recipients) {
- var thread_recipients = suggested_recipients[self.context.default_res_id];
- _.each(thread_recipients, function (recipient) {
- var parsed_email = utils.parse_email(recipient[1]);
- if (_.indexOf(email_addresses, parsed_email[1]) === -1) {
- self.suggested_partners.push({
- checked: true,
- partner_id: recipient[0],
- full_name: recipient[1],
- name: parsed_email[0],
- email_address: parsed_email[1],
- reason: recipient[2],
- });
- }
- });
- });
- },
+ _.each(_.keys(emoji_substitutions), function (key) {
+ var escaped_key = String(key).replace(/([.*+?=^!:${}()|[\]\/\\])/g, '\\$1');
+ var regexp = new RegExp("(?:^|\\s|<[a-z]*>)(" + escaped_key + ")(?=\\s|$|[a-z]*>)", "g");
+ msg.body = msg.body.replace(regexp, ' '+emoji_substitutions[key]+' ');
+ });
- /**
- * Get the list of selected suggested partners
- * @returns Array() : list of 'recipient' selected partners (may not be created in db)
- **/
- get_checked_suggested_partners: function () {
- var self = this;
- var checked_partners = [];
- this.$('.o_composer_suggested_partners input:checked').each(function() {
- var full_name = $(this).data('fullname');
- checked_partners = checked_partners.concat(_.filter(self.suggested_partners, function(item) {
- return full_name === item.full_name;
- }));
- });
- return checked_partners;
- },
+ Object.defineProperties(msg, chat_manager.get_properties(msg));
- /**
- * Check the additional partners (not necessary registered partners), and open a popup form view
- * for the ones who informations is missing.
- * @param Array : list of 'recipient' partners to complete informations or validate
- * @returns Deferred resolved with the list of checked suggested partners (real partner)
- **/
- check_suggested_partners: function (checked_suggested_partners) {
- var self = this;
- var check_done = $.Deferred();
-
- var recipients = _.filter(checked_suggested_partners, 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.thread_dataset.call('message_partner_info_from_emails', [[this.context.default_res_id], names_to_find]);
- } else {
- find_done.resolve([]);
+ msg = chat_manager.set_channel_flags(data, msg);
+ if (msg.model === 'mail.channel') {
+ var real_channels = _.without(chat_manager.get_channel_array(msg));
+ var origin = real_channels.length === 1 ? real_channels[0] : undefined;
+ var channel = origin && chat_manager.get_channel(origin);
+ if (channel) {
+ msg.origin_id = origin;
+ msg.origin_name = channel.name;
}
+ }
- // 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();
- emails_deferred.push(deferred);
-
- var partner_name = partner_info.full_name;
- var partner_id = partner_info.partner_id;
- var parsed_email = utils.parse_email(partner_name);
-
- var dialog = new form_common.FormViewDialog(self, {
- res_model: 'res.partner',
- res_id: partner_id,
- context: {
- force_email: true,
- ref: "compound_context",
- default_name: parsed_email[0],
- default_email: parsed_email[1],
- },
- title: _t("Please complete partner's informations"),
- disable_multiple_selection: true,
- }).open();
- dialog.on('closed', self, function () {
- deferred.resolve();
- });
- dialog.opened().then(function () {
- dialog.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($, 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.thread_dataset.call('message_partner_info_from_emails', [[self.context.default_res_id], 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 check_done;
- },
+ // Compute displayed author name or email
+ if ((!msg.author_id || !msg.author_id[0]) && msg.email_from) {
+ msg.mailto = msg.email_from;
+ } else {
+ msg.displayed_author = (msg.author_id === ODOOBOT_ID) && "OdooBot" ||
+ msg.author_id && msg.author_id[1] ||
+ msg.email_from || _t('Anonymous');
+ }
- on_open_full_composer: function() {
- if (!this.do_check_attachment_upload()){
- return false;
- }
+ // Don't redirect on author clicked of self-posted or OdooBot messages
+ msg.author_redirect = !msg.is_author && msg.author_id !== ODOOBOT_ID;
+
+ // Compute the avatar_url
+ if (msg.author_id === ODOOBOT_ID) {
+ msg.avatar_src = "/mail/static/src/img/odoo_o.png";
+ } else if (msg.author_id && msg.author_id[0]) {
+ msg.avatar_src = "/web/image/res.partner/" + msg.author_id[0] + "/image_small";
+ } else if (msg.message_type === 'email') {
+ msg.avatar_src = "/mail/static/src/img/email_icon.png";
+ } else {
+ msg.avatar_src = "/mail/static/src/img/smiley/avatar.jpg";
+ }
- var self = this;
- var recipient_done = $.Deferred();
- if (this.options.is_log) {
- recipient_done.resolve([]);
- } else {
- var checked_suggested_partners = this.get_checked_suggested_partners();
- recipient_done = this.check_suggested_partners(checked_suggested_partners);
- }
- recipient_done.then(function (partner_ids) {
- var context = {
- default_parent_id: self.id,
- default_body: utils.get_text2html(self.$input.val()),
- default_attachment_ids: _.pluck(self.get('attachment_ids'), 'id'),
- default_partner_ids: partner_ids,
- default_is_log: self.options.is_log,
- mail_post_autofollow: true,
- };
+ // add anchor tags to urls
+ msg.body = utils.parse_and_transform(msg.body, utils.add_link);
- if (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;
- }
+ // Compute url of attachments
+ _.each(msg.attachment_ids, function(a) {
+ a.url = '/web/content/' + a.id + '?download=true';
+ });
- self.do_action({
- type: 'ir.actions.act_window',
- res_model: 'mail.compose.message',
- view_mode: 'form',
- view_type: 'form',
- views: [[false, 'form']],
- target: 'new',
- context: context,
- }, {
- on_close: function() {
- self.trigger('need_refresh');
- var parent = self.getParent();
- chat_manager.get_messages({model: parent.model, res_id: parent.res_id});
- },
- }).then(self.trigger.bind(self, 'close_composer'));
+ // format date to the local only once by message
+ // can not be done in preprocess, since it alter the original value
+ if (msg.tracking_value_ids && msg.tracking_value_ids.length) {
+ _.each(msg.tracking_value_ids, function(f) {
+ if (f.field_type === 'datetime') {
+ var format = 'LLL';
+ if (f.old_value) {
+ f.old_value = moment.utc(f.old_value).local().format(format);
+ }
+ if (f.new_value) {
+ f.new_value = moment.utc(f.new_value).local().format(format);
+ }
+ } else if (f.field_type === 'date') {
+ var format = 'LL';
+ if (f.old_value) {
+ f.old_value = moment(f.old_value).local().format(format);
+ }
+ if (f.new_value) {
+ f.new_value = moment(f.new_value).local().format(format);
+ }
+ }
});
}
-});
-Chatter.include({
- open_composer: function (options) {
- var self = this;
- var old_composer = this.composer;
- // create the new composer
- this.composer = new MailComposer(this, this.thread_dataset, {
- commands_enabled: false,
- context: this.context,
- input_min_height: 50,
- input_max_height: Number.MAX_VALUE, // no max_height limit for the chatter
- input_baseline: 14,
- is_log: options && options.is_log,
- record_name: this.record_name,
- default_body: old_composer && old_composer.$input && old_composer.$input.val(),
- default_mention_selections: old_composer && old_composer.mention_get_listener_selections(),
- });
- this.composer.on('input_focused', this, function () {
- this.composer.mention_set_prefetched_partners(this.mention_suggestions || []);
- });
- this.composer.insertBefore(this.$('.o_mail_thread')).then(function () {
- // destroy existing composer
- if (old_composer) {
- old_composer.destroy();
- }
- if (!config.device.touch) {
- self.composer.focus();
- }
- self.composer.on('post_message', self, self.on_post_message);
- self.composer.on('need_refresh', self, self.refresh_followers);
- self.composer.on('close_composer', null, self.close_composer.bind(self, true));
- });
- this.mute_new_message_button(true);
- },
-});
+ return msg;
+}
-var MailTools = core.Class.extend({
+chat_manager.add_channel_to_message = function (message, channel_id) {
+ message.channel_ids.push(channel_id);
+ message.channel_ids = _.uniq(message.channel_ids);
+}
- notify_incoming_message: function (msg, options) {
- if (bus.is_odoo_focused() && options.is_displayed) {
- // no need to notify
- return;
+chat_manager.add_channel = function (data, options) {
+ options = typeof options === "object" ? options : {};
+ var channel = chat_manager.get_channel(data.id);
+ if (channel) {
+ if (channel.is_folded !== (data.state === "folded")) {
+ channel.is_folded = (data.state === "folded");
+ chat_manager.bus.trigger("channel_toggle_fold", channel);
}
- var title = _t('New message');
- if (msg.author_id[1]) {
- title = _.escape(msg.author_id[1]);
+ } else {
+ channel = chat_manager.make_channel(data, options);
+ channels.push(channel);
+ if (data.last_message) {
+ channel.last_message = chat_manager.add_message(data.last_message);
}
- var content = utils.parse_and_transform(msg.body, utils.strip_html).substr(0, preview_msg_max_size);
-
- if (!bus.is_odoo_focused()) {
- global_unread_counter++;
- var tab_title = _.str.sprintf(_t("%d Messages"), global_unread_counter);
- web_client.set_title_part("_chat", tab_title);
+ // In case of a static channel (Inbox, Starred), the name is translated thanks to _lt
+ // (lazy translate). In this case, channel.name is an object, not a string.
+ channels = _.sortBy(channels, function (channel) { return _.isString(channel.name) ? channel.name.toLowerCase() : '' });
+ if (!options.silent) {
+ chat_manager.bus.trigger("new_channel", channel);
}
-
- utils.send_notification(title, content);
- },
- // Message and channel manipulation helpers
- //----------------------------------------------------------------------------------
-
- // options: channel_id, silent
- add_message: function (data, options) {
- options = options || {};
- var msg = _.findWhere(messages, { id: data.id });
-
- if (!msg) {
- msg = chat_manager.mail_tools.make_message(data);
- // Keep the array ordered by id when inserting the new message
- messages.splice(_.sortedIndex(messages, msg, 'id'), 0, msg);
- _.each(msg.channel_ids, function (channel_id) {
- var channel = chat_manager.get_channel(channel_id);
- if (channel) {
- chat_manager.mail_tools.add_to_cache(msg, []);
- if (options.domain && options.domain !== []) {
- chat_manager.mail_tools.add_to_cache(msg, options.domain);
- }
- if (channel.hidden) {
- channel.hidden = false;
- chat_manager.bus.trigger('new_channel', channel);
- }
- if (channel.type !== 'static' && !msg.is_author && !msg.is_system_notification) {
- if (options.increment_unread) {
- chat_manager.mail_tools.update_channel_unread_counter(channel, channel.unread_counter+1);
- }
- if (channel.is_chat && options.show_notification) {
- if (!client_action_open && config.device.size_class !== config.device.SIZES.XS) {
- // automatically open chat window
- chat_manager.bus.trigger('open_chat', channel, { passively: true });
- }
- var query = {is_displayed: false};
- chat_manager.bus.trigger('anyone_listening', channel, query);
- chat_manager.mail_tools.notify_incoming_message(msg, query);
- }
- }
- }
- });
- if (!options.silent) {
- chat_manager.bus.trigger('new_message', msg);
- }
- } else if (options.domain && options.domain !== []) {
- chat_manager.mail_tools.add_to_cache(msg, options.domain);
+ if (channel.is_detached) {
+ chat_manager.bus.trigger("open_chat", channel);
}
- return msg;
- },
-
- property_descr: function (channel, msg, self) {
- return {
- enumerable: true,
- get: function () {
- return _.contains(msg.channel_ids, channel);
- },
- set: function (bool) {
- if (bool) {
- self.add_channel_to_message(msg, channel);
- } else {
- msg.channel_ids = _.without(msg.channel_ids, channel);
- }
- }
- };
- },
+ }
+ return channel;
+}
- get_properties: function(msg){
- return {
- is_starred: chat_manager.mail_tools.property_descr("channel_starred", msg, chat_manager.mail_tools),
- is_needaction: chat_manager.mail_tools.property_descr("channel_inbox", msg, chat_manager.mail_tools)
- };
- },
+chat_manager.make_channel = function (data, options) {
+ var channel = {
+ id: data.id,
+ name: data.name,
+ server_type: data.channel_type,
+ type: data.type || data.channel_type,
+ all_history_loaded: false,
+ uuid: data.uuid,
+ is_detached: data.is_minimized,
+ is_folded: data.state === "folded",
+ autoswitch: 'autoswitch' in options ? options.autoswitch : true,
+ hidden: options.hidden,
+ display_needactions: options.display_needactions,
+ mass_mailing: data.mass_mailing,
+ group_based_subscription: data.group_based_subscription,
+ needaction_counter: data.message_needaction_counter || 0,
+ unread_counter: 0,
+ last_seen_message_id: data.seen_message_id,
+ cache: {'[]': {
+ all_history_loaded: false,
+ loaded: false,
+ messages: [],
+ }},
+ };
+ if (channel.type === "channel") {
+ channel.type = data.public !== "private" ? "public" : "private";
+ }
+ if (_.size(data.direct_partner) > 0) {
+ channel.type = "dm";
+ channel.name = data.direct_partner[0].name;
+ channel.direct_partner_id = data.direct_partner[0].id;
+ channel.status = data.direct_partner[0].im_status;
+ pinned_dm_partners.push(channel.direct_partner_id);
+ bus.update_option('bus_presence_partner_ids', pinned_dm_partners);
+ } else if ('anonymous_name' in data) {
+ channel.name = data.anonymous_name;
+ }
+ if (data.last_message_date) {
+ channel.last_message_date = moment(time.str_to_datetime(data.last_message_date));
+ }
+ channel.is_chat = !channel.type.match(/^(public|private|static)$/);
+ if (data.message_unread_counter) {
+ chat_manager.update_channel_unread_counter(channel, data.message_unread_counter);
+ }
+ return channel;
+}
- set_channel_flags: function(data, msg){
- if (_.contains(data.needaction_partner_ids, session.partner_id)) {
- msg.is_needaction = true;
- }
- if (_.contains(data.starred_partner_ids, session.partner_id)) {
- msg.is_starred = true;
+chat_manager.remove_channel = function (channel) {
+ if (!channel) { return; }
+ if (channel.type === 'dm') {
+ var index = pinned_dm_partners.indexOf(channel.direct_partner_id);
+ if (index > -1) {
+ pinned_dm_partners.splice(index, 1);
+ bus.update_option('bus_presence_partner_ids', pinned_dm_partners);
}
- return msg;
- },
-
- get_channel_array: function(msg){
- return [ msg.channel_ids, 'channel_inbox', 'channel_starred' ];
- },
-
- make_message: function (data) {
- var msg = {
- id: data.id,
- author_id: data.author_id,
- body: data.body || "",
- date: moment(time.str_to_datetime(data.date)),
- message_type: data.message_type,
- subtype_description: data.subtype_description,
- is_author: data.author_id && data.author_id[0] === session.partner_id,
- is_note: data.is_note,
- is_system_notification: data.message_type === 'notification' && data.model === 'mail.channel' || data.info === 'transient_message',
- attachment_ids: data.attachment_ids || [],
- subject: data.subject,
- email_from: data.email_from,
- customer_email_status: data.customer_email_status,
- customer_email_data: data.customer_email_data,
- record_name: data.record_name,
- tracking_value_ids: data.tracking_value_ids,
- channel_ids: data.channel_ids,
- model: data.model,
- res_id: data.res_id,
- url: session.url("/mail/view?message_id=" + data.id)
- };
-
- _.each(_.keys(emoji_substitutions), function (key) {
- var escaped_key = String(key).replace(/([.*+?=^!:${}()|[\]\/\\])/g, '\\$1');
- var regexp = new RegExp("(?:^|\\s|<[a-z]*>)(" + escaped_key + ")(?=\\s|$|[a-z]*>)", "g");
- msg.body = msg.body.replace(regexp, ' '+emoji_substitutions[key]+' ');
- });
+ }
+ channels = _.without(channels, channel);
+ delete channel_defs[channel.id];
+}
- Object.defineProperties(msg, chat_manager.mail_tools.get_properties(msg));
+chat_manager.get_channel_cache = function (channel, domain) {
+ var stringified_domain = JSON.stringify(domain || []);
+ if (!channel.cache[stringified_domain]) {
+ channel.cache[stringified_domain] = {
+ all_history_loaded: false,
+ loaded: false,
+ messages: [],
+ };
+ }
+ return channel.cache[stringified_domain];
+}
- msg = chat_manager.mail_tools.set_channel_flags(data, msg);
- if (msg.model === 'mail.channel') {
- var real_channels = _.without(chat_manager.mail_tools.get_channel_array(msg));
- var origin = real_channels.length === 1 ? real_channels[0] : undefined;
- var channel = origin && chat_manager.get_channel(origin);
- if (channel) {
- msg.origin_id = origin;
- msg.origin_name = channel.name;
- }
+chat_manager.invalidate_caches = function (channel_ids) {
+ _.each(channel_ids, function (channel_id) {
+ var channel = chat_manager.get_channel(channel_id);
+ if (channel) {
+ channel.cache = { '[]': channel.cache['[]']};
}
+ });
+}
- // Compute displayed author name or email
- if ((!msg.author_id || !msg.author_id[0]) && msg.email_from) {
- msg.mailto = msg.email_from;
- } else {
- msg.displayed_author = (msg.author_id === ODOOBOT_ID) && "OdooBot" ||
- msg.author_id && msg.author_id[1] ||
- msg.email_from || _t('Anonymous');
+chat_manager.add_to_cache = function (message, domain) {
+ _.each(message.channel_ids, function (channel_id) {
+ var channel = chat_manager.get_channel(channel_id);
+ if (channel) {
+ var channel_cache = chat_manager.get_channel_cache(channel, domain);
+ var index = _.sortedIndex(channel_cache.messages, message, 'id');
+ if (channel_cache.messages[index] !== message) {
+ channel_cache.messages.splice(index, 0, message);
+ }
}
+ });
+}
- // Don't redirect on author clicked of self-posted or OdooBot messages
- msg.author_redirect = !msg.is_author && msg.author_id !== ODOOBOT_ID;
-
- // Compute the avatar_url
- if (msg.author_id === ODOOBOT_ID) {
- msg.avatar_src = "/mail/static/src/img/odoo_o.png";
- } else if (msg.author_id && msg.author_id[0]) {
- msg.avatar_src = "/web/image/res.partner/" + msg.author_id[0] + "/image_small";
- } else if (msg.message_type === 'email') {
- msg.avatar_src = "/mail/static/src/img/email_icon.png";
- } else {
- msg.avatar_src = "/mail/static/src/img/smiley/avatar.jpg";
- }
+chat_manager.remove_message_from_channel = function (channel_id, message) {
+ message.channel_ids = _.without(message.channel_ids, channel_id);
+ var channel = _.findWhere(channels, { id: channel_id });
+ _.each(channel.cache, function (cache) {
+ cache.messages = _.without(cache.messages, message);
+ });
+}
- // add anchor tags to urls
- msg.body = utils.parse_and_transform(msg.body, utils.add_link);
+chat_manager.update_channel_unread_counter = function (channel, counter) {
+ if (channel.unread_counter > 0 && counter === 0) {
+ unread_conversation_counter = Math.max(0, unread_conversation_counter-1);
+ } else if (channel.unread_counter === 0 && counter > 0) {
+ unread_conversation_counter++;
+ }
+ if (channel.is_chat) {
+ chat_unread_counter = Math.max(0, chat_unread_counter - channel.unread_counter + counter);
+ }
+ channel.unread_counter = counter;
+ chat_manager.bus.trigger("update_channel_unread_counter", channel);
+}
- // Compute url of attachments
- _.each(msg.attachment_ids, function(a) {
- a.url = '/web/content/' + a.id + '?download=true';
+// Notification handlers
+// ---------------------------------------------------------------------------------
+chat_manager.on_notification = function (notifications) {
+ // sometimes, the web client receives unsubscribe notification and an extra
+ // notification on that channel. This is then followed by an attempt to
+ // rejoin the channel that we just left. The next few lines remove the
+ // extra notification to prevent that situation to occur.
+ var unsubscribed_notif = _.find(notifications, function (notif) {
+ return notif[1].info === "unsubscribe";
+ });
+ if (unsubscribed_notif) {
+ notifications = _.reject(notifications, function (notif) {
+ return notif[0][1] === "mail.channel" && notif[0][2] === unsubscribed_notif[1].id;
});
+ }
+ _.each(notifications, function (notification) {
+ var model = notification[0][1];
+ if (model === 'ir.needaction') {
+ // new message in the inbox
+ chat_manager.on_needaction_notification(notification[1]);
+ } else if (model === 'mail.channel') {
+ // new message in a channel
+ chat_manager.on_channel_notification(notification[1]);
+ } else if (model === 'res.partner') {
+ // channel joined/left, message marked as read/(un)starred, chat open/closed
+ chat_manager.on_partner_notification(notification[1]);
+ } else if (model === 'bus.presence') {
+ // update presence of users
+ chat_manager.on_presence_notification(notification[1]);
+ }
+ });
+}
- return msg;
- },
+chat_manager.on_needaction_notification = function (message) {
+ message = chat_manager.add_message(message, {
+ channel_id: 'channel_inbox',
+ show_notification: true,
+ increment_unread: true,
+ });
+ chat_manager.invalidate_caches(message.channel_ids);
+ if (message.channel_ids.length !== 0) {
+ needaction_counter++;
+ }
+ _.each(message.channel_ids, function (channel_id) {
+ var channel = chat_manager.get_channel(channel_id);
+ if (channel) {
+ channel.needaction_counter++;
+ }
+ });
+ chat_manager.bus.trigger('update_needaction', needaction_counter);
+}
- add_channel_to_message: function (message, channel_id) {
- message.channel_ids.push(channel_id);
- message.channel_ids = _.uniq(message.channel_ids);
- },
+chat_manager.on_channel_notification = function (message) {
+ var def;
+ var channel_already_in_cache = true;
+ if (message.channel_ids.length === 1) {
+ channel_already_in_cache = !!chat_manager.get_channel(message.channel_ids[0]);
+ def = chat_manager.join_channel(message.channel_ids[0], {autoswitch: false});
+ } else {
+ def = $.when();
+ }
+ def.then(function () {
+ // don't increment unread if channel wasn't in cache yet as its unread counter has just been fetched
+ chat_manager.add_message(message, { show_notification: true, increment_unread: channel_already_in_cache });
+ chat_manager.invalidate_caches(message.channel_ids);
+ });
+}
- add_channel: function (data, options) {
- options = typeof options === "object" ? options : {};
+chat_manager.on_partner_notification = function (data) {
+ if (data.info === "unsubscribe") {
var channel = chat_manager.get_channel(data.id);
if (channel) {
- if (channel.is_folded !== (data.state === "folded")) {
- channel.is_folded = (data.state === "folded");
- chat_manager.bus.trigger("channel_toggle_fold", channel);
- }
- } else {
- channel = chat_manager.mail_tools.make_channel(data, options);
- channels.push(channel);
- channels = _.sortBy(channels, function (channel) { return _.isString(channel.name) ? channel.name.toLowerCase() : ''; });
- if (!options.silent) {
- chat_manager.bus.trigger("new_channel", channel);
- }
- if (channel.is_detached) {
- chat_manager.bus.trigger("open_chat", channel);
- }
- }
- return channel;
- },
-
- make_channel: function (data, options) {
- var channel = {
- id: data.id,
- name: data.name,
- server_type: data.channel_type,
- type: data.type || data.channel_type,
- all_history_loaded: false,
- uuid: data.uuid,
- is_detached: data.is_minimized,
- is_folded: data.state === "folded",
- autoswitch: 'autoswitch' in options ? options.autoswitch : true,
- hidden: options.hidden,
- display_needactions: options.display_needactions,
- mass_mailing: data.mass_mailing,
- needaction_counter: data.message_needaction_counter || 0,
- unread_counter: 0,
- last_seen_message_id: data.seen_message_id,
- cache: {'[]': {
- all_history_loaded: false,
- loaded: false,
- messages: []
- }}
- };
- if (channel.type === "channel" && data.public !== "private") {
- channel.type = "public";
- } else if (data.public === "private") {
- channel.type = "private";
- }
- if (_.size(data.direct_partner) > 0) {
- channel.type = "dm";
- channel.name = data.direct_partner[0].name;
- channel.direct_partner_id = data.direct_partner[0].id;
- channel.status = data.direct_partner[0].im_status;
- pinned_dm_partners.push(channel.direct_partner_id);
- bus.update_option('bus_presence_partner_ids', pinned_dm_partners);
- } else if ('anonymous_name' in data) {
- channel.name = data.anonymous_name;
- }
- if (data.last_message_date) {
- channel.last_message_date = moment(time.str_to_datetime(data.last_message_date));
- }
- channel.is_chat = !channel.type.match(/^(public|private|static)$/);
- if (data.message_unread_counter) {
- chat_manager.mail_tools.update_channel_unread_counter(channel, data.message_unread_counter);
- }
- return channel;
- },
-
- remove_channel: function (channel) {
- if (!channel) { return; }
- if (channel.type === 'dm') {
- var index = pinned_dm_partners.indexOf(channel.direct_partner_id);
- if (index > -1) {
- pinned_dm_partners.splice(index, 1);
- bus.update_option('bus_presence_partner_ids', pinned_dm_partners);
+ var msg;
+ if (_.contains(['public', 'private'], channel.type)) {
+ msg = _.str.sprintf(_t('You unsubscribed from %s.'), channel.name);
+ } else {
+ msg = _.str.sprintf(_t('You unpinned your conversation with %s.'), channel.name);
}
+ chat_manager.remove_channel(channel);
+ chat_manager.bus.trigger("unsubscribe_from_channel", data.id);
+ web_client.do_notify(_("Unsubscribed"), msg);
}
- channels = _.without(channels, channel);
- delete channel_defs[channel.id];
- },
-
- get_channel_cache: function (channel, domain) {
- var stringified_domain = JSON.stringify(domain || []);
- if (!channel.cache[stringified_domain]) {
- channel.cache[stringified_domain] = {
- all_history_loaded: false,
- loaded: false,
- messages: []
- };
- }
- return channel.cache[stringified_domain];
- },
+ } else if (data.type === 'toggle_star') {
+ chat_manager.on_toggle_star_notification(data);
+ } else if (data.type === 'mark_as_read') {
+ chat_manager.on_mark_as_read_notification(data);
+ } else if (data.type === 'mark_as_unread') {
+ chat_manager.on_mark_as_unread_notification(data);
+ } else if (data.info === 'channel_seen') {
+ chat_manager.on_channel_seen_notification(data);
+ } else if (data.info === 'transient_message') {
+ chat_manager.on_transient_message_notification(data);
+ } else if (data.type === 'activity_updated') {
+ chat_manager.onActivityUpdateNodification(data);
+ } else {
+ chat_manager.on_chat_session_notification(data);
+ }
+}
- invalidate_caches: function (channel_ids) {
- _.each(channel_ids, function (channel_id) {
- var channel = chat_manager.get_channel(channel_id);
- if (channel) {
- channel.cache = { '[]': channel.cache['[]']};
+chat_manager.on_toggle_star_notification = function (data) {
+ _.each(data.message_ids, function (msg_id) {
+ var message = _.findWhere(messages, { id: msg_id });
+ if (message) {
+ chat_manager.invalidate_caches(message.channel_ids);
+ message.is_starred = data.starred;
+ if (!message.is_starred) {
+ chat_manager.remove_message_from_channel("channel_starred", message);
+ starred_counter--;
+ } else {
+ chat_manager.add_to_cache(message, []);
+ var channel_starred = chat_manager.get_channel('channel_starred');
+ channel_starred.cache = _.pick(channel_starred.cache, "[]");
+ starred_counter++;
}
- });
- },
-
- clear_cache_all_channels: function(){
- _.each(channels, function(channel){
- channel.cache = {};
- });
- },
+ chat_manager.bus.trigger('update_message', message);
+ }
+ });
+ chat_manager.bus.trigger('update_starred', starred_counter);
+}
- add_to_cache: function (message, domain) {
- _.each(message.channel_ids, function (channel_id) {
+chat_manager.on_mark_as_read_notification = function (data) {
+ _.each(data.message_ids, function (msg_id) {
+ var message = _.findWhere(messages, { id: msg_id });
+ if (message) {
+ chat_manager.invalidate_caches(message.channel_ids);
+ chat_manager.remove_message_from_channel("channel_inbox", message);
+ chat_manager.bus.trigger('update_message', message, data.type);
+ }
+ });
+ if (data.channel_ids) {
+ _.each(data.channel_ids, function (channel_id) {
var channel = chat_manager.get_channel(channel_id);
if (channel) {
- var channel_cache = chat_manager.mail_tools.get_channel_cache(channel, domain);
- var index = _.sortedIndex(channel_cache.messages, message, 'id');
- if (channel_cache.messages[index] !== message) {
- channel_cache.messages.splice(index, 0, message);
- }
+ channel.needaction_counter = Math.max(channel.needaction_counter - data.message_ids.length, 0);
}
});
- },
-
- remove_from_cache: function(message, domain){
- var self = this;
- _.each(message.channel_ids, function (channel_id) {
- var channel = chat_manager.get_channel(channel_id);
- if (channel) {
- var channel_cache = self.get_channel_cache(channel, domain);
- var index = _.sortedIndex(channel_cache.messages, message, 'id');
- if (channel_cache.messages[index] === message) {
- channel_cache.messages.splice(index, 1);
- }
- }
+ } else { // if no channel_ids specified, this is a 'mark all read' in the inbox
+ _.each(channels, function (channel) {
+ channel.needaction_counter = 0;
});
- },
+ }
+ needaction_counter = Math.max(needaction_counter - data.message_ids.length, 0);
+ chat_manager.bus.trigger('update_needaction', needaction_counter);
+}
- remove_message_from_channel: function (channel_id, message) {
- message.channel_ids = _.without(message.channel_ids, channel_id);
- var channel = _.findWhere(channels, { id: channel_id });
- _.each(channel.cache, function (cache) {
- cache.messages = _.without(cache.messages, message);
- });
- },
+chat_manager.on_mark_as_unread_notification = function (data) {
+ _.each(data.message_ids, function (message_id) {
+ var message = _.findWhere(messages, { id: message_id });
+ if (message) {
+ chat_manager.invalidate_caches(message.channel_ids);
+ chat_manager.add_channel_to_message(message, 'channel_inbox');
+ chat_manager.add_to_cache(message, []);
+ }
+ });
+ var channel_inbox = chat_manager.get_channel('channel_inbox');
+ channel_inbox.cache = _.pick(channel_inbox.cache, "[]");
- get_domain: function(channel){
- return (channel.id === "channel_inbox") ? [['needaction', '=', true]] :
- (channel.id === "channel_starred") ? [['starred', '=', true]] : false;
- },
+ _.each(data.channel_ids, function (channel_id) {
+ var channel = chat_manager.get_channel(channel_id);
+ if (channel) {
+ channel.needaction_counter += data.message_ids.length;
+ }
+ });
+ needaction_counter += data.message_ids.length;
+ chat_manager.bus.trigger('update_needaction', needaction_counter);
+}
- // options: domain, load_more
- fetch_from_channel: function (channel, options) {
- options = options || {};
- var domain = chat_manager.mail_tools.get_domain(channel) || [['channel_ids', 'in', channel.id]];
- var cache = chat_manager.mail_tools.get_channel_cache(channel, options.domain);
+chat_manager.on_channel_seen_notification = function (data) {
+ var channel = chat_manager.get_channel(data.id);
+ if (channel) {
+ channel.last_seen_message_id = data.last_message_id;
+ if (channel.unread_counter) {
+ chat_manager.update_channel_unread_counter(channel, 0);
+ }
+ }
+}
- if (options.domain) {
- domain = new data.CompoundDomain(domain, options.domain || []);
+chat_manager.on_chat_session_notification = function (chat_session) {
+ var channel;
+ if ((chat_session.channel_type === "channel") && (chat_session.state === "open")) {
+ chat_manager.add_channel(chat_session, {autoswitch: false});
+ if (!chat_session.is_minimized && chat_session.info !== 'creation') {
+ web_client.do_notify(_t("Invitation"), _t("You have been invited to: ") + chat_session.name);
}
- if (options.load_more) {
- var min_message_id = cache.messages[0].id;
- domain = new data.CompoundDomain([['id', '<', min_message_id]], domain);
+ }
+ // partner specific change (open a detached window for example)
+ if ((chat_session.state === "open") || (chat_session.state === "folded")) {
+ channel = chat_session.is_minimized && chat_manager.get_channel(chat_session.id);
+ if (channel) {
+ channel.is_detached = true;
+ channel.is_folded = (chat_session.state === "folded");
+ chat_manager.bus.trigger("open_chat", channel);
}
- return MessageModel.call('message_fetch', [domain], {limit: LIMIT}).then(function (msgs) {
- if (!cache.all_history_loaded) {
- cache.all_history_loaded = msgs.length < LIMIT;
- }
- cache.loaded = true;
+ } else if (chat_session.state === "closed") {
+ channel = chat_manager.get_channel(chat_session.id);
+ if (channel) {
+ channel.is_detached = false;
+ chat_manager.bus.trigger("close_chat", channel, {keep_open_if_unread: true});
+ }
+ }
+}
- _.each(msgs, function (msg) {
- chat_manager.mail_tools.add_message(msg, {channel_id: channel.id, silent: true, domain: options.domain});
- });
- var channel_cache = chat_manager.mail_tools.get_channel_cache(channel, options.domain || []);
- return channel_cache.messages;
- });
- },
+chat_manager.on_presence_notification = function (data) {
+ var dm = chat_manager.get_dm_from_partner_id(data.id);
+ if (dm) {
+ dm.status = data.im_status;
+ chat_manager.bus.trigger('update_dm_presence', dm);
+ }
+}
- // options: force_fetch
- fetch_document_messages: function (ids, options) {
- var loaded_msgs = _.filter(messages, function (message) {
- return _.contains(ids, message.id);
- });
- var loaded_msg_ids = _.pluck(loaded_msgs, 'id');
+chat_manager.on_transient_message_notification = function(data) {
+ var last_message = _.last(messages);
+ data.id = (last_message ? last_message.id : 0) + 0.01;
+ data.author_id = data.author_id || ODOOBOT_ID;
+ chat_manager.add_message(data);
+}
- options = options || {};
- if (options.force_fetch || _.difference(ids.slice(0, LIMIT), loaded_msg_ids).length) {
- var ids_to_load = _.difference(ids, loaded_msg_ids).slice(0, LIMIT);
+chat_manager.onActivityUpdateNodification = function (data) {
+ chat_manager.bus.trigger('activity_updated', data);
+}
+// Public interface
- return MessageModel.call('message_format', [ids_to_load]).then(function (msgs) {
- var processed_msgs = [];
- _.each(msgs, function (msg) {
- processed_msgs.push(chat_manager.mail_tools.add_message(msg, {silent: true}));
- });
- return _.sortBy(loaded_msgs.concat(processed_msgs), function (msg) {
- return msg.date;
- });
- });
- } else {
- return $.when(loaded_msgs);
- }
- },
- update_channel_unread_counter: function (channel, counter) {
- if (channel.unread_counter > 0 && counter === 0) {
- unread_conversation_counter = Math.max(0, unread_conversation_counter-1);
- } else if (channel.unread_counter === 0 && counter > 0) {
- unread_conversation_counter++;
- }
- if (channel.is_chat) {
- chat_unread_counter = Math.max(0, chat_unread_counter - channel.unread_counter + counter);
- }
- channel.unread_counter = counter;
- chat_manager.bus.trigger("update_channel_unread_counter", channel);
- },
-
- // Notification handlers
- // ---------------------------------------------------------------------------------
- on_notification: function (notifications) {
- // sometimes, the web client receives unsubscribe notification and an extra
- // notification on that channel. This is then followed by an attempt to
- // rejoin the channel that we just left. The next few lines remove the
- // extra notification to prevent that situation to occur.
- var unsubscribed_notif = _.find(notifications, function (notif) {
- return notif[1].info === "unsubscribe";
- });
- if (unsubscribed_notif) {
- notifications = _.reject(notifications, function (notif) {
- return notif[0][1] === "mail.channel" && notif[0][2] === unsubscribed_notif[1].id;
- });
- }
- _.each(notifications, function (notification) {
- var model = notification[0][1];
- if (model === 'ir.needaction') {
- // new message in the inbox
- chat_manager.mail_tools.on_needaction_notification(notification[1]);
- } else if (model === 'mail.channel') {
- // new message in a channel
- chat_manager.mail_tools.on_channel_notification(notification[1]);
- } else if (model === 'res.partner') {
- // channel joined/left, message marked as read/(un)starred, chat open/closed
- chat_manager.mail_tools.on_partner_notification(notification[1]);
- } else if (model === 'bus.presence') {
- // update presence of users
- chat_manager.mail_tools.on_presence_notification(notification[1]);
- } else if (model === 'mail_base.mail_sent') {
- // Delete cache in order to fetch new message
-
- // TODO find a solution without deleting cache. Currently
- // problem is that on inheriting send_mail in
- // mail.compose.message it's not possible to get id of new
- // message
- chat_manager.mail_tools.clear_cache_all_channels();
- }
- });
- },
- on_needaction_notification: function (message) {
- message = chat_manager.mail_tools.add_message(message, {
- channel_id: 'channel_inbox',
- show_notification: true,
- increment_unread: true
- });
- chat_manager.mail_tools.invalidate_caches(message.channel_ids);
- needaction_counter++;
- _.each(message.channel_ids, function (channel_id) {
- var channel = chat_manager.get_channel(channel_id);
- if (channel) {
- channel.needaction_counter++;
- }
- });
- chat_manager.bus.trigger('update_needaction', needaction_counter);
- },
-
- on_channel_notification: function (message) {
- var def;
- var channel_already_in_cache = true;
- if (message.channel_ids.length === 1) {
- channel_already_in_cache = !!chat_manager.get_channel(message.channel_ids[0]);
- def = chat_manager.join_channel(message.channel_ids[0], {autoswitch: false});
- } else {
- def = $.when();
- }
- def.then(function () {
- // don't increment unread if channel wasn't in cache yet as its unread counter has just been fetched
- chat_manager.mail_tools.add_message(message, { show_notification: true, increment_unread: channel_already_in_cache });
- chat_manager.mail_tools.invalidate_caches(message.channel_ids);
- });
- },
+//----------------------------------------------------------------------------------
- on_partner_notification: function (data) {
- if (data.info === "unsubscribe") {
- var channel = chat_manager.get_channel(data.id);
- if (channel) {
- var msg;
- if (_.contains(['public', 'private'], channel.type)) {
- msg = _.str.sprintf(_t('You unsubscribed from %s.'), channel.name);
- } else {
- msg = _.str.sprintf(_t('You unpinned your conversation with %s.'), channel.name);
- }
- this.remove_channel(channel);
- chat_manager.bus.trigger("unsubscribe_from_channel", data.id);
- web_client.do_notify(_("Unsubscribed"), msg);
- }
- } else if (data.type === 'toggle_star') {
- chat_manager.mail_tools.on_toggle_star_notification(data);
- } else if (data.type === 'mark_as_read') {
- chat_manager.mail_tools.on_mark_as_read_notification(data);
- } else if (data.type === 'mark_as_unread') {
- chat_manager.mail_tools.on_mark_as_unread_notification(data);
- } else if (data.info === 'channel_seen') {
- chat_manager.mail_tools.on_channel_seen_notification(data);
- } else if (data.info === 'transient_message') {
- chat_manager.mail_tools.on_transient_message_notification(data);
- } else {
- chat_manager.mail_tools.on_chat_session_notification(data);
- }
- },
-
- on_toggle_star_notification: function (data) {
- _.each(data.message_ids, function (msg_id) {
- var message = _.findWhere(messages, { id: msg_id });
- if (message) {
- chat_manager.mail_tools.invalidate_caches(message.channel_ids);
- message.is_starred = data.starred;
- if (!message.is_starred) {
- chat_manager.mail_tools.remove_message_from_channel("channel_starred", message);
- starred_counter--;
- } else {
- chat_manager.mail_tools.add_to_cache(message, []);
- var channel_starred = chat_manager.get_channel('channel_starred');
- channel_starred.cache = _.pick(channel_starred.cache, "[]");
- starred_counter++;
- }
- chat_manager.bus.trigger('update_message', message);
- }
- });
- chat_manager.bus.trigger('update_starred', starred_counter);
- },
-
- on_mark_as_read_notification: function (data) {
- _.each(data.message_ids, function (msg_id) {
- var message = _.findWhere(messages, { id: msg_id });
- if (message) {
- chat_manager.mail_tools.invalidate_caches(message.channel_ids);
- chat_manager.mail_tools.remove_message_from_channel("channel_inbox", message);
- chat_manager.bus.trigger('update_message', message);
- }
- });
- if (data.channel_ids) {
- _.each(data.channel_ids, function (channel_id) {
- var channel = chat_manager.get_channel(channel_id);
- if (channel) {
- channel.needaction_counter = Math.max(channel.needaction_counter - data.message_ids.length, 0);
- }
- });
- } else { // if no channel_ids specified, this is a 'mark all read' in the inbox
- _.each(channels, function (channel) {
- channel.needaction_counter = 0;
+chat_manager.init = function (parent) {
+ var self = this;
+ Mixins.EventDispatcherMixin.init.call(this);
+ this.setParent(parent);
+
+ this.bus = new Bus();
+ this.bus.on('client_action_open', null, function (open) {
+ client_action_open = open;
+ });
+
+ bus.on('notification', null, chat_manager.on_notification);
+
+ this.channel_seen = _.throttle(function (channel) {
+ return self._rpc({
+ model: 'mail.channel',
+ method: 'channel_seen',
+ args: [[channel.id]],
+ }, {
+ shadow: true
});
- }
- needaction_counter = Math.max(needaction_counter - data.message_ids.length, 0);
- chat_manager.bus.trigger('update_needaction', needaction_counter);
- },
-
- on_mark_as_unread_notification: function (data) {
- _.each(data.message_ids, function (message_id) {
- var message = _.findWhere(messages, { id: message_id });
- if (message) {
- chat_manager.mail_tools.invalidate_caches(message.channel_ids);
- chat_manager.mail_tools.add_channel_to_message(message, 'channel_inbox');
- chat_manager.mail_tools.add_to_cache(message, []);
- }
- });
- var channel_inbox = chat_manager.get_channel('channel_inbox');
- channel_inbox.cache = _.pick(channel_inbox.cache, "[]");
+ }, 3000);
+}
- _.each(data.channel_ids, function (channel_id) {
- var channel = chat_manager.get_channel(channel_id);
- if (channel) {
- channel.needaction_counter += data.message_ids.length;
- }
- });
- needaction_counter += data.message_ids.length;
- chat_manager.bus.trigger('update_needaction', needaction_counter);
- },
+chat_manager.start = function () {
+ this.is_ready = session.is_bound.then(function(){
+ var context = _.extend({isMobile: config.device.isMobile}, session.user_context);
+ return session.rpc('/mail/client_action', {context: context});
+ }).then(chat_manager._onMailClientAction.bind(this));
- on_channel_seen_notification: function (data) {
- var channel = chat_manager.get_channel(data.id);
- if (channel) {
- channel.last_seen_message_id = data.last_message_id;
- if (channel.unread_counter) {
- chat_manager.mail_tools.update_channel_unread_counter(channel, 0);
- }
- }
- },
-
- on_chat_session_notification: function (chat_session) {
- var channel;
- if ((chat_session.channel_type === "channel") && (chat_session.state === "open")) {
- chat_manager.mail_tools.add_channel(chat_session, {autoswitch: false});
- if (!chat_session.is_minimized && chat_session.info !== 'creation') {
- web_client.do_notify(_t("Invitation"), _t("You have been invited to: ") + chat_session.name);
- }
- }
- // partner specific change (open a detached window for example)
- if ((chat_session.state === "open") || (chat_session.state === "folded")) {
- channel = chat_session.is_minimized && chat_manager.get_channel(chat_session.id);
- if (channel) {
- channel.is_detached = true;
- channel.is_folded = (chat_session.state === "folded");
- chat_manager.bus.trigger("open_chat", channel);
- }
- } else if (chat_session.state === "closed") {
- channel = chat_manager.get_channel(chat_session.id);
- if (channel) {
- channel.is_detached = false;
- chat_manager.bus.trigger("close_chat", channel, {keep_open_if_unread: true});
+ chat_manager.add_channel({
+ id: "channel_inbox",
+ name: _lt("Inbox"),
+ type: "static",
+ }, { display_needactions: true });
+
+ chat_manager.add_channel({
+ id: "channel_starred",
+ name: _lt("Starred"),
+ type: "static"
+ });
+},
+
+chat_manager._onMailClientAction = function (result) {
+ _.each(result.channel_slots, function (channels) {
+ _.each(channels, chat_manager.add_channel);
+ });
+ needaction_counter = result.needaction_inbox_counter;
+ starred_counter = result.starred_counter;
+ commands = _.map(result.commands, function (command) {
+ return _.extend({ id: command.name }, command);
+ });
+ mention_partner_suggestions = result.mention_partner_suggestions;
+ discuss_menu_id = result.menu_id;
+
+ // Shortcodes: canned responses and emojis
+ _.each(result.shortcodes, function (s) {
+ if (s.shortcode_type === 'text') {
+ canned_responses.push(_.pick(s, ['id', 'source', 'substitution']));
+ } else {
+ emojis.push(_.pick(s, ['id', 'source', 'unicode_source', 'substitution', 'description']));
+ emoji_substitutions[_.escape(s.source)] = s.substitution;
+ if (s.unicode_source) {
+ emoji_substitutions[_.escape(s.unicode_source)] = s.substitution;
+ emoji_unicodes[_.escape(s.source)] = s.unicode_source;
}
}
- },
+ });
+ bus.start_polling();
+}
- on_presence_notification: function (data) {
- var dm = chat_manager.get_dm_from_partner_id(data.id);
- if (dm) {
- dm.status = data.im_status;
- chat_manager.bus.trigger('update_dm_presence', dm);
- }
- },
- on_transient_message_notification: function (data) {
- var last_message = _.last(messages);
- data.id = (last_message ? last_message.id : 0) + 0.01;
- data.author_id = data.author_id || ODOOBOT_ID;
- chat_manager.mail_tools.add_message(data);
+ // options: domain, load_more
+chat_manager._fetchFromChannel = function (channel, options) {
+ options = options || {};
+ var domain =
+ (channel.id === "channel_inbox") ? [['needaction', '=', true]] :
+ (channel.id === "channel_starred") ? [['starred', '=', true]] :
+ [['channel_ids', 'in', channel.id]];
+ var cache = chat_manager.get_channel_cache(channel, options.domain);
+
+ if (options.domain) {
+ domain = domain.concat(options.domain || []);
+ }
+ if (options.load_more) {
+ var min_message_id = cache.messages[0].id;
+ domain = [['id', '<', min_message_id]].concat(domain);
}
-});
+ return this._rpc({
+ model: 'mail.message',
+ method: 'message_fetch',
+ args: [domain],
+ kwargs: {limit: LIMIT, context: session.user_context},
+ })
+ .then(function (msgs) {
+ if (!cache.all_history_loaded) {
+ cache.all_history_loaded = msgs.length < LIMIT;
+ }
+ cache.loaded = true;
-var cls = new MailTools();
+ _.each(msgs, function (msg) {
+ chat_manager.add_message(msg, {channel_id: channel.id, silent: true, domain: options.domain});
+ });
+ var channel_cache = chat_manager.get_channel_cache(channel, options.domain || []);
+ return channel_cache.messages;
+ });
+}
+ // options: force_fetch
+chat_manager._fetchDocumentMessages = function (ids, options) {
+ var loaded_msgs = _.filter(messages, function (message) {
+ return _.contains(ids, message.id);
+ });
+ var loaded_msg_ids = _.pluck(loaded_msgs, 'id');
+
+ options = options || {};
+ if (options.force_fetch || _.difference(ids.slice(0, LIMIT), loaded_msg_ids).length) {
+ var ids_to_load = _.difference(ids, loaded_msg_ids).slice(0, LIMIT);
+
+ return this._rpc({
+ model: 'mail.message',
+ method: 'message_format',
+ args: [ids_to_load],
+ context: session.user_context,
+ })
+ .then(function (msgs) {
+ var processed_msgs = [];
+ _.each(msgs, function (msg) {
+ processed_msgs.push(chat_manager.add_message(msg, {silent: true}));
+ });
+ return _.sortBy(loaded_msgs.concat(processed_msgs), function (msg) {
+ return msg.id;
+ });
+ });
+ } else {
+ return $.when(loaded_msgs);
+ }
+},
-// Public interface
-//----------------------------------------------------------------------------------
-chat_manager.mail_tools = cls;
-// we add this function this way in order to make them extendable via MailTools.include({...})
-chat_manager.make_message = function(){
- return chat_manager.mail_tools.make_message.apply(chat_manager.mail_tools, arguments);
-};
-chat_manager.make_channel = function(){
- return chat_manager.mail_tools.make_channel.apply(chat_manager.mail_tools, arguments);
-};
chat_manager.post_message = function (data, options) {
- options = options || {};
- var msg = {
- partner_ids: data.partner_ids,
- body: _.str.trim(data.content),
- attachment_ids: data.attachment_ids
- };
- if ('subject' in data) {
- msg.subject = data.subject;
- }
- if ('channel_id' in options) {
- // post a message in a channel or execute a command
- return ChannelModel.call(data.command ? 'execute_command' : 'message_post', [options.channel_id], _.extend(msg, {
- message_type: 'comment',
- content_subtype: 'html',
- subtype: 'mail.mt_comment',
- command: data.command,
- }));
- }
- if ('model' in options && 'res_id' in options) {
- // post a message in a chatter
- _.extend(msg, {
- content_subtype: data.content_subtype,
- context: data.context,
- message_type: data.message_type,
- subtype: data.subtype,
- subtype_id: data.subtype_id
+ var self = this;
+ options = options || {};
+
+ // This message will be received from the mail composer as html content subtype
+ // but the urls will not be linkified. If the mail composer takes the responsibility
+ // to linkify the urls we end up with double linkification a bit everywhere.
+ // Ideally we want to keep the content as text internally and only make html
+ // enrichment at display time but the current design makes this quite hard to do.
+ var body = utils.parse_and_transform(_.str.trim(data.content), utils.add_link);
+
+ var msg = {
+ partner_ids: data.partner_ids,
+ body: body,
+ attachment_ids: data.attachment_ids,
+ };
+
+ // Replace emojis by their unicode character
+ _.each(_.keys(emoji_unicodes), function (key) {
+ var escaped_key = String(key).replace(/([.*+?=^!:${}()|[\]\/\\])/g, '\\$1');
+ var regexp = new RegExp("(\\s|^)(" + escaped_key + ")(?=\\s|$)", "g");
+ msg.body = msg.body.replace(regexp, "$1" + emoji_unicodes[key]);
+ });
+
+ if ('subject' in data) {
+ msg.subject = data.subject;
+ }
+ if ('channel_id' in options) {
+ // post a message in a channel or execute a command
+ return this._rpc({
+ model: 'mail.channel',
+ method: data.command ? 'execute_command' : 'message_post',
+ args: [options.channel_id],
+ kwargs: _.extend(msg, {
+ message_type: 'comment',
+ content_subtype: 'html',
+ subtype: 'mail.mt_comment',
+ command: data.command,
+ }),
});
+ }
+ if ('model' in options && 'res_id' in options) {
+ // post a message in a chatter
+ _.extend(msg, {
+ content_subtype: data.content_subtype,
+ context: data.context,
+ message_type: data.message_type,
+ subtype: data.subtype,
+ subtype_id: data.subtype_id,
+ });
- if (options.model && options.res_id){
- var model = new Model(options.model);
- return model.call('message_post', [options.res_id], msg).then(function (msg_id) {
- return MessageModel.call('message_format', [msg_id]).then(function (msgs) {
+ return this._rpc({
+ model: options.model,
+ method: 'message_post',
+ args: [options.res_id],
+ kwargs: msg,
+ })
+ .then(function (msg_id) {
+ return self._rpc({
+ model: 'mail.message',
+ method: 'message_format',
+ args: [msg_id],
+ })
+ .then(function (msgs) {
msgs[0].model = options.model;
msgs[0].res_id = options.res_id;
- chat_manager.mail_tools.add_message(msgs[0]);
+ chat_manager.add_message(msgs[0]);
});
- });
- } else {
- options.model = 'mail.compose.message';
- var compose_model = new Model(options.model);
- return compose_model.call('create', [msg, {default_parent_id: options.parent_id}]).then(function(id){
- return compose_model.call('send_mail_action', [id, {}]);
- });
- }
- }
- };
+ });
+ }
+}
+
chat_manager.get_message = function (id) {
- return _.findWhere(messages, {id: id});
- };
+ return _.findWhere(messages, {id: id});
+}
+
chat_manager.get_messages = function (options) {
var channel;
if ('channel_id' in options && options.load_more) {
// get channel messages, force load_more
channel = this.get_channel(options.channel_id);
- return chat_manager.mail_tools.fetch_from_channel(channel, {domain: options.domain || {}, load_more: true});
+ return this._fetchFromChannel(channel, {domain: options.domain || {}, load_more: true});
}
if ('channel_id' in options) {
// channel message, check in cache first
channel = this.get_channel(options.channel_id);
- var channel_cache = chat_manager.mail_tools.get_channel_cache(channel, options.domain);
+ var channel_cache = chat_manager.get_channel_cache(channel, options.domain);
if (channel_cache.loaded) {
return $.when(channel_cache.messages);
} else {
- return chat_manager.mail_tools.fetch_from_channel(channel, {domain: options.domain});
+ return this._fetchFromChannel(channel, {domain: options.domain});
}
}
if ('ids' in options) {
// get messages from their ids (chatter is the main use case)
- return chat_manager.mail_tools.fetch_document_messages(options.ids, options).then(function(result) {
+ return this._fetchDocumentMessages(options.ids, options).then(function(result) {
chat_manager.mark_as_read(options.ids);
return result;
});
@@ -1129,178 +875,270 @@ chat_manager.get_messages = function (options) {
// get messages for a chatter, when it doesn't know the ids (use
// case is when using the full composer)
var domain = [['model', '=', options.model], ['res_id', '=', options.res_id]];
- MessageModel.call('message_fetch', [domain], {limit: 30}).then(function (msgs) {
- return _.map(msgs, chat_manager.mail_tools.add_message);
- });
+ this._rpc({
+ model: 'mail.message',
+ method: 'message_fetch',
+ args: [domain],
+ kwargs: {limit: 30},
+ })
+ .then(function (msgs) {
+ return _.map(msgs, chat_manager.add_message);
+ });
}
-};
+}
+
chat_manager.toggle_star_status = function (message_id) {
- return MessageModel.call('toggle_message_starred', [[message_id]]);
- };
+ return this._rpc({
+ model: 'mail.message',
+ method: 'toggle_message_starred',
+ args: [[message_id]],
+ });
+}
+
chat_manager.unstar_all = function () {
- return MessageModel.call('unstar_all', [[]], {});
- };
-chat_manager.mark_as_read = function (message_ids) {
- var ids = _.filter(message_ids, function (id) {
- var message = _.findWhere(messages, {id: id});
- // If too many messages, not all are fetched, and some might not be found
- return !message || message.is_needaction;
+ return this._rpc({
+ model: 'mail.message',
+ method: 'unstar_all',
+ args: [[]]
});
- if (ids.length) {
- return MessageModel.call('set_message_done', [ids]);
- } else {
- return $.when();
- }
- };
-chat_manager.mark_all_as_read = function (channel, domain) {
- if ((channel.id === "channel_inbox" && needaction_counter) || (channel && channel.needaction_counter)) {
- return MessageModel.call('mark_all_as_read', [], {channel_ids: channel.id !== "channel_inbox" ? [channel.id] : [], domain: domain});
- }
+}
+
+chat_manager.mark_as_read = function (message_ids) {
+ var ids = _.filter(message_ids, function (id) {
+ var message = _.findWhere(messages, {id: id});
+ // If too many messages, not all are fetched, and some might not be found
+ return !message || message.is_needaction;
+ });
+ if (ids.length) {
+ return this._rpc({
+ model: 'mail.message',
+ method: 'set_message_done',
+ args: [ids],
+ });
+ } else {
return $.when();
- };
+ }
+}
+
+chat_manager.mark_all_as_read = function (channel, domain) {
+ if ((channel.id === "channel_inbox" && needaction_counter) || (channel && channel.needaction_counter)) {
+ return this._rpc({
+ model: 'mail.message',
+ method: 'mark_all_as_read',
+ kwargs: {channel_ids: channel.id !== "channel_inbox" ? [channel.id] : [], domain: domain},
+ });
+ }
+ return $.when();
+}
+
chat_manager.undo_mark_as_read = function (message_ids, channel) {
- return MessageModel.call('mark_as_unread', [message_ids, [channel.id]]);
- };
+ return this._rpc({
+ model: 'mail.message',
+ method: 'mark_as_unread',
+ args: [message_ids, [channel.id]],
+ });
+}
+
chat_manager.mark_channel_as_seen = function (channel) {
- if (channel.unread_counter > 0 && channel.type !== 'static') {
- chat_manager.mail_tools.update_channel_unread_counter(channel, 0);
- channel_seen(channel);
- }
- };
+ if (channel.unread_counter > 0 && channel.type !== 'static') {
+ chat_manager.update_channel_unread_counter(channel, 0);
+ this.channel_seen(channel);
+ }
+}
+
chat_manager.get_channels = function () {
- return _.clone(channels);
- };
+ return _.clone(channels);
+}
+
chat_manager.get_channel = function (id) {
- return _.findWhere(channels, {id: id});
- };
+ return _.findWhere(channels, {id: id});
+}
+
chat_manager.get_dm_from_partner_id = function (partner_id) {
- return _.findWhere(channels, {direct_partner_id: partner_id});
- };
+ return _.findWhere(channels, {direct_partner_id: partner_id});
+}
+
chat_manager.all_history_loaded = function (channel, domain) {
- return chat_manager.mail_tools.get_channel_cache(channel, domain).all_history_loaded;
- };
-chat_manager.get_mention_partner_suggestions = function (channel) {
- if (!channel) {
- return mention_partner_suggestions;
- }
- if (!channel.members_deferred) {
- channel.members_deferred = ChannelModel
- .call("channel_fetch_listeners", [channel.uuid], {}, {shadow: true})
- .then(function (members) {
- var suggestions = [];
- _.each(mention_partner_suggestions, function (partners) {
- suggestions.push(_.filter(partners, function (partner) {
- return !_.findWhere(members, { id: partner.id });
- }));
- });
+ return chat_manager.get_channel_cache(channel, domain).all_history_loaded;
+}
- return [members];
+chat_manager.get_mention_partner_suggestions = function (channel) {
+ if (!channel) {
+ return mention_partner_suggestions;
+ }
+ if (!channel.members_deferred) {
+ channel.members_deferred = this._rpc({
+ model: 'mail.channel',
+ method: 'channel_fetch_listeners',
+ args: [channel.uuid],
+ }, {
+ shadow: true
+ })
+ .then(function (members) {
+ var suggestions = [];
+ _.each(mention_partner_suggestions, function (partners) {
+ suggestions.push(_.filter(partners, function (partner) {
+ return !_.findWhere(members, { id: partner.id });
+ }));
});
- }
- return channel.members_deferred;
- };
+
+ return [members];
+ });
+ }
+ return channel.members_deferred;
+}
+
chat_manager.get_commands = function (channel) {
return _.filter(commands, function (command) {
return !command.channel_types || _.contains(command.channel_types, channel.server_type);
});
-};
+}
+
chat_manager.get_canned_responses = function () {
return canned_responses;
-};
+}
+chat_manager.get_emojis = function() {
+ return emojis;
+}
chat_manager.get_needaction_counter = function () {
- return needaction_counter;
- };
+ return needaction_counter;
+}
chat_manager.get_starred_counter = function () {
- return starred_counter;
-};
+ return starred_counter;
+}
chat_manager.get_chat_unread_counter = function () {
- return chat_unread_counter;
- };
+ return chat_unread_counter;
+}
+
chat_manager.get_unread_conversation_counter = function () {
- return unread_conversation_counter;
- };
+ return unread_conversation_counter;
+}
+
chat_manager.get_last_seen_message = function (channel) {
- if (channel.last_seen_message_id) {
- var messages = channel.cache['[]'].messages;
- var msg = _.findWhere(messages, {id: channel.last_seen_message_id});
- if (msg) {
- var i = _.sortedIndex(messages, msg, 'id') + 1;
- while (i < messages.length && (messages[i].is_author || messages[i].is_system_notification)) {
- msg = messages[i];
- i++;
- }
- return msg;
+ if (channel.last_seen_message_id) {
+ var messages = channel.cache['[]'].messages;
+ var msg = _.findWhere(messages, {id: channel.last_seen_message_id});
+ if (msg) {
+ var i = _.sortedIndex(messages, msg, 'id') + 1;
+ while (i < messages.length && (messages[i].is_author || messages[i].is_system_notification)) {
+ msg = messages[i];
+ i++;
}
+ return msg;
}
- };
+ }
+}
+
chat_manager.get_discuss_menu_id = function () {
- return discuss_menu_id;
- };
+ return discuss_menu_id;
+}
+
chat_manager.detach_channel = function (channel) {
- return ChannelModel.call("channel_minimize", [channel.uuid, true], {}, {shadow: true});
- };
-chat_manager.remove_chatter_messages = function (model) {
- messages = _.reject(messages, function (message) {
- return message.channel_ids.length === 0 && message.model === model;
+ return this._rpc({
+ model: 'mail.channel',
+ method: 'channel_minimize',
+ args: [channel.uuid, true],
+ }, {
+ shadow: true,
});
- };
+}
+
+chat_manager.remove_chatter_messages = function (model) {
+ messages = _.reject(messages, function (message) {
+ return message.channel_ids.length === 0 && message.model === model;
+ });
+}
+
chat_manager.create_channel = function (name, type) {
- var method = type === "dm" ? "channel_get" : "channel_create";
- var args = type === "dm" ? [[name]] : [name, type];
+ var method = type === "dm" ? "channel_get" : "channel_create";
+ var args = type === "dm" ? [[name]] : [name, type];
+ var context = _.extend({isMobile: config.device.isMobile}, session.user_context);
+ return this._rpc({
+ model: 'mail.channel',
+ method: method,
+ args: args,
+ kwargs: {context: context},
+ })
+ .then(chat_manager.add_channel);
+}
- return ChannelModel
- .call(method, args)
- .then(chat_manager.mail_tools.add_channel);
- };
chat_manager.join_channel = function (channel_id, options) {
- if (channel_id in channel_defs) {
- // prevents concurrent calls to channel_join_and_get_info
- return channel_defs[channel_id];
- }
- var channel = this.get_channel(channel_id);
- if (channel) {
- // channel already joined
- channel_defs[channel_id] = $.when(channel);
- } else {
- channel_defs[channel_id] = ChannelModel
- .call('channel_join_and_get_info', [[channel_id]])
- .then(function (result) {
- return chat_manager.mail_tools.add_channel(result, options);
- });
- }
+ if (channel_id in channel_defs) {
+ // prevents concurrent calls to channel_join_and_get_info
return channel_defs[channel_id];
- };
+ }
+ var channel = this.get_channel(channel_id);
+ if (channel) {
+ // channel already joined
+ channel_defs[channel_id] = $.when(channel);
+ } else {
+ channel_defs[channel_id] = this._rpc({
+ model: 'mail.channel',
+ method: 'channel_join_and_get_info',
+ args: [[channel_id]],
+ })
+ .then(function (result) {
+ return chat_manager.add_channel(result, options);
+ });
+ }
+ return channel_defs[channel_id];
+}
+
chat_manager.open_and_detach_dm = function (partner_id) {
- return ChannelModel.call('channel_get_and_minimize', [[partner_id]]).then(chat_manager.mail_tools.add_channel);
- };
+ return this._rpc({
+ model: 'mail.channel',
+ method: 'channel_get_and_minimize',
+ args: [[partner_id]],
+ })
+ .then(chat_manager.add_channel);
+}
+
chat_manager.open_channel = function (channel) {
- chat_manager.bus.trigger(client_action_open ? 'open_channel' : 'detach_channel', channel);
- };
+ chat_manager.bus.trigger(client_action_open ? 'open_channel' : 'detach_channel', channel);
+}
+
chat_manager.unsubscribe = function (channel) {
- var def;
- if (_.contains(['public', 'private'], channel.type)) {
- return ChannelModel.call('action_unfollow', [[channel.id]]);
- } else {
- return ChannelModel.call('channel_pin', [channel.uuid, false]);
- }
- };
+ if (_.contains(['public', 'private'], channel.type)) {
+ return this._rpc({
+ model: 'mail.channel',
+ method: 'action_unfollow',
+ args: [[channel.id]],
+ });
+ } else {
+ return this._rpc({
+ model: 'mail.channel',
+ method: 'channel_pin',
+ args: [channel.uuid, false],
+ });
+ }
+}
+
chat_manager.close_chat_session = function (channel_id) {
- var channel = this.get_channel(channel_id);
- ChannelModel.call("channel_fold", [], {uuid : channel.uuid, state : "closed"}, {shadow: true});
- };
+ var channel = this.get_channel(channel_id);
+ this._rpc({
+ model: 'mail.channel',
+ method: 'channel_fold',
+ kwargs: {uuid : channel.uuid, state : 'closed'},
+ }, {shadow: true});
+}
+
chat_manager.fold_channel = function (channel_id, folded) {
- var args = {
- uuid: this.get_channel(channel_id).uuid
- };
- if (_.isBoolean(folded)) {
- args.state = folded ? 'folded' : 'open';
- }
- return ChannelModel.call("channel_fold", [], args, {shadow: true});
+ var args = {
+ uuid: this.get_channel(channel_id).uuid,
};
+ if (_.isBoolean(folded)) {
+ args.state = folded ? 'folded' : 'open';
+ }
+ return this._rpc({
+ model: 'mail.channel',
+ method: 'channel_fold',
+ kwargs: args,
+ }, {shadow: true});
+}
/**
* Special redirection handling for given model and id
*
@@ -1309,151 +1147,156 @@ chat_manager.fold_channel = function (channel_id, folded) {
* Otherwhise, open the record's form view, if this is not the current user's.
*/
chat_manager.redirect = function (res_model, res_id, dm_redirection_callback) {
- var self = this;
- var redirect_to_document = function (res_model, res_id, view_id) {
- web_client.do_action({
- type:'ir.actions.act_window',
- view_type: 'form',
- view_mode: 'form',
- res_model: res_model,
- views: [[view_id || false, 'form']],
- res_id: res_id
- });
- };
- if (res_model === "res.partner") {
- var domain = [["partner_id", "=", res_id]];
- UserModel.call("search", [domain]).then(function (user_ids) {
+ var self = this;
+ var redirect_to_document = function (res_model, res_id, view_id) {
+ web_client.do_action({
+ type:'ir.actions.act_window',
+ view_type: 'form',
+ view_mode: 'form',
+ res_model: res_model,
+ views: [[view_id || false, 'form']],
+ res_id: res_id,
+ });
+ };
+ if (res_model === "res.partner") {
+ var domain = [["partner_id", "=", res_id]];
+ this._rpc({
+ model: 'res.users',
+ method: 'search',
+ args: [domain],
+ })
+ .then(function (user_ids) {
if (user_ids.length && user_ids[0] !== session.uid && dm_redirection_callback) {
self.create_channel(res_id, 'dm').then(dm_redirection_callback);
} else {
redirect_to_document(res_model, res_id);
}
});
- } else {
- new Model(res_model).call('get_formview_id', [[res_id], session.context]).then(function (view_id) {
+ } else {
+ this._rpc({
+ model: res_model,
+ method: 'get_formview_id',
+ args: [[res_id], session.user_context],
+ })
+ .then(function (view_id) {
redirect_to_document(res_model, res_id, view_id);
});
- }
- };
+ }
+}
+
chat_manager.get_channels_preview = function (channels) {
- var channels_preview = _.map(channels, function (channel) {
- var info = _.pick(channel, 'id', 'is_chat', 'name', 'status', 'unread_counter');
- info.last_message = _.last(channel.cache['[]'].messages);
- if (!info.is_chat) {
- info.image_src = '/web/image/mail.channel/'+channel.id+'/image_small';
- } else if (channel.direct_partner_id) {
- info.image_src = '/web/image/res.partner/'+channel.direct_partner_id+'/image_small';
- } else {
- info.image_src = '/mail/static/src/img/smiley/avatar.jpg';
- }
+ var channels_preview = _.map(channels, function (channel) {
+ var info;
+ if (channel.channel_ids && _.contains(channel.channel_ids,"channel_inbox")) {
+ // map inbox(mail_message) data with existing channel/chat template
+ info = _.pick(channel, 'id', 'body', 'avatar_src', 'res_id', 'model', 'module_icon', 'subject','date', 'record_name', 'status', 'displayed_author', 'email_from', 'unread_counter');
+ info.last_message = {
+ body: info.body,
+ date: info.date,
+ displayed_author: info.displayed_author || info.email_from,
+ };
+ info.name = info.record_name || info.subject || info.displayed_author;
+ info.image_src = info.module_icon || info.avatar_src;
+ info.message_id = info.id;
+ info.id = 'channel_inbox';
return info;
- });
- var missing_channels = _.where(channels_preview, {last_message: undefined});
- if (!channels_preview_def) {
- if (missing_channels.length) {
- var missing_channel_ids = _.pluck(missing_channels, 'id');
- channels_preview_def = ChannelModel.call('channel_fetch_preview', [missing_channel_ids], {}, {shadow: true});
- } else {
- channels_preview_def = $.when();
- }
}
- return channels_preview_def.then(function (channels) {
- _.each(missing_channels, function (channel_preview) {
- var channel = _.findWhere(channels, {id: channel_preview.id});
- if (channel) {
- channel_preview.last_message = chat_manager.mail_tools.add_message(channel.last_message);
- }
- });
- return _.filter(channels_preview, function (channel) {
- return channel.last_message; // remove empty channels
- });
- });
- };
-chat_manager.get_message_body_preview = function (message_body) {
- return utils.parse_and_transform(message_body, utils.inline);
- };
-chat_manager.search_partner = function (search_val, limit) {
- var def = $.Deferred();
- var values = [];
- // search among prefetched partners
- var search_regexp = new RegExp(_.str.escapeRegExp(utils.unaccent(search_val)), 'i');
- _.each(mention_partner_suggestions, function (partners) {
- if (values.length < limit) {
- values = values.concat(_.filter(partners, function (partner) {
- return session.partner_id !== partner.id && search_regexp.test(partner.name);
- })).splice(0, limit);
- }
- });
- if (!values.length) {
- // extend the research to all users
- def = PartnerModel.call('im_search', [search_val, limit || 20], {}, {shadow: true});
+ info = _.pick(channel, 'id', 'is_chat', 'name', 'status', 'unread_counter');
+ info.last_message = channel.last_message || _.last(channel.cache['[]'].messages);
+ if (!info.is_chat) {
+ info.image_src = '/web/image/mail.channel/'+channel.id+'/image_small';
+ } else if (channel.direct_partner_id) {
+ info.image_src = '/web/image/res.partner/'+channel.direct_partner_id+'/image_small';
} else {
- def = $.when(values);
+ info.image_src = '/mail/static/src/img/smiley/avatar.jpg';
}
- return def.then(function (values) {
- var autocomplete_data = _.map(values, function (value) {
- return { id: value.id, value: value.name, label: value.name };
- });
- return _.sortBy(autocomplete_data, 'label');
- });
- };
-
-chat_manager.bus.on('client_action_open', null, function (open) {
- client_action_open = open;
-});
-
-// In order to extend init use chat_manager.is_ready Derrered object. See example in mail_arhive module
-function init () {
- chat_manager.mail_tools.add_channel({
- id: "channel_inbox",
- name: _lt("Inbox"),
- type: "static",
- }, { display_needactions: true });
-
- chat_manager.mail_tools.add_channel({
- id: "channel_starred",
- name: _lt("Starred"),
- type: "static"
- });
-
- // unsubscribe and then subscribe to the event, to avoid duplication of new messages
- bus.off('notification');
- bus.on('notification', null, function(){
- chat_manager.mail_tools.on_notification.apply(chat_manager.mail_tools, arguments);
+ return info;
});
-
- return session.rpc('/mail/client_action').then(function (result) {
- _.each(result.channel_slots, function (channels) {
- _.each(channels, chat_manager.mail_tools.add_channel);
+ var missing_channels = _.where(channels_preview, {last_message: undefined});
+ if (!channels_preview_def) {
+ if (missing_channels.length) {
+ var missing_channel_ids = _.pluck(missing_channels, 'id');
+ channels_preview_def = this._rpc({
+ model: 'mail.channel',
+ method: 'channel_fetch_preview',
+ args: [missing_channel_ids],
+ }, {
+ shadow: true,
+ });
+ } else {
+ channels_preview_def = $.when();
+ }
+ }
+ return channels_preview_def.then(function (channels) {
+ _.each(missing_channels, function (channel_preview) {
+ var channel = _.findWhere(channels, {id: channel_preview.id});
+ if (channel) {
+ channel_preview.last_message = chat_manager.add_message(channel.last_message);
+ }
});
- needaction_counter = result.needaction_inbox_counter;
- starred_counter = result.starred_counter;
- commands = _.map(result.commands, function (command) {
- return _.extend({ id: command.name }, command);
+ // sort channels: 1. unread, 2. chat, 3. date of last msg
+ channels_preview.sort(function (c1, c2) {
+ return Math.min(1, c2.unread_counter) - Math.min(1, c1.unread_counter) ||
+ c2.is_chat - c1.is_chat ||
+ !!c2.last_message - !!c1.last_message ||
+ (c2.last_message && c2.last_message.date.diff(c1.last_message.date));
});
- mention_partner_suggestions = result.mention_partner_suggestions;
- discuss_menu_id = result.menu_id;
- // Shortcodes: canned responses and emojis
- _.each(result.shortcodes, function (s) {
- if (s.shortcode_type === 'text') {
- canned_responses.push(_.pick(s, ['id', 'source', 'substitution']));
- } else {
- emojis.push(_.pick(s, ['id', 'source', 'substitution', 'description']));
- emoji_substitutions[_.escape(s.source)] = s.substitution;
+ // generate last message preview (inline message body and compute date to display)
+ _.each(channels_preview, function (channel) {
+ if (channel.last_message) {
+ channel.last_message_preview = chat_manager.get_message_body_preview(channel.last_message.body);
+ channel.last_message_date = channel.last_message.date.fromNow();
}
});
+ return channels_preview;
+ });
+},
+chat_manager.get_message_body_preview = function (message_body) {
+ return utils.parse_and_transform(message_body, utils.inline);
+}
- bus.start_polling();
+chat_manager.search_partner = function (search_val, limit) {
+ var def = $.Deferred();
+ var values = [];
+ // search among prefetched partners
+ var search_regexp = new RegExp(_.str.escapeRegExp(utils.unaccent(search_val)), 'i');
+ _.each(mention_partner_suggestions, function (partners) {
+ if (values.length < limit) {
+ values = values.concat(_.filter(partners, function (partner) {
+ return session.partner_id !== partner.id && search_regexp.test(partner.name);
+ })).splice(0, limit);
+ }
+ });
+ if (!values.length) {
+ // extend the research to all users
+ def = this._rpc({
+ model: 'res.partner',
+ method: 'im_search',
+ args: [search_val, limit || 20],
+ }, {
+ shadow: true,
+ });
+ } else {
+ def = $.when(values);
+ }
+ return def.then(function (values) {
+ var autocomplete_data = _.map(values, function (value) {
+ return { id: value.id, value: value.name, label: value.name };
+ });
+ return _.sortBy(autocomplete_data, 'label');
});
}
-chat_manager.is_ready = init();
+chat_manager.start();
+bus.off('notification');
+bus.on('notification', null, function () {
+ chat_manager.on_notification.apply(chat_manager, arguments);
+});
+
return {
ODOOBOT_ID: ODOOBOT_ID,
chat_manager: chat_manager,
- MailTools: MailTools,
- MailComposer: MailComposer
};
-
+
});