diff --git a/addons/web/common/http.py b/addons/web/common/http.py index 453484acee7..314ac8ce717 100644 --- a/addons/web/common/http.py +++ b/addons/web/common/http.py @@ -227,7 +227,7 @@ class HttpRequest(WebRequest): _logger.debug("%s --> %s.%s %r", self.httprequest.method, controller.__class__.__name__, method.__name__, akw) r = method(controller, self, **self.params) if self.debug or 1: - if isinstance(r, werkzeug.wrappers.BaseResponse): + if isinstance(r, (werkzeug.wrappers.BaseResponse, werkzeug.exceptions.HTTPException)): _logger.debug('<-- %s', r) else: _logger.debug("<-- size: %s", len(r)) @@ -395,7 +395,8 @@ class Root(object): else: response = result - response.set_cookie(self.session_cookie, session.sid) + if hasattr(response, 'set_cookie'): + response.set_cookie(self.session_cookie, session.sid) return response(environ, start_response) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 1742bd91c95..588c065b03b 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -5,15 +5,16 @@ openerp.web.chrome = function(openerp) { var QWeb = openerp.web.qweb; openerp.web.Notification = openerp.web.Widget.extend(/** @lends openerp.web.Notification# */{ - /** - * @constructs openerp.web.Notification - * @extends openerp.web.Widget - * - * @param parent - * @param element_id - */ - init: function(parent, element_id) { - this._super(parent, element_id); + template: 'Notification', + identifier_prefix: 'notification-', + + init: function() { + this._super.apply(this, arguments); + openerp.notification = this; + }, + + start: function() { + this._super.apply(this, arguments); this.$element.notify({ speed: 500, expires: 1500 @@ -28,9 +29,12 @@ openerp.web.Notification = openerp.web.Widget.extend(/** @lends openerp.web.Not warn: function(title, text) { this.$element.notify('create', 'oe_notification_alert', { title: title, - text: text + text: text, + }, { + expires: false, }); - } + }, + }); openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog# */{ @@ -369,7 +373,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database } $db_list.find(':selected').remove(); self.db_list.splice(_.indexOf(self.db_list, db, true), 1); - self.notification.notify("Dropping database", "The database '" + db + "' has been dropped"); + self.do_notify("Dropping database", "The database '" + db + "' has been dropped"); }); } }); @@ -454,7 +458,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database self.display_error(result); return; } - self.notification.notify("Changed Password", "Password has been changed successfully"); + self.do_notify("Changed Password", "Password has been changed successfully"); }); } }); @@ -788,9 +792,8 @@ openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{ }, start: function() { this.$secondary_menu.addClass(this.folded ? 'oe_folded' : 'oe_unfolded'); - this.reload(); }, - reload: function() { + do_reload: function() { this.rpc("/web/menu/load", {}, this.on_loaded); }, on_loaded: function(data) { @@ -939,14 +942,12 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie } this.$element.html(QWeb.render("Interface", params)); + this.notification = new openerp.web.Notification(); this.session = new openerp.web.Session(); this.loading = new openerp.web.Loading(this,"oe_loading"); this.crashmanager = new openerp.web.CrashManager(this); this.crashmanager.start(); - // Do you autorize this ? will be replaced by notify() in controller - openerp.web.Widget.prototype.notification = new openerp.web.Notification(this, "oe_notification"); - this.header = new openerp.web.Header(this); this.login = new openerp.web.Login(this); this.header.on_logout.add(this.login.on_logout); @@ -966,12 +967,27 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie }, start: function() { + this._super.apply(this, arguments); + this.notification.prependTo(this.$element); this.header.appendTo($("#oe_header")); this.session.start(); this.login.appendTo($('#oe_login')); this.menu.start(); }, + do_reload: function() { + this.session.session_restore(); + this.menu.do_reload(); + }, + do_notify: function() { + var n = this.notification; + n.notify.apply(n, arguments); + }, + do_warn: function() { + var n = this.notification; + n.warn.apply(n, arguments); + }, on_logged: function() { + this.menu.do_reload(); if(this.action_manager) this.action_manager.stop(); this.action_manager = new openerp.web.ActionManager(this); @@ -1058,7 +1074,8 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie this.action_manager.do_action(action); }, do_about: function() { - } + }, + }); }; diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index ea0824fb1df..1eaffcd0e30 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -610,44 +610,120 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({ on_default_get: function(res) { this.last_default_get = res; }, + /** + * Makes sure this dataset has the fields_get for its model stored locally, + * so create/write methods are able to determine if written fields are m2os + * and can name_get those fields if that's the case (in order to cache a + * correct m2o value for them) + * + * @returns {$.Deferred} whether the fields_get is done executing, provides the fields_get value to its callbacks + */ + ensure_has_fields: function () { + var self = this; + + if (this.fields_get) { + var d = $.Deferred(); + setTimeout(function () { d.resolve(self.fields_get, true); }, 0); + return d.promise(); + } else { + return self.call('fields_get', [], function (fields_get) { + self.fields_get = fields_get; + }); + } + }, + /** + * Relational fields may not be written in the same format they are read. + * + * Since the BufferedDataSet is a bit dumb, it returns what it's got stored + * in its cache, which for modified value is what it was given. This breaks + * some basic contracts of openerp such as m2o read being in the + * ``name_get`` format. + * + * Because create & write are supposed to be asynchronous, though, it + * should be easy to just name_get all incorrect values. + * + * @param {Object} data form-data to write to the cache + * @returns {$.Deferred} resolved with a fixed data dictionary + */ + fix_relational: function (data) { + var self = this; + var results = $.Deferred(); + this.ensure_has_fields().then(function (fields) { + var fields_to_fix = _(fields).chain() + .map(function (d, k) { return {key: k, descriptor: d}; }) + .filter(function (field) { + // keep m2o fields which are in the data dict + return field.descriptor.type === 'many2one' && + data[field.key]; + }).pluck('key') + .value(); + var name_gets = _(fields_to_fix).map(function (field) { + return new openerp.web.DataSet(self, self.fields_get[field].relation) + .name_get([data[field]], null); + }); + // null-concat forces stupid bastard `when` to always return an + // array containing the Array-ified results of all the name_gets. + // otherwise, if there's a single field to fix it returns the + // results of the unique name_get directly. + $.when.apply(null, name_gets.concat([null])).then(function () { + var record = _.extend({}, data); + for(var i=0; i 0 ? v_context : f_context; + return ctx; + }, + build_domain: function() { + var f_domain = this.field.domain || []; + var n_domain = this.node.attrs.domain || null; + // if there is a domain on the node, overrides the model's domain + var final_domain = n_domain !== null ? n_domain : f_domain; + if (!(final_domain instanceof Array)) { + var fields_values = this._build_eval_context(); + final_domain = new openerp.web.CompoundDomain(final_domain).set_eval_context(fields_values); + } + return final_domain; } }); @@ -956,9 +1001,16 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({ }, on_confirmed: function() { var self = this; + + var context = this.node.attrs.context; + if (context && context.__ref) { + context = new openerp.web.CompoundContext(context); + context.set_eval_context(this._build_eval_context()); + } return this.view.do_execute_action( - this.node.attrs, this.view.dataset, this.view.datarecord.id, function () { + _.extend({}, this.node.attrs, {context: context}), + this.view.dataset, this.view.datarecord.id, function () { self.view.reload(); }); }, @@ -1105,51 +1157,6 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f this.invalid = false; }, focus: function() { - }, - _build_view_fields_values: function() { - var a_dataset = this.view.dataset; - var fields_values = this.view.get_fields_values(); - var parent_values = a_dataset.parent_view ? a_dataset.parent_view.get_fields_values() : {}; - fields_values.parent = parent_values; - return fields_values; - }, - _build_eval_context: function() { - var a_dataset = this.view.dataset; - return new openerp.web.CompoundContext(a_dataset.get_context(), this._build_view_fields_values()); - }, - /** - * Builds a new context usable for operations related to fields by merging - * the fields'context with the action's context. - */ - build_context: function() { - var f_context = this.field.context || {}; - if (!!f_context.__ref) { - var fields_values = this._build_eval_context(); - f_context = new openerp.web.CompoundDomain(f_context).set_eval_context(fields_values); - } - // maybe the default_get should only be used when we do a default_get? - var v_contexts = _.compact([this.node.attrs.default_get || null, - this.node.attrs.context || null]); - var v_context = new openerp.web.CompoundContext(); - _.each(v_contexts, function(x) {v_context.add(x);}); - if (_.detect(v_contexts, function(x) {return !!x.__ref;})) { - var fields_values = this._build_eval_context(); - v_context.set_eval_context(fields_values); - } - // if there is a context on the node, overrides the model's context - var ctx = v_contexts.length > 0 ? v_context : f_context; - return ctx; - }, - build_domain: function() { - var f_domain = this.field.domain || []; - var n_domain = this.node.attrs.domain || null; - // if there is a domain on the node, overrides the model's domain - var final_domain = n_domain !== null ? n_domain : f_domain; - if (!(final_domain instanceof Array)) { - var fields_values = this._build_eval_context(); - final_domain = new openerp.web.CompoundDomain(final_domain).set_eval_context(fields_values); - } - return final_domain; } }); @@ -1195,7 +1202,7 @@ openerp.web.form.FieldEmail = openerp.web.form.FieldChar.extend({ }, on_button_clicked: function() { if (!this.value || !this.is_valid()) { - this.notification.warn("E-mail error", "Can't send email to invalid e-mail address"); + this.do_warn("E-mail error", "Can't send email to invalid e-mail address"); } else { location.href = 'mailto:' + this.value; } @@ -1210,7 +1217,7 @@ openerp.web.form.FieldUrl = openerp.web.form.FieldChar.extend({ }, on_button_clicked: function() { if (!this.value) { - this.notification.warn("Resource error", "This resource is empty"); + this.do_warn("Resource error", "This resource is empty"); } else { window.open(this.value); } @@ -2476,7 +2483,6 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp this.setup_form_view(); }, on_write: function(id, data) { - this.stop(); if (!this.options.auto_write) return; var self = this; @@ -2499,7 +2505,9 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp $buttons.html(QWeb.render("FormOpenPopup.form.buttons")); var $nbutton = $buttons.find(".oe_formopenpopup-form-save"); $nbutton.click(function() { - self.view_form.do_save(); + self.view_form.do_save().then(function() { + self.stop(); + }); }); var $cbutton = $buttons.find(".oe_formopenpopup-form-close"); $cbutton.click(function() { @@ -2626,7 +2634,7 @@ openerp.web.form.FieldBinary = openerp.web.form.Field.extend({ on_file_uploaded: function(size, name, content_type, file_base64) { delete(window[this.iframe]); if (size === false) { - this.notification.warn("File Upload", "There was a problem while uploading your file"); + this.do_warn("File Upload", "There was a problem while uploading your file"); // TODO: use openerp web crashmanager console.warn("Error while uploading file : ", name); } else { @@ -2640,7 +2648,7 @@ openerp.web.form.FieldBinary = openerp.web.form.Field.extend({ }, on_save_as: function() { if (!this.view.datarecord.id) { - this.notification.warn("Can't save file", "The record has not yet been saved"); + this.do_warn("Can't save file", "The record has not yet been saved"); } else { var url = '/web/binary/saveas?session_id=' + this.session.session_id + '&model=' + this.view.dataset.model +'&id=' + (this.view.datarecord.id || '') + '&field=' + this.name + diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js index 826508eaa27..4cc081a6266 100644 --- a/addons/web/static/src/js/view_list_editable.js +++ b/addons/web/static/src/js/view_list_editable.js @@ -194,7 +194,7 @@ openerp.web.list_editable = function (openerp) { } self.edition = true; self.edition_id = record_id; - self.edition_form = _.extend(new openerp.web.ListEditableFormView(self, self.dataset, false), { + self.edition_form = _.extend(new openerp.web.ListEditableFormView(self.view, self.dataset, false), { form_template: 'ListView.row.form', registry: openerp.web.list.form.widgets, $element: $new_row diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 8976887035a..d4fc7b55bb2 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -123,8 +123,8 @@ db.web.ActionManager = db.web.Widget.extend({ } if (this.dialog && action.context) { var model = action.context.active_model; - if (model === 'base.module.upgrade' || model === 'base.setup.installer') { - db.webclient.menu.reload(); + if (model === 'base.module.upgrade' || model === 'base.setup.installer' || model === 'base.module.upgrade') { + db.webclient.do_reload(); } } this.dialog_stop(); @@ -903,7 +903,7 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{ var view_editor = new db.web.ViewEditor(this, this.$element, this.dataset, this.fields_view.arch); view_editor.start(); } else { - this.notification.warn("Manage Views", "Could not find current view declaration"); + this.do_warn("Manage Views", "Could not find current view declaration"); } }, on_sidebar_edit_workflow: function() { diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 2a1030676b5..8baf7ce561e 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -2,9 +2,8 @@ - -
-
+ +
x

#{title}

@@ -17,6 +16,9 @@

#{text}

+
+ +
diff --git a/addons/web_calendar/static/src/js/calendar.js b/addons/web_calendar/static/src/js/calendar.js index de2ae89b91e..459c44d699a 100644 --- a/addons/web_calendar/static/src/js/calendar.js +++ b/addons/web_calendar/static/src/js/calendar.js @@ -3,6 +3,7 @@ *---------------------------------------------------------*/ openerp.web_calendar = function(openerp) { +var _t = openerp.web._t; var QWeb = openerp.web.qweb; QWeb.add_template('/web_calendar/static/src/xml/web_calendar.xml'); openerp.web.views.add('calendar', 'openerp.web_calendar.CalendarView'); diff --git a/addons/web_dashboard/static/src/js/dashboard.js b/addons/web_dashboard/static/src/js/dashboard.js index 0eac5623b45..74393684ad2 100644 --- a/addons/web_dashboard/static/src/js/dashboard.js +++ b/addons/web_dashboard/static/src/js/dashboard.js @@ -485,9 +485,8 @@ openerp.web_dashboard.ApplicationTiles = openerp.web.View.extend({ var self = this; new openerp.web.DataSet(this, 'res.config').call('start', [[]], function (action) { $.unblockUI(); - self.do_action(action, function () { - // TODO: less brutal reloading - window.location.reload(true); + self.widget_parent.widget_parent.do_action(action, function () { + openerp.webclient.do_reload(); }); }); }