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 () {