[IMP] website_blog: refactoring
[IMP] website_blog: display author avatar option [IMP] website_blog: refactore cover option for blog [IMP] website_blog: tags are now always displayed and as a label [IMP] website_blog: side bar cleaning [IMP] website_blog: new teaser [IMP] website_blog: replace inline comments by quotes comment [IMP] website_blog: new grid layout [WIP] website_blog: read next options [IMP] website_blog: refactoring sharing links [IMP] website_blog: Delete cover narrow option [IMP] website_blog: improvement for sharing links [IMP] website_blog: blog post list cover is an option [IMP] website_blog: archives group by year [IMP] website_blog: if only one blog, no index blog post Courtesy of @movanoncem
This commit is contained in:
@@ -28,7 +28,6 @@ Odoo Blog
|
||||
'test': [
|
||||
],
|
||||
'qweb': [
|
||||
'static/src/xml/*.xml'
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import json
|
||||
import werkzeug
|
||||
import itertools
|
||||
|
||||
from odoo import http, fields, _
|
||||
from odoo.addons.website.controllers.main import QueryURL
|
||||
@@ -25,9 +26,11 @@ class WebsiteBlog(http.Controller):
|
||||
(r, label) = group['create_date']
|
||||
start, end = r.split('/')
|
||||
group['create_date'] = label
|
||||
group['date_begin'] = self._to_date(start)
|
||||
group['date_end'] = self._to_date(end)
|
||||
return groups
|
||||
group['date_begin'] = fields.Date.to_string(self._to_date(start))
|
||||
group['date_end'] = fields.Date.to_string(self._to_date(end))
|
||||
group['month'] = self._to_date(start).strftime("%B")
|
||||
group['year'] = self._to_date(start).strftime("%Y")
|
||||
return {year: [m for m in months] for year, months in itertools.groupby(groups, lambda g: g['year'])}
|
||||
|
||||
def _to_date(self, dt):
|
||||
""" create_date is a datetime so start and end are datetime strings,
|
||||
@@ -40,8 +43,14 @@ class WebsiteBlog(http.Controller):
|
||||
'/blog/page/<int:page>',
|
||||
], type='http', auth="public", website=True)
|
||||
def blogs(self, page=1, **post):
|
||||
Blog = request.env['blog.blog']
|
||||
blogs = Blog.search([], limit=2)
|
||||
if len(blogs) == 1:
|
||||
return werkzeug.utils.redirect('/blog/%s' % slug(blogs[0]), code=302)
|
||||
|
||||
BlogPost = request.env['blog.post']
|
||||
total = BlogPost.search([], count=True)
|
||||
|
||||
pager = request.website.pager(
|
||||
url='/blog',
|
||||
total=total,
|
||||
@@ -133,7 +142,6 @@ class WebsiteBlog(http.Controller):
|
||||
tag_ids.append(current_tag)
|
||||
tag_ids = request.env['blog.tag'].browse(tag_ids).exists()
|
||||
return ','.join(map(slug, tag_ids))
|
||||
|
||||
values = {
|
||||
'blog': blog,
|
||||
'blogs': blogs,
|
||||
@@ -143,6 +151,7 @@ class WebsiteBlog(http.Controller):
|
||||
'active_tag_ids': active_tag_ids,
|
||||
'tags_list' : tags_list,
|
||||
'blog_posts': blog_posts,
|
||||
'blog_posts_cover_properties': [json.loads(b.cover_properties) for b in blog_posts],
|
||||
'pager': pager,
|
||||
'nav_list': self.nav_list(blog),
|
||||
'blog_url': blog_url,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import lxml
|
||||
from datetime import datetime
|
||||
from lxml import html
|
||||
import random
|
||||
|
||||
from datetime import datetime
|
||||
from odoo import api, models, fields, _
|
||||
from odoo.addons.website.models.website import slug
|
||||
from odoo.tools.translate import html_translate
|
||||
|
||||
from odoo.tools import html2plaintext
|
||||
|
||||
class Blog(models.Model):
|
||||
_name = 'blog.blog'
|
||||
@@ -31,7 +31,6 @@ class Blog(models.Model):
|
||||
post_ids.write({'active': vals['active']})
|
||||
return res
|
||||
|
||||
@api.model_cr
|
||||
@api.multi
|
||||
def all_tags(self, min_limit=1):
|
||||
req = """
|
||||
@@ -112,6 +111,9 @@ class BlogPost(models.Model):
|
||||
blog_id = fields.Many2one('blog.blog', 'Blog', required=True, ondelete='cascade')
|
||||
tag_ids = fields.Many2many('blog.tag', string='Tags')
|
||||
content = fields.Html('Content', default=_default_content, translate=html_translate, sanitize=False)
|
||||
teaser = fields.Text('Teaser', compute='_get_teaser', inverse='_set_teaser')
|
||||
teaser_manual = fields.Text(string='Teaser Content')
|
||||
|
||||
website_message_ids = fields.One2many(
|
||||
'mail.message', 'res_id',
|
||||
domain=lambda self: [
|
||||
@@ -130,75 +132,21 @@ class BlogPost(models.Model):
|
||||
visits = fields.Integer('No of Views')
|
||||
ranking = fields.Float(compute='_compute_ranking', string='Ranking')
|
||||
|
||||
def html_tag_nodes(self, html, attribute=None, tags=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. """
|
||||
|
||||
existing_attributes = []
|
||||
mapping = []
|
||||
if not html:
|
||||
return html, mapping
|
||||
if tags is None:
|
||||
tags = ['p']
|
||||
if attribute is None:
|
||||
attribute = 'data-unique-id'
|
||||
|
||||
# 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 node.tag not in tags:
|
||||
continue
|
||||
ancestor_tags = [parent.tag for parent in node.iterancestors()]
|
||||
|
||||
old_attribute = node.get(attribute)
|
||||
new_attribute = old_attribute
|
||||
if not new_attribute or (old_attribute in existing_attributes):
|
||||
if ancestor_tags:
|
||||
ancestor_tags.pop()
|
||||
counter = random.randint(10000, 99999)
|
||||
ancestor_tags.append('counter_%s' % counter)
|
||||
new_attribute = '/'.join(reversed(ancestor_tags))
|
||||
node.set(attribute, new_attribute)
|
||||
|
||||
existing_attributes.append(new_attribute)
|
||||
mapping.append((old_attribute, new_attribute))
|
||||
|
||||
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
|
||||
|
||||
# noguess used to be able to call the method with record = None in the create method
|
||||
@api.noguess
|
||||
def _postproces_content(self, record, content=None):
|
||||
if content is None:
|
||||
content = self.content
|
||||
if content is False:
|
||||
return content
|
||||
|
||||
content, mapping = self.html_tag_nodes(content, attribute='data-chatter-id', tags=['p'])
|
||||
if record: # not creating
|
||||
existing = [x[0] for x in mapping if x[0]]
|
||||
self.env['mail.message'].sudo().search([
|
||||
('res_id', '=', record.id),
|
||||
('model', '=', self._name),
|
||||
('path', 'not in', existing),
|
||||
('path', '!=', False)
|
||||
]).sudo().unlink()
|
||||
|
||||
return content
|
||||
@api.multi
|
||||
@api.depends('content', 'teaser_manual')
|
||||
def _get_teaser(self):
|
||||
for blog_post in self:
|
||||
if blog_post.teaser_manual:
|
||||
blog_post.teaser = blog_post.teaser_manual
|
||||
else:
|
||||
content = html2plaintext(blog_post.content).replace('\n', ' ')
|
||||
blog_post.teaser = ' '.join(filter(None, content.split(' '))[:50]) + '...'
|
||||
|
||||
@api.multi
|
||||
def _set_teaser(self):
|
||||
for blog_post in self:
|
||||
blog_post.teaser_manual = blog_post.teaser
|
||||
|
||||
def _check_for_publication(self, vals):
|
||||
if vals.get('website_published'):
|
||||
for post in self:
|
||||
@@ -212,8 +160,6 @@ class BlogPost(models.Model):
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if 'content' in vals:
|
||||
vals['content'] = self._postproces_content(None, vals['content'])
|
||||
post_id = super(BlogPost, self.with_context(mail_create_nolog=True)).create(vals)
|
||||
post_id._check_for_publication(vals)
|
||||
return post_id
|
||||
@@ -221,8 +167,6 @@ class BlogPost(models.Model):
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
self.ensure_one()
|
||||
if 'content' in vals:
|
||||
vals['content'] = self._postproces_content(self, vals['content'])
|
||||
if 'website_published' in vals:
|
||||
vals['published_date'] = fields.Datetime.now() if vals['website_published'] else False
|
||||
result = super(BlogPost, self).write(vals)
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
(function(){
|
||||
$.fn.share = function(options) {
|
||||
var option = $.extend($.fn.share.defaults,options);
|
||||
$.extend($.fn.share,{
|
||||
init : function(shareable) {
|
||||
var self = this;
|
||||
$.fn.share.defaults.shareable = shareable;
|
||||
$.fn.share.defaults.shareable.on('mouseup',function(){
|
||||
if ($(this).parents('body.editor_enable').length === 0) {
|
||||
self.popOver();
|
||||
}
|
||||
});
|
||||
$.fn.share.defaults.shareable.on('mousedown',function(){
|
||||
self.destroy();
|
||||
});
|
||||
},
|
||||
getContent : function() {
|
||||
var current_url = window.location.href
|
||||
var selected_text = this.getSelection('string').substring(0,option.maxLength-(current_url.length+option.author_name.length+7));
|
||||
var text = encodeURIComponent('\"'+selected_text+'\" '+'--@'+option.author_name+' '+current_url)
|
||||
return '<a onclick="window.open(\''+option.shareLink+text+'\',\'_'+option.target+'\',\'location=yes,height=570,width=520,scrollbars=yes,status=yes\')"><i class="fa fa-twitter fa-lg"/></a>';
|
||||
},
|
||||
getSelection : function(share) {
|
||||
if(window.getSelection){
|
||||
return (share=='string')?String(window.getSelection().getRangeAt(0)).replace(/\s{2,}/g, ' '):window.getSelection().getRangeAt(0);
|
||||
}
|
||||
else if(document.selection){
|
||||
return (share=='string')?document.selection.createRange().text.replace(/\s{2,}/g, ' '):document.selection.createRange();
|
||||
}
|
||||
},
|
||||
popOver : function() {
|
||||
this.destroy();
|
||||
if(this.getSelection('string').length < option.minLength)
|
||||
return;
|
||||
var data = this.getContent();
|
||||
var range = this.getSelection();
|
||||
var newNode = document.createElement("mark");
|
||||
range.surroundContents(newNode);
|
||||
$('mark').addClass(option.className);
|
||||
$('.'+option.className).popover({trigger:'manual', placement: option.placement, html: true
|
||||
, content:function(){
|
||||
return data;
|
||||
}
|
||||
});
|
||||
$('.'+option.className).popover('show');
|
||||
},
|
||||
destroy : function(){
|
||||
$('.'+option.className).popover('hide');
|
||||
$('mark').contents().unwrap();
|
||||
$('mark').remove();
|
||||
}
|
||||
});
|
||||
$.fn.share.init(this);
|
||||
};
|
||||
|
||||
$.fn.share.defaults = {
|
||||
shareLink : "http://twitter.com/intent/tweet?text=",
|
||||
minLength : 5,
|
||||
maxLength : 140,
|
||||
target : "blank",
|
||||
className : "share",
|
||||
placement : "top",
|
||||
};
|
||||
|
||||
}());
|
||||
@@ -58,6 +58,10 @@ div#blog_angle_down a:hover {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.cover_midscreen {
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
.cover_narrow {
|
||||
height: 50vh;
|
||||
overflow: hidden;
|
||||
@@ -95,103 +99,10 @@ div#blog_angle_down a:hover {
|
||||
top: 2%;
|
||||
}
|
||||
}
|
||||
/*Inline Discussion */
|
||||
.discussion {
|
||||
padding: 5px 10px 10px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
line-height: 16px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
z-index: 7;
|
||||
}
|
||||
.discussion > a {
|
||||
opacity: 0;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
width: 20px;
|
||||
height: 17px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
background: #bbbbbb;
|
||||
-webkit-border-radius: 2px;
|
||||
-moz-border-radius: 2px;
|
||||
-ms-border-radius: 2px;
|
||||
-o-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-webkit-transition: all 0.5s;
|
||||
-moz-transition: all 0.5s;
|
||||
-o-transition: all 0.5s;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
.discussion > a.has-comments {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.discussion-contain:hover .discussion > a {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.discussion > a:after {
|
||||
border-right: 7px solid transparent;
|
||||
border-top: 7px solid #bbbbbb;
|
||||
right: 19px;
|
||||
top: 22px;
|
||||
height: 0;
|
||||
width: 0;
|
||||
display: block;
|
||||
content: " ";
|
||||
position: absolute;
|
||||
-webkit-transition: all 0.5s;
|
||||
-moz-transition: all 0.5s;
|
||||
-o-transition: all 0.5s;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
.discussion:hover > a, .discussion.hovered > a {
|
||||
opacity: 1;
|
||||
background: #57AD68;
|
||||
}
|
||||
.discussion:hover > a:after, .discussion.hovered > a:after {
|
||||
border-top-color: #57AD68;
|
||||
}
|
||||
|
||||
#discussions_wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#discussions_overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 8;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.discussion .popover-content {
|
||||
max-height: 250px;
|
||||
width: 250px;
|
||||
overflow: auto;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
mark + .popover, .cover_footer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.discussion_scroll_post {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.blog_publish_btn {
|
||||
padding-top: 16px;
|
||||
}
|
||||
@@ -202,11 +113,107 @@ mark + .popover, .cover_footer {
|
||||
|
||||
#js_blogcover {
|
||||
background-blend-mode: multiply;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.o_blog_post_title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.o_blog_post_teaser {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
/*To display the grid or inline presentation of the blog.post_list */
|
||||
.o_grid {
|
||||
margin: 0 6% 6% 0;
|
||||
border: 1px solid #EEEEEE;
|
||||
box-shadow: 0.5px 0.5px 0.5px 0.5px #eeeeee;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.o_grid .o_blog_post_teaser {
|
||||
width: 100%;
|
||||
}
|
||||
.o_grid > .text-muted > .mb0 > hr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#js_blogcover {
|
||||
height: 150px;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.o_author_avatar_little {
|
||||
width: 40px;
|
||||
display: inline;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
/* Sharing links style */
|
||||
.o_sharing_links {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.o_sharing_links > p {
|
||||
display: inline;
|
||||
font-size: 12px;
|
||||
}
|
||||
.o_sharing_links > a {
|
||||
color: #b3b3b3;
|
||||
font: normal normal normal 28px/1 FontAwesome;
|
||||
margin: 0 4px 0 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.o_sharing_links > a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.o_sharing_links > a.o_twitter_complete, .o_sharing_links > a.o_twitter:hover {
|
||||
color: #4099FF;
|
||||
}
|
||||
.o_sharing_links > a.o_google_complete, .o_sharing_links > a.o_google:hover {
|
||||
color: #DD4B39;
|
||||
}
|
||||
.o_sharing_links > a.o_facebook_complete, .o_sharing_links > a.o_facebook:hover {
|
||||
color: #3b5998;
|
||||
}
|
||||
.o_sharing_links > a.o_linkedin_complete, .o_sharing_links > a.o_linkedin:hover {
|
||||
color: #0E76A8;
|
||||
}
|
||||
.o_sharing_links > a.unhover {
|
||||
color: #b3b3b3;
|
||||
}
|
||||
|
||||
.o_blog_post_complete.o_sharing_links {
|
||||
max-width: 700px;
|
||||
margin: 50px auto 50px auto;
|
||||
text-align: center;
|
||||
}
|
||||
.o_blog_post_complete.o_sharing_links > p {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.o_blog_post_complete.o_sharing_links > a {
|
||||
font: normal normal normal 40px/1 FontAwesome;
|
||||
}
|
||||
|
||||
div[name="blog_post_data"] {
|
||||
margin-top: 20px !important;
|
||||
font-size: 13px;
|
||||
}
|
||||
div[name="blog_post"] {
|
||||
position: relative;
|
||||
}
|
||||
div[name="blog_post"] hr {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/*Button "unpublished"/"published" on each article */
|
||||
.container.blog_publish_btn {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=website_blog.css.map */
|
||||
|
||||
@@ -48,6 +48,9 @@ div#blog_angle_down
|
||||
.cover_full
|
||||
height: 100vh
|
||||
|
||||
.cover_midscreen
|
||||
height: 50vh
|
||||
|
||||
.cover_narrow
|
||||
height: 50vh
|
||||
overflow: hidden
|
||||
@@ -81,93 +84,9 @@ div#blog_angle_down
|
||||
.blog_title
|
||||
top: 2%
|
||||
|
||||
/*Inline Discussion
|
||||
|
||||
.discussion
|
||||
padding: 5px 10px 10px
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
line-height: 16px
|
||||
font-size: 13px
|
||||
font-weight: bold
|
||||
font-family: sans-serif
|
||||
text-align: center
|
||||
z-index: 7
|
||||
> a
|
||||
opacity: 0
|
||||
display: block
|
||||
overflow: hidden
|
||||
width: 20px
|
||||
height: 17px
|
||||
color: white
|
||||
text-decoration: none
|
||||
cursor: pointer
|
||||
background: #bbbbbb
|
||||
-webkit-border-radius: 2px
|
||||
-moz-border-radius: 2px
|
||||
-ms-border-radius: 2px
|
||||
-o-border-radius: 2px
|
||||
border-radius: 2px
|
||||
-webkit-transition: all 0.5s
|
||||
-moz-transition: all 0.5s
|
||||
-o-transition: all 0.5s
|
||||
transition: all 0.5s
|
||||
&.has-comments
|
||||
opacity: .6
|
||||
|
||||
.discussion-contain:hover .discussion > a
|
||||
opacity: 1
|
||||
|
||||
.discussion
|
||||
> a:after
|
||||
border-right: 7px solid transparent
|
||||
border-top: 7px solid #bbbbbb
|
||||
right: 19px
|
||||
top: 22px
|
||||
height: 0
|
||||
width: 0
|
||||
display: block
|
||||
content: " "
|
||||
position: absolute
|
||||
-webkit-transition: all 0.5s
|
||||
-moz-transition: all 0.5s
|
||||
-o-transition: all 0.5s
|
||||
transition: all 0.5s
|
||||
&:hover > a, &.hovered > a
|
||||
opacity: 1
|
||||
background: #57AD68
|
||||
&:hover > a:after, &.hovered > a:after
|
||||
border-top-color: #57AD68
|
||||
|
||||
#discussions_wrapper
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
|
||||
#discussions_overlay
|
||||
position: fixed
|
||||
top: 0
|
||||
left: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
background: rgba(0, 0, 0, 0.5)
|
||||
z-index: 8
|
||||
display: none
|
||||
|
||||
.discussion .popover-content
|
||||
max-height: 250px
|
||||
width: 250px
|
||||
overflow: auto
|
||||
font-weight: normal
|
||||
padding-bottom: 0px
|
||||
|
||||
mark + .popover, .cover_footer
|
||||
cursor: pointer
|
||||
|
||||
.discussion_scroll_post
|
||||
overflow-x: auto
|
||||
|
||||
.blog_publish_btn
|
||||
padding-top: 16px
|
||||
|
||||
@@ -176,10 +95,86 @@ mark + .popover, .cover_footer
|
||||
|
||||
#js_blogcover
|
||||
background-blend-mode: multiply
|
||||
-webkit-background-size: cover
|
||||
-moz-background-size: cover
|
||||
-o-background-size: cover
|
||||
background-size: cover
|
||||
background-position: center
|
||||
background-repeat: no-repeat
|
||||
height: 100%
|
||||
|
||||
.o_blog_post_title
|
||||
font-size: 24px
|
||||
|
||||
.o_blog_post_teaser
|
||||
text-align: justify
|
||||
|
||||
/*To display the grid or inline presentation of the blog.post_list*/
|
||||
.o_grid
|
||||
margin: 0 6% 6% 0
|
||||
border: 1px solid #EEEEEE
|
||||
box-shadow: .5px .5px .5px .5px rgba(238,238,238,1)
|
||||
padding-bottom: 15px
|
||||
.o_blog_post_teaser
|
||||
width: 100%
|
||||
> .text-muted > .mb0 > hr
|
||||
display: none
|
||||
|
||||
#js_blogcover
|
||||
height: 150px
|
||||
opacity: 1 !important
|
||||
|
||||
.o_author_avatar_little
|
||||
width: 40px
|
||||
display: inline
|
||||
margin-top: -5px
|
||||
|
||||
/* Sharing links style */
|
||||
|
||||
.o_sharing_links
|
||||
margin-top: 20px
|
||||
>
|
||||
p
|
||||
display: inline
|
||||
font-size: 12px
|
||||
a
|
||||
color: #b3b3b3
|
||||
font: normal normal normal 28px/1 FontAwesome
|
||||
margin: 0 4px 0 4px
|
||||
cursor: pointer
|
||||
&:hover
|
||||
text-decoration: none
|
||||
&.o_twitter_complete, &.o_twitter:hover
|
||||
color: #4099FF
|
||||
&.o_google_complete, &.o_google:hover
|
||||
color: #DD4B39
|
||||
&.o_facebook_complete, &.o_facebook:hover
|
||||
color: #3b5998
|
||||
&.o_linkedin_complete, &.o_linkedin:hover
|
||||
color: #0E76A8
|
||||
&.unhover
|
||||
color: #b3b3b3
|
||||
|
||||
.o_blog_post_complete.o_sharing_links
|
||||
max-width: 700px
|
||||
margin: 50px auto 50px auto
|
||||
text-align: center
|
||||
>
|
||||
p
|
||||
font-size: 16px
|
||||
font-weight: 600
|
||||
a
|
||||
font: normal normal normal 40px/1 FontAwesome
|
||||
|
||||
div
|
||||
&[name="blog_post_data"]
|
||||
margin-top: 20px !important
|
||||
font-size: 13px
|
||||
&[name="blog_post"]
|
||||
position: relative
|
||||
hr
|
||||
margin-top: 10px
|
||||
|
||||
/*Button "unpublished"/"published" on each article
|
||||
|
||||
.container.blog_publish_btn
|
||||
position: absolute
|
||||
right: 20px
|
||||
z-index: 1000
|
||||
@@ -0,0 +1,96 @@
|
||||
(function(){
|
||||
$.fn.share = function(options) {
|
||||
var option = $.extend($.fn.share.defaults,options);
|
||||
var selected_text ="";
|
||||
$.extend($.fn.share,{
|
||||
init : function(shareable) {
|
||||
var self = this;
|
||||
$.fn.share.defaults.shareable = shareable;
|
||||
$.fn.share.defaults.shareable.on('mouseup',function(){
|
||||
if ($(this).parents('body.editor_enable').length === 0) {
|
||||
self.popOver();
|
||||
}
|
||||
});
|
||||
$.fn.share.defaults.shareable.on('mousedown',function(){
|
||||
self.destroy();
|
||||
});
|
||||
},
|
||||
getContent : function() {
|
||||
var popover_content = '';
|
||||
if($('.blog_title, .blog_content').hasClass('js_comment')){
|
||||
selected_text = this.getSelection('string');
|
||||
popover_content += '<a class="o_share_comment mr12"><i class="fa fa-comment fa-lg mr4 ml4"/></a>';
|
||||
}
|
||||
if($('.blog_title, .blog_content').hasClass('js_tweet')){
|
||||
var current_url = window.location.href;
|
||||
var tweet_selected_text = this.getSelection('string').substring(0,option.maxLength-(current_url.length+option.author_name.length+7));
|
||||
var text = encodeURIComponent(_.str.sprintf('\"%s\" --@%s %s', tweet_selected_text, option.author_name, current_url));
|
||||
popover_content += '<a onclick="window.open(\''+option.shareLink+text+'\',\'_'+option.target+'\',\'location=yes,height=570,width=520,scrollbars=yes,status=yes\')"><i class="ml4 mr4 fa fa-twitter fa-lg"/></a>';
|
||||
}
|
||||
return popover_content;
|
||||
},
|
||||
commentEdition : function(){
|
||||
var positionComment = ($('#comments').position()).top-50;
|
||||
$(".o_website_chatter_form textarea").val('"' + selected_text + '" ').focus();
|
||||
$('html, body').stop().animate({
|
||||
'scrollTop': positionComment
|
||||
}, 500, 'swing', function () {
|
||||
window.location.hash = 'blog_post_comment_quote';
|
||||
});
|
||||
},
|
||||
getSelection : function(share) {
|
||||
if(window.getSelection){
|
||||
if (share === 'string') {
|
||||
return String(window.getSelection().getRangeAt(0)).replace(/\s{2,}/g, ' ');
|
||||
} else {
|
||||
return window.getSelection().getRangeAt(0);
|
||||
}
|
||||
}
|
||||
else if(document.selection){
|
||||
if (share === 'string') {
|
||||
return document.selection.createRange().text.replace(/\s{2,}/g, ' ');
|
||||
} else {
|
||||
return document.selection.createRange();
|
||||
}
|
||||
}
|
||||
},
|
||||
popOver : function() {
|
||||
this.destroy();
|
||||
if(this.getSelection('string').length < option.minLength)
|
||||
return;
|
||||
var data = this.getContent();
|
||||
var range = this.getSelection();
|
||||
|
||||
var newNode = document.createElement("span");
|
||||
range.insertNode(newNode);
|
||||
newNode.className = option.className;
|
||||
var $pop = $(newNode);
|
||||
$pop.popover({
|
||||
trigger:'manual',
|
||||
placement: option.placement,
|
||||
html: true,
|
||||
content: function(){
|
||||
return data;
|
||||
}
|
||||
}).popover('show');
|
||||
$('.o_share_comment').on('click', this.commentEdition);
|
||||
},
|
||||
destroy : function(){
|
||||
var $span = $('span.'+option.className);
|
||||
$span.popover('hide');
|
||||
$span.remove();
|
||||
}
|
||||
});
|
||||
$.fn.share.init(this);
|
||||
};
|
||||
|
||||
$.fn.share.defaults = {
|
||||
shareLink : "http://twitter.com/intent/tweet?text=",
|
||||
minLength : 5,
|
||||
maxLength : 140,
|
||||
target : "blank",
|
||||
className : "share",
|
||||
placement : "top",
|
||||
};
|
||||
|
||||
}());
|
||||
@@ -45,6 +45,12 @@ odoo.define('website_blog.editor', function (require) {
|
||||
}
|
||||
|
||||
rte.Class.include({
|
||||
// Destroy popOver and stop listening mouseup event on edit mode
|
||||
start: function () {
|
||||
var self = this;
|
||||
$(".js_tweet, .js_comment").off('mouseup').trigger('mousedown');
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
saveElement: function ($el, context) {
|
||||
if ($el.is('.website_blog #title')) {
|
||||
return ajax.jsonRpc("/blog/post_change_background", 'call', {
|
||||
@@ -61,7 +67,6 @@ odoo.define('website_blog.editor', function (require) {
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
options.registry.many2one.include({
|
||||
select_record: function (li) {
|
||||
var self = this;
|
||||
@@ -91,7 +96,7 @@ odoo.define('website_blog.editor', function (require) {
|
||||
this.src = null;
|
||||
this.$cover.css({"background-image": '', 'min-height': ''});
|
||||
this.$image.removeAttr("src");
|
||||
this.$target.removeClass('cover cover_full cover_narrow');
|
||||
this.$target.removeClass('cover cover_full cover_narrow cover_midscreen cover_mid_narrow');
|
||||
},
|
||||
change : function(type, value, $li) {
|
||||
if (type !== 'click') return;
|
||||
@@ -99,7 +104,7 @@ odoo.define('website_blog.editor', function (require) {
|
||||
var editor = new widget.MediaDialog(null, {only_images: true}, this.$image, this.$image[0]).open();
|
||||
editor.on('saved', self, function (event, img) {
|
||||
var url = self.$image.attr('src');
|
||||
self.$cover.css({"background-image": url ? 'url(' + url + ')' : "", 'min-height': $(window).height()-this.$cover.offset().top});
|
||||
self.$cover.css({"background-image": url ? 'url(' + url + ')' : ""});
|
||||
self.$target.addClass('o_dirty cover cover_full');
|
||||
self.set_active();
|
||||
});
|
||||
@@ -123,7 +128,15 @@ odoo.define('website_blog.editor', function (require) {
|
||||
this.value = this.$cover.css('opacity');
|
||||
this.$el.parent().find('.snippet-option-website_blog:not(li[data-change])').toggleClass("hidden", !this.$target.hasClass("cover"));
|
||||
this.$el.find('li[data-bgcolor], li[data-opacity], li[data-cover_class]').removeClass("active");
|
||||
this.$el.find('[data-bgcolor="' + this.background + '"], [data-opacity="' + parseFloat(this.value).toFixed(1) + '"], [data-cover_class*="' + ((this.class||'').indexOf('cover_full') === -1 ? 'container' : 'cover_full') + '"]').addClass("active");
|
||||
this.$el.find('[data-bgcolor="' + this.background + '"], [data-opacity="' + parseFloat(this.value).toFixed(1) + '"]').addClass("active");
|
||||
|
||||
if ((this.class || '').indexOf('cover_narrow') != -1) {
|
||||
this.$el.find('[data-cover_class*=cover_narrow]').addClass("active");
|
||||
} else if ((this.class || '').indexOf('cover_midscreen') != -1) {
|
||||
this.$el.find('[data-cover_class*=cover_midscreen]').addClass("active");
|
||||
} else {
|
||||
this.$el.find('[data-cover_class*=cover_full]').addClass("active");
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
odoo.define('website_blog.InlineDiscussion', function (require) {
|
||||
'use strict';
|
||||
|
||||
// Inspired from https://github.com/tsi/inlineDisqussions
|
||||
|
||||
var ajax = require('web.ajax');
|
||||
var core = require('web.core');
|
||||
var base = require('web_editor.base');
|
||||
|
||||
var qweb = core.qweb;
|
||||
|
||||
ajax.loadXML('/website_blog/static/src/xml/website_blog.inline.discussion.xml', qweb);
|
||||
|
||||
|
||||
var InlineDiscussion = core.Class.extend({
|
||||
init: function(options) {
|
||||
var defaults = {
|
||||
position: 'right',
|
||||
post_id: $('#blog_post_name').attr('data-blog-id'),
|
||||
content : false,
|
||||
public_user: false,
|
||||
};
|
||||
this.settings = $.extend({}, defaults, options);
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
var $wrapper = $('#discussions_wrapper');
|
||||
if (!$wrapper.length && this.settings.content.length > 0) {
|
||||
$wrapper = $('<div id="discussions_wrapper"></div>').insertAfter($('#blog_content'));
|
||||
}
|
||||
// Attach a discussion to each paragraph.
|
||||
this.discussions_handler(this.settings.content);
|
||||
|
||||
// Open/close the discussion.
|
||||
$('html').click(function (event) {
|
||||
var $target = $(event.target);
|
||||
var open;
|
||||
|
||||
if ((!$target.is('.discussion-link:not(.active)') && !$target.closest('.popover').length) || !$target.closest('#discussions_wrapper').length) {
|
||||
self.hide_discussion();
|
||||
open = false;
|
||||
} else if ($target.is('.discussion-link')) {
|
||||
self.get_discussion($target);
|
||||
open = true;
|
||||
}
|
||||
|
||||
if (open === !$wrapper.hasClass('o_move_discuss')) {
|
||||
$wrapper.toggleClass('o_move_discuss', open);
|
||||
$wrapper.animate({
|
||||
'marginLeft': (open ? '-' : '+')+"=20%"
|
||||
});
|
||||
$('#blog_content[enable_chatter_discuss=True]').animate({
|
||||
'marginLeft': (open ? '-' : '+')+"=40%"
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
prepare_data : function(identifier, comment_count) {
|
||||
var self = this;
|
||||
return ajax.jsonRpc("/blog/post_get_discussion/", 'call', {
|
||||
'post_id': self.settings.post_id,
|
||||
'path': identifier,
|
||||
'count': comment_count, //if true only get length of total comment, display on discussion thread.
|
||||
});
|
||||
},
|
||||
prepare_multi_data : function(identifiers, comment_count) {
|
||||
var self = this;
|
||||
return ajax.jsonRpc("/blog/post_get_discussions/", 'call', {
|
||||
'post_id': self.settings.post_id,
|
||||
'paths': identifiers,
|
||||
'count': comment_count, //if true only get length of total comment, display on discussion thread.
|
||||
});
|
||||
},
|
||||
discussions_handler: function() {
|
||||
var self = this;
|
||||
var node_by_id = {};
|
||||
$(self.settings.content).each(function() {
|
||||
var node = $(this);
|
||||
var identifier = node.attr('data-chatter-id');
|
||||
if (identifier) {
|
||||
node_by_id[identifier] = node;
|
||||
}
|
||||
});
|
||||
self.prepare_multi_data(_.keys(node_by_id), true).then( function (multi_data) {
|
||||
_.forEach(multi_data, function(data) {
|
||||
self.prepare_discuss_link(data.val, data.path, node_by_id[data.path]);
|
||||
});
|
||||
});
|
||||
},
|
||||
prepare_discuss_link : function(data, identifier, node) {
|
||||
var self = this;
|
||||
var cls = data > 0 ? 'discussion-link has-comments' : 'discussion-link';
|
||||
var a = $('<a class="'+ cls +' css_editable_mode_hidden" />')
|
||||
.attr('data-discus-identifier', identifier)
|
||||
.attr('data-discus-position', self.settings.position)
|
||||
.text(data > 0 ? data : '+')
|
||||
.attr('data-contentwrapper', '.mycontent')
|
||||
.wrap('<div class="discussion" />')
|
||||
.parent()
|
||||
.appendTo('#discussions_wrapper');
|
||||
a.css({
|
||||
'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)
|
||||
node.mouseover(function() {
|
||||
a.addClass("hovered");
|
||||
}).mouseout(function() {
|
||||
a.removeClass("hovered");
|
||||
});
|
||||
},
|
||||
get_discussion : function(source) {
|
||||
var self = this;
|
||||
var identifier = source.attr('data-discus-identifier');
|
||||
self.hide_discussion();
|
||||
self.discus_identifier = identifier;
|
||||
var elt = $('a[data-discus-identifier="'+identifier+'"]');
|
||||
self.settings.current_url = window.location;
|
||||
elt.append(qweb.render("website.blog_discussion.popover", {'identifier': identifier , 'options': self.settings}));
|
||||
var comment = '';
|
||||
self.prepare_data(identifier,false).then(function(data){
|
||||
_.each(data, function(res){
|
||||
comment += qweb.render("website.blog_discussion.comment", {'res': res});
|
||||
});
|
||||
$('.discussion_history').html('<ul class="media-list mt8">' + comment + '</ul>');
|
||||
self.create_popover(elt, identifier);
|
||||
// Add 'active' class.
|
||||
$('a.discussion-link, a.main-discussion-link').removeClass('active').filter(source).addClass('active');
|
||||
elt.popover('hide').filter(source).popover('show');
|
||||
});
|
||||
},
|
||||
create_popover : function(elt, identifier) {
|
||||
var self = this;
|
||||
elt.popover({
|
||||
placement:'right',
|
||||
trigger:'manual',
|
||||
html:true, content:function(){
|
||||
return $($(this).data('contentwrapper')).html();
|
||||
}
|
||||
}).parent().delegate(self).on('click','button#comment_post',function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
self.post_discussion(identifier);
|
||||
});
|
||||
},
|
||||
validate : function(public_user){
|
||||
var comment = $(".popover textarea#inline_comment").val();
|
||||
if(!comment) {
|
||||
$('div#inline_comment').addClass('has-error');
|
||||
return false;
|
||||
}
|
||||
$("div#inline_comment").removeClass('has-error');
|
||||
$(".popover textarea#inline_comment").val('');
|
||||
return [comment];
|
||||
},
|
||||
post_discussion : function() {
|
||||
var self = this;
|
||||
var val = self.validate(self.settings.public_user);
|
||||
if(!val) return;
|
||||
ajax.jsonRpc("/blog/post_discussion", 'call', {
|
||||
'blog_post_id': self.settings.post_id,
|
||||
'path': self.discus_identifier,
|
||||
'comment': val[0],
|
||||
}).then(function(res){
|
||||
$(".popover ul.media-list").prepend(qweb.render("website.blog_discussion.comment", {'res': res[0]}));
|
||||
var ele = $('a[data-discus-identifier="'+ self.discus_identifier +'"]');
|
||||
ele.text(_.isNaN(parseInt(ele.text())) ? 1 : parseInt(ele.text())+1);
|
||||
ele.addClass('has-comments');
|
||||
});
|
||||
},
|
||||
hide_discussion : function() {
|
||||
var self = this;
|
||||
$('a[data-discus-identifier="'+ self.discus_identifier+'"]').popover('destroy');
|
||||
$('a.discussion-link').removeClass('active');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return InlineDiscussion;
|
||||
|
||||
});
|
||||
@@ -2,7 +2,6 @@ odoo.define('website_blog.website_blog', function (require) {
|
||||
"use strict";
|
||||
|
||||
var ajax = require('web.ajax');
|
||||
var InlineDiscussion = require('website_blog.InlineDiscussion');
|
||||
|
||||
function page_transist(event) {
|
||||
event.preventDefault();
|
||||
@@ -28,26 +27,51 @@ function animate(event) {
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
if ($('.website_blog').length) {
|
||||
|
||||
var content = $("div[enable_chatter_discuss='True']").find('p[data-chatter-id]');
|
||||
if (content) {
|
||||
ajax.jsonRpc("/blog/get_user/", 'call', {}).then(function(data){
|
||||
$('#discussions_wrapper').empty();
|
||||
new InlineDiscussion({'content' : content, 'public_user':data[0]}).start();
|
||||
});
|
||||
}
|
||||
|
||||
$(".js_tweet").share({'author_name': $('#blog_author').text()});
|
||||
$('.cover_footer').on('click', page_transist);
|
||||
$('a[href^="#blog_content"]').on('click', animate);
|
||||
|
||||
if ($('#js_blogcover').length) {
|
||||
$('#js_blogcover[style*="background-image: url"]').css('min-height', $(window).height()-$('#js_blogcover').offset().top);
|
||||
function shareArticle(event){
|
||||
var url = '';
|
||||
if ($(this).is('*[class*="_complete"]')) {
|
||||
var blog_title_complete = $('#blog_post_name').html() || '';
|
||||
if ($(this).hasClass('o_twitter_complete')){
|
||||
url = 'https://twitter.com/intent/tweet?tw_p=tweetbutton&text=Amazing blog article : '+blog_title_complete+"! Check it live: "+window.location.href;
|
||||
} else if ($(this).hasClass('o_facebook_complete')){
|
||||
url = 'https://www.facebook.com/sharer/sharer.php?u='+window.location.href;
|
||||
} else if ($(this).hasClass('o_linkedin_complete')){
|
||||
url = 'https://www.linkedin.com/shareArticle?mini=true&url='+window.location.href+'&title='+blog_title_complete;
|
||||
} else{
|
||||
url = 'https://plus.google.com/share?url='+window.location.href;
|
||||
};
|
||||
}
|
||||
else {
|
||||
var blog_post = $(this).parents("[name='blog_post']");
|
||||
var blog_post_title = blog_post.find('.o_blog_post_title').html() || '';
|
||||
var blog_article_link = blog_post.find('.o_blog_post_title').parent('a').attr('href');
|
||||
if ($(this).hasClass('o_twitter')) {
|
||||
url = 'https://twitter.com/intent/tweet?tw_p=tweetbutton&text=Amazing blog article : '+blog_post_title+"! "+window.location.host+blog_article_link;
|
||||
} else if ($(this).hasClass('o_facebook')){
|
||||
url = 'https://www.facebook.com/sharer/sharer.php?u='+window.location.host+blog_article_link;
|
||||
} else if ($(this).hasClass('o_linkedin')){
|
||||
url = 'https://www.linkedin.com/shareArticle?mini=true&url='+window.location.host+blog_article_link+'&title='+blog_post_title;
|
||||
} else if ($(this).hasClass('o_google')){
|
||||
url = 'https://plus.google.com/share?url='+window.location.host+blog_article_link;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
window.open(url, "", "menubar=no, width=500, height=400");
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
if ($('.website_blog').length) {
|
||||
$(".js_tweet, .js_comment").share({'author_name': $('#blog_author').text()});
|
||||
$('.cover_footer').on('click', page_transist);
|
||||
$('a[href^="#blog_content"]').on('click', animate);
|
||||
$('.o_twitter, .o_facebook, .o_linkedin, .o_google, .o_twitter_complete, .o_facebook_complete, .o_linkedin_complete, .o_google_complete').on('click', shareArticle);
|
||||
}
|
||||
|
||||
/* Sharing links hover in blogpost */
|
||||
$('div.o_blog_post_complete a').hover(
|
||||
function() { $('div.o_blog_post_complete a').not('#'+this.id).addClass('unhover'); },
|
||||
function() { $('div.o_blog_post_complete a').not('#'+this.id).removeClass('unhover'); }
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="website.blog_discussion.comment">
|
||||
<li class="media">
|
||||
<div class="pull-left">
|
||||
<img class="media-object img-circle" t-att-src="res.author_image" style="width: 30px;"/>
|
||||
</div>
|
||||
<div t-attf-class="pull-right btn-group js_publish_management #{res.website_published and 'css_published' or 'css_unpublished'} #{res.publish ? '' : 'hidden'}" data-object="mail.message" t-att-data-id="res.id">
|
||||
<button class="btn btn-danger btn-xs js_publish_btn">Unpublished</button>
|
||||
<button class="btn btn-success btn-xs js_publish_btn">Published</button>
|
||||
</div>
|
||||
<div class="media-body discussion_scroll_post">
|
||||
<div t-esc='res.body'/>
|
||||
<small class="text-muted">
|
||||
by
|
||||
<span t-esc='res.author_name'/>
|
||||
</small>
|
||||
</div>
|
||||
</li>
|
||||
</t>
|
||||
<t t-name="website.blog_discussion.popover">
|
||||
<div class="mycontent hidden">
|
||||
<input name="discussion" t-att-value="identifier" type="hidden"/>
|
||||
<input name="blog_post_id" t-att-value="options.post_id" type="hidden"/>
|
||||
<div id="inline_comment">
|
||||
<textarea rows="2" id="inline_comment" placeholder="Write a comment..." t-attf-class="mb8 form-control #{options.public_user ? 'hidden' : ''}"/>
|
||||
</div>
|
||||
<div t-attf-class="media-body discussion_scroll_post #{options.public_user ? '' : 'hidden'}">
|
||||
Please <strong><a t-attf-href="/web/login/?redirect=#{options.current_url}"> Sign in</a></strong> to comment.
|
||||
</div>
|
||||
<button id='comment_post' t-attf-class="btn btn-primary btn-xs mb8 #{options.public_user ? 'hidden' : ''}">Post</button>
|
||||
<div class="discussion_history"/>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -12,6 +12,7 @@
|
||||
<a href="#">Size</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li data-cover_class="cover cover_full"><a>Full Screen</a></li>
|
||||
<li data-cover_class="cover cover_midscreen"><a>Mid screen</a></li>
|
||||
<li data-cover_class="cover container cover_narrow"><a>Narrow</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
<xpath expr="." position="inside">
|
||||
<link rel='stylesheet' href='/website_blog/static/src/css/website_blog.css'/>
|
||||
|
||||
<script type="text/javascript" src="/website_blog/static/lib/contentshare.js"/>
|
||||
<script type="text/javascript" src="/website_blog/static/src/js/website_blog.inline.discussion.js"></script>
|
||||
<script type="text/javascript" src="/website_blog/static/src/js/contentshare.js"/>
|
||||
<script type="text/javascript" src="/website_blog/static/src/js/website_blog.js"/>
|
||||
</xpath>
|
||||
</template>
|
||||
@@ -133,15 +132,12 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div t-foreach="blog_posts" t-as="blog_post" class="mb32">
|
||||
<t t-if="blog_post.author_avatar">
|
||||
<span t-field="blog_post.author_avatar" class="o_not_editable" t-options='{"widget": "image", "class": "img-circle pull-right mt16 media-object"}' />
|
||||
</t>
|
||||
<div t-foreach="blog_posts" t-as="blog_post" class="mb32" name="blog_post">
|
||||
<a t-attf-href="/blog/#{ slug(blog_post.blog_id) }/post/#{ slug(blog_post) }">
|
||||
<h2 t-field="blog_post.name" class="mb4">Untitled Post</h2>
|
||||
<h2 t-field="blog_post.name" class="mb4 o_blog_post_title">Untitled Post</h2>
|
||||
</a>
|
||||
<div class="text-muted">
|
||||
<h4 t-field="blog_post.subtitle" class="mb4 mt4"></h4>
|
||||
<p t-field="blog_post.teaser" class="mb12 mt12 o_blog_post_teaser"/>
|
||||
<div name='blog_post_data' class='mb0'>
|
||||
<span t-field="blog_post.author_id" style="display: inline-block;" t-options='{
|
||||
"widget": "contact",
|
||||
@@ -152,15 +148,27 @@
|
||||
<span t-if="len(blog_post.message_ids) > 0">
|
||||
  <t t-esc="len(blog_post.message_ids)"/>
|
||||
<t t-if="len(blog_post.message_ids) <= 1" >comment</t>
|
||||
<t t-if="len(blog_post.message_ids) > 1">comments</t>
|
||||
<t t-if="len(blog_post.message_ids) > 1">comments</t>
|
||||
</span>
|
||||
<span t-if="blog_post.visits > 0">
|
||||
  <t t-esc="blog_post.visits"/>
|
||||
<t t-if="blog_post.visits <= 1" >view</t>
|
||||
<t t-if="blog_post.visits > 1">views</t>
|
||||
<t t-if="blog_post.visits > 1">views</t>
|
||||
</span>
|
||||
|
||||
<span t-if="not blog_post.website_published" class="label label-danger">unpublished</span>
|
||||
<span class="fa fa-tags"/>
|
||||
|
||||
<!-- To display tags //no options -->
|
||||
<t t-foreach="blog_post.tag_ids" t-as="one_tag">
|
||||
<a class="mr8" t-attf-href="#{blog_url(tag=one_tag.id, date_begin=False, date_end=False)}" t-esc="one_tag.name"/>
|
||||
</t>
|
||||
<div class="o_sharing_links">
|
||||
<a class="fa fa-twitter-square o_twitter"></a>
|
||||
<a class="fa fa-facebook-square o_facebook"></a>
|
||||
<a class="fa fa-linkedin-square o_linkedin"></a>
|
||||
<a class="fa fa-google-plus-square o_google"></a>
|
||||
</div>
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -172,51 +180,66 @@
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- Option: Blog Post List: show tags -->
|
||||
<template id="opt_blog_post_short_tags" name="Tags"
|
||||
customize_show="True" inherit_id="website_blog.blog_post_short">
|
||||
<xpath expr="//*[@name='blog_post_data']" position="inside">
|
||||
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
|
||||
<span class="fa fa-tags"/>
|
||||
<t t-foreach="blog_post.tag_ids" t-as="one_tag">
|
||||
<a class="mr8" t-attf-href="#{blog_url(tag=one_tag.id, date_begin=False, date_end=False)}" t-esc="one_tag.name"/>
|
||||
</t>
|
||||
</p>
|
||||
<!-- Option: Blog Post List: cover image -->
|
||||
<template id="opt_blog_post_cover_image" name="Cover image"
|
||||
customize_show="True" active="True" inherit_id="website_blog.blog_post_short">
|
||||
<xpath expr="//h2[@t-field='blog_post.name']/.." position="before">
|
||||
<t t-if="blog_posts_cover_properties[blog_post_index].get('background-image', 'none') != 'none'">
|
||||
<div id="js_blogcover" t-attf-class="#{blog_posts_cover_properties[blog_post_index].get('background-color')}" t-attf-style="background-image: #{blog_posts_cover_properties[blog_post_index].get('background-image', 'none')};opacity:1; height:250px; margin-top: 15px; margin-bottom: 30px;"></div>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Option: Blog Post List: grid layout -->
|
||||
<template id="opt_blog_post_grid_layout" name="Grid view"
|
||||
customize_show="True" active="False" inherit_id="website_blog.blog_post_short">
|
||||
<xpath expr="//div[@name='blog_post']" position="attributes">
|
||||
<attribute name="class" add="col-sm-5 o_grid" separator=" "/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Option: Blog Post List: display the author avatar -->
|
||||
<template id="opt_blog_post_author_avatar" name="Author avatar"
|
||||
customize_show="True" active="False" inherit_id="website_blog.blog_post_short">
|
||||
<xpath expr="//span[@t-field='blog_post.author_id']" position="before">
|
||||
<t t-if="blog_post.author_avatar">
|
||||
<div t-field="blog_post.author_avatar" class="o_not_editable" style="display:inline" t-field-options='{"widget": "image", "class": "img-circle o_author_avatar_little "}' />
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Blog Post Complete -->
|
||||
<template id="blog_post_complete" name="Blog Post">
|
||||
<t t-call="website_blog.index">
|
||||
<div class="container blog_publish_btn">
|
||||
<t t-call="website.publish_management">
|
||||
<t t-set="object" t-value="blog_post"/>
|
||||
<t t-set="publish_edit" t-value="True"/>
|
||||
<li>
|
||||
<form class="duplicate hidden" action="/blog/post_duplicate" method="POST">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<input name="blog_post_id" t-att-value="blog_post.id"/>
|
||||
</form>
|
||||
<a href="#" class="duplicate" onclick="$(this).prev('form').submit()">Duplicate</a>
|
||||
</li>
|
||||
</t>
|
||||
</div>
|
||||
<div t-attf-class="#{blog_post_cover_properties.get('resize_class', '')}" id="title" t-ignore="True">
|
||||
<div id="js_blogcover" t-attf-class="#{blog_post_cover_properties.get('background-color')}" t-attf-style="background-image: #{blog_post_cover_properties.get('background-image', 'none')};opacity:#{blog_post_cover_properties.get('opacity', 1)}">
|
||||
<div class="container blog_publish_btn">
|
||||
<t t-call="website.publish_management">
|
||||
<t t-set="object" t-value="blog_post"/>
|
||||
<t t-set="publish_edit" t-value="True"/>
|
||||
<li>
|
||||
<form class="duplicate hidden" action="/blog/post_duplicate" method="POST">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<input name="blog_post_id" t-att-value="blog_post.id"/>
|
||||
</form>
|
||||
<a href="#" class="duplicate" onclick="$(this).prev('form').submit()">Duplicate</a>
|
||||
</li>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div id="js_blogcover" t-attf-class="#{blog_post_cover_properties.get('background-color')}" t-attf-style="background-image: #{blog_post_cover_properties.get('background-image', 'none')};opacity:#{blog_post_cover_properties.get('opacity', 1)}"></div>
|
||||
<div class="blog_title">
|
||||
<h1 t-field="blog_post.name" id="blog_post_name" t-att-data-blog-id="blog_post.id" placeholder="Blog Post Title"/>
|
||||
<h2 t-field="blog_post.subtitle" placeholder="Subtitle"/>
|
||||
<p class="post-meta text-muted text-center" name="blog_post_data"/>
|
||||
<div>
|
||||
<t t-if="blog_post.author_avatar">
|
||||
<span t-field="blog_post.author_avatar" class="o_not_editable" t-options='{"widget": "image", "class": "img-circle", "style":"width: 30px; margin-right: 10px; display:inline"}' />
|
||||
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
|
||||
<span class="fa fa-tags"/>
|
||||
<t t-foreach="blog_post.tag_ids" t-as="one_tag">
|
||||
<a class="label label-primary mr8" t-attf-href="#{blog_url(tag=one_tag.id)}" t-esc="one_tag.name"/>
|
||||
</t>
|
||||
<span t-field="blog_post.author_id" style="display: inline-block;" t-options='{
|
||||
"widget": "contact",
|
||||
"fields": ["name"]
|
||||
}'/>
|
||||
</div>
|
||||
</p>
|
||||
<div t-if="blog_post_cover_properties.get('resize_class') == 'cover cover_full'" id="blog_angle_down">
|
||||
<strong><a href="#blog_content" class="fa fa-angle-down fa-3x fa-inverse mt4"/></strong>
|
||||
</div>
|
||||
@@ -225,29 +248,13 @@
|
||||
|
||||
<div id="blog_content" t-field="blog_post.content" class="blog_content mt32"/>
|
||||
|
||||
|
||||
<t t-if="next_post">
|
||||
<div class="cover cover_footer mb0 text-center" t-ignore="True">
|
||||
<div id="js_blogcover" t-attf-class="cover_footer_bg #{next_post_cover_properties.get('background-color')}" t-attf-style="background-image: #{next_post_cover_properties.get('background-image')};opacity:#{next_post_cover_properties.get('opacity', '1')}"></div>
|
||||
<div class="blog_title">
|
||||
<a class="hidden js_next" t-attf-href="/blog/#{ slug(next_post.blog_id) }/post/#{ slug(next_post) }/#wrap"/>
|
||||
<h1 t-field="next_post.name" placeholder="Blog Post Title"/>
|
||||
<h2 t-field="next_post.subtitle" placeholder="Subtitle"/>
|
||||
<div>
|
||||
<t t-if="next_post.author_avatar">
|
||||
<span t-field="next_post.author_avatar" t-options='{"widget": "image", "class": "img-circle", "style":"width: 30px; margin-right: 10px; display:inline"}' />
|
||||
</t>
|
||||
<span t-field="next_post.author_id" style="display: inline-block;" t-options='{
|
||||
"widget": "contact",
|
||||
"fields": ["name"]
|
||||
}'/>
|
||||
</div>
|
||||
<p class="mt32">Read Next <span class="fa fa-long-arrow-right"/></p>
|
||||
</div>
|
||||
<div class="o_blog_post_complete o_sharing_links">
|
||||
<a class="fa fa-twitter-square o_twitter_complete" id="o_twitter_complete"></a>
|
||||
<a class="fa fa-facebook-square o_facebook_complete" id="o_facebook_complete"></a>
|
||||
<a class="fa fa-linkedin-square o_linkedin_complete" id="o_linkedin_complete"></a>
|
||||
<a class="fa fa-google-plus-square o_google_complete" id="o_google_complete"></a>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- Options: Blog Post: breadcrumb -->
|
||||
@@ -273,9 +280,8 @@
|
||||
<!-- Options: Blog Post: user can reply -->
|
||||
<template id="opt_blog_post_complete_comment" name="Allow blog post comment"
|
||||
inherit_id="website_blog.blog_post_complete" active="False" customize_show="True">
|
||||
<xpath expr="//div[@id='blog_content']" position="after">
|
||||
<xpath expr="//div[@class='o_blog_post_complete o_sharing_links']" position="after">
|
||||
<section id="comments" class="read_width">
|
||||
<hr/>
|
||||
<t t-call="website_mail.message_thread">
|
||||
<t t-set="object" t-value="blog_post"/>
|
||||
<t t-set="chatter_mode" t-value="'json'"/>
|
||||
@@ -284,35 +290,66 @@
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Options: Blog Post: user can select text for tweet -->
|
||||
<!-- Options: Blog Post : Read Next Article -->
|
||||
<template id="opt_blog_post_complete_read_next" name="Read next article"
|
||||
inherit_id="website_blog.blog_post_complete" active="True" customize_show="True">
|
||||
<xpath expr="//div[@id='comments']|//div[@class='o_blog_post_complete o_sharing_links']" position="after">
|
||||
<t t-if="next_post">
|
||||
<div class="cover cover_footer mb0 text-center" t-ignore="True">
|
||||
<div id="js_blogcover" t-attf-class="cover_footer_bg #{next_post_cover_properties.get('background-color')}" t-attf-style="background-image: #{next_post_cover_properties.get('background-image')};opacity:#{next_post_cover_properties.get('opacity')}"></div>
|
||||
<div class="blog_title">
|
||||
<a class="hidden js_next" t-attf-href="/blog/#{ slug(next_post.blog_id) }/post/#{ slug(next_post) }/#wrap"/>
|
||||
<h1 t-field="next_post.name" placeholder="Blog Post Title"/>
|
||||
<h2 t-field="next_post.subtitle" placeholder="Subtitle"/>
|
||||
<div>
|
||||
<t t-if="next_post.author_avatar">
|
||||
<span t-field="next_post.author_avatar" t-field-options='{"widget": "image", "class": "img-circle", "style":"width: 30px; margin-right: 10px; display:inline"}' />
|
||||
</t>
|
||||
<span t-field="next_post.author_id" style="display: inline-block;" t-field-options='{
|
||||
"widget": "contact",
|
||||
"fields": ["name"]
|
||||
}'/>
|
||||
</div>
|
||||
<p class="mt32">Read Next <span class="fa fa-long-arrow-right"/></p>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Options: Blog Post: display the author avatar -->
|
||||
<template id="opt_blog_post_author_avatar_display" name="Author Avatar"
|
||||
inherit_id="website_blog.blog_post_complete" active="False" customize_show="True">
|
||||
<xpath expr="//p[@name='blog_post_data']" position="after">
|
||||
<div>
|
||||
<t t-if="blog_post.author_avatar">
|
||||
<span t-field="blog_post.author_avatar" class="o_not_editable" t-field-options='{"widget": "image", "class": "img-circle", "style":"width: 30px; margin-right: 10px; display:inline"}' />
|
||||
</t>
|
||||
<span t-field="blog_post.author_id" style="display: inline-block;" t-field-options='{
|
||||
"widget": "contact",
|
||||
"fields": ["name"]
|
||||
}'/>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="opt_blog_post_select_to_tweet" name="Select to Tweet"
|
||||
inherit_id="website_blog.blog_post_complete" active="False" customize_show="True">
|
||||
<xpath expr="//div[@id='blog_content']" position="attributes">
|
||||
<attribute name="class">blog_content js_tweet mt32</attribute>
|
||||
<attribute name="class" add="js_tweet" separator=" "/>
|
||||
</xpath>
|
||||
<xpath expr="//div[@id='title']//div[@class='blog_title']" position="attributes">
|
||||
<attribute name="class">blog_title js_tweet</attribute>
|
||||
<xpath expr="//div[@id='title']//div[contains(@class, 'blog_title')]" position="attributes">
|
||||
<attribute name="class" add="js_tweet" separator=" "/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Options: Blog Post: user can add Inline Discussion -->
|
||||
<template id="opt_blog_post_inline_discussion" name="Allow comment in text"
|
||||
inherit_id="website_blog.blog_post_complete" active="False" customize_show="True">
|
||||
<template id="opt_blog_post_select_to_comment" name="Select to comment"
|
||||
inherit_id="website_blog.opt_blog_post_complete_comment" customize_show="False">
|
||||
<xpath expr="//div[@id='blog_content']" position="attributes">
|
||||
<attribute name="enable_chatter_discuss">True</attribute>
|
||||
<attribute name="class" add="js_comment" separator=" "/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Options: Blog Post: show tags -->
|
||||
<template id="opt_blog_post_complete_tags" name="Tags"
|
||||
customize_show="True" inherit_id="website_blog.blog_post_complete">
|
||||
<xpath expr="//p[@name='blog_post_data']" position="after">
|
||||
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
|
||||
<span class="fa fa-tags"/>
|
||||
<t t-foreach="blog_post.tag_ids" t-as="one_tag">
|
||||
<a class="mr8" t-attf-href="#{blog_url(tag=one_tag.id)}" t-esc="one_tag.name"/>
|
||||
</t>
|
||||
</p>
|
||||
<xpath expr="//div[@id='title']//div[contains(@class, 'blog_title')]" position="attributes">
|
||||
<attribute name="class" add="js_comment" separator=" "/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
@@ -366,16 +403,19 @@
|
||||
<section class="mt32">
|
||||
<h4>Archives</h4>
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<t t-foreach="nav_list" t-as="months">
|
||||
<t t-if="months['date_begin'] == date">
|
||||
<li class="active">
|
||||
<a t-ignore="True" t-attf-href="#{blog_url(date_begin=False, date_end=False)}"><t t-esc="months['create_date']"/><span class="pull-right badge" t-esc="months['create_date_count']"/></a>
|
||||
</li>
|
||||
</t>
|
||||
<t t-if="months['date_begin'] != date">
|
||||
<li>
|
||||
<a t-ignore="True" t-attf-href="#{blog_url(date_begin=months['date_begin'], date_end=months['date_end'])}"><t t-esc="months['create_date']"/><span class="pull-right badge" t-esc="months['create_date_count']"/></a>
|
||||
</li>
|
||||
<t t-foreach="nav_list" t-as="year">
|
||||
<li t-esc="year"/>
|
||||
<t t-foreach="nav_list[year]" t-as="months">
|
||||
<t t-if="months['date_begin'] == date">
|
||||
<li class="active">
|
||||
<a t-ignore="True" t-attf-href="#{blog_url(date_begin=False, date_end=False)}"><t t-esc="months['month']"/><span class="pull-right badge" t-esc="months['create_date_count']"/></a>
|
||||
</li>
|
||||
</t>
|
||||
<t t-else="1">
|
||||
<li>
|
||||
<a t-ignore="True" t-attf-href="#{blog_url(date_begin=months['date_begin'], date_end=months['date_end'])}"><t t-esc="months['month']"/><span class="pull-right badge" t-esc="months['create_date_count']"/></a>
|
||||
</li>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</ul>
|
||||
@@ -395,23 +435,20 @@
|
||||
<p>
|
||||
Write a small text here for when <b>new visitors</b> find your website
|
||||
through your <b>blog entries</b>, referenced in Google.
|
||||
</p>
|
||||
<div>
|
||||
<a href="/page/website.contactus"><button class="btn btn-primary">Contact us</button></a>
|
||||
</div>
|
||||
</p>
|
||||
</section>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Option:Right Column: follow us -->
|
||||
<template id="opt_blog_rc_follow_us" name="Follow us" priority="4"
|
||||
<template id="opt_blog_rc_follow_us" name="Subscription" priority="4"
|
||||
inherit_id="website_blog.index_right" active="True" customize_show="True">
|
||||
<xpath expr="//div[@id='main_column']" position="attributes">
|
||||
<attribute name="class">col-sm-8</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//div[@id='blog_right_column']" position="inside">
|
||||
<section class="mt32">
|
||||
<h4>Follow us<small t-if="blog">: <t t-esc="blog.name"/></small></h4>
|
||||
<h4>Stay updated :</h4>
|
||||
<t t-if="blog">
|
||||
<t t-call="website_mail.follow">
|
||||
<t t-set="email" t-value="user_id.email"/>
|
||||
|
||||
Reference in New Issue
Block a user