[IMP] Blogs Medium-Like

bzr revid: fp@tinyerp.com-20140223094412-zryqfz2b0n3ojo6g
This commit is contained in:
Fabien Pinckaers 2014-02-23 10:44:12 +01:00
commit 9de47d55f4
32 changed files with 1193 additions and 612 deletions

View File

@ -21,4 +21,3 @@
import controllers import controllers
import models import models
import wizard

View File

@ -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'
], ],

View File

@ -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 []

View File

@ -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">

View File

@ -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>

View File

@ -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:

View File

@ -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

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 blog_blog_all blog.blog model_blog_blog 1 0 0 0
3 blog_post_all blog.post model_blog_post 1 0 0 0
4 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
5 blog_tag blog.tag model_blog_tag 1 0 0 0
6 blog_tag_edition blog.tag model_blog_tag base.group_document_user 1 1 1 1

View File

@ -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>

View File

@ -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",
};
}());

View File

@ -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;
}

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -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');
},
}); });
})(); })();

View File

@ -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');
}
});
})();

View File

@ -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);
}
});
}
});

View File

@ -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>

View File

@ -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[:] })

View File

@ -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 '&amp;' 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 '&amp;' 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 '&amp;' 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&amp;field=image_small&amp;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"/> &amp;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"/> &amp;nbsp;</span> <span class="fa fa-calendar oe_date" name="blog_post_date"> <span t-field="blog_post.create_date"/> &amp;nbsp;</span>
<span t-if="len(blog_post.message_ids) &gt; 0" class="fa fa-comment-o"> With <span t-if="len(blog_post.message_ids) &gt; 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) &lt;= 1" ><t t-esc="len(blog_post.message_ids)"/> comment</t> <t t-if="len(blog_post.message_ids) &lt;= 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&amp;field=image_small&amp;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&amp;field=image_small&amp;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&amp;field=image_small&amp;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&amp;field=image&amp;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">

View File

@ -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>

View File

@ -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:

View File

@ -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:

View File

@ -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>

View File

@ -140,5 +140,4 @@
return this._super(); return this._super();
} }
}); });
}()); }());

View File

@ -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)