From 3faaecf1f3de0e0719be1ea68c92cd9a57d99205 Mon Sep 17 00:00:00 2001 From: Julien Mougenot Date: Wed, 3 Aug 2022 12:11:24 +0000 Subject: [PATCH] [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) --- .../static/src/views/fields/ace/ace_field.js | 33 +++++++++++-------- .../views/fields/ace_editor_field_tests.js | 29 +++++++++++++--- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/addons/web/static/src/views/fields/ace/ace_field.js b/addons/web/static/src/views/fields/ace/ace_field.js index e7c87b0e443..561792652dd 100644 --- a/addons/web/static/src/views/fields/ace/ace_field.js +++ b/addons/web/static/src/views/fields/ace/ace_field.js @@ -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() { diff --git a/addons/web/static/tests/views/fields/ace_editor_field_tests.js b/addons/web/static/tests/views/fields/ace_editor_field_tests.js index d3c4f84a57f..7e45300da30 100644 --- a/addons/web/static/tests/views/fields/ace_editor_field_tests.js +++ b/addons/web/static/tests/views/fields/ace_editor_field_tests.js @@ -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 */ ` +
+ + `, + }); + + assert.ok(target.querySelector(".o_field_ace").textContent.includes("yop")); + + await pagerNext(target); + + assert.ok(target.querySelector(".o_field_ace").textContent.includes("blip")); + }); });