From 2772dae47618bdc5fdac6fe20de702ae02440056 Mon Sep 17 00:00:00 2001 From: Bruno Boi Date: Fri, 14 Apr 2023 13:47:34 +0000 Subject: [PATCH] [FIX] web: fix traceback in useDynamicPlaceholder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Before this commit** Since 394f85c954f anytime this hook opens a popover, a traceback occurs. It is due to the fact this hook passes a callback as a getter-only property to the usePopover hook options. The traceback occur because the usePopover hook has to reassign this option (onClose callback). **After this commit** Fixed and tested. closes odoo/odoo#118580 Signed-off-by: Michaƫl Mattiello --- .../views/fields/dynamic_placeholder_hook.js | 14 ++--- .../tests/views/fields/text_field_tests.js | 58 ++++++++++++++++--- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/addons/web/static/src/views/fields/dynamic_placeholder_hook.js b/addons/web/static/src/views/fields/dynamic_placeholder_hook.js index c1d3e8dfabf..7a4032baca8 100644 --- a/addons/web/static/src/views/fields/dynamic_placeholder_hook.js +++ b/addons/web/static/src/views/fields/dynamic_placeholder_hook.js @@ -12,10 +12,10 @@ export function useDynamicPlaceholder(elementRef) { const triggerKeyReplaceRegex = new RegExp(`${TRIGGER_KEY}$`); let closeCallback; let positionCallback; - const popoverOptions = {}; - Object.defineProperty(popoverOptions, "onClose", { get: () => closeCallback }); - Object.defineProperty(popoverOptions, "onPositioned", { get: () => positionCallback }); - const popover = usePopover(ModelFieldSelectorPopover, popoverOptions); + const popover = usePopover(ModelFieldSelectorPopover, { + onclose: () => closeCallback?.(), + onPositioned: () => positionCallback?.(), + }); const modelField = useModelField(); const notification = useService("notification"); @@ -60,9 +60,9 @@ export function useDynamicPlaceholder(elementRef) { * * @public * @param {Object} opts - * @param {function} options.validateCallback - * @param {function} options.closeCallback - * @param {function} [options.positionCallback] + * @param {function} opts.validateCallback + * @param {function} opts.closeCallback + * @param {function} [opts.positionCallback] */ async function open(opts) { if (!model) { diff --git a/addons/web/static/tests/views/fields/text_field_tests.js b/addons/web/static/tests/views/fields/text_field_tests.js index f261bdf1c0e..72611887882 100644 --- a/addons/web/static/tests/views/fields/text_field_tests.js +++ b/addons/web/static/tests/views/fields/text_field_tests.js @@ -8,9 +8,12 @@ import { clickSave, editInput, getFixture, + nextTick, triggerEvent, + triggerHotkey, } from "@web/../tests/helpers/utils"; import { makeView, setupViewRegistries } from "@web/../tests/views/helpers"; +import { fieldService } from "@web/core/field_service"; const serviceRegistry = registry.category("services"); @@ -255,11 +258,7 @@ QUnit.module("Fields", (hooks) => { }); const textarea = target.querySelector("textarea"); - assert.strictEqual( - textarea.rows, - 4, - "rowCount should be the one set on the field", - ); + assert.strictEqual(textarea.rows, 4, "rowCount should be the one set on the field"); }); QUnit.test( @@ -282,8 +281,9 @@ QUnit.module("Fields", (hooks) => { }); // ensure that autoresize is correctly done - let height = target.querySelector(".o_field_widget[name=text_field] textarea") - .offsetHeight; + let height = target.querySelector( + ".o_field_widget[name=text_field] textarea" + ).offsetHeight; // focus the field to manually trigger autoresize await triggerEvent(target, ".o_field_widget[name=text_field] textarea", "focus"); assert.strictEqual( @@ -352,8 +352,9 @@ QUnit.module("Fields", (hooks) => { await click(target.querySelectorAll(".o_notebook .nav .nav-link")[2]); assert.hasClass(target.querySelectorAll(".o_notebook .nav .nav-link")[2], "active"); - height = target.querySelector(".o_field_widget[name=text_field_empty] textarea") - .offsetHeight; + height = target.querySelector( + ".o_field_widget[name=text_field_empty] textarea" + ).offsetHeight; assert.strictEqual(height, 50, "empty textarea should have height of 50px"); }); @@ -592,4 +593,43 @@ QUnit.module("Fields", (hooks) => { "text area should have the focus" ); }); + + QUnit.test("field text with dynamic placeholder", async (assert) => { + registry.category("services").add("field", fieldService); + + serverData.models.partner.fields.model_reference_field = { + string: "Model Reference Field", + type: "char", + default: "partner", + }; + + await makeView({ + type: "form", + resModel: "partner", + serverData, + arch: ` +
+ + + + + + + `, + }); + + await click(target, "[name=txt] textarea"); + assert.strictEqual(document.activeElement, target.querySelector("[name=txt] textarea")); + + assert.containsNone(document.body, ".o_popover .o_field_selector_popover"); + triggerHotkey("#"); + await nextTick(); + assert.containsOnce(document.body, ".o_popover .o_field_selector_popover"); + }); });