[FIX] web: Make Ace editor field reactive

Before this commit, the Ace editor field did not update on props change.

Now, it will update its value and options when the props keys "value",
"mode" or "readonly" are modified.

closes odoo/odoo#97396

Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Julien Mougenot
2022-08-03 19:33:50 +02:00
parent 455a061d09
commit 3faaecf1f3
2 changed files with 44 additions and 18 deletions
@@ -7,7 +7,7 @@ import { registry } from "@web/core/registry";
import { formatText } from "../formatters";
import { standardFieldProps } from "../standard_field_props";
const { Component, onWillStart, useEffect, useRef } = owl;
const { Component, onWillStart, onWillUpdateProps, useEffect, useRef } = owl;
export class AceField extends Component {
setup() {
@@ -25,9 +25,12 @@ export class AceField extends Component {
return Promise.all(proms);
});
onWillUpdateProps(this.updateAce);
useEffect(
() => {
this.setupAce();
this.updateAce(this.props);
return () => this.destroyAce();
},
() => [this.editorRef.el]
@@ -52,31 +55,35 @@ export class AceField extends Component {
useSoftTabs: true,
});
this.aceEditor.on("blur", this.onBlur.bind(this));
}
updateAce({ mode, readonly, value }) {
if (!this.aceEditor) {
return;
}
this.aceSession.setOptions({
mode: `ace/mode/${this.props.mode === "xml" ? "qweb" : this.props.mode}`,
mode: `ace/mode/${mode === "xml" ? "qweb" : mode}`,
});
this.aceEditor.setOptions({
readOnly: this.props.readonly,
highlightActiveLine: !this.props.readonly,
highlightGutterLine: !this.props.readonly,
readOnly: readonly,
highlightActiveLine: !readonly,
highlightGutterLine: !readonly,
});
this.aceEditor.renderer.setOptions({
displayIndentGuides: !this.props.readonly,
showGutter: !this.props.readonly,
displayIndentGuides: !readonly,
showGutter: !readonly,
});
this.aceEditor.renderer.$cursorLayer.element.style.display = this.props.readonly
? "none"
: "block";
this.aceEditor.renderer.$cursorLayer.element.style.display = readonly ? "none" : "block";
const formattedValue = formatText(this.props.value);
const formattedValue = formatText(value);
if (this.aceSession.getValue() !== formattedValue) {
this.aceSession.setValue(formattedValue);
}
this.aceEditor.on("blur", this.onBlur.bind(this));
}
destroyAce() {
@@ -1,6 +1,7 @@
/** @odoo-module **/
import { getFixture, clickEdit, triggerEvents } from "@web/../tests/helpers/utils";
import { clickEdit, getFixture, triggerEvents } from "@web/../tests/helpers/utils";
import { pagerNext } from "@web/../tests/search/helpers";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
let serverData;
@@ -22,10 +23,8 @@ QUnit.module("Fields", (hooks) => {
},
},
records: [
{
id: 1,
foo: `yop`,
},
{ id: 1, foo: `yop` },
{ id: 2, foo: `blip` },
],
},
},
@@ -75,4 +74,24 @@ QUnit.module("Fields", (hooks) => {
await triggerEvents(target, ".ace-view-editor textarea", ["focus", "click"]);
assert.hasClass(target.querySelector(".ace-view-editor"), "ace_focus");
});
QUnit.test("AceEditorField is updated on value change", async (assert) => {
await makeView({
type: "form",
resModel: "partner",
resId: 1,
resIds: [1, 2],
serverData,
arch: /* xml */ `
<form>
<field name="foo" widget="ace" />
</form>`,
});
assert.ok(target.querySelector(".o_field_ace").textContent.includes("yop"));
await pagerNext(target);
assert.ok(target.querySelector(".o_field_ace").textContent.includes("blip"));
});
});