diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index 1711bddcfce..7824a3974d4 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -288,8 +288,6 @@ class Website(openerp.addons.web.controllers.main.Home): values = {} if 'website_published' in _object._all_columns: values['website_published'] = not obj.website_published - if 'website_published_datetime' in _object._all_columns and values.get('website_published'): - values['website_published_datetime'] = fields.datetime.now() _object.write(request.cr, request.uid, [_id], values, context=request.context) diff --git a/addons/website/static/src/css/website.css b/addons/website/static/src/css/website.css index 354796a053e..87079d270e2 100644 --- a/addons/website/static/src/css/website.css +++ b/addons/website/static/src/css/website.css @@ -284,10 +284,6 @@ ul.nav-stacked > li > a { background-size: 100%; } -section, .carousel, .parallax, .row, .hr, .blockquote { - min-height: 30px; -} - .carousel, .parallax, .blockquote { overflow: hidden; } diff --git a/addons/website/static/src/css/website.sass b/addons/website/static/src/css/website.sass index 77da53c2958..73aa4f77737 100644 --- a/addons/website/static/src/css/website.sass +++ b/addons/website/static/src/css/website.sass @@ -234,8 +234,6 @@ ul.nav-stacked > li > a .oe_img_bg background-size: 100% -section, .carousel, .parallax, .row, .hr, .blockquote - min-height: 30px .carousel, .parallax, .blockquote overflow: hidden diff --git a/addons/website_blog/controllers/main.py b/addons/website_blog/controllers/main.py index 5cb678b5475..7192d56cf67 100644 --- a/addons/website_blog/controllers/main.py +++ b/addons/website_blog/controllers/main.py @@ -29,6 +29,7 @@ from openerp.addons.website.models.website import slug from openerp.osv.orm import browse_record from openerp.tools.translate import _ from openerp import SUPERUSER_ID +from openerp.tools import html2plaintext class QueryURL(object): @@ -62,8 +63,8 @@ class QueryURL(object): class WebsiteBlog(http.Controller): - _blog_post_per_page = 6 - _post_comment_per_page = 6 + _blog_post_per_page = 20 + _post_comment_per_page = 10 def nav_list(self): blog_post_obj = request.registry['blog.post'] @@ -129,14 +130,11 @@ class WebsiteBlog(http.Controller): cr, uid, context = request.cr, request.uid, request.context blog_post_obj = request.registry['blog.post'] - blog_posts = None - blog_obj = request.registry['blog.blog'] blog_ids = blog_obj.search(cr, uid, [], order="create_date asc", context=context) blogs = blog_obj.browse(cr, uid, blog_ids, context=context) domain = [] - if blog: domain += [('blog_id', '=', blog.id)] if tag: @@ -176,12 +174,13 @@ class WebsiteBlog(http.Controller): 'post_url': post_url, 'date': date_begin, } - return request.website.render("website_blog.blog_post_short", values) + response = request.website.render("website_blog.blog_post_short", values) + return response @http.route([ - '/blogpost/', + '/blog//post/', ], type='http', auth="public", website=True, multilang=True) - def blog_post(self, blog_post, tag_id=None, page=1, enable_editor=None, **post): + def blog_post(self, blog, blog_post, tag_id=None, page=1, enable_editor=None, **post): """ Prepare all values to display the blog. :param blog_post: blog post currently browsed. If not set, the user is @@ -204,6 +203,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 """ date_begin, date_end = post.get('date_begin'), post.get('date_end') @@ -227,6 +227,10 @@ class WebsiteBlog(http.Controller): blog_url = QueryURL('', ['blog', 'tag'], blog=blog_post.blog_id, tag=tag, date_begin=date_begin, date_end=date_end) cr, uid, context = request.cr, request.uid, request.context + if not blog_post.blog_id.id==blog.id: + return request.redirect("/blog/%s/post/%s" % (blog_post.blog_id.id, blog_post.id)) + blog_post_obj = request.registry.get('blog.post') + blog_obj = request.registry['blog.blog'] blog_ids = blog_obj.search(cr, uid, [], context=context) blogs = blog_obj.browse(cr, uid, blog_ids, context=context) @@ -235,53 +239,117 @@ class WebsiteBlog(http.Controller): tag_ids = tag_obj.search(cr, uid, [], context=context) tags = tag_obj.browse(cr, uid, tag_ids, context=context) + # Find next Post + visited_blogs = request.httprequest.cookies.get('visited_blogs') or '' + visited_ids = filter(None, visited_blogs.split(',')) + visited_ids = map(lambda x: int(x), visited_ids) + if blog_post.id not in visited_ids: + visited_ids.append(blog_post.id) + next_post_id = blog_post_obj.search(cr, uid, [ + ('id', 'not in', visited_ids), + ], order='ranking desc', limit=1, context=context) + next_post = next_post_id and blog_post_obj.browse(cr, uid, next_post_id[0], context=context) or False + values = { - 'blog': blog_post.blog_id, + 'blog': blog, 'blogs': blogs, 'tags': tags, 'tag': tag, 'blog_post': blog_post, 'main_object': blog_post, - 'pager': pager, 'nav_list': self.nav_list(), 'enable_editor': enable_editor, + 'next_post' : next_post, 'date': date_begin, 'post_url': post_url, 'blog_url': blog_url, } - return request.website.render("website_blog.blog_post_complete", values) + response = request.website.render("website_blog.blog_post_complete", values) + response.set_cookie('visited_blogs', ','.join(map(str, visited_ids))) + + request.session[request.session_id] = request.session.get(request.session_id, []) + if not (blog_post.id in request.session[request.session_id]): + request.session[request.session_id].append(blog_post.id) + # Increase counter + blog_post_obj.write(cr, SUPERUSER_ID, [blog_post.id], { + 'visits': blog_post.visits+1, + },context=context) + return response + + def _blog_post_message(self, user, blog_post_id=0, **post): + cr, uid, context = request.cr, request.uid, request.context + blog_post = request.registry['blog.post'] + partner_obj = request.registry['res.partner'] + thread_obj = request.registry['mail.thread'] + website = request.registry['website'] + + public_id = website.get_public_user(cr, uid, context) + if uid != public_id: + partner_ids = [user.partner_id.id] + else: + partner_ids = blog_post._find_partner_from_emails( + cr, SUPERUSER_ID, 0, [post.get('email')], context=context) + if not partner_ids or not partner_ids[0]: + partner_ids = [partner_obj.create(cr, SUPERUSER_ID, {'name': post.get('name'), 'email': post.get('email')}, context=context)] + + message_id = blog_post.message_post( + cr, SUPERUSER_ID, int(blog_post_id), + body=post.get('comment'), + type='comment', + subtype='mt_comment', + author_id=partner_ids[0], + 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): 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) - group_ids = user.groups_id - group_id = request.registry["ir.model.data"].get_object_reference(cr, uid, 'website_mail', 'group_comment')[1] - 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( - cr, SUPERUSER_ID, int(blog_post_id), - body=post.get('comment'), - type='comment', - subtype='mt_comment', - author_id=user.partner_id.id, - context=dict(context, mail_create_nosubcribe=True)) + user = request.registry['res.users'].browse(cr, uid, uid, context=context) + blog_post = request.registry['blog.post'] + blog_post.check_access_rights(cr, uid, 'read') + self._blog_post_message(user, blog_post_id, **post) return werkzeug.utils.redirect(request.httprequest.referrer + "#comments") + def _get_discussion_detail(self, ids, publish=False, **post): + cr, uid, context = request.cr, request.uid, request.context + values = [] + mail_obj = request.registry.get('mail.message') + for message in mail_obj.browse(cr, SUPERUSER_ID, ids, context=context): + values.append({ + "id": message.id, + "author_name": message.author_id.name, + "author_image": message.author_id.image and \ + ("data:image/png;base64,%s" % message.author_id.image) or \ + '/website_blog/static/src/img/anonymous.png', + "date": message.date, + 'body': html2plaintext(message.body), + 'website_published' : message.website_published, + 'publish' : publish, + }) + return values + + @http.route(['/blogpost/post_discussion'], type='json', auth="public", website=True) + def post_discussion(self, blog_post_id=0, **post): + cr, uid, context = request.cr, request.uid, request.context + publish = request.registry['res.users'].has_group(cr, uid, 'base.group_website_publisher') + user = request.registry['res.users'].browse(cr, uid, uid, context=context) + id = self._blog_post_message(user, blog_post_id, **post) + return self._get_discussion_detail([id], publish, **post) + @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 create_context = dict(context, mail_create_nosubscribe=True) - new_blog_post_id = request.registry['blog.post'].create( - request.cr, request.uid, { + new_blog_post_id = request.registry['blog.post'].create(cr, uid, { 'blog_id': blog_id, 'name': _("Blog Post Title"), + 'sub_title': _("Subtitle"), 'content': '', 'website_published': False, }, context=create_context) - return werkzeug.utils.redirect("/blogpost/%s?enable_editor=1" % new_blog_post_id) + return werkzeug.utils.redirect("/blog/%s/post/%s/?enable_editor=1" % (blog_id, new_blog_post_id)) @http.route('/blogpost/duplicate', type='http', auth="public", website=True) def blog_post_copy(self, blog_post_id, **post): @@ -293,5 +361,32 @@ class WebsiteBlog(http.Controller): """ cr, uid, context = request.cr, request.uid, request.context 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) + nid = request.registry['blog.post'].copy(cr, uid, blog_post_id, {}, context=create_context) + post = request.registry['blog.post'].browse(cr, uid, nid, context) + return werkzeug.utils.redirect("/blog/%s/post/%s/?enable_editor=1" % (post.blog_id.id, nid)) + + @http.route('/blogpost/get_discussion/', type='json', auth="public", website=True) + def discussion(self, post_id=0, discussion=None, count=False, **post): + cr, uid, context = request.cr, request.uid, request.context + mail_obj = request.registry.get('mail.message') + domain = [('res_id', '=', int(post_id)) ,('model','=','blog.post'), ('discussion', '=', discussion)] + #check current user belongs to website publisher group + publish = request.registry['res.users'].has_group(cr, uid, 'base.group_website_publisher') + if not publish: + domain.append(('website_published', '=', True)) + ids = mail_obj.search(cr, SUPERUSER_ID, domain, count=count) + if count: + return ids + return self._get_discussion_detail(ids, publish, **post) + + @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, request.uid, [int(post_id)], values, request.context) + return [] + + @http.route('/blog/get_user/', type='json', auth="public", website=True) + def get_user(self, **post): + return [False if request.session.uid else True] diff --git a/addons/website_blog/data/website_blog_data.xml b/addons/website_blog/data/website_blog_data.xml index a5a3aa3d8c9..efc25264633 100644 --- a/addons/website_blog/data/website_blog_data.xml +++ b/addons/website_blog/data/website_blog_data.xml @@ -2,7 +2,8 @@ - News + Our News + Sharing our evolution with passion Presentation of new OpenERP features diff --git a/addons/website_blog/data/website_blog_demo.xml b/addons/website_blog/data/website_blog_demo.xml index 913c2ddc9b1..16c836732e7 100644 --- a/addons/website_blog/data/website_blog_demo.xml +++ b/addons/website_blog/data/website_blog_demo.xml @@ -13,324 +13,442 @@ website - - pos - - OpenERP v8 New Features + The Future of Emails + Ideas behing the OpenERP communication tools. - OpenERP, Point of Sale, Hardware, Interface, Payment Terminal, Store - Open source Point of Sale with no installation required that runs online and offline. + OpenERP, email + The Future of Emails + /website_blog/static/src/img/post1.jpg -
-
-
- -
-
-

