[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 models
import wizard

View File

@ -35,16 +35,13 @@ OpenERP Blog
'data/website_blog_data.xml',
'views/website_blog_views.xml',
'views/website_blog_templates.xml',
'wizard/document_page_show_diff_view.xml',
'security/ir.model.access.csv',
'security/website_blog.xml',
],
'demo': [
'data/website_blog_demo.xml'
],
'test': [
'tests/test_website_blog.yml'
],
'test': [],
'qweb': [
'static/src/xml/*.xml'
],

View File

@ -25,7 +25,9 @@ from openerp.tools.translate import _
from openerp import SUPERUSER_ID
import werkzeug
import random
import json
from openerp.tools import html2plaintext
class WebsiteBlog(http.Controller):
@ -144,8 +146,26 @@ class WebsiteBlog(http.Controller):
'path_filter': path_filter,
'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([
'/blogpost/<model("blog.post"):blog_post>/',
], 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
- 'tag': current tag, if tag_id
- 'nav_list': a dict [year][month] for archives navigation
- 'next_blog': next blog post , display in footer
"""
pager_url = "/blogpost/%s" % blog_post.id
@ -196,9 +217,17 @@ class WebsiteBlog(http.Controller):
tag_ids = tag_obj.search(cr, uid, [], 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'),
_('May'), _('June'), _('July'), _('August'), _('September'),
_('October'), _('November'), _('December')]
next_post, unvisited = self.get_next_post(cr, uid, blog_post, context)
values = {
'blog': blog_post.blog_id,
@ -211,12 +240,14 @@ class WebsiteBlog(http.Controller):
'nav_list': self.nav_list(),
'enable_editor': enable_editor,
'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)
@http.route(['/blogpost/comment'], type='http', auth="public", methods=['POST'], website=True)
def blog_post_comment(self, blog_post_id=0, **post):
response = request.website.render("website_blog.blog_post_complete", values)
response.set_cookie('unvisited', json.dumps(unvisited))
return response
def _blog_post_message(self, blog_post_id=0, **post):
cr, uid, context = request.cr, request.uid, request.context
if post.get('comment'):
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]:
blog_post = request.registry['blog.post']
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),
body=post.get('comment'),
type='comment',
subtype='mt_comment',
author_id=user.partner_id.id,
discussion=post.get('discussion'),
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")
@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)
def blog_post_create(self, blog_id, **post):
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)
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)
@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">
<field name="name">News</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 id="menu_news" model="website.menu">

View File

@ -13,218 +13,257 @@
<record id="blog_tag_3" model="blog.tag">
<field name="name">website</field>
</record>
<record id="blog_tag_4" model="blog.tag">
<field name="name">pos</field>
</record>
<!-- POSTS -->
<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="tag_ids" eval="[(6, 0, [ref('blog_tag_1')])]"/>
<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_description">Open source Point of Sale with no installation required that runs online and offline.</field>
<field name="website_meta_keywords">OpenERP, email</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[
<section data-snippet-id='image-text'>
<div class="container">
<section class="mt16 mb16" data-snippet-id='image-text'>
<div class="container readable">
<div class="row">
<div class="col-md-6 mt16 mb16">
<img class="img-responsive shadow" src="/website/static/src/img/image_text.jpg"/>
</div>
<div class="col-md-6 mt16">
<p>
OpenERP's Point of Sale introduces a super clean
interface with no installation required that runs
online and offline on modern hardwares.
</p><p>
It's full integration with the company inventory
and accounting, gives you real time statistics
without the hassle of integrating several applications.
</p>
</div>
<iframe width="361" height="200" src="http://www.youtube.com/embed/EkbBFmIWoTE" frameborder="0" allowfullscreen></iframe>
<p>
Emails are broken.
</p><p>
Emails make me waste my time. But I need them.
Given the importance that emails have in our lives,
it's incredible it's still one of the only software
areas that did not evolve in the past 20 years!
</p><p>
Reading my inbox is the most unproductive task I do
on a daily basis. I have to spend one full hour a
day to process my emails. All the junk flows in the
same inbox; spams, information that doesn't matter,
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>
</section>
<section class="mt16 mb16" data-snippet-id='text-block'>
<div class="container">
<section class="mt16 mb16" data-snippet-id='text-image'>
<div class="container readable">
<div class="row">
<div class="col-md-12 text-center mt16 mb32">
<h2>
Linked with Project Management
</h2>
<h3 class="text-muted">Infinitely flexible. Incredibly easy to use.</h3>
</div>
<div class="col-md-12 mb16 mt16">
<p>
OpenERP's <b>collaborative and realtime</b> project
management helps your team get work done. Keep
track of everything, from the big picture to the
minute details, from the customer contract to the
billing.
</p><p>
Organize projects around <b>your own processes</b>. Work
on tasks and issues using the kanban view, schedule
tasks using the gantt chart and control deadlines
in the calendar view. Every project may have it's
own stages allowing teams to optimize their job.
</p>
</div>
<p>
At OpenERP, we build tools to bring productivity to
enterprises. As emails and information flows are one of
the biggest wastes of time in companies, we have to fix
this.
</p><p>
To disrupt emails, you need more than just another user
interface. We need to rethink the whole communication flow.
</p>
<h3>The Communication Mechanism of OpenERP</h3>
<p>
Here are the ideas behing the OpenERP communication tools:
</p>
<ul>
<li>
Get Things Done: your inbox is a
todo list. You should be able to process (not only
read) the inbox and easily mark messages for future
actions. Every inbox should be empty after having
been processed; no more overload of information.
<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>
</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>
</record>
<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="website_published" eval="True"/>
<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">
<![CDATA[<section class="mt16 mb16" data-snippet-id='big-picture'>
<div class="container">
<![CDATA[<section class="mt16 mb16 " data-snippet-id='image-text'>
<div class="container readable">
<div class="row">
<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 class="col-md-6 col-md-offset-3 mb16 mt16">
<p class="text-center">
<b>New Features Launched</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.
New Features Launched
</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>
</section>
<section data-snippet-id='pricing'>
<div class="container">
<div class="row">
<div class="col-md-12 text-center mt16 mb32">
<h2>Our Offers</h2>
</div>
<div class="col-md-4">
<div class="panel panel-info">
<!-- Default panel contents -->
<div class="panel-heading text-center">
<h2 style="margin: 0">Beginner</h2>
<p style="margin: 0" class="text-muted">
Starter package
</p>
</div>
<div class="panel-body text-center text-muted" style="background-color: rgba(0,0,0,0.1)">
<h2 style="margin: 0"><span>$</span><b style="font-size: 60px">450</b><small>.00</small></h2>
<div>per month</div>
</div>
<!-- List group -->
<ul class="list-group">
<li class="list-group-item">Battery: 8 hours</li>
<li class="list-group-item">Screen: 2.5 inch</li>
<li class="list-group-item">Weight: 1.1 ounces</li>
<li class="list-group-item">No support</li>
</ul>
<div class="panel-footer text-center">
<p class="text-muted">
<i>Free shipping, satisfied or reimbursed.</i>
</p>
<a href="/page/website.contactus" class="btn btn-primary btn-lg">Order now</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-primary">
<!-- Default panel contents -->
<div class="panel-heading text-center">
<h2 style="margin: 0">Professional</h2>
<p style="margin: 0">
Enterprise package
</p>
</div>
<div class="panel-body text-center text-muted" style="background-color: rgba(0,0,0,0.1)">
<h2 style="margin: 0"><span>$</span><b style="font-size: 60px">590</b><small>.00</small></h2>
<div>per month</div>
</div>
<!-- List group -->
<ul class="list-group">
<li class="list-group-item">Battery: 12 hours</li>
<li class="list-group-item">Screen: 2.8 inch</li>
<li class="list-group-item">Weight: 1.2 ounces</li>
<li class="list-group-item">Limited support</li>
</ul>
<div class="panel-footer text-center">
<p class="text-muted">
<i>Free shipping, satisfied or reimbursed.</i>
</p>
<a href="/page/website.contactus" class="btn btn-primary btn-lg">Order now</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-info">
<!-- Default panel contents -->
<div class="panel-heading text-center">
<h2 style="margin: 0">Expert</h2>
<p style="margin: 0" class="text-muted">
The top of the top
</p>
</div>
<div class="panel-body text-center text-muted" style="background-color: rgba(0,0,0,0.1)">
<h2 style="margin: 0"><span>$</span><b style="font-size: 60px">890</b><small>.00</small></h2>
<div>per month</div>
</div>
<!-- List group -->
<ul class="list-group">
<li class="list-group-item">Battery: 20 hours</li>
<li class="list-group-item">Screen: 2.8 inch</li>
<li class="list-group-item">Weight: 1.2 ounces</li>
<li class="list-group-item">Unlimited support</li>
</ul>
<div class="panel-footer text-center">
<p class="text-muted">
<i>Free shipping, satisfied or reimbursed.</i>
</p>
<a href="/page/website.contactus" class="btn btn-primary btn-lg">Contact us</a>
</div>
</div>
</div>
</div>
<section data-snippet-id='text'>
<div class="container readable">
<p>
OpenERP claims to be 'the Open Source software that makes
building your company's website and selling your products
online easy'. So how true is this statement?
</p><p>
"OpenERP's latest launch will allow a business to go from
zero to trading online quicker than ever before,” Stuart
Mackintosh, MD of Open Source specialist and OpenERP
integration partner, OpusVL, explains. “The investment
required to have a fully automated business system is
dramatically reduced, enabling the small and medium
enterprise to compete at a level of functionality and
performance previously reserved for the big IT investors."
</p>
<h4>
"Finally, the leading edge is being brought to the masses.
It will now be the turn of the big players to catch up to
the superior technologies of the SME."
</h4>
<p>
"This is another clever and highly disruptive move by
OpenERP,which will force other technology providers to
take another look at the value they are providing to ensure
that their 'solutions' can still compete."
</p><p>
"OpenERP now competes on many fronts, with no real
competition out there to knock them off the top spot.
With the launch of their integrated CMS and Ecommerce
systems,it only elevates their position as one of the leading
lights in the open source revolution. It will be at least 5
years before another ERP or CMS provider will be able to
compete at this level due to the technology currently
employed by most industry providers."
</p>
<h4>Adding to industry leading technology</h4>
<p>
Like many modern website editors, with OpenERP you can edit
content in-line, enabling you to see exactly what you are
changing and ensure your changes suit the context.
</p><p>
However, unlike other web content management systems, it
fully integrates into the back-end database. This means
that when you edit a product description, image or price,
it updates the product database in real time, providing a
true self-service window into the business.
</p><p>
This provides a single source of data for your company and
removes the need to create offline synchronisation between
website and product database.
</p><p>
As it comes, there is a default website based on Bootstrap
3, the latest industry standard for rapid development of
multi-device websites backed by Twitter, so can be directly
integrated with many web tools and works across all devices
by default.
</p>
<h4>So, what does this mean to me and my business?</h4>
<p>
The CMS removes the need for Magento integration for the
shopping basket and Drupal/Joomla for the website. For any
organisation, this will reduce the technology footprint and
eliminate the complexities of FTP or file transfer data
uploads and exports which for many, are manual tasks.
Implementation is easier and the web designer can get
straight on with developing the site without requiring the
project management and interactions with site developers,
providing a quicker and more efficient deployment. However,
for larger sites, stringent process and project management
disciplines are still required to ensure a low-risk project.
</p>
<h4>How does it work in practice?</h4>
<p>
When items are placed in the basket, a sales order is
created automatically to reflect the basket contents.
Payments are recorded on the balance sheet and all
accounting journal entries are automatic. As it is in real
time, stock records are always accurate and decremented on
the fly when orders placed.
</p><p>
Automatic translations can be created for international
traders and available languages selected.
</p>
<p>
Customer queries and returns can be set up to use the case
handling system which will escalate depending on customer
spend, grouping or profile and notify relevant parties as
appropriate.
</p><p>
More information about the feature set can be found
<a href="https://www.openerp.com/website_cms" target="_TOP">
on the OpenERP website here</a>
</p>
<h4>Created in just four months</h4>
<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>
</section>
@ -232,105 +271,210 @@
]]>
</field>
</record>
<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="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_meta_keywords">OpenERP, Partnership, News, Accounting</field>
<field name="website_meta_description">Our company partners with OpenERP to develop accounting best practices.</field>
<field name="website_meta_keywords">OpenERP, News, Sorry SAP</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[
<section data-snippet-id='image-text'>
<div class="container">
<section data-snippet-id="text">
<div class="container readable">
<div class="row">
<div class="col-md-6 mt16 mb16">
<img class="img-responsive shadow" src="/website/static/src/img/text_image.png"/>
</div>
<div class="col-md-6 mt16">
<p>
We are proud to announce a new partnership with
the company OpenERP. Their open source application suite
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>
<p>I needed to change the world. I wanted to ... You know how
it is when you are young; you have big dreams, a lot of energ
and naïve stupidity. My dream was to lead the enterprise
management market with a fully open source software.(I also
wanted to get 100 employees before 30 years old with a
self-financed company but I failed this one by a few months).
</p>
</div>
</div>
</section>
<section class="mt16 mb16" data-snippet-id='text-block'>
<div class="container">
<section data-snippet-id="text-image">
<div class="container readable">
<div class="row">
<div class="col-md-12 text-center mt16 mb32">
<h2>
OpenERP Project Management
</h2>
<h3 class="text-muted">Infinitely flexible. Incredibly easy to use.</h3>
</div>
<div class="col-md-12 mb16 mt16">
<p>
OpenERP's <b>collaborative and realtime</b> project
management helps your team get work done. Keep
track of everything, from the big picture to the
minute details, from the customer contract to the
billing.
</p><p>
Organize projects around <b>your own processes</b>. Work
on tasks and issues using the kanban view, schedule
tasks using the gantt chart and control deadlines
in the calendar view. Every project may have it's
own stages allowing teams to optimize their job.
</p>
</div>
<p>
To fuel my motivation, I had to pick someone to fight
against. In business, it's like a playground. When you
arrive in a new school, if you want to quickly become the
leader, you must choose the class bully, the older guy who
terrorises small boys,and kick his butt in front of
everyone. That was my strategy with SAP, the enterprise
software giant.
</p><p>
So, in 2005, I started to develop the TinyERP product, the
software that (at least in my mind) would change the enterprise
world. While preparing for the "day of the fight" in 2006,
I <a href="http://whois.domaintools.com/sorrysap.com">
bought the SorrySAP.com </a>domain name. I put it on hold
for 6 years, waiting for the right moment to use it.
I thought it would take 3 years to deprecate a 77 billion
dollars company just because open source is so cool.
Sometimes it's better for your self-motivation not to
face reality...
</p><p>
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>
</section>
]]>
]]>
</field>
</record>
</data>
</openerp>

View File

@ -37,6 +37,7 @@ class Blog(osv.Model):
_columns = {
'name': fields.char('Name', required=True),
'description': fields.text('Description'),
'image': fields.binary('Image'),
'blog_post_ids': fields.one2many(
'blog.post', 'blog_id',
'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):
_name = "blog.post"
@ -66,32 +72,9 @@ class BlogPost(osv.Model):
# maximum number of characters to display in summary
_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 = {
'name': fields.char('Title', required=True, translate=True),
'sub_title' : fields.char('Sub Title', translate=True),
'content_image': fields.binary('Background Image'),
'blog_id': fields.many2one(
'blog.blog', 'Blog',
@ -101,12 +84,6 @@ class BlogPost(osv.Model):
'blog.tag', string='Tags',
),
'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_published': fields.boolean(
'Publish', help="Publish on the website"
@ -114,20 +91,6 @@ class BlogPost(osv.Model):
'website_published_datetime': fields.datetime(
'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
'create_date': fields.datetime(
'Created on',
@ -145,37 +108,14 @@ class BlogPost(osv.Model):
'res.users', 'Last Contributor',
select=True, readonly=True,
),
'visits': fields.integer('No of Visitors'),
}
_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):
if default is None:
default = {}
default = default or {}
default.update({
'website_message_ids': [],
'website_published': False,
@ -187,33 +127,3 @@ class BlogPost(osv.Model):
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)
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_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_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_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'))]"/>
</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>
</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";
@import url(compass/css3.css);
@charset "UTF-8";
.css_website_mail .has-error {
border-color: red;
}
@ -21,3 +20,124 @@ p.post-meta {
position: relative;
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
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) {
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>
</div>
<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">
<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>
@ -122,7 +122,6 @@
</span>
<span t-if="not blog_post.website_published" class="label label-danger">not published</span>
</p>
<div t-raw="blog_post.shortened_content" class="blog_content"/>
<hr/>
</div>
@ -130,6 +129,26 @@
</t>
</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 -->
<template id="opt_blog_post_short_author" name="Author"
inherit_option_id="website_blog.blog_post_short">
@ -140,7 +159,7 @@
<!-- Option: Blog Post Summary: show 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">
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
<span class="fa fa-tags"/>
@ -151,14 +170,15 @@
</xpath>
</template>
<!-- Blog Post Complete -->
<template id="blog_post_complete" name="Blog Post">
<t t-call="website_blog.index">
<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">
<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
<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>
@ -179,8 +199,7 @@
</li>
</t>
</div>
<div t-field="blog_post.content"/>
<div id="blog_content" t-field="blog_post.content"/>
<section id="comments" class="container">
<ul class="media-list" id="comments-list">
@ -223,10 +242,93 @@
</xpath>
</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 -->
<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">
<xpath expr="//ul[@id='comments-list']" position="before">
<section class="mb32 css_editable_mode_hidden">
@ -261,7 +363,7 @@
<!-- Options: Blog Post: show 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">
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
<span class="fa fa-tags"/>
@ -277,6 +379,9 @@
<t t-call="website.layout">
<t t-set="head">
<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>
<div id="wrap" class="js_blog">
<t t-raw="0"/>
@ -284,26 +389,26 @@
</t>
</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">
<xpath expr="//div[@id='wrap']" position="replace">
<div class="container mt16 js_website_blog">
<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"/>
</div>
<div class="col-lg-3 col-lg-offset-1 col-sm-4" id="blog_right_column"/>
</div>
</div>
</xpath>
</template>
<!-- Option: Right Column: tags -->
<!-- Option: Left Column: tags -->
<template id="opt_blog_rc_tags" name="Tags"
inherit_option_id="website_blog.index_right">
<xpath expr="//div[@id='blog_right_column']" position="inside">
inherit_option_id="website_blog.index_left">
<xpath expr="//div[@id='blog_left_column']" position="inside">
<section class="mt32">
<h4>Tags</h4>
<ul class="nav nav-pills nav-stacked">
@ -317,10 +422,10 @@
</xpath>
</template>
<!-- Option: Right Column: archives -->
<!-- Option: Left Column: archives -->
<template id="opt_blog_rc_history" name="Archives"
inherit_option_id="website_blog.index_right">
<xpath expr="//div[@id='blog_right_column']" position="inside">
inherit_option_id="website_blog.index_left">
<xpath expr="//div[@id='blog_left_column']" position="inside">
<section class="mt32">
<h4>Archives</h4>
<ul class="nav nav-pills nav-stacked">
@ -334,10 +439,10 @@
</xpath>
</template>
<!-- Option: Right Column: about us -->
<!-- Option: Left Column: about us -->
<template id="opt_blog_rc_about_us" name="About Us" priority="2"
inherit_option_id="website_blog.index_right">
<xpath expr="//div[@id='blog_right_column']" position="inside">
inherit_option_id="website_blog.index_left">
<xpath expr="//div[@id='blog_left_column']" position="inside">
<section class="mt32">
<h4>About us</h4>
<p>
@ -351,10 +456,10 @@
</xpath>
</template>
<!-- Option: Right Column: follow us -->
<!-- Option: Left Column: follow us -->
<template id="opt_blog_rc_follow_us" name="Follow us" priority="4"
inherit_option_id="website_blog.index_right">
<xpath expr="//div[@id='blog_right_column']" position="inside">
inherit_option_id="website_blog.index_left">
<xpath expr="//div[@id='blog_left_column']" position="inside">
<section class="mt32">
<h4>Follow us<small t-if="blog">: <t t-esc="blog.name"/></small></h4>
<t t-if="blog">
@ -378,10 +483,10 @@
</xpath>
</template>
<!-- Option: Right Column: blogs -->
<!-- Option: Left Column: blogs -->
<template id="opt_blog_rc_blogs" name="Our Blogs" priority="6"
inherit_option_id="website_blog.index_right">
<xpath expr="//div[@id='blog_right_column']" position="inside">
inherit_option_id="website_blog.index_left">
<xpath expr="//div[@id='blog_left_column']" position="inside">
<section class="mt32 mb32">
<h4>Our Blogs</h4>
<ul class="nav nav-pills nav-stacked">

View File

@ -56,7 +56,9 @@
<sheet>
<h1><field name="name" placeholder="Name"/></h1>
<field name="tag_ids" widget="many2many_tags"/>
<field name="sub_title"/>
<group>
<field name="content_image"/>
<field name="blog_id"/>
</group>
<field name="content" placeholder="e.g. Once upon a time..." widget="html"/>
@ -113,47 +115,5 @@
</record>
<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>
</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();
}
});
}());

View File

@ -23,4 +23,3 @@ class TestUi(openerp.tests.HttpCase):
@unittest2.expectedFailure
def test_04_public_checkout(self):
self.phantom_js("/", "openerp.website.Tour.run_test('shop_buy_product')", "openerp.website.Tour.ShopTest", inject=inject)