diff --git a/addons/web/static/src/views/widgets/widget.js b/addons/web/static/src/views/widgets/widget.js index 3b6bdf67b06..4a5e17b2331 100644 --- a/addons/web/static/src/views/widgets/widget.js +++ b/addons/web/static/src/views/widgets/widget.js @@ -47,7 +47,12 @@ export class Widget extends Component { widgetInfo.attrs.readonly, record.evalContextWithVirtualIds ); - propsFromNode = this.widget.extractProps ? this.widget.extractProps(widgetInfo) : {}; + const dynamicInfo = { + readonly: readonlyFromModifiers, + }; + propsFromNode = this.widget.extractProps + ? this.widget.extractProps(widgetInfo, dynamicInfo) + : {}; } return { 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 c58cbf9b34a..61f8c6eb912 100644 --- a/addons/web/static/tests/views/form/form_view_tests.js +++ b/addons/web/static/tests/views/form/form_view_tests.js @@ -10623,6 +10623,37 @@ QUnit.module("Views", (hooks) => { assert.containsOnce(target, ".o_widget.my_classname"); }); + QUnit.test("widget with readonly attribute", async function (assert) { + class MyComponent extends owl.Component { + static template = owl.xml``; + get value() { + return this.props.readonly ? "readonly" : "not readonly"; + } + } + const myComponent = { + component: MyComponent, + extractProps(widgetInfo, dynamicInfo) { + return { readonly: dynamicInfo.readonly }; + }, + }; + widgetRegistry.add("test_widget", myComponent); + + await makeView({ + type: "form", + serverData, + resModel: "partner", + arch: ` +
+ + + `, + }); + + assert.strictEqual(target.querySelector(".o_widget").textContent, "not readonly"); + await click(target.querySelector(".o_field_widget[name=bar] input")); + assert.strictEqual(target.querySelector(".o_widget").textContent, "readonly"); + }); + QUnit.test("support header button as widgets on form statusbar", async function (assert) { serviceRegistry.add("http", { start: () => ({}),