- OpenERP's Point of Sale introduces a super clean - interface with no installation required that runs - online and offline on modern hardwares. -

- It's full integration with the company inventory - and accounting, gives you real time statistics - without the hassle of integrating several applications. -

-
-
-
+
+ +

+ Emails are broken. +

+ 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! +

+ 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! +

-
-
-
-
-

- Linked with Project Management -

-

Infinitely flexible. Incredibly easy to use.

-
-
-

- OpenERP's collaborative and realtime 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. -

- Organize projects around your own processes. 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. -

-
-
-
+
+

+ 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. +

+ To disrupt emails, you need more than just another user + interface. We need to rethink the whole communication flow. +

+

The Communication Mechanism of OpenERP

+

+ Here are the ideas behing the OpenERP communication tools: +

+
    +
  • + 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. + +
  • + 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. +
  • + 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. + +
  • + A mix of push & pull: Today, people + are victims of what others decide to push to them. + OpenERP differentiates: +
      +
    • + 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. +
    • + 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. +
    • +
    +
  • + 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) +
  • + 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. +
  • +
+

All of this with a super sexy and minimalist user interface.

-
-
-
-
-

Work with the hardware you already have...

-
-
- -
-
-

- No installation required -

-

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

-

- Get more information » -

-
-
-
-
- ]]> - New Hardware Integration + Integrating your CMS and E-Commerce + Building your company's website and selling your products online easy. - - - -
-
-
- -
-
-

