summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Matthieu <chm@openerp.com>2012-09-27 10:30:56 +0200
committerChristophe Matthieu <chm@openerp.com>2012-09-27 10:30:56 +0200
commitbc85a60e8efa2dbc98eb9acc3e2109a2e5ceae16 (patch)
treee5f292f10b14e89662074784f1a704ce22d219ee
parent4ddb50dbf920a02bbb6f1c210a1215abd8a0b428 (diff)
[IMP] mail: read/unread with propagation; browse_thread on js
bzr revid: chm@openerp.com-20120927083056-o8s4h0pehsjdzw5j
-rw-r--r--addons/mail/mail_followers.py8
-rw-r--r--addons/mail/mail_message_view.xml4
-rw-r--r--addons/mail/static/src/css/mail.css31
-rw-r--r--addons/mail/static/src/js/mail.js155
-rw-r--r--addons/mail/static/src/xml/mail.xml52
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&amp;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&amp;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&amp;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>