From f58f2e0d4f24de52e72a5b0fe3c7fb78680eac0c Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Thu, 19 Jan 2023 14:24:32 +0000 Subject: [PATCH] [FIX] web: do not save untouched fields on F5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Have a char field with trim option set to True (this is the default). Open a form view where the value of this field has leading or trailing spaces. Press F5 (or close the tab/browser). Before this commit, a write was done before leaving, with the trimmed value of the char field. This isn't the expected behavior: as the field hasn't been manually edited, we don't want to write on it. This could be reproduced on project.task form views, on tasks with a name with leading/trailing spaces (e.g. tasks created by mails sent to feedback@odoo.com). The issue occurred when we saved a record "urgently" (before unload) because we parsed the value of each input field, and we sent it if it was different from the initial (or last set) value. In our case, parsing the value trimmed it, and it was thus different from the initial value. Bug reported after the migration of odoo.com to 16.0. closes odoo/odoo#110528 X-original-commit: 43b7ae39e633ced6008b067bb4e63ed9be7eda01 Signed-off-by: Michaƫl Mattiello --- .../src/views/fields/input_field_hook.js | 15 ++++++++-- .../tests/views/form/form_view_tests.js | 29 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/views/fields/input_field_hook.js b/addons/web/static/src/views/fields/input_field_hook.js index 7eb9d3824e3..a32a9ec0294 100644 --- a/addons/web/static/src/views/fields/input_field_hook.js +++ b/addons/web/static/src/views/fields/input_field_hook.js @@ -33,6 +33,14 @@ export function useInputField(params) { */ let lastSetValue = null; + /** + * Track the fact that there is a change sent to the model that hasn't been acknowledged yet + * (e.g. because the onchange is still pending). This is necessary if we must do an urgent save, + * as we have to re-send that change for the write that will be done directly. + * FIXME: this could/should be handled by the model itself, when it will be rewritten + */ + let pendingUpdate = false; + /** * When a user types, we need to set the field as dirty. */ @@ -64,7 +72,10 @@ export function useInputField(params) { } if (!isInvalid) { - component.props.update(val); + pendingUpdate = true; + Promise.resolve(component.props.update(val)).then(() => { + pendingUpdate = false; + }); lastSetValue = ev.target.value; } @@ -126,7 +137,7 @@ export function useInputField(params) { } isDirty = inputRef.el.value !== lastSetValue; - if (isDirty || urgent) { + if (isDirty || (urgent && pendingUpdate)) { let isInvalid = false; isDirty = false; let val = inputRef.el.value; diff --git a/addons/web/static/tests/views/form/form_view_tests.js b/addons/web/static/tests/views/form/form_view_tests.js index 0414cbe1ac1..a04cbee6fc8 100644 --- a/addons/web/static/tests/views/form/form_view_tests.js +++ b/addons/web/static/tests/views/form/form_view_tests.js @@ -11868,6 +11868,35 @@ QUnit.module("Views", (hooks) => { assert.verifySteps([], "should not save because we do not change anything"); }); + QUnit.test( + "Auto save: save on closing tab/browser (not dirty but trailing spaces)", + async function (assert) { + serverData.models.partner.fields.foo.trim = true; + serverData.models.partner.records[0].foo = "name with trailing spaces "; + + await makeView({ + type: "form", + resModel: "partner", + serverData, + arch: `
`, + resId: 1, + mockRPC(route, { args, method, model }) { + if (method === "write" && model === "partner") { + throw new Error("no write should be done"); + } + }, + }); + + assert.strictEqual( + target.querySelector(".o_field_widget[name=foo] input").value, + "name with trailing spaces " + ); + + window.dispatchEvent(new Event("beforeunload")); + await nextTick(); + } + ); + QUnit.test( "Auto save: save on closing tab/browser (not dirty) with text field", async function (assert) {