- New Features Launched -

-

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

-
-
-
-
-
-
-
-
-

Our Offers

-
- -
-
- -
-

Beginner

-

- Starter package -

-
-
-

$450.00

-
per month
-
- - -
    -
  • Battery: 8 hours
  • -
  • Screen: 2.5 inch
  • -
  • Weight: 1.1 ounces
  • -
  • No support
  • -
- -
-
-
-
- -
-

Professional

-

- Enterprise package -

-
-
-

$590.00

-
per month
-
- - -
    -
  • Battery: 12 hours
  • -
  • Screen: 2.8 inch
  • -
  • Weight: 1.2 ounces
  • -
  • Limited support
  • -
- -
-
-
-
- -
-

Expert

-

- The top of the top -

-
-
-

$890.00

-
per month
-
- - -
    -
  • Battery: 20 hours
  • -
  • Screen: 2.8 inch
  • -
  • Weight: 1.2 ounces
  • -
  • Unlimited support
  • -
- -
- -
-
-
-
- - -]]> -
-
- - - Touchscreen Point of Sale for 6.1 - - - Point of Sale, Hardware, Interface, Payment Terminal, Store - Point of Sale with no installation required that runs online and offline. - -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.

- -

Here's a summary of its main features and benefits:

-
    -
  • 100% WEB based
  • -
  • available for any touchscreen device (ipod, ipad, any tablet)mobile (with portable devices)
  • -
  • no installation required
  • -
  • no synchronization needed, completely integrated
  • -
  • continue working even when your connection is down or if you close your browser, data won't be lost
  • -
  • fully web based with a clean interface smart interface
  • -
-

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.

-

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

-]]> -
-
- - - Announcing a New Partnership - - - OpenERP, Partnership, News, Accounting - Our company partners with OpenERP to develop accounting best practices. - -
-
-
- -
-
-

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

- The full integration with the company inventory - and accounting, will give our customers real time statistics - without the hassle of integrating several applications. -

-
-
+ + /website_blog/static/src/img/post2.jpg + + +
+ +
+
+

+ New Features Launched +

+

+ 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. +

-
-
-
-
-

- OpenERP Project Management -

-

Infinitely flexible. Incredibly easy to use.

-
-
-

- OpenERP's collaborative and realtime 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. -

- Organize projects around your own processes. 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. -

-
-
-
+
+

+ 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? +

+ "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." +

+
+

+ "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." +

+
+

+ "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." +

+ "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." +

+

Adding to industry leading technology

+

+ 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. +

+ 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. +

