var _t = session.web._t,
_lt = session.web._lt;
- var mail = session.mail = {};
+ var mail = session.mail;
- openerp_mail_followers(session, mail); // import mail_followers.js
- openerp_FieldMany2ManyTagsEmail(session); // import manyy2many_tags_email.js
+ openerp_mail_followers(session, mail); // import mail_followers.js
+ openerp_FieldMany2ManyTagsEmail(session); // import manyy2many_tags_email.js
+ openerp_announcement(session);
/**
* ------------------------------------------------------------
*/
get_text2html: function (text) {
return text
- .replace(/[\n\r]/g,'<br/>')
.replace(/((?:https?|ftp):\/\/[\S]+)/g,'<a href="$1">$1</a> ')
+ .replace(/[\n\r]/g,'<br/>')
},
/* Returns the complete domain with "&"
}
return out;
},
-
- // returns the file type of a file based on its extension
- // As it only looks at the extension it is quite approximative.
- filetype: function(url){
- var url = url && url.filename || url;
- var tokens = typeof url == 'string' ? url.split('.') : [];
- if(tokens.length <= 1){
- return 'unknown';
- }
- var extension = tokens[tokens.length -1];
- if(extension.length === 0){
- return 'unknown';
- }else{
- extension = extension.toLowerCase();
- }
- var filetypes = {
- 'webimage': ['png','jpg','jpeg','jpe','gif'], // those have browser preview
- 'image': ['tif','tiff','tga',
- 'bmp','xcf','psd','ppm','pbm','pgm','pnm','mng',
- 'xbm','ico','icon','exr','webp','psp','pgf','xcf',
- 'jp2','jpx','dng','djvu','dds'],
- 'vector': ['ai','svg','eps','vml','cdr','xar','cgm','odg','sxd'],
- 'print': ['dvi','pdf','ps'],
- 'document': ['doc','docx','odm','odt'],
- 'presentation': ['key','keynote','odp','pps','ppt'],
- 'font': ['otf','ttf','woff','eot'],
- 'archive': ['zip','7z','ace','apk','bzip2','cab','deb','dmg','gzip','jar',
- 'rar','tar','gz','pak','pk3','pk4','lzip','lz','rpm'],
- 'certificate': ['cer','key','pfx','p12','pem','crl','der','crt','csr'],
- 'audio': ['aiff','wav','mp3','ogg','flac','wma','mp2','aac',
- 'm4a','ra','mid','midi'],
- 'video': ['asf','avi','flv','mkv','m4v','mpeg','mpg','mpe','wmv','mp4','ogm'],
- 'text': ['txt','rtf','ass'],
- 'html': ['html','xhtml','xml','htm','css'],
- 'disk': ['iso','nrg','img','ccd','sub','cdi','cue','mds','mdx'],
- 'script': ['py','js','c','cc','cpp','cs','h','java','bat','sh',
- 'd','rb','pl','as','cmd','coffee','m','r','vbs','lisp'],
- 'spreadsheet': ['123','csv','ods','numbers','sxc','xls','vc','xlsx'],
- 'binary': ['exe','com','bin','app'],
- };
- for(filetype in filetypes){
- var ext_list = filetypes[filetype];
- for(var i = 0, len = ext_list.length; i < len; i++){
- if(extension === ext_list[i]){
- return filetype;
- }
- }
- }
- return 'unknown';
- },
-
};
this.res_id = datasets.res_id || this.context.default_res_id || false,
this.parent_id = datasets.parent_id || false,
this.type = datasets.type || false,
+ this.subtype = datasets.subtype || false,
this.is_author = datasets.is_author || false,
+ this.author_avatar = datasets.author_avatar || false,
this.is_private = datasets.is_private || false,
this.subject = datasets.subject || false,
this.name = datasets.name || false,
this.record_name = datasets.record_name || false,
this.body = datasets.body || '',
+ this.body_short = datasets.body_short || '',
this.vote_nb = datasets.vote_nb || 0,
this.has_voted = datasets.has_voted || false,
this.is_favorite = datasets.is_favorite || false,
this.attachment_ids = datasets.attachment_ids || [],
this.partner_ids = datasets.partner_ids || [];
this.date = datasets.date;
-
+ this.user_pid = datasets.user_pid || false;
this.format_data();
+ // update record_name: Partner profile
+ if (this.model == 'res.partner') {
+ this.record_name = 'Partner Profile of ' + this.record_name;
+ }
+ else if (this.model == 'hr.employee') {
+ this.record_name = 'News from ' + this.record_name;
+ }
// record options and data
- this.show_record_name = this.options.show_record_name && this.record_name && !this.thread_level && this.model != 'res.partner';
+ this.show_record_name = this.options.show_record_name && this.record_name && !this.thread_level;
this.options.show_read = false;
this.options.show_unread = false;
if (this.options.show_read_unread_button) {
/* Convert date, timerelative and avatar in displayable data. */
format_data: function () {
+
//formating and add some fields for render
this.date = this.date ? session.web.str_to_datetime(this.date) : false;
+ this.display_date = this.date.toString('ddd MMM dd yyyy HH:mm');
if (this.date && new Date().getTime()-this.date.getTime() < 7*24*60*60*1000) {
this.timerelative = $.timeago(this.date);
- }
- if (this.type == 'email' && (!this.author_id || !this.author_id[0])) {
+ }
+ if (this.author_avatar) {
+ this.avatar = "data:image/png;base64," + this.author_avatar;
+ } else if (this.type == 'email' && (!this.author_id || !this.author_id[0])) {
this.avatar = ('/mail/static/src/img/email_icon.png');
} else if (this.author_id && this.template != 'mail.compose_message') {
this.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', this.author_id[0]);
var attach = this.attachment_ids[l];
if (!attach.formating) {
attach.url = mail.ChatterUtils.get_attachment_url(this.session, this.id, attach.id);
- attach.filetype = mail.ChatterUtils.filetype(attach.filename || attach.name);
attach.name = mail.ChatterUtils.breakword(attach.name || attach.filename);
attach.formating = true;
}
}
$.when(recipient_done).done(function (partner_ids) {
var context = {
- 'default_composition_mode': default_composition_mode,
'default_parent_id': self.id,
'default_body': mail.ChatterUtils.get_text2html(self.$el ? (self.$el.find('textarea:not(.oe_compact)').val() || '') : ''),
'default_attachment_ids': _.map(self.attachment_ids, function (file) {return file.id;}),
'default_partner_ids': partner_ids,
+ 'default_is_log': self.is_log,
'mail_post_autofollow': true,
'mail_post_autofollow_partner_ids': partner_ids,
+ 'is_private': self.is_private
};
- if (self.is_log) {
- _.extend(context, {'mail_compose_log': true});
- }
if (default_composition_mode != 'reply' && self.context.default_model && self.context.default_res_id) {
context.default_model = self.context.default_model;
context.default_res_id = self.context.default_res_id;
// have unknown names -> call message_get_partner_info_from_emails to try to find partner_id
var find_done = $.Deferred();
if (names_to_find.length > 0) {
- find_done = self.parent_thread.ds_thread._model.call('message_get_partner_info_from_emails', [names_to_find]);
+ find_done = self.parent_thread.ds_thread._model.call('message_partner_info_from_emails', [this.context.default_res_id, names_to_find]);
}
else {
find_done.resolve([]);
var new_names_to_find = _.difference(names_to_find, names_to_remove);
find_done = $.Deferred();
if (new_names_to_find.length > 0) {
- find_done = self.parent_thread.ds_thread._model.call('message_get_partner_info_from_emails', [new_names_to_find, true]);
+ find_done = self.parent_thread.ds_thread._model.call('message_partner_info_from_emails', [self.context.default_res_id, new_names_to_find, true]);
}
else {
find_done.resolve([]);
}
// create object and attach to the thread object
thread.message_fetch([["id", "=", message_id]], false, [message_id], function (arg, data) {
- var message = thread.create_message_object( data[0] );
+ var message = thread.create_message_object( data.slice(-1)[0] );
// insert the message on dom
thread.insert_message( message, root ? undefined : self.$el, root );
});
// if clicked: call for suggested recipients
if (event.type == 'click') {
this.is_log = $input.hasClass('oe_compose_log');
- suggested_partners = this.parent_thread.ds_thread.call('message_get_suggested_recipients', [[this.context.default_res_id]]).done(function (additional_recipients) {
+ suggested_partners = this.parent_thread.ds_thread.call('message_get_suggested_recipients', [[this.context.default_res_id], this.context]).done(function (additional_recipients) {
var thread_recipients = additional_recipients[self.context.default_res_id];
_.each(thread_recipients, function (recipient) {
var parsed_email = mail.ChatterUtils.parse_email(recipient[1]);
// go to the parented message
var message = this.parent_thread.parent_message;
var parent_message = message.parent_id ? message.parent_thread.parent_message : message;
- var messages = [parent_message].concat(parent_message.get_childs());
+ if(parent_message){
+ var messages = [parent_message].concat(parent_message.get_childs());
+ }
} else if (this.options.emails_from_on_composer) {
// get all wall messages if is not a mail.Wall
_.each(this.options.root_thread.messages, function (msg) {messages.push(msg); messages.concat(msg.get_childs());});
on_checked_recipient: function (event) {
var $input = $(event.target);
- var email = $input.attr("data");
+ var full_name = $input.attr("data");
_.each(this.recipients, function (recipient) {
- if (recipient.email_address == email) {
+ if (recipient.full_name == full_name) {
recipient.checked = $input.is(":checked");
}
});
self.parent_thread.message_fetch(this.domain, this.context, false, function (arg, data) {
self.id = false;
// insert the message on dom after this message
- self.parent_thread.switch_new_message( data, self.$el );
+ self.parent_thread.switch_new_message( data, self.$el.parent() );
self.animated_destroy(200);
});
start: function () {
this._super.apply(this, arguments);
- this.expender();
this.bind_events();
if(this.thread_level < this.options.display_indented_thread) {
this.create_thread();
this.$('.oe_reply').on('click', this.on_message_reply);
this.$('.oe_star').on('click', this.on_star);
this.$('.oe_msg_vote').on('click', this.on_vote);
+ this.$('.oe_mail_vote_count').on('mouseenter', this.on_hover);
+ this.$('.oe_mail_expand').on('click', this.on_expand);
+ this.$('.oe_mail_reduce').on('click', this.on_expand);
+ this.$('.oe_mail_action_model').on('click', this.on_record_clicked);
+ this.$('.oe_mail_action_author').on('click', this.on_record_author_clicked);
+ },
+ on_hover : function(event){
+ var self = this;
+ var voter = "";
+ var limit = 10;
+ event.stopPropagation();
+ var $target = $(event.target).hasClass("fa-thumbs-o-up") ? $(event.target).parent() : $(event.target);
+ //Note: We can set data-content attr on target element once we fetch data so that next time when one moves mouse on element it saves call
+ //But if there is new like comes then we'll not have new likes in popover in that case
+ if ($target.data('liker-list'))
+ {
+ voter = $target.data('liker-list');
+ self.bindTooltipTo($target, voter);
+ $target.tooltip('hide').tooltip('show');
+ $(".tooltip").on("mouseleave", function () {
+ $(this).remove();
+ });
+ }else{
+ this.ds_message.call('get_likers_list', [this.id, limit])
+ .done(function (data) {
+ _.each(data, function(people, index) {
+ voter = voter + people.substring(0,1).toUpperCase() + people.substring(1);
+ if(index != data.length-1) {
+ voter = voter + "<br/>";
+ }
+ });
+ $target.data('liker-list', voter);
+ self.bindTooltipTo($target, voter);
+ $target.tooltip('hide').tooltip('show');
+ $(".tooltip").on("mouseleave", function () {
+ $(this).remove();
+ });
+ });
+ }
+ return true;
+ },
+ bindTooltipTo: function($el, value) {
+ $el.tooltip({
+ 'title': value,
+ 'placement': 'top',
+ 'container': this.el,
+ 'html': true,
+ 'trigger': 'manual',
+ 'animation': false
+ }).on("mouseleave", function () {
+ setTimeout(function () {
+ if (!$(".tooltip:hover").length) {
+ $el.tooltip("hide");
+ }
+ },100);
+ });
+ },
+ on_record_clicked: function (event) {
+ event.preventDefault();
+ var self = this;
+ var state = {
+ 'model': this.model,
+ 'id': this.res_id,
+ 'title': this.record_name
+ };
+ session.webclient.action_manager.do_push_state(state);
+ this.context.params = {
+ model: this.model,
+ res_id: this.res_id,
+ };
+ this.thread.ds_thread.call("message_redirect_action", {context: this.context}).then(function(action){
+ self.do_action(action);
+ });
+ },
+
+ on_record_author_clicked: function (event) {
+ event.preventDefault();
+ var partner_id = $(event.target).data('partner');
+ var state = {
+ 'model': 'res.partner',
+ 'id': partner_id,
+ 'title': this.record_name
+ };
+ session.webclient.action_manager.do_push_state(state);
+ var action = {
+ type:'ir.actions.act_window',
+ view_type: 'form',
+ view_mode: 'form',
+ res_model: 'res.partner',
+ views: [[false, 'form']],
+ res_id: partner_id,
+ }
+ this.do_action(action);
},
/* Call the on_compose_message on the thread of this message. */
return false;
},
- expender: function () {
- this.$('.oe_msg_body:first').expander({
- slicePoint: this.options.truncate_limit,
- expandText: 'read more',
- userCollapseText: 'read less',
- detailClass: 'oe_msg_tail',
- moreClass: 'oe_mail_expand',
- lessClass: 'oe_mail_reduce',
- });
+ on_expand: function (event) {
+ event.stopPropagation();
+ this.$('.oe_msg_body:first > .oe_msg_body_short:first').toggle();
+ this.$('.oe_msg_body:first > .oe_msg_body_long:first').toggle();
+ return false;
},
/**
msg.renderElement();
msg.start();
}
- if( self.options.root_thread.__parentedParent.__parentedParent.do_reload_menu_emails ) {
- self.options.root_thread.__parentedParent.__parentedParent.do_reload_menu_emails();
- }
+ self.options.root_thread.MailWidget.do_reload_menu_emails();
});
});
this.$(".oe_msg_footer:first .oe_mail_vote_count").remove();
this.$(".oe_msg_footer:first .oe_msg_vote").replaceWith(vote_element);
this.$('.oe_msg_vote').on('click', this.on_vote);
+ this.$('.oe_mail_vote_count').on('mouseenter', this.on_hover);
},
/**
init: function (parent, datasets, options) {
var self = this;
this._super(parent, options);
+ this.MailWidget = parent instanceof mail.Widget ? parent : false;
this.domain = options.domain || [];
this.context = _.extend(options.context || {});
if (datasets.author_id && !_.contains(_.flatten(datasets.partner_ids),datasets.author_id[0]) && datasets.author_id[0]) {
datasets.partner_ids.push(datasets.author_id);
}
+ this.user_pid = datasets.user_pid || false;
this.partner_ids = datasets.partner_ids;
this.messages = [];
-
this.options.flat_mode = (this.options.display_indented_thread - this.thread_level > 0);
// object compose message
message_fetch: function (replace_domain, replace_context, ids, callback) {
return this.ds_message.call('message_read', [
// ids force to read
- ids == false ? undefined : ids,
+ ids === false ? undefined : ids,
// domain + additional
(replace_domain ? replace_domain : this.domain),
// ids allready loaded
message_fetch_set_read: function (message_list) {
if (! this.context.mail_read_set_read) return;
- this.render_mutex.exec(_.bind(function() {
+ var self = this;
+ this.render_mutex.exec(function() {
msg_ids = _.pluck(message_list, 'id');
- return this.ds_message.call('set_message_read', [
- msg_ids, true, false, this.context]);
- }, this));
+ return self.ds_message.call('set_message_read', [msg_ids, true, false, self.context])
+ .then(function (nb_read) {
+ if (nb_read) {
+ self.options.root_thread.MailWidget.do_reload_menu_emails();
+ }
+ });
+ });
},
/**
},
/**
+ * create an object "related_menu"
+ * contains the menu widget and the sub menu related of this wall
+ */
+ do_reload_menu_emails: function () {
+ var menu = session.webclient.menu;
+ if (!menu || !menu.current_menu) {
+ return $.when();
+ }
+ return menu.rpc("/web/menu/load_needaction", {'menu_ids': [menu.current_menu]}).done(function(r) {
+ menu.on_needaction_loaded(r);
+ }).then(function () {
+ menu.trigger("need_action_reloaded");
+ });
+ },
+
+ /**
*Create the root thread and display this object in the DOM.
* Call the no_message method then c all the message_fetch method
* of this root thread to display the messages.
init: function (parent, node) {
this._super.apply(this, arguments);
+ this.ParentViewManager = parent;
this.node = _.clone(node);
this.node.params = _.extend({
'display_indented_thread': -1,
'read_action': 'unread',
'show_record_name': false,
'show_compact_message': 1,
+ 'display_log_button' : true,
}, this.node.params);
-
if (this.node.attrs.placeholder) {
this.node.params.compose_placeholder = this.node.attrs.placeholder;
}
if (this.node.attrs.readonly) {
this.node.params.readonly = this.node.attrs.readonly;
}
+ if ('display_log_button' in this.options) {
+ this.node.params.display_log_button = this.options.display_log_button;
+ }
+ this.domain = (this.node.params && this.node.params.domain) || (this.field && this.field.domain) || [];
- this.domain = this.node.params && this.node.params.domain || [];
-
- if (!this.__parentedParent.is_action_enabled('edit')) {
+ if (!this.ParentViewManager.is_action_enabled('edit')) {
this.node.params.show_link = false;
}
},
/**
* ------------------------------------------------------------
+ * Aside Widget
+ * ------------------------------------------------------------
+ *
+ * This widget handles the display of a sidebar on the Wall. Its main use
+ * is to display group and employees suggestion (if hr is installed).
+ */
+ mail.WallSidebar = session.web.Widget.extend({
+ template: 'mail.wall.sidebar',
+ });
+
+
+ /**
+ * ------------------------------------------------------------
* Wall Widget
* ------------------------------------------------------------
*
*/
init: function (parent, action) {
this._super(parent, action);
+ this.ActionManager = parent;
this.action = _.clone(action);
this.domain = this.action.params.domain || this.action.domain || [];
this.context = _.extend(this.action.params.context || {}, this.action.context || {});
+ // filter some parameters that we will propagate as search_default
this.defaults = {};
+ for (var key in this.action.context.params) {
+ if (_.indexOf(['model', 'res_id'], key) == -1) {
+ continue;
+ }
+ this.context['search_default_' + key] = this.action.context.params[key];
+ }
for (var key in this.context) {
if (key.match(/^search_default_/)) {
this.defaults[key.replace(/^search_default_/, '')] = this.context[key];
if (! this.searchview.has_defaults) {
this.message_render();
}
- },
-
- /**
- * crete an object "related_menu"
- * contain the menu widget and the the sub menu related of this wall
- */
- do_reload_menu_emails: function () {
- var menu = this.__parentedParent.__parentedParent.menu;
- // return this.rpc("/web/menu/load", {'menu_id': 100}).done(function(r) {
- // _.each(menu.data.data.children, function (val) {
- // if (val.id == 100) {
- // val.children = _.find(r.data.children, function (r_val) {return r_val.id == 100;}).children;
- // }
- // });
- // var r = menu.data;
- // window.setTimeout(function(){menu.do_reload();}, 0);
- // });
+ // render sidebar
+ var wall_sidebar = new mail.WallSidebar(this);
+ wall_sidebar.appendTo(this.$el.find('.oe_mail_wall_aside'));
},
/**
* @param {Object} defaults ??
*/
load_searchview: function (defaults) {
- var self = this;
var ds_msg = new session.web.DataSetSearch(this, 'mail.message');
this.searchview = new session.web.SearchView(this, ds_msg, false, defaults || {}, false);
- this.searchview.appendTo(this.$('.oe_view_manager_view_search'))
- .then(function () { self.searchview.on('search_data', self, self.do_searchview_search); });
+ this.searchview.on('search_data', this, this.do_searchview_search);
+ this.searchview.appendTo(this.$('.oe_view_manager_view_search'),
+ this.$('.oe_searchview_drawer_container'));
if (this.searchview.has_defaults) {
this.searchview.ready.then(this.searchview.do_search);
}
}
});
-
/**
* ------------------------------------------------------------
- * UserMenu
+ * Sub-widgets loading
* ------------------------------------------------------------
*
- * Add a link on the top user bar for write a full mail
+ * Load here widgets that could depend on widgets defined in mail.js
*/
- session.web.ComposeMessageTopButton = session.web.Widget.extend({
- template:'mail.ComposeMessageTopButton',
- start: function () {
- this.$('button').on('click', this.on_compose_message );
- this._super();
- },
-
- on_compose_message: function (event) {
- event.stopPropagation();
- var action = {
- type: 'ir.actions.act_window',
- res_model: 'mail.compose.message',
- view_mode: 'form',
- view_type: 'form',
- views: [[false, 'form']],
- target: 'new',
- context: {},
- };
- session.client.action_manager.do_action(action);
- },
- });
+ openerp.mail.suggestions(session, mail); // import suggestion.js (suggestion widget)
- session.web.UserMenu.include({
- do_update: function(){
- var self = this;
- this._super.apply(this, arguments);
- this.update_promise.then(function() {
- var mail_button = new session.web.ComposeMessageTopButton();
- mail_button.appendTo(session.webclient.$el.find('.oe_systray'));
- });
- },
- });
};