diff --git a/demo/src/RootWidget.ts b/demo/src/RootWidget.ts
index 36cac83c..36056a15 100644
--- a/demo/src/RootWidget.ts
+++ b/demo/src/RootWidget.ts
@@ -5,6 +5,7 @@ const template = `
Root Widget
+
@@ -23,6 +24,12 @@ export default class RootWidget extends Widget {
this.refs.counter.updateState({counter: 3})
}
+ resetCounterAsync(ev: MouseEvent) {
+ setTimeout(() => {
+ this.refs.counter.updateState({counter: 3})
+ }, 3000);
+ }
+
toggle() {
this.updateState({validcounter: !this.state.validcounter});
}
diff --git a/demo/src/main.ts b/demo/src/main.ts
index f9f926b8..11543bbe 100644
--- a/demo/src/main.ts
+++ b/demo/src/main.ts
@@ -11,12 +11,12 @@
// (window).h = h;
// (window).patch = patch;
// (window).QWeb = QWeb;
-import Counter from "./Counter";
-// import RootWidget from "./RootWidget";
+// import Counter from "./Counter";
+import RootWidget from "./RootWidget";
import env from "./env";
document.addEventListener("DOMContentLoaded", async function() {
- const rootWidget = new Counter(null, {});
+ const rootWidget = new RootWidget(null);
rootWidget.setEnvironment(env);
const mainDiv = document.getElementById("app")!;
await rootWidget.mount(mainDiv);
diff --git a/src/core/qweb_vdom.ts b/src/core/qweb_vdom.ts
index e33fdbba..fa6ebf30 100644
--- a/src/core/qweb_vdom.ts
+++ b/src/core/qweb_vdom.ts
@@ -96,7 +96,8 @@ export default class QWeb {
elifDirective,
ifDirective,
callDirective,
- onDirective
+ onDirective,
+ widgetDirective
].forEach(d => this.addDirective(d));
}
@@ -641,21 +642,25 @@ const onDirective: Directive = {
}
};
-// const widgetDirective: Directive = {
-// name: "widget",
-// priority: 100,
-// atNodeEncounter({ ctx, fullName, value, node, qweb}): boolean {
-// let spanID = ctx.generateID();
-// ctx.addLine(`let ${spanID} = document.createElement('span')`);
-// ctx.addNode(spanID)
-// let props = node.getAttribute('t-props');
-// let widgetID = ctx.generateID();
-// ctx.addLine(`let ${widgetID} = new context.widgets['${value}'](context, ${props})`);
-// ctx.addLine(`${widgetID}.mount(${spanID}).then(()=>${ctx.parentNode}.replaceChild(${widgetID}.el, ${spanID}))`);
-// let ref = node.getAttribute('t-ref');
-// if (ref) {
-// ctx.addLine(`context.refs['${ref}'] = ${widgetID}`);
-// }
-// return true;
-// }
-// };
+const widgetDirective: Directive = {
+ name: "widget",
+ priority: 100,
+ atNodeEncounter({ ctx, fullName, value, node, qweb}): boolean {
+ let dummyID = ctx.generateID();
+ let defID = ctx.generateID();
+ ctx.addLine(`let _${dummyID} = {} // DUMMY`);
+ ctx.addLine(`c${ctx.parentNode}.push(_${dummyID})`);
+ let props = node.getAttribute('t-props');
+ let widgetID = ctx.generateID();
+ ctx.addLine(`let _${widgetID} = new context.widgets['${value}'](context, ${props})`);
+ ctx.addLine(`let def${defID} = _${widgetID}.mount().then(vnode=>Object.assign(_${dummyID}, vnode))`);
+ ctx.addLine(`context._TEMP.push(def${defID})`);
+
+ // split into extra directive?
+ let ref = node.getAttribute('t-ref');
+ if (ref) {
+ ctx.addLine(`context.refs['${ref}'] = _${widgetID}`);
+ }
+ return true;
+ }
+};
diff --git a/src/core/widget.ts b/src/core/widget.ts
index 2d86953e..692ec3e6 100644
--- a/src/core/widget.ts
+++ b/src/core/widget.ts
@@ -17,6 +17,7 @@ export default class Widget {
name: string = "widget";
template: string = "";
vnode: VNode | null = null;
+ _TEMP: Promise[] | null = null;
parent: Widget | null;
children: Widget[] = [];
@@ -50,13 +51,16 @@ export default class Widget {
// Public
//--------------------------------------------------------------------------
- async mount(target: HTMLElement) {
+ async mount(target?: HTMLElement): Promise {
await this.willStart();
this.env!.qweb.addTemplate(this.name, this.template);
delete this.template;
- await this.render();
+ const vnode = await this.render();
- target.appendChild(this.el!);
+ if (target) {
+ target.appendChild(this.el!);
+ }
+ return vnode;
}
destroy() {
@@ -84,19 +88,15 @@ export default class Widget {
// Private
//--------------------------------------------------------------------------
- async render() {
- let vnode = await this.env!.qweb.render(this.name, this);
+ async render(): Promise {
+ this._TEMP = [];
+ let vnode = this.env!.qweb.render(this.name, this);
+ await Promise.all(this._TEMP);
if (!this.el) {
this.el = document.createElement(vnode.sel!);
}
patch(this.vnode || this.el, vnode);
this.vnode = vnode;
+ return vnode;
}
-
- // private _setElement(el: ChildNode) {
- // if (this.el) {
- // this.el.replaceWith(el);
- // }
- // this.el = el;
- // }
}
diff --git a/tests/qweb_vdom.test.ts b/tests/qweb_vdom.test.ts
index 402d79e3..bba80013 100644
--- a/tests/qweb_vdom.test.ts
+++ b/tests/qweb_vdom.test.ts
@@ -311,7 +311,7 @@ describe("attributes", () => {
);
});
- xit("various escapes", () => {
+ test.skip("various escapes", () => {
// need to think about this... This one does not pass, but I am not sure it is
// a correct test
const template = `
diff --git a/tests/widget.test.ts b/tests/widget.test.ts
index f96cee7f..ae4a59ac 100644
--- a/tests/widget.test.ts
+++ b/tests/widget.test.ts
@@ -93,3 +93,23 @@ describe("destroy method", () => {
expect(document.contains(widget.el)).toBe(false);
});
});
+
+describe("composition", () => {
+ test("a widget with a sub widget", async () => {
+
+ class WidgetB extends Widget {
+ template= `world
`;
+ }
+
+ class WidgetA extends Widget {
+ name="a";
+ template= `Hello
`;
+ widgets = {b: WidgetB}
+ }
+
+ const widget = makeWidget(WidgetA);
+ const target = document.createElement("div");
+ await widget.mount(target);
+ expect(target.innerHTML).toBe("");
+ });
+});