[MERGE] trunk-website-al

bzr revid: ddm@openerp.com-20131011141759-uqo52ta0haqyn3z6
This commit is contained in:
ddm
2013-10-11 16:17:59 +02:00
43 changed files with 3034 additions and 322 deletions
+23
View File
@@ -0,0 +1,23 @@
# Spanish (Argentina) translation for openobject-addons
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
"PO-Revision-Date: 2013-10-07 21:16+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Spanish (Argentina) <es_AR@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-10-08 05:42+0000\n"
"X-Generator: Launchpad (build 16799)\n"
#. module: account_accountant
#: model:ir.actions.client,name:account_accountant.action_client_account_menu
msgid "Open Accounting Menu"
msgstr ""
+23
View File
@@ -0,0 +1,23 @@
# Estonian translation for openobject-addons
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2013-10-09 14:39+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Estonian <et@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
#. module: account_cancel
#: view:account.invoice:0
msgid "Cancel"
msgstr ""
+15 -17
View File
@@ -1,30 +1,28 @@
# Estonian translation for openobject-addons
# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-03 16:03+0000\n"
"PO-Revision-Date: 2011-10-10 19:33+0000\n"
"Last-Translator: Aare Vesi <Unknown>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2013-10-09 14:40+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Estonian <et@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-12-04 05:53+0000\n"
"X-Generator: Launchpad (build 16335)\n"
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
#. module: base_crypt
#: model:ir.model,name:base_crypt.model_res_users
#. module: auth_crypt
#: field:res.users,password_crypt:0
msgid "Encrypted Password"
msgstr "Krüpteeritud Parool"
#. module: auth_crypt
#: model:ir.model,name:auth_crypt.model_res_users
msgid "Users"
msgstr ""
#, python-format
#~ msgid "Error"
#~ msgstr "Viga"
#~ msgid "res.users"
#~ msgstr "res.users"
msgstr "Kasutajad"
+23
View File
@@ -0,0 +1,23 @@
# Estonian translation for openobject-addons
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2013-10-09 14:34+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Estonian <et@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
#. module: auth_oauth_signup
#: model:ir.model,name:auth_oauth_signup.model_res_users
msgid "Users"
msgstr "Kasutajad"
+185
View File
@@ -0,0 +1,185 @@
# Hindi translation for openobject-addons
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2013-10-09 05:55+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Hindi <hi@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
#. module: base_report_designer
#: model:ir.model,name:base_report_designer.model_base_report_sxw
msgid "base.report.sxw"
msgstr "base.report.sxw"
#. module: base_report_designer
#: view:base_report_designer.installer:0
msgid "OpenERP Report Designer Configuration"
msgstr ""
#. module: base_report_designer
#: view:base_report_designer.installer:0
msgid ""
"This plug-in allows you to create/modify OpenERP Reports into OpenOffice "
"Writer."
msgstr ""
#. module: base_report_designer
#: view:base.report.sxw:0
msgid "Upload the modified report"
msgstr ""
#. module: base_report_designer
#: view:base.report.file.sxw:0
msgid "The .SXW report"
msgstr ""
#. module: base_report_designer
#: model:ir.model,name:base_report_designer.model_base_report_designer_installer
msgid "base_report_designer.installer"
msgstr ""
#. module: base_report_designer
#: model:ir.model,name:base_report_designer.model_base_report_rml_save
msgid "base.report.rml.save"
msgstr ""
#. module: base_report_designer
#: view:base_report_designer.installer:0
msgid "Configure"
msgstr ""
#. module: base_report_designer
#: view:base_report_designer.installer:0
msgid "title"
msgstr ""
#. module: base_report_designer
#: field:base.report.file.sxw,report_id:0
#: field:base.report.sxw,report_id:0
msgid "Report"
msgstr ""
#. module: base_report_designer
#: view:base.report.rml.save:0
msgid "The RML Report"
msgstr ""
#. module: base_report_designer
#: model:ir.ui.menu,name:base_report_designer.menu_action_report_designer_wizard
msgid "Report Designer"
msgstr ""
#. module: base_report_designer
#: field:base_report_designer.installer,name:0
msgid "File name"
msgstr ""
#. module: base_report_designer
#: view:base.report.file.sxw:0
#: view:base.report.sxw:0
msgid "Get a report"
msgstr ""
#. module: base_report_designer
#: view:base_report_designer.installer:0
#: model:ir.actions.act_window,name:base_report_designer.action_report_designer_wizard
msgid "OpenERP Report Designer"
msgstr ""
#. module: base_report_designer
#: view:base.report.sxw:0
msgid "Continue"
msgstr ""
#. module: base_report_designer
#: field:base.report.rml.save,file_rml:0
msgid "Save As"
msgstr ""
#. module: base_report_designer
#: help:base_report_designer.installer,plugin_file:0
msgid ""
"OpenObject Report Designer plug-in file. Save as this file and install this "
"plug-in in OpenOffice."
msgstr ""
#. module: base_report_designer
#: view:base.report.rml.save:0
msgid "Save RML FIle"
msgstr ""
#. module: base_report_designer
#: field:base.report.file.sxw,file_sxw:0
#: field:base.report.file.sxw,file_sxw_upload:0
msgid "Your .SXW file"
msgstr ""
#. module: base_report_designer
#: view:base_report_designer.installer:0
msgid "Installation and Configuration Steps"
msgstr ""
#. module: base_report_designer
#: field:base_report_designer.installer,description:0
msgid "Description"
msgstr ""
#. module: base_report_designer
#: view:base.report.file.sxw:0
msgid ""
"This is the template of your requested report.\n"
"Save it as a .SXW file and open it with OpenOffice.\n"
"Don't forget to install the OpenERP SA OpenOffice package to modify it.\n"
"Once it is modified, re-upload it in OpenERP using this wizard."
msgstr ""
#. module: base_report_designer
#: model:ir.actions.act_window,name:base_report_designer.action_view_base_report_sxw
msgid "Base Report sxw"
msgstr ""
#. module: base_report_designer
#: model:ir.model,name:base_report_designer.model_base_report_file_sxw
msgid "base.report.file.sxw"
msgstr ""
#. module: base_report_designer
#: field:base_report_designer.installer,plugin_file:0
msgid "OpenObject Report Designer Plug-in"
msgstr ""
#. module: base_report_designer
#: model:ir.actions.act_window,name:base_report_designer.action_report_designer_installer
msgid "OpenERP Report Designer Installation"
msgstr ""
#. module: base_report_designer
#: view:base.report.sxw:0
msgid "Cancel"
msgstr ""
#. module: base_report_designer
#: view:base.report.sxw:0
msgid "or"
msgstr ""
#. module: base_report_designer
#: model:ir.model,name:base_report_designer.model_ir_actions_report_xml
msgid "ir.actions.report.xml"
msgstr ""
#. module: base_report_designer
#: view:base.report.sxw:0
msgid "Select your report"
msgstr ""
+33
View File
@@ -0,0 +1,33 @@
# Estonian translation for openobject-addons
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2013-10-09 14:42+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Estonian <et@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
#. module: claim_from_delivery
#: view:stock.picking.out:0
msgid "Claims"
msgstr "Nõuded"
#. module: claim_from_delivery
#: model:res.request.link,name:claim_from_delivery.request_link_claim_from_delivery
msgid "Delivery Order"
msgstr "Tarnetellimus"
#. module: claim_from_delivery
#: model:ir.actions.act_window,name:claim_from_delivery.action_claim_from_delivery
msgid "Claim From Delivery"
msgstr ""
+85
View File
@@ -0,0 +1,85 @@
# Estonian translation for openobject-addons
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2013-10-09 15:39+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Estonian <et@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
#. module: crm_todo
#: model:ir.model,name:crm_todo.model_project_task
msgid "Task"
msgstr "Ülesanne"
#. module: crm_todo
#: view:crm.lead:0
msgid "Timebox"
msgstr "Ajalahter"
#. module: crm_todo
#: view:crm.lead:0
msgid "Lead"
msgstr ""
#. module: crm_todo
#: view:crm.lead:0
msgid "For cancelling the task"
msgstr "Ülesande katkestamiseks"
#. module: crm_todo
#: view:crm.lead:0
msgid "Next"
msgstr "Järgmine"
#. module: crm_todo
#: model:ir.actions.act_window,name:crm_todo.crm_todo_action
#: model:ir.ui.menu,name:crm_todo.menu_crm_todo
msgid "My Tasks"
msgstr "Minu ülesanded"
#. module: crm_todo
#: view:crm.lead:0
#: field:crm.lead,task_ids:0
msgid "Tasks"
msgstr "Ülesanded"
#. module: crm_todo
#: view:crm.lead:0
msgid "Done"
msgstr "Valmis"
#. module: crm_todo
#: view:crm.lead:0
msgid "Cancel"
msgstr "Katkesta"
#. module: crm_todo
#: model:ir.model,name:crm_todo.model_crm_lead
msgid "Lead/Opportunity"
msgstr ""
#. module: crm_todo
#: field:project.task,lead_id:0
msgid "Lead / Opportunity"
msgstr ""
#. module: crm_todo
#: view:crm.lead:0
msgid "For changing to done state"
msgstr ""
#. module: crm_todo
#: view:crm.lead:0
msgid "Previous"
msgstr "Eelmine"
@@ -133,7 +133,7 @@ class hr_si_project(osv.osv_memory):
def check_state(self, cr, uid, ids, context=None):
obj_model = self.pool.get('ir.model.data')
emp_id = self.default_get(cr, uid, context)['emp_id']
emp_id = self.default_get(cr, uid, ['emp_id'], context)['emp_id']
# get the latest action (sign_in or out) for this employee
cr.execute('select action from hr_attendance where employee_id=%s and action in (\'sign_in\',\'sign_out\') order by name desc limit 1', (emp_id,))
res = (cr.fetchone() or ('sign_out',))[0]
@@ -143,7 +143,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
var self = this;
this._super();
this.$el.click(function(){
self.order.selectLine(this.model);
self.order.selectLine(self.model);
self.trigger('order_line_selected');
});
if(this.model.is_selected()){
+1 -2
View File
@@ -93,8 +93,7 @@
</div>
</div>
<div class="oe_right oe_button_box" name="buttons" groups="base.group_user">
<button name="%(act_project_project_2_project_task_all)d" string="Tasks"
type="action" attrs="{'invisible':[('use_tasks','=', 0)]}"/>
<field name="tasks" widget="x2many_counter" string="Tasks" attrs="{'invisible':[('use_tasks','=', False)]}" options='{"views": [[false, "kanban"], [false, "tree"], [false, "form"], [false, "calendar"], [false, "gantt"], [false, "graph"]]}'/>
<button name="attachment_tree_view" string="Documents" type="object"/>
</div>
<group>
File diff suppressed because it is too large Load Diff
+28 -12
View File
@@ -7,6 +7,7 @@ import json
import logging
import os
import datetime
import re
from sys import maxint
@@ -17,7 +18,16 @@ import werkzeug.utils
import werkzeug.wrappers
from PIL import Image
try:
from slugify import slugify
except ImportError:
def slugify(s, max_length=None):
spaceless = re.sub(r'\s+', '-', s)
specialless = re.sub(r'[^-_a-z0-9]', '', spaceless)
return specialless[:max_length]
import openerp
from openerp.osv import fields
from openerp.addons.website.models import website
from openerp.addons.web import http
from openerp.addons.web.http import request
@@ -50,12 +60,9 @@ class Website(openerp.addons.web.controllers.main.Home):
# FIXME: auth, if /pagenew known anybody can create new empty page
@website.route('/pagenew/<path:path>', type='http', auth="admin")
def pagenew(self, path, noredirect=NOPE):
if '.' in path:
module, idname = path.split('.', 1)
else:
module = 'website'
idname = path
xid = "%s.%s" % (module, idname)
module = 'website'
# completely arbitrary max_length
idname = slugify(path, max_length=50)
request.cr.execute('SAVEPOINT pagenew')
imd = request.registry['ir.model.data']
@@ -67,8 +74,9 @@ class Website(openerp.addons.web.controllers.main.Home):
newview = view.browse(
request.cr, request.uid, newview_id, context=request.context)
newview.write({
'arch': newview.arch.replace("website.default_page", xid),
'name': "page/%s" % path,
'arch': newview.arch.replace("website.default_page",
"%s.%s" % (module, idname)),
'name': path,
'page': True,
})
# Fuck it, we're doing it live
@@ -81,10 +89,13 @@ class Website(openerp.addons.web.controllers.main.Home):
'noupdate': True
}, context=request.context)
except psycopg2.IntegrityError:
logger.exception('Unable to create ir_model_data for page %s', path)
request.cr.execute('ROLLBACK TO SAVEPOINT pagenew')
return werkzeug.exceptions.InternalServerError()
else:
request.cr.execute('RELEASE SAVEPOINT pagenew')
url = "/page/%s" % path
url = "/page/%s" % idname
if noredirect is not NOPE:
return werkzeug.wrappers.Response(url, mimetype='text/plain')
return werkzeug.utils.redirect(url)
@@ -242,11 +253,16 @@ class Website(openerp.addons.web.controllers.main.Home):
def publish(self, id, object):
_id = int(id)
_object = request.registry[object]
obj = _object.browse(request.cr, request.uid, _id)
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],
{'website_published': not obj.website_published},
context=request.context)
values, context=request.context)
obj = _object.browse(request.cr, request.uid, _id)
return obj.website_published and True or False
+1
View File
@@ -3,3 +3,4 @@
import ir_fields
import view
import website
import ir_rule
+25
View File
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
from openerp.osv import osv
from openerp.addons.web.http import request
from openerp.tools.misc import unquote as unquote
class ir_rule(osv.osv):
_inherit = 'ir.rule'
def _eval_context_for_combinations(self):
"""Returns a dictionary to use as evaluation context for
ir.rule domains, when the goal is to obtain python lists
that are easier to parse and combine, but not to
actually execute them."""
res = super(ir_rule, self)._eval_context_for_combinations()
res.update(session=unquote('session'))
return res
def _eval_context(self, cr, uid):
"""Returns a dictionary to use as evaluation context for
ir.rule domains."""
res = super(ir_rule, self)._eval_context(cr, uid)
res.update(session=request and request.httprequest and request.httprequest.session)
return res
+33 -6
View File
@@ -66,10 +66,12 @@ def url_for(path, lang=None):
def urlplus(url, params):
if not params:
return url
url += "?"
for k,v in params.items():
url += "%s=%s&" % (k, urllib.quote_plus(str(v)))
return url
# can't use urlencode because it encodes to (ascii, replace) in p2
return "%s?%s" % (url, '&'.join(
k + '=' + urllib.quote_plus(v.encode('utf-8') if isinstance(v, unicode) else str(v))
for k, v in params.iteritems()
))
class website(osv.osv):
_name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco
@@ -118,6 +120,7 @@ class website(osv.osv):
is_master_lang = lang == request.website.default_lang_id.code
request.context.update({
'lang': lang,
'lang_selected': [lg for lg in request.website.language_ids if lg.code == lang],
'langs': [lg.code for lg in request.website.language_ids],
'multilang': request.multilang,
'is_public_user': is_public_user,
@@ -141,8 +144,7 @@ class website(osv.osv):
qweb_context.update(values)
qweb_context.update(
request=request,
registry=request.registry,
_request=request, # begin with underscore to mark this attribute as unsafe
json=simplejson,
website=request.website,
url_for=url_for,
@@ -346,3 +348,28 @@ class res_partner(osv.osv):
'q': '%s, %s %s, %s' % (partner.street, partner.city, partner.zip, partner.country_id and partner.country_id.name_get()[0][1] or ''),
}
return urlplus('https://maps.google.be/maps' , params)
class base_language_install(osv.osv):
_inherit = "base.language.install"
_columns = {
'website_ids': fields.many2many('website', string='Websites to translate'),
}
def lang_install(self, cr, uid, ids, context=None):
if context is None:
context = {}
action = super(base_language_install, self).lang_install(cr, uid, ids, context)
language_obj = self.browse(cr, uid, ids)[0]
website_ids = [website.id for website in language_obj['website_ids']]
lang_id = self.pool['res.lang'].search(cr, uid, [('code', '=', language_obj['lang'])])
if website_ids and lang_id:
data = {'language_ids': [(4, lang_id[0])]}
self.pool['website'].write(cr, uid, website_ids, data)
params = context.get('params', {})
if 'url_return' in params:
return {
'url': params['url_return'].replace('[lang]', language_obj['lang']),
'type': 'ir.actions.act_url',
'target': 'self'
}
return action
+63 -34
View File
@@ -1,4 +1,3 @@
@charset "utf-8";
/* ---- CKEditor Minimal Reset ---- */
.navbar.navbar-inverse .cke_chrome {
border: none;
@@ -178,17 +177,23 @@ table.editorbar-panel td.selected {
}
#oe_snippets .scroll {
white-space: nowrap;
overflow-y: auto;
overflow-y: none;
}
#oe_snippets .nav {
position: fixed;
display: inline-block;
border-bottom: none !important;
vertical-align: middle;
margin-top: 5px;
min-width: 120px;
margin-left: 6px;
z-index: 1;
border: 0;
}
#oe_snippets .nav > li {
display: inline-block;
display: block;
float: none;
font-size: 13px;
}
#oe_snippets .nav > li.active {
background: black !important;
}
#oe_snippets .nav > li > a {
padding: 2px 10px !important;
@@ -196,10 +201,14 @@ table.editorbar-panel td.selected {
display: block;
border: 0;
}
#oe_snippets .pill-content {
border: 0;
}
#oe_snippets .tab-content {
margin-top: 24px;
display: inline-block;
white-space: nowrap;
background: black;
margin-top: 5px;
}
#oe_snippets .tab-content > div {
background: black;
@@ -207,7 +216,6 @@ table.editorbar-panel td.selected {
}
#oe_snippets .tab-content > div label {
width: 44px;
height: 100%;
color: white;
padding-left: 10px;
}
@@ -227,10 +235,9 @@ table.editorbar-panel td.selected {
}
.oe_snippet {
display: inline-block;
float: left;
vertical-align: top;
width: 100px;
height: 100px;
margin: 1px;
margin-top: 0px;
position: relative;
@@ -249,14 +256,31 @@ table.editorbar-panel td.selected {
color: white;
position: relative;
}
.oe_snippet .oe_snippet_thumbnail:hover .oe_snippet_thumbnail_img {
-webkit-transform: scale(0.95, 0.95);
-moz-transform: scale(0.95, 0.95);
-ms-transform: scale(0.95, 0.95);
-o-transform: scale(0.95, 0.95);
transform: scale(0.95, 0.95);
}
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_title {
font-size: 12px;
display: block;
text-shadow: 0 0 2px black;
}
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_img {
-webkit-transition: all 150ms linear;
-moz-transition: all 150ms linear;
-o-transition: all 150ms linear;
transition: all 150ms linear;
-webkit-box-shadow: inset 0px 0px 0px 3px #333333;
-moz-box-shadow: inset 0px 0px 0px 3px #333333;
box-shadow: inset 0px 0px 0px 3px #333333;
-webkit-transform: scale(1, 1);
-moz-transform: scale(1, 1);
-ms-transform: scale(1, 1);
-o-transform: scale(1, 1);
transform: scale(1, 1);
}
.oe_snippet .oe_snippet_thumbnail span, .oe_snippet .oe_snippet_thumbnail div {
line-height: 18px;
@@ -305,20 +329,21 @@ table.editorbar-panel td.selected {
margin: 0px -24px !important;
}
.oe_drop_zone.oe_insert.oe_overlay {
background: rgba(153, 0, 255, 0.17);
border-radius: 3px;
background: rgba(153, 0, 255, 0.5);
}
.oe_drop_zone, .oe_drop_zone_style {
background: rgba(153, 0, 255, 0.17);
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
border: none;
background: rgba(153, 0, 255, 0.3);
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
-ms-border-radius: 4px;
-o-border-radius: 4px;
border-radius: 4px;
}
.oe_drop_zone.oe_hover, .oe_drop_zone_style.oe_hover {
background: rgba(0, 255, 133, 0.22);
background: rgba(0, 255, 133, 0.3);
z-index: 1001;
}
@@ -355,7 +380,7 @@ table.editorbar-panel td.selected {
-webkit-box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
-moz-box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
border-color: rgba(153, 0, 255, 0.5);
border-color: rgba(0, 0, 0, 0.5);
}
.oe_overlay.oe_active .oe_handle {
display: block !important;
@@ -367,39 +392,43 @@ table.editorbar-panel td.selected {
left: 50%;
display: block;
background: white;
border: solid 1px #9900ff;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
-ms-border-radius: 8px;
-o-border-radius: 8px;
border-radius: 8px;
width: 16px;
height: 16px;
margin: -8px;
border: solid 1px rgba(0, 0, 0, 0.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
width: 18px;
height: 18px;
margin: -9px;
padding-left: 1px;
font-size: 14px;
line-height: 14px;
color: #9900ff;
font-family: FontAwesome;
color: rgba(0, 0, 0, 0.5);
-webkit-transition: background 100ms linear;
-moz-transition: background 100ms linear;
-o-transition: background 100ms linear;
transition: background 100ms linear;
}
.oe_overlay.oe_active .oe_handle:hover:before {
background: #9900ff;
background: rgba(0, 0, 0, 0.5);
color: white;
-webkit-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
-moz-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
}
.oe_overlay.oe_active .oe_handle.e:before {
content: "⇨";
content: "\F061";
}
.oe_overlay.oe_active .oe_handle.s:before {
content: "⇩";
content: "\F063";
}
.oe_overlay.oe_active .oe_handle.w:before {
content: "⇦";
content: "\F060";
}
.oe_overlay.oe_active .oe_handle.n:before {
content: "⇧";
content: "\F062";
}
.oe_overlay .icon.btn {
display: inline-block;
+59 -31
View File
@@ -4,6 +4,17 @@
@import "compass/css3/user-interface"
@import "compass/css3/transition"
//smartphones, iPhone, portrait 480x320 phones
$smart_phone: 320px
//portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide.*/
$small-tablet: 481px
//portrait tablets, portrait iPad, landscape e-readers, landscape 800x480 or 854x480 phones
$portrait-tablet: 641px
//tablet, landscape iPad, lo-res laptops ands desktops
$tablet: 961px
//big landscape tablets, laptops, and desktops
$desktop: 1025px
/* ---- CKEditor Minimal Reset ---- */
.navbar.navbar-inverse .cke_chrome
@@ -146,32 +157,40 @@ table.editorbar-panel
height: auto
.scroll
white-space: nowrap
overflow-y: auto
overflow-y: none
.nav
display: inline-block
border-bottom: none !important
vertical-align: middle
margin-top: 5px
min-width: 120px
margin-left: 6px
> li
display: inline-block
display: block
float: none
font-size: 13px
&.active
background: black !important
> a
padding: 2px 10px !important
width: 100%
width: 100%
display: block
border: 0
position: fixed
z-index: 1
.pill-content
border: 0
.tab-content
margin-top: 24px
display: inline-block
white-space: nowrap
> div
background: black
margin-top: 5px
> div
background: rgb(0,0,0)
padding: 5px
label
width: 44px
height: 100%
color: #fff
padding-left: 10px
div
width: 100px
text-align: center
@@ -179,10 +198,9 @@ table.editorbar-panel
@include transform-origin(50% 50%)
.oe_snippet
display: inline-block
float: left
vertical-align: top
width: 100px
height: 100px
margin: 1px
margin-top: 0px
position: relative
@@ -197,11 +215,17 @@ table.editorbar-panel
background: transparent
color: white
position: relative
&:hover
.oe_snippet_thumbnail_img
@include transform( scale(.95,.95))
.oe_snippet_thumbnail_title
font-size: 12px
display: block
+text-shadow(0 0 2px rgb(0,0,0))
.oe_snippet_thumbnail_img
@include transition(all 150ms linear)
+box-shadow(inset 0px 0px 0px 3px #333333)
@include transform( scale(1,1))
span, div
line-height: 18px
& > :not(.oe_snippet_thumbnail)
@@ -236,14 +260,19 @@ table.editorbar-panel
position: relative
margin: 0px -24px !important
&.oe_overlay
background: rgba(153, 0, 255, 0.17)
border-radius: 3px
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.1) ,rgba(255,255,255,.1) 35px, rgba(0,0,0,.1) 35px, rgba(0,0,0,.1) 75px))
//background-size: 100px 100px
background: rgba(153, 0, 255,.5)
.oe_drop_zone, .oe_drop_zone_style
background: rgba(153, 0, 255, 0.17)
+border-radius(3px)
border: none
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.1) ,rgba(255,255,255,.1) 35px, rgba(0,0,0,.1) 35px, rgba(0,0,0,.1) 75px))
//background-size: 100px 100px
background: rgba(153, 0, 255, .3)
+border-radius(4px)
&.oe_hover
background: rgba(0, 255, 133, 0.22)
background: rgba(0, 255, 133, .3)
z-index: 1001
.oe_drop_zone_style
@@ -258,6 +287,7 @@ table.editorbar-panel
display: none
position: absolute
background: transparent
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.02) ,rgba(255,255,255,.02) 35px, rgba(0,0,0,.02) 35px, rgba(0,0,0,.02) 75px))
+border-radius(3px)
@include transition(opacity 100ms linear)
+box-sizing(border-box)
@@ -267,7 +297,7 @@ table.editorbar-panel
border-style: dashed
border-width: 1px
+box-shadow(0px 0px 0px 1px rgba(255,255,255,0.3), 0px 0px 0px 1px rgba(255,255,255,0.3) inset)
border-color: rgba(153, 0, 255, 0.5)
border-color: rgba(0, 0, 0, 0.5)
.oe_handle
display: block !important
pointer-events: auto
@@ -277,27 +307,29 @@ table.editorbar-panel
left: 50%
display: block
background: rgba(255, 255, 255, 1)
border: solid 1px rgba(153, 0, 255, 1)
+border-radius(8px)
width: 16px
height: 16px
margin: -8px
border: solid 1px rgba(0, 0, 0, .2)
+border-radius(5px)
width: 18px
height: 18px
margin: -9px
padding-left: 1px
font-size: 14px
line-height: 14px
color: rgba(153, 0, 255, 1)
font-family: FontAwesome
color: rgba(0,0,0,.5)
@include transition(background 100ms linear)
&:hover:before
background: rgba(153, 0, 255, 1)
background: rgba(0, 0, 0, .5)
color: #fff
+box-shadow(0 0 5px 3px rgba(255,255,255,.7))
.oe_handle.e:before
content: "⇨"
content: "\F061"
.oe_handle.s:before
content: "⇩"
content: "\F063"
.oe_handle.w:before
content: "⇦"
content: "\F060"
.oe_handle.n:before
content: "⇧"
content: "\F062"
.icon.btn
display: inline-block
@@ -432,10 +464,6 @@ $ace_width: 720px
$editorbar_height: 40px
// TODO Fix => might break with themes
$navbar_height: 51px
@mixin pointer-events($type: none)
$type: unquote($type)
@include experimental(pointer-events, $type,-moz, -webkit, not -o, not -ms, -khtml, official)
@mixin editor-font
font-size: 14px
+12 -13
View File
@@ -3,13 +3,12 @@
var website = openerp.website;
// $.fn.data automatically parses value, '0'|'1' -> 0|1
website.is_editable = $(document.documentElement).data('editable');
website.templates.push('/website/static/src/xml/website.editor.xml');
website.dom_ready.done(function () {
var is_smartphone = $(document.body)[0].clientWidth < 767;
if (website.is_editable && !is_smartphone) {
if (!is_smartphone) {
website.ready().then(website.init_editor);
}
});
@@ -21,16 +20,15 @@
return new website.editor.RTEImageDialog(editor).appendTo(document.body);
}
if (website.is_editable) {
// only enable editors manually
CKEDITOR.disableAutoInline = true;
// EDIT ALL THE THINGS
CKEDITOR.dtd.$editable = $.extend(
{}, CKEDITOR.dtd.$block, CKEDITOR.dtd.$inline);
// Disable removal of empty elements on CKEDITOR activation. Empty
// elements are used for e.g. support of FontAwesome icons
CKEDITOR.dtd.$removeEmpty = {};
}
// only enable editors manually
CKEDITOR.disableAutoInline = true;
// EDIT ALL THE THINGS
CKEDITOR.dtd.$editable = $.extend(
{}, CKEDITOR.dtd.$block, CKEDITOR.dtd.$inline);
// Disable removal of empty elements on CKEDITOR activation. Empty
// elements are used for e.g. support of FontAwesome icons
CKEDITOR.dtd.$removeEmpty = {};
website.init_editor = function () {
CKEDITOR.plugins.add('customdialogs', {
// requires: 'link,image',
@@ -604,7 +602,7 @@
} else if ($e.hasClass('pages')) {
// Create the page, get the URL back
done = $.get(_.str.sprintf(
'/pagenew/%s?noredirect', encodeURIComponent(val)))
'/pagenew/%s?noredirect', encodeURI(val)))
.then(function (response) {
self.make_link(response, false, val);
});
@@ -801,6 +799,7 @@
var element, editor = this.editor;
if (!(element = this.element)) {
element = editor.document.createElement('img');
element.addClass('img');
// focus event handler interactions between bootstrap (modal)
// and ckeditor (RTE) lead to blowing the stack in Safari and
// Chrome (but not FF) when this is done synchronously =>
@@ -55,8 +55,7 @@
New page
</label>
</h3>
<input type="text" class="form-control pages url-source"
id="link-new" pattern="[\\w/-]+"/>
<input type="text" class="form-control pages url-source" id="link-new"/>
</li>
<li class="list-group-item form-group clearfix">
<div class="pull-right">
+1 -1
View File
@@ -42,7 +42,7 @@ class TestConvertBack(common.TransactionCase):
rendered = renderer.render_tag_field(
e, {'field': field_value}, '', {
'record': record,
'request': Request(self.cr, self.uid, RegistryProxy( self.registry)),
'_request': Request(self.cr, self.uid, RegistryProxy( self.registry)),
})
element = html.fromstring(
rendered, parser=html.HTMLParser(encoding='utf-8'))
+19 -7
View File
@@ -14,9 +14,8 @@
<template id="layout" name="Main layout">
&lt;!DOCTYPE html&gt;
<html t-att-lang="lang.replace('_', '-')"
t-att-data-editable="'1' if editable else '0'"
t-att-data-translatable="'1' if translatable else '0'"
t-att-data-view-xmlid="str(__stack__[0])">
t-att-data-translatable="'1' if translatable else None"
t-att-data-view-xmlid="xmlid if editable else None">
<head>
<title><t t-esc="title or res_company.name"/></title>
<meta name="openerp.company" t-att-value="res_company.name" />
@@ -84,20 +83,30 @@
<li name="contactus"><a t-href="/page/website.contactus">Contact us</a></li>
<li t-if="user_id.id == website.public_user.id"><a href="/admin">Sign in</a></li>
<li t-if="user_id.id != website.public_user.id"><a href="/admin"><span t-field="user_id.name"/></a></li>
<li t-if="request.multilang and len(website.language_ids) &gt; 1" class="dropdown">
<li t-if="request.multilang and
(len(website.language_ids) &gt; 1 or editable)" class="dropdown">
<!-- TODO: use flags for language selection -->
<t t-set="lang_selected" t-value="[lg for lg in website.language_ids if lg.code == lang]"/>
<t t-set="lang_selected" t-value="website.lang_selected"/>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<t t-esc="lang_selected[0]['name']"/> <span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu">
<li t-foreach="website.language_ids" t-as="lg">
<a t-att-href="url_for('', lang=lg.code)" role="menuitem">
<strong t-att-class="'icon-check' if lg.code == lang
else 'icon-check-empty'"></strong>
<strong t-att-class="'icon-circle' if lg.code == lang
else 'icon-circle-blank'"></strong>
<t t-esc="lg.name"/>
</a>
</li>
<li t-if="editable" class="text-center">
<t t-set="url_return" t-value="request.multilang and url_for(request.httprequest.path, '[lang]') or request.httprequest.path"/>
<t t-if="request.httprequest.query_string">
<t t-set="url_return" t-value="url_return + '?' + request.httprequest.query_string"/>
</t>
<a t-attf-href="/web#action=base.action_view_base_language_install&amp;url_return=#{url_return}">
Add a Language
</a>
</li>
</ul>
</li>
</ul>
@@ -375,6 +384,9 @@
<a href="#" class="js_publish_btn css_unpublish">Unpublish</a>
<a href="#" class="js_publish_btn css_publish">Publish</a>
</li>
<li t-if="publish_duplicate">
<a t-att-href="publish_duplicate">Duplicate</a>
</li>
</ul>
</div>
<t t-if="publish_edit">
+12 -2
View File
@@ -55,9 +55,9 @@
<field name="social_youtube" placeholder="http://www.youtube.com/channel/HCU842OHPPNrQ"/>
<field name="social_github" placeholder="https://youraccount.github.io"/>
</group>
<group string="Others Info">
<group string="Other Info">
<field name="company_id" groups="base.group_multi_company"/>
<field name="language_ids" widget="many2many_tags"/>
<field name="language_ids" widget="many2many_checkboxes"/>
<field name="default_lang_id" widget="selection"/>
</group>
</group>
@@ -65,5 +65,15 @@
</form>
</field>
</record>
<record id="view_base_language_install" model="ir.ui.view">
<field name="name">view_base_language_install.inherit</field>
<field name="model">base.language.install</field>
<field name="inherit_id" ref="base.view_base_language_install"/>
<field name="arch" type="xml">
<group states="init" position="inside">
<field name="website_ids" widget="many2many_checkboxes"/>
</group>
</field>
</record>
</data>
</openerp>
+1 -1
View File
@@ -20,5 +20,5 @@
##############################################################################
import controllers
import website_blog
import models
import wizard
+3 -3
View File
@@ -32,16 +32,16 @@ OpenERP Blog
'author': 'OpenERP SA',
'depends': ['knowledge', 'website_mail'],
'data': [
'website_blog_data.xml',
'data/website_blog_data.xml',
'views/website_blog_classic.xml',
'views/website_blog_templates.xml',
# 'wizard/document_page_create_menu_view.xml',
'wizard/document_page_show_diff_view.xml',
'security/ir.model.access.csv',
'security/website_mail.xml',
'security/website_blog.xml',
],
'demo': [
'website_blog_demo.xml'
'data/website_blog_demo.xml'
],
'test': [
'test/document_page_test00.yml'
+26 -17
View File
@@ -35,10 +35,10 @@ class WebsiteBlog(http.Controller):
@website.route([
'/blog/',
'/blog/<int:category_id>/',
'/blog/<int:category_id>/<int:blog_post_id>/',
'/blog/<int:category_id>/page/<int:page>/',
'/blog/<int:category_id>/<int:blog_post_id>/page/<int:page>/',
'/blog/<int:blog_post_id>/',
'/blog/<int:blog_post_id>/page/<int:page>/',
'/blog/cat/<int:category_id>/',
'/blog/cat/<int:category_id>/page/<int:page>/',
'/blog/tag/',
'/blog/tag/<int:tag_id>/',
], type='http', auth="public")
@@ -90,11 +90,13 @@ class WebsiteBlog(http.Controller):
tag = tag_obj.browse(cr, uid, tag_id, context=context)
if category_id:
category = category_obj.browse(cr, uid, category_id, context=context)
if category and blog_post_id:
elif blog_post_id:
blog_post = blog_post_obj.browse(cr, uid, blog_post_id, context=context)
blog_message_ids = blog_post.website_message_ids
else:
category = blog_post.category_id
category_id = category.id
if not blog_post_id:
if category and tag:
blog_posts = [cat_post for cat_post in category.blog_post_ids
if tag_id in [post_tag.id for post_tag in cat_post.tag_ids]]
@@ -108,7 +110,7 @@ class WebsiteBlog(http.Controller):
if blog_posts:
pager = request.website.pager(
url="/blog/%s/" % category_id,
url="/blog/cat/%s/" % category_id,
total=len(blog_posts),
page=page,
step=self._category_post_per_page,
@@ -120,7 +122,7 @@ class WebsiteBlog(http.Controller):
if blog_post:
pager = request.website.pager(
url="/blog/%s/%s/" % (category_id, blog_post_id),
url="/blog/%s/" % blog_post_id,
total=len(blog_message_ids),
page=page,
step=self._post_comment_per_page,
@@ -138,8 +140,8 @@ class WebsiteBlog(http.Controller):
nav[year]['months'].append(group)
values = {
'categories': categories,
'category': category,
'categories': categories,
'tag': tag,
'blog_post': blog_post,
'blog_posts': blog_posts,
@@ -170,13 +172,13 @@ class WebsiteBlog(http.Controller):
]
return simplejson.dumps(blog_post_data)
@website.route(['/blog/<int:category_id>/<int:blog_post_id>/post'], type='http', auth="public")
def blog_comment(self, category_id=None, blog_post_id=None, **post):
@website.route(['/blog/<int:blog_post_id>/post'], type='http', auth="public")
def blog_post_comment(self, blog_post_id=None, **post):
cr, uid, context = request.cr, request.uid, request.context
url = request.httprequest.host_url
request.session.body = post.get('body')
if request.context['is_public_user']: # purpose of this ?
return '%s/admin#action=redirect&url=%s/blog/%s/%s/post' % (url, url, category_id, blog_post_id)
return '%s/admin#action=redirect&url=%s/blog/%s/post' % (url, url, blog_post_id)
if request.session.get('body') and blog_post_id:
request.registry['blog.post'].message_post(
@@ -187,17 +189,24 @@ class WebsiteBlog(http.Controller):
context=dict(context, mail_create_nosubcribe=True))
request.session.body = False
return werkzeug.utils.redirect("/blog/%s/%s/?unable_editor=1" % (category_id, blog_post_id))
return werkzeug.utils.redirect("/blog/%s/?unable_editor=1" % (blog_post_id))
@website.route(['/blog/<int:category_id>/new'], type='http', auth="public")
def create_blog_post(self, category_id=None, **post):
def blog_post_create(self, category_id=None, **post):
cr, uid, context = request.cr, request.uid, request.context
create_context = dict(context, mail_create_nosubscribe=True)
blog_post_id = request.registry['blog.post'].create(
new_blog_post_id = request.registry['blog.post'].create(
request.cr, request.uid, {
'category_id': category_id,
'name': _("Blog title"),
'content': '',
'website_published': False,
}, context=create_context)
return werkzeug.utils.redirect("/blog/%s/%s/?unable_editor=1" % (category_id, blog_post_id))
return werkzeug.utils.redirect("/blog/%s/?unable_editor=1" % (new_blog_post_id))
@website.route(['/blog/<int:blog_post_id>/duplicate'], type='http', auth="public")
def blog_post_copy(self, blog_post_id=None, **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'].copy(cr, uid, blog_post_id, {}, context=create_context)
return werkzeug.utils.redirect("/blog/%s/?unable_editor=1" % (new_blog_post_id))
@@ -17,15 +17,6 @@
<record id="blog_category_1" model="blog.category">
<field name="name">News</field>
<field name="description">Presentation of new OpenERP features</field>
<field name="template">
Summary of the feature
Long explanation
Conclusion
Additional ressources
</field>
</record>
<!-- Post-related subtypes for messaging / Chatter -->
@@ -8,6 +8,12 @@
<field name="name">functional</field>
</record>
<record id="blog_tag_2" model="blog.tag">
<field name="name">technical</field>
</record>
<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>
@@ -16,6 +22,7 @@
<field name="name">OpenERP v8 New Features</field>
<field name="category_id" ref="blog_category_1"/>
<field name="tag_ids" eval="[(6, 0, [ref('blog_tag_1')])]"/>
<field name="website_published" eval="True"/>
<field name="content"><![CDATA[
<section data-snippet-id='image-text'>
<div class="container">
@@ -264,6 +271,7 @@ Think of it as an out-of-the-box solution to boost your business' productivity.
<field name="name">Announcig a New Partnership</field>
<field name="category_id" ref="blog_category_1"/>
<field name="tag_ids" eval="[(6, 0, [ref('blog_tag_1')])]"/>
<field name="website_published" eval="True"/>
<field name="content"><![CDATA[
<section data-snippet-id='image-text'>
<div class="container">
@@ -291,7 +299,7 @@ Think of it as an out-of-the-box solution to boost your business' productivity.
<div class="row">
<div class="col-md-12 text-center mt16 mb32">
<h2>
Linked with Project Management
OpenERP Project Management
</h2>
<h3 class="text-muted">Infinitely flexible. Incredibly easy to use.</h3>
</div>
@@ -313,33 +321,6 @@ Think of it as an out-of-the-box solution to boost your business' productivity.
</div>
</div>
</section>
<section class="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>
+1
View File
@@ -0,0 +1 @@
import website_blog
@@ -37,7 +37,6 @@ class BlogCategory(osv.Model):
_columns = {
'name': fields.char('Name', required=True),
'description': fields.text('Description'),
'template': fields.html('Template'),
'blog_post_ids': fields.one2many(
'blog.post', 'category_id',
'Blogs',
@@ -62,7 +61,7 @@ class BlogPost(osv.Model):
_name = "blog.post"
_description = "Blog Post"
_inherit = ['mail.thread']
_order = 'name'
_order = 'write_date DESC'
# maximum number of characters to display in summary
_shorten_max_char = 250
@@ -170,6 +169,16 @@ class BlogPost(osv.Model):
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.update({
'website_message_ids': [],
'website_published': False,
'website_published_datetime': False,
})
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)
@@ -177,7 +186,7 @@ class BlogPost(osv.Model):
class BlogPostHistory(osv.Model):
_name = "blog.post.history"
_description = "Document Page History"
_description = "Blog Post History"
_order = 'id DESC'
_rec_name = "create_date"
@@ -19,11 +19,11 @@
#
##############################################################################
from openerp.addons.mail.tests.test_mail_base import TestMailBase
from openerp.addons.mail.tests.common import TestMail
from openerp.tools import mute_logger, email_split
class TestControllers(TestMailBase):
class TestControllers(TestMail):
def test_00(self):
cr, uid = self.cr, self.uid
@@ -2,7 +2,7 @@
<openerp>
<data>
<menuitem name="Knowledge" id="knowledge.menu_document"/>
<menuitem name="Pages" id="menu_wiki" parent="knowledge.menu_document" sequence="20" />
<menuitem name="Blog Posts" id="menu_wiki" parent="knowledge.menu_document" sequence="20" />
<!-- Category views -->
<record model="ir.ui.view" id="view_blog_category_list">
@@ -23,7 +23,6 @@
<group>
<field name="name"/>
<field name="description"/>
<field name="template" widget="html"/>
</group>
</sheet>
<div class="oe_chatter">
@@ -60,14 +59,12 @@
<group>
<field name="category_id" string="Category"/>
</group>
<group>
<field name="write_uid" groups="base.group_no_one" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_document_user']}"/>
<field name="write_date" groups="base.group_no_one"/>
<field name="menu_id" groups="base.group_no_one"/>
<field name="content" placeholder="e.g. Once upon a time..." widget="html"/>
<group string="Technical" groups="base.group_no_one">
<field name="write_uid" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_document_user']}"/>
<field name="write_date"/>
<field name="menu_id"/>
</group>
<div class="oe_document_page">
<field name="content" placeholder="e.g. Once upon a time..." widget="html"/>
</div>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
@@ -107,7 +104,7 @@
</p>
</field>
</record>
<menuitem id="menu_page" parent="menu_wiki" name="Pages" action="action_blog_post" sequence="10"/>
<menuitem id="menu_page" parent="menu_wiki" name="Blog Posts" action="action_blog_post" sequence="10"/>
<record model="ir.actions.act_window" id="action_blog_category">
<field name="name">Category</field>
@@ -5,25 +5,34 @@
<!-- Layout add nav and footer -->
<template id="header_footer_custom" inherit_id="website.layout">
<xpath expr="//header//ul[@id='top_menu']/li[@name='contactus']" position="before">
<li><a href="/blog/%(website_blog.blog_category_1)d/">News</a></li>
<li><a t-attf-href="/blog/cat/%(website_blog.blog_category_1)d/">News</a></li>
</xpath>
<xpath expr="//footer//div[@name='info']/ul" position="inside">
<li><a href="/blog/%(website_blog.blog_category_1)d/">News</a></li>
<li><a t-attf-href="/blog/cat/%(website_blog.blog_category_1)d/">News</a></li>
</xpath>
</template>
<!-- Blog Post Summary -->
<template id="view_blog_post_short" name="Blog Post Summary">
<template id="blog_post_short" name="Blog Post Summary">
<div>
<div class="pull-right">
<t t-call="website.publish_management">
<t t-set="object" t-value="blog_post"/>
<t t-set="publish_edit" t-value="True"/>
<t t-set="publish_duplicate" t-value="'/blog/%s/duplicate' % (blog_post.id)"/>
</t>
</div>
<h2 class="text-center">
<a t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}" t-field="blog_post.name"></a>
<a t-attf-href="/blog/#{blog_post.id}" t-field="blog_post.name"></a>
</h2>
<p class="post-meta text-muted text-center">
<p class="post-meta text-muted text-center" name='blog_post_data'>
<span class="icon-calendar"> <span t-field="blog_post.create_date"/></span> &amp;nbsp;
<span class="icon-user"> By <span t-field="blog_post.create_uid"/> &amp;nbsp;</span>
<span t-if="len(blog_post.message_ids) &gt; 0" class="icon-comment"> With
<a t-if="len(blog_post.message_ids) &lt;= 1" t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}#comments"><t t-esc="len(blog_post.message_ids)"/> comment</a>
<a t-if="len(blog_post.message_ids) > 1" t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}#comments"><t t-esc="len(blog_post.message_ids)"/> comments</a>
<span t-if="len(blog_post.message_ids) &gt; 0" class="icon-comment">
<a t-attf-href="/blog/#{blog_post.id}/#comment">
<t t-if="len(blog_post.message_ids) &lt;= 1" ><t t-esc="len(blog_post.message_ids)"/> comment</t>
<t t-if="len(blog_post.message_ids) > 1"><t t-esc="len(blog_post.message_ids)"/> comments</t>
</a>
</span>
</p>
<div t-field="blog_post.shortened_content" class="blog_content"/>
@@ -33,43 +42,56 @@
</template>
<!-- Options: Blog Post Summary: hide author -->
<template id="view_blog_post_short_author" inherit_option_id="website_blog.view_blog_post_short" name="Hide Authors">
<template id="opt_blog_post_short_author" name="Hide Authors"
inherit_option_id="website_blog.blog_post_short">
<xpath expr="//span[@class='icon-user']" position="attributes">
<attribute name="class">hidden</attribute>
</xpath>
</template>
<!-- Options: Blog Post Summary: show category -->
<template id="view_blog_post_short_category" inherit_option_id="website_blog.view_blog_post_short" name="Show Blog Name">
<template id="opt_blog_post_short_category" name="Blog Name"
inherit_option_id="website_blog.blog_post_short">
<xpath expr="//span[@class='icon-user']" position="after">
<span class="icon-folder-open"> In <span t-field="blog_post.category_id"/> &amp;nbsp;</span>
</xpath>
</template>
<!-- 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">
<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="icon-tags"/>
<t t-foreach="blog_post.tag_ids" t-as="tag">
<a t-attf-href="/blog/tag/#{tag.id}" t-esc="tag.name"/> &amp;nbsp;
</t>
</p>
</xpath>
</template>
<!-- Blog Post Complete -->
<template id="view_blog_post" name="Blog Post">
<template id="blog_post_complete" name="Blog Post">
<div>
<t t-call="website.publish_management">
<t t-set="object" t-value="blog_post"/>
<t t-set="publish_edit" t-value="True"/>
<t t-set="publish_duplicate" t-value="'/blog/%s/duplicate' % (blog_post.id)"/>
</t>
</div><div class="clearfix"/>
</div>
<div class="clearfix"/>
<h1 class="text-center" t-field="blog_post.name"/>
<p class="post-meta text-muted text-center">
<p class="post-meta text-muted text-center" name="blog_post_data">
<span class="icon-calendar"> <span t-field="blog_post.create_date"/></span> &amp;nbsp;
<span class="icon-user"> By <span t-field="blog_post.create_uid"/> &amp;nbsp;</span>
<span t-if="len(blog_post.message_ids) &gt; 0" class="icon-comment"> With
<a t-if="len(blog_post.message_ids) &lt;= 1" t-attf-href="#comments"><t t-esc="len(blog_post.message_ids)"/> comment</a>
<a t-if="len(blog_post.message_ids) > 1" t-attf-href="#comments"><t t-esc="len(blog_post.message_ids)"/> comments</a>
<a t-attf-href="#comments">
<t t-if="len(blog_post.message_ids) &lt;= 1" ><t t-esc="len(blog_post.message_ids)"/> comment</t>
<t t-if="len(blog_post.message_ids) > 1"><t t-esc="len(blog_post.message_ids)"/> comments</t>
</a>
</span>
</p>
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
<span class="icon-tags"/>
<t t-foreach="blog_post.tag_ids" t-as="tag">
<a t-attf-href="/blog/tag/#{tag.id}" t-esc="tag.name"/> &amp;nbsp;
</t>
</p>
<div t-field="blog_post.content" class="mt16"/>
<hr class="mb32"/>
@@ -102,78 +124,103 @@
</template>
<!-- Options: Blog Post: user can reply -->
<template id="view_blog_post_author" inherit_option_id="website_blog.view_blog_post" name="Hide Authors">
<template id="opt_blog_post_complete_comment" name="Comment Form"
inherit_option_id="website_blog.blog_post_complete" inherit_id="website_blog.blog_post_complete">
<xpath expr="//ul[last()]" position="after">
<section groups="group_website_blog_reply" class="mb32">
<h4>Leave a Comment</h4>
<form id="comment" t-attf-action="/blog/#{blog_post.category_id.id}/#{blog_post.id}/post#post"
method="POST">
<img class="img pull-left img-rounded" t-att-src="'/website/image?model=res.partner&amp;field=image_small&amp;id='+str(user_id.partner_id.id)" style="width: 50px; margin-right: 10px;"/>
<div class="pull-left mb32" style="width: 75%%">
<textarea rows="3" class="form-control" placeholder="Write a comment..."></textarea>
<button type="submit" class="btn btn-danger mt8">Post</button>
</div>
</form>
</section>
<section groups="group_website_blog_reply" class="mb32">
<h4>Leave a Comment</h4>
<form id="comment" t-attf-action="/blog/#{blog_post.id}/post#post"
method="POST">
<img class="img pull-left img-rounded" t-att-src="'/website/image?model=res.partner&amp;field=image_small&amp;id='+str(user_id.partner_id.id)" style="width: 50px; margin-right: 10px;"/>
<div class="pull-left mb32" style="width: 75%%">
<textarea rows="3" class="form-control" placeholder="Write a comment..."></textarea>
<button type="submit" class="btn btn-danger mt8">Post</button>
</div>
</form>
</section>
</xpath>
</template>
<!-- Options: Blog Post: hide author -->
<template id="view_blog_post_author" inherit_option_id="website_blog.view_blog_post" name="Hide Authors">
<template id="opt_blog_post_complete_author" name="Hide Authors"
inherit_option_id="website_blog.blog_post_complete">
<xpath expr="//span[@class='icon-user']" position="attributes">
<attribute name="class">hidden</attribute>
</xpath>
</template>
<!-- Options: Blog Post: show category -->
<template id="view_blog_post_show_category" inherit_option_id="website_blog.view_blog_post" name="Show Blog Name">
<template id="opt_blog_post_complete_category" name="Blog Name"
inherit_option_id="website_blog.blog_post_complete">
<xpath expr="//span[@class='icon-user']" position="after">
<span class="icon-folder-open"> In <span t-field="blog_post.category_id"/> &amp;nbsp;</span>
</xpath>
</template>
<!-- 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">
<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="icon-tags"/>
<t t-foreach="blog_post.tag_ids" t-as="tag">
<a t-attf-href="/blog/tag/#{tag.id}" t-esc="tag.name"/> &amp;nbsp;
</t>
</p>
</xpath>
</template>
<!-- Page -->
<template id="index" name="Blogs" page="True">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_blog/static/src/js/website_blog.js"></script>
<link rel='stylesheet' href='/website_blog/static/src/css/website_blog.css'/>
</t>
<t t-set="title">Blog</t>
<div id="wrap">
<div class="container mt16 js_website_blog">
<div class="row">
<div class="col-lg-8 col-sm-9" t-if="not blog_post">
<t t-foreach="blog_posts" t-as="blog_post" data-publish="">
<t t-call="website_blog.view_blog_post_short"/>
</t>
<div class="pull-right" t-call="website.pager"/>
</div>
<div class="col-md-9 col-lg-8" t-if="blog_post">
<t t-call="website_blog.view_blog_post">
<t t-set="blog_post" t-value="blog_post"/>
</t>
<t t-set="head">
<script type="text/javascript" src="/website_blog/static/src/js/website_blog.js"></script>
<link rel='stylesheet' href='/website_blog/static/src/css/website_blog.css'/>
</t>
<t t-set="title">Blog</t>
<div id="wrap">
<div class="container mt16 js_website_blog">
<div class="row">
<div class="col-lg-12 col-sm-12" t-if="not blog_post" id="blog_post">
<t t-if="category and editable">
<div class="row">
<a t-attf-href="/blog/#{category.id}/new" class="btn btn-primary pull-right">New Blog Post</a>
</div>
</t>
<t t-foreach="blog_posts" t-as="blog_post" data-publish="">
<t t-call="website_blog.blog_post_short"/>
</t>
<div class="pull-right" t-call="website.pager"/>
</div>
<div class="col-lg-12 col-sm-12" t-if="blog_post" id="blog_posts_summary">
<t t-call="website_blog.blog_post_complete">
<t t-set="blog_post" t-value="blog_post"/>
</t>
</div>
</div>
</div>
</div>
</div>
</t>
</template>
<!-- Option: right column -->
<template id="blog_right_column" inherit_id="website_blog.index" inherit_option_id="website_blog.index" name="Right Column">
<!-- Option: Blog: Right Column -->
<template id="blog_right_column" name="Right Column"
inherit_option_id="website_blog.index" inherit_id="website_blog.index">
<xpath expr="//div[@class='row']" position="inside">
<div class="col-sm-3 hidden-xs col-lg-offset-1 mb32" id="right_column">
<t t-if="category and editable">
<a t-attf-href="/blog/#{category.id}/new" class="btn btn-primary pull-right">New Blog Post</a>
</t>
<div class="clearfix mb48"/>
<div class="col-lg-3 col-sm-3 hidden-xs col-lg-offset-1 mb32" id="right_column">
</div>
</xpath>
<xpath expr="//div[@id='blog_post']" position="attributes">
<attribute name="class">col-lg-8 col-sm-8</attribute>
</xpath>
<xpath expr="//div[@id='blog_posts_summary']" position="attributes">
<attribute name="class">col-lg-8 col-sm-8</attribute>
</xpath>
</template>
<!-- Option: Right Column: archives -->
<template id="blog_history" inherit_id="website_blog.blog_right_column" inherit_option_id="website_blog.blog_right_column" name="Archives">
<template id="opt_blog_rc_history" name="Archives"
inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column">
<xpath expr="//div[@id='right_column']" position="inside">
<section>
<h4>Archives</h4>
@@ -195,7 +242,8 @@
</template>
<!-- Option: Right Column: about us -->
<template id="blog_aboutus" inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column" name="About" priority="4">
<template id="opt_blog_rc_about_us" name="About Us" priority="4"
inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column">
<xpath expr="//div[@id='right_column']" position="inside">
<section class="mb16">
<h4>About us</h4>
@@ -211,7 +259,8 @@
</template>
<!-- Option: Right Column: follow us -->
<template id="blog_followus" inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column" name="Follow us" priority="2">
<template id="opt_blog_rc_follow_us" name="Follow us" priority="2"
inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column">
<xpath expr="//div[@id='right_column']" position="inside">
<section class="mb16">
<h4>Follow us</h4>
@@ -239,8 +288,9 @@
</xpath>
</template>
<!-- Option: Right Column: categories + category in blog post -->
<template id="blog_categories" inherit_option_id="website_blog.blog_right_column" name="Other Blogs" priority="6">
<!-- Option: Right Column: categories -->
<template id="opt_blog_rc_categories" name="Other Blogs" priority="6"
inherit_option_id="website_blog.blog_right_column">
<xpath expr="//div[@id='right_column']" position="inside">
<section class="mb16">
<h4>Other Blogs</h4>
@@ -257,5 +307,5 @@
</xpath>
</template>
</data>
</data>
</openerp>
+1 -2
View File
@@ -20,5 +20,4 @@
##############################################################################
import controllers
import mail_message
import mail_thread
import models
+2
View File
@@ -0,0 +1,2 @@
import mail_message
import mail_thread
@@ -19,12 +19,12 @@
#
##############################################################################
from openerp.addons.mail.tests.test_mail_base import TestMailBase
from openerp.addons.mail.tests.common import TestMail
from openerp.addons.website_mail.controllers.main import WebsiteMail
from openerp.tools import mute_logger, email_split
class TestControllers(TestMailBase):
class TestControllers(TestMail):
def test_00_subscribe(self):
# from openerp.addons.web.http import request
+12 -9
View File
@@ -3,15 +3,18 @@
<data>
<template id="follow">
<a href="#" t-att-data-id="object.id" t-att-data-object="object._name" t-att-data-follow="object.id and object.message_is_follower and 'on' or 'off'" class="pull-right js_follow" t-if="editable" t-ignore="true">
<span t-attf-class="label label-success css_follow">Follow</span>
<span t-attf-class="label label-danger css_unfollow">Unfollow</span>
<span t-attf-class="label label-success css_followed">Following</span>
<span t-attf-class="label label-danger css_unfollowed">Not Following</span>
</a>
<input type="email" name="email" class="js_follow_email css_unfollowed_email"
t-att-value="email"
t-att-placeholder="email or 'Email Address'"/>
<div name="follow">
<a href="#" t-att-data-id="object.id" t-att-data-object="object._name" t-att-data-follow="object.id and object.message_is_follower and 'on' or 'off'"
class="pull-right js_follow" t-if="editable" t-ignore="true">
<span t-attf-class="label label-success css_follow">Follow</span>
<span t-attf-class="label label-danger css_unfollow">Unfollow</span>
<span t-attf-class="label label-success css_followed">Following</span>
<span t-attf-class="label label-danger css_unfollowed">Not Following</span>
</a>
<input type="email" name="email" class="js_follow_email css_unfollowed_email"
t-att-value="email"
t-att-placeholder="email or 'Email Address'"/>
</div>
</template>
<template id="website.layout" inherit_id="website.layout">
+1
View File
@@ -259,6 +259,7 @@ class Ecommerce(http.Controller):
'search': post.get("search"),
'pager': pager,
'styles': styles,
'style_in_product': lambda style, product: style.id in [s.id for s in product.website_style_ids]
}
return request.website.render("website_sale.products", values)
@@ -51,6 +51,16 @@
left: 15px;
right: 15px;
border-top: 1px solid #dddddd;
max-height: 120px;
overflow: hidden;
padding-bottom: 24px;
}
.product_price {
position: absolute;
left: 15px;
bottom: 5px;
z-index: 6;
}
.oe_mycart .input-group-addon {
@@ -123,21 +133,22 @@
height: 560px;
}
@media (max-width: 728px) {
.oe_product {
float: left;
width: 100%;
height: 200px;
display: inline-block;
}
@media (max-width: 600px) {
#products_grid table, #products_grid tbody, #products_grid tr, #products_grid td {
float: left;
width: 100%;
display: inline-block;
}
#products_grid table td.oe-height-2 {
display: none;
#products_grid .oe_product {
float: left;
width: 100%;
height: 300px;
display: inline-block;
}
}
@media (max-width: 400px) {
#products_grid .oe_product {
height: 200px;
}
}
@media (min-width: 992px) {
@@ -228,6 +239,10 @@
right: 0;
border-top: none;
top: 15px;
max-height: 94px;
}
.oe_list_products .product_price {
left: 180px;
}
.oe_website_sale .row .row .col-md-12 {
@@ -49,6 +49,14 @@
left: 15px
right: 15px
border-top: 1px solid #dddddd
max-height: 120px
overflow: hidden
padding-bottom: 24px
.product_price
position: absolute
left: 15px
bottom: 5px
z-index: 6
.oe_mycart
.input-group-addon
@@ -113,19 +121,22 @@
.oe-height-8
height: 560px
@media (max-width: 728px)
.oe_product
float: left
width: 100%
height: 200px
display: inline-block
@media (max-width: 600px)
#products_grid
table, tbody,tr, td
float: left
width: 100%
display: inline-block
table td.oe-height-2
display: none
.oe_product
float: left
width: 100%
height: 300px
display: inline-block
@media (max-width: 400px)
#products_grid
.oe_product
height: 200px
@media (min-width: 992px)
.col-md-12
@@ -195,6 +206,9 @@
right: 0
border-top: none
top: 15px
max-height: 94px
.product_price
left: 180px
.oe_website_sale .row .row .col-md-12
float: none
+15 -22
View File
@@ -110,18 +110,17 @@
<a t-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&amp;category_id=%s' % category_id) or ''}">
<b t-field="product.name"/>
</a>
<div class="product_price">
<b>
<t t-if="product.product_variant_ids[0].lst_price != product.product_variant_ids[0].price">
<span class="text-danger" style="text-decoration: line-through;">
<t t-esc="product.product_variant_ids[0].lst_price" /> €
</span>&amp;nbsp;
</t>
<t t-esc="product.product_variant_ids[0].price" /> €
</b>
</div>
</div>
<div class="product_price">
<b>
<t t-if="product.product_variant_ids[0].lst_price != product.product_variant_ids[0].price">
<span class="text-danger" style="text-decoration: line-through;">
<t t-esc="product.product_variant_ids[0].lst_price" /> €
</span>&amp;nbsp;
</t>
<t t-esc="product.product_variant_ids[0].price" /> €
</b>
</div>
<div class="oe_product_image text-center">
<a t-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&amp;category_id=%s' % category_id) or ''}">
<img class="img" t-att-src="product.img('image')"/>
@@ -160,12 +159,6 @@
<div class='style_default row'>
<div class="col-md-12" id="products_grid">
<table width="100%">
<colgroup>
<col class="col-md-3" />
<col class="col-md-3" />
<col class="col-md-3" />
<col class="col-md-3" />
</colgroup>
<tbody>
<t t-set="table_products" t-value="get_bin_packing_products(product_ids, product_ids_for_holes, 4)"/>
<tr t-foreach="table_products" t-as="tr_product">
@@ -219,7 +212,7 @@
<a tabindex="-1" href="#">Styles</a>
<ul class="dropdown-menu" name="style">
<t t-foreach="styles" t-as="style">
<li t-att-class="style.id in [s.id for s in product.website_style_ids] and 'active' or ''"><a href="#" t-att-data-id="style.id" t-att-data-class="style.html_class"><t t-esc="style.name"/></a></li>
<li t-att-class="style_in_product(style, product) and 'active' or ''"><a href="#" t-att-data-id="style.id" t-att-data-class="style.html_class"><t t-esc="style.name"/></a></li>
</t>
</ul>
</li>
@@ -251,7 +244,7 @@
<!-- Product Description-->
<template id="product_description" inherit_option_id="website_sale.products_cart" name="Product Description">
<xpath expr="//div[@class='product_price']" position="before">
<xpath expr="//div[@class='oe_product_description']" position="inside">
<p class="text-muted oe_subdescription">
<span t-field="product.description_sale"/>
</p>
@@ -635,7 +628,7 @@
<input type="text" name="name" class="form-control" t-att-value="checkout.get('name')"/>
</div>
<div t-attf-class="form-group #{error.get('company') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="company">Your Company</label>
<label class="control-label" for="company" style="font-weight: normal">Your Company</label>
<input type="text" name="company" class="form-control" t-att-value="checkout.get('company')"/>
</div>
<div t-attf-class="form-group #{error.get('email') and 'has-error' or ''} col-lg-6">
@@ -662,7 +655,7 @@
<input type="text" name="zip" class="form-control" t-att-value="checkout.get('zip')"/>
</div>
<div t-attf-class="form-group #{error.get('state_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="state_id">State / Province</label>
<label class="control-label" for="state_id" style="font-weight: normal">State / Province</label>
<select name="state_id" class="form-control">
<option value="">select...</option>
<t t-foreach="states or []" t-as="state">
@@ -716,7 +709,7 @@
<input type="text" name="shipping_zip" class="form-control" t-att-value="checkout.get('shipping_zip', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_state_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">State / Province</label>
<label class="control-label" for="contact_name" style="font-weight: normal">State / Province</label>
<select name="shipping_state_id" class="form-control">
<option value="">State / Province...</option>
<t t-foreach="states or []" t-as="state">