+ This provides a single source of data for your company and + removes the need to create offline synchronisation between + website and product database. +

+ 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. +

+

So, what does this mean to me and my business?

+

+ 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. +

+

How does it work in practice?

+

+ 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. +

+ Automatic translations can be created for international + traders and available languages selected. +

+

+ 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. +

+ More information about the feature set can be found + + on the OpenERP website here +

+

Created in just four months

+

+ 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. +

+ Inspiration has come from various other platforms including + Prestashop, Magento and Drupal and contributors bring many + years of industry experience across many platforms. +

]]> - - + + Sorry SAP Campaign - The Making Of + To lead the enterprise management market with a fully open source software. + + + OpenERP, News, Sorry SAP + Sorry SAP Campaign - The Making Of + /website_blog/static/src/img/post3.jpg + +

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). +

+
+
+

+ 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. +

+ 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 + bought the SorrySAP.com 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... +

+ 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 + :). +

+ 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 + + in front of Danone's directors asking; "but why + should we pay millions of dollars for a tiny software?" + So, we renamed TinyERP to OpenERP. +

+ 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). +

+ 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. +

+ It was time to do a pivot in the business model. +

+

The Pivot

+

+ 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 changed our + business model 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. +

+ 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. +

+ 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. +

+ 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. +

+ We changed the deal and I got the 3 million EUR. It allowed + me to recruit a rocking management team. +

+ +

Being a mature company

+

+ 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. +

+ 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. +

+ 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. +

+ 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. +

+ +

+ OpenERP Monthly Turnover +

+ 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 + fastest growing company in Belgium!". (Deloitte awarded + us as the fastest growing company of Belgium with 1549% + growth of the turnover between 2007 and 2011) +

+

Changing the world

+

+ Then, the dream started to become reality. We started to + get clues that what we did would change the world: +

+ +

+ Something is happening... And it's big! +

+ OpenERP 7.0 is about to be released and I know you will be + astonished by it. +

+ 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. +

+ It's time to pull out the Ace: the SorrySAP.com domain + name that I bought 6 years ago. +

