change children implementation, remove parented link on destroy

This commit is contained in:
Géry Debongnie
2019-01-27 13:50:53 +01:00
parent 8b6ce52cd7
commit 37175df9ad
2 changed files with 48 additions and 21 deletions
+15 -6
View File
@@ -23,7 +23,7 @@ interface Meta<T extends WEnv> {
isMounted: boolean; isMounted: boolean;
isDestroyed: boolean; isDestroyed: boolean;
parent: Widget<T> | null; parent: Widget<T> | null;
children: Widget<T>[]; children: { [key: number]: Widget<T> };
} }
export class Widget<T extends WEnv> { export class Widget<T extends WEnv> {
@@ -45,22 +45,25 @@ export class Widget<T extends WEnv> {
constructor(parent: Widget<T> | T, props?: any) { constructor(parent: Widget<T> | T, props?: any) {
wl.push(this); wl.push(this);
let id: number;
let p: Widget<T> | null = null; let p: Widget<T> | null = null;
if (parent instanceof Widget) { if (parent instanceof Widget) {
p = parent; p = parent;
parent.__widget__.children.push(this);
this.env = parent.env; this.env = parent.env;
id = this.env.getID();
parent.__widget__.children[id] = this;
} else { } else {
this.env = parent; this.env = parent;
id = this.env.getID();
} }
this.__widget__ = { this.__widget__ = {
id: this.env.getID(), id: id,
vnode: null, vnode: null,
isStarted: false, isStarted: false,
isMounted: false, isMounted: false,
isDestroyed: false, isDestroyed: false,
parent: p, parent: p,
children: [] children: {}
}; };
} }
@@ -97,6 +100,11 @@ export class Widget<T extends WEnv> {
this.el.remove(); this.el.remove();
delete this.__widget__.vnode; delete this.__widget__.vnode;
} }
if (this.__widget__.parent) {
let id = this.__widget__.id;
delete this.__widget__.parent.__widget__.children[id];
this.__widget__.parent = null;
}
this.__widget__.isDestroyed = true; this.__widget__.isDestroyed = true;
this.destroyed(); this.destroyed();
} }
@@ -163,8 +171,9 @@ export class Widget<T extends WEnv> {
private visitSubTree(callback: (w: Widget<T>) => void) { private visitSubTree(callback: (w: Widget<T>) => void) {
callback(this); callback(this);
for (let child of this.__widget__.children) { const children = this.__widget__.children;
child.visitSubTree(callback); for (let id in children) {
children[id].visitSubTree(callback);
} }
} }
} }
+33 -15
View File
@@ -31,7 +31,12 @@ function nextTick(): Promise<void> {
return Promise.resolve(); return Promise.resolve();
} }
// Test widget function children(w: Widget<WEnv>): Widget<WEnv>[] {
const childrenMap = w.__widget__.children;
return Object.keys(childrenMap).map(id => childrenMap[id]);
}
// Test widgets
class Counter extends Widget<WEnv> { class Counter extends Widget<WEnv> {
name = "counter"; name = "counter";
template = `<div><t t-esc="state.counter"/><button t-on-click="inc">Inc</button></div>`; template = `<div><t t-esc="state.counter"/><button t-on-click="inc">Inc</button></div>`;
@@ -44,6 +49,16 @@ class Counter extends Widget<WEnv> {
} }
} }
class WidgetA extends Widget<WEnv> {
name = "a";
template = `<div>Hello<t t-widget="b"/></div>`;
widgets = { b: WidgetB };
}
class WidgetB extends Widget<WEnv> {
template = `<div>world</div>`;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Tests // Tests
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -269,23 +284,26 @@ describe("destroy method", () => {
widget.destroy(); widget.destroy();
expect(count).toBe(1); expect(count).toBe(1);
}); });
test("destroy remove the parent/children link", async () => {
const parent = new WidgetA(env);
await parent.mount(fixture);
const child = children(parent)[0];
expect(child.__widget__.parent).toBe(parent);
expect(children(parent).length).toBe(1);
child.destroy();
expect(child.__widget__.parent).toBe(null);
expect(children(parent).length).toBe(0);
});
}); });
describe("composition", () => { describe("composition", () => {
class WidgetA extends Widget<WEnv> {
name = "a";
template = `<div>Hello<t t-widget="b"/></div>`;
widgets = { b: WidgetB };
}
class WidgetB extends Widget<WEnv> {
template = `<div>world</div>`;
}
test("a widget with a sub widget", async () => { test("a widget with a sub widget", async () => {
const widget = new WidgetA(env); const widget = new WidgetA(env);
await widget.mount(fixture); await widget.mount(fixture);
expect(fixture.innerHTML).toBe("<div>Hello<div>world</div></div>"); expect(fixture.innerHTML).toBe("<div>Hello<div>world</div></div>");
expect(widget.__widget__.children[0].__widget__.parent).toBe(widget); expect(children(widget)[0].__widget__.parent).toBe(widget);
}); });
test("t-refs on widget are widgets", async () => { test("t-refs on widget are widgets", async () => {
@@ -322,11 +340,11 @@ describe("composition", () => {
await widget.mount(fixture); await widget.mount(fixture);
expect((<any>widget.__widget__.vnode!.children![1]).elm).toBe( expect((<any>widget.__widget__.vnode!.children![1]).elm).toBe(
(<any>widget.__widget__.children[0].__widget__.vnode).elm (<any>children(widget)[0].__widget__.vnode).elm
); );
await widget.__widget__.children[0].render(); await children(widget)[0].render();
expect((<any>widget.__widget__.vnode!.children![1]).elm).toBe( expect((<any>widget.__widget__.vnode!.children![1]).elm).toBe(
(<any>widget.__widget__.children[0].__widget__.vnode).elm (<any>children(widget)[0].__widget__.vnode).elm
); );
}); });
@@ -334,6 +352,6 @@ describe("composition", () => {
const widget = new WidgetA(env); const widget = new WidgetA(env);
await widget.mount(fixture); await widget.mount(fixture);
expect(widget.__widget__.children[0].env).toBe(env); expect(children(widget)[0].env).toBe(env);
}); });
}); });