diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index e05a53194c3..67218e5decd 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -1063,7 +1063,11 @@ var FieldOne2Many = FieldX2Many.extend({ ev.stopPropagation(); if (this.editable) { - if (!this.creatingRecord) { + if (!this.activeActions.create) { + if (ev.data.onFail) { + ev.data.onFail(); + } + } else if (!this.creatingRecord) { this.creatingRecord = true; this._setValue({ operation: 'CREATE', diff --git a/addons/web/static/src/js/views/list/list_controller.js b/addons/web/static/src/js/views/list/list_controller.js index 3b74f140e4d..33637e53f52 100644 --- a/addons/web/static/src/js/views/list/list_controller.js +++ b/addons/web/static/src/js/views/list/list_controller.js @@ -313,7 +313,11 @@ var ListController = BasicController.extend({ */ _onAddRecord: function (event) { event.stopPropagation(); - this._addRecord(); + if (this.activeActions.create) { + this._addRecord(); + } else if (event.data.onFail) { + event.data.onFail(); + } }, /** * Handles a click on a button by performing its action. diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js index 3cd93bb6e8b..c5f65ecc6e2 100644 --- a/addons/web/static/src/js/views/list/list_editable_renderer.js +++ b/addons/web/static/src/js/views/list/list_editable_renderer.js @@ -341,7 +341,12 @@ ListRenderer.include({ if (this.currentRow < this.state.data.length - 1) { this._selectCell(this.currentRow + 1, 0); } else { - this.unselectRow().then(this.trigger_up.bind(this, 'add_record')); + var self = this; + this.unselectRow().then(function () { + self.trigger_up('add_record', { + onFail: self._selectCell.bind(self, 0, 0, {}), + }); + }); } }, /** diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 4b33af9f0a6..2ac373dbcd0 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -19,6 +19,7 @@ QUnit.module('Views', { int_field: {string: "int_field", type: "integer", sortable: true}, qux: {string: "my float", type: "float"}, m2o: {string: "M2O field", type: "many2one", relation: "bar"}, + o2m: {string: "O2M field", type: "one2many", relation: "bar"}, m2m: {string: "M2M field", type: "many2many", relation: "bar"}, amount: {string: "Monetary field", type: "monetary"}, currency_id: {string: "Currency", type: "many2one", @@ -1994,6 +1995,80 @@ QUnit.module('Views', { list.destroy(); }); + QUnit.test('navigation with tab on a list with create="0"', function (assert) { + assert.expect(4); + + var list = createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: '' + + '' + + '', + }); + + assert.strictEqual(list.$('.o_data_row').length, 4, + "the list should contain 4 rows"); + + list.$('.o_data_row:nth(2) .o_data_cell:first').click(); + assert.ok(list.$('.o_data_row:nth(2)').hasClass('o_selected_row'), + "third row should be in edition"); + + // Press 'Tab' -> should go to next line + list.$('.o_selected_row input').trigger({type: 'keydown', which: 9}); + assert.ok(list.$('.o_data_row:nth(3)').hasClass('o_selected_row'), + "fourth row should be in edition"); + + // Press 'Tab' -> should go back to first line as the create action isn't available + list.$('.o_selected_row input').trigger({type: 'keydown', which: 9}); + assert.ok(list.$('.o_data_row:first').hasClass('o_selected_row'), + "first row should be in edition"); + + list.destroy(); + }); + + + QUnit.test('navigation with tab on a one2many list with create="0"', function (assert) { + assert.expect(4); + + this.data.foo.records[0].o2m = [1, 2]; + var form = createView({ + View: FormView, + model: 'foo', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '
', + res_id: 1, + viewOptions: { + mode: 'edit', + }, + }); + + assert.strictEqual(form.$('.o_field_widget[name=o2m] .o_data_row').length, 2, + "there should be two records in the many2many"); + + form.$('.o_field_widget[name=o2m] .o_data_cell:first').click(); + assert.ok(form.$('.o_field_widget[name=o2m] .o_data_row:first').hasClass('o_selected_row'), + "first row should be in edition"); + + // Press 'Tab' -> should go to next line + form.$('.o_field_widget[name=o2m] .o_selected_row input').trigger({type: 'keydown', which: 9}); + assert.ok(form.$('.o_field_widget[name=o2m] .o_data_row:nth(1)').hasClass('o_selected_row'), + "second row should be in edition"); + + // Press 'Tab' -> should go back to first line as the create action isn't available + form.$('.o_field_widget[name=o2m] .o_selected_row input').trigger({type: 'keydown', which: 9}); + assert.ok(form.$('.o_field_widget[name=o2m] .o_data_row:first').hasClass('o_selected_row'), + "first row should be in edition"); + + form.destroy(); + }); + QUnit.test('edition, then navigation with tab (with a readonly field)', function (assert) { // This test makes sure that if we have 2 cells in a row, the first in // edit mode, and the second one readonly, then if we edit and press TAB,