[FIX] web: owlCompatibility: standaloneAdapter can trigger DOM events
Before this commit, when spawning a LegacyWidget with the standaloneAdapter, the legacyWidget couldn't re-trigger an OdooEvent (trigger_up) in the DOM forbidding any attempts to, for instance, execute an action button (a stat button in form view) After this commit, not only standaloneAdapter takes an optional owl ref to trigger onto (defaults to document.body), but the last resort legacy_provider handles execute-action DOM event. closes odoo/odoo#90172 X-original-commit: 616d0761a8e15dfe49db9bacdfa6f7df75587dff Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com> Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -289,7 +289,8 @@ odoo.define('web.OwlCompatibility', function (require) {
|
||||
}
|
||||
}
|
||||
|
||||
function standaloneAdapter(props) {
|
||||
const bodyRef = { get el() { return document.body } };
|
||||
function standaloneAdapter(props = {}, ref=bodyRef) {
|
||||
const env = owl.Component.env;
|
||||
const app = new App(null, {
|
||||
templates: window.__OWL_TEMPLATES__,
|
||||
@@ -298,8 +299,16 @@ odoo.define('web.OwlCompatibility', function (require) {
|
||||
translatableAttributes: ["data-tooltip"],
|
||||
translateFn: env._t,
|
||||
});
|
||||
const node = app.makeNode(ComponentAdapter, props);
|
||||
return node.component;
|
||||
if (!("Component" in props)) {
|
||||
props.Component = owl.Component;
|
||||
}
|
||||
const component = app.makeNode(ComponentAdapter, props).component;
|
||||
Object.defineProperty(component, "el", {
|
||||
get() {
|
||||
return ref.el;
|
||||
}
|
||||
});
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@ import Context from "web.Context";
|
||||
import { browser } from "../core/browser/browser";
|
||||
import { registry } from "../core/registry";
|
||||
import { mapDoActionOptionAPI } from "./backend_utils";
|
||||
import { wrapSuccessOrFail } from "@web/legacy/utils";
|
||||
|
||||
export const legacyServiceProvider = {
|
||||
dependencies: ["effect", "action"],
|
||||
@@ -25,6 +26,29 @@ export const legacyServiceProvider = {
|
||||
const legacyOptions = mapDoActionOptionAPI(payload.options);
|
||||
services.action.doAction(payload.action, legacyOptions);
|
||||
});
|
||||
|
||||
browser.addEventListener("execute-action", (ev) => {
|
||||
const payload = ev.detail;
|
||||
const buttonContext = new Context(payload.action_data.context).eval();
|
||||
const envContext = new Context(payload.env.context).eval();
|
||||
wrapSuccessOrFail(
|
||||
services.action.doActionButton({
|
||||
args: payload.action_data.args,
|
||||
buttonContext: buttonContext,
|
||||
context: envContext,
|
||||
close: payload.action_data.close,
|
||||
resModel: payload.env.model,
|
||||
name: payload.action_data.name,
|
||||
resId: payload.env.currentID || null,
|
||||
resIds: payload.env.resIDs,
|
||||
special: payload.action_data.special,
|
||||
type: payload.action_data.type,
|
||||
onClose: payload.on_closed,
|
||||
effect: payload.action_data.effect,
|
||||
}),
|
||||
payload
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -9,13 +9,18 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
|
||||
ComponentAdapter,
|
||||
ComponentWrapper,
|
||||
WidgetAdapterMixin,
|
||||
standaloneAdapter,
|
||||
} = require('web.OwlCompatibility');
|
||||
const testUtils = require('web.test_utils');
|
||||
const Widget = require('web.Widget');
|
||||
const Dialog = require("web.Dialog");
|
||||
const { registry } = require("@web/core/registry");
|
||||
const { LegacyComponent } = require("@web/legacy/legacy_component");
|
||||
const { mapLegacyEnvToWowlEnv, useWowlService } = require("@web/legacy/utils");
|
||||
|
||||
const { legacyServiceProvider } = require("@web/legacy/legacy_service_provider");
|
||||
const { click } = require("@web/../tests/helpers/utils");
|
||||
|
||||
const makeTestEnvironment = require("web.test_env");
|
||||
const { makeTestEnv } = require("@web/../tests/helpers/mock_env");
|
||||
const { getFixture, mount, useLogLifeCycle, destroy } = require("@web/../tests/helpers/utils");
|
||||
@@ -807,6 +812,69 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
|
||||
assert.verifySteps(["GED", "AAB", "MCM"]);
|
||||
});
|
||||
|
||||
QUnit.test("standaloneAdapter can trigger in the DOM and execute action", async (assert) => {
|
||||
assert.expect(3)
|
||||
const done = assert.async();
|
||||
|
||||
const MyDialog = Dialog.extend({
|
||||
async start() {
|
||||
const res = await this._super(...arguments);
|
||||
const btn = document.createElement("button");
|
||||
btn.classList.add("myButton");
|
||||
btn.addEventListener("click", () => {
|
||||
this.trigger_up("execute_action", {
|
||||
action_data: {},
|
||||
env: {},
|
||||
});
|
||||
});
|
||||
this.el.appendChild(btn);
|
||||
return res;
|
||||
}
|
||||
});
|
||||
|
||||
const dialogOpened = makeTestPromise();
|
||||
class MyComp extends Component {
|
||||
setup() {
|
||||
onWillDestroy(() => {
|
||||
this.dialog.destroy();
|
||||
})
|
||||
}
|
||||
async spawnDialog() {
|
||||
const parent = standaloneAdapter();
|
||||
this.dialog = new MyDialog(parent);
|
||||
await this.dialog.open();
|
||||
dialogOpened.resolve();
|
||||
}
|
||||
}
|
||||
MyComp.template = xml`<button class="spawnDialog" t-on-click="spawnDialog"/>`;
|
||||
|
||||
const actionService = {
|
||||
start() {
|
||||
return {
|
||||
async doActionButton() {
|
||||
assert.step("doActionButton");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registry.category("services").add("action", actionService);
|
||||
registry.category("services").add("legacy_service_provider", legacyServiceProvider);
|
||||
|
||||
const env = await makeTestEnv();
|
||||
await addMockEnvironmentOwl(Component);
|
||||
|
||||
const target = getFixture()
|
||||
await mount(MyComp, target, {env});
|
||||
await click(target.querySelector(".spawnDialog"));
|
||||
await dialogOpened;
|
||||
|
||||
assert.containsOnce(document.body, ".modal"); // legacy modal
|
||||
await click(document.body.querySelector(".modal .myButton"));
|
||||
assert.verifySteps(["doActionButton"]);
|
||||
done();
|
||||
})
|
||||
|
||||
QUnit.module('WidgetAdapterMixin and ComponentWrapper');
|
||||
|
||||
QUnit.test("widget with sub component", async function (assert) {
|
||||
|
||||
Reference in New Issue
Block a user