[MERGE]Merge trunk-website-al.
bzr revid: bth@tinyerp.com-20131024051543-zow19or2yqh5kczn
This commit is contained in:
@@ -7,17 +7,19 @@ Also, adds methods to convert values back to openerp models.
|
||||
"""
|
||||
|
||||
import cStringIO
|
||||
import datetime
|
||||
import itertools
|
||||
import logging
|
||||
import re
|
||||
import urllib2
|
||||
|
||||
import werkzeug.utils
|
||||
from dateutil import parser
|
||||
from lxml import etree, html
|
||||
from PIL import Image as I
|
||||
|
||||
from openerp.osv import orm, fields
|
||||
from openerp.tools import ustr
|
||||
from openerp.tools import ustr, DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
|
||||
REMOTE_CONNECTION_TIMEOUT = 2.5
|
||||
|
||||
@@ -75,19 +77,48 @@ class Float(orm.AbstractModel):
|
||||
return float(value.replace(lang.thousands_sep, '')
|
||||
.replace(lang.decimal_point, '.'))
|
||||
|
||||
|
||||
def parse_fuzzy(in_format, value):
|
||||
day_first = in_format.find('%d') < in_format.find('%m')
|
||||
|
||||
if '%y' in in_format:
|
||||
year_first = in_format.find('%y') < in_format.find('%d')
|
||||
else:
|
||||
year_first = in_format.find('%Y') < in_format.find('%d')
|
||||
|
||||
return parser.parse(value, dayfirst=day_first, yearfirst=year_first)
|
||||
|
||||
class Date(orm.AbstractModel):
|
||||
_name = 'website.qweb.field.date'
|
||||
_inherit = ['website.qweb.field', 'ir.qweb.field.date']
|
||||
|
||||
def from_html(self, cr, uid, model, column, element, context=None):
|
||||
raise NotImplementedError("Can not parse and save localized dates")
|
||||
lang = self.user_lang(cr, uid, context=context)
|
||||
in_format = lang.date_format.encode('utf-8')
|
||||
|
||||
value = element.text_content().strip()
|
||||
try:
|
||||
dt = datetime.datetime.strptime(in_format, value)
|
||||
except ValueError:
|
||||
dt = parse_fuzzy(in_format, value)
|
||||
|
||||
return dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
class DateTime(orm.AbstractModel):
|
||||
_name = 'website.qweb.field.datetime'
|
||||
_inherit = ['website.qweb.field', 'ir.qweb.field.datetime']
|
||||
|
||||
def from_html(self, cr, uid, model, column, element, context=None):
|
||||
raise NotImplementedError("Can not parse and save localized datetimes")
|
||||
lang = self.user_lang(cr, uid, context=context)
|
||||
in_format = (u"%s %s" % (lang.date_format, lang.time_format)).encode('utf-8')
|
||||
|
||||
value = element.text_content().strip()
|
||||
try:
|
||||
dt = datetime.datetime.strptime(in_format, value)
|
||||
except ValueError:
|
||||
dt = parse_fuzzy(in_format, value)
|
||||
|
||||
return dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
class Text(orm.AbstractModel):
|
||||
_name = 'website.qweb.field.text'
|
||||
|
||||
@@ -100,22 +100,24 @@ class view(osv.osv):
|
||||
|
||||
return arch
|
||||
|
||||
def _normalize_urls(self, element):
|
||||
attr = None
|
||||
if element.tag == 'form':
|
||||
attr = 'action' if 'action' in element.attrib else None
|
||||
elif element.tag in ['a', 'link']:
|
||||
attr = 'href' if 'href' in element.attrib else None
|
||||
elif element.tag in ['frame', 'iframe', 'script']:
|
||||
attr = 'src' if 'src' in element.attrib else None
|
||||
if attr:
|
||||
value = element.attrib[attr]
|
||||
URL_ATTRS = {
|
||||
'form': 'action',
|
||||
'a': 'href',
|
||||
'link': 'href',
|
||||
'frame': 'src',
|
||||
'iframe': 'src',
|
||||
'script': 'src',
|
||||
}
|
||||
def _normalize_urls(self, root):
|
||||
for element in root.iter():
|
||||
attr = self.URL_ATTRS.get(element.tag)
|
||||
if attr is None or attr not in element.attrib:
|
||||
continue
|
||||
|
||||
value = element.get(attr)
|
||||
if not urlparse(value).scheme:
|
||||
element.attrib.pop(attr)
|
||||
element.attrib['t-' + attr] = value
|
||||
for el in list(element):
|
||||
self._normalize_urls(el)
|
||||
return element
|
||||
element.set('t-' + attr, value)
|
||||
|
||||
def save(self, cr, uid, res_id, value, xpath=None, context=None):
|
||||
""" Update a view section. The view section may embed fields to write
|
||||
|
||||
@@ -238,10 +238,26 @@ class website(osv.osv):
|
||||
return {
|
||||
"page_count": page_count,
|
||||
"offset": (page - 1) * step,
|
||||
"page": {'url': get_url(page), 'num': page},
|
||||
"page_start": {'url': get_url(pmin), 'num': pmin},
|
||||
"page_end": {'url': get_url(min(pmax, page + 1)),
|
||||
'num': min(pmax, page + 1)},
|
||||
"page": {
|
||||
'url': get_url(page),
|
||||
'num': page
|
||||
},
|
||||
"page_start": {
|
||||
'url': get_url(pmin),
|
||||
'num': pmin
|
||||
},
|
||||
"page_previous": {
|
||||
'url': get_url(max(pmin, page - 1)),
|
||||
'num': max(pmin, page - 1)
|
||||
},
|
||||
"page_next": {
|
||||
'url': get_url(min(pmax, page + 1)),
|
||||
'num': min(pmax, page + 1)
|
||||
},
|
||||
"page_end": {
|
||||
'url': get_url(pmax),
|
||||
'num': pmax
|
||||
},
|
||||
"pages": [
|
||||
{'url': get_url(page), 'num': page}
|
||||
for page in xrange(pmin, pmax+1)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
@charset "utf-8";
|
||||
/* ---- CKEditor Minimal Reset ---- */
|
||||
.navbar.navbar-inverse .cke_chrome {
|
||||
border: none;
|
||||
@@ -174,6 +173,11 @@ table.editorbar-panel td.selected {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.oe_carlos_danger {
|
||||
outline: 1px solid red !important;
|
||||
background-color: #ffd9dd !important;
|
||||
}
|
||||
|
||||
/* ---- SNIPPET EDITOR ---- */
|
||||
#oe_snippets {
|
||||
position: fixed;
|
||||
|
||||
@@ -154,6 +154,10 @@ table.editorbar-panel
|
||||
content: " "
|
||||
white-space: pre-wrap
|
||||
|
||||
.oe_carlos_danger
|
||||
outline: 1px solid red !important
|
||||
background-color: #ffd9dd !important
|
||||
|
||||
/* ---- SNIPPET EDITOR ---- */
|
||||
|
||||
#oe_snippets
|
||||
|
||||
@@ -272,30 +272,58 @@
|
||||
editor.destroy();
|
||||
// FIXME: select editables then filter by dirty?
|
||||
var defs = this.rte.fetch_editables(root)
|
||||
.removeClass('oe_editable cke_focus')
|
||||
.removeAttr('contentEditable')
|
||||
.filter('.oe_dirty')
|
||||
.removeAttr('contentEditable')
|
||||
.removeClass('oe_dirty oe_editable cke_focus oe_carlos_danger')
|
||||
.map(function () {
|
||||
var $el = $(this);
|
||||
// TODO: Add a queue with concurrency limit in webclient
|
||||
// https://github.com/medikoo/deferred/blob/master/lib/ext/function/gate.js
|
||||
return self.saving_mutex.exec(function () {
|
||||
return self.saveElement($el)
|
||||
.fail(function () {
|
||||
var data = $el.data();
|
||||
console.error(_.str.sprintf('Could not save %s(%d).%s', data.oeModel, data.oeId, data.oeField));
|
||||
.then(undefined, function (thing, response) {
|
||||
// because ckeditor regenerates all the dom,
|
||||
// we can't just setup the popover here as
|
||||
// everything will be destroyed by the DOM
|
||||
// regeneration. Add markings instead, and
|
||||
// returns a new rejection with all relevant
|
||||
// info
|
||||
var id = _.uniqueId('carlos_danger_');
|
||||
$el.addClass('oe_dirty oe_carlos_danger');
|
||||
$el.addClass(id);
|
||||
return $.Deferred().reject({
|
||||
id: id,
|
||||
error: response.data,
|
||||
});
|
||||
});
|
||||
});
|
||||
}).get();
|
||||
return $.when.apply(null, defs).then(function () {
|
||||
website.reload();
|
||||
}, function (failed) {
|
||||
// If there were errors, re-enable edition
|
||||
self.rte.start_edition(true).then(function () {
|
||||
// jquery's deferred being a pain in the ass
|
||||
if (!_.isArray(failed)) { failed = [failed]; }
|
||||
|
||||
_(failed).each(function (failure) {
|
||||
$(root).find('.' + failure.id)
|
||||
.removeClass(failure.id)
|
||||
.popover({
|
||||
trigger: 'hover',
|
||||
content: failure.error.message,
|
||||
placement: 'auto top',
|
||||
})
|
||||
// Force-show popovers so users will notice them.
|
||||
.popover('show');
|
||||
})
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Saves an RTE content, which always corresponds to a view section (?).
|
||||
*/
|
||||
saveElement: function ($el) {
|
||||
$el.removeClass('oe_dirty');
|
||||
var markup = $el.prop('outerHTML');
|
||||
return openerp.jsonRpc('/web/dataset/call', 'call', {
|
||||
model: 'ir.ui.view',
|
||||
@@ -422,15 +450,25 @@
|
||||
|
||||
return true;
|
||||
},
|
||||
start_edition: function () {
|
||||
/**
|
||||
* Makes the page editable
|
||||
*
|
||||
* @param {Boolean} [restart=false] in case the edition was already set
|
||||
* up once and is being re-enabled.
|
||||
* @returns {$.Deferred} deferred indicating when the RTE is ready
|
||||
*/
|
||||
start_edition: function (restart) {
|
||||
var self = this;
|
||||
// create a single editor for the whole page
|
||||
var root = document.getElementById('wrapwrap');
|
||||
$(root).on('dragstart', 'img', function (e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
this.webkitSelectionFixer(root);
|
||||
this.tableNavigation(root);
|
||||
if (!restart) {
|
||||
$(root).on('dragstart', 'img', function (e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
this.webkitSelectionFixer(root);
|
||||
this.tableNavigation(root);
|
||||
}
|
||||
var def = $.Deferred();
|
||||
var editor = this.editor = CKEDITOR.inline(root, self._config());
|
||||
editor.on('instanceReady', function () {
|
||||
editor.setReadOnly(false);
|
||||
@@ -446,7 +484,9 @@
|
||||
document.execCommand("enableInlineTableEditing", false, "false");
|
||||
|
||||
self.trigger('rte:ready');
|
||||
def.resolve();
|
||||
});
|
||||
return def;
|
||||
},
|
||||
|
||||
setup_editables: function (root) {
|
||||
|
||||
@@ -263,13 +263,13 @@
|
||||
<template id="pager" name="Pager">
|
||||
<ul t-if="pager['page_count'] > 1" t-attf-class="#{ classname or '' } pagination">
|
||||
<li t-att-class=" 'disabled' if pager['page']['num'] == 1 else '' ">
|
||||
<a t-att-href=" pager['page_start']['url'] if pager['page']['num'] != 1 else '' ">Prev</a>
|
||||
<a t-att-href=" pager['page_previous']['url'] if pager['page']['num'] != 1 else '' ">Prev</a>
|
||||
</li>
|
||||
<t t-foreach="pager['pages']" t-as="page">
|
||||
<li t-att-class=" 'active' if page['num'] == pager['page']['num'] else '' "> <a t-att-href="page['url']" t-raw="page['num']"></a></li>
|
||||
</t>
|
||||
<li t-att-class=" 'disabled' if pager['page']['num'] == pager['page_count'] else '' ">
|
||||
<a t-att-href=" pager['page_end']['url'] if pager['page']['num'] != pager['page_count'] else '' ">Next</a>
|
||||
<a t-att-href=" pager['page_next']['url'] if pager['page']['num'] != pager['page_count'] else '' ">Next</a>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
@@ -463,7 +463,7 @@
|
||||
</thead>
|
||||
</table>
|
||||
<div class="clearfix"/>
|
||||
<a t-href="/shop" class="btn btn-default"><span class="icon-long-arrow-left"/> Continue Shopping</a>
|
||||
<a t-href="/shop" class="btn btn-default mb32"><span class="icon-long-arrow-left"/> Continue Shopping</a>
|
||||
<a t-if="website_sale_order and website_sale_order.order_line" t-href="/shop/checkout/" class="btn btn-primary pull-right mb32">Process Checkout <span class="icon-long-arrow-right"/></a>
|
||||
<div class="oe_structure"/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user