[IMP] website_blog: path computation (unique key) for paragraphs in medium-like blogs

is now done server-side and stored directly in the html content, as post processing.
The front-end attaches messages based on the attribute data-chatter-id, but do not
compute the attribute itself anymore.
Misc cleaning of code.

bzr revid: tde@openerp.com-20140403112656-ane3ovhh70qdc8b4
This commit is contained in:
Thibault Delavallée 2014-04-03 13:26:56 +02:00
parent eccbb272ee
commit 8f105b6624
6 changed files with 87 additions and 36 deletions

View File

@ -210,7 +210,6 @@ class WebsiteBlog(http.Controller):
('id', 'not in', visited_ids),
], order='ranking desc', limit=1, context=context)
next_post = next_post_id and blog_post_obj.browse(cr, uid, next_post_id[0], context=context) or False
print next_post
values = {
'tags': tags,
@ -259,7 +258,7 @@ class WebsiteBlog(http.Controller):
type='comment',
subtype='mt_comment',
author_id=partner_ids[0],
discussion=post.get('discussion'),
path=post.get('path', False),
context=dict(context, mail_create_nosubcribe=True))
return message_id
@ -327,10 +326,10 @@ class WebsiteBlog(http.Controller):
return werkzeug.utils.redirect("/blog/%s/post/%s/?enable_editor=1" % (post.blog_id.id, nid))
@http.route('/blogpost/get_discussion/', type='json', auth="public", website=True)
def discussion(self, post_id=0, discussion=None, count=False, **post):
def discussion(self, post_id=0, path=None, count=False, **post):
cr, uid, context = request.cr, request.uid, request.context
mail_obj = request.registry.get('mail.message')
domain = [('res_id', '=', int(post_id)) ,('model','=','blog.post'), ('discussion_key', '=', discussion)]
domain = [('res_id', '=', int(post_id)), ('model', '=', 'blog.post'), ('path', '=', path)]
#check current user belongs to website publisher group
publish = request.registry['res.users'].has_group(cr, uid, 'base.group_website_publisher')
if not publish:

View File

@ -7,6 +7,7 @@ class MailMessage(osv.Model):
_inherit = 'mail.message'
_columns = {
'discussion_key': fields.char('Discussion Key',
help='Used in Blogs to display messages in a group based on their discussion key.'),
'path': fields.char(
'Discussion Path', select=1,
help='Used to display messages in a paragraph-based chatter using a unique path;'),
}

View File

@ -2,9 +2,11 @@
from datetime import datetime
import difflib
import lxml
import random
from openerp import tools
from openerp import SUPERUSER_ID
from openerp.osv import osv, fields
from openerp.tools.translate import _
@ -66,7 +68,7 @@ class BlogPost(osv.Model):
'website_message_ids': fields.one2many(
'mail.message', 'res_id',
domain=lambda self: [
'&', '&', ('model', '=', self._name), ('type', '=', 'comment'), ('discussion_key', '=', False)
'&', '&', ('model', '=', self._name), ('type', '=', 'comment'), ('path', '=', False)
],
string='Website Messages',
help="Website communication history",
@ -103,6 +105,59 @@ class BlogPost(osv.Model):
'author_id': lambda self, cr, uid, ctx=None: self.pool['res.users'].browse(cr, uid, uid, context=ctx).partner_id.id,
}
def html_tag_nodes(self, html, attribute=None, tags=None, context=None):
""" Processing of html content to tag paragraphs and set them an unique
ID.
:return result: (html, mappin), where html is the updated html with ID
and mapping is a list of (old_ID, new_ID), where old_ID
is None is the paragraph is a new one. """
mapping = []
if not html:
return html, mapping
if tags is None:
tags = ['p']
if attribute is None:
attribute = 'data-unique-id'
counter = 0
# form a tree
root = lxml.html.fragment_fromstring(html, create_parent='div')
if not len(root) and root.text is None and root.tail is None:
return html, mapping
# check all nodes, replace :
# - img src -> check URL
# - a href -> check URL
for node in root.iter():
if not node.tag in tags:
continue
ancestor_tags = [parent.tag for parent in node.iterancestors()]
ancestor_tags.pop()
new_attribute = '/'.join(reversed(ancestor_tags))
old_attribute = node.get(attribute)
node.set(attribute, new_attribute)
mapping.append((old_attribute, counter))
counter += 1
html = lxml.html.tostring(root, pretty_print=False, method='html')
# this is ugly, but lxml/etree tostring want to put everything in a 'div' that breaks the editor -> remove that
if html.startswith('<div>') and html.endswith('</div>'):
html = html[5:-6]
return html, mapping
def _postproces_content(self, cr, uid, id, content=None, context=None):
if content is None:
content = self.browse(cr, uid, id, context=context).content
if content is False:
return content
content, mapping = self.html_tag_nodes(content, attribute='data-chatter-id', tags=['p'], context=context)
for old_attribute, new_attribute in mapping:
if not old_attribute:
continue
msg_ids = self.pool['mail.message'].search(cr, SUPERUSER_ID, [('path', '=', old_attribute)], context=context)
self.pool['mail.message'].write(cr, SUPERUSER_ID, msg_ids, {'path': new_attribute}, context=context)
return content
def create_history(self, cr, uid, ids, vals, context=None):
for i in ids:
history = self.pool.get('blog.post.history')
@ -116,12 +171,16 @@ class BlogPost(osv.Model):
def create(self, cr, uid, vals, context=None):
if context is None:
context = {}
if 'content' in vals:
vals['content'] = self._postproces_content(cr, uid, None, vals['content'], context=context)
create_context = dict(context, mail_create_nolog=True)
post_id = super(BlogPost, self).create(cr, uid, vals, context=create_context)
self.create_history(cr, uid, [post_id], vals, context)
return post_id
def write(self, cr, uid, ids, vals, context=None):
if 'content' in vals:
vals['content'] = self._postproces_content(cr, uid, None, vals['content'], context=context)
result = super(BlogPost, self).write(cr, uid, ids, vals, context)
self.create_history(cr, uid, ids, vals, context)
return result