+
+ ]]> +
+ diff --git a/addons/website_blog/doc/blog_blog.rst b/addons/website_blog/doc/blog_blog.rst new file mode 100644 index 00000000000..8c5f80ab8e4 --- /dev/null +++ b/addons/website_blog/doc/blog_blog.rst @@ -0,0 +1,20 @@ +_blog_blog: + +blog.blog +========= +In ``blog.blog``, added field ``subtitle`` which Indicates the subtitle of blogs. + - ``subtitle``: fields.char('Blog Subtitle') + +mail.message +============ +In ``mail.message``, added field ``discussion`` which Indicates the unique identification +of paragraph on blog post. + - ``discussion``: fields.char('Discussion Unique Name') + +blog.post +========= +Fields +++++++ + - ``sub_title`` : contains the subtitle of every blog post. + - ``visits`` : Indicates the number of visits on evry blog post. + - ``ranking`` : Indicates the ranking on every blog post. diff --git a/addons/website_blog/doc/changelog.rst b/addons/website_blog/doc/changelog.rst index 8b6131b5806..42f2fd7e170 100644 --- a/addons/website_blog/doc/changelog.rst +++ b/addons/website_blog/doc/changelog.rst @@ -7,3 +7,29 @@ Changelog ---------------- - created ``website_blog`` menu, build on defunct document_page module. + - added new feature ``Inline Discussion`` , that will allow a user to comment + on every paragraph on blog post + - added new feature ``Select to Tweet``, that will alllow a user tweet a selected + text from blog to post , directly on twitter. + + + +WebsiteBlog(controller) +======================= +Methods ++++++++ + - ``blog`` : remove routing related to date. + - ``blog_post`` : updated with , suggestion of next post to the user based on + cookie and number of views. + - ``discussion`` : added method , contains a detail of discussion on every paragraph, + if count is true it only return len of ids else return full detail. + def discussion(self, post_id=0, discussion=None, count=False, **post) + - ``post_discussion`` : added methodt, that allow to post discussion on any paragraph. + def post_discussion(self, blog_post_id=0, **post) + - ``change_bg`` : added method allow a user to change background image on blog + post from front-end. + def change_bg(self, post_id=0, image=None, **post) + - ``get_user`` : added method , that will return True if user is public else False. + def get_user(self, **post): + return [False if request.session.uid else True] + diff --git a/addons/website_blog/doc/controller.rst b/addons/website_blog/doc/controller.rst new file mode 100644 index 00000000000..727368aab8c --- /dev/null +++ b/addons/website_blog/doc/controller.rst @@ -0,0 +1,21 @@ +.. _controller: + +WebsiteBlog(controller) +======================= +Methods ++++++++ + - ``blog`` : remove routing related to date. + - ``blog_post`` : updated with , suggestion of next post to the user based on + cookie and number of views. + - ``discussion`` : added method , contains a detail of discussion on every paragraph, + if count is true it only return len of ids else return full detail. + def discussion(self, post_id=0, discussion=None, count=False, **post) + - ``post_discussion`` : added methodt, that allow to post discussion on any paragraph. + def post_discussion(self, blog_post_id=0, **post) + - ``change_bg`` : added method allow a user to change background image on blog + post from front-end. + def change_bg(self, post_id=0, image=None, **post) + - ``get_user`` : added method , that will return True if user is public else False. + def get_user(self, **post): + return [False if request.session.uid else True] + diff --git a/addons/website_blog/models/website_blog.py b/addons/website_blog/models/website_blog.py index e132e4c5e15..7f691f93aa5 100644 --- a/addons/website_blog/models/website_blog.py +++ b/addons/website_blog/models/website_blog.py @@ -19,28 +19,23 @@ # ############################################################################## +import random +import difflib +from datetime import datetime from openerp import tools -from openerp import SUPERUSER_ID from openerp.osv import osv, fields from openerp.tools.translate import _ -import difflib - - class Blog(osv.Model): _name = 'blog.blog' _description = 'Blogs' _inherit = ['mail.thread', 'website.seo.metadata'] _order = 'name' - _columns = { - 'name': fields.char('Name', required=True), + 'name': fields.char('Blog Name', required=True), + 'subtitle': fields.char('Blog Subtitle'), 'description': fields.text('Description'), - 'blog_post_ids': fields.one2many( - 'blog.post', 'blog_id', - 'Blogs', - ), } @@ -49,49 +44,32 @@ class BlogTag(osv.Model): _description = 'Blog Tag' _inherit = ['website.seo.metadata'] _order = 'name' - _columns = { 'name': fields.char('Name', required=True), - 'blog_post_ids': fields.many2many( - 'blog.post', string='Posts', - ), } +class MailMessage(osv.Model): + _inherit = 'mail.message' + _columns = { + 'discussion': fields.char('Discussion Unique Name'), + } class BlogPost(osv.Model): _name = "blog.post" _description = "Blog Post" _inherit = ['mail.thread', 'website.seo.metadata'] - _order = 'write_date DESC' - # maximum number of characters to display in summary - _shorten_max_char = 250 + _order = 'id DESC' - def get_shortened_content(self, cr, uid, ids, name, arg, context=None): + def _compute_ranking(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 + for blog_post in self.browse(cr, uid, ids, context=context): + d = datetime.now() - datetime.strptime(blog_post.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT) + res[blog_post.id] = blog_post.visits * (0.5+random.random()) / max(3, d.days) 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,32 +79,22 @@ 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" ), - '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') + '&', '&', ('model', '=', self._name), ('type', '=', 'comment') , ('discussion', '=', False) ], 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' + 'History', help='Last post modifications', + deprecated= 'Will be removed in v9.' ), # creation / update stuff 'create_date': fields.datetime( @@ -145,9 +113,13 @@ class BlogPost(osv.Model): 'res.users', 'Last Contributor', select=True, readonly=True, ), + 'visits': fields.integer('No of Views', readonly=True), + 'ranking': fields.function(_compute_ranking, string='Ranking', type='float'), } _defaults = { - 'website_published': False + 'website_published': False, + 'visits': 0, + 'ranking': 0 } def create_history(self, cr, uid, ids, vals, context=None): @@ -183,11 +155,6 @@ class BlogPost(osv.Model): }) return super(BlogPost, self).copy(cr, uid, id, default=default, context=context) - def img(self, cr, uid, ids, field='image_small', context=None): - 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" @@ -216,4 +183,3 @@ class BlogPostHistory(osv.Model): 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: diff --git a/addons/website_blog/security/website_blog.xml b/addons/website_blog/security/website_blog.xml index 97efcb82eab..4aab731454b 100644 --- a/addons/website_blog/security/website_blog.xml +++ b/addons/website_blog/security/website_blog.xml @@ -9,5 +9,15 @@ + + + res_partner: portal/public: read access on my commercial partner + + [] + + + + + diff --git a/addons/website_blog/static/lib/contentshare.js b/addons/website_blog/static/lib/contentshare.js new file mode 100644 index 00000000000..9bfda158703 --- /dev/null +++ b/addons/website_blog/static/lib/contentshare.js @@ -0,0 +1,63 @@ +(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+option.author_name.length+7)); + var text = encodeURIComponent('\"'+selected_text+'\" '+'--@'+option.author_name+' '+current_url) + return ''; + }, + getSelection : function(share) { + if(window.getSelection){ + return (share=='string')?String(window.getSelection().getRangeAt(0)).replace(/\s{2,}/g, ' '):window.getSelection().getRangeAt(0); + } + else if(document.selection){ + return (share=='string')?document.selection.createRange().text.replace(/\s{2,}/g, ' '):document.selection.createRange(); + } + }, + popOver : function() { + this.destroy(); + if(this.getSelection('string').length < option.minLength) + return; + var data = this.getContent(); + var range = this.getSelection(); + var newNode = document.createElement("mark"); + range.surroundContents(newNode); + $('mark').addClass(option.className); + $('.'+option.className).popover({trigger:'manual', placement: option.placement, html: true + , content:function(){ + return data; + } + }); + $('.'+option.className).popover('show'); + }, + destroy : function(){ + $('.'+option.className).popover('hide'); + $('mark').contents().unwrap(); + $('mark').remove(); + } + }); + $.fn.share.init(this); + }; + + $.fn.share.defaults = { + shareLink : "http://twitter.com/intent/tweet?text=", + minLength : 5, + maxLength : 140, + target : "blank", + className : "share", + placement : "top", + }; + +}()); diff --git a/addons/website_blog/static/src/css/website_blog.css b/addons/website_blog/static/src/css/website_blog.css index f7355ce783d..9097e3af31f 100644 --- a/addons/website_blog/static/src/css/website_blog.css +++ b/addons/website_blog/static/src/css/website_blog.css @@ -9,6 +9,12 @@ display: block; } +.read_width { + max-width: 700px; + margin-left: auto; + margin-right: auto; +} + .blog_content a.oe_mail_expand:after { content: " →"; } @@ -20,3 +26,127 @@ p.post-meta { position: relative; top: -5px; } + +div#blog_angle_down a:hover { + text-decoration: none; +} + +.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: black; + color: white; + position: relative; +} +.cover .blog_title { + position: absolute; + text-align: center; + top: 20%; + left: 0; + right: 0; +} +.cover .blog_title h1 { + font-weight: bold; +} + +.cover_footer { + min-height: 350px; + height: 65vh; + cursor: pointer; +} + +/*Inline Discussion */ +.discussion { + padding: 5px 10px 10px; + position: absolute; + top: 0; + left: 0; + line-height: 16px; + font-size: 13px; + font-weight: bold; + font-family: sans-serif; + text-align: center; + z-index: 7; +} +.discussion > a { + opacity: 0; + display: block; + overflow: hidden; + width: 20px; + height: 17px; + color: white; + text-decoration: none; + cursor: pointer; + background: #bbbbbb; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + -ms-border-radius: 2px; + -o-border-radius: 2px; + border-radius: 2px; + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + transition: all 0.5s; +} +.discussion > a.has-comments { + opacity: 0.6; +} + +.discussion-contain:hover .discussion > a { + opacity: 1; +} + +.discussion > a:after { + border-right: 7px solid transparent; + border-top: 7px solid #bbbbbb; + right: 19px; + top: 22px; + height: 0; + width: 0; + display: block; + content: " "; + position: absolute; + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + transition: all 0.5s; +} +.discussion:hover > a, .discussion.hovered > a { + opacity: 1; + background: #57ad68; +} +.discussion:hover > a:after, .discussion.hovered > a:after { + border-top-color: #57ad68; +} + +#discussions_wrapper { + position: absolute; + top: 0; + left: 0; +} + +#discussions_overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 8; + display: none; +} + +.discussion .popover-content { + max-height: 250px; + width: 250px; + overflow: auto; + font-weight: normal; +} + +mark + .popover { + cursor: pointer; +} diff --git a/addons/website_blog/static/src/css/website_blog.sass b/addons/website_blog/static/src/css/website_blog.sass index 4691dde83c2..6342c6b99a2 100644 --- a/addons/website_blog/static/src/css/website_blog.sass +++ b/addons/website_blog/static/src/css/website_blog.sass @@ -1,5 +1,4 @@ @charset "utf-8" - @import "compass/css3" .css_website_mail @@ -10,6 +9,11 @@ &:first-of-type display: block +.read_width + max-width: 700px + margin-left: auto + margin-right: auto + .blog_content a.oe_mail_expand:after content: " →" @@ -20,3 +24,113 @@ p.post-meta position: relative top: -5px +div#blog_angle_down + a:hover + text-decoration: none + +.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: #000 + color: #fff + position: relative + .blog_title + position: absolute + text-align: center + top: 20% + left: 0 + right: 0 + h1 + font-weight: bold + +.cover_footer + min-height : 350px + height: 65vh + cursor: pointer + +/*Inline Discussion + +.discussion + padding: 5px 10px 10px + position: absolute + top: 0 + left: 0 + line-height: 16px + font-size: 13px + font-weight: bold + font-family: sans-serif + text-align: center + z-index: 7 + > a + opacity: 0 + display: block + overflow: hidden + width: 20px + height: 17px + color: white + text-decoration: none + cursor: pointer + background: #bbbbbb + -webkit-border-radius: 2px + -moz-border-radius: 2px + -ms-border-radius: 2px + -o-border-radius: 2px + border-radius: 2px + -webkit-transition: all 0.5s + -moz-transition: all 0.5s + -o-transition: all 0.5s + transition: all 0.5s + &.has-comments + opacity: .6 + +.discussion-contain:hover .discussion > a + opacity: 1 + +.discussion + > a:after + border-right: 7px solid transparent + border-top: 7px solid #bbbbbb + right: 19px + top: 22px + height: 0 + width: 0 + display: block + content: " " + position: absolute + -webkit-transition: all 0.5s + -moz-transition: all 0.5s + -o-transition: all 0.5s + transition: all 0.5s + &:hover > a, &.hovered > a + opacity: 1 + background: #57AD68 + &:hover > a:after, &.hovered > a:after + border-top-color: #57AD68 + +#discussions_wrapper + position: absolute + top: 0 + left: 0 + +#discussions_overlay + position: fixed + top: 0 + left: 0 + right: 0 + bottom: 0 + background: rgba(0, 0, 0, 0.5) + z-index: 8 + display: none + +.discussion .popover-content + max-height: 250px + width: 250px + overflow: auto + font-weight: normal + +mark + .popover + cursor: pointer diff --git a/addons/website_blog/static/src/img/CMS_WMS_screens.jpg b/addons/website_blog/static/src/img/CMS_WMS_screens.jpg new file mode 100644 index 00000000000..08fc4aafc41 Binary files /dev/null and b/addons/website_blog/static/src/img/CMS_WMS_screens.jpg differ diff --git a/addons/website_blog/static/src/img/OpemERP_board.jpg b/addons/website_blog/static/src/img/OpemERP_board.jpg new file mode 100644 index 00000000000..05a854f15eb Binary files /dev/null and b/addons/website_blog/static/src/img/OpemERP_board.jpg differ diff --git a/addons/website_blog/static/src/img/anonymous.png b/addons/website_blog/static/src/img/anonymous.png new file mode 100644 index 00000000000..6461bf735f1 Binary files /dev/null and b/addons/website_blog/static/src/img/anonymous.png differ diff --git a/addons/website_blog/static/src/img/mail-sc-00.png b/addons/website_blog/static/src/img/mail-sc-00.png new file mode 100644 index 00000000000..dbb14b4da36 Binary files /dev/null and b/addons/website_blog/static/src/img/mail-sc-00.png differ diff --git a/addons/website_blog/static/src/img/mail-sc-03.png b/addons/website_blog/static/src/img/mail-sc-03.png new file mode 100644 index 00000000000..3011ef129b5 Binary files /dev/null and b/addons/website_blog/static/src/img/mail-sc-03.png differ diff --git a/addons/website_blog/static/src/img/post1.jpg b/addons/website_blog/static/src/img/post1.jpg new file mode 100644 index 00000000000..f3e3aa852a6 Binary files /dev/null and b/addons/website_blog/static/src/img/post1.jpg differ diff --git a/addons/website_blog/static/src/img/post2.jpg b/addons/website_blog/static/src/img/post2.jpg new file mode 100644 index 00000000000..8f6002a40db Binary files /dev/null and b/addons/website_blog/static/src/img/post2.jpg differ diff --git a/addons/website_blog/static/src/img/post3.jpg b/addons/website_blog/static/src/img/post3.jpg new file mode 100644 index 00000000000..0123f640dab Binary files /dev/null and b/addons/website_blog/static/src/img/post3.jpg differ diff --git a/addons/website_blog/static/src/img/turnover_updated.png b/addons/website_blog/static/src/img/turnover_updated.png new file mode 100644 index 00000000000..8edbb5a61b5 Binary files /dev/null and b/addons/website_blog/static/src/img/turnover_updated.png differ diff --git a/addons/website_blog/static/src/js/website_blog.editor.js b/addons/website_blog/static/src/js/website_blog.editor.js index 1c5deef56f7..81a40117dbb 100644 --- a/addons/website_blog/static/src/js/website_blog.editor.js +++ b/addons/website_blog/static/src/js/website_blog.editor.js @@ -27,7 +27,38 @@ }).then(function (cat_id) { document.location = '/blogpost/new?blog_id=' + cat_id; }); - } + }, }), + edit: function () { + $('.popover').remove(); + this._super(); + var vHeight = $(window).height(); + $('body').on('click','#change_cover',_.bind(this.change_bg,{},vHeight)); + $('body').on('click', '#clear_cover',_.bind(this.clean_bg,{},vHeight)); + }, + save : function() { + var res = this._super(); + if ($('.cover').length){ + openerp.jsonRpc("/blogpsot/change_background", 'call', { + 'post_id' : $('#blog_post_name').attr('data-oe-id'), + 'image' : $('.cover').css('background-image').replace(/url\(|\)|"|'/g,''), + }); + } + return res; + }, + clean_bg : function(vHeight) { + $('.js_fullheight').css({"background-image":'none', 'min-height': vHeight}); + }, + change_bg : function(vHeight) { + var self = this; + var editor = new website.editor.ImageDialog(); + editor.on('start', self, function (o) { + o.url = $('.js_fullheight').length ? $('.js_fullheight').css('background-image').replace(/url\(|\)|"|'/g,'') : ''; + }); + editor.on('save', self, function (o) { + $('.js_fullheight').css({"background-image": o.url && o.url !== "" ? 'url(' + o.url + ')' : "", 'min-height': vHeight}) + }); + editor.appendTo('body'); + }, }); })(); diff --git a/addons/website_blog/static/src/js/website_blog.inline.discussion.js b/addons/website_blog/static/src/js/website_blog.inline.discussion.js new file mode 100644 index 00000000000..574a29806e9 --- /dev/null +++ b/addons/website_blog/static/src/js/website_blog.inline.discussion.js @@ -0,0 +1,207 @@ +// Inspired from https://github.com/tsi/inlineDisqussions +(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-blog-id'), + content : false, + public_user: false, + }; + self.settings = $.extend({}, defaults, options); + self.do_render(self); + }, + do_render: function(data) { + var self = this; + if ($('#discussions_wrapper').length === 0 && self.settings.content.length > 0) { + $('
').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(); + } + if(!$(event.target).hasClass('discussion-link') && !$(event.target).parents('.popover').length){ + if($('.move_discuss').length){ + $('.js_discuss').next().removeClass('move_discuss'); + $('.js_discuss').next().animate({ + 'marginLeft': "+=40%" + }); + $('#discussions_wrapper').animate({ + 'marginLeft': "+=250px" + }); + } + } + }); + }, + prepare_data : function(identifier,comment_count) { + var self = this; + return openerp.jsonRpc("/blogpost/get_discussion/", 'call', { + 'post_id': self.settings.post_id, + 'discussion':identifier, + 'count' : comment_count, //if true only get length of total comment, display on discussion thread. + }) + }, + 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,true).then(function(data){ + self.prepare_discuss_link(data,identifier,node) + }); + }, + prepare_discuss_link : function(data, identifier, node) { + var self = this; + var cls = data > 0 ? 'discussion-link has-comments' : 'discussion-link'; + var a = $('') + .attr('data-discus-identifier', identifier) + .attr('data-discus-position', self.settings.position) + .text(data > 0 ? data : '+') + .attr('data-contentwrapper','.mycontent') + .wrap('
') + .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(!$('.move_discuss').length){ + $('.js_discuss').next().addClass('move_discuss'); + $('.js_discuss').next().animate({ + 'marginLeft': "-=40%" + }); + $('#discussions_wrapper').animate({ + 'marginLeft': "-=250px" + }); + } + 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,false).then(function(data){ + _.each(data, function(res){ + comment += qweb.render("website.blog_discussion.comment", {'res': res}); + }); + $('.discussion_history').html('
    '+comment+'
