diff options
| author | Christophe Matthieu <chm@openerp.com> | 2012-09-27 10:30:56 +0200 |
|---|---|---|
| committer | Christophe Matthieu <chm@openerp.com> | 2012-09-27 10:30:56 +0200 |
| commit | bc85a60e8efa2dbc98eb9acc3e2109a2e5ceae16 (patch) | |
| tree | e5f292f10b14e89662074784f1a704ce22d219ee /addons | |
| parent | 4ddb50dbf920a02bbb6f1c210a1215abd8a0b428 (diff) | |
[IMP] mail: read/unread with propagation; browse_thread on js
bzr revid: chm@openerp.com-20120927083056-o8s4h0pehsjdzw5j
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/mail/mail_followers.py | 8 | ||||
| -rw-r--r-- | addons/mail/mail_message_view.xml | 4 | ||||
| -rw-r--r-- | addons/mail/static/src/css/mail.css | 31 | ||||
| -rw-r--r-- | addons/mail/static/src/js/mail.js | 155 | ||||
| -rw-r--r-- | addons/mail/static/src/xml/mail.xml | 52 |
5 files changed, 192 insertions, 58 deletions
diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py index 0d5cde3982e..c351e8a5491 100644 --- a/addons/mail/mail_followers.py +++ b/addons/mail/mail_followers.py @@ -83,9 +83,13 @@ class mail_notification(osv.Model): return super(mail_notification, self).create(cr, uid, vals, context=context) return False - def set_message_read(self, cr, uid, msg_id, context=None): + def set_message_read(self, cr, uid, msg_ids, context=None): + if msg_ids == None: + return False + if type(msg_ids) is not list: + msg_ids=[msg_ids] partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id - notif_ids = self.search(cr, uid, [('partner_id', '=', partner_id), ('message_id', '=', msg_id)], context=context) + notif_ids = self.search(cr, uid, [('partner_id', '=', partner_id), ('message_id', 'in', msg_ids)], context=context) return self.write(cr, uid, notif_ids, {'read': True}, context=context) def get_partners_to_notify(self, cr, uid, partner_ids, message, context=None): diff --git a/addons/mail/mail_message_view.xml b/addons/mail/mail_message_view.xml index 01a0ee10e54..78ecc6867c2 100644 --- a/addons/mail/mail_message_view.xml +++ b/addons/mail/mail_message_view.xml @@ -56,6 +56,9 @@ <field name="subject" string="Content" filter_domain="['|', ('subject', 'ilike', self), ('body', 'ilike', self)]" /> <field name="type"/> <field name="author_id"/> + <filter icon="terp-personal+" string="Unread" + name="unread_message" help="Show unread message" + domain="[('unread', '=', True)]"/> <filter icon="terp-personal+" string="Comments" name="comments" help="Comments" domain="[('type', '=', 'comment')]"/> @@ -75,6 +78,7 @@ <field name="view_type">form</field> <field name="view_mode">tree,form</field> <field name="search_view_id" ref="view_message_search"/> + <field name="context">{'search_default_unread_message':True}</field> </record> <act_window domain="[('partner_id', '=', active_id), ('email_from', '!=', False)]" diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 497e5940791..6c3d6500e4e 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -298,7 +298,6 @@ display: none; } - /* ------------------------------------------------------------ */ /* mail.compose.message form view & OpenERP hacks /* ------------------------------------------------------------ */ @@ -403,15 +402,37 @@ } /* Dropdown menu */ -.openerp .oe_mail_msg_content .oe_dropdown_toggle { +/*.openerp .oe_mail_msg_content .oe_dropdown_toggle { position: absolute; top: 0px; right: 3px; +}*/ + +.openerp .oe_mail .oe_semantic_html_override { + position: relative; } -.openerp .oe_mail_msg_content .oe_dropdown_arrow:after { - border-top: 4px solid transparent; + +.openerp .oe_mail ul.oe_header { + position: absolute; + right: 3px; + top: -6px; + display: none; + z-index: 10; } -.openerp .oe_mail_msg_content:hover .oe_dropdown_arrow:after { + +.openerp .oe_mail ul.oe_header a { + text-decoration: none; +} + +.openerp .oe_mail .oe_semantic_html_override:hover ul.oe_header { + display: block; +} + +.openerp .oe_mail ul.oe_header>li { + display: inline-block; +} + +.openerp .oe_mail_msg_content .oe_dropdown_arrow:after { border-top: 4px solid #404040; } diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index f4ae9018df1..1eb91621186 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -269,6 +269,9 @@ openerp.mail = function(session) { default_model: 'mail.thread', default_res_id: 0, default_parent_id: false }, context || {}); + // wall for browse + this.mail_wall= options.mail_wall || this; + // options this.options = { message_ids: options.message_ids || null, @@ -283,10 +286,14 @@ openerp.mail = function(session) { show_dd_delete: options.show_dd_delete || false, show_dd_hide: options.show_dd_hide || false, truncate_limit: options.truncate_limit || 250, - mail_wall: options.mail_wall || this } + // datasets and internal vars + this.id= options.id || false; + this.model= options.model || false; this.records = {}; + this.thread = {}; + this.ds_thread = new session.web.DataSetSearch(this, this.context.default_model); this.ds_notification = new session.web.DataSetSearch(this, 'mail.notification'); this.ds_message = new session.web.DataSetSearch(this, 'mail.message'); @@ -337,10 +344,10 @@ openerp.mail = function(session) { var act_dom = $(this).parent().parent().parent().find('.oe_mail_msg_attachments'); act_dom.toggle(); }); + // event: click on icone 'Read' in header + this.$el.on('click', 'a.oe_read', this.on_message_read); // event: click on 'Delete' in msg side menu this.$el.on('click', 'a.oe_mail_msg_delete', this.on_message_delete); - // event: click on 'Hide' in msg side menu - this.$el.on('click', 'a.oe_mail_msg_hide', this.on_message_read); // event: click on 'Reply by email' in msg side menu this.$el.on('click', 'a.oe_mail_msg_reply_by_email', function (event) { if (! self.compose_message_widget) return true; @@ -363,12 +370,82 @@ openerp.mail = function(session) { return this.ds_message.unlink([parseInt(msg_id)]); }, + /*The selected thread and all childs (messages/thread) became read + * @param {object} mouse envent + */ on_message_read: function (event) { //TDE: TODO - var msg_id = event.srcElement.dataset.id; - if (! msg_id) return false; - $(event.srcElement).parents('li.oe_mail_thread_msg').eq(0).remove(); - return this.ds_notification.call('set_message_read', [parseInt(msg_id)]); + var source = $(event.srcElement).parents('[data-msg_id]:first'); + var msg_id = source.data("msg_id"); + var msg_model = source.data("msg_model"); + if (!msg_id || !msg_model) return false; + + var thread=this.browse_thread({'id':msg_id, 'model':msg_model}); + if(thread){ + thread.animated_destroy({fadeTime:250}); + + var ids = [thread.id] + // if this thread is read, all childs thread display is read + var ids = ids.concat( thread.get_child_thread_ids() ); + + thread.ds_notification.call('set_message_read', [ids]); + } + }, + + /* get all child message id liked to this message + */ + get_child_thread_ids: function(){ + var res=[]; + if(arguments[0]) res.push(this.id); + for(var i in this.thread){ + res = res.concat( this.thread[i].get_child_thread_ids(true) ); + } + return res; + }, + + /** browse thread and message + * @param {object}{int} option.id + * @param {object}{string} option.model + * @param {object}{boolean} option._go_thread_wall + * private for check the top thread + * @return thread object + */ + browse_thread: function(options){ + // goto the wall thread for launch browse + if(!options._go_thread_wall) { + options._go_thread_wall = true; + return this.mail_wall.browse_thread(options); + } + + if(this.id==options.id && this.model==options.model) + return this; + + options._go_thread_wall = true; + for(var i in this.thread){ + var res=this.thread[i].browse_thread(options); + if(res) return res; + } + + return false; + }, + + animated_destroy: function(options) { + var self=this; + //graphic effects + if(options.fadeTime) + self.$el.parents(".oe_mail_thread_msg:first").fadeOut(options.fadeTime, function(){ + self.destroy(); + }); + else + self.destroy(); + + for(var i in this.thread){ + this.thread[i].animated_destroy({fadeTime:0}); + } + }, + + console: function(){ + console.log(arguments); }, on_vote: function (event) { @@ -419,7 +496,7 @@ openerp.mail = function(session) { /** Clean the thread */ message_clean: function() { - this.$('div.oe_mail_thread_display').empty(); + this.$('ul.oe_mail_thread_display').empty(); }, /** Fetch messages @@ -454,15 +531,17 @@ openerp.mail = function(session) { self.fetch_more_domain = record.domain; self.fetch_more_context = record.context; var rendered = session.web.qweb.render('mail.thread.message.expandable', {'record': record}); - $(rendered).appendTo(self.$el.children('div.oe_mail_thread_display:first')); + $(rendered).appendTo(self.$el.children('ul.oe_mail_thread_display:first')); } else { self.display_record(record); - self.thread = new mail.Thread(self, self.domain, + var thread = new mail.Thread(self, self.domain, { 'default_model': record.model, 'default_res_id': record.res_id, 'default_parent_id': record.id }, - { 'message_data': record.child_ids, + { 'model': record.model, + 'id': record.id, + 'message_data': record.child_ids, 'thread_level': self.options.thread_level - 1, 'show_header_compose': false, 'show_reply': self.options.show_reply && self.options.thread_level > 1, @@ -470,8 +549,11 @@ openerp.mail = function(session) { 'show_dd_hide': self.options.show_dd_hide, 'show_dd_delete': self.options.show_dd_delete, 'mail_wall': self.options.mail_wall }); - self.$('li.oe_mail_thread_msg:last').append('<div class="oe_mail_thread_subthread" data-msg_id="'+record.res_id+'"/>'); - self.thread.appendTo(self.$('div.oe_mail_thread_subthread:last')); + + self.$('li.oe_mail_thread_msg:last').append('<div class="oe_mail_thread_subthread"/>'); + thread.appendTo(self.$('div.oe_mail_thread_subthread:last')); + + self.thread[record.model+":"+record.id]=thread; } }); }, @@ -483,6 +565,7 @@ openerp.mail = function(session) { * - record.attachment_ids[].url: url of each attachment */ display_record: function (record) { // formatting and additional fields + record.timestamp = Date.parse(record.date).getTime(); record.date = session.web.format_value(record.date, {type:"datetime"}); record.timerelative = $.timeago(record.date); if (record.type == 'email') { @@ -498,7 +581,24 @@ openerp.mail = function(session) { this.records[record.id] = record; // render, add the expand feature var rendered = session.web.qweb.render('mail.thread.message', {'record': record, 'thread': this, 'options': this.options}); - $(rendered).appendTo(this.$el.children('div.oe_mail_thread_display:first')); + + // check older and newer message for insert + var parent_newer = false; + var parent_older = false; + this.$('ul.oe_mail_thread_display:first > li').each(function(){ + var timestamp=$(this).data("msg_timestamp"); + if(timestamp > record.timestamp){ + if(!parent_newer || parent_newer>timestamp) parent_newer = timestamp; + } else if(!parent_older || parent_older<timestamp) parent_older = timestamp; + }); + + if(parent_newer) + $(rendered).insertAfter(this.$('ul.oe_mail_thread_display:first > li[data-msg_timestamp='+parent_newer+']')); + else if(parent_older) + $(rendered).insertBefore(this.$('ul.oe_mail_thread_display:first > li[data-msg_timestamp='+parent_older+']')); + else + $(rendered).appendTo(this.$('ul.oe_mail_thread_display:first')); + this.$('div.oe_mail_msg_body').expander({ slicePoint: this.options.truncate_limit, expandText: 'read more', @@ -537,21 +637,12 @@ openerp.mail = function(session) { var self=this; _(records).each(function (record) { - if( !self.options.mail_wall.$('.oe_mail_thread_msg[data-msg_id="'+record.id+'"]').size() ) { + if( !self.mail_wall.$('.oe_mail_thread_msg[data-msg_id="'+record.id+'"]').size() ) { self.display_record( record ); } }); }, - search_thread: function() { - - }, - - animated_destroy: function(animated) { - //graphic effects - this.destroy(); - }, - /*post a message and flatch the message*/ message_post: function (body) { var self = this; @@ -705,11 +796,15 @@ openerp.mail = function(session) { return self.message_render(); }); }, - - search_thread: function(id) { - var self=this; - /*this.thread*/ + /** browse thread and message + * @param {int} id + * @param {string} model + * @return thread object + */ + browse_thread: function(options){ + options._go_thread_wall = true; + return this.thread.browse_thread(options); }, /** Clean and display the threads */ @@ -724,10 +819,10 @@ openerp.mail = function(session) { 'use_composer': true, 'show_reply': this.options.thread_level > 0, 'show_dd_hide': true, - 'mail_wall': self + 'mail_wall': this } ); - return this.thread.appendTo(this.$('li.oe_mail_wall_thread:last')); + return this.thread.appendTo( this.$('li.oe_mail_wall_thread:last') ); }, }); }; diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 49ca8ac03ba..f888d9ea19f 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -93,38 +93,50 @@ container, holding the composition form. Then come the various messages. Then comes the 'more' button. --> - <ul t-name="mail.thread" class="oe_mail oe_mail_thread oe_semantic_html_override"> + <div t-name="mail.thread" class="oe_mail oe_mail_thread oe_semantic_html_override"> <div class="oe_mail_thread_action"> <!-- contains the composition box (form + image) --> <t t-call="mail.compose_message"/> </div> - <div class="oe_mail_thread_display"> + <ul class="oe_mail_thread_display"> <!-- contains the threads --> - </div> -<!-- <div class="oe_mail_thread_more"> + </ul> + <div class="oe_mail_thread_more"> <button class="oe_mail_button_more" type="button">Load more messages</button> - </div> --> - </ul> + </div> + </div> <!-- default layout --> - <li t-name="mail.thread.message" class="oe_mail oe_mail_thread_msg" t-attf-data-msg_id="{record.id}"> + <li t-name="mail.thread.message" class="oe_mail oe_mail_thread_msg" t-attf-data-msg_model="{record.model}" t-attf-data-msg_id="{record.id}" t-attf-data-msg_timestamp="{record.timestamp}"> <div t-attf-class="oe_mail_msg_#{record.type} oe_semantic_html_override"> + + <!-- message actions (read/unread, reply, delete...) --> + <ul class="oe_header"> + <li t-if="options.thread_level>0"><a class="oe_read oe_e">W<!-- Read/Unread --></a></li> + <li t-if="options.show_reply"><a class="oe_mail_msg_reply oe_e">)</a></li> + <li t-if="options.show_reply_by_email"><a class="oe_mail_msg_reply_by_email oe_e">)</a></li> + <li> + <span class="oe_dropdown_toggle"> + <a class="oe_e">é</a> + <ul class="oe_dropdown_menu"> + <li t-if="record.is_author and options.show_dd_delete"><a class="oe_mail_msg_delete">Delete</a></li> + <!-- Uncomment when adding subtype hiding + <li t-if="display['show_hide']"> + <a href="#" class="oe_mail_msg_hide_type" t-attf-data-subtype='{record.subtype}'>Hide '<t t-esc="record.subtype"/>' for this document</a> + </li> --> + <li t-if="options.show_dd_reply_by_email"><a class="oe_mail_msg_reply_by_email">Quote and reply</a></li> + <li t-if="record.type == 'email'"><a class="oe_mail_msg_details" t-attf-href="#model=mail.message&id=#{record.id}" >Details</a></li> + </ul> + </span> + </li> + </ul> + <img class="oe_mail_icon oe_mail_frame oe_left" t-att-src="record.avatar"/> + <div class="oe_mail_msg_content"> <!-- dropdown menu with message options and actions --> <span class="placeholder-mail-thread-message-vote"/> - <span class="oe_dropdown_toggle oe_dropdown_arrow"> - <ul class="oe_dropdown_menu"> - <li t-if="record.is_author and options.show_dd_delete"><a class="oe_mail_msg_delete" t-attf-data-id='{record.id}'>Delete</a></li> - <li t-if="options.show_dd_hide"><a class="oe_mail_msg_hide" t-attf-data-id='{record.id}'>Remove notification</a></li> -<!-- Uncomment when adding subtype hiding - <li t-if="display['show_hide']"> - <a href="#" class="oe_mail_msg_hide_type" t-attf-data-subtype='{record.subtype}'>Hide '<t t-esc="record.subtype"/>' for this document</a> - </li> --> - <li t-if="options.show_dd_reply_by_email"><a class="oe_mail_msg_reply_by_email" t-attf-data-msg_id="{record.id}">Quote and reply</a></li> - <li t-if="record.type == 'email'"><a class="oe_mail_msg_details" t-attf-href="#model=mail.message&id=#{record.id}" >Details</a></li> - </ul> - </span> + <!-- message itself --> <div class="oe_mail_msg"> <h1 t-if="record.subject" class="oe_mail_msg_title"> @@ -144,8 +156,6 @@ <li t-if="record.author_id"><a t-attf-href="#model=res.partner&id=#{record.author_id[0]}"><t t-raw="record.author_id[1]"/></a></li> <li><span t-att-title="record.date"><t t-raw="record.timerelative"/></span></li> <t t-call="mail.thread.message.vote"/> - <li t-if="options.show_reply"><a class="oe_mail_msg_reply">Reply</a></li> - <li t-if="options.show_reply_by_email"><a class="oe_mail_msg_reply_by_email" t-attf-data-msg_id="{record.id}">Reply</a></li> <li t-if="record.attachment_ids.length > 0"> <a class="oe_mail_msg_view_attachments"> <t t-if="record.attachment_ids.length == 1">1 Attachment</t> |
