diff --git a/addons/stock/wizard/stock_change_product_qty.py b/addons/stock/wizard/stock_change_product_qty.py
index 01ed6f2409a..cf4099ac3ba 100644
--- a/addons/stock/wizard/stock_change_product_qty.py
+++ b/addons/stock/wizard/stock_change_product_qty.py
@@ -33,6 +33,10 @@ class stock_change_product_qty(osv.osv_memory):
'prodlot_id': fields.many2one('stock.production.lot', 'Serial Number', domain="[('product_id','=',product_id)]"),
'location_id': fields.many2one('stock.location', 'Location', required=True, domain="[('usage', '=', 'internal')]"),
}
+ _defaults = {
+ 'new_quantity': 1,
+ 'product_id': lambda self, cr, uid, ctx: ctx and ctx.get('active_id', False) or False
+ }
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
if context is None: context = {}
@@ -54,20 +58,22 @@ class stock_change_product_qty(osv.osv_memory):
@param context: A standard dictionary
@return: A dictionary which of fields with values.
"""
- product_id = context and context.get('active_id', False) or False
+
res = super(stock_change_product_qty, self).default_get(cr, uid, fields, context=context)
- if 'new_quantity' in fields:
- res.update({'new_quantity': 1})
- if 'product_id' in fields:
- res.update({'product_id': product_id})
if 'location_id' in fields:
- try:
- model, location_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_stock')
- self.pool.get('stock.location').check_access_rule(cr, uid, [location_id], 'read', context=context)
- except (orm.except_orm, ValueError):
- location_id = False
- res.update({'location_id': location_id})
+ location_id = res.get('location_id', False)
+ if not location_id:
+ try:
+ model, location_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_stock')
+ except (orm.except_orm, ValueError):
+ pass
+ if location_id:
+ try:
+ self.pool.get('stock.location').check_access_rule(cr, uid, [location_id], 'read', context=context)
+ except (orm.except_orm, ValueError):
+ pass
+ res['location_id'] = location_id
return res
def change_product_qty(self, cr, uid, ids, context=None):
diff --git a/addons/stock/wizard/stock_move_view.xml b/addons/stock/wizard/stock_move_view.xml
index 5dc0d0d824c..f2bc40d9a3f 100644
--- a/addons/stock/wizard/stock_move_view.xml
+++ b/addons/stock/wizard/stock_move_view.xml
@@ -67,6 +67,7 @@
form
form
new
+
{'form_view_ref': False}
@@ -124,6 +125,7 @@
form
form
new
+ {'form_view_ref': False}
diff --git a/addons/subscription/__openerp__.py b/addons/subscription/__openerp__.py
index b301525eb42..5f8a1d1338b 100644
--- a/addons/subscription/__openerp__.py
+++ b/addons/subscription/__openerp__.py
@@ -37,7 +37,7 @@ e.g. To have an invoice generated automatically periodically:
above. Specify the interval information and partner to be invoice.
""",
'author': 'OpenERP SA',
- 'depends': [],
+ 'depends': ['base'],
'data': ['security/subcription_security.xml', 'security/ir.model.access.csv', 'subscription_view.xml'],
'demo': ['subscription_demo.xml',],
'installable': True,
diff --git a/addons/survey/wizard/survey_send_invitation.py b/addons/survey/wizard/survey_send_invitation.py
index 44d3bec7f6e..e16d0d6ce77 100644
--- a/addons/survey/wizard/survey_send_invitation.py
+++ b/addons/survey/wizard/survey_send_invitation.py
@@ -128,23 +128,14 @@ Thanks,''') % (name, self.pool.get('ir.config_parameter').get_param(cr, uid, 'we
for use in exist_user:
new_user.append(use.id)
for id in survey_ref.browse(cr, uid, survey_ids):
- report = self.create_report(cr, uid, [id.id], 'report.survey.form', id.title)
- file = open(get_module_resource('survey', 'report') + id.title +".pdf")
- file_data = ""
- while 1:
- line = file.readline()
- file_data += line
- if not line:
- break
- file.close()
- attachments[id.title +".pdf"] = file_data
- os.remove(get_module_resource('survey', 'report') + id.title +".pdf")
+ result, format = openerp.report.render_report(cr, uid, [id.id], 'survey.form', {}, {})
+ attachments[id.title +".pdf"] = result
for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids):
if not partner.email:
skipped+= 1
continue
- user = user_ref.search(cr, uid, [('login', "=", partner.email)])
+ user = user_ref.search(cr, uid, [('partner_id', "=", partner.id)])
if user:
if user[0] not in new_user:
new_user.append(user[0])
@@ -185,6 +176,8 @@ Thanks,''') % (name, self.pool.get('ir.config_parameter').get_param(cr, uid, 'we
if ans:
res_data = {'name': partner.name or _('Unknown'),
'login': partner.email,
+ 'email': partner.email,
+ 'partner_id': partner.id,
'password': passwd,
'address_id': partner.id,
'groups_id': [[6, 0, [group_id]]],
diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py
index 76907faec3c..1711bddcfce 100644
--- a/addons/website/controllers/main.py
+++ b/addons/website/controllers/main.py
@@ -299,7 +299,7 @@ class Website(openerp.addons.web.controllers.main.Home):
#------------------------------------------------------
# Helpers
#------------------------------------------------------
- @http.route(['/website/kanban/'], type='http', auth="public", methods=['POST'], website=True)
+ @http.route(['/website/kanban'], type='http', auth="public", methods=['POST'], website=True)
def kanban(self, **post):
return request.website.kanban_col(**post)
diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py
index 47c0853d6be..c0a9e209d00 100644
--- a/addons/website/models/ir_http.py
+++ b/addons/website/models/ir_http.py
@@ -91,7 +91,12 @@ class ir_http(orm.AbstractModel):
assert path is not None
except Exception:
return self._handle_exception(werkzeug.exceptions.NotFound())
- if path != request.httprequest.path:
+
+ generated_path = werkzeug.url_unquote_plus(path)
+ current_path = werkzeug.url_unquote_plus(request.httprequest.path)
+ if generated_path != current_path:
+ if request.lang != request.website.default_lang_code:
+ path = '/' + request.lang + path
return werkzeug.utils.redirect(path)
def _handle_exception(self, exception=None, code=500):
diff --git a/addons/website/models/ir_qweb.py b/addons/website/models/ir_qweb.py
index 64aad94c83e..ef60aefbeff 100644
--- a/addons/website/models/ir_qweb.py
+++ b/addons/website/models/ir_qweb.py
@@ -381,42 +381,8 @@ class RelativeDatetime(orm.AbstractModel):
class Contact(orm.AbstractModel):
_name = 'website.qweb.field.contact'
- _inherit = ['website.qweb.field', 'website.qweb.field.many2one']
+ _inherit = ['ir.qweb.field.contact', 'website.qweb.field.many2one']
- def from_html(self, cr, uid, model, column, element, context=None):
- # FIXME: this behavior is really weird, what if the user wanted to edit the name of the related thingy? Should m2os really be editable without a widget?
- divs = element.xpath(".//div")
- for div in divs:
- if div != divs[0]:
- div.getparent().remove(div)
- return super(Contact, self).from_html(cr, uid, model, column, element, context=context)
-
- def record_to_html(self, cr, uid, field_name, record, column, options=None, context=None):
- opf = options.get('fields') or ["name", "address", "phone", "mobile", "fax", "email"]
-
- if not getattr(record, field_name):
- return None
-
- id = getattr(record, field_name).id
- field_browse = self.pool[column._obj].browse(cr, openerp.SUPERUSER_ID, id, context={"show_address": True})
- value = werkzeug.utils.escape( field_browse.name_get()[0][1] )
-
- val = {
- 'name': value.split("\n")[0],
- 'address': werkzeug.utils.escape("\n".join(value.split("\n")[1:])),
- 'phone': field_browse.phone,
- 'mobile': field_browse.mobile,
- 'fax': field_browse.fax,
- 'city': field_browse.city,
- 'country_id': field_browse.country_id and field_browse.country_id.name_get()[0][1],
- 'email': field_browse.email,
- 'fields': opf,
- 'options': options
- }
-
- html = self.pool["ir.ui.view"].render(cr, uid, "website.contact", val, engine='website.qweb', context=context).decode('utf8')
-
- return ir_qweb.HTMLSafe(html)
def html_to_text(element):
""" Converts HTML content with HTML-specified line breaks (br, p, div, ...)
diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py
index 857b99d40d2..67781cc02a0 100644
--- a/addons/website/models/ir_ui_view.py
+++ b/addons/website/models/ir_ui_view.py
@@ -168,20 +168,9 @@ class view(osv.osv):
arch_no_whitespace = etree.fromstring(
etree.tostring(arch, encoding='utf-8'),
parser=etree.XMLParser(encoding='utf-8', remove_blank_text=True))
- arch_pretty_indent_2 = etree.tostring(
+ return etree.tostring(
arch_no_whitespace, encoding='unicode', pretty_print=True)
- # pretty_print uses a fixed indent level of 2, we want an indent of 4,
- # double up leading spaces.
- def repl(m):
- indent = len(m.group(0)) / 2
- return u' ' * 4 * indent
- # FIXME: If py2.7 only, can use re.M in sub and don't have to do replacement line by line
- return u'\n'.join(
- re.sub(ur'^((?: )+)', repl, line)
- for line in arch_pretty_indent_2.split(u'\n')
- )
-
def save(self, cr, uid, res_id, value, xpath=None, context=None):
""" Update a view section. The view section may embed fields to write
diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index 1a541865987..15e1a643d3d 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -248,7 +248,7 @@ class website(osv.osv):
pmin = pmax - scope if pmax - scope > 0 else 1
def get_url(page):
- _url = "%spage/%s/" % (url, page) if page > 1 else url
+ _url = "%s/page/%s" % (url, page) if page > 1 else url
if url_args:
_url = "%s?%s" % (_url, werkzeug.url_encode(url_args))
return _url
diff --git a/addons/website/static/src/css/bootswatch/amelia.fix.css b/addons/website/static/src/css/bootswatch/amelia.fix.css
new file mode 100644
index 00000000000..2f16ea5465c
--- /dev/null
+++ b/addons/website/static/src/css/bootswatch/amelia.fix.css
@@ -0,0 +1,27 @@
+#website-top-navbar a.btn-link {
+ color: #ad1d28;
+}
+.oe_product section {
+ background: rgba(16, 138, 147, 0.75) !important;
+}
+.oe_product section .text-info {
+ color: #DFD6F5;
+}
+ul.wizard li {
+ background: #debb27 !important;
+}
+ul.wizard .chevron:before {
+ border-left: 10px solid #debb27 !important;
+}
+ul.wizard .text-primary {
+ color: #ad1d28 !important;
+}
+ul.wizard .text-success {
+ color: #ffffff !important;
+}
+.oe_structure.oe_empty:empty:before, [data-oe-type=html]:empty:before {
+ color: #79D5DB !important;
+}
+.input-group-addon .fa {
+ color: #444;
+}
diff --git a/addons/website/static/src/css/bootswatch/cosmo.fix.css b/addons/website/static/src/css/bootswatch/cosmo.fix.css
new file mode 100644
index 00000000000..907aa7bf757
--- /dev/null
+++ b/addons/website/static/src/css/bootswatch/cosmo.fix.css
@@ -0,0 +1,7 @@
+#website-top-navbar button.btn-primary {
+ color: #fff;
+ border: 2px solid #0061c2;
+}
+#website-top-navbar a.btn-link {
+ color: #fff;
+}
\ No newline at end of file
diff --git a/addons/website/static/src/css/bootswatch/cyborg.fix.css b/addons/website/static/src/css/bootswatch/cyborg.fix.css
new file mode 100644
index 00000000000..e93b2aa8ded
--- /dev/null
+++ b/addons/website/static/src/css/bootswatch/cyborg.fix.css
@@ -0,0 +1,30 @@
+.oe_product section {
+ background: rgba(40, 40, 40, 0.85) !important;
+}
+.oe_product section .text-info {
+ color: #BA66E4;
+}
+ul.wizard li {
+ background: #222 !important;
+}
+ul.wizard .chevron:before {
+ border-left: 10px solid #222 !important;
+}
+.popover, .modal-content {
+ border: 1px solid rgba(200,200,200,0.5);
+}
+.close {
+ color: #fff;
+}
+.popover.bottom .arrow:after {
+ border-bottom-color: #333;
+}
+.popover.top .arrow:after {
+ border-top-color: #333;
+}
+.popover.left .arrow:after {
+ border-left-color: #333;
+}
+.popover.right .arrow:after {
+ border-right-color: #333;
+}
\ No newline at end of file
diff --git a/addons/website/static/src/css/bootswatch/flatly.fix.css b/addons/website/static/src/css/bootswatch/flatly.fix.css
new file mode 100644
index 00000000000..c2d9500f5da
--- /dev/null
+++ b/addons/website/static/src/css/bootswatch/flatly.fix.css
@@ -0,0 +1,3 @@
+#website-top-navbar a.btn-link {
+ color: #2c3e50;
+}
\ No newline at end of file
diff --git a/addons/website/static/src/css/bootswatch/journal.fix.css b/addons/website/static/src/css/bootswatch/journal.fix.css
new file mode 100644
index 00000000000..e9f41a33e8f
--- /dev/null
+++ b/addons/website/static/src/css/bootswatch/journal.fix.css
@@ -0,0 +1,6 @@
+#website-top-navbar button.btn-primary {
+ border: 2px solid #e4332e;
+}
+#website-top-navbar a.btn-link {
+ color: #fff;
+}
\ No newline at end of file
diff --git a/addons/website/static/src/css/bootswatch/readable.fix.css b/addons/website/static/src/css/bootswatch/readable.fix.css
new file mode 100644
index 00000000000..8e22d318615
--- /dev/null
+++ b/addons/website/static/src/css/bootswatch/readable.fix.css
@@ -0,0 +1,3 @@
+.oe_product section .text-info {
+ color: #2A9CBE;
+}
\ No newline at end of file
diff --git a/addons/website/static/src/css/bootswatch/simplex.fix.css b/addons/website/static/src/css/bootswatch/simplex.fix.css
new file mode 100644
index 00000000000..56dbb1fdd5f
--- /dev/null
+++ b/addons/website/static/src/css/bootswatch/simplex.fix.css
@@ -0,0 +1,3 @@
+#website-top-navbar a.btn-link {
+ color: #fff;
+}
\ No newline at end of file
diff --git a/addons/website/static/src/css/bootswatch/slate.fix.css b/addons/website/static/src/css/bootswatch/slate.fix.css
new file mode 100644
index 00000000000..c2e1a999b03
--- /dev/null
+++ b/addons/website/static/src/css/bootswatch/slate.fix.css
@@ -0,0 +1,21 @@
+.oe_product section {
+ background: rgba(40, 40, 45, 0.80) !important;
+}
+ul.wizard li {
+ background-image: -webkit-linear-gradient(#8a9196,#7a8288 60%,#788084) !important;
+ background-image: linear-gradient(#8a9196,#7a8288 60%,#788084 ) !important;
+ color: #ccc;
+}
+ul.wizard .chevron:before {
+ border-left: 10px solid #7C8386 !important;
+}
+ul.wizard li.text-primary {
+ color: #fff;
+}
+.close {
+ color: #fff;
+}
+.popover {
+ -webkit-box-shadow: 0px 0px 20px rgba(0,0,0,0.5);
+ box-shadow: 0px 0px 20px rgba(0,0,0,0.5);
+}
diff --git a/addons/website/static/src/css/bootswatch/spacelab.fix.css b/addons/website/static/src/css/bootswatch/spacelab.fix.css
new file mode 100644
index 00000000000..6d01e9a2485
--- /dev/null
+++ b/addons/website/static/src/css/bootswatch/spacelab.fix.css
@@ -0,0 +1,8 @@
+.carousel .carousel-caption.content,
+.carousel .carousel-caption.content h1,
+.carousel .carousel-caption.content h2,
+.carousel .carousel-caption.content h3,
+.carousel .carousel-caption.content h4,
+.carousel .carousel-caption.content h5 {
+ color: #ccc;
+}
\ No newline at end of file
diff --git a/addons/website/static/src/css/bootswatch/yeti.fix.css b/addons/website/static/src/css/bootswatch/yeti.fix.css
new file mode 100644
index 00000000000..3fd285c826e
--- /dev/null
+++ b/addons/website/static/src/css/bootswatch/yeti.fix.css
@@ -0,0 +1,6 @@
+#website-top-navbar a.btn-link {
+ color: #fff;
+}
+.popover .close {
+ color: #fff;
+}
\ No newline at end of file
diff --git a/addons/website/static/src/css/snippets.css b/addons/website/static/src/css/snippets.css
index 4121b70ef2e..726855f311b 100644
--- a/addons/website/static/src/css/snippets.css
+++ b/addons/website/static/src/css/snippets.css
@@ -328,14 +328,10 @@
}
.oe_overlay .oe_handle.size .oe_handle_button {
z-index: 3;
- content: "Resize";
- width: 64px;
text-align: center;
margin-left: -32px;
margin-top: -10px;
- cursor: row-resize;
left: 0px;
- top: 9px;
}
.oe_overlay .oe_handle.size .oe_handle_button:hover {
background: rgba(30, 30, 30, 0.8);
@@ -344,6 +340,18 @@
-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_handle.size .size {
+ width: 64px;
+ cursor: row-resize;
+ top: 9px;
+}
+.oe_overlay .oe_handle.size .auto_size {
+ width: 20px;
+ padding: 0 5px;
+ top: 1px;
+ margin-left: 36px;
+ cursor: pointer;
+}
.oe_overlay .oe_handle.readonly {
cursor: auto !important;
}
diff --git a/addons/website/static/src/css/snippets.sass b/addons/website/static/src/css/snippets.sass
index d7442a5b0f7..9b12e9df246 100644
--- a/addons/website/static/src/css/snippets.sass
+++ b/addons/website/static/src/css/snippets.sass
@@ -240,18 +240,24 @@
bottom: -6px
.oe_handle_button
z-index: 3
- content: "Resize"
- width: 64px
text-align: center
margin-left: -32px
margin-top: -10px
- cursor: row-resize
left: 0px
- top: 9px
&:hover
background: rgba(30, 30, 30, .8)
color: #fff
+box-shadow(0 0 5px 3px rgba(255,255,255,.7))
+ .size
+ width: 64px
+ cursor: row-resize
+ top: 9px
+ .auto_size
+ width: 20px
+ padding: 0 5px
+ top: 1px
+ margin-left: 36px
+ cursor: pointer
&.readonly
cursor: auto !important
&:before, &.size
diff --git a/addons/website/static/src/css/website.css b/addons/website/static/src/css/website.css
index dc0628ca3c5..e9df2841347 100644
--- a/addons/website/static/src/css/website.css
+++ b/addons/website/static/src/css/website.css
@@ -240,7 +240,7 @@ ul.nav-stacked > li > a {
display: none;
}
-[data-publish='off'] {
+[data-publish='off'] > *:not(.css_options) {
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50);
opacity: 0.5;
}
diff --git a/addons/website/static/src/css/website.sass b/addons/website/static/src/css/website.sass
index a15953e0f2b..2c8d5d2fdda 100644
--- a/addons/website/static/src/css/website.sass
+++ b/addons/website/static/src/css/website.sass
@@ -199,7 +199,7 @@ ul.nav-stacked > li > a
.btn-success, .css_unpublish
display: none
-[data-publish='off']
+[data-publish='off']>*:not(.css_options)
+opacity(0.5)
/* ---- END of PUBLISH ---- */
diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js
index c89bf9ec2fb..ae126ad16ab 100644
--- a/addons/website/static/src/js/website.editor.js
+++ b/addons/website/static/src/js/website.editor.js
@@ -1789,6 +1789,9 @@
if (node.nodeName === 'BR' && node.getAttribute('type') === '_moz') {
//
appears when focusing RTE in FF, ignore
continue;
+ } else if (node.nodeName === 'DIV' && $(node).hasClass('oe_drop_zone')) {
+ // ignore dropzone inserted by snippets
+ continue
}
}
diff --git a/addons/website/static/src/js/website.editor.newpage.js b/addons/website/static/src/js/website.editor.newpage.js
index b475223ecd9..77a086790fa 100644
--- a/addons/website/static/src/js/website.editor.newpage.js
+++ b/addons/website/static/src/js/website.editor.newpage.js
@@ -48,7 +48,7 @@
}
}).then(function (val, field, $dialog) {
if (val) {
- var url = '/website/add/' + encodeURI(val);
+ var url = '/website/add' + encodeURI(val);
if ($dialog.find('input[type="checkbox"]').is(':checked')) url +="?add_menu=1";
document.location = url;
}
diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js
index 065928df1cf..31e39b3bbc4 100644
--- a/addons/website/static/src/js/website.js
+++ b/addons/website/static/src/js/website.js
@@ -53,6 +53,7 @@
/* ----------------------------------------------------
Widgets
---------------------------------------------------- */
+
website.prompt = function (options) {
/**
* A bootstrapped version of prompt() albeit asynchronous
@@ -198,7 +199,7 @@
var page = +$a.attr("href").split(",").pop().split('-')[1];
data['page'] = page;
- $.post('/website/kanban/', data, function (col) {
+ $.post('/website/kanban', data, function (col) {
$col.find("> .thumbnail").remove();
$pagination.last().before(col);
});
diff --git a/addons/website/static/src/js/website.mobile.js b/addons/website/static/src/js/website.mobile.js
index 59c2328e09b..88a558f5094 100644
--- a/addons/website/static/src/js/website.mobile.js
+++ b/addons/website/static/src/js/website.mobile.js
@@ -18,9 +18,9 @@
},
start: function () {
if (!window.location.origin) { // fix for ie9
- window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '') + '/';
+ window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
}
- document.getElementById("mobile-viewport").src = window.location.origin + window.location.pathname + "#mobile-preview";
+ document.getElementById("mobile-viewport").src = window.location.origin + (window.location.pathname.length ? '/' : '') + window.location.pathname + "#mobile-preview";
this.$el.modal();
},
destroy: function () {
diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js
index b8533236e01..52deeabf5e6 100644
--- a/addons/website/static/src/js/website.snippets.editor.js
+++ b/addons/website/static/src/js/website.snippets.editor.js
@@ -1,6 +1,136 @@
(function () {
'use strict';
+/* Building block / Snippet Editor
+
+ The building blocks appear in the edit bar website. These prebuilt html block
+ allowing the designer to easily generate content on a page (drag and drop).
+ Options allow snippets to add customizations part html code according to their
+ selector (jQuery) and javascript object.
+
+ How to create content?
+
+ Designers can add their own html block in the "snippets" (/website/views/snippets.xml).
+ The block must be added in one of four menus (structure, content, feature or effect).
+ Structure:
+
+
+
![](...image src...)
+
...Block Name...
+
+
+ ...
+
+
+
+
+ How to create options?
+
+ Designers can add their own html block in the "snippet_options" (/website/views/snippets.xml).
+ Structure:
+
+
+ data-selector="..."
+ data-selector-siblings="..."
+ data-selector-children="..."
+ data-selector-vertical-children='...'>
+ ...
+
...
+ ...
+
+
+
+ How to create a javascript object for an options?
+
+ openerp.website.snippet.options["...option-id..."] = website.snippet.Option.extend({
+ // start is called when the user click into a block or when the user drop a block
+ // into the page (just after the init method).
+ // start is usually used to bind event.
+ //
+ // this.$target: block html inserted inside the page
+ // this.$el: html li list of this options
+ // this.$overlay: html editor overlay who content resize bar, customize menu...
+ start: function () {},
+
+
+ // onFocus is called when the user click inside the block inserted in page
+ // and when the user drop on block into the page
+ onFocus : function () {},
+
+
+ // onBlur is called when the user click outside the block inserted in page, if
+ // the block is focused
+ onBlur : function () {},
+
+
+ // on_clone is called when the snippet is duplicate
+ // @variables: $clone is allready inserted is the page
+ on_clone: function ($clone) {},
+
+
+ // on_remove is called when the snippet is removed (dom is removing after this tigger)
+ on_remove: function () {},
+
+
+ // drop_and_build_snippet is called just after that a thumbnail is drag and dropped
+ // into a drop zone. The content is already inserted in the page.
+ drop_and_build_snippet: function () {},
+
+ // select is called when a user select an item in the li list of options
+ // By default, if the li item have a data-value attribute, the data-vlue it's apply
+ // like a class to the html block (this.$target)
+ // @variables: next_previous = {$next, $prev}
+ // $next = next item selected or false
+ // $prev = previous item selected or false
+ select: function (event, next_previous) {}
+
+ // preview is called when a user is on mouse over or mouse out of an item
+ // variables: next_previous = {$next, $prev}
+ // $next = next item selected or false
+ // $prev = previous item selected or false
+ preview: function (event, next_previous) {}
+
+ // clean_for_save
+ // clean_for_save is called just before to save the vue
+ // Sometime it's important to remove or add some datas (contentEditable, added
+ // classes to a running animation...)
+ clean_for_save: function () {}
+ });
+
+
+ // 'snippet-dropped' is triggered on '#oe_snippets' whith $target as attribute when a snippet is dropped
+ // 'snippet-activated' is triggered on '#oe_snippets' (and on snippet) when a snippet is activated
+
+*/
+
+
var website = openerp.website;
website.add_template_file('/website/static/src/xml/website.snippets.xml');
@@ -19,23 +149,11 @@
edit: function () {
var self = this;
$("[data-oe-model] *, [data-oe-type=html] *").off('click');
- website.snippet.stop_animation();
window.snippets = this.snippets = new website.snippet.BuildingBlock(this);
this.snippets.appendTo(this.$el);
this.on('rte:ready', this, function () {
self.snippets.$button.removeClass("hidden");
- website.snippet.start_animation();
- $(website.snippet.readyAnimation).each(function() {
- var animation = $(this).data("snippet-view");
- if (animation) {
- animation.$target.on('focus', '*', function(){
- animation.stop();
- });
- animation.$target.on('blur', '*', function(){
- animation.start();
- });
- }
- });
+ website.snippet.stop_animation();
});
return this._super.apply(this, arguments);
@@ -56,9 +174,6 @@
}
});
- // 'snippet-dropped' is triggered on '#oe_snippets' whith $target as attribute when a snippet is dropped
- // 'snippet-activated' is triggered on '#oe_snippets' (and on snippet) when a snippet is activated
-
if (!website.snippet) website.snippet = {};
website.snippet.templateOptions = {};
website.snippet.globalSelector = "";
@@ -397,18 +512,17 @@
$("#oe_snippets").trigger('snippet-dropped', $target);
website.snippet.start_animation(true, $target);
-
// drop_and_build_snippet
self.create_overlay($target);
if ($target.data("snippet-editor")) {
- $target.data("snippet-editor").drop_and_build_snippet($target);
+ $target.data("snippet-editor").drop_and_build_snippet();
}
for (var k in website.snippet.templateOptions) {
$target.find(website.snippet.templateOptions[k].selector).each(function () {
var $snippet = $(this);
self.create_overlay($snippet);
if ($snippet.data("snippet-editor")) {
- $snippet.data("snippet-editor").drop_and_build_snippet($snippet);
+ $snippet.data("snippet-editor").drop_and_build_snippet();
}
});
}
@@ -665,80 +779,12 @@
self.set_active();
self.$target.trigger("snippet-style-change", [self, np]);
},0);
- this.select(event, {'$next': $next, '$prev': $prev});
+ this.select({'$next': $next, '$prev': $prev});
} else {
setTimeout(function () {
self.$target.trigger("snippet-style-preview", [self, np]);
},0);
- this.preview(event, np);
- }
- },
- // start is call just after the init
- start: function () {
- },
- /* onFocus
- * This method is called when the user click inside the snippet in the dom
- */
- onFocus : function () {
- },
-
- /* onFocus
- * This method is called when the user click outside the snippet in the dom, after a focus
- */
- onBlur : function () {
- },
-
- /* on_clone
- * This method is called when the snippet is cloned ($clone is allready inserted)
- */
- on_clone: function ($clone) {
- },
-
- /* on_remove
- * This method is called when the snippet is removed (dom is removing after this call)
- */
- on_remove: function () {
- },
-
- /*
- * drop_and_build_snippet
- * This method is called just after that a thumbnail is drag and dropped into a drop zone
- * (after the insertion of this.$body, if this.$body exists)
- */
- drop_and_build_snippet: function ($target) {
- },
- /* select
- * called when a user select an item
- * li must have data-value attribute
- * variables: np = {$next, $prev}
- * $next is false if they are no next item selected
- * $prev is false if they are no previous item selected
- */
- select: function (event, np) {
- var self = this;
- // add or remove html class
- if (np.$prev) {
- this.$target.removeClass(np.$prev.data('value' || ""));
- }
- if (np.$next) {
- this.$target.addClass(np.$next.data('value') || "");
- }
- },
- /* preview
- * called when a user is on mouse over or mouse out of an item
- * variables: np = {$next, $prev}
- * $next is false if they are no next item selected
- * $prev is false if they are no previous item selected
- */
- preview: function (event, np) {
- var self = this;
-
- // add or remove html class
- if (np.$prev) {
- this.$target.removeClass(np.$prev.data('value') || "");
- }
- if (np.$next) {
- this.$target.addClass(np.$next.data('value') || "");
+ this.preview(np);
}
},
/* set_active
@@ -757,9 +803,48 @@
.addClass("active");
this.$el.find('li:has(li[data-value].active)').addClass("active");
},
- /* clean_for_save
- * function called just before save vue
- */
+
+ start: function () {
+ },
+
+ onFocus : function () {
+ },
+
+ onBlur : function () {
+ },
+
+ on_clone: function ($clone) {
+ },
+
+ on_remove: function () {
+ },
+
+ drop_and_build_snippet: function () {
+ },
+
+ select: function (np) {
+ var self = this;
+ // add or remove html class
+ if (np.$prev && this.required) {
+ this.$target.removeClass(np.$prev.data('value' || ""));
+ }
+ if (np.$next) {
+ this.$target.addClass(np.$next.data('value') || "");
+ }
+ },
+
+ preview: function (np) {
+ var self = this;
+
+ // add or remove html class
+ if (np.$prev && this.required) {
+ this.$target.removeClass(np.$prev.data('value') || "");
+ }
+ if (np.$next) {
+ this.$target.addClass(np.$next.data('value') || "");
+ }
+ },
+
clean_for_save: function () {
}
});
@@ -776,9 +861,9 @@
var src = this._get_bg();
this.$el.find("li[data-value].active.oe_custom_bg").data("src", src);
},
- select: function(event, np) {
+ select: function(np) {
var self = this;
- this._super(event, np);
+ this._super(np);
if (np.$next) {
if (np.$next.hasClass("oe_custom_bg")) {
var editor = new website.editor.ImageDialog();
@@ -803,8 +888,8 @@
this.$target.removeClass(np.$prev.data("value"));
}
},
- preview: function (event, np) {
- this._super(event, np);
+ preview: function (np) {
+ this._super(np);
if (np.$next) {
this._set_bg(np.$next.data("src"));
}
@@ -872,6 +957,7 @@
start : function () {
var self = this;
this._super();
+ this.$target.carousel({interval: false});
this.id = this.$target.attr("id");
this.$inner = this.$target.find('.carousel-inner');
this.$indicators = this.$target.find('.carousel-indicators');
@@ -1003,7 +1089,7 @@
this.$target.find('.carousel-control').off('click').on('click', function () {
self.$target.carousel( $(this).data('slide')); });
- this.$target.find('.carousel-inner .content > div').attr('contentEditable', 'true');
+ this.$target.find('.carousel-image, .carousel-inner .content > div').attr('contentEditable', 'true');
this.$target.find('.carousel-image').attr('attributeEditable', 'true');
this._super();
},
@@ -1021,7 +1107,7 @@
if (resize_values.w) this.$overlay.find(".oe_handle.w").removeClass("readonly");
if (resize_values.size) this.$overlay.find(".oe_handle.size").removeClass("readonly");
- this.$overlay.find(".oe_handle:not(:has(.oe_handle_button)), .oe_handle .oe_handle_button").on('mousedown', function (event){
+ this.$overlay.find(".oe_handle:not(.size), .oe_handle.size .size").on('mousedown', function (event){
event.preventDefault();
var $handle = $(this);
@@ -1123,6 +1209,11 @@
$body.mousemove(body_mousemove);
$body.mouseup(body_mouseup);
});
+ this.$overlay.find(".oe_handle.size .auto_size").on('click', function (event){
+ self.$target.css("height", "");
+ self.BuildingBlock.cover_target(self.$overlay, self.$target);
+ return false;
+ });
},
getSize: function () {
this.grid = {};
@@ -1286,15 +1377,6 @@
this.grid.size = 8;
return this.grid;
},
- start: function () {
- var self = this;
- this._super();
- this.$el.find(".js_size_auto").on('click', function (event){
- self.$target.css("height", "");
- self.BuildingBlock.cover_target(self.$overlay, self.$target);
- return false;
- });
- },
});
website.snippet.options.parallax = website.snippet.Option.extend({
@@ -1543,9 +1625,9 @@
* This method is called just after that a thumbnail is drag and dropped into a drop zone
* (after the insertion of this.$body, if this.$body exists)
*/
- drop_and_build_snippet: function ($target) {
+ drop_and_build_snippet: function () {
for (var i in this.styles){
- this.styles[i].drop_and_build_snippet($target);
+ this.styles[i].drop_and_build_snippet();
}
},
diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js
index 61b8f851339..b7e55fe166b 100644
--- a/addons/website/static/src/js/website.tour.js
+++ b/addons/website/static/src/js/website.tour.js
@@ -1,11 +1,30 @@
(function () {
'use strict';
-var website = openerp.website;
+// raise an error in test mode if openerp don't exist
+if (typeof openerp === "undefined") {
+ var error = "openerp is undefined"
+ + "\nhref: " + window.location.href
+ + "\nreferrer: " + document.referrer
+ + "\nlocalStorage: " + JSON.stringify(window.localStorage);
+ if (typeof $ !== "undefined") {
+ error += '\n\n' + $("body").html();
+ }
+ throw new Error(error);
+}
+
+var website = window.openerp.website;
+
+// don't rewrite website.Tour in test mode
+if (typeof website.Tour !== "undefined") {
+ return;
+}
// don't need template to use bootstrap Tour in automatic mode
-if (typeof QWeb2 !== "undefined")
-website.add_template_file('/website/static/src/xml/website.tour.xml');
+if (typeof QWeb2 !== "undefined") {
+ website.add_template_file('/website/static/src/xml/website.tour.xml');
+
+}
// don't need to use bootstrap Tour to launch an automatic tour
function bootstrap_tour_stub () {
@@ -19,27 +38,28 @@ function bootstrap_tour_stub () {
-if (website.EditorBar)
-website.EditorBar.include({
- tours: [],
- start: function () {
- var self = this;
- var menu = $('#help-menu');
- _.each(this.tours, function (tour) {
- var $menuItem = $($.parseHTML('
'+tour.name+''));
- $menuItem.click(function () {
- tour.reset();
- tour.run();
+if (website.EditorBar) {
+ website.EditorBar.include({
+ tours: [],
+ start: function () {
+ var self = this;
+ var menu = $('#help-menu');
+ _.each(this.tours, function (tour) {
+ var $menuItem = $($.parseHTML('
'+tour.name+''));
+ $menuItem.click(function () {
+ tour.reset();
+ tour.run();
+ });
+ menu.append($menuItem);
});
- menu.append($menuItem);
- });
- return this._super();
- },
- registerTour: function (tour) {
- website.Tour.add(tour);
- this.tours.push(tour);
- }
-});
+ return this._super();
+ },
+ registerTour: function (tour) {
+ website.Tour.add(tour);
+ this.tours.push(tour);
+ }
+ });
+}
/////////////////////////////////////////////////
@@ -308,7 +328,8 @@ website.Tour = openerp.Class.extend({
self.timer = setTimeout(checkNext, self.defaultDelay);
} else {
self.reset();
- throw new Error("Time overlaps to arrive to step " + step.stepId + ": '" + step._title + "'"
+ throw new Error("Can't arrive to step " + step.stepId + ": '" + step._title + "'"
+ + '\nhref: ' + window.location.href
+ '\nelement: ' + Boolean(!step.element || ($(step.element).size() && $(step.element).is(":visible") && !$(step.element).is(":hidden")))
+ '\nwaitNot: ' + Boolean(!step.waitNot || !$(step.waitNot).size())
+ '\nwaitFor: ' + Boolean(!step.waitFor || $(step.waitFor).size())
@@ -363,12 +384,13 @@ website.Tour = openerp.Class.extend({
}
},
endTour: function () {
- if (parseInt(this.localStorage.getItem("tour-"+this.id+"-test"),10) >= this.steps.length-1) {
+ var test = parseInt(this.localStorage.getItem("tour-"+this.id+"-test"),10) >= this.steps.length-1;
+ this.reset();
+ if (test) {
console.log('ok');
} else {
console.log('error');
}
- this.reset();
},
autoNextStep: function () {
var self = this;
diff --git a/addons/website/static/src/js/website.translator.js b/addons/website/static/src/js/website.translator.js
index 2f145f53dc5..5b2ad413395 100644
--- a/addons/website/static/src/js/website.translator.js
+++ b/addons/website/static/src/js/website.translator.js
@@ -71,6 +71,7 @@
},
processTranslatableNodes: function () {
var self = this;
+ var source_attr = 'data-oe-source-id';
var $editables = $('[data-oe-model="ir.ui.view"]')
.not('link, script')
.not('.oe_snippets,.oe_snippet, .oe_snippet *')
@@ -78,7 +79,8 @@
$editables.each(function () {
var $node = $(this);
- var view_id = $node.attr('data-oe-source-id') || $node.attr('data-oe-id');
+ var source_id = $node.parents('[' + source_attr + ']:first').attr(source_attr)|0;
+ var view_id = $node.attr('data-oe-source-id') || source_id || $node.attr('data-oe-id');
self.transNode(this, view_id|0);
});
$('.oe_translatable_text').on('paste', function () {
diff --git a/addons/website/static/src/xml/website.editor.xml b/addons/website/static/src/xml/website.editor.xml
index 09aa3783c3f..6edf553b7cb 100644
--- a/addons/website/static/src/xml/website.editor.xml
+++ b/addons/website/static/src/xml/website.editor.xml
@@ -6,7 +6,7 @@
or
-
Discard
+
Discard
diff --git a/addons/website/static/src/xml/website.snippets.xml b/addons/website/static/src/xml/website.snippets.xml
index 511876b116d..c5cf94d4791 100644
--- a/addons/website/static/src/xml/website.snippets.xml
+++ b/addons/website/static/src/xml/website.snippets.xml
@@ -38,7 +38,10 @@
-
+