View File

@ -11,7 +11,6 @@
var self = this ;
self.discus_identifier;
var defaults = {
identifier: 'name',
position: 'right',
post_id: $('#blog_post_name').attr('data-blog-id'),
content : false,
@ -23,7 +22,7 @@
do_render: function(data) {
var self = this;
if ($('#discussions_wrapper').length === 0 && self.settings.content.length > 0) {
$('<div id="discussions_wrapper"></div>').appendTo($('#blog_content'));
$('<div id="discussions_wrapper"></div>').insertAfter($('#blog_content'));
}
// Attach a discussion to each paragraph.
$(self.settings.content).each(function(i) {
@ -36,8 +35,8 @@
}
if(!$(event.target).hasClass('discussion-link') && !$(event.target).parents('.popover').length){
if($('.move_discuss').length){
$('.js_discuss').next().removeClass('move_discuss');
$('.js_discuss').next().animate({
$('[enable_chatter_discuss=True]').removeClass('move_discuss');
$('[enable_chatter_discuss=True]').animate({
'marginLeft': "+=40%"
});
$('#discussions_wrapper').animate({
@ -47,30 +46,22 @@
}
});
},
prepare_data : function(identifier,comment_count) {
prepare_data : function(identifier, comment_count) {
var self = this;
return openerp.jsonRpc("/blogpost/get_discussion/", 'call', {
'post_id': self.settings.post_id,
'discussion':identifier,
'count' : comment_count, //if true only get length of total comment, display on discussion thread.
'path': identifier,
'count': comment_count, //if true only get length of total comment, display on discussion thread.
})
},
discussion_handler : function(i, node) {
var self = this;
var identifier;
// You can force a specific identifier by adding an attribute to the paragraph.
if (node.attr('data-discus-identifier')) {
identifier = node.attr('data-discus-identifier');
var identifier = node.attr('data-chatter-id');
if (identifier) {
self.prepare_data(identifier, true).then( function (data) {
self.prepare_discuss_link(data, identifier, node);
});
}
else {
while ($('[data-discus-identifier="' + self.settings.identifier + '-' + i + '"]').length > 0) {
i++;
}
identifier = self.settings.identifier + '-' + i;
}
self.prepare_data(identifier,true).then(function(data){
self.prepare_discuss_link(data,identifier,node)
});
},
prepare_discuss_link : function(data, identifier, node) {
var self = this;
@ -79,7 +70,7 @@
.attr('data-discus-identifier', identifier)
.attr('data-discus-position', self.settings.position)
.text(data > 0 ? data : '+')
.attr('data-contentwrapper','.mycontent')
.attr('data-contentwrapper', '.mycontent')
.wrap('<div class="discussion" />')
.parent()
.appendTo('#discussions_wrapper');
@ -87,7 +78,8 @@
'top': node.offset().top,
'left': self.settings.position == 'right' ? node.outerWidth() + node.offset().left: node.offset().left - a.outerWidth()
});
node.attr('data-discus-identifier', identifier).mouseover(function() {
// node.attr('data-discus-identifier', identifier)
node.mouseover(function() {
a.addClass("hovered");
}).mouseout(function() {
a.removeClass("hovered");
@ -96,8 +88,8 @@
a.delegate('a.discussion-link', "click", function(e) {
e.preventDefault();
if(!$('.move_discuss').length){
$('.js_discuss').next().addClass('move_discuss');
$('.js_discuss').next().animate({
$('[enable_chatter_discuss=True]').addClass('move_discuss');
$('[enable_chatter_discuss=True]').animate({
'marginLeft': "-=40%"
});
$('#discussions_wrapper').animate({
@ -185,7 +177,7 @@
if(!val) return
openerp.jsonRpc("/blogpost/post_discussion", 'call', {
'blog_post_id': self.settings.post_id,
'discussion': self.discus_identifier,
'path': self.discus_identifier,
'comment': val[0],
'name' : val[1],
'email': val[2],

View File

@ -24,8 +24,8 @@ $(document).ready(function() {
});
}
var content = $(".js_discuss").next().find('p');
if(content){
var content = $("div[enable_chatter_discuss='True']").find('p[data-chatter-id]');
if (content) {
openerp.jsonRpc("/blog/get_user/", 'call', {}).then(function(data){
$('#discussions_wrapper').empty();
new openerp.website.blog_discussion({'content' : content, 'public_user':data[0]});

View File

@ -318,8 +318,8 @@
<!-- Options: Blog Post: user can add Inline Discussion -->
<template id="opt_blog_post_inline_discussion" name="Allow comment in text"
inherit_option_id="website_blog.blog_post_complete">
<xpath expr="//div[@id='blog_content']" position="before">
<div class="js_discuss"/>
<xpath expr="//div[@id='blog_content']" position="attributes">
<attribute name="enable_chatter_discuss">True</attribute>
</xpath>
</template>