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 6469b78347a..3e60403fab2 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 @@ -1126,27 +1126,6 @@ ListRenderer.include({ break; } }, - /** - * It will returns the last visible widget that is editable - * - * @private - * @returns {Class} Widget returns last widget - */ - _getLastWidget: function () { - var recordID = this._getRecordID(this.currentRow); - var recordWidgets = this.allFieldWidgets[recordID]; - var lastWidget = _.chain(recordWidgets).filter(function (widget) { - var isLast = - widget.$el.is(':visible') && - ( - widget.$('input').length > 0 || widget.tagName === 'input' || - widget.$('textarea').length > 0 || widget.tagName === 'textarea' - ) && - !widget.$el.hasClass('o_readonly_modifier'); - return isLast; - }).last().value(); - return lastWidget; - }, /** * Handles the keyboard navigation according to events triggered by field * widgets. @@ -1175,18 +1154,12 @@ ListRenderer.include({ } break; case 'next': - var column = this.columns[this.currentFieldIndex]; - var lastWidget = this._getLastWidget(); - if (column.attrs.name === lastWidget.name) { - this._moveToNextLine(); + if (this.currentFieldIndex + 1 < this.columns.length) { + this._selectCell(this.currentRow, this.currentFieldIndex + 1, {wrap: false}) + .guardedCatch(this._moveToNextLine.bind(this)); } else { - if (this.currentFieldIndex + 1 < this.columns.length) { - this._selectCell(this.currentRow, this.currentFieldIndex + 1, {wrap: false}) - .guardedCatch(this._moveToNextLine.bind(this)); - } else { - this._moveToNextLine(); - } - } + this._moveToNextLine(); + } break; case 'next_line': this._moveToNextLine({forceCreate: true}); diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 4175a7171aa..797aaea016b 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -3375,6 +3375,37 @@ QUnit.module('Views', { form.destroy(); }); + QUnit.test('navigation with tab in editable list with only readonly fields', async function (assert) { + assert.expect(6); + + var list = await createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: '' + + '' + + '' + + '', + }); + + assert.hasClass(list.$('.o_data_row:first .o_data_cell:first'), 'o_readonly_modifier'); + assert.doesNotHaveClass(list.$('.o_data_row:nth(1) .o_data_cell:first'), 'o_readonly_modifier'); + + // try to enter first row in edition + await testUtils.dom.click(list.$('.o_data_row .o_data_cell:first')); + + assert.hasClass(list.$('.o_data_row:first'), 'o_selected_row'); + assert.strictEqual(document.activeElement, list.$('.o_selected_row .o_field_widget[name=m2o]').get(0)); + + // press tab to move to next focusable field (next line here) + $(document.activeElement).trigger($.Event('keydown', {which: $.ui.keyCode.TAB})); + await testUtils.nextTick(); + assert.hasClass(list.$('.o_data_row:nth(1)'), 'o_selected_row'); + assert.strictEqual(document.activeElement, list.$('.o_selected_row .o_field_many2one input').get(0)); + + list.destroy(); + }); + QUnit.test('edition, then navigation with tab (with a readonly field)', async 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,