diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index 029b3ef4f10..fd2f0db381d 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -2353,6 +2353,11 @@
.openerp .oe_list {
position: relative;
}
+.openerp .oe_list .oe_form .oe_form_nosheet {
+ margin: 0;
+ padding: 0;
+ border: none;
+}
.openerp .oe_list .oe_form .oe_form_field {
width: auto;
position: absolute;
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index 449d76b882b..0efd43dc5ac 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -1841,11 +1841,16 @@ $sheet-max-width: 860px
.oe_list
position: relative
- .oe_form .oe_form_field
- width: auto
- position: absolute
- margin: 0 !important // dammit
- padding: 0
+ .oe_form
+ .oe_form_nosheet
+ margin: 0 // FIXME: either class or border should not be by default
+ padding: 0
+ border: none
+ .oe_form_field
+ width: auto
+ position: absolute
+ margin: 0 !important // dammit
+ padding: 0
.oe_list_content
width: 100%
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 506d08decd7..c2dac62366b 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -3349,6 +3349,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
ListType: instance.web.form.One2ManyList
}));
this.on('edit:before', this, this.proxy('_before_edit'));
+ this.on('edit:after', this, this.proxy('_after_edit'));
this.on('save:before cancel:before', this, this.proxy('_before_unedit'));
this.records
@@ -3459,6 +3460,12 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
this.__ignore_blur = false;
this.editor.form.on('blurred', this, this._on_form_blur);
},
+ _after_edit: function () {
+ // The form's blur thing may be jiggered during the edition setup,
+ // potentially leading to the o2m instasaving the row. Cancel any
+ // blurring triggered the edition startup here
+ this.editor.form.widgetFocused();
+ },
_before_unedit: function () {
this.editor.form.off('blurred', this, this._on_form_blur);
},
@@ -3492,6 +3499,28 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
// the current row *anyway*, then create a new one/edit the next one)
this.__ignore_blur = true;
this._super.apply(this, arguments);
+ },
+ do_delete: function (ids) {
+ var self = this;
+ var next = $.when();
+ var _super = this._super;
+ // handle deletion of an item which does not exist
+ // TODO: better handle that in the editable list?
+ var false_id_index = _(ids).indexOf(false);
+ if (false_id_index !== -1) {
+ ids.splice(false_id_index, 1);
+ next = this.cancel_edition(true);
+ }
+ return next.pipe(function () {
+ // wheeee
+ var confirm = window.confirm;
+ window.confirm = function () { return true; };
+ try {
+ return _super.call(self, ids);
+ } finally {
+ window.confirm = confirm;
+ }
+ });
}
});
instance.web.form.One2ManyList = instance.web.ListView.List.extend({
@@ -3512,27 +3541,34 @@ instance.web.form.One2ManyList = instance.web.ListView.List.extend({
var $cell = $('
', {
colspan: columns,
'class': 'oe_form_field_one2many_list_row_add'
- }).text(_t("Add a row"))
- .mousedown(function () {
- // FIXME: needs to be an official API somehow
- if (self.view.editor.is_editing()) {
- self.view.__ignore_blur = true;
- }
- })
- .click(function (e) {
- e.preventDefault();
- e.stopPropagation();
- // FIXME: there should also be an API for that one
- if (self.view.editor.form.__blur_timeout) {
- clearTimeout(self.view.editor.form.__blur_timeout);
- self.view.editor.form.__blur_timeout = false;
- }
- self.view.ensure_saved().then(function () {
- self.view.do_add_record();
- });
- });
- this.$current.append(
- $(' | ').append($cell))
+ }).append(
+ $('', {href: '#'}).text(_t("Add a row"))
+ .mousedown(function () {
+ // FIXME: needs to be an official API somehow
+ if (self.view.editor.is_editing()) {
+ self.view.__ignore_blur = true;
+ }
+ })
+ .click(function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ // FIXME: there should also be an API for that one
+ if (self.view.editor.form.__blur_timeout) {
+ clearTimeout(self.view.editor.form.__blur_timeout);
+ self.view.editor.form.__blur_timeout = false;
+ }
+ self.view.ensure_saved().then(function () {
+ self.view.do_add_record();
+ });
+ }));
+
+ var $padding = this.$current.find('tr:not([data-id]):first');
+ var $newrow = $('').append($cell);
+ if ($padding.length) {
+ $padding.before($newrow);
+ } else {
+ this.$current.append($newrow)
+ }
}
});
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index 57be3ca6db1..4bce8d639f8 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -674,6 +674,10 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
* Base handling of buttons, can be called when overriding do_button_action
* in order to bypass parent overrides.
*
+ * The callback will be provided with the ``id`` as its parameter, in case
+ * handle_button's caller had to alter the ``id`` (or even create one)
+ * while not being ``callback``'s creator.
+ *
* This method should not be overridden.
*
* @param {String} name action name
@@ -699,7 +703,8 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
c.add(action.context);
}
action.context = c;
- this.do_execute_action(action, this.dataset, id, callback);
+ this.do_execute_action(
+ action, this.dataset, id, _.bind(callback, null, id));
},
/**
* Handles the activation of a record (clicking on it)
@@ -991,8 +996,8 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
// of digits, nice when storing actual numbers, not nice when
// storing strings composed only of digits. Force the action
// name to be a string
- $(self).trigger('action', [field.toString(), record_id, function () {
- return self.reload_record(self.records.get(record_id));
+ $(self).trigger('action', [field.toString(), record_id, function (id) {
+ return self.reload_record(self.records.get(id));
}]);
})
.delegate('a', 'click', function (e) {
diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js
index 038593c54c3..78fef767f5a 100644
--- a/addons/web/static/src/js/view_list_editable.js
+++ b/addons/web/static/src/js/view_list_editable.js
@@ -135,10 +135,13 @@ openerp.web.list_editable = function (instance) {
make_editor: function () {
return new instance.web.list.Editor(this);
},
- do_button_action: function () {
+ do_button_action: function (name, id, callback) {
var self = this, args = arguments;
- this.ensure_saved().then(function () {
- self.handle_button.apply(self, args);
+ this.ensure_saved().then(function (done) {
+ if (!id && done.created) {
+ id = done.record.get('id');
+ }
+ self.handle_button.call(self, name, id, callback);
});
},
/**
@@ -281,16 +284,17 @@ openerp.web.list_editable = function (instance) {
});
},
/**
+ * @param {Boolean} [force=false] discards the data even if the form has been edited
* @return {jQuery.Deferred}
*/
- cancel_edition: function () {
+ cancel_edition: function (force) {
var self = this;
return this.with_event('cancel', {
editor: this.editor,
form: this.editor.form,
cancel: false
}, function () {
- return this.editor.cancel().pipe(function (attrs) {
+ return this.editor.cancel(force).pipe(function (attrs) {
if (attrs.id) {
var record = self.records.get(attrs.id);
if (!record) {
@@ -717,13 +721,13 @@ openerp.web.list_editable = function (instance) {
return self.cancel();
});
},
- cancel: function () {
- var record = this.record;
- this.record = null;
- if (!this.form.can_be_discarded()) {
+ cancel: function (force) {
+ if (!(force || this.form.can_be_discarded())) {
return $.Deferred().reject({
message: "The form's data can not be discarded"}).promise();
}
+ var record = this.record;
+ this.record = null;
this.form.do_hide();
return $.when(record);
}
diff --git a/doc/list-view.rst b/doc/list-view.rst
index 83925d82f46..24c7bb3beb4 100644
--- a/doc/list-view.rst
+++ b/doc/list-view.rst
@@ -160,11 +160,14 @@ Interaction Methods
updated) and ``record`` the reloaded record having been
edited.
-.. js:function:: openerp.web.ListView.cancel_edition
+.. js:function:: openerp.web.ListView.cancel_edition([force=false])
Cancels pending edition, cleans up the list view in case of
creation (removes the empty record being created).
+ :param Boolean force: doesn't check if the user has added any
+ data, discards the edition unconditionally
+
Utility Methods
+++++++++++++++
@@ -345,11 +348,14 @@ formview, delegating instead to its
from when it was passed in, aside from the ``id``
attribute.
- .. js:function:: openerp.web.list.Editor.cancel
+ .. js:function:: openerp.web.list.Editor.cancel([force=false])
Attemps to cancel the edition of the internal form, then hide
the form
+ :param Boolean force: unconditionally cancels the edition of
+ the internal form, even if the user has
+ already entered data in it.
:returns: delegate to the record under edition
.. js:class:: EditorOptions