From 38cb3de5183654661d92db6134fa6423f9441261 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 24 Jul 2012 19:05:50 +0200 Subject: [PATCH] [FIX] attempt to make editability handling more logical and simpler to manage. Also less buggy, with a bit o' luck bzr revid: xmo@openerp.com-20120724170550-150vimuk6bvzh8y8 --- addons/web/static/src/js/view_form.js | 13 +++-- addons/web/static/src/js/view_list.js | 3 -- .../web/static/src/js/view_list_editable.js | 44 +++++++++-------- doc/list-view.rst | 49 ++++++++++++------- 4 files changed, 63 insertions(+), 46 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 7a0482a3034..835527b3135 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -3027,8 +3027,11 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ this.viewmanager.on_controller_inited.add_last(function(view_type, controller) { controller.o2m = self; if (view_type == "list") { - if (self.get("effective_readonly")) - controller.set_editable(false); + if (self.get("effective_readonly")) { + controller.on('edit:before', self, function (e) { + e.cancel = true; + }); + } } else if (view_type === "form") { if (self.get("effective_readonly")) { $(".oe_form_buttons", controller.$element).children().remove(); @@ -3301,7 +3304,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({ .value(); }, do_add_record: function () { - if (this.options.editable) { + if (this.editable()) { this._super.apply(this, arguments); } else { var self = this; @@ -4108,10 +4111,12 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend self.dataset, false, _.extend({'deletable': false, 'selectable': !self.options.disable_multiple_selection, - 'read_only': true, 'import_enabled': false, '$buttons': self.$buttonpane, }, self.options.list_view_options || {})); + self.view_list.on('edit:before', self, function (e) { + e.cancel = true; + }); self.view_list.popup = self; self.view_list.appendTo($(".oe_popup_list", self.$element)).pipe(function() { self.view_list.do_show(); diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index f68f1354099..53a8c0126b2 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -21,9 +21,6 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi // whether the view rows can be reordered (via vertical drag & drop) 'reorderable': true, 'action_buttons': true, - // if true, the view can't be editable, ignoring the view's and the context's - // instructions - 'read_only': false, // if true, the 'Import', 'Export', etc... buttons will be shown 'import_enabled': true, }, diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js index f2ce08f12ca..697715f2f77 100644 --- a/addons/web/static/src/js/view_list_editable.js +++ b/addons/web/static/src/js/view_list_editable.js @@ -12,6 +12,8 @@ openerp.web.list_editable = function (instance) { var self = this; this._super.apply(this, arguments); + this._force_editability = null; + this._context_editable = false; this.editor = this.make_editor(); // Stores records of {field, cell}, allows for re-rendering fields // depending on cell state during and after resize events @@ -37,6 +39,11 @@ openerp.web.list_editable = function (instance) { } }); + this.on('edit:before', this, function (event) { + if (!self.editable() || self.editor.is_editing()) { + event.cancel = true; + } + }); this.on('edit:after', this, function () { self.$element.add(self.$buttons).addClass('oe_editing'); }); @@ -62,26 +69,18 @@ openerp.web.list_editable = function (instance) { do_edit: function (index, id, dataset) { _.extend(this.dataset, dataset); }, - /** - * Sets editability status for the list, based on defaults, view - * architecture and the provided flag, if any. - * - * @param {Boolean} [force] forces the list to editability. Sets new row edition status to "bottom". - */ - set_editable: function (force) { - // TODO: fix handling of editability status to be simpler & clearer & more coherent - // If ``force``, set editability to bottom - // otherwise rely on view default - // view' @editable is handled separately as we have not yet - // fetched and processed the view at this point. - this.options.editable = ( - ! this.options.read_only && ((force && "bottom") || this.defaults.editable)); + editable: function () { + if (this.fields_view.arch.attrs.editable || this._context_editable) { + return true; + } + + return this.options.editable; }, /** * Replace do_search to handle editability process */ do_search: function(domain, context, group_by) { - this.set_editable(context['set_editable']); + this._context_editable = !!context.set_editable; this._super.apply(this, arguments); }, /** @@ -89,7 +88,7 @@ openerp.web.list_editable = function (instance) { * as an editable row at the top or bottom of the list) */ do_add_record: function () { - if (this.options.editable) { + if (this.editable()) { this.$element.find('table:first').show(); this.$element.find('.oe_view_nocontent').remove(); this.start_edition(); @@ -103,9 +102,8 @@ openerp.web.list_editable = function (instance) { this.editor.destroy(); } // tree/@editable takes priority on everything else if present. - this.options.editable = ! this.options.read_only && (data.arch.attrs.editable || this.options.editable); var result = this._super(data, grouped); - if (this.options.editable) { + if (this.editable()) { // FIXME: any hook available to ensure this is only done once? this.$buttons .off('click', '.oe_list_save') @@ -210,6 +208,12 @@ openerp.web.list_editable = function (instance) { self.resize_fields(); return record.attributes; }); + }).fail(function () { + // if the start_edition event is cancelled and it was a + // creation, remove the newly-created empty record + if (!record.get('id')) { + self.records.remove(record); + } }); }); }, @@ -379,7 +383,7 @@ openerp.web.list_editable = function (instance) { return this.reload_record(record); }, prepends_on_create: function () { - return this.options.editable === 'top'; + return this.editable() === 'top'; }, setup_events: function () { var self = this; @@ -701,7 +705,7 @@ openerp.web.list_editable = function (instance) { instance.web.ListView.List.include(/** @lends instance.web.ListView.List# */{ row_clicked: function (event) { - if (!this.options.editable) { + if (!this.view.editable()) { return this._super.apply(this, arguments); } var record_id = $(event.currentTarget).data('id'); diff --git a/doc/list-view.rst b/doc/list-view.rst index 0d67c27f963..83925d82f46 100644 --- a/doc/list-view.rst +++ b/doc/list-view.rst @@ -87,34 +87,37 @@ List view edition is an extension to the base listview providing the capability of inline record edition by delegating to an embedded form view. -.. todo:: +Editability status +++++++++++++++++++ - cleanup options and settings for editability configuration. Right - now there are: +The editability status of a list view can be queried through the +:js:func:`~openerp.web.ListView.editable` method, will return a falsy +value if the listview is not currently editable. - ``defaults.editable`` +The editability status is based on three flags: - ``null``, ``"top"`` or ``"bottom"``, generally broken and - useless +``tree/@editable`` - ``context.set_editable`` + If present, can be either ``"top"`` or ``"bottom"``. Either will + make the list view editable, with new records being respectively + created at the top or at the bottom of the view. - forces ``options.editable`` to ``"bottom"`` +``context.set_editable`` - ``view.arch.attrs.editable`` + Boolean flag extracted from a search context (during the + :js:func:`~openerp.web.ListView.do_search`` handler), ``true`` + will make the view editable (from the top), ``false`` or the + absence of the flag is a noop. - same as ``defaults.editable``, but applied separately (after - reloading the view), if absent delegates to - ``options.editable`` which may have been set previously. +``defaults.editable`` - ``options.read_only`` + Like ``tree/@editable``, one of absent (``null``)), ``"top"`` or + ``"bottom"``, fallback for the list view if none of the previous + two flags are set. - force options.editable to false, or something? - - .. note:: can probably be replaced by cancelling ``edit:before`` - - and :js:func:`~openerp.web.ListView.set_editable` which - ultimately behaves weird-as-fuck-ly. +These three flags can only *make* a listview editable, they can *not* +override a previously set flag. To do that, a listview user should +instead cancel :ref:`the edit:before event `. The editable list view module adds a number of methods to the list view, on top of implementing the :js:class:`EditorDelegate` protocol: @@ -219,6 +222,14 @@ view provides a number of dedicated events to its lifecycle. abort its current behavior as soon as possible, and rollback any state modification. + Generally speaking, an event should only be cancelled (by + setting the ``cancel`` flag to ``true``), uncancelling an + event is undefined as event handlers are executed on a + first-come-first-serve basis and later handlers may + re-cancel an uncancelled event. + +.. _listview-edit-before: + ``edit:before`` *cancellable* Invoked before the list view starts editing a record.