mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] app: allow mounting owl apps in iframe
Previously, attempting to mount an app in an iframe would crash, saying that the target is not a valid DOM element, this is because instanceof checks do not work cross-frame as global objects do not have the same identity in frames as with the main window. This commit fixes that by making sure the target is an instance of HTMLElement of the corresponding window, and checks that the corresponding document body contains it.
This commit is contained in:
committed by
Bruno Boi
parent
02a187d80b
commit
a93f015795
+11
-5
@@ -28,12 +28,18 @@ export function batched(callback: Callback): Callback {
|
||||
}
|
||||
|
||||
export function validateTarget(target: HTMLElement) {
|
||||
if (!(target instanceof HTMLElement)) {
|
||||
throw new OwlError("Cannot mount component: the target is not a valid DOM element");
|
||||
}
|
||||
if (!document.body.contains(target)) {
|
||||
throw new OwlError("Cannot mount a component on a detached dom node");
|
||||
// Get the document and HTMLElement corresponding to the target to allow mounting in iframes
|
||||
const document = target && target.ownerDocument;
|
||||
if (document) {
|
||||
const HTMLElement = document.defaultView!.HTMLElement;
|
||||
if (target instanceof HTMLElement) {
|
||||
if (!document.body.contains(target)) {
|
||||
throw new OwlError("Cannot mount a component on a detached dom node");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new OwlError("Cannot mount component: the target is not a valid DOM element");
|
||||
}
|
||||
|
||||
export class EventBus extends EventTarget {
|
||||
|
||||
@@ -29,6 +29,19 @@ exports[`app can configure an app with props 1`] = `
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`app can mount app in an iframe 1`] = `
|
||||
"function anonymous(app, bdom, helpers
|
||||
) {
|
||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||
|
||||
let block1 = createBlock(\`<div class=\\"my-div\\"/>\`);
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
return block1();
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`app destroy remove the widget from the DOM 1`] = `
|
||||
"function anonymous(app, bdom, helpers
|
||||
) {
|
||||
|
||||
@@ -76,4 +76,22 @@ describe("app", () => {
|
||||
"Component 'Root' does not have a static props description"
|
||||
);
|
||||
});
|
||||
|
||||
test("can mount app in an iframe", async () => {
|
||||
class SomeComponent extends Component {
|
||||
static template = xml`<div class="my-div"/>`;
|
||||
}
|
||||
|
||||
const iframe = document.createElement("iframe");
|
||||
fixture.appendChild(iframe);
|
||||
const app = new App(SomeComponent);
|
||||
const iframeDoc = iframe.contentDocument!;
|
||||
const comp = await app.mount(iframeDoc.body);
|
||||
const div = iframeDoc.querySelector(".my-div");
|
||||
expect(div).not.toBe(null);
|
||||
expect(iframeDoc.contains(div)).toBe(true);
|
||||
app.destroy();
|
||||
expect(iframeDoc.contains(div)).toBe(false);
|
||||
expect(status(comp)).toBe("destroyed");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user