summaryrefslogtreecommitdiff
path: root/addons/website_mail/static/src
diff options
context:
space:
mode:
authorJérome Maes <jem@openerp.com>2016-12-26 11:32:25 +0100
committerJérome Maes <jem@openerp.com>2017-06-30 11:06:32 +0200
commitd79678fdd5faccffff65a439653fa5d639a3d3c4 (patch)
tree7cb3f4a849289dbae3983daefea02c6cbbd21467 /addons/website_mail/static/src
parent890e665b882b27184003cc5de6ad365f2910815d (diff)
[IMP] website_mail: make the frontend chatter lazy
Message are now fetched and display using javascript to optimize performance. Also the chatter is completely rewrite : add pager, filter possiblity, ... This commit is mainly technical: posting feature does not change. Only the display with pager is new. The goal is also to prepare frontend chatter for a better integration with rating widget. The mail.thread mixin is extended to manage the field website_message_ids (display all messages that can be seen on frontend by user (employee or not). When fetching or posting message, a check is done to see if we need to do it as sudo(). website_mail implement posting messages with token or sha_in (using in website_quote). The same verification is now done when fetching messages, via '_special_access_object' method.
Diffstat (limited to 'addons/website_mail/static/src')
-rw-r--r--addons/website_mail/static/src/css/website_mail.css4
-rw-r--r--addons/website_mail/static/src/css/website_mail.less38
-rw-r--r--addons/website_mail/static/src/js/message_post.js80
-rw-r--r--addons/website_mail/static/src/js/website_mail.js232
-rw-r--r--addons/website_mail/static/src/xml/chatter_message.xml15
-rw-r--r--addons/website_mail/static/src/xml/website_mail.xml132
6 files changed, 402 insertions, 99 deletions
diff --git a/addons/website_mail/static/src/css/website_mail.css b/addons/website_mail/static/src/css/website_mail.css
deleted file mode 100644
index 5678442416c..00000000000
--- a/addons/website_mail/static/src/css/website_mail.css
+++ /dev/null
@@ -1,4 +0,0 @@
-.js_follow[data-follow='on'] .js_follow_btn ,
-.js_follow[data-follow='off'] .js_unfollow_btn {
- display: none;
-} \ No newline at end of file
diff --git a/addons/website_mail/static/src/css/website_mail.less b/addons/website_mail/static/src/css/website_mail.less
new file mode 100644
index 00000000000..dda250e65e5
--- /dev/null
+++ b/addons/website_mail/static/src/css/website_mail.less
@@ -0,0 +1,38 @@
+.js_follow[data-follow='on'] .js_follow_btn ,
+.js_follow[data-follow='off'] .js_unfollow_btn {
+ display: none;
+}
+
+.o_website_mail_chatter {
+ padding: 10px;
+
+ .o_website_mail_avatar{
+ width: 45px;
+ height: 45px;
+ }
+
+ .o_website_mail_header {
+ margin-bottom: 15px;
+ }
+
+ .o_website_mail_composer {
+ margin-bottom: 15px;
+ }
+
+ .o_website_mail_messages {
+ margin-bottom: 15px;
+
+ .o_website_mail_message_title {
+ p {
+ font-size:85%;
+ color:@odoo-main-color-muted;
+ margin: 0px;
+ }
+ }
+
+ }
+
+ .o_website_mail_pager {
+ text-align: center;
+ }
+}
diff --git a/addons/website_mail/static/src/js/message_post.js b/addons/website_mail/static/src/js/message_post.js
deleted file mode 100644
index 2e93e8708a0..00000000000
--- a/addons/website_mail/static/src/js/message_post.js
+++ /dev/null
@@ -1,80 +0,0 @@
-odoo.define('website_mail.thread', function(require) {
- 'use strict';
-
- var web_editor_base = require('web_editor.base');
- var ajax = require('web.ajax');
- var core = require('web.core');
- var Widget = require('web.Widget');
-
- var qweb = core.qweb;
-
- // load qweb template
- ajax.loadXML('/website_mail/static/src/xml/chatter_message.xml', qweb);
-
- /**
- * Widget WebsiteMailThread
- *
- * Widget sending message to the server, using json request. Used to not refresh all
- * the page. Its DOM already exists on the page (The class of root element is
- * '.o_website_mail_thread').
- */
- var WebsiteMailThread = Widget.extend({
- events:{
- "click .o_website_chatter_json": "on_click",
- },
- on_click: function(e){
- var self = this;
- e.preventDefault();
-
- var $button = this.$(e.currentTarget);
- var $form = this.$('.o_website_chatter_form');
- var $error = this.$('.o_website_chatter_error');
- var action = $form.attr('action');
- var data = this._get_form_data($form);
-
- data.message = data.message.replace(/\n/g,"<br/>");
- if (data.message) {
- // make the 'send' button loading
- $button.attr('disabled', true);
- var button_bk = $button.html();
- $button.prepend('<i class="fa fa-refresh fa-spin"></i> ');
- // post message, shw/hide error message and empty textarea
- ajax.jsonRpc(action, 'call', data).then(function (result) {
- if (result) {
- $error.fadeOut();
- self.prepend_message(result);
- $form.find('textarea').val('');
- } else {
- $error.fadeIn();
- }
- $button.html(button_bk);
- $button.attr('disabled', false);
- });
- }
- },
- prepend_message: function(message_data){
- var msg = qweb.render('website_mail.thread_message', message_data);
- var elem = $(msg).hide().prependTo(this.$('.o_website_comments'));
- elem.slideToggle();
- return elem;
- },
- _get_form_data: function($form){
- var unindexed_array = $form.serializeArray();
- var indexed_array = {};
- $.map(unindexed_array, function(n, i){
- indexed_array[n.name] = n.value;
- });
- return indexed_array;
- },
- });
-
- web_editor_base.ready().then(function(){
- if($('.o_website_mail_thread').length) {
- var mail_thread = new WebsiteMailThread($('body')).setElement($('.o_website_mail_thread'));
- }
- });
-
- return {
- WebsiteMailThread: WebsiteMailThread,
- }
-});
diff --git a/addons/website_mail/static/src/js/website_mail.js b/addons/website_mail/static/src/js/website_mail.js
new file mode 100644
index 00000000000..ef43190c529
--- /dev/null
+++ b/addons/website_mail/static/src/js/website_mail.js
@@ -0,0 +1,232 @@
+odoo.define('website_mail.thread', function(require) {
+ 'use strict';
+
+ var web_editor_base = require('web_editor.base');
+ var ajax = require('web.ajax');
+ var core = require('web.core');
+ var Widget = require('web.Widget');
+ var rpc = require('web.rpc');
+
+ var qweb = core.qweb;
+ var _t = core._t;
+
+ /**
+ * Widget WebsiteMailThread
+ *
+ * - Fetch message fron controller
+ * - Display chatter: pager, total message, composer (according to access right)
+ * - Provider API to filter displayed messages
+ */
+ var WebsiteMailThread = Widget.extend({
+ template: 'website_mail.chatter',
+ events: {
+ "click .o_website_mail_pager_btn": '_onClickPager'
+ },
+
+ init: function(parent, options){
+ this._super.apply(this, arguments);
+ this.options = _.defaults(options || {}, {
+ 'allow_composer': true,
+ 'display_composer': false,
+ 'csrf_token': odoo.csrf_token,
+ 'message_count': 0,
+ 'pager_step': 10,
+ 'pager_scope': 5,
+ 'pager_start': 1,
+ 'is_user_public': true,
+ 'is_user_publisher': false,
+ 'domain': [],
+ });
+ this.set('messages', []);
+ this.set('message_count', this.options['message_count']);
+ this.set('current_page', this.options['pager_start']);
+ this.set('pager', {});
+ this.set('domain', this.options['domain']);
+ },
+ willStart: function(){
+ var self = this;
+ // load qweb template and init data
+ return $.when(
+ rpc.query({
+ route: '/website_mail/init',
+ params: this._messageFetchPrepareParams()
+ }), this._loadTemplates()
+ ).then(function(result){
+ // bind events
+ self.on("change:messages", self, self._renderMessages);
+ self.on("change:message_count", self, function(){
+ self._renderMessageCount();
+ self.set('pager', self._pager(self.get('current_page')));
+ });
+ self.on("change:pager", self, self._renderPager);
+ self.on("change:domain", self, self._onChangeDomain);
+ self.on("change:current_page", self, self._onChangeCurrentPage);
+ // set options and parameters
+ self.options = _.extend(self.options, result['options'] || {});
+ self.set('message_count', self.options['message_count']);
+ self.set('messages', self.preprocessMessages(result['messages']));
+ });
+ },
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * Fetch the messages and the message count from the server for the
+ * current page and current domain.
+ *
+ * @param {Array}
+ * @returns {Deferred}
+ */
+ messageFetch: function(domain){
+ var self = this;
+ return rpc.query({
+ route: '/website_mail/fetch',
+ params: self._messageFetchPrepareParams()
+ }).then(function(result){
+ self.set('messages', self.preprocessMessages(result['messages']));
+ self.set('message_count', result['message_count']);
+ });
+ },
+ /**
+ * Update the messages format
+ *
+ * @param {Array<Object>}
+ * @returns {Array}
+ */
+ preprocessMessages: function(messages){
+ _.each(messages, function(m){
+ m['author_avatar_url'] = _.str.sprintf('/web/image/%s/%s/author_avatar/50x50', 'mail.message', m.id);
+ m['published_date_str'] = _.str.sprintf(_t('Published on %s'), moment(m.date).format('MMMM Do YYYY, h:mm:ss a'));
+ });
+ return messages;
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @returns {Deferred}
+ */
+ _loadTemplates: function(){
+ return ajax.loadXML('/website_mail/static/src/xml/website_mail.xml', qweb);
+ },
+ _messageFetchPrepareParams: function(){
+ var self = this;
+ var data = {
+ 'res_model': this.options['res_model'],
+ 'res_id': this.options['res_id'],
+ 'limit': this.options['pager_step'],
+ 'offset': (this.get('current_page')-1) * this.options['pager_step'],
+ 'allow_composer': this.options['allow_composer'],
+ };
+ // add fields to allow to post comment without being logged
+ _.each(['token', 'token_field'], function(field){
+ if(self.options[field]){
+ data[field] = self.options[field];
+ }
+ });
+ // add domain
+ if(this.get('domain')){
+ data['domain'] = this.get('domain');
+ }
+ return ajax.jsonRpc('/website_mail/fetch', 'call', data).then(function(result){
+ self.set('messages', self.preprocessMessages(result['messages']));
+ self.set('message_count', result['message_count']);
+ });
+ },
+ /**
+ * Generate the pager data for the given page number
+ *
+ * @private
+ * @param {Number} page
+ * @returns {Object}
+ */
+ _pager: function(page){
+ var page = page || 1;
+ var total = this.get('message_count');
+ var scope = this.options['pager_scope'];
+ var step = this.options['pager_step'];
+
+ // Compute Pager
+ var page_count = Math.ceil(parseFloat(total) / step);
+
+ var page = Math.max(1, Math.min(parseInt(page), page_count));
+ scope -= 1;
+
+ var pmin = Math.max(page - parseInt(Math.floor(scope/2)), 1);
+ var pmax = Math.min(pmin + scope, page_count);
+
+ if(pmax - scope > 0){
+ pmin = pmax - scope;
+ }else{
+ pmin = 1;
+ }
+
+ var pages = [];
+ _.each(_.range(pmin, pmax+1), function(index){
+ pages.push(index);
+ });
+
+ return {
+ "page_count": page_count,
+ "offset": (page - 1) * step,
+ "page": page,
+ "page_start": pmin,
+ "page_previous": Math.max(pmin, page - 1),
+ "page_next": Math.min(pmax, page + 1),
+ "page_end": pmax,
+ "pages": pages
+ };
+ },
+ _renderMessages: function(){
+ this.$('.o_website_mail_messages').html(qweb.render("website_mail.chatter_messages", {widget: this}));
+ },
+ _renderMessageCount: function(){
+ this.$('.o_message_counter').replaceWith(qweb.render("website_mail.chatter_message_count", {widget: this}));
+ },
+ _renderPager: function(){
+ this.$('.o_website_mail_pager').replaceWith(qweb.render("website_mail.pager", {widget: this}));
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ _onChangeCurrentPage: function(){
+ var self = this;
+ this.messageFetch().then(function(){
+ var p = self.get('current_page');
+ self.set('pager', self._pager(p));
+ });
+ },
+ _onChangeDomain: function(){
+ this.set('current_page', 1);
+ },
+ /**
+ * @private
+ * @param {MouseEvent} event
+ */
+ _onClickPager: function(ev){
+ ev.preventDefault();
+ var page = $(ev.currentTarget).data('page');
+ this.set('current_page', page);
+ },
+
+ });
+
+ web_editor_base.ready().then(function(){
+ $('.o_website_mail_thread').each(function(index){
+ var $elem = $(this);
+ var mail_thread = new WebsiteMailThread(null, $elem.data());
+ mail_thread.appendTo($elem);
+ });
+ });
+
+ return {
+ WebsiteMailThread: WebsiteMailThread,
+ };
+});
diff --git a/addons/website_mail/static/src/xml/chatter_message.xml b/addons/website_mail/static/src/xml/chatter_message.xml
deleted file mode 100644
index 111f9877d7a..00000000000
--- a/addons/website_mail/static/src/xml/chatter_message.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<templates id="template" xml:space="preserve">
- <t t-name="website_mail.thread_message">
- <li class="media" t-att-id="'message-' + id">
- <div class="media-body">
- <img class="media-object pull-left img-circle" t-att-src="image_url" style="width: 50px; margin-right: 10px;"/>
- <div class="media-body">
- <h5 class="media-heading">
- <span t-esc="author"/> <small>just now</small>
- </h5>
- <div t-raw="body"/>
- </div>
- </div>
- </li>
- </t>
-</templates> \ No newline at end of file
diff --git a/addons/website_mail/static/src/xml/website_mail.xml b/addons/website_mail/static/src/xml/website_mail.xml
new file mode 100644
index 00000000000..0e26c7e56ab
--- /dev/null
+++ b/addons/website_mail/static/src/xml/website_mail.xml
@@ -0,0 +1,132 @@
+<templates id="template" xml:space="preserve">
+
+ <t t-name="website_mail.publish_short">
+ <t t-if="is_publisher" t-ignore="true">
+ <div t-attf-class="pull-right js_publish_management #{object.website_published and 'css_published' or 'css_unpublished'}" t-att-data-id="res_id" t-att-data-object="res_model" t-att-data-controller="publish_controller">
+ <button class="btn btn-danger js_publish_btn">Unpublished</button>
+ <button class="btn btn-success js_publish_btn">Published</button>
+ </div>
+ </t>
+ </t>
+
+ <t t-name="website_mail.chatter_message_count">
+ <t t-set="count" t-value="widget.get('message_count')"/>
+ <div class="o_message_counter">
+ <t t-if="count">
+ <span class="o_message_count fa fa-comments"> <t t-esc="count"/></span>
+ <t t-if="count == 1">comment</t>
+ <t t-else="">comments</t>
+ </t>
+ <t t-else="">
+ There are no comments for now.
+ </t>
+ </div>
+ </t>
+
+ <t t-name="website_mail.chatter_composer">
+ <div class="o_website_mail_composer" t-if="widget.options['allow_composer']">
+ <t t-if="!widget.options['display_composer']">
+ <h4>Leave a comment</h4>
+ <p>You must be <a t-attf-href="/web/login?redirect=#{window.encodeURI(window.location.href + '#discussion')}">logged in</a> to post a comment.</p>
+ </t>
+ <t t-if="widget.options['display_composer']">
+ <div class="media">
+ <div class="media-left">
+ <img class="o_website_mail_avatar pull-left" t-attf-src="/web/image/res.partner/#{widget.options['partner_id']}/image_small/50x50"/>
+ </div>
+ <div class="media-body">
+ <form class="o_website_mail_composer_form" t-attf-action="/website_mail/post/post" method="POST">
+ <input type="hidden" name="csrf_token" t-att-value="widget.options['csrf_token']"/>
+ <div class="mb32">
+ <textarea rows="4" name="message" class="form-control" placeholder="Write a message..." style="width: 75%"></textarea>
+ <input type='hidden' name="res_model" t-att-value="widget.options['res_model']"/>
+ <input type='hidden' name="res_id" t-att-value="widget.options['res_id']"/>
+ <input type='hidden' name="token" t-att-value="widget.options['token']" t-if="widget.options['token']"/>
+ <input type='hidden' name="sha_in" t-att-value="widget.options['sha_in']" t-if="widget.options['sha_in']"/>
+ <input type='hidden' name="sha_time" t-att-value="widget.options['sha_time']" t-if="widget.options['sha_time']"/>
+ <input type='hidden' name="token_field" t-att-value="widget.options['token_field']" t-if="widget.options['token_field']"/>
+ <div class="alert alert-danger mt8 mb0 o_website_mail_composer_error" style="display:none;">
+ Oops! Something went wrong. Try to reload the page and log in.
+ </div>
+ <button t-attf-class="o_website_mail_composer_btn btn btn-primary mt8 o_website_message_post_helper" type="submit">Send</button>
+ </div>
+ </form>
+ </div>
+ </div>
+ </t>
+ <hr/>
+ </div>
+ </t>
+
+ <t t-name="website_mail.chatter_messages">
+ <div class="o_website_mail_messages">
+ <t t-foreach="widget.get('messages')" t-as="message">
+ <div class="media o_website_mail_message" t-att-id="'message-' + message.id">
+ <div class="media-left">
+ <img class="media-object o_website_mail_avatar" t-att-src="message.author_avatar_url" alt="avatar"/>
+ </div>
+ <div class="media-body">
+
+ <t t-call="website_mail.publish_short">
+ <t t-set="res_model" t-value="'mail.message'"/>
+ <t t-set="res_id" t-value="message.id"/>
+ <t t-set="object" t-value="message"/>
+ <t t-set="is_publisher" t-value="widget.options['is_user_publisher']"/>
+ </t>
+
+ <div class="o_website_mail_message_title">
+ <h5 class="media-heading">
+ <t t-esc="message.author_id[1]"/>
+ </h5>
+ <p class="o_website_mail_puslished_date"><t t-esc="message.published_date_str"/></p>
+ </div>
+ <t t-raw="message.body"/>
+
+ <div class="o_website_mail_attachments">
+ <div class="col-md-2 col-sm-3 text-center" t-foreach='message.attachment_ids' t-as='attachment'>
+ <a t-attf-href="/web/content/#{attachment.id}?download=true" target="_blank">
+ <div class='oe_attachment_embedded o_image' t-att-title="attachment.name" t-att-data-mimetype="attachment.mimetype" t-attf-data-src="/web/image/#{attachment.id}/100x80"/>
+ <div class='oe_attachment_name'><t t-raw='attachment.name'/></div>
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </t>
+ </div>
+ </t>
+
+ <t t-name="website_mail.pager">
+ <div class="o_website_mail_pager">
+ <t t-if="!_.isEmpty(widget.get('pager'))">
+ <ul class="pagination" t-if="widget.get('pager')['pages'].length &gt; 1">
+ <li t-if="widget.get('pager')['page'] != widget.get('pager')['page_previous']" t-att-data-page="widget.get('pager')['page_previous']" class="o_website_mail_pager_btn">
+ <a href="#"><i class="fa fa-chevron-left"/></a>
+ </li>
+ <t t-foreach="widget.get('pager')['pages']" t-as="page">
+ <li t-att-data-page="page" t-att-class="page == widget.get('pager')['page'] ? 'o_website_mail_pager_btn active' : 'o_website_mail_pager_btn'">
+ <a href="#"><t t-esc="page"/></a>
+ </li>
+ </t>
+ <li t-if="widget.get('pager')['page'] != widget.get('pager')['page_next']" t-att-data-page="widget.get('pager')['page_next']" class="o_website_mail_pager_btn">
+ <a href="#"><i class="fa fa-chevron-right"/></a>
+ </li>
+ </ul>
+ </t>
+ </div>
+ </t>
+
+ <t t-name="website_mail.chatter">
+ <div class="o_website_mail_chatter">
+ <div class="o_website_mail_header">
+ <t t-call="website_mail.chatter_message_count"/>
+ </div>
+ <hr/>
+ <t t-call="website_mail.chatter_composer"/>
+ <t t-call="website_mail.chatter_messages"/>
+ <div class="o_website_mail_footer">
+ <t t-call="website_mail.pager"/>
+ </div>
+ </div>
+ </t>
+</templates>