[MERGE] forward port of branch 8.0 up to e883193
[odoo/odoo.git] / addons / mail / static / src / js / mail.js
index 1e58dc4..a42bc41 100644 (file)
@@ -2,10 +2,11 @@ openerp.mail = function (session) {
     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);
 
     /**
      * ------------------------------------------------------------
@@ -75,8 +76,8 @@ openerp.mail = function (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 "&" 
@@ -113,57 +114,6 @@ openerp.mail = function (session) {
             }
             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';
-        },
-
     };
 
 
@@ -219,11 +169,13 @@ openerp.mail = function (session) {
             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,
@@ -233,11 +185,18 @@ openerp.mail = function (session) {
             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) {
@@ -256,12 +215,16 @@ openerp.mail = function (session) {
 
         /* 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]);
@@ -290,7 +253,6 @@ openerp.mail = function (session) {
                 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;
                 }
@@ -545,17 +507,15 @@ openerp.mail = function (session) {
             }
             $.when(recipient_done).done(function (partner_ids) {
                 var context = {
-                    'default_composition_mode': default_composition_mode,
                     'default_parent_id': self.id,
                     'default_body': mail.ChatterUtils.get_text2html(self.$el ? (self.$el.find('textarea:not(.oe_compact)').val() || '') : ''),
-                    'default_attachment_ids': self.attachment_ids,
+                    'default_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;
@@ -620,10 +580,7 @@ openerp.mail = function (session) {
             // 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) {
-                var values = {
-                    'res_id': this.context.default_res_id,
-                }
-                find_done = self.parent_thread.ds_thread._model.call('message_get_partner_info_from_emails', [names_to_find], values);
+                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([]);
@@ -669,11 +626,7 @@ openerp.mail = function (session) {
                     var new_names_to_find = _.difference(names_to_find, names_to_remove);
                     find_done = $.Deferred();
                     if (new_names_to_find.length > 0) {
-                        var values = {
-                            'link_mail': true,
-                            'res_id': self.context.default_res_id,
-                        }
-                        find_done = self.parent_thread.ds_thread._model.call('message_get_partner_info_from_emails', [new_names_to_find], values);
+                        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([]);
@@ -742,7 +695,7 @@ openerp.mail = function (session) {
                 }
                 // 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 );
                 });
@@ -767,7 +720,7 @@ openerp.mail = function (session) {
             // 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]);
@@ -827,7 +780,9 @@ openerp.mail = function (session) {
                 // 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());});
@@ -925,7 +880,7 @@ openerp.mail = function (session) {
             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);
             });
 
@@ -939,7 +894,6 @@ openerp.mail = function (session) {
         
         start: function () {
             this._super.apply(this, arguments);
-            this.expender();
             this.bind_events();
             if(this.thread_level < this.options.display_indented_thread) {
                 this.create_thread();
@@ -962,6 +916,99 @@ openerp.mail = function (session) {
             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. */
@@ -972,15 +1019,11 @@ openerp.mail = function (session) {
             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;
         },
 
         /**
@@ -1132,6 +1175,7 @@ openerp.mail = function (session) {
             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);
         },
 
         /**
@@ -1196,7 +1240,7 @@ openerp.mail = function (session) {
         init: function (parent, datasets, options) {
             var self = this;
             this._super(parent, options);
-            this.MailWidget = parent.__proto__ == mail.Widget.prototype ? parent : false;
+            this.MailWidget = parent instanceof mail.Widget ? parent : false;
             this.domain = options.domain || [];
             this.context = _.extend(options.context || {});
 
@@ -1218,9 +1262,9 @@ openerp.mail = function (session) {
             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
@@ -1413,7 +1457,7 @@ openerp.mail = function (session) {
         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
@@ -1705,8 +1749,8 @@ openerp.mail = function (session) {
         },
         
         /**
-        * crete an object "related_menu"
-        * contain the menu widget and the the sub menu related of this wall
+        * 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;
@@ -1778,16 +1822,18 @@ openerp.mail = function (session) {
                 '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;
             }
-
-            this.domain = this.node.params && this.node.params.domain || [];
+            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) || [];
 
             if (!this.ParentViewManager.is_action_enabled('edit')) {
                 this.node.params.show_link = false;
@@ -1839,6 +1885,19 @@ openerp.mail = function (session) {
 
     /**
      * ------------------------------------------------------------
+     * 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
      * ------------------------------------------------------------
      *
@@ -1866,7 +1925,14 @@ openerp.mail = function (session) {
             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];
@@ -1891,6 +1957,9 @@ openerp.mail = function (session) {
             if (! this.searchview.has_defaults) {
                 this.message_render();
             }
+            // render sidebar
+            var wall_sidebar = new mail.WallSidebar(this);
+            wall_sidebar.appendTo(this.$el.find('.oe_mail_wall_aside'));
         },
 
         /**
@@ -1898,11 +1967,11 @@ openerp.mail = function (session) {
          * @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);
             }
@@ -1950,6 +2019,7 @@ openerp.mail = function (session) {
             this.$(".oe_write_full").click(function (event) {
                 event.stopPropagation();
                 var action = {
+                    name: _t('Compose Email'),
                     type: 'ir.actions.act_window',
                     res_model: 'mail.compose.message',
                     view_mode: 'form',
@@ -1966,45 +2036,14 @@ openerp.mail = function (session) {
         }
     });
 
-
     /**
      * ------------------------------------------------------------
-     * 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();
-        },
+    openerp.mail.suggestions(session, mail);        // import suggestion.js (suggestion widget)
 
-        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);
-        },
-    });
-
-    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'));
-            });
-        },
-    });
 };