summaryrefslogtreecommitdiff
path: root/addons/mail/static/src
diff options
context:
space:
mode:
authorRandhir Mayatra (OpenERP) <rma@tinyerp.com>2012-11-19 16:38:24 +0530
committerRandhir Mayatra (OpenERP) <rma@tinyerp.com>2012-11-19 16:38:24 +0530
commitd23c5c8dca985dd0fde280c9237dee85b7bb4d7a (patch)
treecf03bc2a74a1d9e93b5ef571fb78070c09c9857b /addons/mail/static/src
parentf4ab81afb8285a8157258232c5fb2a6745ae7f72 (diff)
parent66afff1b52b7ab6ab8c340e18960fb6367cfb714 (diff)
[MERGE]merge with trunk
bzr revid: rma@tinyerp.com-20121119110824-rj4y32rfbszqln7g
Diffstat (limited to 'addons/mail/static/src')
-rw-r--r--addons/mail/static/src/css/mail.css276
-rw-r--r--addons/mail/static/src/css/mail_group.css34
-rw-r--r--addons/mail/static/src/img/mimetypes/addresses.pngbin0 -> 3151 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/archive.pngbin0 -> 2450 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/audio.pngbin0 -> 2290 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/binary.pngbin0 -> 3060 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/calendar.pngbin0 -> 2848 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/certificate.pngbin0 -> 1643 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/disk.pngbin0 -> 3997 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/document.pngbin0 -> 2625 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/font.pngbin0 -> 3894 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/html.pngbin0 -> 3347 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/image.pngbin0 -> 2603 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/presentation.pngbin0 -> 2260 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/print.pngbin0 -> 2625 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/script.pngbin0 -> 3025 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/spreadsheet.pngbin0 -> 2693 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/text.pngbin0 -> 2086 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/unknown.pngbin0 -> 2086 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/vector.pngbin0 -> 2865 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/video.pngbin0 -> 4665 bytes
-rw-r--r--addons/mail/static/src/img/mimetypes/webimage.pngbin0 -> 2603 bytes
-rw-r--r--addons/mail/static/src/js/mail.js1155
-rw-r--r--addons/mail/static/src/js/mail_followers.js21
-rw-r--r--addons/mail/static/src/xml/mail.xml109
25 files changed, 917 insertions, 678 deletions
diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css
index af3cc3ed359..b0ce6d499b5 100644
--- a/addons/mail/static/src/css/mail.css
+++ b/addons/mail/static/src/css/mail.css
@@ -1,7 +1,36 @@
+/* ------------ TOPBAR MAIL BUTTON --------------- */
+
+/* FIXME this css is not very pretty because it uses a
+ * 'button' element wich comes with a lot of inappropriate
+ * styling. Entypo is also a headache to center properly
+ * */
+
+.openerp .oe_topbar_item.oe_topbar_compose_full_email{
+ padding: 0px;
+ width: 32px;
+ height: 32px;
+}
+.openerp .oe_topbar_item.oe_topbar_compose_full_email button{
+ position: relative;
+ top: -3px; /* centering entypo ... urgh */
+ box-sizing: border-box;
+ border: none;
+ box-shadow: none;
+ color: white;
+ background: none;
+ text-shadow: 0px 1px 2px black;
+ width: 32px;
+ height: 32px;
+ padding: 0px;
+ margin: 0px
+ border-radius: 0px;
+}
/* ------------ MAIL WIDGET --------------- */
.openerp .oe_mail, .openerp .oe_mail *{
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.openerp .oe_mail {
display: block;
@@ -42,9 +71,10 @@
}
.openerp .oe_mail .oe_msg .oe_msg_footer{
padding-left: 4px;
+ padding-top: 3px;
overflow: hidden;
- opacity:0.8;
- -webkit-transition: opacity 0.2s linear;
+ margin-bottom: 4px;
+ font-size: 11px;
}
.openerp .oe_mail .oe_msg .oe_msg_content{
display: block;
@@ -57,6 +87,13 @@
margin-bottom: 0px;
margin-top: 2px;
}
+.openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body p:first-of-type {
+ margin-top: 0px;
+}
+
+.openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body p {
+ margin-bottom: 0px;
+}
/* a) Indented Messages */
@@ -80,18 +117,24 @@
.openerp .oe_mail .oe_msg.oe_msg_indented .oe_msg_content{
padding-top:2px;
}
+.openerp .oe_mail .oe_msg.oe_msg_indented .oe_msg_footer{
+ margin-bottom: 5px;
+}
+
/* b) Votes (likes) */
+
.openerp .oe_mail .oe_mail_vote_count{
display: inline;
position: relative;
- background: #7C7BAD;
- color: white;
+ background: white;
+ box-shadow: 0px 0px 0px 1px rgba(124, 123, 173, 0.36) inset;
+ color: #7c7bad;
text-shadow: none;
border-radius: 3px;
margin: 0px;
padding-left: 3px;
- padding-right: 18px;
- margin-right: 3px;
+ padding-right: 15px;
+ margin-right: 5px;
}
.openerp .oe_mail .oe_mail_vote_count .oe_e{
position: absolute;
@@ -102,12 +145,6 @@
/* c) Message action icons */
-.openerp .oe_mail .oe_msg.oe_msg_unread .oe_unread{
- display:none;
-}
-.openerp .oe_mail .oe_msg.oe_msg_read .oe_read{
- display:none;
-}
.openerp .oe_mail .oe_msg .oe_msg_icons{
float: right;
margin-top: 4px;
@@ -115,6 +152,9 @@
margin-left: 8px;
height: 24px;
-webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
}
.openerp .oe_mail .oe_msg .oe_msg_icons span{
float:right;
@@ -128,10 +168,16 @@
color: #FFF;
text-shadow: 0px 1px #AAA,0px -1px #AAA, -1px 0px #AAA, 1px 0px #AAA, 0px 3px 3px rgba(0,0,0,0.1);
-webkit-transition: all 0.2s linear;
+ -moz-transition: all 0.2s linear;
+ -o-transition: all 0.2s linear;
+ transition: all 0.2s linear;
}
.openerp .oe_mail .oe_msg:hover .oe_msg_icons a{
opacity: 1;
-webkit-transition: all 0.1s linear;
+ -moz-transition: all 0.1s linear;
+ -o-transition: all 0.1s linear;
+ transition: all 0.1s linear;
}
.openerp .oe_mail .oe_msg .oe_msg_icons .oe_star:hover a{
color: #FFF6C0;
@@ -155,7 +201,7 @@
}
.openerp .oe_mail .oe_msg .oe_msg_content textarea{
width: 100%;
- height: 32px;
+ height: 64px;
margin: 0px;
padding: 0px;
resize: vertical;
@@ -171,43 +217,156 @@
width: 100%;
}
-/* ---------------- MESSAGE QUICK COMPOSER --------------- */
+/* --------------------- ATTACHMENTS --------------------- */
-.openerp .oe_mail .oe_msg_composer .oe_msg_footer{
- padding-right:4px;
- padding-top: 2px;
- padding-bottom:6px;
+.openerp .oe_mail .oe_msg_attachment_list{
+ display: none;
+ margin-top: 12px;
+ margin-bottom: 12px;
}
-.openerp .oe_mail .oe_msg_attachments.oe_hidden,
-.openerp .oe_mail .oe_msg_images.oe_hidden{
- margin:0px;
- border: none;
+.openerp .oe_mail .oe_msg_composer .oe_msg_attachment_list{
+ display: block;
+}
+.openerp .oe_mail .oe_attachment{
+ display: inline-block;
+ width: 100px;
+ margin: 2px;
+ min-height: 80px;
+ position: relative;
+ border-radius: 3px;
+ text-align: center;
+ vertical-align: top;
+}
+.openerp .oe_mail .oe_attachment .oe_name{
+ display: inline-block;
+ max-width: 100%;
+ padding: 1px 3px;
+ margin-top: 50px;
+ margin-bottom: 5px;
+ background: rgba(124, 123, 173, 0.13);
+ overflow: hidden;
+ color: #4c4c4c;
+ text-shadow: none;
+ border-radius: 3px;
+}
+
+.openerp .oe_mail .oe_attachment.oe_preview{
+ background: url( data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAJ0lEQVQYV2MsLS39z4AGLCws0IUYGIeCwrVr12J45sSJE5ieGQIKAbuZKf/EMCs7AAAAAElFTkSuQmCC );
+}
+.openerp .oe_mail .oe_attachment .oe_progress_bar{
display: none;
+ position: absolute;
+ top: 18px;
+ left: 16px;
+ right: 16px;
+ height: 17px;
+ line-height: 13px;
+ padding: 0px;
+ background: #4BBD00;
+ color: white;
+ text-align: center;
+ border-radius: 3px;
+ border: solid 1px rgba(0,0,0,0.2);
+ box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.34);
+ -webkit-animation: oe_mail_attach_loading_anim 0.75s infinite linear;
+ -moz-animation: oe_mail_attach_loading_anim 0.75s infinite linear;
+ -o-animation: oe_mail_attach_loading_anim 0.75s infinite linear;
+ animation: oe_mail_attach_loading_anim 0.75s infinite linear;
+}
+.openerp .oe_mail .oe_attachment.oe_uploading .oe_progress_bar{
+ display: block;
}
-.openerp .oe_mail .oe_msg_attachments{
- margin-bottom: 4px;
- margin-right: 0px;
- font-size: 12px;
- border-radius: 2px;
- border: solid 1px rgba(124,123,173,0.14);
+@-webkit-keyframes oe_mail_attach_loading_anim{
+ 0% { background: #4BBD00 }
+ 50% { background: #009123 }
+ 100% { background: #4BBD00 }
}
-.openerp .oe_mail .oe_msg_attachments .oe_attachment{
- padding: 2px;
- padding-left: 4px;
- padding-right: 4px;
+@-moz-keyframes oe_mail_attach_loading_anim{
+ 0% { background: #4BBD00 }
+ 50% { background: #009123 }
+ 100% { background: #4BBD00 }
}
-.openerp .oe_mail .oe_msg_attachments .oe_attachment .oe_e{
- font-size: 23px;
- margin-top: -5px;
+@-o-keyframes oe_mail_attach_loading_anim{
+ 0% { background: #4BBD00 }
+ 50% { background: #009123 }
+ 100% { background: #4BBD00 }
}
-.openerp .oe_mail .oe_msg_attachments .oe_attachment .oe_e:hover{
- text-decoration: none;
+@keyframes oe_mail_attach_loading_anim{
+ 0% { background: #4BBD00 }
+ 50% { background: #009123 }
+ 100% { background: #4BBD00 }
}
-.openerp .oe_mail .oe_msg_attachments .oe_attachment:nth-child(odd){
- background:white;
+.openerp .oe_mail .oe_attachment.oe_preview .oe_name{
+ position: absolute;
+ bottom: 0px;
+ margin: 0px;
+ left: 0px;
+ right: 0px;
+ max-height: 64px;
+ background: rgba(0,0,0,0.8);
+ color: white;
+ border-top-left-radius: 0px;
+ border-top-right-radius: 0px;
+ opacity: 0;
+ -webkit-transition: opacity 0.2s linear;
+ -moz-transition: opacity 0.2s linear;
+ -o-transition: opacity 0.2s linear;
+ transition: opacity 0.2s linear;
+}
+.openerp .oe_mail .oe_attachment.oe_preview:hover .oe_name{
+ opacity: 1;
+ -webkit-transition: opacity 0.2s linear;
+ -moz-transition: opacity 0.2s linear;
+ -o-transition: opacity 0.2s linear;
+ transition: opacity 0.2s linear;
}
-.openerp .oe_mail .oe_msg_attachments .oe_attachment:nth-child(even){
- background: #F4F5FA;
+.openerp .oe_mail .oe_attachment img{
+ position: absolute;
+ width: 48px;
+ height: 48px;
+ top: 0px;
+ left: 50%;
+ margin-left: -24px;
+}
+.openerp .oe_mail .oe_attachment.oe_preview img{
+ display: block;
+ position: relative;
+ margin:0px;
+ width: 100px;
+ height: 100px;
+ border-radius: 3px;
+ margin-left: -50px;
+}
+.openerp .oe_mail .oe_attachment .oe_delete{
+ display: none;
+}
+.openerp .oe_mail .oe_msg_composer .oe_attachment .oe_delete{
+ display: block;
+ position: absolute;
+ top: -7px;
+ right: 0px;
+ color: black;
+ text-shadow: 1px 0px white, -1px 0px white, 0px 1px white, 0px -1px white;
+ cursor: pointer;
+ opacity: 0;
+ -webkit-transition: opacity 0.2s linear;
+ -moz-transition: opacity 0.2s linear;
+ -o-transition: opacity 0.2s linear;
+ transition: opacity 0.2s linear;
+}
+.openerp .oe_mail .oe_msg_composer .oe_attachment:hover .oe_delete{
+ opacity: 1;
+ -webkit-transition: opacity 0.2s linear;
+ -moz-transition: opacity 0.2s linear;
+ -o-transition: opacity 0.2s linear;
+ transition: opacity 0.2s linear;
+}
+/* ---------------- MESSAGE QUICK COMPOSER --------------- */
+
+.openerp .oe_mail .oe_msg_composer .oe_msg_footer{
+ padding-right:4px;
+ padding-top: 2px;
+ padding-bottom:6px;
}
.openerp .oe_mail .oe_msg_images {
display: block;
@@ -222,11 +381,13 @@
.openerp .oe_mail .oe_msg_footer button.oe_attach{
width: 24px;
overflow: hidden;
+ filter:none;
}
.openerp .oe_mail .oe_msg_footer button.oe_attach .oe_e{
position: relative;
top: -1px;
left: -9px;
+ filter:none;
}
.openerp .oe_mail .oe_hidden_input_file, .openerp .oe_mail .oe_hidden_input_file form{
display:inline;
@@ -235,11 +396,13 @@
width:24px;
overflow:hidden;
float: right;
+ filter:none;
}
.openerp .oe_mail .oe_msg_footer button.oe_full .oe_e{
position: relative;
top: -1px;
left: -9px;
+ filter:none;
}
.openerp .oe_mail button.oe_attach, .openerp .oe_mail button.oe_full{
background: transparent;
@@ -247,6 +410,7 @@
box-shadow: none;
border: none;
text-shadow: none;
+ filter:none;
}
.openerp .oe_mail .oe_attach_label{
color: #7C7BAD;
@@ -258,6 +422,7 @@
height: 28px;
width: 52px;
margin-top: -6px;
+ filter:none;
}
.openerp .oe_mail .oe_mail_list_recipients{
font-size: 12px;
@@ -269,6 +434,7 @@
.openerp .oe_mail .oe_msg_content.oe_msg_more_message{
text-align: right;
+ cursor: pointer;
}
.openerp .oe_mail .oe_msg_content.oe_msg_more_message .oe_separator{
height: 0;
@@ -280,7 +446,7 @@
}
.openerp .oe_mail .oe_msg_more_message .oe_msg_fetch_more {
background: white;
- margin-right: 280px;
+ margin-right: 210px;
padding-left: 8px;
padding-right: 8px;
text-decoration: none;
@@ -298,6 +464,7 @@
padding-top: 5px;
width: 160px;
float: right;
+ margin-right: 16px;
}
/* a) THE FOLLOW BUTTON */
@@ -308,9 +475,23 @@
width:100%;
}
.openerp .oe_followers button.oe_follower.oe_following{
+ color: white;
background-color: #3465A4;
background-image: -webkit-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -moz-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -ms-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -o-linear-gradient(top, #729FCF, #3465A4);
+ background-image: linear-gradient(to bottom, #729FCF, #3465A4);
+}
+.openerp .oe_followers button.oe_follower.oe_following:hover{
color: white;
+ filter:none;
+ background-color: #A21A1A;
+ background-image: -webkit-linear-gradient(top, #DF3F3F, #A21A1A);
+ background-image: -moz-linear-gradient(top, #DF3F3F, #A21A1A);
+ background-image: -ms-linear-gradient(top, #DF3F3F, #A21A1A);
+ background-image: -o-linear-gradient(top, #DF3F3F, #A21A1A);
+ background-image: linear-gradient(to bottom, #DF3F3F, #A21A1A);
}
.openerp .oe_followers button.oe_follower .oe_follow,
@@ -371,12 +552,17 @@
.openerp .oe_record_thread{
display: block;
- margin-right: 180px;
+ margin-left: 16px;
+ margin-right: 212px;
}
/* ----------- INBOX INTEGRATION ----------- */
.openerp .oe_mail_wall .oe_mail{
margin: 16px;
- width: 720px;
+ width: 600px;
+}
+
+.openerp .oe_mail .oe_view_nocontent > p {
+ padding-left: 15px;
}
diff --git a/addons/mail/static/src/css/mail_group.css b/addons/mail/static/src/css/mail_group.css
index b700cb8c80f..c1cefee9070 100644
--- a/addons/mail/static/src/css/mail_group.css
+++ b/addons/mail/static/src/css/mail_group.css
@@ -44,20 +44,23 @@
text-align: center;
overflow: hidden;
-moz-border-radius: 3px;
+ border-collapse: separate;
-webkit-border-radius: 3px;
-o-border-radius: 3px;
-ms-border-radius: 3px;
border-radius: 3px;
+ border-collapse: separate;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
-o-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
- -box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}
.oe_group_photo {
width: 100px;
height: 100px;
clip: rect(0px, 100px, 100px, 0px);
+ border:none;
}
.oe_group_details {
@@ -68,30 +71,31 @@
min-height: 120px;
}
-.oe_group_details a, .oe_group_details a:hover {
- font-weight: bold;
- color: #4c4c4c;
-}
-
.oe_group_details h4 {
margin: 0;
font-size: 13px;
}
-.oe_group_details h4 a {
- color: #4c4c4c;
-}
-
-.oe_group_details h4 a:hover {
- text-decoration: underline;
-}
-
.oe_group_details ul {
margin: 3px 0 5px;
padding: 0;
list-style: none;
}
-.oe_group_details li {
+.openerp .oe_group_details li {
margin: 2px 0;
}
+
+.openerp .oe_group_button {
+ padding-top: 7px;
+}
+
+.openerp .oe_group_button .oe_group_join {
+ color: white;
+ background-color: #3465A4;
+ background-image: -webkit-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -moz-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -ms-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -o-linear-gradient(top, #729FCF, #3465A4);
+ background-image: linear-gradient(to bottom, #729FCF, #3465A4);
+}
diff --git a/addons/mail/static/src/img/mimetypes/addresses.png b/addons/mail/static/src/img/mimetypes/addresses.png
new file mode 100644
index 00000000000..586f1257196
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/addresses.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/archive.png b/addons/mail/static/src/img/mimetypes/archive.png
new file mode 100644
index 00000000000..704d962d426
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/archive.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/audio.png b/addons/mail/static/src/img/mimetypes/audio.png
new file mode 100644
index 00000000000..6dd4c635fe7
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/audio.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/binary.png b/addons/mail/static/src/img/mimetypes/binary.png
new file mode 100644
index 00000000000..5708c9fc2a5
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/binary.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/calendar.png b/addons/mail/static/src/img/mimetypes/calendar.png
new file mode 100644
index 00000000000..81791af05e0
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/calendar.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/certificate.png b/addons/mail/static/src/img/mimetypes/certificate.png
new file mode 100644
index 00000000000..e48cb1de432
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/certificate.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/disk.png b/addons/mail/static/src/img/mimetypes/disk.png
new file mode 100644
index 00000000000..9c241cdf896
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/disk.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/document.png b/addons/mail/static/src/img/mimetypes/document.png
new file mode 100644
index 00000000000..fee2f1619b6
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/document.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/font.png b/addons/mail/static/src/img/mimetypes/font.png
new file mode 100644
index 00000000000..3b04787b9f9
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/font.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/html.png b/addons/mail/static/src/img/mimetypes/html.png
new file mode 100644
index 00000000000..440c5bc9972
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/html.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/image.png b/addons/mail/static/src/img/mimetypes/image.png
new file mode 100644
index 00000000000..ab2f84a1a54
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/image.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/presentation.png b/addons/mail/static/src/img/mimetypes/presentation.png
new file mode 100644
index 00000000000..8642a8e9298
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/presentation.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/print.png b/addons/mail/static/src/img/mimetypes/print.png
new file mode 100644
index 00000000000..fee2f1619b6
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/print.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/script.png b/addons/mail/static/src/img/mimetypes/script.png
new file mode 100644
index 00000000000..10c58c0bcc3
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/script.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/spreadsheet.png b/addons/mail/static/src/img/mimetypes/spreadsheet.png
new file mode 100644
index 00000000000..77a834697f1
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/spreadsheet.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/text.png b/addons/mail/static/src/img/mimetypes/text.png
new file mode 100644
index 00000000000..e65d2ec5a67
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/text.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/unknown.png b/addons/mail/static/src/img/mimetypes/unknown.png
new file mode 100644
index 00000000000..e65d2ec5a67
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/unknown.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/vector.png b/addons/mail/static/src/img/mimetypes/vector.png
new file mode 100644
index 00000000000..c4595ec1b24
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/vector.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/video.png b/addons/mail/static/src/img/mimetypes/video.png
new file mode 100644
index 00000000000..e3a87b5bde6
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/video.png
Binary files differ
diff --git a/addons/mail/static/src/img/mimetypes/webimage.png b/addons/mail/static/src/img/mimetypes/webimage.png
new file mode 100644
index 00000000000..ab2f84a1a54
--- /dev/null
+++ b/addons/mail/static/src/img/mimetypes/webimage.png
Binary files differ
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js
index 7acebe9b1df..dc265a343d5 100644
--- a/addons/mail/static/src/js/mail.js
+++ b/addons/mail/static/src/js/mail.js
@@ -24,9 +24,10 @@ openerp.mail = function (session) {
*/
var context_keys = ['default_template_id', 'default_composition_mode',
'default_use_template', 'default_partner_ids', 'default_model',
- 'default_res_id', 'default_content_subtype', , 'default_subject',
+ 'default_res_id', 'default_content_subtype', 'default_subject',
'default_body', 'active_id', 'lang', 'bin_raw', 'tz',
- 'active_model', 'edi_web_url_view', 'active_ids']
+ 'active_model', 'edi_web_url_view', 'active_ids',
+ 'default_attachment_ids']
for (var key in action.context) {
if (_.indexOf(context_keys, key) == -1) {
action.context[key] = null;
@@ -54,13 +55,15 @@ openerp.mail = function (session) {
mail.ChatterUtils = {
/* Get an image in /web/binary/image?... */
- get_image: function (session, model, field, id) {
- return session.prefix + '/web/binary/image?session_id=' + session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || '');
+ get_image: function (session, model, field, id, resize) {
+ var r = resize ? encodeURIComponent(resize) : '';
+ id = id || '';
+ return session.url('/web/binary/image', {model: model, field: field, id: id, resize: r});
},
/* Get the url of an attachment {'id': id} */
get_attachment_url: function (session, attachment) {
- return session.origin + '/web/binary/saveas?session_id=' + session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id=' + attachment['id'];
+ return session.url('/web/binary/saveas', {model: 'ir.attachment', field: 'datas', filename_field: 'datas_fname', id: attachment['id']});
},
/**
@@ -111,12 +114,267 @@ openerp.mail = function (session) {
}
return domain;
- }
+ },
+
+ // inserts zero width space between each letter of a string so that
+ // the word will correctly wrap in html boxes smaller than the text
+ breakword: function(str){
+ var out = '';
+ if (!str) {
+ return str;
+ }
+ for(var i = 0, len = str.length; i < len; i++){
+ out += _.str.escapeHTML(str[i]) + '&#8203;';
+ }
+ 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){
+ url = url.filename || url;
+ var tokens = 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';
+ },
+
};
/**
* ------------------------------------------------------------
+ * MessageCommon
+ * ------------------------------------------------------------
+ *
+ * Common base for expandables, chatter messages and composer. It manages
+ * the various variables common to those models.
+ */
+
+ mail.MessageCommon = session.web.Widget.extend({
+
+ /**
+ * ------------------------------------------------------------
+ * FIXME: this comment was moved as is from the ThreadMessage Init as
+ * part of a refactoring. Check that it is still correct
+ * ------------------------------------------------------------
+ * This widget handles the display of a messages in a thread.
+ * Displays a record and performs some formatting on the record :
+ * - record.date: formatting according to the user timezone
+ * - record.timerelative: relative time givein by timeago lib
+ * - record.avatar: image url
+ * - record.attachment_ids[].url: url of each attachmentThe
+ * thread view :
+ * - root thread
+ * - - sub message (parent_id = root message)
+ * - - - sub thread
+ * - - - - sub sub message (parent id = sub thread)
+ * - - sub message (parent_id = root message)
+ * - - - sub thread
+ */
+
+ init: function (parent, datasets, options) {
+ this._super(parent, options);
+
+ // record options
+ this.options = datasets.options || options || {};
+ // record domain and context
+ this.domain = datasets.domain || options.domain || [];
+ this.context = _.extend({
+ default_model: false,
+ default_res_id: 0,
+ default_parent_id: false }, options.context || {});
+
+ // data of this message
+ this.id = datasets.id || false,
+ this.last_id = this.id,
+ this.model = datasets.model || this.context.default_model || false,
+ 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.is_author = datasets.is_author || 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 || false,
+ this.vote_nb = datasets.vote_nb || 0,
+ this.has_voted = datasets.has_voted || false,
+ this.is_favorite = datasets.is_favorite || false,
+ this.thread_level = datasets.thread_level || 0,
+ this.to_read = datasets.to_read || false,
+ this.author_id = datasets.author_id || false,
+ this.attachment_ids = datasets.attachment_ids || [],
+ this.partner_ids = datasets.partner_ids || [];
+ this._date = datasets.date;
+
+ this.format_data();
+
+ // record options and data
+ this.show_record_name = this.record_name && !this.thread_level && this.model != 'res.partner';
+ this.options.show_read = false;
+ this.options.show_unread = false;
+ if (this.options.show_read_unread_button) {
+ if (this.options.read_action == 'read') this.options.show_read = true;
+ else if (this.options.read_action == 'unread') this.options.show_unread = true;
+ else {
+ this.options.show_read = this.to_read;
+ this.options.show_unread = !this.to_read;
+ this.options.rerender = true;
+ this.options.toggle_read = true;
+ }
+ }
+ this.parent_thread = parent.messages != undefined ? parent : this.options.root_thread;
+ this.thread = false;
+ },
+
+ /* Convert date, timerelative and avatar in displayable data. */
+ format_data: function () {
+
+ //formating and add some fields for render
+ if (this._date) {
+ this.date = session.web.format_value(this._date, {type:"datetime"});
+ this.timerelative = $.timeago(this.date);
+ }
+ 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]);
+ } else {
+ this.avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid);
+ }
+
+ },
+
+
+ /* upload the file on the server, add in the attachments list and reload display
+ */
+ display_attachments: function () {
+ for (var l in this.attachment_ids) {
+ var attach = this.attachment_ids[l];
+ if (!attach.formating) {
+ attach.url = mail.ChatterUtils.get_attachment_url(this.session, attach);
+ attach.filetype = mail.ChatterUtils.filetype(attach.filename);
+ attach.name = mail.ChatterUtils.breakword(attach.name || attach.filename);
+ attach.formating = true;
+ }
+ }
+ this.$(".oe_msg_attachment_list").html( session.web.qweb.render('mail.thread.message.attachments', {'widget': this}) );
+ },
+
+ /* return the link to resized image
+ */
+ attachments_resize_image: function (id, resize) {
+ return mail.ChatterUtils.get_image(this.session, 'ir.attachment', 'datas', id, resize);
+ },
+
+ /* get all child message id linked.
+ * @return array of id
+ */
+ get_child_ids: function () {
+ return _.map(this.get_childs(), function (val) { return val.id; });
+ },
+
+ /* get all child message linked.
+ * @return array of message object
+ */
+ get_childs: function (nb_thread_level) {
+ var res=[];
+ if (arguments[1] && this.id) res.push(this);
+ if ((isNaN(nb_thread_level) || nb_thread_level>0) && this.thread) {
+ _(this.thread.messages).each(function (val, key) {
+ res = res.concat( val.get_childs((isNaN(nb_thread_level) ? undefined : nb_thread_level-1), true) );
+ });
+ }
+ return res;
+ },
+
+ /**
+ * search a message in all thread and child thread.
+ * This method return an object 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_message: function (options) {
+ // goto the wall thread for launch browse
+ if (!options._go_thread_wall) {
+ options._go_thread_wall = true;
+ for (var i in this.options.root_thread.messages) {
+ var res=this.options.root_thread.messages[i].browse_message(options);
+ if (res) return res;
+ }
+ }
+
+ if (this.id==options.id)
+ return this;
+
+ for (var i in this.thread.messages) {
+ if (this.thread.messages[i].thread) {
+ var res=this.thread.messages[i].browse_message(options);
+ if (res) return res;
+ }
+ }
+
+ return false;
+ },
+
+ /**
+ * call on_message_delete on his parent thread
+ */
+ destroy: function () {
+
+ this._super();
+ this.parent_thread.on_message_detroy(this);
+
+ }
+
+ });
+
+ /**
+ * ------------------------------------------------------------
* ComposeMessage widget
* ------------------------------------------------------------
*
@@ -126,7 +384,7 @@ openerp.mail = function (session) {
* When the user focuses the textarea, the compose message is instantiated.
*/
- mail.ThreadComposeMessage = session.web.Widget.extend({
+ mail.ThreadComposeMessage = mail.MessageCommon.extend({
template: 'mail.compose_message',
/**
@@ -138,45 +396,22 @@ openerp.mail = function (session) {
*/
init: function (parent, datasets, options) {
- var self = this;
- this._super(parent);
- this.context = options.context || {};
- this.options = options.options;
-
+ this._super(parent, datasets, options);
this.show_compact_message = false;
+ this.show_delete_attachment = true;
+ },
- // data of this compose message
- this.attachment_ids = [];
- this.id = datasets.id;
- this.model = datasets.model;
- this.res_model = datasets.res_model;
- this.is_private = datasets.is_private || false;
- this.partner_ids = datasets.partner_ids || [];
- this.avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid);
- this.thread_level = datasets.thread_level;
- this.parent_thread= parent.messages!= undefined ? parent : false;
+ start: function () {
+ this._super.apply(this, arguments);
this.ds_attachment = new session.web.DataSetSearch(this, 'ir.attachment');
- this.show_delete_attachment = true;
-
this.fileupload_id = _.uniqueId('oe_fileupload_temp');
- $(window).on(self.fileupload_id, self.on_attachment_loaded);
- },
+ $(window).on(this.fileupload_id, this.on_attachment_loaded);
- start: function () {
this.display_attachments();
this.bind_events();
},
- /* upload the file on the server, add in the attachments list and reload display
- */
- display_attachments: function () {
- this.$(".oe_msg_attachment_list").html(
- session.web.qweb.render('mail.thread.message.attachments', {'widget': this}) );
- // event: delete an attachment
- this.$(".oe_msg_attachment_list").on('click', '.oe_mail_attachment_delete', this.on_attachment_delete);
- },
-
/* when a user click on the upload button, send file read on_attachment_loaded
*/
on_attachment_change: function (event) {
@@ -263,19 +498,24 @@ openerp.mail = function (session) {
this.$('textarea.oe_compact').on('focus', _.bind( this.on_compose_expandable, this));
// set the function called when attachments are added
- this.$el.on('change', 'input.oe_form_binary_file', _.bind( this.on_attachment_change, this) );
+ this.$('input.oe_form_binary_file').on('change', _.bind( this.on_attachment_change, this) );
- this.$el.on('click', '.oe_cancel', _.bind( this.on_cancel, this) );
- this.$el.on('click', '.oe_post', _.bind( this.on_message_post, this) );
- this.$el.on('click', '.oe_full', _.bind( this.on_compose_fullmail, this, 'reply') );
+ this.$('.oe_cancel').on('click', _.bind( this.on_cancel, this) );
+ this.$('.oe_post').on('click', _.bind( this.on_message_post, this) );
+ this.$('.oe_full').on('click', _.bind( this.on_compose_fullmail, this, this.id ? 'reply' : 'comment') );
/* stack for don't close the compose form if the user click on a button */
- this.$el.on('mousedown', '.oe_msg_footer', _.bind( function () { this.stay_open = true; }, this));
- this.$('textarea:not(.oe_compact):first').on('focus, mouseup, keydown', _.bind( function () { this.stay_open = false; }, this));
- this.$('textarea:not(.oe_compact):first').autosize();
+ this.$('.oe_msg_footer').on('mousedown', _.bind( function () { this.stay_open = true; }, this));
+ var ev_stay = {};
+ ev_stay.mouseup = ev_stay.keydown = ev_stay.focus = function () { self.stay_open = false; };
+ this.$('textarea:not(.oe_compact)').on(ev_stay);
+ this.$('textarea:not(.oe_compact)').autosize();
// auto close
- this.$el.on('blur', 'textarea:not(.oe_compact):first', _.bind( this.on_compose_expandable, this));
+ this.$('textarea:not(.oe_compact)').on('blur', _.bind( this.on_compose_expandable, this));
+
+ // event: delete child attachments off the oe_msg_attachment_list box
+ this.$(".oe_msg_attachment_list").on('click', '.oe_delete', this.on_attachment_delete);
},
on_compose_fullmail: function (default_composition_mode) {
@@ -290,7 +530,6 @@ openerp.mail = function (session) {
var context = {
'default_model': this.context.default_model,
'default_res_id': this.context.default_res_id,
- 'default_content_subtype': 'html',
'default_composition_mode': default_composition_mode,
'default_parent_id': this.id,
'default_body': mail.ChatterUtils.get_text2html(this.$el ? (this.$el.find('textarea:not(.oe_compact)').val() || '') : ''),
@@ -350,7 +589,7 @@ openerp.mail = function (session) {
if (body.match(/\S+/)) {
//session.web.blockUI();
- this.parent_thread.ds_thread.call('message_post_api', [
+ this.parent_thread.ds_thread.call('message_post_user_api', [
this.context.default_res_id,
mail.ChatterUtils.get_text2html(body),
false,
@@ -359,11 +598,15 @@ openerp.mail = function (session) {
this.parent_thread.context
]).done(function (record) {
var thread = self.parent_thread;
+ if (self.options.display_indented_thread < self.thread_level && thread.parent_message) {
+ var thread = thread.parent_message.parent_thread;
+ }
+ var root = thread == self.options.root_thread;
// create object and attach to the thread object
- thread.message_fetch(false, false, [record], function (arg, data) {
+ thread.message_fetch([['id', 'child_of', [self.id]]], false, [record], function (arg, data) {
var message = thread.create_message_object( data[0] );
// insert the message on dom
- thread.insert_message( message, self.$el );
+ thread.insert_message( message, root ? undefined : self.$el, root );
if (thread.parent_message) {
self.$el.remove();
self.parent_thread.compose_message = null;
@@ -419,30 +662,16 @@ openerp.mail = function (session) {
* - - visible message
* - - expandable
*/
- mail.ThreadExpandable = session.web.Widget.extend({
+ mail.ThreadExpandable = mail.MessageCommon.extend({
template: 'mail.thread.expandable',
- init: function (parent, datasets, context) {
- this._super(parent);
- this.domain = datasets.domain || [];
- this.options = datasets.options;
- this.context = _.extend({
- default_model: 'mail.thread',
- default_res_id: 0,
- default_parent_id: false }, context || {});
-
- // data of this expandable message
- this.id = datasets.id || -1,
- this.model = datasets.model || false,
- this.parent_id = datasets.parent_id || false,
- this.nb_messages = datasets.nb_messages || 0,
- this.thread_level = datasets.thread_level || 0,
- this.type = 'expandable',
- this.max_limit = this.id < 0 || false,
- this.flag_used = false,
- this.parent_thread= parent.messages!= undefined ? parent : this.options._parents[0];
+ init: function (parent, datasets, options) {
+ this._super(parent, datasets, options);
+ this.type = 'expandable';
+ this.max_limit = datasets.max_limit;
+ this.nb_messages = datasets.nb_messages;
+ this.flag_used = false;
},
-
start: function () {
this._super.apply(this, arguments);
@@ -460,7 +689,7 @@ openerp.mail = function (session) {
* Bind events in the widget. Each event is slightly described
* in the function. */
bind_events: function () {
- this.$el.on('click', 'a.oe_msg_fetch_more', this.on_expandable);
+ this.$('.oe_msg_more_message').on('click', this.on_expandable);
},
animated_destroy: function (fadeTime) {
@@ -480,154 +709,35 @@ openerp.mail = function (session) {
}
this.flag_used = true;
- this.animated_destroy(200);
- this.parent_thread.message_fetch(this.domain, this.context);
- return false;
- },
+ var self = this;
- /**
- * call on_message_delete on his parent thread
- */
- destroy: function () {
+ // read messages
+ self.parent_thread.message_fetch(this.domain, this.context, false, function (arg, data) {
+ // insert the message on dom after this message
+ self.id = false;
+ self.parent_thread.switch_new_message( data, self.$el );
+ self.animated_destroy(200);
+ });
- this._super();
- this.parent_thread.on_message_detroy(this);
+ return false;
+ },
- }
});
- /**
- * ------------------------------------------------------------
- * Thread Message Widget
- * ------------------------------------------------------------
- * This widget handles the display of a messages in a thread.
- * Displays a record and performs some formatting on the record :
- * - record.date: formatting according to the user timezone
- * - record.timerelative: relative time givein by timeago lib
- * - record.avatar: image url
- * - record.attachment_ids[].url: url of each attachmentThe
- * thread view :
- * - root thread
- * - - sub message (parent_id = root message)
- * - - - sub thread
- * - - - - sub sub message (parent id = sub thread)
- * - - sub message (parent_id = root message)
- * - - - sub thread
- */
- mail.ThreadMessage = session.web.Widget.extend({
+ mail.ThreadMessage = mail.MessageCommon.extend({
template: 'mail.thread.message',
-
- /**
- * @param {Object} parent parent
- * @param {Array} [domain]
- * @param {Object} [context] context of the thread. It should
- contain at least default_model, default_res_id. Please refer to
- the ComposeMessage widget for more information about it.
- * @param {Object} [options]
- * @param {Object} [thread] read obout mail.Thread object
- * @param {Object} [message]
- * @param {Number} [truncate_limit=250] number of character to
- * display before having a "show more" link; note that the text
- * will not be truncated if it does not have 110% of the parameter
- * @param {Boolean} [show_record_name]
- *... @param {int} [show_reply_button] number thread level to display the reply button
- *... @param {int} [show_read_unread_button] number thread level to display the read/unread button
- */
- init: function (parent, datasets, context) {
- this._super(parent);
-
- // record domain and context
- this.domain = datasets.domain || [];
- this.context = _.extend({
- default_model: 'mail.thread',
- default_res_id: 0,
- default_parent_id: false }, context || {});
-
- // record options
- this.options = datasets.options;
-
- // data of this message
- this.id = datasets.id || -1,
- this.model = datasets.model || false,
- this.parent_id = datasets.parent_id || false,
- this.res_id = datasets.res_id || false,
- this.type = datasets.type || false,
- this.is_author = datasets.is_author || 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 || false,
- this.vote_nb = datasets.vote_nb || 0,
- this.has_voted = datasets.has_voted || false,
- this.is_favorite = datasets.is_favorite || false,
- this.thread_level = datasets.thread_level || 0,
- this.to_read = datasets.to_read || false,
- this.author_id = datasets.author_id || [],
- this.attachment_ids = datasets.attachment_ids || [],
- this._date = datasets.date;
-
-
- this.show_reply_button = this.options.show_compose_message && this.options.show_reply_button > this.thread_level;
- this.show_read_unread_button = this.options.show_read_unread_button > this.thread_level;
-
- // record options and data
- this.parent_thread= parent.messages!= undefined ? parent : this.options._parents[0];
- this.thread = false;
-
- if ( this.id > 0 ) {
- this.formating_data();
- }
-
- this.ds_notification = new session.web.DataSetSearch(this, 'mail.notification');
- this.ds_message = new session.web.DataSetSearch(this, 'mail.message');
- this.ds_follow = new session.web.DataSetSearch(this, 'mail.followers');
- },
-
- /* Convert date, timerelative and avatar in displayable data. */
- formating_data: function () {
-
- //formating and add some fields for render
- this.date = session.web.format_value(this._date, {type:"datetime"});
- this.timerelative = $.timeago(this.date);
- if (this.type == 'email') {
- this.avatar = ('/mail/static/src/img/email_icon.png');
- } else {
- this.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', this.author_id[0]);
- }
- for (var l in this.attachment_ids) {
- var attach = this.attachment_ids[l];
- attach['url'] = mail.ChatterUtils.get_attachment_url(this.session, attach);
-
- if ((attach.filename || attach.name).match(/[.](jpg|jpg|gif|png|tif|svg)$/i)) {
- attach.is_image = true;
- attach['url'] = mail.ChatterUtils.get_image(this.session, 'ir.attachment', 'datas', attach.id);
- }
- }
- },
start: function () {
this._super.apply(this, arguments);
this.expender();
- this.$el.hide().fadeIn(750, function () {$(this).css('display', '');});
- this.resize_img();
this.bind_events();
if(this.thread_level < this.options.display_indented_thread) {
this.create_thread();
}
this.$('.oe_msg_attachments, .oe_msg_images').addClass("oe_hidden");
- },
- resize_img: function () {
- var resize = function () {
- var h = $(this).height();
- var w = $(this).width();
- if ( h > 100 || w >100 ) {
- var ratio = 100 / (h > w ? h : w);
- $(this).attr("width", parseInt( w*ratio )).attr("height", parseInt( h*ratio ));
- }
- };
- this.$("img").load(resize).each(resize);
+ this.ds_notification = new session.web.DataSetSearch(this, 'mail.notification');
+ this.ds_message = new session.web.DataSetSearch(this, 'mail.message');
},
/**
@@ -635,30 +745,15 @@ openerp.mail = function (session) {
* in the function. */
bind_events: function () {
var self = this;
+ // header icons bindings
+ this.$('.oe_read').on('click', this.on_message_read);
+ this.$('.oe_unread').on('click', this.on_message_unread);
+ this.$('.oe_msg_delete').on('click', this.on_message_delete);
+ 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_view_attachments').on('click', this.on_view_attachments);
- // event: click on 'Attachment(s)' in msg
- this.$('.oe_mail_msg_view_attachments').on('click', function (event) {
- var attach = self.$('.oe_msg_attachments:first, .oe_msg_images:first');
- if ( self.$('.oe_msg_attachments:first').hasClass("oe_hidden") ) {
- attach.removeClass("oe_hidden");
- } else {
- attach.addClass("oe_hidden");
- }
- self.resize_img();
- });
- // event: click on icone 'Read' in header
- this.$el.on('click', '.oe_read', this.on_message_read_unread);
- // event: click on icone 'UnRead' in header
- this.$el.on('click', '.oe_unread', this.on_message_read_unread);
- // event: click on 'Delete' in msg side menu
- this.$el.on('click', '.oe_msg_delete', this.on_message_delete);
-
- // event: click on 'Reply' in msg
- this.$el.on('click', '.oe_reply', this.on_message_reply);
- // event: click on 'Vote' button
- this.$el.on('click', '.oe_msg_vote', this.on_vote);
- // event: click on 'starred/favorite' button
- this.$el.on('click', '.oe_star', this.on_star);
},
/* Call the on_compose_message on the thread of this message. */
@@ -673,7 +768,7 @@ openerp.mail = function (session) {
this.$('.oe_msg_body:first').expander({
slicePoint: this.options.truncate_limit,
expandText: 'read more',
- userCollapseText: '[^]',
+ userCollapseText: 'read less',
detailClass: 'oe_msg_tail',
moreClass: 'oe_mail_expand',
lessClass: 'oe_mail_reduce',
@@ -717,6 +812,17 @@ openerp.mail = function (session) {
}
},
+ /* Call the on_compose_message on the thread of this message. */
+ on_view_attachments:function (event) {
+ event.stopPropagation();
+ var self = this;
+ if (!this.toggle_attachment) {
+ self.display_attachments();
+ this.toggle_attachment = true;
+ }
+ this.$('.oe_msg_attachment_list').toggle(200);
+ },
+
/**
* Wait a confirmation for delete the message on the DB.
* Make an animate destroy
@@ -732,68 +838,76 @@ openerp.mail = function (session) {
return false;
},
- /*The selected thread and all childs (messages/thread) became read
- * @param {object} mouse envent
+ /* Check if the message must be destroy and detroy it or check for re render widget
+ * @param {callback} apply function
*/
- on_message_read_unread: function (event) {
- event.stopPropagation();
- var self=this;
+ check_for_rerender: function () {
+ var self = this;
- if ( (this.to_read && this.options.typeof_thread == 'inbox') ||
- (!this.to_read && this.options.typeof_thread == 'archives')) {
- this.animated_destroy(150);
- }
+ var messages = [this].concat(this.get_childs());
+ var message_ids = _.map(messages, function (msg) { return msg.id;});
+ var domain = mail.ChatterUtils.expand_domain( this.options.root_thread.domain )
+ .concat([["id", "in", message_ids ]]);
+
+ return this.parent_thread.ds_message.call('message_read', [undefined, domain, [], !!this.parent_thread.options.display_indented_thread, this.context, this.parent_thread.id])
+ .then( function (records) {
+ // remove message not loaded
+ _.map(messages, function (msg) {
+ if(!_.find(records, function (record) { return record.id == msg.id; })) {
+ msg.animated_destroy(150);
+ } else {
+ msg.renderElement();
+ msg.start()
+ }
+ });
- // if this message is read, all childs message display is read
- this.ds_notification.call('set_message_read', [ [this.id].concat( this.get_child_ids() ) , this.to_read, this.context]).then(function () {
- self.$el.removeClass(self.to_read ? 'oe_msg_unread':'oe_msg_read').addClass(self.to_read ? 'oe_msg_read':'oe_msg_unread');
- self.to_read = !self.to_read;
- });
- return false;
+ });
},
- /**
- * search a message in all thread and child thread.
- * This method return an object 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_message: function (options) {
- // goto the wall thread for launch browse
- if (!options._go_thread_wall) {
- options._go_thread_wall = true;
- for (var i in this.options._parents[0].messages) {
- var res=this.options._parents[0].messages[i].browse_message(options);
- if (res) return res;
- }
- }
-
- if (this.id==options.id)
- return this;
-
- for (var i in this.thread.messages) {
- if (this.thread.messages[i].thread) {
- var res=this.thread.messages[i].browse_message(options);
- if (res) return res;
- }
- }
+ on_message_read: function (event) {
+ event.stopPropagation();
+ this.on_message_read_unread(true);
+ return false;
+ },
+ on_message_unread: function (event) {
+ event.stopPropagation();
+ this.on_message_read_unread(false);
return false;
},
- /* get all child message id linked.
- * @return array of id
+ /*The selected thread and all childs (messages/thread) became read
+ * @param {object} mouse envent
*/
- get_child_ids: function () {
- var res=[]
- if (arguments[0]) res.push(this.id);
- if (this.thread) {
- res = res.concat( this.thread.get_child_ids(true) );
+ on_message_read_unread: function (read_value) {
+ var self = this;
+ var messages = [this].concat(this.get_childs());
+
+ // inside the inbox, when the user mark a message as read/done, don't apply this value
+ // for the stared/favorite message
+ if (this.options.view_inbox && read_value) {
+ var messages = _.filter(messages, function (val) { return !val.is_favorite && val.id; });
+ if (!messages.length) {
+ this.check_for_rerender();
+ return false;
+ }
}
- return res;
+ var message_ids = _.map(messages, function (val) { return val.id; });
+
+ this.ds_notification.call('set_message_read', [message_ids, read_value, this.context])
+ .then(function () {
+ // apply modification
+ _.each(messages, function (msg) {
+ msg.to_read = !read_value;
+ if (msg.options.toggle_read) {
+ msg.options.show_read = msg.to_read;
+ msg.options.show_unread = !msg.to_read;
+ }
+ });
+ // check if the message must be display, destroy or rerender
+ self.check_for_rerender();
+ });
+ return false;
},
/**
@@ -801,12 +915,13 @@ openerp.mail = function (session) {
*/
on_vote: function (event) {
event.stopPropagation();
- var self=this;
- return this.ds_message.call('vote_toggle', [[self.id]]).then(function (vote) {
- self.has_voted = vote;
- self.vote_nb += self.has_voted ? 1 : -1;
- self.display_vote();
- });
+ this.ds_message.call('vote_toggle', [[this.id]])
+ .then(
+ _.bind(function (vote) {
+ this.has_voted = vote;
+ this.vote_nb += this.has_voted ? 1 : -1;
+ this.display_vote();
+ }, this));
return false;
},
@@ -814,10 +929,10 @@ openerp.mail = function (session) {
* Display the render of this message's vote
*/
display_vote: function () {
- var self = this;
- var vote_element = session.web.qweb.render('mail.thread.message.vote', {'widget': self});
- self.$(".oe_msg_vote:first").remove();
- self.$(".oe_mail_vote_count:first").replaceWith(vote_element);
+ var vote_element = session.web.qweb.render('mail.thread.message.vote', {'widget': this});
+ 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);
},
/**
@@ -827,34 +942,29 @@ openerp.mail = function (session) {
event.stopPropagation();
var self=this;
var button = self.$('.oe_star:first');
- return this.ds_message.call('favorite_toggle', [[self.id]]).then(function (star) {
- self.is_favorite=star;
- if (self.is_favorite) {
- button.addClass('oe_starred');
- } else {
- button.removeClass('oe_starred');
- if ( self.options.typeof_thread == 'stared' ) {
- self.animated_destroy(150);
+
+ this.ds_message.call('favorite_toggle', [[self.id]])
+ .then(function (star) {
+ self.is_favorite=star;
+ if (self.is_favorite) {
+ button.addClass('oe_starred');
+ } else {
+ button.removeClass('oe_starred');
}
- }
- });
+
+ if (self.options.view_inbox && self.is_favorite) {
+ self.on_message_read_unread(true);
+ } else {
+ self.check_for_rerender();
+ }
+ });
return false;
},
- /**
- * call on_message_delete on his parent thread
- */
- destroy: function () {
-
- this._super();
- this.parent_thread.on_message_detroy(this);
-
- }
-
});
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* Thread Widget
* ------------------------------------------------------------
*
@@ -881,14 +991,11 @@ openerp.mail = function (session) {
* @param {Object} [thread]
* @param {int} [display_indented_thread] number thread level to indented threads.
* other are on flat mode
- * @param {Select} [typeof_thread] inbox/archives/stared/sent
- * type of thread and option for user application like animate
- * destroy for read/unread
* @param {Array} [parents] liked with the parents thread
* use with browse, fetch... [O]= top parent
*/
init: function (parent, datasets, options) {
- this._super(parent);
+ this._super(parent, options);
this.domain = options.domain || [];
this.context = _.extend({
default_model: 'mail.thread',
@@ -896,21 +1003,24 @@ openerp.mail = function (session) {
default_parent_id: false }, options.context || {});
this.options = options.options;
- this.options._parents = (options.options._parents != undefined ? options.options._parents : []).concat( [this] );
-
+ this.options.root_thread = (options.options.root_thread != undefined ? options.options.root_thread : this);
+ this.options.show_compose_message = this.options.show_compose_message && (this.options.display_indented_thread >= this.thread_level || !this.thread_level);
+
// record options and data
this.parent_message= parent.thread!= undefined ? parent : false ;
// data of this thread
this.id = datasets.id || false,
- this.model = datasets.model || false,
+ this.last_id = datasets.last_id || false,
this.parent_id = datasets.parent_id || false,
+
this.is_private = datasets.is_private || false,
this.author_id = datasets.author_id || false,
this.thread_level = (datasets.thread_level+1) || 0,
this.partner_ids = _.filter(datasets.partner_ids, function (partner) { return partner[0]!=datasets.author_id[0]; } )
this.messages = [];
- this.show_compose_message = this.options.show_compose_message && (this.options.show_reply_button > this.thread_level || !this.thread_level);
+
+ this.options.flat_mode = !!(this.options.display_indented_thread > this.thread_level ? this.options.display_indented_thread - this.thread_level : 0);
// object compose message
this.compose_message = false;
@@ -934,13 +1044,10 @@ openerp.mail = function (session) {
'context': this.context,
'options': this.options,
});
- if (!this.thread_level) {
- // root view
+ if (!this.thread_level || this.thread_level > this.options.display_indented_thread) {
this.compose_message.insertBefore(this.$el);
- } else if (this.thread_level > this.options.display_indented_thread) {
- this.compose_message.insertAfter(this.$el);
} else {
- this.compose_message.appendTo(this.$el);
+ this.compose_message.prependTo(this.$el);
}
}
},
@@ -948,21 +1055,20 @@ openerp.mail = function (session) {
/* When the expandable object is visible on screen (with scrolling)
* then the on_expandable function is launch
*/
- on_scroll: function (event) {
- if (event)event.stopPropagation();
- this.$('.oe_msg_expandable:last');
-
- var message = this.messages[this.messages.length-1];
- if (message && message.type=="expandable" && message.max_limit) {
- var pos = message.$el.position();
+ on_scroll: function () {
+ var expandables =
+ _.each( _.filter(this.messages, function (val) {return val.max_limit && !val.parent_id;}), function (val) {
+ var pos = val.$el.position();
if (pos.top) {
/* bottom of the screen */
var bottom = $(window).scrollTop()+$(window).height()+200;
if (bottom > pos.top) {
- message.on_expandable();
+ val.on_expandable();
+ // load only one time
+ val.loading = true;
}
}
- }
+ });
},
/**
@@ -970,8 +1076,8 @@ openerp.mail = function (session) {
* in the function. */
bind_events: function () {
var self = this;
- self.$el.on('click', '.oe_mail_list_recipients .oe_more', self.on_show_recipients);
- self.$el.on('click', '.oe_mail_compose_textarea .oe_more_hidden', self.on_hide_recipients);
+ self.$('.oe_mail_list_recipients .oe_more').on('click', self.on_show_recipients);
+ self.$('.oe_mail_compose_textarea .oe_more_hidden').on('click', self.on_hide_recipients);
},
/**
@@ -981,6 +1087,7 @@ openerp.mail = function (session) {
var p=$(this).parent();
p.find('.oe_more_hidden, .oe_hidden').show();
p.find('.oe_more').hide();
+ return false;
},
/**
@@ -990,15 +1097,14 @@ openerp.mail = function (session) {
var p=$(this).parent();
p.find('.oe_more_hidden, .oe_hidden').hide();
p.find('.oe_more').show();
+ return false;
},
/* get all child message/thread id linked.
* @return array of id
*/
get_child_ids: function () {
- var res=[];
- _(this.get_childs()).each(function (val, key) { res.push(val.id); });
- return res;
+ return _.map(this.get_childs(), function (val) { return val.id; });
},
/* get all child message/thread linked.
@@ -1033,17 +1139,17 @@ openerp.mail = function (session) {
// goto the wall thread for launch browse
if (!options._go_thread_wall) {
options._go_thread_wall = true;
- return this.options._parents[0].browse_thread(options);
+ return this.options.root_thread.browse_thread(options);
}
- if (this.id==options.id) {
+ if (this.id == options.id) {
return this;
}
if (options.id) {
for (var i in this.messages) {
if (this.messages[i].thread) {
- var res=this.messages[i].thread.browse_thread({'id':options.id, '_go_thread_wall':true});
+ var res = this.messages[i].thread.browse_thread({'id':options.id, '_go_thread_wall':true});
if (res) return res;
}
}
@@ -1067,8 +1173,8 @@ openerp.mail = function (session) {
* @return message object
*/
browse_message: function (options) {
- if (this.options._parents[0].messages[0])
- return this.options._parents[0].messages[0].browse_message(options);
+ if (this.options.root_thread.messages[0])
+ return this.options.root_thread.messages[0].browse_message(options);
},
/**
@@ -1079,6 +1185,7 @@ openerp.mail = function (session) {
on_compose_message: function () {
this.instantiate_compose_message();
this.compose_message.on_compose_expandable();
+ return false;
},
/**
@@ -1086,8 +1193,8 @@ openerp.mail = function (session) {
*/
no_message: function () {
var no_message = $(session.web.qweb.render('mail.wall_no_message', {}));
- if (this.options.no_message) {
- no_message.html(this.options.no_message);
+ if (this.options.help) {
+ no_message.html(this.options.help);
}
no_message.appendTo(this.$el);
},
@@ -1101,18 +1208,20 @@ openerp.mail = function (session) {
* @param {Array} ids read (if the are some ids, the method don't use the domain)
*/
message_fetch: function (replace_domain, replace_context, ids, callback) {
- var self = this;
-
- // domain and context: options + additional
- fetch_domain = replace_domain ? replace_domain : this.domain;
- fetch_context = replace_context ? replace_context : this.context;
- var message_loaded_ids = this.id ? [this.id].concat( self.get_child_ids() ) : self.get_child_ids();
-
- // CHM note : option for sending in flat mode by server
- var thread_level = this.options.display_indented_thread > this.thread_level ? this.options.display_indented_thread - this.thread_level : 0;
-
- return this.ds_message.call('message_read', [ids, fetch_domain, message_loaded_ids, thread_level, fetch_context, this.context.default_parent_id || undefined])
- .done(callback ? _.bind(callback, this, arguments) : this.proxy('switch_new_message'));
+ return this.ds_message.call('message_read', [
+ // ids force to read
+ ids == false ? undefined : ids,
+ // domain + additional
+ (replace_domain ? replace_domain : this.domain),
+ // ids allready loaded
+ (this.id ? [this.id].concat( this.get_child_ids() ) : this.get_child_ids()),
+ // option for sending in flat mode by server
+ this.options.flat_mode,
+ // context + additional
+ (replace_context ? replace_context : this.context),
+ // parent_id
+ this.context.default_parent_id || undefined
+ ]).done(callback ? _.bind(callback, this, arguments) : this.proxy('switch_new_message'));
},
/**
@@ -1128,22 +1237,23 @@ openerp.mail = function (session) {
data.options = _.extend(self.options, data.options);
if (data.type=='expandable') {
- var message = new mail.ThreadExpandable(self, data, {
+ var message = new mail.ThreadExpandable(self, data, {'context':{
'default_model': data.model || self.context.default_model,
'default_res_id': data.res_id || self.context.default_res_id,
'default_parent_id': self.id,
- });
+ }});
} else {
- var message = new mail.ThreadMessage(self, data, {
+ var message = new mail.ThreadMessage(self, data, {'context':{
'default_model': data.model,
'default_res_id': data.res_id,
'default_parent_id': data.id,
- });
+ }});
}
// check if the message is already create
for (var i in self.messages) {
if (self.messages[i] && self.messages[i].id == message.id) {
+ console.log('Reload message', message.id);
self.messages[i].destroy();
}
}
@@ -1161,76 +1271,22 @@ openerp.mail = function (session) {
* The sort is define by the thread_level (O for newer on top).
* @param : {object} ThreadMessage object
*/
- insert_message: function (message, dom_insert_after) {
+ insert_message: function (message, dom_insert_after, prepend) {
var self=this;
-
- if (this.show_compose_message && this.options.show_compact_message) {
+ if (this.options.show_compact_message > this.thread_level) {
this.instantiate_compose_message();
this.compose_message.do_show_compact();
}
- this.$('.oe_wall_no_message').remove();
+ this.$('.oe_view_nocontent').remove();
if (dom_insert_after) {
message.insertAfter(dom_insert_after);
- return message
- }
-
- // check older and newer message for insertion
- var message_newer = false;
- var message_older = false;
- if (message.id > 0) {
- for (var i in self.messages) {
- if (self.messages[i].id > message.id) {
- if (!message_newer || message_newer.id > self.messages[i].id) {
- message_newer = self.messages[i];
- }
- } else if (self.messages[i].id > 0 && self.messages[i].id < message.id) {
- if (!message_older || message_older.id < self.messages[i].id) {
- message_older = self.messages[i];
- }
- }
- }
- }
-
- var sort = (!!self.thread_level || message.id<0);
-
- if (sort) {
- if (message_older) {
-
- message.insertAfter(message_older.thread ? (message_older.thread.compose_message ? message_older.thread.compose_message.$el : message_older.thread.$el) : message_older.$el);
-
- } else if (message_newer) {
-
- message.insertBefore(message_newer.$el);
-
- } else if (message.id < 0) {
-
- message.appendTo(self.$el);
-
- } else {
-
- message.prependTo(self.$el);
- }
+ }if (prepend) {
+ message.prependTo(self.$el);
} else {
- if (message_older) {
-
- message.insertBefore(message_older.$el);
-
- } else if (message_newer) {
-
- message.insertAfter(message_newer.thread ? (message_newer.thread.compose_message ? message_newer.thread.compose_message.$el : message_newer.thread.$el) : message_newer.$el );
-
- } else if (message.id < 0) {
-
- message.prependTo(self.$el);
-
- } else {
-
- message.appendTo(self.$el);
-
- }
+ message.appendTo(self.$el);
}
return message
@@ -1241,7 +1297,7 @@ openerp.mail = function (session) {
* Each message is send to his parent object (or parent thread flat mode) for creating the object message.
* @param : {Array} datas from calling RPC to "message_read"
*/
- switch_new_message: function (records) {
+ switch_new_message: function (records, dom_insert_after) {
var self=this;
_(records).each(function (record) {
var thread = self.browse_thread({
@@ -1251,7 +1307,7 @@ openerp.mail = function (session) {
// create object and attach to the thread object
var message = thread.create_message_object( record );
// insert the message on dom
- thread.insert_message( message );
+ thread.insert_message( message, typeof dom_insert_after == 'object' ? dom_insert_after : false);
});
},
@@ -1262,6 +1318,10 @@ openerp.mail = function (session) {
on_message_detroy: function (message) {
this.messages = _.filter(this.messages, function (val) { return !val.isDestroyed(); });
+ if (this.options.root_thread == this && !this.messages.length) {
+ this.no_message();
+ }
+ return false;
},
@@ -1323,7 +1383,6 @@ openerp.mail = function (session) {
} else {
// create a expandable message
var expandable = new mail.ThreadExpandable(this, {
- 'id': message.id,
'model': message.model,
'parent_id': message.parent_id,
'nb_messages': 1,
@@ -1332,9 +1391,11 @@ openerp.mail = function (session) {
'domain': message_dom,
'options': message.options,
}, {
- 'default_model': message.model || this.context.default_model,
- 'default_res_id': message.res_id || this.context.default_res_id,
- 'default_parent_id': this.id,
+ 'context':{
+ 'default_model': message.model || this.context.default_model,
+ 'default_res_id': message.res_id || this.context.default_res_id,
+ 'default_parent_id': this.id,
+ }
});
// add object on array and DOM
@@ -1350,7 +1411,7 @@ openerp.mail = function (session) {
});
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* mail : root Widget
* ------------------------------------------------------------
*
@@ -1360,7 +1421,7 @@ openerp.mail = function (session) {
*/
session.web.client_actions.add('mail.Widget', 'session.mail.Widget');
mail.Widget = session.web.Widget.extend({
- template: 'mail.Widget',
+ template: 'mail.Root',
/**
* @param {Object} parent parent
@@ -1368,15 +1429,13 @@ openerp.mail = function (session) {
* @param {Object} [context] context of the thread. It should
* contain at least default_model, default_res_id. Please refer to
* the compose_message widget for more information about it.
- * ... @param {Select} [typeof_thread=(mail|stared|archives|send|other)]
- * options for destroy message when the user click on a button
* @param {Object} [options]
*... @param {Number} [truncate_limit=250] number of character to
* display before having a "show more" link; note that the text
* will not be truncated if it does not have 110% of the parameter
*... @param {Boolean} [show_record_name] display the name and link for do action
- *... @param {int} [show_reply_button] number thread level to display the reply button
- *... @param {int} [show_read_unread_button] number thread level to display the read/unread button
+ *... @param {boolean} [show_reply_button] display the reply button
+ *... @param {boolean} [show_read_unread_button] display the read/unread button
*... @param {int} [display_indented_thread] number thread level to indented threads.
* other are on flat mode
*... @param {Boolean} [show_compose_message] allow to display the composer
@@ -1387,35 +1446,25 @@ openerp.mail = function (session) {
* @param {String} [no_message] Message to display when there are no message
*/
init: function (parent, action) {
- var options = action.params || {};
- this._super(parent);
- this.domain = options.domain || [];
- this.context = options.context || {};
- this.search_results = {'domain': [], 'context': {}, 'groupby': {}};
+ this._super(parent, action);
+ var self = this;
+ this.action = _.clone(action);
+ this.domain = this.action.domain || this.action.params.domain || [];
+ this.context = this.action.context || this.action.params.context || {};
- this.options = _.extend({
- 'typeof_thread' : 'inbox',
+ this.action.params = _.extend({
'display_indented_thread' : -1,
- 'show_reply_button' : -1,
- 'show_read_unread_button' : -1,
+ 'show_reply_button' : false,
+ 'show_read_unread_button' : false,
'truncate_limit' : 250,
'show_record_name' : false,
'show_compose_message' : false,
'show_compact_message' : false,
+ 'view_inbox': false,
'message_ids': undefined,
- 'no_message': false
- }, options);
+ }, this.action.params);
- if (this.display_indented_thread === false) {
- this.display_indented_thread = -1;
- }
- if (this.show_reply_button === false) {
- this.show_reply_button = -1;
- }
- if (this.show_read_unread_button === false) {
- this.show_read_unread_button = -1;
- }
-
+ this.action.params.help = this.action.help || false;
},
start: function (options) {
@@ -1423,7 +1472,6 @@ openerp.mail = function (session) {
this.message_render();
this.bind_events();
},
-
/**
*Create the root thread and display this object in the DOM.
@@ -1435,35 +1483,32 @@ openerp.mail = function (session) {
this.thread = new mail.Thread(this, {}, {
'domain' : this.domain,
'context' : this.context,
- 'options': this.options,
+ 'options': this.action.params,
});
this.thread.appendTo( this.$el );
this.thread.no_message();
- this.thread.message_fetch(null, null, this.options.message_ids);
- if (this.options.show_compose_message) {
+ if (this.action.params.show_compose_message) {
this.thread.instantiate_compose_message();
- if (this.options.show_compact_message) {
- this.thread.compose_message.do_show_compact();
- } else {
- this.thread.compose_message.do_hide_compact();
- }
+ this.thread.compose_message.do_show_compact();
}
+
+ this.thread.message_fetch(null, null, this.action.params.message_ids);
+
},
bind_events: function () {
- if (this.context['typeof_thread']!='other') {
- $(document).scroll( this.thread.on_scroll );
- $(window).resize( this.thread.on_scroll );
- window.setTimeout( this.thread.on_scroll, 500 );
- }
+ $(document).scroll( _.bind(this.thread.on_scroll, this.thread) );
+ $(window).resize( _.bind(this.thread.on_scroll, this.thread) );
+ this.$el.resize( _.bind(this.thread.on_scroll, this.thread) );
+ window.setTimeout( _.bind(this.thread.on_scroll, this.thread), 500 );
}
});
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* mail_thread Widget
* ------------------------------------------------------------
*
@@ -1476,10 +1521,18 @@ openerp.mail = function (session) {
mail.RecordThread = session.web.form.AbstractField.extend({
template: 'mail.record_thread',
- init: function () {
+ init: function (parent, node) {
this._super.apply(this, arguments);
- this.options.domain = this.options.domain || [];
- this.options.context = {'default_model': 'mail.thread', 'default_res_id': false};
+ this.node = _.clone(node);
+
+ this.node.params = _.extend({
+ 'display_indented_thread': -1,
+ 'show_reply_button': false,
+ 'show_read_unread_button': false,
+ 'show_compact_message': 1,
+ }, this.node.params);
+
+ this.domain = this.node.params && this.node.params.domain || [];
},
start: function () {
@@ -1492,42 +1545,32 @@ openerp.mail = function (session) {
_check_visibility: function () {
this.$el.toggle(this.view.get("actual_mode") !== "create");
},
+
render_value: function () {
var self = this;
+
if (! this.view.datarecord.id || session.web.BufferedDataSet.virtual_id_regex.test(this.view.datarecord.id)) {
this.$('oe_mail_thread').hide();
return;
}
- // update context
- _.extend(this.options.context, {
- default_res_id: this.view.datarecord.id,
- default_model: this.view.model,
- default_is_private: false });
- // update domain
- var domain = this.options.domain.concat([['model', '=', this.view.model], ['res_id', '=', this.view.datarecord.id]]);
-
- var show_compose_message = this.view.is_action_enabled('edit') ||
- (this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value());
- var message_ids = this.getParent().fields.message_ids && this.getParent().fields.message_ids.get_value();
+ this.node.params = _.extend(this.node.params, {
+ 'message_ids': this.get_value(),
+ 'show_compose_message': this.view.is_action_enabled('edit'),
+ });
+ this.node.context = {
+ 'default_res_id': this.view.datarecord.id || false,
+ 'default_model': this.view.model || false,
+ };
if (this.root) {
+ $('<span class="oe_mail-placeholder"/>').insertAfter(this.root.$el);
this.root.destroy();
}
// create and render Thread widget
- this.root = new mail.Widget(this, { params: {
- 'domain' : domain,
- 'context' : this.options.context,
- 'typeof_thread': this.options.context['typeof_thread'] || 'other',
- 'display_indented_thread': -1,
- 'show_reply_button': 0,
- 'show_read_unread_button': -1,
- 'show_compose_message': show_compose_message,
- 'message_ids': message_ids,
- 'show_compact_message': true,
- 'no_message': this.node.attrs.help
- }}
- );
+ this.root = new mail.Widget(this, _.extend(this.node, {
+ 'domain' : (this.domain || []).concat([['model', '=', this.view.model], ['res_id', '=', this.view.datarecord.id]]),
+ }));
return this.root.replace(this.$('.oe_mail-placeholder'));
},
@@ -1535,7 +1578,7 @@ openerp.mail = function (session) {
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* Wall Widget
* ------------------------------------------------------------
*
@@ -1543,6 +1586,7 @@ openerp.mail = function (session) {
* use is to receive a context and a domain, and to delegate the message
* fetching and displaying to the Thread widget.
*/
+
session.web.client_actions.add('mail.wall', 'session.mail.Wall');
mail.Wall = session.web.Widget.extend({
template: 'mail.wall',
@@ -1555,35 +1599,53 @@ openerp.mail = function (session) {
* contain default_model, default_res_id, to give it to the threads.
*/
init: function (parent, action) {
- this._super(parent);
- var options = action.params || {};
- this.options = options;
- this.options.domain = options.domain || [];
- this.options.context = options.context || {};
- this.search_results = {'domain': [], 'context': {}, 'groupby': {}}
- this.ds_msg = new session.web.DataSetSearch(this, 'mail.message');
+ this._super(parent, action);
+
+ this.action = _.clone(action);
+ this.domain = this.action.params.domain || this.action.domain || [];
+ this.context = this.action.params.context || this.action.context || {};
+
+ this.defaults = {};
+ for (var key in this.context) {
+ if (key.match(/^search_default_/)) {
+ this.defaults[key.replace(/^search_default_/, '')] = this.context[key];
+ }
+ }
+
+ this.action.params = _.extend({
+ 'display_indented_thread': 1,
+ 'show_reply_button': true,
+ 'show_read_unread_button': true,
+ 'show_compose_message': true,
+ 'show_compact_message': this.action.params.view_mailbox ? false : 1,
+ 'view_inbox': false,
+ }, this.action.params);
},
start: function () {
- this._super.apply(this, arguments);
- var searchview_ready = this.load_searchview({}, false);
- var thread_displayed = this.message_render();
- this.options.domain = this.options.domain.concat(this.search_results['domain']);
+ this._super.apply(this);
this.bind_events();
- return $.when(searchview_ready, thread_displayed);
+ var searchview_loaded = this.load_searchview(this.defaults);
+ if (! this.searchview.has_defaults) {
+ this.message_render();
+ }
+
},
/**
* Load the mail.message search view
* @param {Object} defaults ??
- * @param {Boolean} hidden some kind of trick we do not care here
*/
- load_searchview: function (defaults, hidden) {
+ load_searchview: function (defaults) {
var self = this;
- this.searchview = new session.web.SearchView(this, this.ds_msg, false, defaults || {}, hidden || false);
- return this.searchview.appendTo(this.$('.oe_view_manager_view_search')).done(function () {
- self.searchview.on('search_data', self, self.do_searchview_search);
- });
+ 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); });
+ if (this.searchview.has_defaults) {
+ this.searchview.ready.then(this.searchview.do_search);
+ }
+ return this.searchview
},
/**
@@ -1599,33 +1661,26 @@ openerp.mail = function (session) {
domains: domains || [],
contexts: contexts || [],
group_by_seq: groupbys || []
- }).done(function (results) {
- self.search_results['context'] = results.context;
- self.search_results['domain'] = results.domain;
- self.root.destroy();
- return self.message_render();
+ }).then(function (results) {
+ if(self.root) {
+ $('<span class="oe_mail-placeholder"/>').insertAfter(self.root.$el);
+ self.root.destroy();
+ }
+ return self.message_render(results);
});
},
-
/**
- *Create the root thread widget and display this object in the DOM
- */
+ * Create the root thread widget and display this object in the DOM
+ */
message_render: function (search) {
- var domain = this.options.domain.concat(this.search_results['domain']);
- var context = _.extend(this.options.context, search&&search.search_results['context'] ? search.search_results['context'] : {});
- this.root = new mail.Widget(this, { params: {
+ var domain = this.domain.concat(search && search['domain'] ? search['domain'] : []);
+ var context = _.extend(this.context, search && search['context'] ? search['context'] : {});
+
+ this.root = new mail.Widget(this, _.extend(this.action, {
'domain' : domain,
'context' : context,
- 'typeof_thread': context['typeof_thread'] || 'other',
- 'display_indented_thread': 1,
- 'show_reply_button': 10,
- 'show_read_unread_button': 11,
- 'show_compose_message': true,
- 'show_compact_message': false,
- }}
- );
-
+ }));
return this.root.replace(this.$('.oe_mail-placeholder'));
},
@@ -1642,7 +1697,6 @@ openerp.mail = function (session) {
views: [[false, 'form']],
target: 'new',
context: {
- 'default_content_subtype': 'html',
},
};
session.client.action_manager.do_action(action);
@@ -1653,19 +1707,18 @@ openerp.mail = function (session) {
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* UserMenu
* ------------------------------------------------------------
*
* Add a link on the top user bar for write a full mail
*/
session.web.ComposeMessageTopButton = session.web.Widget.extend({
- template:'mail.compose_message.button_top_bar',
+ template:'mail.ComposeMessageTopButton',
- start: function (parent, params) {
- var self = this;
- this.$el.on('click', 'button', self.on_compose_message );
- this._super(parent, params);
+ start: function () {
+ this.$('button').on('click', this.on_compose_message );
+ this._super();
},
on_compose_message: function (event) {
@@ -1675,26 +1728,22 @@ openerp.mail = function (session) {
res_model: 'mail.compose.message',
view_mode: 'form',
view_type: 'form',
- action_from: 'mail.ThreadComposeMessage',
views: [[false, 'form']],
target: 'new',
- context: {
- 'default_model': '',
- 'default_res_id': false,
- 'default_content_subtype': 'html',
- },
+ context: {},
};
session.client.action_manager.do_action(action);
},
-
});
- session.web.UserMenu = session.web.UserMenu.extend({
- start: function (parent, params) {
- var render = new session.web.ComposeMessageTopButton();
- render.insertAfter(this.$el);
- this._super(parent, params);
- }
+ 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'));
+ });
+ },
});
-
};
diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js
index a5a97f48d26..7bb019cde4f 100644
--- a/addons/mail/static/src/js/mail_followers.js
+++ b/addons/mail/static/src/js/mail_followers.js
@@ -30,6 +30,8 @@ openerp_mail_followers = function(session, mail) {
this.ds_model = new session.web.DataSetSearch(this, this.view.model);
this.ds_follow = new session.web.DataSetSearch(this, this.field.relation);
this.ds_users = new session.web.DataSetSearch(this, 'res.users');
+
+ this.value = [];
},
start: function() {
@@ -41,6 +43,11 @@ openerp_mail_followers = function(session, mail) {
this._super();
},
+ set_value: function(_value) {
+ this.value = _value;
+ this._super(_value);
+ },
+
_check_visibility: function() {
this.$el.toggle(this.view.get("actual_mode") !== "create");
},
@@ -86,13 +93,14 @@ openerp_mail_followers = function(session, mail) {
read_value: function () {
var self = this;
return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).then(function (results) {
- self.set_value(results[0].message_follower_ids);
+ self.value = results[0].message_follower_ids;
+ self.render_value();
});
},
render_value: function () {
this.reinit();
- return this.fetch_followers(this.get("value"));
+ return this.fetch_followers(this.value);
},
fetch_followers: function (value_) {
@@ -111,7 +119,7 @@ openerp_mail_followers = function(session, mail) {
event.preventDefault();
return this.ds_users.call('read', [this.session.uid, ['partner_id']]).then(function (results) {
var pid = results['partner_id'][0];
- self.message_is_follower = (_.indexOf(self.get('value'), pid) != -1);
+ self.message_is_follower = (_.indexOf(self.value, pid) != -1);
}).then(self.proxy('display_generic'));
},
_format_followers: function(count){
@@ -131,7 +139,7 @@ openerp_mail_followers = function(session, mail) {
display_generic: function () {
var self = this;
var node_user_list = this.$('.oe_follower_list').empty();
- this.$('.oe_follower_title').html(this._format_followers(this.get('value').length));
+ this.$('.oe_follower_title').html(this._format_followers(this.value.length));
},
/** Display the followers */
@@ -206,7 +214,8 @@ openerp_mail_followers = function(session, mail) {
$(record).attr('checked',false);
});
var context = new session.web.CompoundContext(this.build_context(), {});
- return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context]).then(this.proxy('read_value'));
+ return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context])
+ .then(this.proxy('read_value'));
},
do_update_subscription: function (event) {
@@ -220,7 +229,7 @@ openerp_mail_followers = function(session, mail) {
});
var context = new session.web.CompoundContext(this.build_context(), {});
- return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], this.message_is_follower ? checklist:undefined, context])
+ return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], this.message_is_follower ? checklist : undefined, context])
.then(this.proxy('read_value'));
},
});
diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml
index bfd0e4cd10f..89fbe45dc36 100644
--- a/addons/mail/static/src/xml/mail.xml
+++ b/addons/mail/static/src/xml/mail.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<template>
- <!-- this template contains the mail widget and is used to namespace the css -->
- <t t-name="mail.Widget">
+ <!--
+ mail.Widget template used to namespace the css -->
+ <t t-name="mail.Root">
<div class="oe_mail">
</div>
</t>
@@ -38,7 +39,8 @@
</div>
</div>
<div t-if="widget.show_compact_message and !widget.show_composer" t-attf-class="oe_msg oe_msg_composer_compact #{widget.thread_level and widget.options.display_indented_thread > -1 ? 'oe_msg_indented' : ''}">
- <textarea class="field_text oe_compact" placeholder="Write a reply..."/>
+ <textarea t-if="!widget.options.view_mailbox" class="field_text oe_compact" placeholder="Write to the followers of this docmuent..."/>
+ <textarea t-if="widget.options.view_mailbox" class="field_text oe_compact" placeholder="Write to my followers..."/>
</div>
<span t-if="!(widget.show_compact_message and !widget.show_composer) and !widget.show_composer" class="oe_placeholder_compose"></span>
</t>
@@ -69,41 +71,28 @@
Template used to display attachments in a mail.message
-->
<t t-name="mail.thread.message.attachments">
- <span class="oe_msg_attachments">
- <t t-foreach="widget.attachment_ids" t-as="attachment" t-if="!attachment.is_image">
- <div class="oe_attachment">
- <span t-if="(attachment.upload and attachment.percent_loaded&lt;100)" t-attf-title="{(attachment.name || attachment.filename) + (attachment.date?' \n('+attachment.date+')':'' )}" t-attf-name="{attachment.name || attachment.filename}">
- <div class="oe_upload_in_process">
- <span>...Upload in progress...</span>
- </div>
- <t t-raw="attachment.name || attachment.filename"/>
- </span>
- <t t-if="(!attachment.upload or attachment.percent_loaded&gt;=100)">
- <a t-att-href="attachment.url" t-attf-title="{(attachment.name || attachment.filename) + (attachment.date?' \n('+attachment.date+')':'' )}">
- <t t-raw="attachment.name || attachment.filename"/>
- </a>
- </t>
- <t t-if="(widget.show_delete_attachment and (!attachment.upload or attachment.percent_loaded&gt;=100))">
- <a class="oe_right oe_mail_attachment_delete oe_e" title="Delete this attachment" t-attf-data-id="{attachment.id}">[</a>
- </t>
+ <t t-foreach='widget.attachment_ids' t-as='attachment'>
+ <t t-if="attachment.filetype !== 'webimage'">
+ <div t-attf-class="oe_attachment #{attachment.upload ? 'oe_uploading' : ''}">
+ <a t-att-href='attachment.url'><img t-att-src="'/mail/static/src/img/mimetypes/' + attachment.filetype + '.png'"></img></a>
+ <div class='oe_delete oe_e' title="Delete this attachment" t-attf-data-id="{attachment.id}">[</div>
+ <div class='oe_name'><t t-raw='attachment.name' /></div>
+ <div class='oe_progress_bar'>
+ uploading
+ </div>
</div>
</t>
- </span>
- <span class="oe_msg_images">
- <t t-foreach="widget.attachment_ids" t-as="attachment" t-if="attachment.is_image">
- <a t-att-href="attachment.url" t-attf-title="{(attachment.name || attachment.filename) + (attachment.date?' \n('+attachment.date+')':'' )}">
- <img t-if="attachment.is_image" t-attf-title="{(attachment.name || attachment.filename) + (attachment.date?' \n('+attachment.date+')':'' )}" t-att-src="attachment.url"/>
- </a>
+ <t t-if="attachment.filetype === 'webimage'">
+ <div t-attf-class="oe_attachment oe_preview #{attachment.upload ? 'oe_uploading' : ''}">
+ <a t-att-href='attachment.url'><img t-att-src="widget.attachments_resize_image(attachment.id, [100,100])"></img></a>
+ <div class='oe_delete oe_e'>[</div>
+ <div class='oe_name'><t t-raw='attachment.name' /></div>
+ <div class='oe_progress_bar'>
+ uploading
+ </div>
+ </div>
</t>
- </span>
- </t>
-
- <t t-name="mail.thread.message.private">
- <div>
- <span class="oe_placeholder_checkbox_private"/>
- <span class="oe_send_private">This email is private.</span>
- <span class="oe_send_public">I wrote for contacts and all my followers.</span>
- </div>
+ </t>
</t>
<!--
@@ -112,7 +101,7 @@
<t t-name="mail.thread.list_recipients">
<div class="oe_mail_list_recipients">
To:
- <span t-if="!widget.is_private" class="oe_all_follower">Everyone</span>
+ <span t-if="!widget.is_private" class="oe_all_follower">Followers <t t-raw="' of ' + (widget.parent_thread.parent_message.record_name ? '&quot;' + widget.parent_thread.parent_message.record_name + '&quot;' : 'this document')"/></span>
<t t-if="!widget.is_private and widget.partner_ids.length"> and </t>
<t t-set="inc" t-value="0"/>
<t t-if="widget.partner_ids.length" t-foreach="widget.partner_ids" t-as="partner"><span t-attf-class="oe_partner_follower #{inc>=3?'oe_hidden':''}"><t t-if="inc" t-raw="', '"/><a t-attf-href="#model=res.partner&amp;id=#{partner[0]}"><t t-raw="partner[1]"/></a></span><t t-set="inc" t-value="inc+1"/>
@@ -140,22 +129,20 @@
<td colspan="2">
<h2 class="oe_view_title">
<span class="oe_view_title_text">
- News Feed
- <t t-if="widget.options.res_model"> / </t>
- <t t-if="widget.options.res_model" t-esc="widget.options.res_model"/>
+ Email box
</span>
</h2>
</td>
<td><div class="oe_view_manager_view_search" t-opentag="true"/></td>
</tr>
- <tr class="oe_header_row">
+ <tr class="oe_header_row" t-if="widget.action.params.view_inbox" >
<td colspan="2">
<button type="button" class="oe_write_full oe_highlight">
Compose a new message
</button>
<span class='oe_alternative'>
or
- <a href='#' class='oe_write_onwall oe_bold' help='Your followers can read this message'>Write to your followers</a>
+ <a href='#' class='oe_write_onwall oe_bold' help='Your followers can read this message'>Write to my followers</a>
</span>
</td>
</tr>
@@ -168,7 +155,7 @@
display message on the wall when there are no message
-->
<t t-name="mail.wall_no_message">
- <div class="oe_wall_no_message">You have no messages</div>
+ <div class="oe_view_nocontent">No messages.</div>
</t>
<!--
@@ -187,7 +174,7 @@
<!-- default layout -->
<t t-name="mail.thread.message">
- <div t-attf-class="oe_msg #{widget.thread_level and widget.options.display_indented_thread > -1 ? 'oe_msg_indented' : ''} oe_msg_#{widget.type} oe_msg_#{widget.to_read?'unread':'read'}">
+ <div t-attf-class="oe_msg #{widget.thread_level and widget.options.display_indented_thread > -1 ? 'oe_msg_indented' : ''} oe_msg_#{widget.type}">
<div class='oe_msg_left'>
<a t-attf-href="#model=res.partner&amp;id=#{widget.author_id[0]}" t-att-title="widget.author_id[1]">
@@ -197,10 +184,11 @@
<div class="oe_msg_center">
<div class='oe_msg_icons'>
- <span class='oe_read' t-if="widget.show_read_unread_button"><a title="Mark as read" class="oe_e">X</a></span>
- <span class='oe_unread' t-if="widget.show_read_unread_button"><a title="Mark as unread" class="oe_e">v</a></span>
- <span class='oe_reply' t-if="widget.show_reply_button"><a title="Reply" class="oe_e">(</a></span>
- <span t-attf-class="oe_star #{widget.is_favorite?'oe_starred':''}"><a title="Add To Favorites" class="oe_e">7</a></span>
+ <span class='oe_read' t-if="widget.options.show_read"><a title="Done" class="oe_e">X</a></span>
+ <span class='oe_unread' t-if="widget.is_favorite and widget.options.show_unread"><a title="Set back to Todo" class="oe_e">v</a></span>
+ <span class='oe_unread' t-if="!widget.is_favorite and widget.options.show_unread"><a title="Set back to Inbox" class="oe_e">v</a></span>
+ <span class='oe_reply' t-if="widget.options.show_reply_button"><a title="Reply" class="oe_e">(</a></span>
+ <span t-attf-class="oe_star #{widget.is_favorite?'oe_starred':''}"><a title="Mark as Todo" class="oe_e">7</a></span>
</div>
<!-- message itself -->
<div class="oe_msg_content">
@@ -208,23 +196,26 @@
<t t-raw="widget.subject"/>
</h1>
<div class="oe_msg_body">
- <t t-if="widget.options.show_record_name and widget.record_name and (!widget.subject) and !widget.options.thread_level and !widget.options.display_on_thread[0] and widget.model!='res.partner'">
+ <t t-if="widget.show_record_name">
<a class="oe_mail_action_model" t-attf-href="#model=#{widget.model}&amp;id=#{widget.res_id}"><t t-raw="widget.record_name"/></a>
</t>
<t t-raw="widget.body"/>
</div>
- <t t-if="widget.attachment_ids.length > 0">
- <t t-call="mail.thread.message.attachments"/>
- </t>
</div>
<div class="oe_msg_footer">
+ <t t-if="widget.attachment_ids.length > 0">
+ <div class="oe_msg_attachment_list"></div>
+ </t>
<a t-if="widget.author_id" t-attf-href="#model=res.partner&amp;id=#{widget.author_id[0]}"><t t-raw="widget.author_id[1]"/></a>
<span class='oe_subtle'>•</span>
<span t-att-title="widget.date"><t t-raw="widget.timerelative"/></span>
- <a t-if="widget.attachment_ids.length > 0" class="oe_mail_msg_view_attachments">
+ <t t-if='widget.attachment_ids.length > 0'>
+ <span class='oe_subtle'>•</span>
+ <a class="oe_view_attachments">
<t t-if="widget.attachment_ids.length == 1">1 Attachment</t>
<t t-if="widget.attachment_ids.length > 1"><t t-raw="widget.attachment_ids.length"/> Attachments</t>
</a>
+ </t>
<span class='oe_subtle'>•</span>
<t t-call="mail.thread.message.vote"/>
</div>
@@ -234,11 +225,12 @@
<!-- expandable message layout -->
<t t-name="mail.thread.expandable">
- <div t-attf-class="oe_msg oe_msg_#{widget.type} #{widget.thread_level and widget.options.display_indented_thread > -1 ? 'oe_msg_indented' : ''} oe_msg_unread">
+ <div t-attf-class="oe_msg oe_msg_#{widget.type} #{widget.max_limit ? 'oe_max_limit' : ''} #{widget.thread_level and widget.options.display_indented_thread > -1 ? 'oe_msg_indented' : ''}">
<div class="oe_msg_content oe_msg_more_message">
<div class='oe_separator'></div>
+ <a t-if="widget.nb_messages &lt;= 0" class="oe_msg_fetch_more">show more message</a>
<a t-if="widget.nb_messages === 1" class="oe_msg_fetch_more">show one more message</a>
- <a t-if="widget.nb_messages !== 1" class="oe_msg_fetch_more">show <t t-raw="widget.nb_messages" /> more messages</a>
+ <a t-if="widget.nb_messages &gt; 1" class="oe_msg_fetch_more">show <t t-raw="widget.nb_messages" /> more messages</a>
</div>
</div>
</t>
@@ -247,9 +239,9 @@
mail.compose_message.button_top_bar
render of the button on the user bar for open wizard compose message
-->
- <t t-name="mail.compose_message.button_top_bar">
- <div class="oe_topbar_compose_full_email">
- <!-- <button class="oe_button oe_highlight">Write an email</button> -->
+ <t t-name="mail.ComposeMessageTopButton">
+ <div title='Compose new Message' class="oe_topbar_item oe_topbar_compose_full_email">
+ <button class="oe_e">%</button>
</div>
</t>
@@ -257,12 +249,11 @@
Template used to display Like/Unlike in a mail.message
-->
<span t-name="mail.thread.message.vote">
-
<span class="oe_mail_vote_count" t-if='widget.vote_nb > 0'>
<t t-raw='widget.vote_nb' />
<span class='oe_e'>8</span>
</span>
- <a href='#' t-attf-class="oe_msg_vote">
+ <a href='#' class="oe_msg_vote">
<t t-if="!widget.has_voted">like</t>
<t t-if="widget.has_voted">unlike</t>
</a>