From b38137d498cca39cf0d8a82a2af7a63c12c9bd9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Tue, 2 May 2017 21:39:23 +0200 Subject: [PATCH] [FIX] web: prevent loss of edits in list view Before this commit, it was possible to edit something in an editable list view, then press the DOWN key, then enter some other values. With the DOWN key, the focus is supposed to move to the line below, so we save the current line, in the current state. This means that the edit coming after are simply lost (well, just not saved nor displayed). What this commit does is simply disable all control elements in that situation. This prevents uncomfortable situations from occurring. --- .../js/views/list/list_editable_renderer.js | 16 +++++++++++- addons/web/static/tests/views/list_tests.js | 25 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) 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 a9b9cacd9c9..12ef168c131 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 @@ -425,6 +425,10 @@ ListRenderer.include({ * in edit mode. This is the moment we save all accumulated changes on that * row, if needed (@see BasicController.saveRecord). * + * Note that we have to disable the focusable elements (inputs, ...) to + * prevent subsequent editions. These edits would be lost, because the list + * view only saves records when unselecting a row. + * * @returns {Deferred} The deferred resolves if the row was unselected (and * possibly removed). If may be rejected, when the row is dirty and the * user refuses to discard its changes. @@ -436,13 +440,23 @@ ListRenderer.include({ } var record = this.state.data[this.currentRow]; + var recordWidgets = this.allFieldWidgets[record.id]; + toggleWidgets(true); + var def = $.Deferred(); this.trigger_up('save_line', { recordID: record.id, onSuccess: def.resolve.bind(def), onFailure: def.reject.bind(def), }); - return def; + return def.fail(toggleWidgets.bind(null, false)); + + function toggleWidgets(disabled) { + _.each(recordWidgets, function (widget) { + var $el = widget.getFocusableElement(); + $el.prop('disabled', disabled); + }); + } }, //-------------------------------------------------------------------------- diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 0b754c2b5bb..ddfb985c3c1 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -1759,6 +1759,31 @@ QUnit.module('Views', { list.destroy(); }); + + QUnit.test('inputs are disabled when unselecting rows', function (assert) { + assert.expect(1); + + var list = createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: '', + mockRPC: function (route, args) { + if (args.method === 'write') { + assert.strictEqual($input.prop('disabled'), true, + "input should be disabled"); + } + return this._super.apply(this, arguments); + }, + }); + + list.$('td:contains(gnap)').click(); + var $input = list.$('tr.o_selected_row input[name="foo"]'); + $input.val('lemon').trigger('input'); + $input.trigger({type: 'keydown', which: $.ui.keyCode.DOWN}); + list.destroy(); + }); + }); });