[IMP] mail: read/unread with propagation; browse_thread on js

bzr revid: chm@openerp.com-20120927083056-o8s4h0pehsjdzw5j
This commit is contained in:
Christophe Matthieu 2012-09-27 10:30:56 +02:00
parent 4ddb50dbf9
commit bc85a60e8e
5 changed files with 192 additions and 58 deletions

View File

@ -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):

View File

@ -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)]"

View File

@ -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 ul.oe_header {
position: absolute;
right: 3px;
top: -6px;
display: none;
z-index: 10;
}
.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 transparent;
}
.openerp .oe_mail_msg_content:hover .oe_dropdown_arrow:after {
border-top: 4px solid #404040;
}

View File

@ -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') );
},
});
};

View File

@ -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>