[IMP] Blogs Medium-Like
bzr revid: fp@tinyerp.com-20140223094412-zryqfz2b0n3ojo6g
|
@ -21,4 +21,3 @@
|
||||||
|
|
||||||
import controllers
|
import controllers
|
||||||
import models
|
import models
|
||||||
import wizard
|
|
||||||
|
|
|
@ -35,16 +35,13 @@ OpenERP Blog
|
||||||
'data/website_blog_data.xml',
|
'data/website_blog_data.xml',
|
||||||
'views/website_blog_views.xml',
|
'views/website_blog_views.xml',
|
||||||
'views/website_blog_templates.xml',
|
'views/website_blog_templates.xml',
|
||||||
'wizard/document_page_show_diff_view.xml',
|
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'security/website_blog.xml',
|
'security/website_blog.xml',
|
||||||
],
|
],
|
||||||
'demo': [
|
'demo': [
|
||||||
'data/website_blog_demo.xml'
|
'data/website_blog_demo.xml'
|
||||||
],
|
],
|
||||||
'test': [
|
'test': [],
|
||||||
'tests/test_website_blog.yml'
|
|
||||||
],
|
|
||||||
'qweb': [
|
'qweb': [
|
||||||
'static/src/xml/*.xml'
|
'static/src/xml/*.xml'
|
||||||
],
|
],
|
||||||
|
|
|
@ -25,7 +25,9 @@ from openerp.tools.translate import _
|
||||||
from openerp import SUPERUSER_ID
|
from openerp import SUPERUSER_ID
|
||||||
|
|
||||||
import werkzeug
|
import werkzeug
|
||||||
|
import random
|
||||||
|
import json
|
||||||
|
from openerp.tools import html2plaintext
|
||||||
|
|
||||||
|
|
||||||
class WebsiteBlog(http.Controller):
|
class WebsiteBlog(http.Controller):
|
||||||
|
@ -144,8 +146,26 @@ class WebsiteBlog(http.Controller):
|
||||||
'path_filter': path_filter,
|
'path_filter': path_filter,
|
||||||
'date': date,
|
'date': date,
|
||||||
}
|
}
|
||||||
return request.website.render("website_blog.blog_post_short", values)
|
response = request.website.render("website_blog.blog_post_short", values)
|
||||||
|
response.set_cookie('unvisited', json.dumps(blog_post_ids))
|
||||||
|
return response
|
||||||
|
|
||||||
|
def get_next_post(self, cr, uid, blog_post, context):
|
||||||
|
""" Get next blog post display in footer of current post """
|
||||||
|
blog_post_obj = request.registry.get('blog.post')
|
||||||
|
unvisited = eval(request.httprequest.cookies.get('unvisited'))
|
||||||
|
if blog_post.id in unvisited:
|
||||||
|
# if post is not visited yet return a random post
|
||||||
|
unvisited.remove(blog_post.id)
|
||||||
|
post_list = blog_post_obj.search(cr, uid, [('id', '!=', blog_post.id)],context=context)
|
||||||
|
next_post_id = post_list[random.randint(0, (len(post_list)-1))]
|
||||||
|
else:
|
||||||
|
# if post is visited return a most visited(count) and post share same keywords
|
||||||
|
post_list = blog_post_obj.search(cr, uid, [('id', '!=', blog_post.id),('website_meta_keywords', 'ilike', blog_post.website_meta_keywords)], order='visits',context=context)
|
||||||
|
next_post_id = post_list and post_list[0] or (unvisited and unvisited[0] or False)
|
||||||
|
next_post = next_post_id and blog_post_obj.browse(cr, uid, next_post_id, context=context) or False
|
||||||
|
return (next_post,unvisited)
|
||||||
|
|
||||||
@http.route([
|
@http.route([
|
||||||
'/blogpost/<model("blog.post"):blog_post>/',
|
'/blogpost/<model("blog.post"):blog_post>/',
|
||||||
], type='http', auth="public", website=True, multilang=True)
|
], type='http', auth="public", website=True, multilang=True)
|
||||||
|
@ -172,6 +192,7 @@ class WebsiteBlog(http.Controller):
|
||||||
- 'pager': the pager to display comments pager in a blog post
|
- 'pager': the pager to display comments pager in a blog post
|
||||||
- 'tag': current tag, if tag_id
|
- 'tag': current tag, if tag_id
|
||||||
- 'nav_list': a dict [year][month] for archives navigation
|
- 'nav_list': a dict [year][month] for archives navigation
|
||||||
|
- 'next_blog': next blog post , display in footer
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pager_url = "/blogpost/%s" % blog_post.id
|
pager_url = "/blogpost/%s" % blog_post.id
|
||||||
|
@ -196,9 +217,17 @@ class WebsiteBlog(http.Controller):
|
||||||
tag_ids = tag_obj.search(cr, uid, [], context=context)
|
tag_ids = tag_obj.search(cr, uid, [], context=context)
|
||||||
tags = tag_obj.browse(cr, uid, tag_ids, context=context)
|
tags = tag_obj.browse(cr, uid, tag_ids, context=context)
|
||||||
|
|
||||||
|
blog_post_obj = request.registry.get('blog.post')
|
||||||
|
if not request.httprequest.session.get(blog_post.id,False):
|
||||||
|
request.httprequest.session[blog_post.id] = True
|
||||||
|
counter = blog_post.visits + 1;
|
||||||
|
blog_post_obj.write(cr, SUPERUSER_ID, [blog_post.id], {'visits':counter},context=context)
|
||||||
|
|
||||||
MONTHS = [None, _('January'), _('February'), _('March'), _('April'),
|
MONTHS = [None, _('January'), _('February'), _('March'), _('April'),
|
||||||
_('May'), _('June'), _('July'), _('August'), _('September'),
|
_('May'), _('June'), _('July'), _('August'), _('September'),
|
||||||
_('October'), _('November'), _('December')]
|
_('October'), _('November'), _('December')]
|
||||||
|
|
||||||
|
next_post, unvisited = self.get_next_post(cr, uid, blog_post, context)
|
||||||
|
|
||||||
values = {
|
values = {
|
||||||
'blog': blog_post.blog_id,
|
'blog': blog_post.blog_id,
|
||||||
|
@ -211,12 +240,14 @@ class WebsiteBlog(http.Controller):
|
||||||
'nav_list': self.nav_list(),
|
'nav_list': self.nav_list(),
|
||||||
'enable_editor': enable_editor,
|
'enable_editor': enable_editor,
|
||||||
'date': date,
|
'date': date,
|
||||||
'date_name': date and "%s %s" % (MONTHS[int(date.split("-")[1])], date.split("-")[0]) or None
|
'date_name': date and "%s %s" % (MONTHS[int(date.split("-")[1])], date.split("-")[0]) or None,
|
||||||
|
'next_post' : next_post,
|
||||||
}
|
}
|
||||||
return request.website.render("website_blog.blog_post_complete", values)
|
response = request.website.render("website_blog.blog_post_complete", values)
|
||||||
|
response.set_cookie('unvisited', json.dumps(unvisited))
|
||||||
@http.route(['/blogpost/comment'], type='http', auth="public", methods=['POST'], website=True)
|
return response
|
||||||
def blog_post_comment(self, blog_post_id=0, **post):
|
|
||||||
|
def _blog_post_message(self, blog_post_id=0, **post):
|
||||||
cr, uid, context = request.cr, request.uid, request.context
|
cr, uid, context = request.cr, request.uid, request.context
|
||||||
if post.get('comment'):
|
if post.get('comment'):
|
||||||
user = request.registry['res.users'].browse(cr, SUPERUSER_ID, uid, context=context)
|
user = request.registry['res.users'].browse(cr, SUPERUSER_ID, uid, context=context)
|
||||||
|
@ -225,15 +256,35 @@ class WebsiteBlog(http.Controller):
|
||||||
if group_id in [group.id for group in group_ids]:
|
if group_id in [group.id for group in group_ids]:
|
||||||
blog_post = request.registry['blog.post']
|
blog_post = request.registry['blog.post']
|
||||||
blog_post.check_access_rights(cr, uid, 'read')
|
blog_post.check_access_rights(cr, uid, 'read')
|
||||||
blog_post.message_post(
|
message_id = blog_post.message_post(
|
||||||
cr, SUPERUSER_ID, int(blog_post_id),
|
cr, SUPERUSER_ID, int(blog_post_id),
|
||||||
body=post.get('comment'),
|
body=post.get('comment'),
|
||||||
type='comment',
|
type='comment',
|
||||||
subtype='mt_comment',
|
subtype='mt_comment',
|
||||||
author_id=user.partner_id.id,
|
author_id=user.partner_id.id,
|
||||||
|
discussion=post.get('discussion'),
|
||||||
context=dict(context, mail_create_nosubcribe=True))
|
context=dict(context, mail_create_nosubcribe=True))
|
||||||
|
return message_id
|
||||||
|
|
||||||
|
@http.route(['/blogpost/comment'], type='http', auth="public", methods=['POST'], website=True)
|
||||||
|
def blog_post_comment(self, blog_post_id=0, **post):
|
||||||
|
self._blog_post_message(blog_post_id, **post)
|
||||||
return werkzeug.utils.redirect(request.httprequest.referrer + "#comments")
|
return werkzeug.utils.redirect(request.httprequest.referrer + "#comments")
|
||||||
|
|
||||||
|
@http.route(['/blogpost/post_discussion'], type='json', auth="public", website=True)
|
||||||
|
def post_discussion(self, blog_post_id=0, **post):
|
||||||
|
id = self._blog_post_message(blog_post_id, **post)
|
||||||
|
mail_obj = request.registry.get('mail.message')
|
||||||
|
values = []
|
||||||
|
post = mail_obj.browse(request.cr, SUPERUSER_ID, id)
|
||||||
|
values = {
|
||||||
|
"author_name": post.author_id.name,
|
||||||
|
"date": post.date,
|
||||||
|
"body": html2plaintext(post.body),
|
||||||
|
"author_image": "data:image/png;base64,%s" % post.author_id.image,
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
|
||||||
@http.route('/blogpost/new', type='http', auth="public", website=True, multilang=True)
|
@http.route('/blogpost/new', type='http', auth="public", website=True, multilang=True)
|
||||||
def blog_post_create(self, blog_id, **post):
|
def blog_post_create(self, blog_id, **post):
|
||||||
cr, uid, context = request.cr, request.uid, request.context
|
cr, uid, context = request.cr, request.uid, request.context
|
||||||
|
@ -259,3 +310,25 @@ class WebsiteBlog(http.Controller):
|
||||||
create_context = dict(context, mail_create_nosubscribe=True)
|
create_context = dict(context, mail_create_nosubscribe=True)
|
||||||
new_blog_post_id = request.registry['blog.post'].copy(cr, uid, blog_post_id, {}, context=create_context)
|
new_blog_post_id = request.registry['blog.post'].copy(cr, uid, blog_post_id, {}, context=create_context)
|
||||||
return werkzeug.utils.redirect("/blogpost/%s/?enable_editor=1" % new_blog_post_id)
|
return werkzeug.utils.redirect("/blogpost/%s/?enable_editor=1" % new_blog_post_id)
|
||||||
|
|
||||||
|
@http.route('/blogpost/get_discussion', type='json', auth="public", website=True)
|
||||||
|
def discussion(self, post_id=0, discussion=None, **post):
|
||||||
|
mail_obj = request.registry.get('mail.message')
|
||||||
|
values = []
|
||||||
|
ids = mail_obj.search(request.cr, SUPERUSER_ID, [('res_id', '=', int(post_id)) ,('model','=','blog.post'), ('discussion', '=', discussion)])
|
||||||
|
if ids:
|
||||||
|
for post in mail_obj.browse(request.cr, SUPERUSER_ID, ids):
|
||||||
|
values.append({
|
||||||
|
"author_name": post.author_id.name,
|
||||||
|
"date": post.date,
|
||||||
|
'body': html2plaintext(post.body),
|
||||||
|
'author_image': "data:image/png;base64,%s" % post.author_id.image,
|
||||||
|
})
|
||||||
|
return values
|
||||||
|
|
||||||
|
@http.route('/blogpsot/change_background', type='json', auth="public", website=True)
|
||||||
|
def change_bg(self, post_id=0,image=None, **post):
|
||||||
|
post_obj = request.registry.get('blog.post')
|
||||||
|
values = {'content_image' : image}
|
||||||
|
ids = post_obj.write(request.cr, SUPERUSER_ID, [int(post_id)], values)
|
||||||
|
return []
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<record id="blog_blog_1" model="blog.blog">
|
<record id="blog_blog_1" model="blog.blog">
|
||||||
<field name="name">News</field>
|
<field name="name">News</field>
|
||||||
<field name="description">Presentation of new OpenERP features</field>
|
<field name="description">Presentation of new OpenERP features</field>
|
||||||
|
<field name="image" type="base64" file="website_blog/static/src/img/news.png"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="menu_news" model="website.menu">
|
<record id="menu_news" model="website.menu">
|
||||||
|
|
|
@ -13,218 +13,257 @@
|
||||||
<record id="blog_tag_3" model="blog.tag">
|
<record id="blog_tag_3" model="blog.tag">
|
||||||
<field name="name">website</field>
|
<field name="name">website</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="blog_tag_4" model="blog.tag">
|
|
||||||
<field name="name">pos</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- POSTS -->
|
<!-- POSTS -->
|
||||||
<record id="blog_post_1" model="blog.post">
|
<record id="blog_post_1" model="blog.post">
|
||||||
<field name="name">OpenERP v8 New Features</field>
|
<field name="name">The Future of Emails</field>
|
||||||
|
<field name="sub_title">Ideas behing the OpenERP communication tools.</field>
|
||||||
<field name="blog_id" ref="blog_blog_1"/>
|
<field name="blog_id" ref="blog_blog_1"/>
|
||||||
<field name="tag_ids" eval="[(6, 0, [ref('blog_tag_1')])]"/>
|
<field name="tag_ids" eval="[(6, 0, [ref('blog_tag_1')])]"/>
|
||||||
<field name="website_published" eval="True"/>
|
<field name="website_published" eval="True"/>
|
||||||
<field name="website_meta_keywords">OpenERP, Point of Sale, Hardware, Interface, Payment Terminal, Store</field>
|
<field name="website_meta_keywords">OpenERP, email</field>
|
||||||
<field name="website_meta_description">Open source Point of Sale with no installation required that runs online and offline.</field>
|
<field name="website_meta_description">The Future of Emails</field>
|
||||||
|
<field name="content_image">/website_blog/static/src/img/post1.jpg</field>
|
||||||
<field name="content"><![CDATA[
|
<field name="content"><![CDATA[
|
||||||
<section data-snippet-id='image-text'>
|
<section class="mt16 mb16" data-snippet-id='image-text'>
|
||||||
<div class="container">
|
<div class="container readable">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 mt16 mb16">
|
<iframe width="361" height="200" src="http://www.youtube.com/embed/EkbBFmIWoTE" frameborder="0" allowfullscreen></iframe>
|
||||||
<img class="img-responsive shadow" src="/website/static/src/img/image_text.jpg"/>
|
<p>
|
||||||
</div>
|
Emails are broken.
|
||||||
<div class="col-md-6 mt16">
|
</p><p>
|
||||||
<p>
|
Emails make me waste my time. But I need them.
|
||||||
OpenERP's Point of Sale introduces a super clean
|
Given the importance that emails have in our lives,
|
||||||
interface with no installation required that runs
|
it's incredible it's still one of the only software
|
||||||
online and offline on modern hardwares.
|
areas that did not evolve in the past 20 years!
|
||||||
</p><p>
|
</p><p>
|
||||||
It's full integration with the company inventory
|
Reading my inbox is the most unproductive task I do
|
||||||
and accounting, gives you real time statistics
|
on a daily basis. I have to spend one full hour a
|
||||||
without the hassle of integrating several applications.
|
day to process my emails. All the junk flows in the
|
||||||
</p>
|
same inbox; spams, information that doesn't matter,
|
||||||
</div>
|
quoted answers of quoted answers, etc. At the end
|
||||||
|
of the hour, only 10 emails actually requested an
|
||||||
|
answer from me. With a good tool, I could have done
|
||||||
|
my job in 10 minutes!
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="mt16 mb16" data-snippet-id='text-block'>
|
<section class="mt16 mb16" data-snippet-id='text-image'>
|
||||||
<div class="container">
|
<div class="container readable">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12 text-center mt16 mb32">
|
<p>
|
||||||
<h2>
|
At OpenERP, we build tools to bring productivity to
|
||||||
Linked with Project Management
|
enterprises. As emails and information flows are one of
|
||||||
</h2>
|
the biggest wastes of time in companies, we have to fix
|
||||||
<h3 class="text-muted">Infinitely flexible. Incredibly easy to use.</h3>
|
this.
|
||||||
</div>
|
</p><p>
|
||||||
<div class="col-md-12 mb16 mt16">
|
To disrupt emails, you need more than just another user
|
||||||
<p>
|
interface. We need to rethink the whole communication flow.
|
||||||
OpenERP's <b>collaborative and realtime</b> project
|
</p>
|
||||||
management helps your team get work done. Keep
|
<h3>The Communication Mechanism of OpenERP</h3>
|
||||||
track of everything, from the big picture to the
|
<p>
|
||||||
minute details, from the customer contract to the
|
Here are the ideas behing the OpenERP communication tools:
|
||||||
billing.
|
</p>
|
||||||
</p><p>
|
<ul>
|
||||||
Organize projects around <b>your own processes</b>. Work
|
<li>
|
||||||
on tasks and issues using the kanban view, schedule
|
Get Things Done: your inbox is a
|
||||||
tasks using the gantt chart and control deadlines
|
todo list. You should be able to process (not only
|
||||||
in the calendar view. Every project may have it's
|
read) the inbox and easily mark messages for future
|
||||||
own stages allowing teams to optimize their job.
|
actions. Every inbox should be empty after having
|
||||||
</p>
|
been processed; no more overload of information.
|
||||||
</div>
|
<img class="img-responsive" src="/website_blog/static/src/img/mail-sc-00.png"/>
|
||||||
|
</li><li>
|
||||||
|
Keep control of what you want to receive or don't want
|
||||||
|
to receive. People should never receive spam. You
|
||||||
|
should follow/unfollow any kind of information in one
|
||||||
|
click.
|
||||||
|
</li><li>
|
||||||
|
Productivity is key: our smart user
|
||||||
|
interface does not require you to click on every mail
|
||||||
|
to read a thread. Reading a full thread, replying,
|
||||||
|
attaching documents is super fast.
|
||||||
|
<img class="img-responsive" src="/website_blog/static/src/img/mail-sc-03.png"/>
|
||||||
|
</li><li>
|
||||||
|
A mix of push & pull: Today, people
|
||||||
|
are victims of what others decide to push to them.
|
||||||
|
OpenERP differentiates:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Messages "for information":
|
||||||
|
you can pull them when you need some specific
|
||||||
|
information; they are not required to be read
|
||||||
|
every day.You receive only what you decided
|
||||||
|
to follow.This accounts for 90% of your daily
|
||||||
|
emails.Use the "Inbox" menu for these.
|
||||||
|
</li><li>
|
||||||
|
Messages "for action": they
|
||||||
|
require your immediate attention and you need
|
||||||
|
to process them all. This accounts for 10%
|
||||||
|
of your daily emails. Use the "To: me" menu
|
||||||
|
for these.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li><li>
|
||||||
|
Focus on the Content: Everything is
|
||||||
|
stripped to emphasize on the real message. No more
|
||||||
|
welcome introductions, greetings, signatures and legal
|
||||||
|
notes.We standardize the layout of each message.
|
||||||
|
(signatures are on the profile of a contact, not in
|
||||||
|
every message)
|
||||||
|
</li><li>
|
||||||
|
Folders and mailing lists are great tools but too
|
||||||
|
complex in traditional email clients. In OpenERP, a
|
||||||
|
group of contacts that share a discussion can be
|
||||||
|
created with one click. Every group should have it's
|
||||||
|
own email address.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>All of this with a super sexy and minimalist user interface.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="oe_dark mt16 mb16" data-snippet-id='big-picture'>
|
|
||||||
<div class="container">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-12 text-center mt32 mb32">
|
|
||||||
<h2>Work with the hardware you already have...</h2>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-12">
|
|
||||||
<img class="img-responsive" src="/website/static/src/img/big_picture.png" style="margin: 0 auto;"/>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 col-md-offset-3 mb16 mt16">
|
|
||||||
<p class="text-center">
|
|
||||||
<b>No installation required</b>
|
|
||||||
</p>
|
|
||||||
<p class="text-center">
|
|
||||||
OpenERP's Point of Sale introduces a super clean
|
|
||||||
interface with no installation required that runs
|
|
||||||
online and offline on modern hardware. Laptops,
|
|
||||||
tablets, industrial POS, it runs on everything.
|
|
||||||
</p>
|
|
||||||
<p class="text-center">
|
|
||||||
<a href="/page/website.contactus">Get more information »</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
]]>
|
]]>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="blog_post_2" model="blog.post">
|
<record id="blog_post_2" model="blog.post">
|
||||||
<field name="name">New Hardware Integration</field>
|
<field name="name">OpenERP launches integrated CMS and E-Commerce</field>
|
||||||
|
<field name="sub_title">Building your company's website and selling your products online easy.</field>
|
||||||
<field name="blog_id" ref="blog_blog_1"/>
|
<field name="blog_id" ref="blog_blog_1"/>
|
||||||
|
<field name="website_published" eval="True"/>
|
||||||
<field name="tag_ids" eval="[(6, 0, [ref('blog_tag_1')])]"/>
|
<field name="tag_ids" eval="[(6, 0, [ref('blog_tag_1')])]"/>
|
||||||
|
<field name="content_image">/website_blog/static/src/img/post2.jpg</field>
|
||||||
<field name="content">
|
<field name="content">
|
||||||
<![CDATA[<section class="mt16 mb16" data-snippet-id='big-picture'>
|
<![CDATA[<section class="mt16 mb16 " data-snippet-id='image-text'>
|
||||||
<div class="container">
|
<div class="container readable">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<img class="img-responsive" src="/website/static/src/img/big_picture.png" style="margin: 0 auto;"/>
|
<img class="img-responsive" src="/website_blog/static/src/img/CMS_WMS_screens.jpg"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-md-offset-3 mb16 mt16">
|
<div class="col-md-6 col-md-offset-3 mb16 mt16">
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<b>New Features Launched</b>
|
New Features Launched
|
||||||
</p>
|
|
||||||
<p class="text-center">
|
|
||||||
OpenERP's Point of Sale introduces a super clean
|
|
||||||
interface with no installation required that runs
|
|
||||||
online and offline on modern hardware. Laptops,
|
|
||||||
tablets, industrial POS, it runs on everything.
|
|
||||||
</p>
|
</p>
|
||||||
|
<h4 class="text-center">
|
||||||
|
To add to an already comprehensive set of OpenERP
|
||||||
|
features, a website content management system (CMS
|
||||||
|
or WMS) has been developed and a beta release is
|
||||||
|
available from today, 31st January 2014.
|
||||||
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section data-snippet-id='pricing'>
|
<section data-snippet-id='text'>
|
||||||
<div class="container">
|
<div class="container readable">
|
||||||
<div class="row">
|
<p>
|
||||||
<div class="col-md-12 text-center mt16 mb32">
|
OpenERP claims to be 'the Open Source software that makes
|
||||||
<h2>Our Offers</h2>
|
building your company's website and selling your products
|
||||||
</div>
|
online easy'. So how true is this statement?
|
||||||
|
</p><p>
|
||||||
<div class="col-md-4">
|
"OpenERP's latest launch will allow a business to go from
|
||||||
<div class="panel panel-info">
|
zero to trading online quicker than ever before,” Stuart
|
||||||
<!-- Default panel contents -->
|
Mackintosh, MD of Open Source specialist and OpenERP
|
||||||
<div class="panel-heading text-center">
|
integration partner, OpusVL, explains. “The investment
|
||||||
<h2 style="margin: 0">Beginner</h2>
|
required to have a fully automated business system is
|
||||||
<p style="margin: 0" class="text-muted">
|
dramatically reduced, enabling the small and medium
|
||||||
Starter package
|
enterprise to compete at a level of functionality and
|
||||||
</p>
|
performance previously reserved for the big IT investors."
|
||||||
</div>
|
</p>
|
||||||
<div class="panel-body text-center text-muted" style="background-color: rgba(0,0,0,0.1)">
|
<h4>
|
||||||
<h2 style="margin: 0"><span>$</span><b style="font-size: 60px">450</b><small>.00</small></h2>
|
"Finally, the leading edge is being brought to the masses.
|
||||||
<div>per month</div>
|
It will now be the turn of the big players to catch up to
|
||||||
</div>
|
the superior technologies of the SME."
|
||||||
|
</h4>
|
||||||
<!-- List group -->
|
<p>
|
||||||
<ul class="list-group">
|
"This is another clever and highly disruptive move by
|
||||||
<li class="list-group-item">Battery: 8 hours</li>
|
OpenERP,which will force other technology providers to
|
||||||
<li class="list-group-item">Screen: 2.5 inch</li>
|
take another look at the value they are providing to ensure
|
||||||
<li class="list-group-item">Weight: 1.1 ounces</li>
|
that their 'solutions' can still compete."
|
||||||
<li class="list-group-item">No support</li>
|
</p><p>
|
||||||
</ul>
|
"OpenERP now competes on many fronts, with no real
|
||||||
<div class="panel-footer text-center">
|
competition out there to knock them off the top spot.
|
||||||
<p class="text-muted">
|
With the launch of their integrated CMS and Ecommerce
|
||||||
<i>Free shipping, satisfied or reimbursed.</i>
|
systems,it only elevates their position as one of the leading
|
||||||
</p>
|
lights in the open source revolution. It will be at least 5
|
||||||
<a href="/page/website.contactus" class="btn btn-primary btn-lg">Order now</a>
|
years before another ERP or CMS provider will be able to
|
||||||
</div>
|
compete at this level due to the technology currently
|
||||||
</div>
|
employed by most industry providers."
|
||||||
</div>
|
</p>
|
||||||
<div class="col-md-4">
|
<h4>Adding to industry leading technology</h4>
|
||||||
<div class="panel panel-primary">
|
<p>
|
||||||
<!-- Default panel contents -->
|
Like many modern website editors, with OpenERP you can edit
|
||||||
<div class="panel-heading text-center">
|
content in-line, enabling you to see exactly what you are
|
||||||
<h2 style="margin: 0">Professional</h2>
|
changing and ensure your changes suit the context.
|
||||||
<p style="margin: 0">
|
</p><p>
|
||||||
Enterprise package
|
However, unlike other web content management systems, it
|
||||||
</p>
|
fully integrates into the back-end database. This means
|
||||||
</div>
|
that when you edit a product description, image or price,
|
||||||
<div class="panel-body text-center text-muted" style="background-color: rgba(0,0,0,0.1)">
|
it updates the product database in real time, providing a
|
||||||
<h2 style="margin: 0"><span>$</span><b style="font-size: 60px">590</b><small>.00</small></h2>
|
true self-service window into the business.
|
||||||
<div>per month</div>
|
</p><p>
|
||||||
</div>
|
This provides a single source of data for your company and
|
||||||
|
removes the need to create offline synchronisation between
|
||||||
<!-- List group -->
|
website and product database.
|
||||||
<ul class="list-group">
|
</p><p>
|
||||||
<li class="list-group-item">Battery: 12 hours</li>
|
As it comes, there is a default website based on Bootstrap
|
||||||
<li class="list-group-item">Screen: 2.8 inch</li>
|
3, the latest industry standard for rapid development of
|
||||||
<li class="list-group-item">Weight: 1.2 ounces</li>
|
multi-device websites backed by Twitter, so can be directly
|
||||||
<li class="list-group-item">Limited support</li>
|
integrated with many web tools and works across all devices
|
||||||
</ul>
|
by default.
|
||||||
<div class="panel-footer text-center">
|
</p>
|
||||||
<p class="text-muted">
|
<h4>So, what does this mean to me and my business?</h4>
|
||||||
<i>Free shipping, satisfied or reimbursed.</i>
|
<p>
|
||||||
</p>
|
The CMS removes the need for Magento integration for the
|
||||||
<a href="/page/website.contactus" class="btn btn-primary btn-lg">Order now</a>
|
shopping basket and Drupal/Joomla for the website. For any
|
||||||
</div>
|
organisation, this will reduce the technology footprint and
|
||||||
</div>
|
eliminate the complexities of FTP or file transfer data
|
||||||
</div>
|
uploads and exports which for many, are manual tasks.
|
||||||
<div class="col-md-4">
|
Implementation is easier and the web designer can get
|
||||||
<div class="panel panel-info">
|
straight on with developing the site without requiring the
|
||||||
<!-- Default panel contents -->
|
project management and interactions with site developers,
|
||||||
<div class="panel-heading text-center">
|
providing a quicker and more efficient deployment. However,
|
||||||
<h2 style="margin: 0">Expert</h2>
|
for larger sites, stringent process and project management
|
||||||
<p style="margin: 0" class="text-muted">
|
disciplines are still required to ensure a low-risk project.
|
||||||
The top of the top
|
</p>
|
||||||
</p>
|
<h4>How does it work in practice?</h4>
|
||||||
</div>
|
<p>
|
||||||
<div class="panel-body text-center text-muted" style="background-color: rgba(0,0,0,0.1)">
|
When items are placed in the basket, a sales order is
|
||||||
<h2 style="margin: 0"><span>$</span><b style="font-size: 60px">890</b><small>.00</small></h2>
|
created automatically to reflect the basket contents.
|
||||||
<div>per month</div>
|
Payments are recorded on the balance sheet and all
|
||||||
</div>
|
accounting journal entries are automatic. As it is in real
|
||||||
|
time, stock records are always accurate and decremented on
|
||||||
<!-- List group -->
|
the fly when orders placed.
|
||||||
<ul class="list-group">
|
</p><p>
|
||||||
<li class="list-group-item">Battery: 20 hours</li>
|
Automatic translations can be created for international
|
||||||
<li class="list-group-item">Screen: 2.8 inch</li>
|
traders and available languages selected.
|
||||||
<li class="list-group-item">Weight: 1.2 ounces</li>
|
</p>
|
||||||
<li class="list-group-item">Unlimited support</li>
|
<p>
|
||||||
</ul>
|
Customer queries and returns can be set up to use the case
|
||||||
<div class="panel-footer text-center">
|
handling system which will escalate depending on customer
|
||||||
<p class="text-muted">
|
spend, grouping or profile and notify relevant parties as
|
||||||
<i>Free shipping, satisfied or reimbursed.</i>
|
appropriate.
|
||||||
</p>
|
</p><p>
|
||||||
<a href="/page/website.contactus" class="btn btn-primary btn-lg">Contact us</a>
|
More information about the feature set can be found
|
||||||
</div>
|
<a href="https://www.openerp.com/website_cms" target="_TOP">
|
||||||
</div>
|
on the OpenERP website here</a>
|
||||||
|
</p>
|
||||||
</div>
|
<h4>Created in just four months</h4>
|
||||||
</div>
|
<p>
|
||||||
|
OpenERP competently manages customer and product data, and
|
||||||
|
has mature sales work-flow built in, so the addition of the
|
||||||
|
E-commerce module was achieved by presenting these
|
||||||
|
components through a customer-friendly interface so most
|
||||||
|
of the effort invested was creating the CMS functions. This
|
||||||
|
was achieved within just four months of development by a
|
||||||
|
core team of 6 OpenERP developers and significant community
|
||||||
|
support.
|
||||||
|
</p><p>
|
||||||
|
Inspiration has come from various other platforms including
|
||||||
|
Prestashop, Magento and Drupal and contributors bring many
|
||||||
|
years of industry experience across many platforms.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -232,105 +271,210 @@
|
||||||
]]>
|
]]>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="blog_post_3" model="blog.post">
|
<record id="blog_post_3" model="blog.post">
|
||||||
<field name="name">Touchscreen Point of Sale for 6.1</field>
|
<field name="name">Sorry SAP Campaign - The Making Of</field>
|
||||||
|
<field name="sub_title">To lead the enterprise management market with a fully open source software.</field>
|
||||||
<field name="blog_id" ref="blog_blog_1"/>
|
<field name="blog_id" ref="blog_blog_1"/>
|
||||||
<field name="tag_ids" eval="[(6, 0, [ref('blog_tag_1'), ref('blog_tag_2')])]"/>
|
|
||||||
<field name="website_meta_keywords">Point of Sale, Hardware, Interface, Payment Terminal, Store</field>
|
|
||||||
<field name="website_meta_description">Point of Sale with no installation required that runs online and offline.</field>
|
|
||||||
<field name="content">
|
|
||||||
<![CDATA[<p>The brand new OpenERP touchscreen point of sale is available with 6.1 which allows you
|
|
||||||
to manage your shop sales very easily. It's fully web based so that you don't
|
|
||||||
have to install or deploy any software and all the sales shops can be easily
|
|
||||||
consolidated. It works in connected and disconnected modes so that you can
|
|
||||||
continue to sell even if you lose your internet connection.</p>
|
|
||||||
<img src="http://www.openerp.com/sites/default/files/fileattach/POS(2).png" alt="">
|
|
||||||
<h3>Here's a summary of its main features and benefits:</h3>
|
|
||||||
<ul>
|
|
||||||
<li>100% WEB based</li>
|
|
||||||
<li>available for any touchscreen device (ipod, ipad, any tablet)mobile (with portable devices)</li>
|
|
||||||
<li>no installation required</li>
|
|
||||||
<li>no synchronization needed, completely integrated</li>
|
|
||||||
<li>continue working even when your connection is down or if you close your browser, data won't be lost</li>
|
|
||||||
<li>fully web based with a clean interface smart interface</li>
|
|
||||||
</ul>
|
|
||||||
<p>You have different options to select your products. You can do it through the
|
|
||||||
barcode reader, just browse through the categories you have put in place (ie.
|
|
||||||
drinks, snacks, meals, etc.), or text search in case neither of the other
|
|
||||||
options work for you. For example, if you need to use the POS for your restaurant,
|
|
||||||
your employees can record multiple tickets at the same time without having to wait
|
|
||||||
to process one transaction at a time. In addition, you can facilitate payments,
|
|
||||||
the application allows multiple payment methods.</p>
|
|
||||||
<p>The POS application is so simple and accessible to use that your shop or
|
|
||||||
restaurant will never need any other tool to manage orders. Due to its smart
|
|
||||||
and user-friendly interface you don't need any training to learn how to use it.
|
|
||||||
Think of it as an out-of-the-box solution to boost your business' productivity.
|
|
||||||
</p>
|
|
||||||
]]>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="blog_post_4" model="blog.post">
|
|
||||||
<field name="name">Announcing a New Partnership</field>
|
|
||||||
<field name="blog_id" ref="blog_blog_1"/>
|
|
||||||
<field name="tag_ids" eval="[(6, 0, [ref('blog_tag_1')])]"/>
|
|
||||||
<field name="website_published" eval="True"/>
|
<field name="website_published" eval="True"/>
|
||||||
<field name="website_meta_keywords">OpenERP, Partnership, News, Accounting</field>
|
<field name="website_meta_keywords">OpenERP, News, Sorry SAP</field>
|
||||||
<field name="website_meta_description">Our company partners with OpenERP to develop accounting best practices.</field>
|
<field name="website_meta_description">Sorry SAP Campaign - The Making Of</field>
|
||||||
|
<field name="content_image">/website_blog/static/src/img/post3.jpg</field>
|
||||||
<field name="content"><![CDATA[
|
<field name="content"><![CDATA[
|
||||||
<section data-snippet-id='image-text'>
|
<section data-snippet-id="text">
|
||||||
<div class="container">
|
<div class="container readable">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 mt16 mb16">
|
<p>I needed to change the world. I wanted to ... You know how
|
||||||
<img class="img-responsive shadow" src="/website/static/src/img/text_image.png"/>
|
it is when you are young; you have big dreams, a lot of energ
|
||||||
</div>
|
and naïve stupidity. My dream was to lead the enterprise
|
||||||
<div class="col-md-6 mt16">
|
management market with a fully open source software.(I also
|
||||||
<p>
|
wanted to get 100 employees before 30 years old with a
|
||||||
We are proud to announce a new partnership with
|
self-financed company but I failed this one by a few months).
|
||||||
the company OpenERP. Their open source application suite
|
</p>
|
||||||
will allow us to reach new markets, specifically in
|
|
||||||
the accounting area.
|
|
||||||
</p><p>
|
|
||||||
The full integration with the company inventory
|
|
||||||
and accounting, will give our customers real time statistics
|
|
||||||
without the hassle of integrating several applications.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="mt16 mb16" data-snippet-id='text-block'>
|
<section data-snippet-id="text-image">
|
||||||
<div class="container">
|
<div class="container readable">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12 text-center mt16 mb32">
|
<p>
|
||||||
<h2>
|
To fuel my motivation, I had to pick someone to fight
|
||||||
OpenERP Project Management
|
against. In business, it's like a playground. When you
|
||||||
</h2>
|
arrive in a new school, if you want to quickly become the
|
||||||
<h3 class="text-muted">Infinitely flexible. Incredibly easy to use.</h3>
|
leader, you must choose the class bully, the older guy who
|
||||||
</div>
|
terrorises small boys,and kick his butt in front of
|
||||||
<div class="col-md-12 mb16 mt16">
|
everyone. That was my strategy with SAP, the enterprise
|
||||||
<p>
|
software giant.
|
||||||
OpenERP's <b>collaborative and realtime</b> project
|
</p><p>
|
||||||
management helps your team get work done. Keep
|
So, in 2005, I started to develop the TinyERP product, the
|
||||||
track of everything, from the big picture to the
|
software that (at least in my mind) would change the enterprise
|
||||||
minute details, from the customer contract to the
|
world. While preparing for the "day of the fight" in 2006,
|
||||||
billing.
|
I <a href="http://whois.domaintools.com/sorrysap.com">
|
||||||
</p><p>
|
bought the SorrySAP.com </a>domain name. I put it on hold
|
||||||
Organize projects around <b>your own processes</b>. Work
|
for 6 years, waiting for the right moment to use it.
|
||||||
on tasks and issues using the kanban view, schedule
|
I thought it would take 3 years to deprecate a 77 billion
|
||||||
tasks using the gantt chart and control deadlines
|
dollars company just because open source is so cool.
|
||||||
in the calendar view. Every project may have it's
|
Sometimes it's better for your self-motivation not to
|
||||||
own stages allowing teams to optimize their job.
|
face reality...
|
||||||
</p>
|
</p><p>
|
||||||
</div>
|
To make things happen, I worked hard, very hard. I worked
|
||||||
|
13 hours a day, 7 days a week, with no vacations for 7
|
||||||
|
years.I lost friendships and broke up with my girlfriend in
|
||||||
|
the process (fortunately, I found a more valuable wife
|
||||||
|
now. I will explain later why she is worth 1 million EUR
|
||||||
|
:).
|
||||||
|
</p><p>
|
||||||
|
Three years later, I discovered you can't change the world
|
||||||
|
if you are "tiny". Especially if the United States is part
|
||||||
|
of this world, where it's better to be a BigERP, rather
|
||||||
|
than a TinyERP. Can you imagine how small you feel
|
||||||
|
<a href="http://www.slideshare.net/openobject/danone-deployes-openerp-locally">
|
||||||
|
in front of Danone's directors</a> asking; "but why
|
||||||
|
should we pay millions of dollars for a tiny software?"
|
||||||
|
So, we renamed TinyERP to OpenERP.
|
||||||
|
</p><p>
|
||||||
|
As we worked hard, things started to evolve. We were
|
||||||
|
developing dozens of modules for OpenERP, the open source
|
||||||
|
community was growing and I was even able to pay all
|
||||||
|
employees' salaries at the end of the month without fear
|
||||||
|
(which was a situation I struggled with for 4 years).
|
||||||
|
</p><p>
|
||||||
|
In 2010, we had a 100+ employees company selling services
|
||||||
|
on OpenERP and a powerful but ugly product. This is what
|
||||||
|
happens when delivering services to customers distracts
|
||||||
|
you from building an exceptional product.
|
||||||
|
</p><p>
|
||||||
|
It was time to do a pivot in the business model.
|
||||||
|
</p>
|
||||||
|
<h3>The Pivot</h3>
|
||||||
|
<p>
|
||||||
|
We wanted to switch from a service company to a software
|
||||||
|
publisher company. This would allow to increase our efforts
|
||||||
|
in our research and development activities. As a result,
|
||||||
|
we <a href="http://v6.openerp.com/node/465">changed our
|
||||||
|
business model</a> and decided to stop our services to
|
||||||
|
customers and focus on building a strong partner network
|
||||||
|
and maintenance offer. This would cost money, so I had to
|
||||||
|
raise a few million euros.
|
||||||
|
</p><p>
|
||||||
|
After a few months of pitching investors, I got roughly
|
||||||
|
10 LOI from different VCs. We chosed Sofinnova Partners,
|
||||||
|
the biggest European VC, and Xavier Niel the founder of
|
||||||
|
Iliad, the only company in France funded in the past 10
|
||||||
|
years to have reached the 1 billion euro valuation.
|
||||||
|
</p><p>
|
||||||
|
I signed the LOI. I didn't realize that this contract could
|
||||||
|
have turned me into a homeless person. (I already had a dog,
|
||||||
|
all I needed was to lose a lot of money to become homeless).
|
||||||
|
The fund raising was based on a company valuation but there
|
||||||
|
was a financial mechanism to re-evaluate the company up by
|
||||||
|
9.8 m€ depending on the turnover of the next 4 years. I should
|
||||||
|
have received warrants convertible into shares if we achieved
|
||||||
|
the turnover targeted in the business plan.
|
||||||
|
</p><p>
|
||||||
|
The night before receiving the warrants in front of the
|
||||||
|
notary, my wife checked the contracts. She asked me what
|
||||||
|
would be the taxation on these warrants. I rang the lawyer
|
||||||
|
and guess what? Belgium is probably the only country in
|
||||||
|
the world where you have to pay taxes on warrants when you
|
||||||
|
receive them, even if you never reach the conditions to
|
||||||
|
convert them into shares.If I had accepted these warrants,
|
||||||
|
I would have had to pay a 12.5% tax on 9.8 m€; resulting
|
||||||
|
in a tax of 1.2m€ to pay in 18 months! So, my wife is worth
|
||||||
|
1.2 million EUR. I would have ended up a homeless person
|
||||||
|
without her, as I still did not have a salary at that time.
|
||||||
|
</p><p>
|
||||||
|
We changed the deal and I got the 3 million EUR. It allowed
|
||||||
|
me to recruit a rocking management team.
|
||||||
|
</p>
|
||||||
|
<img class="img-responsive" src="/website_blog/static/src/img/OpemERP_board.jpg"/>
|
||||||
|
<h3 class="mt16">Being a mature company<h3>
|
||||||
|
<p>
|
||||||
|
With this money in our bank account, we boosted two
|
||||||
|
departments: R&D and Sales. We burned two million EUR in
|
||||||
|
18 months,mostly in salaries. The company started to grow
|
||||||
|
even faster.We developed a partner network of 500 partners
|
||||||
|
in 100 countries and we started to sign contracts with 6
|
||||||
|
zeros.
|
||||||
|
</p><p>
|
||||||
|
Then, things became different. You know, tedious things like
|
||||||
|
handling human resources, board meetings, dealing with big
|
||||||
|
customer contracts, traveling to launch international
|
||||||
|
subsidiaries. We did boring stuff like budgets, career paths,
|
||||||
|
management meetings, etc.
|
||||||
|
</p><p>
|
||||||
|
2011 was a complex year. We did not meet our expectations:
|
||||||
|
we only achieved 70% of the forecasted sales budget. Our
|
||||||
|
management meetings were tense. We under performed. We were not
|
||||||
|
satisfied with ourselves. We had a constant feeling that we
|
||||||
|
missed something. It's a strange feeling to build extraordinary
|
||||||
|
things but to not be proud of ourselves.
|
||||||
|
</p><p>
|
||||||
|
But one day, someone (I don't remember who, I have a
|
||||||
|
goldfish memory) made a graph of the monthly turnover
|
||||||
|
of the past 2 years. It was like waking up from a nighmare.
|
||||||
|
In fact,it was not that bad, we had multiplied by 10 the
|
||||||
|
monthly turnover over the span of roughly two years!
|
||||||
|
This is when we understood that OpenERP is a marathon,
|
||||||
|
not a sprint. Only 100% growth a year is ok... if you can
|
||||||
|
keep the rhythm for several years.
|
||||||
|
</p>
|
||||||
|
<img class="img-responsive" src="/website_blog/static/src/img/turnover_updated.png"/>
|
||||||
|
<p class="text-center" section_inner="1">
|
||||||
|
OpenERP Monthly Turnover
|
||||||
|
</p><p>
|
||||||
|
As usual, I should have listened to my wife. She is way
|
||||||
|
more lucid than I am. Every week I complained to her "it's
|
||||||
|
not good enough, we should grow faster, what am I missing?"
|
||||||
|
and she used to reply; "But you already are the
|
||||||
|
<a href="http://v6.openerp.com/node/1244/2012/10">
|
||||||
|
fastest growing company in Belgium!". </a>(Deloitte awarded
|
||||||
|
us as the fastest growing company of Belgium with 1549%
|
||||||
|
growth of the turnover between 2007 and 2011)
|
||||||
|
</p>
|
||||||
|
<h3 class="mt16">Changing the world</h3>
|
||||||
|
<p>
|
||||||
|
Then, the dream started to become reality. We started to
|
||||||
|
get clues that what we did would change the world:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
With 1.000 installations per day, we became the most
|
||||||
|
installed management software in the world,
|
||||||
|
</li><li>
|
||||||
|
<a href="http://www.amazon.com/OpenERP-Evaluation-SAP-as-Reference/dp/296008764X/ref=sr_1_3?ie=UTF8&qid=1351150366&sr=8-3&keywords=openerp">
|
||||||
|
Analysts from Big 4 started to prefer OpenERP over SAP,
|
||||||
|
</a>
|
||||||
|
</li><li>
|
||||||
|
OpenERP is now a <a href="http://www.nathan.fr/catalogue/catalogue_detail_enseignants.asp?ean13=9782091619262">
|
||||||
|
compulsory subject for the baccalaureate in France</a>
|
||||||
|
like Word, Excel and Powerpoint
|
||||||
|
</li><li>
|
||||||
|
60 new modules are released every month (we became
|
||||||
|
the wikipedia of the management software thanks to
|
||||||
|
our strong community)
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Something is happening... And it's big!
|
||||||
|
</p><p>
|
||||||
|
OpenERP 7.0 is about to be released and I know you will be
|
||||||
|
astonished by it.
|
||||||
|
</p><p>
|
||||||
|
The official release is planned for the 21th of December.
|
||||||
|
As the Mayas predicted it, this is the end of an age,
|
||||||
|
the old ERP dinosaurs.
|
||||||
|
</p><p>
|
||||||
|
It's time to pull out the Ace: the SorrySAP.com domain
|
||||||
|
name that I bought 6 years ago.
|
||||||
|
</p><p>
|
||||||
|
If you want to test the v7 version online, just go
|
||||||
|
<a href="https://www.openerp.com/"> the homepage.</a>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
]]>
|
]]>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -37,6 +37,7 @@ class Blog(osv.Model):
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Name', required=True),
|
'name': fields.char('Name', required=True),
|
||||||
'description': fields.text('Description'),
|
'description': fields.text('Description'),
|
||||||
|
'image': fields.binary('Image'),
|
||||||
'blog_post_ids': fields.one2many(
|
'blog_post_ids': fields.one2many(
|
||||||
'blog.post', 'blog_id',
|
'blog.post', 'blog_id',
|
||||||
'Blogs',
|
'Blogs',
|
||||||
|
@ -57,6 +58,11 @@ class BlogTag(osv.Model):
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MailMessage(osv.Model):
|
||||||
|
_inherit = 'mail.message'
|
||||||
|
_columns = {
|
||||||
|
'discussion': fields.char('Discussion Unique Name'),
|
||||||
|
}
|
||||||
|
|
||||||
class BlogPost(osv.Model):
|
class BlogPost(osv.Model):
|
||||||
_name = "blog.post"
|
_name = "blog.post"
|
||||||
|
@ -66,32 +72,9 @@ class BlogPost(osv.Model):
|
||||||
# maximum number of characters to display in summary
|
# maximum number of characters to display in summary
|
||||||
_shorten_max_char = 250
|
_shorten_max_char = 250
|
||||||
|
|
||||||
def get_shortened_content(self, cr, uid, ids, name, arg, context=None):
|
|
||||||
res = {}
|
|
||||||
for page in self.browse(cr, uid, ids, context=context):
|
|
||||||
try:
|
|
||||||
body_short = tools.html_email_clean(
|
|
||||||
page.content,
|
|
||||||
remove=True,
|
|
||||||
shorten=True,
|
|
||||||
max_length=self._shorten_max_char,
|
|
||||||
expand_options={
|
|
||||||
'oe_expand_container_tag': 'div',
|
|
||||||
'oe_expand_container_class': 'oe_mail_expand text-center',
|
|
||||||
'oe_expand_container_content': '',
|
|
||||||
'oe_expand_a_href': '/blogpost/%d' % page.id,
|
|
||||||
'oe_expand_a_class': 'oe_mail_expand btn btn-info',
|
|
||||||
'oe_expand_separator_node': 'br',
|
|
||||||
},
|
|
||||||
protect_sections=True,
|
|
||||||
)
|
|
||||||
except Exception:
|
|
||||||
body_short = False
|
|
||||||
res[page.id] = body_short
|
|
||||||
return res
|
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Title', required=True, translate=True),
|
'name': fields.char('Title', required=True, translate=True),
|
||||||
|
'sub_title' : fields.char('Sub Title', translate=True),
|
||||||
'content_image': fields.binary('Background Image'),
|
'content_image': fields.binary('Background Image'),
|
||||||
'blog_id': fields.many2one(
|
'blog_id': fields.many2one(
|
||||||
'blog.blog', 'Blog',
|
'blog.blog', 'Blog',
|
||||||
|
@ -101,12 +84,6 @@ class BlogPost(osv.Model):
|
||||||
'blog.tag', string='Tags',
|
'blog.tag', string='Tags',
|
||||||
),
|
),
|
||||||
'content': fields.html('Content', translate=True),
|
'content': fields.html('Content', translate=True),
|
||||||
'shortened_content': fields.function(
|
|
||||||
get_shortened_content,
|
|
||||||
type='html',
|
|
||||||
string='Shortened Content',
|
|
||||||
help="Shortened content of the page that serves as a summary"
|
|
||||||
),
|
|
||||||
# website control
|
# website control
|
||||||
'website_published': fields.boolean(
|
'website_published': fields.boolean(
|
||||||
'Publish', help="Publish on the website"
|
'Publish', help="Publish on the website"
|
||||||
|
@ -114,20 +91,6 @@ class BlogPost(osv.Model):
|
||||||
'website_published_datetime': fields.datetime(
|
'website_published_datetime': fields.datetime(
|
||||||
'Publish Date'
|
'Publish Date'
|
||||||
),
|
),
|
||||||
# TDE TODO FIXME: when website_mail/mail_thread.py inheritance work -> this field won't be necessary
|
|
||||||
'website_message_ids': fields.one2many(
|
|
||||||
'mail.message', 'res_id',
|
|
||||||
domain=lambda self: [
|
|
||||||
'&', ('model', '=', self._name), ('type', '=', 'comment')
|
|
||||||
],
|
|
||||||
string='Website Messages',
|
|
||||||
help="Website communication history",
|
|
||||||
),
|
|
||||||
# technical stuff: history, menu (to keep ?)
|
|
||||||
'history_ids': fields.one2many(
|
|
||||||
'blog.post.history', 'post_id',
|
|
||||||
'History', help='Last post modifications'
|
|
||||||
),
|
|
||||||
# creation / update stuff
|
# creation / update stuff
|
||||||
'create_date': fields.datetime(
|
'create_date': fields.datetime(
|
||||||
'Created on',
|
'Created on',
|
||||||
|
@ -145,37 +108,14 @@ class BlogPost(osv.Model):
|
||||||
'res.users', 'Last Contributor',
|
'res.users', 'Last Contributor',
|
||||||
select=True, readonly=True,
|
select=True, readonly=True,
|
||||||
),
|
),
|
||||||
|
'visits': fields.integer('No of Visitors'),
|
||||||
}
|
}
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'website_published': False
|
'website_published': False,
|
||||||
|
'visits': 0
|
||||||
}
|
}
|
||||||
|
|
||||||
def create_history(self, cr, uid, ids, vals, context=None):
|
|
||||||
for i in ids:
|
|
||||||
history = self.pool.get('blog.post.history')
|
|
||||||
if vals.get('content'):
|
|
||||||
res = {
|
|
||||||
'content': vals.get('content', ''),
|
|
||||||
'post_id': i,
|
|
||||||
}
|
|
||||||
history.create(cr, uid, res)
|
|
||||||
|
|
||||||
def create(self, cr, uid, vals, context=None):
|
|
||||||
if context is None:
|
|
||||||
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):
|
|
||||||
result = super(BlogPost, self).write(cr, uid, ids, vals, context)
|
|
||||||
self.create_history(cr, uid, ids, vals, context)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def copy(self, cr, uid, id, default=None, context=None):
|
def copy(self, cr, uid, id, default=None, context=None):
|
||||||
if default is None:
|
default = default or {}
|
||||||
default = {}
|
|
||||||
default.update({
|
default.update({
|
||||||
'website_message_ids': [],
|
'website_message_ids': [],
|
||||||
'website_published': False,
|
'website_published': False,
|
||||||
|
@ -187,33 +127,3 @@ class BlogPost(osv.Model):
|
||||||
post = self.browse(cr, SUPERUSER_ID, ids[0], context=context)
|
post = self.browse(cr, SUPERUSER_ID, ids[0], context=context)
|
||||||
return "/website/image?model=%s&field=%s&id=%s" % ('res.users', field, post.create_uid.id)
|
return "/website/image?model=%s&field=%s&id=%s" % ('res.users', field, post.create_uid.id)
|
||||||
|
|
||||||
|
|
||||||
class BlogPostHistory(osv.Model):
|
|
||||||
_name = "blog.post.history"
|
|
||||||
_description = "Blog Post History"
|
|
||||||
_order = 'id DESC'
|
|
||||||
_rec_name = "create_date"
|
|
||||||
|
|
||||||
_columns = {
|
|
||||||
'post_id': fields.many2one('blog.post', 'Blog Post'),
|
|
||||||
'summary': fields.char('Summary', size=256, select=True),
|
|
||||||
'content': fields.text("Content"),
|
|
||||||
'create_date': fields.datetime("Date"),
|
|
||||||
'create_uid': fields.many2one('res.users', "Modified By"),
|
|
||||||
}
|
|
||||||
|
|
||||||
def getDiff(self, cr, uid, v1, v2, context=None):
|
|
||||||
history_pool = self.pool.get('blog.post.history')
|
|
||||||
text1 = history_pool.read(cr, uid, [v1], ['content'])[0]['content']
|
|
||||||
text2 = history_pool.read(cr, uid, [v2], ['content'])[0]['content']
|
|
||||||
line1 = line2 = ''
|
|
||||||
if text1:
|
|
||||||
line1 = text1.splitlines(1)
|
|
||||||
if text2:
|
|
||||||
line2 = text2.splitlines(1)
|
|
||||||
if (not line1 and not line2) or (line1 == line2):
|
|
||||||
raise osv.except_osv(_('Warning!'), _('There are no changes in revisions.'))
|
|
||||||
diff = difflib.HtmlDiff()
|
|
||||||
return diff.make_table(line1, line2, "Revision-%s" % (v1), "Revision-%s" % (v2), context=True)
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
||||||
|
|
|
@ -2,6 +2,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
blog_blog_all,blog.blog,model_blog_blog,,1,0,0,0
|
blog_blog_all,blog.blog,model_blog_blog,,1,0,0,0
|
||||||
blog_post_all,blog.post,model_blog_post,,1,0,0,0
|
blog_post_all,blog.post,model_blog_post,,1,0,0,0
|
||||||
blog_post,blog.post,model_blog_post,base.group_document_user,1,1,1,1
|
blog_post,blog.post,model_blog_post,base.group_document_user,1,1,1,1
|
||||||
blog_post_history,blog.post.history,model_blog_post_history,base.group_document_user,1,0,1,0
|
|
||||||
blog_tag,blog.tag,model_blog_tag,,1,0,0,0
|
blog_tag,blog.tag,model_blog_tag,,1,0,0,0
|
||||||
blog_tag_edition,blog.tag,model_blog_tag,base.group_document_user,1,1,1,1
|
blog_tag_edition,blog.tag,model_blog_tag,base.group_document_user,1,1,1,1
|
||||||
|
|
|
|
@ -9,5 +9,13 @@
|
||||||
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
|
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.rule" id="base.res_partner_portal_public_rule">
|
||||||
|
<field name="name">res_partner: portal/public: read access on my commercial partner</field>
|
||||||
|
<field name="model_id" ref="base.model_res_partner"/>
|
||||||
|
<field name="domain_force">[]</field>
|
||||||
|
<field name="perm_create" eval="False"/>
|
||||||
|
<field name="perm_unlink" eval="False"/>
|
||||||
|
<field name="perm_write" eval="False"/>
|
||||||
|
</record>
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
(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(){
|
||||||
|
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+3));
|
||||||
|
var text = encodeURIComponent('\"'+selected_text+'\" '+ 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() {
|
||||||
|
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",
|
||||||
|
};
|
||||||
|
|
||||||
|
}());
|
|
@ -1,5 +1,4 @@
|
||||||
@charset "utf-8";
|
@charset "UTF-8";
|
||||||
@import url(compass/css3.css);
|
|
||||||
.css_website_mail .has-error {
|
.css_website_mail .has-error {
|
||||||
border-color: red;
|
border-color: red;
|
||||||
}
|
}
|
||||||
|
@ -21,3 +20,124 @@ p.post-meta {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -5px;
|
top: -5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.blog_cover {
|
||||||
|
-webkit-background-size: cover;
|
||||||
|
-moz-background-size: cover;
|
||||||
|
-o-background-size: cover;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
min-height: 400px;
|
||||||
|
height: 100vh;
|
||||||
|
color: white;
|
||||||
|
padding-top: 1vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover_footer {
|
||||||
|
-webkit-background-size: cover;
|
||||||
|
-moz-background-size: cover;
|
||||||
|
-o-background-size: cover;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
min-height: 200px;
|
||||||
|
height: 50vh;
|
||||||
|
color: white;
|
||||||
|
padding-top: 5vh;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover_title {
|
||||||
|
padding-top: 20vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*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-left: 7px solid transparent;
|
||||||
|
border-top: 7px solid #bbbbbb;
|
||||||
|
left: 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;
|
||||||
|
}
|
||||||
|
|
|
@ -20,3 +20,112 @@ p.post-meta
|
||||||
position: relative
|
position: relative
|
||||||
top: -5px
|
top: -5px
|
||||||
|
|
||||||
|
.blog_cover
|
||||||
|
-webkit-background-size: cover
|
||||||
|
-moz-background-size: cover
|
||||||
|
-o-background-size: cover
|
||||||
|
background-size: cover
|
||||||
|
background-position: center
|
||||||
|
background-repeat: no-repeat
|
||||||
|
background-color: rgba(0, 0, 0, 0.3)
|
||||||
|
min-height : 400px
|
||||||
|
height: 100vh
|
||||||
|
color: white
|
||||||
|
padding-top: 1vh
|
||||||
|
|
||||||
|
.cover_footer
|
||||||
|
-webkit-background-size: cover
|
||||||
|
-moz-background-size: cover
|
||||||
|
-o-background-size: cover
|
||||||
|
background-size: cover
|
||||||
|
background-position: center
|
||||||
|
background-repeat: no-repeat
|
||||||
|
background-color: rgba(0, 0, 0, 0.3)
|
||||||
|
min-height : 200px
|
||||||
|
height: 50vh
|
||||||
|
color: white
|
||||||
|
padding-top: 5vh
|
||||||
|
cursor: pointer
|
||||||
|
|
||||||
|
.cover_title
|
||||||
|
padding-top : 20vh
|
||||||
|
|
||||||
|
/*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-left: 7px solid transparent
|
||||||
|
border-top: 7px solid #bbbbbb
|
||||||
|
left: 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
|
||||||
|
|
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 187 KiB |
After Width: | Height: | Size: 25 KiB |
|
@ -27,7 +27,29 @@
|
||||||
}).then(function (cat_id) {
|
}).then(function (cat_id) {
|
||||||
document.location = '/blogpost/new?blog_id=' + cat_id;
|
document.location = '/blogpost/new?blog_id=' + cat_id;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
edit: function () {
|
||||||
|
this._super();
|
||||||
|
$('body').on('click', '#change_cover',_.bind(this.change_bg));
|
||||||
|
},
|
||||||
|
save : function() {
|
||||||
|
openerp.jsonRpc("/blogpsot/change_background", 'call', {
|
||||||
|
'post_id' : $('#blog_post_name').attr('data-oe-id'),
|
||||||
|
'image' : $('.blog_cover')[0].style.background.replace('url(','').replace(')',''),
|
||||||
|
});
|
||||||
|
return this._super();
|
||||||
|
},
|
||||||
|
change_bg : function() {
|
||||||
|
var self = this;
|
||||||
|
var editor = new website.editor.ImageDialog();
|
||||||
|
editor.on('start', self, function (o) {
|
||||||
|
o.url = $('.blog_cover')[0].style.background.replace('url(','').replace(')','');
|
||||||
|
});
|
||||||
|
editor.on('save', self, function (o) {
|
||||||
|
$('.blog_cover').css("background-image", o.url && o.url !== "" ? 'url(' + o.url + ')' : "");
|
||||||
|
});
|
||||||
|
editor.appendTo('body');
|
||||||
|
},
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
// Inspired from https://github.com/tsi/inlinediscussions
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var website = openerp.website,
|
||||||
|
qweb = openerp.qweb;
|
||||||
|
website.add_template_file('/website_blog/static/src/xml/website_blog.inline.discussion.xml');
|
||||||
|
website.blog_discussion = openerp.Class.extend({
|
||||||
|
init: function(options) {
|
||||||
|
var self = this ;
|
||||||
|
self.discus_identifier;
|
||||||
|
var defaults = {
|
||||||
|
identifier: 'name',
|
||||||
|
position: 'right',
|
||||||
|
post_id: $('#blog_post_name').attr('data-oe-id'),
|
||||||
|
document_user : false,
|
||||||
|
content : false,
|
||||||
|
};
|
||||||
|
self.settings = $.extend({}, defaults, options);
|
||||||
|
self.do_render(self);
|
||||||
|
},
|
||||||
|
do_render: function(data) {
|
||||||
|
var self = this;
|
||||||
|
if ($('#discussions_wrapper').length === 0) {
|
||||||
|
$('<div id="discussions_wrapper"></div>').appendTo($('#blog_content'));
|
||||||
|
}
|
||||||
|
// Attach a discussion to each paragraph.
|
||||||
|
$(self.settings.content).each(function(i) {
|
||||||
|
self.discussion_handler(i, $(this));
|
||||||
|
});
|
||||||
|
// Hide the discussion.
|
||||||
|
$('html').click(function(event) {
|
||||||
|
if($(event.target).parents('#discussions_wrapper, .main-discussion-link-wrp').length === 0) {
|
||||||
|
self.hide_discussion();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
prepare_data : function(identifier) {
|
||||||
|
var self = this;
|
||||||
|
return openerp.jsonRpc("/blogpost/get_discussion/", 'call', {
|
||||||
|
'post_id': self.settings.post_id,
|
||||||
|
'discussion':identifier,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while ($('[data-discus-identifier="' + self.settings.identifier + '-' + i + '"]').length > 0) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
identifier = self.settings.identifier + '-' + i;
|
||||||
|
}
|
||||||
|
self.prepare_data(identifier).then(function(data){
|
||||||
|
self.prepare_discuss_link(data,identifier,node)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
prepare_discuss_link : function(data, identifier, node) {
|
||||||
|
var self = this;
|
||||||
|
var cls = data.length > 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.length > 0 ? data.length : '+')
|
||||||
|
.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).mouseover(function() {
|
||||||
|
a.addClass("hovered");
|
||||||
|
}).mouseout(function() {
|
||||||
|
a.removeClass("hovered");
|
||||||
|
});
|
||||||
|
|
||||||
|
a.delegate('a.discussion-link', "click", function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if ($(this).is('.active')) {
|
||||||
|
e.stopPropagation();
|
||||||
|
self.hide_discussion();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.get_discussion($(this), function(source) {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get_discussion : function(source, callback) {
|
||||||
|
var self = this;
|
||||||
|
var identifier = source.attr('data-discus-identifier');
|
||||||
|
self.hide_discussion();
|
||||||
|
self.discus_identifier = identifier;
|
||||||
|
var elt = $('a[data-discus-identifier="'+identifier+'"]');
|
||||||
|
elt.append(qweb.render("website.blog_discussion.popover", {'identifier': identifier , 'options': self.settings}));
|
||||||
|
var comment = '';
|
||||||
|
self.prepare_data(identifier).then(function(data){
|
||||||
|
console.log(identifier, data);
|
||||||
|
_.each(data, function(res){
|
||||||
|
comment += qweb.render("website.blog_discussion.comment", {'res': res});
|
||||||
|
});
|
||||||
|
$('.discussion_history').html('<ul class="media-list">'+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');
|
||||||
|
callback(source);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
post_discussion : function(identifier) {
|
||||||
|
var self = this;
|
||||||
|
var val = $(".popover #comment").val()
|
||||||
|
if(val){
|
||||||
|
$(".popover #comment").removeClass('danger');
|
||||||
|
openerp.jsonRpc("/blogpost/post_discussion", 'call', {
|
||||||
|
'blog_post_id': self.settings.post_id,
|
||||||
|
'discussion': self.discus_identifier,
|
||||||
|
'comment': val,
|
||||||
|
}).then(function(res){
|
||||||
|
$(".popover ul.media-list").prepend(qweb.render("website.blog_discussion.comment", {'res': res}))
|
||||||
|
$(".popover #comment").val('')
|
||||||
|
var ele = $('a[data-discus-identifier="'+ self.discus_identifier +'"]');
|
||||||
|
ele.text(_.isNaN(parseInt(ele.text())) ? 1 : parseInt(ele.text())+1)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hide_discussion : function() {
|
||||||
|
var self = this;
|
||||||
|
$('a[data-discus-identifier="'+ self.discus_identifier+'"]').popover('destroy');
|
||||||
|
$('a.discussion-link').removeClass('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
|
@ -0,0 +1,48 @@
|
||||||
|
$(document).ready(function() {
|
||||||
|
var content = $("#blog_content p");
|
||||||
|
if(content.length)
|
||||||
|
new openerp.website.blog_discussion({'document_user': $('#is_document_user').length, 'content' : content});
|
||||||
|
$('.cover_footer').on('click',page_transist);
|
||||||
|
$('a[href^="#blog_content"]').on('click', animate);
|
||||||
|
$("p").share();
|
||||||
|
function page_transist(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var translationValue = $('.cover_footer').get(0).getBoundingClientRect().top;
|
||||||
|
newLocation = $('.js_next')[0].href;
|
||||||
|
$('.cover_footer')
|
||||||
|
.fadeIn(900, newpage);
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate(event) {
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
var target = this.hash;
|
||||||
|
$target = $(target);
|
||||||
|
$('html, body').stop().animate({
|
||||||
|
'scrollTop': $target.offset().top
|
||||||
|
}, 900, 'swing', function () {
|
||||||
|
window.location.hash = target;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function newpage() {
|
||||||
|
$.ajax({
|
||||||
|
url: newLocation,
|
||||||
|
}).done(function(data) {
|
||||||
|
$('main').append($(data).find('main').html());
|
||||||
|
$("html").stop().animate({ scrollTop: $("#wrap:last-child").offset().top }, 1000,function(e){
|
||||||
|
$("#wrap:first").remove();
|
||||||
|
$(document).scrollTop($("#wrap:last-child").offset().top);
|
||||||
|
//bind again it takes control from now on, until page relaod.
|
||||||
|
$(document).find('.cover_footer').on('click',page_transist);
|
||||||
|
$(document).find('a[href^="#blog_content"]').on('click', animate);
|
||||||
|
var content = $(document).find("#blog_content p");
|
||||||
|
if (content)
|
||||||
|
new openerp.website.blog_discussion({'document_user': $('#is_document_user').length, 'content' : content});
|
||||||
|
$("p").share();
|
||||||
|
});
|
||||||
|
if (newLocation != window.location) {
|
||||||
|
history.pushState(null, null, newLocation);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?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="media-body">
|
||||||
|
<img class="media-object pull-left img-circle" t-att-src="res.author_image" style="width: 30px; margin-right: 5px;"/>
|
||||||
|
<div class="media-body">
|
||||||
|
<h5 class="media-heading">
|
||||||
|
<small><span t-esc='res.author_name'/> on <span t-esc='res.date'/></small>
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<h6 t-esc='res.body'/>
|
||||||
|
</li>
|
||||||
|
<hr class="mb0 mt0"/>
|
||||||
|
</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"/>
|
||||||
|
<textarea t-att-class="options.document_user ? 'mb8 form-control' : 'mb8 form-control hidden'" rows="2" id="comment" placeholder="Write a comment..."/>
|
||||||
|
<button id='comment_post' t-att-class="options.document_user ? 'btn btn-primary btn-xs mb8 mt4' : 'btn btn-primary btn-xs mb8 mt4 hidden'">Post</button>
|
||||||
|
<div class="discussion_history"/>
|
||||||
|
<a t-att-class="options.document_user ? 'btn btn-block btn-success hidden' : 'btn btn-block btn-success'" href="/web/login">Sign In</a>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</templates>
|
|
@ -1,33 +0,0 @@
|
||||||
-
|
|
||||||
In order to test the document_page in OpenERP, I create a new page to blog blog_blog_1
|
|
||||||
-
|
|
||||||
!record {model: blog.post, id: test_page0}:
|
|
||||||
name: Test Page0
|
|
||||||
blog_id: blog_blog_1
|
|
||||||
content: 'Test content
|
|
||||||
|
|
||||||
The Open ERP wiki allows you to manage your enterprise contents using wiki
|
|
||||||
|
|
||||||
restructured texts. This module provides a collaborative way to manage internal
|
|
||||||
|
|
||||||
FAQs, quality manuals, technical references, etc.'
|
|
||||||
|
|
||||||
-
|
|
||||||
!record {model: blog.post, id: test_page0}:
|
|
||||||
content: 'Test updated content
|
|
||||||
|
|
||||||
The Open ERP wiki allows you to manage your enterprise contents using wiki
|
|
||||||
|
|
||||||
restructured texts. This module provides a collaborative way to manage internal
|
|
||||||
|
|
||||||
FAQs, quality manuals, technical references, etc.
|
|
||||||
|
|
||||||
Wiki text can easily be edited
|
|
||||||
'
|
|
||||||
-
|
|
||||||
I check the page history for the current page by clicking on "Page History".After that find difference between history.
|
|
||||||
-
|
|
||||||
!python {model: blog.post.history.show_diff}: |
|
|
||||||
hist_obj = model.pool.get('blog.post.history')
|
|
||||||
ids = hist_obj.search(cr, uid, [('post_id', '=', ref("test_page0"))])
|
|
||||||
model.get_diff(cr, uid, {'active_ids': ids[:] })
|
|
|
@ -108,7 +108,7 @@
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</div>
|
||||||
<t t-foreach="blog_posts" t-as="blog_post">
|
<t t-foreach="blog_posts" t-as="blog_post">
|
||||||
<div t-att-data-publish="blog_post.website_published and 'on' or 'off'">
|
<div name="blog_post_summary" t-att-data-publish="blog_post.website_published and 'on' or 'off'">
|
||||||
<h2 class="text-center">
|
<h2 class="text-center">
|
||||||
<a t-attf-href="/blogpost/#{ slug(blog_post) }/?#{ tag and 'tag=%s' % tag.id or '' }#{tag and date and '&' or ''}#{ date and 'date=%s' % date or ''}" t-field="blog_post.name"></a>
|
<a t-attf-href="/blogpost/#{ slug(blog_post) }/?#{ tag and 'tag=%s' % tag.id or '' }#{tag and date and '&' or ''}#{ date and 'date=%s' % date or ''}" t-field="blog_post.name"></a>
|
||||||
</h2>
|
</h2>
|
||||||
|
@ -122,7 +122,6 @@
|
||||||
</span>
|
</span>
|
||||||
<span t-if="not blog_post.website_published" class="label label-danger">not published</span>
|
<span t-if="not blog_post.website_published" class="label label-danger">not published</span>
|
||||||
</p>
|
</p>
|
||||||
<div t-raw="blog_post.shortened_content" class="blog_content"/>
|
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -130,6 +129,26 @@
|
||||||
</t>
|
</t>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- Blog Post List -->
|
||||||
|
<template id="opt_blog_post_short_list" name="Blog Post List"
|
||||||
|
inherit_id="website_blog.blog_post_short">
|
||||||
|
<xpath expr="//div[@name='blog_post_summary']" position="replace">
|
||||||
|
<div class="readable" name="blog_post_summary" t-att-publish-data="blog_post.website_published and 'on' or 'off'">
|
||||||
|
<div class="row">
|
||||||
|
<a class="col-sm-11" t-attf-href="/blogpost/#{ slug(blog_post) }/?#{ tag and 'tag=%s' % tag.id or '' }#{tag and date and '&' or ''}#{ date and 'date=%s' % date or ''}"><h2 t-field="blog_post.name"></h2></a>
|
||||||
|
<h2 class="col-sm-1"><img class="img-circle" t-att-src="'/website/image?model=res.users&field=image_small&id='+str(blog_post.create_uid.id)" style="width: 40px;"/></h2>
|
||||||
|
</div>
|
||||||
|
<div class="row col-sm-12 text-muted">
|
||||||
|
<h3 t-field="blog_post.sub_title"/>
|
||||||
|
<p class="post-meta text-muted text-left " name='blog_post_data'>
|
||||||
|
<span t-field="blog_post.create_uid.name"/> <span class="fa fa-calendar oe_date"> <span t-field="blog_post.create_date"/> &nbsp;</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<hr class="mb0 mt0"/>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- Options: Blog Post Summary: hide author -->
|
<!-- Options: Blog Post Summary: hide author -->
|
||||||
<template id="opt_blog_post_short_author" name="Author"
|
<template id="opt_blog_post_short_author" name="Author"
|
||||||
inherit_option_id="website_blog.blog_post_short">
|
inherit_option_id="website_blog.blog_post_short">
|
||||||
|
@ -140,7 +159,7 @@
|
||||||
|
|
||||||
<!-- Option: Blog Post Summary: show tags -->
|
<!-- Option: Blog Post Summary: show tags -->
|
||||||
<template id="opt_blog_post_short_tags" name="Tags"
|
<template id="opt_blog_post_short_tags" name="Tags"
|
||||||
inherit_option_id="website_blog.blog_post_short" inherit_id="website_blog.blog_post_short">
|
inherit_option_id="website_blog.blog_post_short">
|
||||||
<xpath expr="//p[@name='blog_post_data']" position="after">
|
<xpath expr="//p[@name='blog_post_data']" position="after">
|
||||||
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
|
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
|
||||||
<span class="fa fa-tags"/>
|
<span class="fa fa-tags"/>
|
||||||
|
@ -151,14 +170,15 @@
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<!-- Blog Post Complete -->
|
<!-- Blog Post Complete -->
|
||||||
<template id="blog_post_complete" name="Blog Post">
|
<template id="blog_post_complete" name="Blog Post">
|
||||||
<t t-call="website_blog.index">
|
<t t-call="website_blog.index">
|
||||||
|
|
||||||
<div class="container" id="title">
|
<div class="container" id="title">
|
||||||
<h1 class="text-center" t-field="blog_post.name"/>
|
<h1 class="text-center" t-field="blog_post.name" id="blog_post_name"/>
|
||||||
<p class="post-meta text-muted text-center" name="blog_post_data">
|
<p class="post-meta text-muted text-center" name="blog_post_data">
|
||||||
<span class="fa fa-calendar oe_date"> <span t-field="blog_post.create_date"/> &nbsp;</span>
|
<span class="fa fa-calendar oe_date" name="blog_post_date"> <span t-field="blog_post.create_date"/> &nbsp;</span>
|
||||||
<span t-if="len(blog_post.message_ids) > 0" class="fa fa-comment-o"> With
|
<span t-if="len(blog_post.message_ids) > 0" class="fa fa-comment-o"> With
|
||||||
<a t-attf-href="#comments">
|
<a t-attf-href="#comments">
|
||||||
<t t-if="len(blog_post.message_ids) <= 1" ><t t-esc="len(blog_post.message_ids)"/> comment</t>
|
<t t-if="len(blog_post.message_ids) <= 1" ><t t-esc="len(blog_post.message_ids)"/> comment</t>
|
||||||
|
@ -179,8 +199,7 @@
|
||||||
</li>
|
</li>
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="blog_content" t-field="blog_post.content"/>
|
||||||
<div t-field="blog_post.content"/>
|
|
||||||
|
|
||||||
<section id="comments" class="container">
|
<section id="comments" class="container">
|
||||||
<ul class="media-list" id="comments-list">
|
<ul class="media-list" id="comments-list">
|
||||||
|
@ -223,10 +242,93 @@
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- Options: Blog Post: Full Screen Background Image -->
|
||||||
|
<template id="blog_post_background_cover" name="Blog Cover"
|
||||||
|
inherit_option_id="website_blog.blog_post_complete" inherit_id="website_blog.blog_post_complete">
|
||||||
|
<xpath expr="//div[@id='title']" position="attributes">
|
||||||
|
<attribute name="class">blog_cover</attribute>
|
||||||
|
<attribute name="t-attf-style">background-image : url(#{blog_post.content_image})</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//h1[@id='blog_post_name']" position="replace">
|
||||||
|
<div class="text-right">
|
||||||
|
<a id="change_cover" t-ignore="true" class="btn btn-primary css_non_editable_mode_hidden" style="cursor :pointer">
|
||||||
|
Change Cover Photo
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-center cover_title" t-ignore="true"><strong t-field="blog_post.name" id="blog_post_name"/></h1>
|
||||||
|
<p t-ignore="true" id="is_document_user" groups="base.group_document_user"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//p[@name='blog_post_data']" position="replace">
|
||||||
|
<h2 class="text-center" t-field="blog_post.sub_title"/>
|
||||||
|
<p class="post-meta text-muted text-center" name="blog_post_data"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//div[@id='title']" position="inside">
|
||||||
|
<div class="text-center blog_item" t-ignore="true">
|
||||||
|
<img class="img-circle" t-att-src="'/website/image?model=res.users&field=image_small&id='+str(blog_post.create_uid.id)" style="width: 30px; margin-right: 10px;"/>
|
||||||
|
<small id="blog_author" t-field="blog_post.create_uid.name"/>
|
||||||
|
</div>
|
||||||
|
<div class="text-center mt32">
|
||||||
|
<a href="#blog_content" t-ignore="true"><span class="fa fa-angle-down fa-2x fa-inverse"/></a>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//section[@id='comments']" position="after">
|
||||||
|
<t t-if="next_post">
|
||||||
|
<div class="cover_footer mb0" t-attf-style="background-image: url(#{next_post.content_image})">
|
||||||
|
<p class="text-center" t-ignore="true">Read Next</p>
|
||||||
|
<a class="hidden js_next" t-attf-href="/blogpost/#{ slug(next_post) }#wrap"/>
|
||||||
|
<h1 class="text-center" t-field="next_post.name"/>
|
||||||
|
<h2 class="text-center" t-field="next_post.sub_title"/>
|
||||||
|
<div class="text-center blog_item" t-ignore="true">
|
||||||
|
<img class="img-circle" t-att-src="'/website/image?model=res.users&field=image_small&id='+str(next_post.create_uid.id)" style="width: 30px; margin-right: 10px;"/>
|
||||||
|
<small id="blog_author" t-field="next_post.create_uid.name"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Options: Blog Post: Footer author detail -->
|
||||||
|
<template id="blog_post_footer" name="Blog Footer"
|
||||||
|
inherit_option_id="website_blog.blog_post_complete">
|
||||||
|
<xpath expr="//section[@id='comments']" position="before">
|
||||||
|
<div class="container mt16 mb32">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="col-sm-4 col-sm-push-2">
|
||||||
|
<hr class="mt0 mb0"/>
|
||||||
|
<strong class="text-muted text-right">WRITTEN BY</strong>
|
||||||
|
<div class="media">
|
||||||
|
<a class="pull-left" href="#">
|
||||||
|
<img class="img-rounded" t-att-src="'/website/image?model=res.users&field=image_small&id='+str(blog_post.create_uid.id)" style="width: 50px; margin-right: 10px;"/>
|
||||||
|
</a>
|
||||||
|
<div class="media-body">
|
||||||
|
<h4 class="media-heading" t-field="blog_post.create_uid.name"></h4>
|
||||||
|
<p t-field="blog_post.create_uid.email"></p>
|
||||||
|
<small t-if="blog_post.website_published_datetime" class="text-right text-muted">Published on <t t-esc="blog_post.website_published_datetime"/></small>
|
||||||
|
<small t-if="not blog_post.website_published_datetime" class="text-right text-muted">Last Modified on <t t-esc="blog_post.write_date"/></small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 col-sm-push-2" t-if="blog_post.blog_id">
|
||||||
|
<hr class="mt0 mb0"/>
|
||||||
|
<strong class="text-muted text-right">PUBLISHED IN</strong>
|
||||||
|
<div class="media">
|
||||||
|
<a class="pull-left" href="#">
|
||||||
|
<img class="img-rounded" t-att-src="'/website/image?model=blog.blog&field=image&id='+str(blog_post.blog_id.id)" style="width: 50px; margin-right: 10px;"/>
|
||||||
|
</a>
|
||||||
|
<div class="media-body">
|
||||||
|
<h4 class="media-heading" t-field="blog_post.blog_id.name"></h4>
|
||||||
|
<span t-field="blog_post.blog_id.description"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- Options: Blog Post: user can reply -->
|
<!-- Options: Blog Post: user can reply -->
|
||||||
<template id="opt_blog_post_complete_comment" name="Allow Comments"
|
<template id="opt_blog_post_complete_comment" name="Allow Comments"
|
||||||
inherit_option_id="website_blog.blog_post_complete" inherit_id="website_blog.blog_post_complete"
|
inherit_option_id="website_blog.blog_post_complete"
|
||||||
groups="website_mail.group_comment">
|
groups="website_mail.group_comment">
|
||||||
<xpath expr="//ul[@id='comments-list']" position="before">
|
<xpath expr="//ul[@id='comments-list']" position="before">
|
||||||
<section class="mb32 css_editable_mode_hidden">
|
<section class="mb32 css_editable_mode_hidden">
|
||||||
|
@ -261,7 +363,7 @@
|
||||||
|
|
||||||
<!-- Options: Blog Post: show tags -->
|
<!-- Options: Blog Post: show tags -->
|
||||||
<template id="opt_blog_post_complete_tags" name="Tags"
|
<template id="opt_blog_post_complete_tags" name="Tags"
|
||||||
inherit_option_id="website_blog.blog_post_complete" inherit_id="website_blog.blog_post_complete">
|
inherit_option_id="website_blog.blog_post_complete">
|
||||||
<xpath expr="//p[@name='blog_post_data']" position="after">
|
<xpath expr="//p[@name='blog_post_data']" position="after">
|
||||||
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
|
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
|
||||||
<span class="fa fa-tags"/>
|
<span class="fa fa-tags"/>
|
||||||
|
@ -277,6 +379,9 @@
|
||||||
<t t-call="website.layout">
|
<t t-call="website.layout">
|
||||||
<t t-set="head">
|
<t t-set="head">
|
||||||
<link rel='stylesheet' href='/website_blog/static/src/css/website_blog.css'/>
|
<link rel='stylesheet' href='/website_blog/static/src/css/website_blog.css'/>
|
||||||
|
<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/website_blog.js"/>
|
||||||
|
<script type="text/javascript" src="/website_blog/static/lib/contentshare.js"/>
|
||||||
</t>
|
</t>
|
||||||
<div id="wrap" class="js_blog">
|
<div id="wrap" class="js_blog">
|
||||||
<t t-raw="0"/>
|
<t t-raw="0"/>
|
||||||
|
@ -284,26 +389,26 @@
|
||||||
</t>
|
</t>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Option: Right Column for extra info -->
|
<!-- Option: Left Column for extra info -->
|
||||||
|
|
||||||
<template id="index_right" name="Right Column"
|
<template id="index_left" name="Left Column"
|
||||||
inherit_option_id="website_blog.index">
|
inherit_option_id="website_blog.index">
|
||||||
<xpath expr="//div[@id='wrap']" position="replace">
|
<xpath expr="//div[@id='wrap']" position="replace">
|
||||||
<div class="container mt16 js_website_blog">
|
<div class="container mt16 js_website_blog">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-8 col-sm-8" id="blog_left_column">
|
<div class="col-lg-3 col-lg-offset-1 col-sm-4" id="blog_left_column"/>
|
||||||
|
<div class="col-lg-8 col-sm-8" id="blog_right_column">
|
||||||
<t t-raw="0"/>
|
<t t-raw="0"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3 col-lg-offset-1 col-sm-4" id="blog_right_column"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Option: Right Column: tags -->
|
<!-- Option: Left Column: tags -->
|
||||||
<template id="opt_blog_rc_tags" name="Tags"
|
<template id="opt_blog_rc_tags" name="Tags"
|
||||||
inherit_option_id="website_blog.index_right">
|
inherit_option_id="website_blog.index_left">
|
||||||
<xpath expr="//div[@id='blog_right_column']" position="inside">
|
<xpath expr="//div[@id='blog_left_column']" position="inside">
|
||||||
<section class="mt32">
|
<section class="mt32">
|
||||||
<h4>Tags</h4>
|
<h4>Tags</h4>
|
||||||
<ul class="nav nav-pills nav-stacked">
|
<ul class="nav nav-pills nav-stacked">
|
||||||
|
@ -317,10 +422,10 @@
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Option: Right Column: archives -->
|
<!-- Option: Left Column: archives -->
|
||||||
<template id="opt_blog_rc_history" name="Archives"
|
<template id="opt_blog_rc_history" name="Archives"
|
||||||
inherit_option_id="website_blog.index_right">
|
inherit_option_id="website_blog.index_left">
|
||||||
<xpath expr="//div[@id='blog_right_column']" position="inside">
|
<xpath expr="//div[@id='blog_left_column']" position="inside">
|
||||||
<section class="mt32">
|
<section class="mt32">
|
||||||
<h4>Archives</h4>
|
<h4>Archives</h4>
|
||||||
<ul class="nav nav-pills nav-stacked">
|
<ul class="nav nav-pills nav-stacked">
|
||||||
|
@ -334,10 +439,10 @@
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Option: Right Column: about us -->
|
<!-- Option: Left Column: about us -->
|
||||||
<template id="opt_blog_rc_about_us" name="About Us" priority="2"
|
<template id="opt_blog_rc_about_us" name="About Us" priority="2"
|
||||||
inherit_option_id="website_blog.index_right">
|
inherit_option_id="website_blog.index_left">
|
||||||
<xpath expr="//div[@id='blog_right_column']" position="inside">
|
<xpath expr="//div[@id='blog_left_column']" position="inside">
|
||||||
<section class="mt32">
|
<section class="mt32">
|
||||||
<h4>About us</h4>
|
<h4>About us</h4>
|
||||||
<p>
|
<p>
|
||||||
|
@ -351,10 +456,10 @@
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Option: Right Column: follow us -->
|
<!-- Option: Left Column: follow us -->
|
||||||
<template id="opt_blog_rc_follow_us" name="Follow us" priority="4"
|
<template id="opt_blog_rc_follow_us" name="Follow us" priority="4"
|
||||||
inherit_option_id="website_blog.index_right">
|
inherit_option_id="website_blog.index_left">
|
||||||
<xpath expr="//div[@id='blog_right_column']" position="inside">
|
<xpath expr="//div[@id='blog_left_column']" position="inside">
|
||||||
<section class="mt32">
|
<section class="mt32">
|
||||||
<h4>Follow us<small t-if="blog">: <t t-esc="blog.name"/></small></h4>
|
<h4>Follow us<small t-if="blog">: <t t-esc="blog.name"/></small></h4>
|
||||||
<t t-if="blog">
|
<t t-if="blog">
|
||||||
|
@ -378,10 +483,10 @@
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Option: Right Column: blogs -->
|
<!-- Option: Left Column: blogs -->
|
||||||
<template id="opt_blog_rc_blogs" name="Our Blogs" priority="6"
|
<template id="opt_blog_rc_blogs" name="Our Blogs" priority="6"
|
||||||
inherit_option_id="website_blog.index_right">
|
inherit_option_id="website_blog.index_left">
|
||||||
<xpath expr="//div[@id='blog_right_column']" position="inside">
|
<xpath expr="//div[@id='blog_left_column']" position="inside">
|
||||||
<section class="mt32 mb32">
|
<section class="mt32 mb32">
|
||||||
<h4>Our Blogs</h4>
|
<h4>Our Blogs</h4>
|
||||||
<ul class="nav nav-pills nav-stacked">
|
<ul class="nav nav-pills nav-stacked">
|
||||||
|
|
|
@ -56,7 +56,9 @@
|
||||||
<sheet>
|
<sheet>
|
||||||
<h1><field name="name" placeholder="Name"/></h1>
|
<h1><field name="name" placeholder="Name"/></h1>
|
||||||
<field name="tag_ids" widget="many2many_tags"/>
|
<field name="tag_ids" widget="many2many_tags"/>
|
||||||
|
<field name="sub_title"/>
|
||||||
<group>
|
<group>
|
||||||
|
<field name="content_image"/>
|
||||||
<field name="blog_id"/>
|
<field name="blog_id"/>
|
||||||
</group>
|
</group>
|
||||||
<field name="content" placeholder="e.g. Once upon a time..." widget="html"/>
|
<field name="content" placeholder="e.g. Once upon a time..." widget="html"/>
|
||||||
|
@ -113,47 +115,5 @@
|
||||||
</record>
|
</record>
|
||||||
<menuitem id="menu_blog" parent="menu_wiki" name="Blogs" action="action_blog_blog" sequence="20"/>
|
<menuitem id="menu_blog" parent="menu_wiki" name="Blogs" action="action_blog_blog" sequence="20"/>
|
||||||
|
|
||||||
<!-- History Tree view -->
|
|
||||||
<record model="ir.ui.view" id="view_blog_history_tree">
|
|
||||||
<field name="name">blog.post.history.tree</field>
|
|
||||||
<field name="model">blog.post.history</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree string="Document History">
|
|
||||||
<field name="create_date"/>
|
|
||||||
<field name="create_uid"/>
|
|
||||||
<field name="post_id"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<!-- History Form view -->
|
|
||||||
<record model="ir.ui.view" id="view_blog_history_form">
|
|
||||||
<field name="name">blog.post.history.form</field>
|
|
||||||
<field name="model">blog.post.history</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="Blog Post History" version="7.0">
|
|
||||||
<label for="post_id" class="oe_edit_only"/>
|
|
||||||
<h1><field name="post_id" select="1" /></h1>
|
|
||||||
<label for="create_date" class="oe_edit_only"/>
|
|
||||||
<field name="create_date" readonly="1"/>
|
|
||||||
<label for="content" class="oe_edit_only"/>
|
|
||||||
<field name="content" colspan="4"/>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<!-- History Action -->
|
|
||||||
<record model="ir.actions.act_window" id="action_history">
|
|
||||||
<field name="name">Page history</field>
|
|
||||||
<field name="res_model">blog.post.history</field>
|
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_mode">tree,form</field>
|
|
||||||
</record>
|
|
||||||
<menuitem id="menu_page_history" parent="menu_wiki" name="Pages history" action="action_history" sequence="30" groups="base.group_no_one"/>
|
|
||||||
<act_window
|
|
||||||
id="action_related_page_history"
|
|
||||||
context="{'search_default_post_id': [active_id], 'default_post_id': active_id}"
|
|
||||||
domain="[('post_id','=',active_id)]"
|
|
||||||
name="Page History"
|
|
||||||
res_model="blog.post.history"
|
|
||||||
src_model="blog.post"/>
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# OpenERP, Open Source Management Solution
|
|
||||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
import document_page_show_diff
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
|
@ -1,61 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# OpenERP, Open Source Management Solution
|
|
||||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
from openerp.osv import fields, osv
|
|
||||||
from openerp.tools.translate import _
|
|
||||||
|
|
||||||
|
|
||||||
class showdiff(osv.osv_memory):
|
|
||||||
""" Disp[ay Difference for History """
|
|
||||||
|
|
||||||
_name = 'blog.post.history.show_diff'
|
|
||||||
|
|
||||||
def get_diff(self, cr, uid, context=None):
|
|
||||||
if context is None:
|
|
||||||
context = {}
|
|
||||||
history = self.pool.get('blog.post.history')
|
|
||||||
ids = context.get('active_ids', [])
|
|
||||||
|
|
||||||
diff = ""
|
|
||||||
if len(ids) == 2:
|
|
||||||
if ids[0] > ids[1]:
|
|
||||||
diff = history.getDiff(cr, uid, ids[1], ids[0])
|
|
||||||
else:
|
|
||||||
diff = history.getDiff(cr, uid, ids[0], ids[1])
|
|
||||||
|
|
||||||
elif len(ids) == 1:
|
|
||||||
old = history.browse(cr, uid, ids[0])
|
|
||||||
nids = history.search(cr, uid, [('post_id', '=', old.post_id.id)])
|
|
||||||
nids.sort()
|
|
||||||
diff = history.getDiff(cr, uid, ids[0], nids[-1])
|
|
||||||
else:
|
|
||||||
raise osv.except_osv(_('Warning!'), _('You need to select minimum one or maximum two history revisions!'))
|
|
||||||
return diff
|
|
||||||
|
|
||||||
_columns = {
|
|
||||||
'diff': fields.text('Diff', readonly=True),
|
|
||||||
}
|
|
||||||
|
|
||||||
_defaults = {
|
|
||||||
'diff': get_diff
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
|
@ -1,39 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<openerp>
|
|
||||||
<data>
|
|
||||||
|
|
||||||
<!-- Create Index Form view -->
|
|
||||||
<record id="view_wiki_show_diff" model="ir.ui.view">
|
|
||||||
<field name="name">Show Difference</field>
|
|
||||||
<field name="model">blog.post.history.show_diff</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="Difference" version="7.0">
|
|
||||||
<field name="diff" widget="html" options='{"safe": True}'/>
|
|
||||||
<footer>
|
|
||||||
<button string="Cancel" class="oe_link" special="cancel" />
|
|
||||||
</footer>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<!-- Create Index Action -->
|
|
||||||
<record id="action_view_wiki_show_diff" model="ir.actions.act_window">
|
|
||||||
<field name="name">Difference</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="res_model">blog.post.history.show_diff</field>
|
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_mode">form</field>
|
|
||||||
<field name="target">new</field>
|
|
||||||
</record>
|
|
||||||
<!-- Create Index Action Window -->
|
|
||||||
<act_window
|
|
||||||
id="action_view_wiki_show_diff_values"
|
|
||||||
key2="client_action_multi"
|
|
||||||
name="Difference"
|
|
||||||
res_model="blog.post.history.show_diff"
|
|
||||||
src_model="blog.post.history"
|
|
||||||
view_mode="form"
|
|
||||||
target="new"
|
|
||||||
view_type="form"/>
|
|
||||||
|
|
||||||
</data>
|
|
||||||
</openerp>
|
|
|
@ -140,5 +140,4 @@
|
||||||
return this._super();
|
return this._super();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -23,4 +23,3 @@ class TestUi(openerp.tests.HttpCase):
|
||||||
@unittest2.expectedFailure
|
@unittest2.expectedFailure
|
||||||
def test_04_public_checkout(self):
|
def test_04_public_checkout(self):
|
||||||
self.phantom_js("/", "openerp.website.Tour.run_test('shop_buy_product')", "openerp.website.Tour.ShopTest", inject=inject)
|
self.phantom_js("/", "openerp.website.Tour.run_test('shop_buy_product')", "openerp.website.Tour.ShopTest", inject=inject)
|
||||||
|
|
||||||
|
|