'); + 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); + }); + }, + validate : function(public_user){ + var comment = $(".popover textarea#inline_comment").val(); + if (public_user){ + var author_name = $('.popover input#author_name').val(); + var author_email = $('.popover input#author_email').val(); + if(!comment || !author_name || !author_email){ + if (!author_name) + $('div#author_name').addClass('has-error'); + else + $('div#author_name').removeClass('has-error'); + if (!author_email) + $('div#author_email').addClass('has-error'); + else + $('div#author_email').removeClass('has-error'); + if(!comment) + $('div#inline_comment').addClass('has-error'); + else + $('div#inline_comment').removeClass('has-error'); + return false + } + } + else if(!comment) { + $('div#inline_comment').addClass('has-error'); + return false + } + $("div#inline_comment").removeClass('has-error'); + $('div#author_name').removeClass('has-error'); + $('div#author_email').removeClass('has-error'); + $(".popover textarea#inline_comment").val(''); + $('.popover input#author_name').val(''); + $('.popover input#author_email').val(''); + return [comment, author_name, author_email] + }, + post_discussion : function(identifier) { + var self = this; + var val = self.validate(self.settings.public_user) + if(!val) return + openerp.jsonRpc("/blogpost/post_discussion", 'call', { + 'blog_post_id': self.settings.post_id, + 'discussion': self.discus_identifier, + 'comment': val[0], + 'name' : val[1], + 'email': val[2], + }).then(function(res){ + $(".popover ul.media-list").prepend(qweb.render("website.blog_discussion.comment", {'res': res[0]})) + var ele = $('a[data-discus-identifier="'+ self.discus_identifier +'"]'); + ele.text(_.isNaN(parseInt(ele.text())) ? 1 : parseInt(ele.text())+1) + ele.addClass('has-comments'); + }); + }, + hide_discussion : function() { + var self = this; + $('a[data-discus-identifier="'+ self.discus_identifier+'"]').popover('destroy'); + $('a.discussion-link').removeClass('active'); + } + + }); + +})(); diff --git a/addons/website_blog/static/src/js/website_blog.js b/addons/website_blog/static/src/js/website_blog.js new file mode 100644 index 00000000000..6e8dbb25661 --- /dev/null +++ b/addons/website_blog/static/src/js/website_blog.js @@ -0,0 +1,40 @@ +$(document).ready(function() { + + function page_transist(event) { + event.preventDefault(); + newLocation = $('.js_next')[0].href; + var top = $('.cover_footer').offset().top; + $('.cover_footer').animate({ + height: $(window).height()+'px' + }, 300); + $('html, body').animate({ + scrollTop: top + }, 300, 'swing', function() { + window.location.href = newLocation; + }); + } + function animate(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + var target = $(this.hash); + $('html, body').stop().animate({ + 'scrollTop': target.offset().top - 32 + }, 500, 'swing', function () { + window.location.hash = 'blog_content'; + }); + } + + var content = $(".js_discuss").next().find('p'); + if(content){ + openerp.jsonRpc("/blog/get_user/", 'call', {}).then(function(data){ + $('#discussions_wrapper').empty(); + new openerp.website.blog_discussion({'content' : content, 'public_user':data[0]}); + }); + } + + $('.js_fullheight').css('min-height', $(window).height()); + $(".js_tweet").share({'author_name':$('#blog_author').text()}); + $('.cover_footer').on('click',page_transist); + $('a[href^="#blog_content"]').on('click', animate); + +}); diff --git a/addons/website_blog/static/src/xml/website_blog.inline.discussion.xml b/addons/website_blog/static/src/xml/website_blog.inline.discussion.xml new file mode 100644 index 00000000000..8c1cda26265 --- /dev/null +++ b/addons/website_blog/static/src/xml/website_blog.inline.discussion.xml @@ -0,0 +1,38 @@ + + + +
  • +
    + +
    +
    + + +
    +
    +
    + + by + + +
    +
  • +
    + +