diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py
index 5ea54abb549..21737a5ee22 100644
--- a/addons/web/controllers/main.py
+++ b/addons/web/controllers/main.py
@@ -95,6 +95,9 @@ def db_list(req, force=False):
return dbs
def db_monodb_redirect(req):
+ return db_redirect(req, not config['list_db'])
+
+def db_redirect(req, match_first_only_if_unique):
db = False
redirect = False
@@ -111,7 +114,7 @@ def db_monodb_redirect(req):
db = cookie_db
# 3 use the first db if user can list databases
- if dbs and not db and (config['list_db'] or len(dbs) == 1):
+ if dbs and not db and (not match_first_only_if_unique or len(dbs) == 1):
db = dbs[0]
# redirect to the chosen db if multiple are available
@@ -123,7 +126,7 @@ def db_monodb_redirect(req):
def db_monodb(req):
# if only one db exists, return it else return False
- return db_monodb_redirect(req)[0]
+ return db_redirect(req, True)[0]
def redirect_with_hash(req, url, code=303):
if req.httprequest.user_agent.browser == 'msie':
@@ -820,7 +823,7 @@ class Database(openerpweb.Controller):
return req.make_response(db_dump,
[('Content-Type', 'application/octet-stream; charset=binary'),
('Content-Disposition', content_disposition(filename, req))],
- {'fileToken': int(token)}
+ {'fileToken': token}
)
except Exception, e:
return simplejson.dumps([[],[{'error': openerp.tools.ustr(e), 'title': _('Backup Database')}]])
@@ -1327,7 +1330,7 @@ class Binary(openerpweb.Controller):
return req.make_response(filecontent,
headers=[('Content-Type', 'application/octet-stream'),
('Content-Disposition', content_disposition(filename, req))],
- cookies={'fileToken': int(token)})
+ cookies={'fileToken': token})
@openerpweb.httprequest
def upload(self, req, callback, ufile):
@@ -1634,7 +1637,7 @@ class ExportFormat(object):
headers=[('Content-Disposition',
content_disposition(self.filename(model), req)),
('Content-Type', self.content_type)],
- cookies={'fileToken': int(token)})
+ cookies={'fileToken': token})
class CSVExport(ExportFormat, http.Controller):
_cp_path = '/web/export/csv'
@@ -1774,6 +1777,6 @@ class Reports(openerpweb.Controller):
('Content-Disposition', content_disposition(file_name, req)),
('Content-Type', report_mimetype),
('Content-Length', len(report))],
- cookies={'fileToken': int(token)})
+ cookies={'fileToken': token})
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index 30413236bf8..bf9013a43c8 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -2918,8 +2918,8 @@
margin: 0 !important;
padding: 0;
}
-.openerp .oe_list .oe_form .oe_form_field_boolean {
- padding: 1px 6px 3px;
+.openerp .oe_list .oe_form .oe_form_field_boolean input {
+ margin: 1px 0 0 10px !important;
}
.openerp .oe_list .oe_list_content .oe_group_header {
background-color: #ededed;
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index 287314c1995..42cfe615d21 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -2311,10 +2311,8 @@ $sheet-padding: 16px
position: absolute
margin: 0 !important // dammit
padding: 0
- .oe_form_field_boolean
- // use padding similar to actual cell to correctly position the
- // checkbox
- padding: 1px 6px 3px
+ .oe_form_field_boolean input
+ margin: 1px 0 0 10px !important
.oe_list_content .oe_group_header
@include vertical-gradient(#fcfcfc, #dedede)
diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js
index 6fc837333b6..7d37dc2261d 100644
--- a/addons/web/static/src/js/coresetup.js
+++ b/addons/web/static/src/js/coresetup.js
@@ -283,6 +283,16 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
CHECK_INTERVAL = 1000, id = _.uniqueId('get_file_frame'),
remove_form = false;
+
+ // iOS devices doesn't allow iframe use the way we do it,
+ // opening a new window seems the best way to workaround
+ if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
+ var params = _.extend({}, options.data || {}, {token: token});
+ var url = this.url(options.url, params);
+ instance.web.unblockUI();
+ return window.open(url);
+ }
+
var $form, $form_data = $('
');
var complete = function () {
diff --git a/addons/web/static/src/js/pyeval.js b/addons/web/static/src/js/pyeval.js
index c8207066ca9..6ce85f8d4a3 100644
--- a/addons/web/static/src/js/pyeval.js
+++ b/addons/web/static/src/js/pyeval.js
@@ -602,6 +602,86 @@ openerp.web.pyeval = function (instance) {
}
});
+ // recursively wraps JS objects passed into the context to attributedicts
+ // which jsonify back to JS objects
+ var wrap = function (value) {
+ if (value === null) { return py.None; }
+
+ switch (typeof value) {
+ case 'undefined': throw new Error("No conversion for undefined");
+ case 'boolean': return py.bool.fromJSON(value);
+ case 'number': return py.float.fromJSON(value);
+ case 'string': return py.str.fromJSON(value);
+ }
+
+ switch(value.constructor) {
+ case Object: return wrapping_dict.fromJSON(value);
+ case Array: return wrapping_list.fromJSON(value);
+ }
+
+ throw new Error("ValueError: unable to wrap " + value);
+ };
+ var wrapping_dict = py.type('wrapping_dict', null, {
+ __init__: function () {
+ this._store = {};
+ },
+ __getitem__: function (key) {
+ var k = key.toJSON();
+ if (!(k in this._store)) {
+ throw new Error("KeyError: '" + k + "'");
+ }
+ return wrap(this._store[k]);
+ },
+ __getattr__: function (key) {
+ return this.__getitem__(py.str.fromJSON(key));
+ },
+ get: function () {
+ var args = py.PY_parseArgs(arguments, ['k', ['d', py.None]]);
+
+ if (!(args.k.toJSON() in this._store)) { return args.d; }
+ return this.__getitem__(args.k);
+ },
+ fromJSON: function (d) {
+ var instance = py.PY_call(wrapping_dict);
+ instance._store = d;
+ return instance;
+ },
+ toJSON: function () {
+ return this._store;
+ },
+ });
+ var wrapping_list = py.type('wrapping_list', null, {
+ __init__: function () {
+ this._store = [];
+ },
+ __getitem__: function (index) {
+ return wrap(this._store[index.toJSON()]);
+ },
+ fromJSON: function (ar) {
+ var instance = py.PY_call(wrapping_list);
+ instance._store = ar;
+ return instance;
+ },
+ toJSON: function () {
+ return this._store;
+ },
+ });
+ var wrap_context = function (context) {
+ for (var k in context) {
+ if (!context.hasOwnProperty(k)) { continue; }
+ var val = context[k];
+
+ if (val === null) { continue; }
+ if (val.constructor === Array) {
+ context[k] = wrapping_list.fromJSON(val);
+ } else if (val.constructor === Object
+ && !py.PY_isInstance(val, py.object)) {
+ context[k] = wrapping_dict.fromJSON(val);
+ }
+ }
+ return context;
+ };
+
var eval_contexts = function (contexts, evaluation_context) {
evaluation_context = _.extend(instance.web.pyeval.context(), evaluation_context || {});
return _(contexts).reduce(function (result_context, ctx) {
@@ -615,8 +695,8 @@ openerp.web.pyeval = function (instance) {
var evaluated = ctx;
switch(ctx.__ref) {
case 'context':
- evaluation_context.context = py.dict.fromJSON(evaluation_context);
- evaluated = py.eval(ctx.__debug, evaluation_context);
+ evaluation_context.context = evaluation_context;
+ evaluated = py.eval(ctx.__debug, wrap_context(evaluation_context));
break;
case 'compound_context':
var eval_context = eval_contexts([ctx.__eval_context]);
@@ -640,9 +720,9 @@ openerp.web.pyeval = function (instance) {
}
switch(domain.__ref) {
case 'domain':
- evaluation_context.context = py.dict.fromJSON(evaluation_context);
+ evaluation_context.context = evaluation_context;
result_domain.push.apply(
- result_domain, py.eval(domain.__debug, evaluation_context));
+ result_domain, py.eval(domain.__debug, wrap_context(evaluation_context)));
break;
case 'compound_domain':
var eval_context = eval_contexts([domain.__eval_context]);
@@ -669,8 +749,8 @@ openerp.web.pyeval = function (instance) {
var evaluated = ctx;
switch(ctx.__ref) {
case 'context':
- evaluation_context.context = py.dict.fromJSON(evaluation_context);
- evaluated = py.eval(ctx.__debug, evaluation_context);
+ evaluation_context.context = evaluation_context;
+ evaluated = py.eval(ctx.__debug, wrap_context(evaluation_context));
break;
case 'compound_context':
var eval_context = eval_contexts([ctx.__eval_context]);
@@ -712,7 +792,6 @@ openerp.web.pyeval = function (instance) {
instance.web.pyeval.eval = function (type, object, context, options) {
options = options || {};
context = _.extend(instance.web.pyeval.context(), context || {});
- context['context'] = py.dict.fromJSON(context);
//noinspection FallthroughInSwitchStatementJS
switch(type) {
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index cef92ccf293..5d06d75573f 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -1174,7 +1174,7 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
return $.when(_.map(facet_values, function (facet_value) {
return {
label: _.str.sprintf(self.completion_label.toString(),
- facet_value.label),
+ _.escape(facet_value.label)),
facet: self.make_facet([facet_value])
}
}));
@@ -1342,8 +1342,8 @@ instance.web.search.CharField = instance.web.search.Field.extend( /** @lends ins
if (_.isEmpty(value)) { return $.when(null); }
var label = _.str.sprintf(_.str.escapeHTML(
_t("Search %(field)s for: %(value)s")), {
- field: '
' + this.attrs.string + '',
- value: '
' + _.str.escapeHTML(value) + ''});
+ field: '
' + _.escape(this.attrs.string) + '',
+ value: '
' + _.escape(value) + ''});
return $.when([{
label: label,
facet: {
@@ -1360,8 +1360,8 @@ instance.web.search.NumberField = instance.web.search.Field.extend(/** @lends in
if (isNaN(val)) { return $.when(); }
var label = _.str.sprintf(
_t("Search %(field)s for: %(value)s"), {
- field: '
' + this.attrs.string + '',
- value: '
' + _.str.escapeHTML(value) + ''});
+ field: '
' + _.escape(this.attrs.string) + '',
+ value: '
' + _.escape(value) + ''});
return $.when([{
label: label,
facet: {
@@ -1449,13 +1449,13 @@ instance.web.search.SelectionField = instance.web.search.Field.extend(/** @lends
})
.map(function (sel) {
return {
- label: sel[1],
+ label: _.escape(sel[1]),
facet: facet_from(self, sel)
};
}).value();
if (_.isEmpty(results)) { return $.when(null); }
return $.when.call(null, [{
- label: this.attrs.string
+ label: _.escape(this.attrs.string)
}].concat(results));
},
facet_for: function (value) {
@@ -1493,7 +1493,7 @@ instance.web.search.DateField = instance.web.search.Field.extend(/** @lends inst
var date_string = instance.web.format_value(d, this.attrs);
var label = _.str.sprintf(_.str.escapeHTML(
_t("Search %(field)s at: %(value)s")), {
- field: '
' + this.attrs.string + '',
+ field: '
' + _.escape(this.attrs.string) + '',
value: '
' + date_string + ''});
return $.when([{
label: label,
@@ -1540,10 +1540,10 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
context: context
}).then(function (results) {
if (_.isEmpty(results)) { return null; }
- return [{label: self.attrs.string}].concat(
+ return [{label: _.escape(self.attrs.string)}].concat(
_(results).map(function (result) {
return {
- label: result[1],
+ label: _.escape(result[1]),
facet: facet_from(self, result)
};
}));
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 5eafbf85ef5..33bca889dc0 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -722,7 +722,10 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
self.trigger("save", result);
self.to_view_mode();
}).then(function(result) {
- self.ViewManager.ActionManager.__parentedParent.menu.do_reload_needaction();
+ var parent = self.ViewManager.ActionManager.getParent();
+ if(parent){
+ parent.menu.do_reload_needaction();
+ }
});
},
on_button_cancel: function(event) {
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index 60e2b50bbce..e24b9894e3f 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -470,6 +470,20 @@ instance.web.ActionManager = instance.web.Widget.extend({
}).then(function(res) {
action = _.clone(action);
action.context = res.context;
+
+ // iOS devices doesn't allow iframe use the way we do it,
+ // opening a new window seems the best way to workaround
+ if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
+ var params = {
+ action: JSON.stringify(action),
+ token: new Date().getTime()
+ }
+ var url = self.session.url('/web/report', params)
+ instance.web.unblockUI();
+ $('
')[0].click();
+ return;
+ }
+
var c = instance.webclient.crashmanager;
return $.Deferred(function (d) {
self.session.get_file({
diff --git a/addons/web/static/test/evals.js b/addons/web/static/test/evals.js
index 2cc3655a0aa..8e9fb682e0c 100644
--- a/addons/web/static/test/evals.js
+++ b/addons/web/static/test/evals.js
@@ -704,6 +704,73 @@ openerp.testing.section('eval.contexts', {
}]);
deepEqual(result, {type: 'out_invoice'});
});
+ test('return-input-value', function (instance) {
+ var result = instance.web.pyeval.eval('contexts', [{
+ __ref: 'compound_context',
+ __contexts: ["{'line_id': line_id , 'journal_id': journal_id }"],
+ __eval_context: {
+ __ref: 'compound_context',
+ __contexts: [{
+ __ref: 'compound_context',
+ __contexts: [
+ {lang: 'en_US', tz: 'Europe/Paris', uid: 1},
+ {lang: 'en_US', tz: 'Europe/Paris', uid: 1},
+ {}
+ ],
+ __eval_context: null,
+ }, {
+ active_id: false,
+ active_ids: [],
+ active_model: 'account.move',
+ amount: 0,
+ company_id: 1,
+ date: '2013-06-21',
+ id: false,
+ journal_id: 14,
+ line_id: [
+ [0, false, {
+ account_id: 55,
+ amount_currency: 0,
+ analytic_account_id: false,
+ credit: 0,
+ currency_id: false,
+ date_maturity: false,
+ debit: 0,
+ name: "dscsd",
+ partner_id: false,
+ tax_amount: 0,
+ tax_code_id: false,
+ }]
+ ],
+ name: '/',
+ narration: false,
+ parent: {},
+ partner_id: false,
+ period_id: 6,
+ ref: false,
+ state: 'draft',
+ to_check: false,
+ }],
+ __eval_context: null,
+ },
+ }]);
+ deepEqual(result, {
+ journal_id: 14,
+ line_id: [[0, false, {
+ account_id: 55,
+ amount_currency: 0,
+ analytic_account_id: false,
+ credit: 0,
+ currency_id: false,
+ date_maturity: false,
+ debit: 0,
+ name: "dscsd",
+ partner_id: false,
+ tax_amount: 0,
+ tax_code_id: false,
+ }]],
+ });
+ });
});
openerp.testing.section('eval.domains', {
dependencies: ['web.coresetup', 'web.dates']
diff --git a/addons/web_calendar/static/src/js/calendar.js b/addons/web_calendar/static/src/js/calendar.js
index 8da2ad43819..a0945836fd6 100644
--- a/addons/web_calendar/static/src/js/calendar.js
+++ b/addons/web_calendar/static/src/js/calendar.js
@@ -395,10 +395,19 @@ instance.web_calendar.CalendarView = instance.web.View.extend({
});
},
get_range_domain: function() {
- var format = instance.web.date_to_str,
- domain = this.last_search[0].slice(0);
- domain.unshift([this.date_start, '>=', format(this.range_start.clone().addDays(-6))]);
- domain.unshift([this.date_start, '<=', format(this.range_stop.clone().addDays(6))]);
+ var format = instance.web.date_to_str;
+ var A = format(this.range_start.clone().addDays(-6));
+ var B = format(this.range_stop.clone().addDays(6));
+ var domain = [
+ '&', [this.date_start, '>=', A], [this.date_start, '<=', B]
+ ];
+ if (this.date_stop) {
+ domain.push(
+ '&', [this.date_stop, '>=', A], [this.date_stop, '<=', B],
+ '&', [this.date_start, '<', A], [this.date_stop, '>', B]);
+ domain.unshift("|", "|");
+ }
+ domain.concat(this.last_search[0].slice(0))
return domain;
},
do_show: function () {