summaryrefslogtreecommitdiff
path: root/addons/mail/static/src
diff options
context:
space:
mode:
authorRaphael Collet <rco@openerp.com>2012-04-27 15:12:41 +0200
committerRaphael Collet <rco@openerp.com>2012-04-27 15:12:41 +0200
commit33deda8f83dff5a510df8ef49522bbb9bb8ca7f6 (patch)
tree91705d2f6c76e06f3b1b6b81f9ba91aedc06455e /addons/mail/static/src
parent1e7213e03b3572e4557f3390c4b1981b24dc1752 (diff)
parent0ba09e28c93bce54f16c02a699c7747a28406318 (diff)
[MERGE] from trunk
bzr revid: rco@openerp.com-20120427131241-6gf7x3lzhux5qnnh
Diffstat (limited to 'addons/mail/static/src')
-rw-r--r--addons/mail/static/src/css/mail.css298
-rw-r--r--addons/mail/static/src/css/mail_group.css79
-rw-r--r--addons/mail/static/src/img/_al.pngbin0 -> 1017 bytes
-rw-r--r--addons/mail/static/src/img/_fp.pngbin0 -> 7725 bytes
-rw-r--r--addons/mail/static/src/img/_pinky.pngbin0 -> 7725 bytes
-rw-r--r--addons/mail/static/src/img/email_icon.pngbin0 -> 2772 bytes
-rw-r--r--addons/mail/static/src/img/feeds-hover.pngbin0 -> 15696 bytes
-rw-r--r--addons/mail/static/src/img/feeds.pngbin0 -> 5647 bytes
-rw-r--r--addons/mail/static/src/img/groupdefault.pngbin0 -> 3092 bytes
-rw-r--r--addons/mail/static/src/js/mail.js783
-rw-r--r--addons/mail/static/src/xml/mail.xml115
11 files changed, 1275 insertions, 0 deletions
diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css
new file mode 100644
index 00000000000..7f0cc6f222c
--- /dev/null
+++ b/addons/mail/static/src/css/mail.css
@@ -0,0 +1,298 @@
+/* ------------------------------ */
+/* Wall */
+/* ------------------------------ */
+
+.openerp div.oe_mail_wall {
+ overflow: auto;
+ padding: 0;
+ background: white;
+}
+
+.openerp div.oe_mail_wall_act:after {
+ content: "";
+ display: block;
+ clear: both;
+}
+
+/* 2 columns view */
+.openerp div.oe_mail_wall_left {
+ float: left;
+ width: 560px;
+ margin: 8px;
+}
+
+.openerp div.oe_mail_wall_right {
+ margin-left: 565px;
+ margin: 8px;
+}
+
+.openerp div.oe_mail_wall_threads {
+ margin-top: 8px;
+}
+
+.openerp textarea.oe_mail_wall_action_textarea {
+ width: 550px;
+ height: 60px;
+ padding: 5px;
+}
+
+.openerp div.oe_mail_wall_threads textarea {
+ height: 20px;
+ padding: 2px;
+}
+
+.openerp div.oe_mail_thread_subthread img {
+ width: 30px;
+ height: 30px;
+}
+
+.openerp div.oe_mail_thread_subthread div.oe_mail_msg_content {
+ margin-left: 40px;
+}
+
+.openerp div.oe_mail_wall_more {
+ text-align: center;
+ display: none;
+}
+
+
+/* ------------------------------ */
+/* RecordThread */
+/* ------------------------------ */
+
+.openerp div.oe_mail_recthread {
+ overflow: auto;
+}
+
+/* Left-side CSS */
+.openerp div.oe_mail_recthread_actions {
+ margin-bottom: 8px;
+}
+
+.openerp div.oe_mail_recthread_followers {
+ margin-bottom: 8px;
+}
+
+/* RecordThread: 2 columns view */
+.openerp div.oe_mail_recthread_left {
+ float: left;
+ width: 55%;
+}
+
+.openerp div.oe_mail_recthread_right {
+ float: right;
+ width: 250px;
+}
+
+.openerp div.oe_mail_recthread_actions button {
+ width: 120px;
+}
+
+.openerp button.oe_mail_button_followers {
+ display: inline;
+}
+
+.openerp button.oe_mail_button_mouseout {
+ color: white;
+ background-color: #8a89ba;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#8a89ba), to(#807fb4));
+ background-image: -webkit-linear-gradient(top, #8a89ba, #807fb4);
+ background-image: -moz-linear-gradient(top, #8a89ba, #807fb4);
+ background-image: -ms-linear-gradient(top, #8a89ba, #807fb4);
+ background-image: -o-linear-gradient(top, #8a89ba, #807fb4);
+ background-image: linear-gradient(to bottom, #8a89ba, #807fb4);
+}
+
+.openerp button.oe_mail_button_mouseover {
+ display: none;
+ color: white;
+ background-color: #dc5f59;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dc5f59), to(#b33630));
+ background-image: -webkit-linear-gradient(top, #dc5f59, #b33630);
+ background-image: -moz-linear-gradient(top, #dc5f59, #b33630);
+ background-image: -ms-linear-gradient(top, #dc5f59, #b33630);
+ background-image: -o-linear-gradient(top, #dc5f59, #b33630);
+ background-image: linear-gradient(to bottom, #dc5f59, #b33630);
+}
+
+.openerp textarea.oe_mail_action_textarea {
+ height: 60px;
+ padding: 5px;
+}
+
+/* ------------------------------ */
+/* ThreadDisplay */
+/* ------------------------------ */
+
+.openerp div.oe_mail_thread_act {
+ white-space: normal;
+ margin-bottom: 5px;
+ padding: 4px;
+}
+
+.openerp div.oe_mail_thread_act:after {
+ content: "";
+ display: block;
+ clear: both;
+}
+
+.openerp div.oe_mail_thread_display {
+ white-space: normal;
+}
+
+.openerp div.oe_mail_thread_subthread {
+ margin-top: 8px;
+ padding-left: 5%;
+}
+
+.openerp div.oe_mail_thread_more {
+ display: none;
+ border-bottom: 1px solid #D2D9E7;
+}
+
+.openerp li.oe_mail_thread_msg {
+ padding: 1px;
+}
+
+.openerp li.oe_mail_thread_msg:after {
+ content: "";
+ display: block;
+ clear: both;
+}
+
+.openerp li.oe_mail_thread_msg > div:after {
+ content: "";
+ display: block;
+ clear: both;
+}
+
+.openerp .oe_mail_msg_notification, .openerp .oe_mail_msg_comment, .openerp .oe_mail_msg_email {
+ padding: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -o-border-radius: 4px;
+ -ms-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.openerp li.oe_mail_thread_msg > .oe_mail_msg_comment {
+ background: #eee;
+}
+
+.openerp div.oe_mail_thread_subthread .oe_mail_msg_comment {
+ background: white;
+}
+
+.openerp .oe_mail_msg_notification {
+ background: #eee;
+}
+
+.openerp .oe_mail_msg_notification:after, .openerp .oe_mail_msg_comment:after, .openerp .oe_mail_msg_email:after {
+ content: "";
+ display: block;
+ clear: both;
+}
+
+.openerp .oe_mail_msg_content {
+ margin-left: 60px;
+}
+
+.openerp .oe_mail_msg_content:after {
+ content: "";
+ display: block;
+ clear: both;
+}
+
+.openerp img.oe_mail_msg_image {
+ margin-right: 8px;
+ width: 45px;
+ height: 45px;
+ text-align: center;
+ overflow: hidden;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -o-border-radius: 4px;
+ -ms-border-radius: 4px;
+ border-radius: 4px;
+ -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
+ -webkit-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);
+ clip: rect(5px, 40px, 45px, 0px);
+}
+
+.openerp p.oe_mail_msg_p_email_header {
+ border-bottom: 1px solid #D2D9E7;
+}
+
+.openerp span.oe_mail_msg_body a.reduce, .openerp span.oe_mail_msg_body_short a.expand {
+ color: #4E43E7;
+}
+
+/* ------------------------------ */
+/* Styling (should be openerp) */
+/* ------------------------------ */
+
+.openerp ul.oe_mail {
+ padding: 0;
+ margin: 0;
+}
+
+.openerp li.oe_mail {
+ list-style-type: none;
+ margin-bottom: 2px;
+}
+
+.openerp input.oe_mail, textarea.oe_mail {
+ width: 100%;
+ padding: 4px;
+ font-size: 12px;
+ border: 1px solid #cccccc;
+ -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
+ -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
+ -ms-transition: border linear 0.2s, box-shadow linear 0.2s;
+ -o-transition: border linear 0.2s, box-shadow linear 0.2s;
+ transition: border linear 0.2s, box-shadow linear 0.2s;
+ -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ -box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.openerp input.oe_mail:focus, textarea.oe_mail:focus {
+ outline: 0;
+ border-color: rgba(82, 168, 236, 0.8);
+ -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
+ -box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
+}
+
+.openerp p.oe_mail_msg {
+ padding: 0;
+ margin: 0;
+}
+
+.openerp .oe_mail_oe_right {
+ float: right;
+ margin-right: 8px;
+}
+
+.openerp .oe_mail_oe_left {
+ float: left;
+ margin-right: 8px;
+}
+
+.openerp a.oe_mail_oe_intlink {
+ color: #8786b7;
+}
+
+.openerp .oe_mail_oe_bold {
+ font-weight: bold;
+}
+
+.openerp .oe_mail_oe_space {
+ margin-left: 15px;
+ margin-right: 4px;
+}
diff --git a/addons/mail/static/src/css/mail_group.css b/addons/mail/static/src/css/mail_group.css
new file mode 100644
index 00000000000..90261499753
--- /dev/null
+++ b/addons/mail/static/src/css/mail_group.css
@@ -0,0 +1,79 @@
+.oe_group_vignette {
+ padding: 8px 0;
+ min-height: 100px;
+}
+
+.oe_group_image, .oe_group_details {
+ display: inline-block;
+ vertical-align: top;
+}
+
+.oe_group_image {
+ width: 100px;
+ height: 100px;
+ text-align: center;
+ overflow: hidden;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ -o-border-radius: 3px;
+ -ms-border-radius: 3px;
+ border-radius: 3px;
+ -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
+ -webkit-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: auto;
+ clip: rect(0px, 100px, 100px, 0px);
+}
+
+.oe_group_photo_wide {
+ height: 100px;
+ width: auto;
+ clip: rect(0px, 115px, 100px, 15px);
+}
+
+.oe_group_details {
+ width: 220px;
+ font-size: 13px;
+ padding: 2px 5px;
+ color: #4c4c4c;
+ 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 {
+ margin: 2px 0;
+}
+
+.oe_group_description {
+}
+
+.oe_kanban_record div.true {
+}
diff --git a/addons/mail/static/src/img/_al.png b/addons/mail/static/src/img/_al.png
new file mode 100644
index 00000000000..f6843ddf95c
--- /dev/null
+++ b/addons/mail/static/src/img/_al.png
Binary files differ
diff --git a/addons/mail/static/src/img/_fp.png b/addons/mail/static/src/img/_fp.png
new file mode 100644
index 00000000000..17dce2a047c
--- /dev/null
+++ b/addons/mail/static/src/img/_fp.png
Binary files differ
diff --git a/addons/mail/static/src/img/_pinky.png b/addons/mail/static/src/img/_pinky.png
new file mode 100644
index 00000000000..69c18a32976
--- /dev/null
+++ b/addons/mail/static/src/img/_pinky.png
Binary files differ
diff --git a/addons/mail/static/src/img/email_icon.png b/addons/mail/static/src/img/email_icon.png
new file mode 100644
index 00000000000..6390d9e6e69
--- /dev/null
+++ b/addons/mail/static/src/img/email_icon.png
Binary files differ
diff --git a/addons/mail/static/src/img/feeds-hover.png b/addons/mail/static/src/img/feeds-hover.png
new file mode 100644
index 00000000000..67070d3e7df
--- /dev/null
+++ b/addons/mail/static/src/img/feeds-hover.png
Binary files differ
diff --git a/addons/mail/static/src/img/feeds.png b/addons/mail/static/src/img/feeds.png
new file mode 100644
index 00000000000..ac2293c0bf5
--- /dev/null
+++ b/addons/mail/static/src/img/feeds.png
Binary files differ
diff --git a/addons/mail/static/src/img/groupdefault.png b/addons/mail/static/src/img/groupdefault.png
new file mode 100644
index 00000000000..cf160022470
--- /dev/null
+++ b/addons/mail/static/src/img/groupdefault.png
Binary files differ
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js
new file mode 100644
index 00000000000..d99674f98a7
--- /dev/null
+++ b/addons/mail/static/src/js/mail.js
@@ -0,0 +1,783 @@
+openerp.mail = function(session) {
+ var _t = session.web._t,
+ _lt = session.web._lt;
+
+ var mail = session.mail = {};
+
+ /**
+ * Add records to sorted_comments array
+ * @param {Array} records records from mail.message sorted by date desc
+ * @returns {Object} cs comments_structure: dict
+ * cs.model_to_root_ids = {model: [root_ids], }
+ * cs.new_root_ids = [new_root_ids]
+ * cs.root_ids = [root_ids]
+ * cs.msgs = {record.id: record,}
+ * cs.tree_struct = {record.id: {
+ * 'level': record_level in hierarchy, 0 is root,
+ * 'msg_nbr': number of childs,
+ * 'direct_childs': [msg_ids],
+ * 'all_childs': [msg_ids],
+ * 'for_thread_msgs': [records],
+ * 'ancestors': [msg_ids], } }
+ */
+ function tools_sort_comments(cs, records, parent_id) {
+ var cur_iter = 0; var max_iter = 10; var modif = true;
+ while ( modif && (cur_iter++) < max_iter) {
+ modif = false;
+ _(records).each(function (record) {
+ // root and not yet recorded
+ if ( (record.parent_id == false || record.parent_id[0] == parent_id) && ! cs['msgs'][record.id]) {
+ // add to model -> root_list ids
+ if (! cs['model_to_root_ids'][record.model]) cs['model_to_root_ids'][record.model] = [record.id];
+ else cs['model_to_root_ids'][record.model].push(record.id);
+ // add root data
+ cs['new_root_ids'].push(record.id);
+ // add record
+ cs['tree_struct'][record.id] = {'level': 0, 'direct_childs': [], 'all_childs': [], 'for_thread_msgs': [record], 'msg_nbr': -1, 'ancestors': []};
+ cs['msgs'][record.id] = record;
+ modif = true;
+ }
+ // not yet recorded, but parent is recorded
+ else if (! cs['msgs'][record.id] && cs['msgs'][record.parent_id[0]]) {
+ var parent_level = cs['tree_struct'][record.parent_id[0]]['level'];
+ // update parent structure
+ cs['tree_struct'][record.parent_id[0]]['direct_childs'].push(record.id);
+ cs['tree_struct'][record.parent_id[0]]['for_thread_msgs'].push(record);
+ // update ancestors structure
+ for (ancestor_id in cs['tree_struct'][record.parent_id[0]]['ancestors']) {
+ cs['tree_struct'][ancestor_id]['all_childs'].push(record.id);
+ }
+ // add record
+ cs['tree_struct'][record.id] = {'level': parent_level+1, 'direct_childs': [], 'all_childs': [], 'for_thread_msgs': [], 'msg_nbr': -1, 'ancestors': []};
+ cs['msgs'][record.id] = record;
+ modif = true;
+ }
+ });
+ }
+ return cs;
+ }
+
+ /* Add ThreadDisplay widget to registry */
+ session.web.form.widgets.add( 'Thread', 'openerp.mail.Thread');
+// session.web.page.readonly.add( 'Thread', 'openerp.mail.Thread');
+
+ /**
+ * ThreadDisplay widget: this widget handles the display of a thread of
+ * messages. The [thread_level] parameter sets the thread level number:
+ * - root message
+ * - - sub message (parent_id = root message)
+ * - - - sub sub message (parent id = sub message)
+ * - - sub message (parent_id = root message)
+ * This widget has 2 ways of initialization, either you give records to be rendered,
+ * either it will fetch [limit] messages related to [res_model]:[res_id].
+ */
+ mail.Thread = session.web.Widget.extend({
+ template: 'Thread',
+
+ /**
+ * @param {Object} parent parent
+ * @param {Object} [params]
+ * @param {String} [params.res_model] res_model of mail.thread object
+ * @param {Number} [params.res_id] res_id of record
+ * @param {Number} [params.parent_id=false] parent_id of message
+ * @param {Number} [params.uid] user id
+ * @param {Number} [params.thread_level=0] number of levels in the thread (only 0 or 1 currently)
+ * @param {Number} [params.msg_more_limit=100] 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 (ex: 110 characters needed to be truncated and be displayed
+ * as a 100-characters message)
+ * @param {Number} [params.limit=10] maximum number of messages to fetch
+ * @param {Number} [params.offset=0] offset for fetching messages
+ * @param {Number} [params.records=null] records to show instead of fetching messages
+ */
+ init: function(parent, params) {
+ this._super(parent);
+ this.params = params;
+ this.params.parent_id = this.params.parent_id || false;
+ this.params.thread_level = this.params.thread_level || 0;
+ this.params.msg_more_limit = this.params.msg_more_limit || 100;
+ this.params.limit = this.params.limit || 100;
+ this.params.offset = this.params.offset || 0;
+ this.params.records = this.params.records || null;
+ // datasets and internal vars
+ this.ds = new session.web.DataSet(this, this.params.res_model);
+ this.ds_users = new session.web.DataSet(this, 'res.users');
+ this.ds_msg = new session.web.DataSet(this, 'mail.message');
+ this.sorted_comments = {'root_ids': [], 'root_id_msg_list': {}};
+ this.comments_structure = {'root_ids': [], 'new_root_ids': [], 'msgs': {}, 'tree_struct': {}, 'model_to_root_ids': {}};
+ // display customization vars
+ this.display = {};
+ this.display.show_post_comment = this.params.show_post_comment || false;
+ this.display.show_reply = (this.params.thread_level > 0);
+ this.display.show_delete = true;
+ this.display.show_hide = this.params.show_hide || false;
+ this.display.show_more = (this.params.thread_level == 0);
+ // not used currently
+ this.intlinks_mapping = {};
+ },
+
+ start: function() {
+ this._super.apply(this, arguments);
+ // customize display
+ if (! this.display.show_post_comment) this.$element.find('div.oe_mail_thread_act').hide();
+ // add events
+ this.add_events();
+ /* display user, fetch comments */
+ this.display_current_user();
+ if (this.params.records) var display_done = this.display_comments_from_parameters(this.params.records);
+ else var display_done = this.init_comments();
+ return display_done
+ },
+
+ add_events: function() {
+ var self = this;
+ // event: click on 'more' at bottom of thread
+ this.$element.find('button.oe_mail_button_more').click(function () {
+ self.do_more();
+ });
+ // event: writing in textarea
+ this.$element.find('textarea.oe_mail_action_textarea').keyup(function (event) {
+ var charCode = (event.which) ? event.which : window.event.keyCode;
+ if (event.shiftKey && charCode == 13) { this.value = this.value+"\n"; }
+ else if (charCode == 13) { return self.do_comment(); }
+ });
+ // event: click on 'reply' in msg
+ this.$element.find('div.oe_mail_thread_display').delegate('a.oe_mail_msg_reply', 'click', function (event) {
+ var act_dom = $(this).parents('div.oe_mail_thread_display').find('div.oe_mail_thread_act:first');
+ act_dom.toggle();
+ event.preventDefault();
+ });
+ // event: click on 'delete' in msg
+ this.$element.find('div.oe_mail_thread_display').delegate('a.oe_mail_msg_delete', 'click', function (event) {
+ //console.log('deleting');
+ if (! confirm(_t("Do you really want to delete this message?"))) { return false; }
+ var msg_id = event.srcElement.dataset.id;
+ if (! msg_id) return false;
+ var call_defer = self.ds_msg.unlink([parseInt(msg_id)]);
+ $(event.srcElement).parents('li.oe_mail_thread_msg').eq(0).hide();
+ if (self.params.thread_level > 0) {
+ $(event.srcElement).parents('ul.oe_mail_thread').eq(0).hide();
+ }
+ return false;
+ });
+ // event: click on 'hide' in msg
+ this.$element.find('div.oe_mail_thread_display').delegate('a.oe_mail_msg_hide', 'click', function (event) {
+ //console.log('hiding');
+ if (! confirm(_t("Do you really want to hide this thread ?"))) { return false; }
+ var msg_id = event.srcElement.dataset.id;
+ if (! msg_id) return false;
+ //console.log(msg_id);
+ var call_defer = self.ds.call('message_remove_pushed_notifications', [[self.params.res_id], [parseInt(msg_id)], true]);
+ $(event.srcElement).parents('li.oe_mail_thread_msg').eq(0).hide();
+ if (self.params.thread_level > 0) {
+ $(event.srcElement).parents('ul.oe_mail_thread').eq(0).hide();
+ }
+ return false;
+ });
+ // event: click on an internal link
+ this.$element.find('div.oe_mail_thread_display').delegate('a.intlink', 'click', function (event) {
+ // lazy implementation: fetch data and try to redirect
+ if (! event.srcElement.dataset.resModel) return false;
+ else var res_model = event.srcElement.dataset.resModel;
+ var res_login = event.srcElement.dataset.resLogin;
+ var res_id = event.srcElement.dataset.resId;
+ if ((! res_login) && (! res_id)) return false;
+ if (! res_id) {
+ var ds = new session.web.DataSet(self, res_model);
+ var defer = ds.call('search', [[['login', '=', res_login]]]).then(function (records) {
+ if (records[0]) {
+ self.do_action({ type: 'ir.actions.act_window', res_model: res_model, res_id: parseInt(records[0]), views: [[false, 'form']]});
+ }
+ else return false;
+ });
+ }
+ else self.do_action({ type: 'ir.actions.act_window', res_model: res_model, res_id: parseInt(res_id), views: [[false, 'form']]});
+ });
+ },
+
+ destroy: function () {
+ this._super.apply(this, arguments);
+ },
+
+ init_comments: function() {
+ var self = this;
+ this.params.offset = 0;
+ this.sorted_comments = {'root_ids': [], 'root_id_msg_list': {}};
+ this.comments_structure = {'root_ids': [], 'new_root_ids': [], 'msgs': {}, 'tree_struct': {}, 'model_to_root_ids': {}};
+ this.$element.find('div.oe_mail_thread_display').empty();
+ domain = this.get_fetch_domain(this.sorted_comments);
+ return this.fetch_comments(this.params.limit, this.params.offset, domain).then();
+ },
+
+ fetch_comments: function (limit, offset, domain) {
+ var self = this;
+ var defer = this.ds.call('message_load', [[this.params.res_id], ( (limit+1)||(this.params.limit+1) ), (offset||this.params.offset), (domain||[]), (this.params.thread_level > 0), (this.sorted_comments['root_ids'])]);
+ $.when(defer).then(function (records) {
+ if (records.length <= self.params.limit) self.display.show_more = false;
+ else { self.display.show_more = true; records.pop(); }
+ self.display_comments(records);
+ if (self.display.show_more == true) self.$element.find('div.oe_mail_thread_more:last').show();
+ else self.$element.find('div.oe_mail_thread_more:last').hide();
+ });
+ return defer;
+ },
+
+ display_comments_from_parameters: function (records) {
+ if (records.length > 0 && records.length < (records[0].child_ids.length+1) ) this.display.show_more = true;
+ else this.display.show_more = false;
+ var defer = this.display_comments(records);
+ if (this.display.show_more == true) $('div.oe_mail_thread_more').eq(-2).show();
+ else $('div.oe_mail_thread_more').eq(-2).hide();
+ return defer;
+ },
+
+ display_comments: function (records) {
+ var self = this;
+ this.cs = this.sort_comments_tmp(records);
+
+ /* WIP: map matched regexp -> records to browse with name */
+ //_(records).each(function (record) {
+ //self.do_check_internal_links(record.body_text);
+ //});
+
+ _(records).each(function (record) {
+ var sub_msgs = [];
+ if ((record.parent_id == false || record.parent_id[0] == self.params.parent_id) && self.params.thread_level > 0 ) {
+ var sub_list = self.cs['tree_struct'][record.id]['direct_childs'];
+ _(records).each(function (record) {
+ //if (record.parent_id == false || record.parent_id[0] == self.params.parent_id) return;
+ if (_.indexOf(sub_list, record.id) != -1) {
+ sub_msgs.push(record);
+ }
+ });
+ self.display_comment(record);
+ self.thread = new mail.Thread(self, {'res_model': self.params.res_model, 'res_id': self.params.res_id, 'uid': self.params.uid,
+ 'records': sub_msgs, 'thread_level': (self.params.thread_level-1), 'parent_id': record.id});
+ self.$element.find('li.oe_mail_thread_msg:last').append('<div class="oe_mail_thread_subthread"/>');
+ self.thread.appendTo(self.$element.find('div.oe_mail_thread_subthread:last'));
+ }
+ else if (self.params.thread_level == 0) {
+ self.display_comment(record);
+ }
+ });
+ // update offset for "More" buttons
+ if (this.params.thread_level == 0) this.params.offset += records.length;
+ },
+
+ /**
+ * Display a record
+ */
+ display_comment: function (record) {
+ if (record.type == 'email') { record.mini_url = ('/mail/static/src/img/email_icon.png'); }
+ else { record.mini_url = this.thread_get_avatar('res.users', 'avatar', record.user_id[0]); }
+ // body text manipulation
+ record.body = this.do_clean_text(record.body);
+ record.tr_body = this.do_truncate_string(record.body, this.params.msg_more_limit);
+ record.body = this.do_replace_internal_links(record.body);
+ if (record.tr_body) record.tr_body = this.do_replace_internal_links(record.tr_body);
+ // format date according to the user timezone
+ record.date = session.web.format_value(record.date, {type:"datetime"});
+ // render
+ $(session.web.qweb.render('ThreadMsg', {'record': record, 'thread': this, 'params': this.params, 'display': this.display})
+ ).appendTo(this.$element.children('div.oe_mail_thread_display:first'));
+ // truncated: hide full-text, show summary, add buttons
+ if (record.tr_body) {
+ var node_body = this.$element.find('span.oe_mail_msg_body:last').append(' <a href="#" class="reduce">[ ... Show less]</a>');
+ var node_body_short = this.$element.find('span.oe_mail_msg_body_short:last').append(' <a href="#" class="expand">[ ... Show more]</a>');
+ node_body.hide();
+ node_body.find('a:last').click(function() { node_body.hide(); node_body_short.show(); return false; });
+ node_body_short.find('a:last').click(function() { node_body_short.hide(); node_body.show(); return false; });
+ }
+ },
+
+ /**
+ * Add records to sorted_comments array
+ * @param {Array} records records from mail.message sorted by date desc
+ * @returns {Object} sc sorted_comments: dict {
+ * 'root_id_list': list or root_ids
+ * 'root_id_msg_list': {'record_id': [ancestor_ids]}, still sorted by date desc
+ * 'id_to_root': {'root_id': [records]}, still sorted by date desc
+ * }
+ */
+ sort_comments: function (records) {
+ var self = this;
+ sc = {'root_id_list': [], 'root_id_msg_list': {}, 'id_to_root': {}}
+ var cur_iter = 0; var max_iter = 10; var modif = true;
+ /* step1: get roots */
+ while ( modif && (cur_iter++) < max_iter) {
+ modif = false;
+ _(records).each(function (record) {
+ if ( (record.parent_id == false || record.parent_id[0] == self.params.parent_id) && (_.indexOf(sc['root_id_list'], record.id) == -1)) {
+ sc['root_id_list'].push(record.id);
+ sc['root_id_msg_list'][record.id] = [];
+ self.sorted_comments['root_ids'].push(record.id);
+ modif = true;
+ }
+ else {
+ if (_.indexOf(sc['root_id_list'], record.parent_id[0]) != -1) {
+ sc['id_to_root'][record.id] = record.parent_id[0];
+ modif = true;
+ }
+ else if ( sc['id_to_root'][record.parent_id[0]] ) {
+ sc['id_to_root'][record.id] = sc['id_to_root'][record.parent_id[0]];
+ modif = true;
+ }
+ }
+ });
+ }
+ /* step2: add records */
+ _(records).each(function (record) {
+ var root_id = sc['id_to_root'][record.id];
+ if (! root_id) return;
+ sc['root_id_msg_list'][root_id].push(record);
+ //self.sorted_comments['root_id_msg_list'][root_id].push(record.id);
+ });
+ return sc;
+ },
+
+ /**
+ * Add records to comments_structure object: see function for details
+ */
+ sort_comments_tmp: function(records) {
+ return tools_sort_comments(this.comments_structure, records, this.params.parent_id);
+ },
+
+ display_current_user: function () {
+ return this.$element.find('img.oe_mail_msg_image').attr('src', this.thread_get_avatar('res.users', 'avatar', this.params.uid));
+ },
+
+ do_comment: function () {
+ var comment_node = this.$element.find('textarea');
+ var body_text = comment_node.val();
+ comment_node.val('');
+ return this.ds.call('message_append_note', [[this.params.res_id], 'Reply', body_text, this.params.parent_id, 'comment', 'html']).then(
+ this.proxy('init_comments'));
+ },
+
+ /**
+ * Create a domain to fetch new comments according to
+ * comment already present in sorted_comments
+ * @param {Object} sorted_comments (see sort_comments)
+ * @returns {Array} fetch_domain (OpenERP domain style)
+ */
+ get_fetch_domain: function (sorted_comments) {
+ var domain = [];
+ var ids = sorted_comments.root_ids.slice();
+ var ids2 = [];
+ // must be child of current parent
+ if (this.params.parent_id) { domain.push(['id', 'child_of', this.params.parent_id]); }
+ _(sorted_comments.root_ids).each(function (id) { // each record
+ ids.push(id);
+ ids2.push(id);
+ });
+ if (this.params.parent_id != false) {
+ ids2.push(this.params.parent_id);
+ }
+ // must not be children of already fetched messages
+ if (ids.length > 0) {
+ domain.push('&');
+ domain.push('!');
+ domain.push(['id', 'child_of', ids]);
+ }
+ if (ids2.length > 0) {
+ domain.push(['id', 'not in', ids2]);
+ }
+ return domain;
+ },
+
+ do_more: function () {
+ domain = this.get_fetch_domain(this.sorted_comments);
+ return this.fetch_comments(this.params.limit, this.params.offset, domain);
+ },
+
+ /**
+ *
+ * var regex_login = new RegExp(/(^|\s)@((\w|@|\.)*)/g);
+ * var regex_intlink = new RegExp(/(^|\s)#(\w*[a-zA-Z_]+\w*)\.(\w+[a-zA-Z_]+\w*),(\w+)/g);
+ */
+ do_replace_internal_links: function (string) {
+ var self = this;
+ var icon_list = ['al', 'pinky']
+ /* shortcut to user: @login */
+ var regex_login = new RegExp(/(^|\s)@((\w|@|\.)*)/g);
+ var regex_res = regex_login.exec(string);
+ while (regex_res != null) {
+ var login = regex_res[2];
+ string = string.replace(regex_res[0], regex_res[1] + '<a href="#" class="intlink oe_mail_oe_intlink" data-res-model="res.users" data-res-login = ' + login + '>@' + login + '</a>');
+ regex_res = regex_login.exec(string);
+ }
+ /* special shortcut: :name, try to find an icon if in list */
+ var regex_login = new RegExp(/(^|\s):((\w)*)/g);
+ var regex_res = regex_login.exec(string);
+ while (regex_res != null) {
+ var icon_name = regex_res[2];
+ if (_.include(icon_list, icon_name))
+ string = string.replace(regex_res[0], regex_res[1] + '<img src="/mail/static/src/img/_' + icon_name + '.png" width="22px" height="22px" alt="' + icon_name + '"/>');
+ regex_res = regex_login.exec(string);
+ }
+ return string;
+ },
+
+ thread_get_avatar: function(model, field, id) {
+ return this.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || '');
+ },
+
+ do_truncate_string: function(string, max_length) {
+ if (string.length <= (max_length * 1.2)) return false;
+ else return string.slice(0, max_length);
+ },
+
+ do_clean_text: function (string) {
+ var html = $('<div/>').text(string.replace(/\s+/g, ' ')).html().replace(new RegExp('&lt;(/)?(b|em)\\s*&gt;', 'gi'), '<$1$2>');
+ return html;
+ },
+
+ /**
+ *
+ * var regex_login = new RegExp(/(^|\s)@((\w|@|\.)*)/g);
+ * var regex_intlink = new RegExp(/(^|\s)#(\w*[a-zA-Z_]+\w*)\.(\w+[a-zA-Z_]+\w*),(\w+)/g);
+ */
+ do_check_internal_links: function(string) {
+ /* shortcut to user: @login */
+ var regex_login = new RegExp(/(^|\s)@((\w|@|\.)*)/g);
+ var regex_res = regex_login.exec(string);
+ while (regex_res != null) {
+ var login = regex_res[2];
+ if (! ('res.users' in this.map_hash)) { this.map_hash['res.users']['name'] = []; }
+ this.map_hash['res.users']['login'].push(login);
+ regex_res = regex_login.exec(string);
+ }
+ /* internal links: #res.model,name */
+ var regex_intlink = new RegExp(/(^|\s)#(\w*[a-zA-Z_]+\w*)\.(\w+[a-zA-Z_]+\w*),(\w+)/g);
+ regex_res = regex_intlink.exec(string);
+ while (regex_res != null) {
+ var res_model = regex_res[2] + '.' + regex_res[3];
+ var res_name = regex_res[4];
+ if (! (res_model in this.map_hash)) { this.map_hash[res_model]['name'] = []; }
+ this.map_hash[res_model]['name'].push(res_name);
+ regex_res = regex_intlink.exec(string);
+ }
+ },
+
+ /** checks if tue current user is the message author */
+ _is_author: function (id) {
+ return (this.session.uid == id);
+ },
+
+ });
+
+
+ /* Add ThreadView widget to registry */
+ session.web.form.widgets.add( 'ThreadView', 'openerp.mail.RecordThread');
+// session.web.page.readonly.add( 'ThreadView', 'openerp.mail.RecordThread');
+
+ /* ThreadView widget: thread of comments */
+ mail.RecordThread = session.web.form.AbstractField.extend({
+ // QWeb template to use when rendering the object
+ template: 'RecordThread',
+
+ init: function() {
+ this._super.apply(this, arguments);
+ this.see_subscribers = true;
+ this.thread = null;
+ // datasets
+ this.ds = new session.web.DataSet(this, this.view.model);
+ this.ds_users = new session.web.DataSet(this, 'res.users');
+ },
+
+ start: function() {
+ this._super.apply(this, arguments);
+ var self = this;
+ // bind buttons
+ this.$element.find('button.oe_mail_button_followers').click(function () { self.do_toggle_followers(); }).hide();
+ this.$element.find('button.oe_mail_button_follow').click(function () { self.do_follow(); })
+ .mouseover(function () { $(this).html('Follow').removeClass('oe_mail_button_mouseout').addClass('oe_mail_button_mouseover'); })
+ .mouseleave(function () { $(this).html('Not following').removeClass('oe_mail_button_mouseover').addClass('oe_mail_button_mouseout'); });
+ this.$element.find('button.oe_mail_button_unfollow').click(function () { self.do_unfollow(); })
+ .mouseover(function () { $(this).html('Unfollow').removeClass('oe_mail_button_mouseout').addClass('oe_mail_button_mouseover'); })
+ .mouseleave(function () { $(this).html('Following').removeClass('oe_mail_button_mouseover').addClass('oe_mail_button_mouseout'); });
+ this.reinit();
+ },
+
+ destroy: function () {
+ this._super.apply(this, arguments);
+ },
+
+ reinit: function() {
+ this.see_subscribers = true;
+ this.$element.find('button.oe_mail_button_followers').html('Hide followers')
+ this.$element.find('button.oe_mail_button_follow').hide();
+ this.$element.find('button.oe_mail_button_unfollow').hide();
+ },
+
+ set_value: function() {
+ this._super.apply(this, arguments);
+ var self = this;
+ this.reinit();
+ if (! this.view.datarecord.id) { this.$element.find('ul.oe_mail_thread').hide(); return; }
+ // fetch followers
+ var fetch_sub_done = this.fetch_subscribers();
+ // create and render Thread widget
+ this.$element.find('div.oe_mail_recthread_left').empty();
+ if (this.thread) this.thread.destroy();
+ // hack: for groups and users
+ if (this.view.model == 'mail.group') thread_level = 1;
+ if (this.view.model == 'res.users') thread_level = 1;
+ else thread_level = 0;
+ this.thread = new mail.Thread(this, {'res_model': this.view.model, 'res_id': this.view.datarecord.id, 'uid': this.session.uid,
+ 'thread_level': thread_level, 'show_post_comment': true, 'limit': 15});
+ var thread_done = this.thread.appendTo(this.$element.find('div.oe_mail_recthread_left'));
+ return fetch_sub_done && thread_done;
+ },
+
+ fetch_subscribers: function () {
+ return this.ds.call('message_get_subscribers', [[this.view.datarecord.id]]).then(this.proxy('display_subscribers'));
+ },
+
+ display_subscribers: function (records) {
+ var self = this;
+ this.is_subscriber = false;
+ var sub_node = this.$element.find('div.oe_mail_recthread_followers')
+ sub_node.empty();
+ $('<h4/>').html('Followers (' + records.length + ')').appendTo(sub_node);
+ _(records).each(function (record) {
+ if (record.id == self.session.uid) { self.is_subscriber = true; }
+ var mini_url = self.thread_get_avatar('res.users', 'avatar', record.id);
+ $('<img class="oe_mail_oe_left oe_mail_msg_image" src="' + mini_url + '" title="' + record.name + '" alt="' + record.name + '"/>').appendTo(sub_node);
+ });
+ if (self.is_subscriber) {
+ self.$element.find('button.oe_mail_button_follow').hide();
+ self.$element.find('button.oe_mail_button_unfollow').show(); }
+ else {
+ self.$element.find('button.oe_mail_button_follow').show();
+ self.$element.find('button.oe_mail_button_unfollow').hide(); }
+ },
+
+ do_follow: function () {
+ return this.ds.call('message_subscribe', [[this.view.datarecord.id]]).pipe(this.proxy('fetch_subscribers'));
+ },
+
+ do_unfollow: function () {
+ var self = this;
+ return this.ds.call('message_unsubscribe', [[this.view.datarecord.id]]).then(function (record) {
+ if (record == false) self.do_notify("Impossible to unsubscribe", "You are automatically subscribed to this record. You cannot unsubscribe.");
+ }).pipe(this.proxy('fetch_subscribers'));
+ },
+
+ do_toggle_followers: function () {
+ this.see_subscribers = ! this.see_subscribers;
+ if (this.see_subscribers) { this.$element.find('button.oe_mail_button_followers').html('Hide followers'); }
+ else { this.$element.find('button.oe_mail_button_followers').html('Display followers'); }
+ this.$element.find('div.oe_mail_recthread_followers').toggle();
+ },
+
+ thread_get_avatar: function(model, field, id) {
+ return this.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || '');
+ },
+ });
+
+
+ /* Add WallView widget to registry */
+ session.web.client_actions.add('mail.all_feeds', 'session.mail.WallView');
+
+ /* WallView widget: a wall of messages */
+ mail.WallView = session.web.Widget.extend({
+ template: 'Wall',
+
+ /**
+ * @param {Object} parent parent
+ * @param {Object} [params]
+ * @param {Number} [params.limit=20] number of messages to show and fetch
+ * @param {Number} [params.search_view_id=false] search view id for messages
+ * @var {Array} sorted_comments records sorted by res_model and res_id
+ * records.res_model = {res_ids}
+ * records.res_model.res_id = [records]
+ */
+ init: function (parent, params) {
+ this._super(parent);
+ this.params = {};
+ this.params.limit = params.limit || 25;
+ this.params.domain = params.domain || [];
+ this.params.context = params.context || {};
+ this.params.search_view_id = params.search_view_id || false;
+ this.params.thread_level = params.thread_level || 1;
+ this.comments_structure = {'root_ids': [], 'new_root_ids': [], 'msgs': {}, 'tree_struct': {}, 'model_to_root_ids': {}};
+ this.display_show_more = true;
+ this.thread_list = [];
+ this.search = {'domain': [], 'context': {}, 'groupby': {}}
+ this.search_results = {'domain': [], 'context': {}, 'groupby': {}}
+ // datasets
+ this.ds_msg = new session.web.DataSet(this, 'mail.message');
+ this.ds_thread = new session.web.DataSet(this, 'mail.thread');
+ this.ds_users = new session.web.DataSet(this, 'res.users');
+ },
+
+ start: function () {
+ this._super.apply(this, arguments);
+ var self = this;
+ // add events
+ this.add_event_handlers();
+ // load mail.message search view
+ var search_view_ready = this.load_search_view(this.params.search_view_id, {}, false);
+ // fetch first threads
+ var comments_ready = this.init_and_fetch_comments(this.params.limit, 0);
+ return (search_view_ready && comments_ready);
+ },
+
+ stop: function () {
+ this._super.apply(this, arguments);
+ },
+
+ /** Add events */
+ add_event_handlers: function () {
+ var self = this;
+ // post a comment
+ this.$element.find('button.oe_mail_wall_button_comment').click(function () { return self.do_comment(); });
+ // display more threads
+ this.$element.find('button.oe_mail_wall_button_more').click(function () { return self.do_more(); });
+ },
+
+ /**
+ * Loads the mail.message search view
+ * @param {Number} view_id id of the search view to load
+ * @param {Object} defaults ??
+ * @param {Boolean} hidden some kind of trick we do not care here
+ */
+ load_search_view: function (view_id, defaults, hidden) {
+ var self = this;
+ this.searchview = new session.web.SearchView(this, this.ds_msg, view_id || false, defaults || {}, hidden || false);
+ var search_view_loaded = this.searchview.appendTo(this.$element.find('.oe_view_manager_row'));
+ return $.when(search_view_loaded).then(function () {
+ self.searchview.on_search.add(self.do_searchview_search);
+ });
+ },
+
+ /**
+ * Aggregate the domains, contexts and groupbys in parameter
+ * with those from search form, and then calls fetch_comments
+ * to actually fetch comments
+ * @param {Array} domains
+ * @param {Array} contexts
+ * @param {Array} groupbys
+ */
+ do_searchview_search: function(domains, contexts, groupbys) {
+ var self = this;
+ this.rpc('/web/session/eval_domain_and_context', {
+ domains: domains || [],
+ contexts: contexts || [],
+ group_by_seq: groupbys || []
+ }, function (results) {
+ self.search_results['context'] = results.context;
+ self.search_results['domain'] = results.domain;
+ self.search_results['groupby'] = results.group_by;
+ return self.init_and_fetch_comments();
+ });
+ },
+
+ /**
+ * Initializes the wall and calls fetch_comments
+ * @param {Number} limit: number of notifications to fetch
+ * @param {Number} offset: offset in notifications search
+ * @param {Array} domain
+ * @param {Array} context
+ */
+ init_and_fetch_comments: function() {
+ this.search['domain'] = _.union(this.params.domain, this.search_results.domain);
+ this.search['context'] = _.extend(this.params.context, this.search_results.context);
+ this.display_show_more = true;
+ this.comments_structure = {'root_ids': [], 'new_root_ids': [], 'msgs': {}, 'tree_struct': {}, 'model_to_root_ids': {}};
+ this.$element.find('div.oe_mail_wall_threads').empty();
+ return this.fetch_comments(this.params.limit, 0);
+ },
+
+ /**
+ * Fetches wall messages
+ * @param {Number} limit: number of notifications to fetch
+ * @param {Number} offset: offset in notifications search
+ * @param {Array} domain
+ * @param {Array} context
+ */
+ fetch_comments: function (limit, offset, additional_domain, additional_context) {
+ var self = this;
+ if (additional_domain) var fetch_domain = this.search['domain'].concat(additional_domain);
+ else var fetch_domain = this.search['domain'];
+ if (additional_context) var fetch_context = _.extend(this.search['context'], additional_context);
+ else var fetch_context = this.search['context'];
+ return this.ds_thread.call('get_pushed_messages',
+ [[this.session.uid], (limit || 0), (offset || 0), fetch_domain, true, [], fetch_context]).then(this.proxy('display_comments'));
+ },
+
+ /**
+ * @param {Array} records records to show in threads
+ */
+ display_comments: function (records) {
+ var self = this;
+ this.do_update_show_more(records.length >= self.params.limit);
+ this.sort_comments(records);
+ _(this.comments_structure['new_root_ids']).each(function (root_id) {
+ var records = self.comments_structure.tree_struct[root_id]['for_thread_msgs'];
+ var model_name = self.comments_structure.msgs[root_id]['model'];
+ var res_id = self.comments_structure.msgs[root_id]['res_id'];
+ var render_res = session.web.qweb.render('WallThreadContainer', {});
+ $('<div class="oe_mail_wall_thread">').html(render_res).appendTo(self.$element.find('div.oe_mail_wall_threads'));
+ var thread = new mail.Thread(self, {
+ 'res_model': model_name, 'res_id': res_id, 'uid': self.session.uid, 'records': records,
+ 'parent_id': false, 'thread_level': self.params.thread_level, 'show_hide': true}
+ );
+ self.thread_list.push(thread);
+ return thread.appendTo(self.$element.find('div.oe_mail_wall_thread:last'));
+ });
+ // update TODO
+ this.comments_structure['root_ids'] = _.union(this.comments_structure['root_ids'], this.comments_structure['new_root_ids']);
+ this.comments_structure['new_root_ids'] = [];
+ },
+
+ /**
+ * Add records to comments_structure object: see function for details
+ */
+ sort_comments: function(records) {
+ tools_sort_comments(this.comments_structure, records, false);
+ },
+
+ /**
+ * Create a domain to fetch new comments according to
+ * comments already present in sorted_comments
+ * - for each model:
+ * -- should not be child of already displayed ids
+ * @param {Object} sorted_comments (see sort_comments)
+ * @returns {Array} fetch_domain (OpenERP domain style)
+ */
+ get_fetch_domain: function () {
+ var self = this;
+ var model_to_root = {};
+ var fetch_domain = [];
+ _(this.comments_structure['model_to_root_ids']).each(function (sc_model, model_name) {
+ fetch_domain.push('|', ['model', '!=', model_name], '!', ['id', 'child_of', sc_model]);
+ });
+ return fetch_domain;
+ },
+
+ /** Display update: show more button */
+ do_update_show_more: function (new_value) {
+ if (new_value != undefined) this.display_show_more = new_value;
+ if (this.display_show_more) this.$element.find('div.oe_mail_wall_more:last').show();
+ else this.$element.find('div.oe_mail_wall_more:last').hide();
+ },
+
+ /** Action: Shows more discussions */
+ do_more: function () {
+ var domain = this.get_fetch_domain();
+ return this.fetch_comments(this.params.limit, 0, domain);
+ },
+
+ /** Action: Posts a comment */
+ do_comment: function () {
+ var comment_node = this.$element.find('textarea.oe_mail_wall_action_textarea');
+ var body_text = comment_node.val();
+ comment_node.val('');
+ var call_done = this.ds_users.call('message_append_note', [[this.session.uid], 'Tweet', body_text, false, 'comment', 'html']).then(this.proxy('init_and_fetch_comments'));
+ },
+ });
+};
+
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml
new file mode 100644
index 00000000000..f034b04311d
--- /dev/null
+++ b/addons/mail/static/src/xml/mail.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template>
+
+ <div t-name="Wall" class="oe_mail_wall">
+ <div class="oe_view_manager_header">
+ <div class="oe_view_manager_row">
+ <h2 class="oe_view_title">All Feeds</h2>
+ </div>
+ </div>
+ <div class="oe_mail_wall_left">
+ <div class="oe_mail_wall_act">
+ <textarea class="oe_mail oe_mail_wall_action_textarea" placeholder="Add a personnal message here..."/>
+ <button class="oe_mail_oe_right oe_mail_wall_button_comment" type="button">Post comment</button>
+ </div>
+ <div class="oe_clear"></div>
+ <div class="oe_mail_wall_threads">
+ </div>
+ <div class="oe_mail_wall_more">
+ <button class="oe_mail_wall_button_more" type="button">See more discussions</button>
+ </div>
+ </div>
+ <div class="oe_mail_wall_right"></div>
+ </div>
+
+ <t t-name="WallThreadContainer">
+ </t>
+
+ <div t-name="RecordThread" class="oe_mail_recthread">
+ <h4>History and Comments</h4>
+ <div class="oe_mail_recthread_left">
+ </div>
+ <div class="oe_mail_recthread_right">
+ <div class="oe_mail_recthread_actions">
+ <button type="button" class="oe_mail_button_follow oe_mail_button_mouseout">Not following</button>
+ <button type="button" class="oe_mail_button_unfollow oe_mail_button_mouseout">Following</button>
+ <button type="button" class="oe_mail_button_followers">Display followers</button>
+ </div>
+ <div class="oe_mail_recthread_followers">
+ <h4>Followers</h4>
+ <div class="oe_mail_followers_display">
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <ul t-name="Thread" class="oe_mail oe_mail_thread">
+ <div class="oe_mail_thread_act">
+ <img class="oe_mail_msg_image oe_mail_oe_left" alt="User img"/>
+ <div class="oe_mail_msg_content">
+ <textarea class="oe_mail oe_mail_action_textarea" placeholder="Add your comment here..." onfocus="this.value = '';"/><br />
+ </div>
+ </div>
+ <div class="oe_mail_thread_display"></div>
+ <div class="oe_mail_thread_more">
+ <button class="oe_mail_button_more" type="button">Load more messages</button>
+ </div>
+ </ul>
+
+ <li t-name="ThreadMsg" t-attf-class="oe_mail oe_mail_thread_msg">
+ <div t-attf-class="oe_mail_msg_#{record.type}">
+ <img class="oe_mail_msg_image oe_mail_oe_left" t-att-src="record.mini_url"/>
+ <div class="oe_mail_msg_content">
+ <t t-if="record.type == 'email'"><t t-call="EmailDisplay" /></t>
+ <t t-if="record.type == 'notification' || record.type == 'comment'"><t t-call="NoteDisplay" /></t>
+ </div>
+ <t t-if="record.type == 'tmp'"><t t-call="ThreadDisplay" /></t>
+ </div>
+ </li>
+
+ <t t-name="NoteDisplay">
+ <p class="oe_mail_msg">
+ <t t-if="params.thread_level > 0">
+ <a href="#" class="intlink oe_mail_oe_intlink" t-attf-data-res-model='{params.res_model}' t-attf-data-res-id='{params.res_id}'><t t-raw="record.record_name"/></a>
+ </t>
+ <span class="oe_mail_msg_body"><t t-raw="record.body"/></span>
+ <t t-if="record.tr_body"><span class="oe_mail_msg_body_short"><t t-raw="record.tr_body"/></span></t>
+ <br />
+ <span class="oe_mail_oe_fade">
+ <a href="#" class="intlink oe_mail_oe_intlink" data-res-model='res.users' t-attf-data-res-id='{record.user_id[0]}'><t t-raw="record.user_id[1]"/></a>
+ on <t t-raw="record.date"/>
+ </span>
+ <t t-if="display['show_reply']"><a href="#" class="oe_mail_oe_space oe_mail_msg_reply oe_mail_oe_intlink"> Reply</a> </t>
+ <t t-if="display['show_delete']">
+ <t t-if="thread._is_author(record.user_id[0])"><a href="#" t-attf-data-id='{record.id}' class="oe_mail_oe_space oe_mail_msg_delete oe_mail_oe_intlink"> Delete </a></t>
+ </t>
+ <t t-if="display['show_hide']">
+ <t t-if="!(thread._is_author(record.user_id[0]))"><a href="#" t-attf-data-id='{record.id}' class="oe_mail_oe_space oe_mail_msg_hide oe_mail_oe_intlink">Hide</a></t>
+ </t>
+ </p>
+ </t>
+
+ <t t-name="EmailDisplay">
+ <p class="oe_mail_msg oe_mail_msg_p_email_header">
+ <t t-if="params.thread_level > 0">
+ <a href="#" class="intlink oe_mail_oe_intlink" t-attf-data-res-model='{params.res_model}' t-attf-data-res-id='{params.res_id}'><t t-raw="record.record_name"/></a>
+ </t>
+ <br />
+ <span class="oe_mail_oe_bold">From:</span> <t t-esc="record.email_from"/> on <span class="oe_mail_oe_fade"><t t-raw="record.date"/></span><br />
+ <span class="oe_mail_oe_bold">To:</span> <t t-esc="record.email_to"/><br />
+ <span class="oe_mail_oe_bold">Subject:</span> <t t-esc="record.subject"/><br />
+ </p>
+ <p class="oe_mail_msg">
+ <span class="oe_mail_msg_body"><t t-raw="record.body"/></span>
+ <t t-if="record.tr_body"><span class="oe_mail_msg_body_short"><t t-raw="record.tr_body"/></span></t>
+ <br />
+ <t t-if="display['show_delete']">
+ <t t-if="thread._is_author(record.user_id[0])"><a href="#" t-attf-data-id='{record.id}' class="oe_mail_msg_delete oe_mail_oe_intlink"> Delete </a></t>
+ </t>
+ <t t-if="display['show_hide']">
+ <t t-if="!(thread._is_author(record.user_id[0]))"><span class="oe_mail_oe_space"><a href="#" t-attf-data-id='{record.id}' class="oe_mail_msg_hide oe_mail_oe_intlink">Hide</a></span></t>
+ </t>
+ </p>
+ </t>
+
+</template>