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();
.value();
},
do_add_record: function () {
- if (this.options.editable) {
+ if (this.editable()) {
this._super.apply(this, arguments);
} else {
var self = this;
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();
// 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,
},
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
}
});
+ 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');
});
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);
},
/**
* 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();
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')
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);
+ }
});
});
},
return this.reload_record(record);
},
prepends_on_create: function () {
- return this.options.editable === 'top';
+ return this.editable() === 'top';
},
setup_events: function () {
var self = this;
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');
capability of inline record edition by delegating to an embedded form
view.
-.. todo::
-
- cleanup options and settings for editability configuration. Right
- now there are:
-
- ``defaults.editable``
+Editability status
+++++++++++++++++++
- ``null``, ``"top"`` or ``"bottom"``, generally broken and
- useless
+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.
- ``context.set_editable``
+The editability status is based on three flags:
- forces ``options.editable`` to ``"bottom"``
+``tree/@editable``
- ``view.arch.attrs.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.
- same as ``defaults.editable``, but applied separately (after
- reloading the view), if absent delegates to
- ``options.editable`` which may have been set previously.
+``context.set_editable``
- ``options.read_only``
+ 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.
- force options.editable to false, or something?
+``defaults.editable``
- .. note:: can probably be replaced by cancelling ``edit:before``
+ Like ``tree/@editable``, one of absent (``null``)), ``"top"`` or
+ ``"bottom"``, fallback for the list view if none of the previous
+ two flags are set.
- 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 <listview-edit-before>`.
The editable list view module adds a number of methods to the list
view, on top of implementing the :js:class:`EditorDelegate` protocol:
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.