From 4fba43c027fcc52066ad5149a7fd08bde1109806 Mon Sep 17 00:00:00 2001 From: Julien Mougenot Date: Thu, 12 Sep 2019 09:01:28 +0000 Subject: [PATCH] [FIX] web: lists: focus last edited cell Gave back focus to the last edited cell to increase usability with key nav. Before this commit, after saving several records with multi edition in a list, focus was lost (given to the body). Now, last edited cell is given back the focus after multi editing. --- .../src/js/views/list/list_controller.js | 18 +++++++++++++----- .../js/views/list/list_editable_renderer.js | 11 +++++++++++ addons/web/static/tests/views/list_tests.js | 6 +++++- 3 files changed, 29 insertions(+), 6 deletions(-) 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 a78f2bc61b0..32c05537439 100644 --- a/addons/web/static/src/js/views/list/list_controller.js +++ b/addons/web/static/src/js/views/list/list_controller.js @@ -477,6 +477,7 @@ var ListController = BasicController.extend({ this.model.discardChanges(recordId); return this._confirmSave(recordId).then(reject); }; + let dialog; if (validRecordIds.length > 0) { let message; if (nbInvalid === 0) { @@ -488,13 +489,13 @@ var ListController = BasicController.extend({ _t("Do you want to set the value on the %d valid selected records? (%d invalid)"), validRecordIds.length, nbInvalid); } - Dialog.confirm(this, message, { + dialog = Dialog.confirm(this, message, { confirm_callback: () => { - this.model.saveRecords(recordId, validRecordIds, fieldName) - .then(() => { + return this.model.saveRecords(recordId, validRecordIds, fieldName) + .then(async () => { this._updateButtons('readonly'); const state = this.model.get(this.handle); - this.renderer.updateState(state, {keepWidths: true}); + await this.renderer.updateState(state, {keepWidths: true}); resolve(Object.keys(changes)); }) .guardedCatch(rejectAndDiscard); @@ -502,10 +503,17 @@ var ListController = BasicController.extend({ cancel_callback: rejectAndDiscard, }); } else { - Dialog.alert(this, _t("No valid record to save"), { + dialog = Dialog.alert(this, _t("No valid record to save"), { confirm_callback: rejectAndDiscard, }); } + dialog.on('closed', this, async () => { + // we need to wait for the dialog to be actually closed, but + // the 'closed' event is triggered just before, and it prevents + // from focussing the cell + await Promise.resolve(); + this.renderer.focusCell(recordId, node); + }); }); }, /** 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 deb29554798..e2393ef61e3 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 @@ -319,6 +319,17 @@ ListRenderer.include({ var rowIndex = $row.prop('rowIndex') - 1; this._selectCell(rowIndex, 0); }, + /** + * Gives focus to a specific cell, given its row and its related column. + * + * @param {string} recordId + * @param {Object} column + */ + focusCell: function (recordId, column) { + var $row = this._getRow(recordId); + var cellIndex = this.columns.indexOf(column); + $row.find('.o_data_cell')[cellIndex].focus(); + }, /** * Returns the recordID associated to the line which is currently in edition * or null if there is no line in edition. diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 0311fab3062..e15e2dc0d40 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -5308,7 +5308,7 @@ QUnit.module('Views', { }); QUnit.test('editable list view: multi edition', async function (assert) { - assert.expect(22); + assert.expect(24); var list = await createView({ View: ListView, @@ -5364,6 +5364,8 @@ QUnit.module('Views', { await testUtils.dom.click($('.modal .btn:contains(Cancel)')); assert.strictEqual(list.$('.o_data_row:eq(0) .o_data_cell').text(), 'yop10', "changes have been discarded and row is back to readonly"); + assert.strictEqual(document.activeElement, list.$('.o_data_row:eq(0) .o_data_cell:eq(1)')[0], + "focus should be given to the most recently edited cell after discard"); await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_data_cell:eq(1)')); await testUtils.fields.editInput(list.$('.o_field_widget[name=int_field]'), 666); await testUtils.dom.click(list.$('.o_data_row:eq(1) .o_data_cell:eq(0)')); @@ -5376,6 +5378,8 @@ QUnit.module('Views', { assert.strictEqual(list.$('.o_data_row:eq(1) .o_data_cell').text(), "blip666", "the second row should be updated"); assert.containsNone(list, '.o_data_cell input.o_field_widget', "no field should be editable anymore"); + assert.strictEqual(document.activeElement, list.$('.o_data_row:eq(0) .o_data_cell:eq(1)')[0], + "focus should be given to the most recently edited cell after confirm"); list.destroy(); });