[FIX] web: do not save untouched fields on F5

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 <mcm@odoo.com>
This commit is contained in:
Aaron Bohy
2023-01-20 20:58:45 +01:00
parent 79044b31ff
commit f58f2e0d4f
2 changed files with 42 additions and 2 deletions
@@ -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;
@@ -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: `<form><field name="foo"/></form>`,
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) {