def.then(function (value) { if (value === 'denied') { utils.send_notification(_t('Permission denied'), _t('Odoo will not have the permission to send native notifications on this device.')); } else { utils.send_notification(_t('Permission granted'), _t('Odoo has now the permission to send you native notifications on this device.')); } });
_.each(this._activities, function (activity) { var note = mailUtils.parseAndTransform(activity.note || '', mailUtils.inline); var is_blank = (/^\s*$/).test(note); if (!is_blank) { activity.note = mailUtils.parseAndTransform(activity.note, mailUtils.addLink); } else { activity.note = ''; } });
var prom = new Promise(function(innerResolve, innerReject) { var partnerName = partnerInfo.full_name; var partnerID = partnerInfo.partner_id; var parsedEmail = mailUtils.parseEmail(partnerName); var dialog = new viewDialogs.FormViewDialog(self, { res_model: 'res.partner', res_id: partnerID, context: { active_model: self._model, active_id: self.context.default_res_id, force_email: true, ref: 'compound_context', default_name: parsedEmail[0], default_email: parsedEmail[1], }, title: _t("Please complete customer's informations"), disable_multiple_selection: true, }).open(); dialog.on('closed', self, function () { innerResolve(); }); dialog.opened().then(function () { dialog.form_view.on('on_button_cancel', self, function () { namesToRemove.push(partnerName); if (partnerID) { recipientIDsToRemove.push(partnerID); } }); }); });
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'); }); },
_notifyIncomingMessage: function (message) { if (this.call('bus_service', 'isOdooFocused')) { // no need to notify return; } var title = _t("New message"); if (message.hasAuthor()) { title = _.escape(message.getAuthorName()); } var content = mailUtils.parseAndTransform(message.getBody(), mailUtils.stripHTML) .substr(0, PREVIEW_MSG_MAX_SIZE); if (!this.call('bus_service', 'isOdooFocused')) { this._outOfFocusUnreadMessageCounter++; var tabTitle = _.str.sprintf( _t("%d Messages"), this._outOfFocusUnreadMessageCounter ); this.trigger_up('set_title_part', { part: '_chat', title: tabTitle }); } this.call('bus_service', 'sendNotification', title, content); },
_.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); } }); }); });
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, }; 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; } 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')); });
return $.when(this.mention_prefetched_partners).then(function (prefetched_partners) { // filter prefetched partners with the given search string var suggestions = []; var limit = self.options.mention_fetch_limit; var search_regexp = new RegExp(_.str.escapeRegExp(utils.unaccent(search)), 'i'); _.each(prefetched_partners, function (partners) { if (limit > 0) { var filtered_partners = _.filter(partners, function (partner) { return partner.email && search_regexp.test(partner.email) || partner.name && search_regexp.test(utils.unaccent(partner.name)); }); if (filtered_partners.length) { suggestions.push(filtered_partners.slice(0, limit)); limit -= filtered_partners.length; } } }); if (!suggestions.length && !self.options.mention_partners_restricted) { // no result found among prefetched partners, fetch other suggestions suggestions = self.mention_fetch_throttled('res.partner', 'get_mention_suggestions', { limit: limit, search: search, }); } return suggestions; });
_postMessage: function (data) { // 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 = mailUtils.parseAndTransform(_.str.trim(data.content), mailUtils.addLink); body = this._generateEmojis(body); var messageData = { partner_ids: data.partner_ids, channel_ids: _.map(data.channel_ids, function (channelID) { return [4, channelID, false]; }), body: body, attachment_ids: data.attachment_ids, canned_response_ids: data.canned_response_ids, }; if ('subject' in data) { messageData.subject = data.subject; } return this._super.apply(this, arguments).then(function () { return messageData; }); },
recipientDoneDef.then(function (partnerIDs) { var context = { default_parent_id: self.id, default_body: mailUtils.getTextToHTML(self.$input.val()), default_attachment_ids: _.pluck(self.get('attachment_ids'), 'id'), default_partner_ids: partnerIDs, default_is_log: self.options.isLog, mail_post_autofollow: true, }; 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; } var action = { type: 'ir.actions.act_window', res_model: 'mail.compose.message', view_mode: 'form', view_type: 'form', views: [[false, 'form']], target: 'new', context: context, }; self.do_action(action, { on_close: self.trigger.bind(self, 'need_refresh'), }).then(self.trigger.bind(self, 'close_composer')); });
this.canned_timeout = setTimeout(function() { var canned_responses = self._getCannedResponses(); var matches = fuzzy.filter(utils.unaccent(search), _.pluck(canned_responses, 'source')); var indexes = _.pluck(matches.slice(0, self.options.mention_fetch_limit), 'index'); def.resolve(_.map(indexes, function (i) { return canned_responses[i]; })); }, 500);
this._cannedTimeout = setTimeout(function () { var cannedResponses = self.call('mail_service', 'getCannedResponses'); var matches = fuzzy.filter(mailUtils.unaccent(search), _.pluck(cannedResponses, 'source')); var indexes = _.pluck(matches.slice(0, self.options.mentionFetchLimit), 'index'); def.resolve(_.map(indexes, function (index) { return cannedResponses[index]; })); }, 500);
mention_get_canned_responses: function (search) { var canned_responses = chat_manager.get_canned_responses(); var matches = fuzzy.filter(utils.unaccent(search), _.pluck(canned_responses, 'source')); var indexes = _.pluck(matches.slice(0, this.options.mention_fetch_limit), 'index'); return _.map(indexes, function (i) { return canned_responses[i]; }); },
function notify_incoming_message (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); 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(title, content); }
_.each(thread_recipients, function (recipient) { var parsed_email = recipient[1] && mailUtils.parseEmail(recipient[1]); 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], }); });
getPreview: function () { var result = this._super.apply(this, arguments); if (!this.isTwoUserThread()) { result.imageSRC = '/web/image/mail.channel/' + this.getID() + '/image_small'; } var lastMessage = this.getLastMessage(); return _.extend(result, { author: lastMessage ? lastMessage.getDisplayedAuthor() : '', body: lastMessage ? mailUtils.parseAndTransform(lastMessage.getBody(), mailUtils.inline) : '', date: lastMessage ? lastMessage.getDate() : moment(), isMyselfAuthor: this.hasMessages() && this.getLastMessage().isMyselfAuthor(), }); },
_searchPartnerPrefetch: function (searchVal, limit) { var values = []; var searchRegexp = new RegExp(_.str.escapeRegExp(mailUtils.unaccent(searchVal)), 'i'); _.each(this._mentionPartnerSuggestions, function (partners) { if (values.length < limit) { values = values.concat(_.filter(partners, function (partner) { return (session.partner_id !== partner.id) && searchRegexp.test(partner.name); })).splice(0, limit); } }); return values; },
_.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], }); } });
post_message: function (data, options) { 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, }; 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 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) { msgs[0].model = options.model; msgs[0].res_id = options.res_id; add_message(msgs[0]); }); }); } },
getPreview: function () { var id, title; if (this.isLinkedToDocumentThread()) { id = this.getDocumentModel() + '_' + this.getDocumentID(); title = this.getDocumentName(); } else { id = 'mailbox_inbox'; title = this.hasSubject() ? this.getSubject() : this.getDisplayedAuthor(); } return { author: this.getDisplayedAuthor(), body: mailUtils.parseAndTransform(this.getBody(), mailUtils.inline), date: this.getDate(), documentModel: this.getDocumentModel(), documentID: this.getDocumentID(), id: id, imageSRC: this._getModuleIcon() || this.getAvatarSource(), status: this.status, title: title, }; },
_processBody: function () { var self = this; _.each(emojis, function (emoji) { var unicode = emoji.unicode; var regexp = new RegExp("(?:^|\\s|<[a-z]*>)(" + unicode + ")(?=\\s|$|</[a-z]*>)", 'g'); var originalBody = self.body; self._body = self._body.replace(regexp, ' <span class="o_mail_emoji">' + unicode + '</span> '); // Idiot-proof limit. If the user had the amazing idea of // copy-pasting thousands of emojis, the image rendering can lead // to memory overflow errors on some browsers (e.g. Chrome). Set an // arbitrary limit to 200 from which we simply don't replace them // (anyway, they are already replaced by the unicode counterpart). if (_.str.count(self._body, 'o_mail_emoji') > 200) { self._body = originalBody; } }); // add anchor tags to urls self._body = mailUtils.parseAndTransform(self._body, mailUtils.addLink); },
var filtered_partners = _.filter(partners, function (partner) { return partner.email && search_regexp.test(partner.email) || partner.name && search_regexp.test(utils.unaccent(partner.name)); });
_.each(self.activities, function (activity) { if (activity.note) { activity.note = utils.parse_and_transform(activity.note, utils.add_link); } });
this.$('.o_mail_timestamp').each(function () { var date = $(this).data('date'); $(this).html(mailUtils.timeFromNow(date)); });
def.then(function () { utils.send_notification('Permission granted', 'Odoo has now the permission to send you native notifications on this device.'); });
_mentionGetCommands: function (search) { var searchRegexp = new RegExp(_.str.escapeRegExp(mailUtils.unaccent(search)), 'i'); return _.filter(this._mentionCommands, function (command) { return searchRegexp.test(command.name); }).slice(0, this.options.mentionFetchLimit); },
get_message_body_preview: function (message_body) { return utils.parse_and_transform(message_body, utils.inline); },
mention_get_commands: function (search) { var search_regexp = new RegExp(_.str.escapeRegExp(utils.unaccent(search)), 'i'); return _.filter(this.mention_commands, function (command) { return search_regexp.test(command.name); }).slice(0, this.options.mention_fetch_limit); },
function make_message (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', attachment_ids: data.attachment_ids, subject: data.subject, email_from: data.email_from, 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, ' <span class="o_mail_emoji">'+emoji_substitutions[key]+'</span> '); }); function property_descr(channel) { return { enumerable: true, get: function () { return _.contains(msg.channel_ids, channel); }, set: function (bool) { if (bool) { add_channel_to_message(msg, channel); } else { msg.channel_ids = _.without(msg.channel_ids, channel); } } }; } Object.defineProperties(msg, { is_starred: property_descr("channel_starred"), is_needaction: property_descr("channel_inbox"), }); 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; } if (msg.model === 'mail.channel') { var real_channels = _.without(msg.channel_ids, 'channel_inbox', 'channel_starred'); 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; } } // 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 && msg.author_id[1] || msg.email_from || _t('Anonymous'); } // Don't redirect on author clicked of self-posted messages msg.author_redirect = !msg.is_author; // Compute the avatar_url 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"; } // add anchor tags to urls msg.body = utils.parse_and_transform(msg.body, utils.add_link); // Compute url of attachments _.each(msg.attachment_ids, function(a) { a.url = '/web/content/' + a.id + '?download=true'; }); return msg; }