diff --git a/addons/website_blog/controllers/main.py b/addons/website_blog/controllers/main.py index 5e4baf13ef4..1a0bcf9402e 100644 --- a/addons/website_blog/controllers/main.py +++ b/addons/website_blog/controllers/main.py @@ -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: diff --git a/addons/website_blog/models/mail_message.py b/addons/website_blog/models/mail_message.py index 72fdb01ebbd..e1b60f6ad20 100644 --- a/addons/website_blog/models/mail_message.py +++ b/addons/website_blog/models/mail_message.py @@ -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;'), } diff --git a/addons/website_blog/models/website_blog.py b/addons/website_blog/models/website_blog.py index 784c7bd6427..b2ab2670876 100644 --- a/addons/website_blog/models/website_blog.py +++ b/addons/website_blog/models/website_blog.py @@ -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('
') and html.endswith('
'): + 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 diff --git a/addons/website_blog/static/src/js/website_blog.inline.discussion.js b/addons/website_blog/static/src/js/website_blog.inline.discussion.js index 574a29806e9..56851c3939c 100644 --- a/addons/website_blog/static/src/js/website_blog.inline.discussion.js +++ b/addons/website_blog/static/src/js/website_blog.inline.discussion.js @@ -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) { - $('
').appendTo($('#blog_content')); + $('
').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('
') .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], diff --git a/addons/website_blog/static/src/js/website_blog.js b/addons/website_blog/static/src/js/website_blog.js index 6e8dbb25661..3217bf1a04d 100644 --- a/addons/website_blog/static/src/js/website_blog.js +++ b/addons/website_blog/static/src/js/website_blog.js @@ -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]}); diff --git a/addons/website_blog/views/website_blog_templates.xml b/addons/website_blog/views/website_blog_templates.xml index 121e4972382..fa6c6af53c6 100644 --- a/addons/website_blog/views/website_blog_templates.xml +++ b/addons/website_blog/views/website_blog_templates.xml @@ -318,8 +318,8 @@