Files
owl/web/static/src/ts/core/Widget.ts
T

106 lines
2.7 KiB
TypeScript
Raw Normal View History

2019-01-22 19:25:12 +01:00
import sdAttrs from "../../../libs/snabbdom/src/modules/attributes";
2019-01-23 14:28:41 +01:00
import sdListeners from "../../../libs/snabbdom/src/modules/eventlisteners";
import { init } from "../../../libs/snabbdom/src/snabbdom";
2019-01-22 19:25:12 +01:00
import { VNode } from "../../../libs/snabbdom/src/vnode";
2019-01-24 10:33:11 +01:00
import { QWeb } from "./qweb_vdom";
2019-01-17 18:08:39 +01:00
2019-01-21 14:38:44 +01:00
const patch = init([sdListeners, sdAttrs]);
2019-01-16 13:19:58 +01:00
2019-01-23 14:28:41 +01:00
export interface WEnv {
2019-01-16 13:19:58 +01:00
qweb: QWeb;
}
2019-01-24 10:33:11 +01:00
export class Widget<T extends WEnv> {
2019-01-16 13:19:58 +01:00
name: string = "widget";
template: string = "<div></div>";
2019-01-20 09:25:41 +01:00
vnode: VNode | null = null;
2019-01-16 13:19:58 +01:00
2019-01-23 11:12:54 +01:00
parent: Widget<T> | null = null;
children: Widget<T>[] = [];
env: T;
2019-01-20 09:25:41 +01:00
el: HTMLElement | null = null;
2019-01-16 13:19:58 +01:00
state: Object = {};
refs: { [key: string]: any } = {}; // either HTMLElement or Widget
2019-01-16 13:19:58 +01:00
//--------------------------------------------------------------------------
// Lifecycle
//--------------------------------------------------------------------------
2019-01-23 11:12:54 +01:00
constructor(parent: Widget<T> | T, props?: any) {
if (parent instanceof Widget) {
this.parent = parent;
2019-01-16 13:19:58 +01:00
parent.children.push(this);
this.env = Object.create(parent.env);
} else {
this.env = parent;
2019-01-16 13:19:58 +01:00
}
}
async willStart() {}
mounted() {}
willUnmount() {}
destroyed() {}
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
2019-01-20 14:46:36 +01:00
async mount(target?: HTMLElement): Promise<VNode> {
2019-01-16 13:19:58 +01:00
await this.willStart();
2019-01-23 14:28:41 +01:00
this.env.qweb.addTemplate(this.name, this.template);
2019-01-17 12:49:13 +01:00
delete this.template;
2019-01-20 14:46:36 +01:00
const vnode = await this.render();
2019-01-20 09:25:41 +01:00
2019-01-20 14:46:36 +01:00
if (target) {
target.appendChild(this.el!);
2019-01-21 14:54:13 +01:00
if (document.body.contains(target)) {
this.visitSubTree(w => w.mounted());
2019-01-21 14:54:13 +01:00
}
2019-01-20 14:46:36 +01:00
}
return vnode;
2019-01-16 13:19:58 +01:00
}
2019-01-16 23:03:51 +01:00
destroy() {
if (this.el) {
this.el.remove();
2019-01-16 13:19:58 +01:00
}
}
2019-01-17 18:08:39 +01:00
/**
* DOCSTRIGN
*
* @param {Object} newState
* @memberof Widget
*/
2019-01-16 13:19:58 +01:00
async updateState(newState: Object) {
Object.assign(this.state, newState);
await this.render();
}
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
2019-01-20 14:46:36 +01:00
async render(): Promise<VNode> {
2019-01-21 14:54:13 +01:00
// localized hack to keep track of deferred list
(<any>this)._TEMP = [];
2019-01-20 14:46:36 +01:00
let vnode = this.env!.qweb.render(this.name, this);
2019-01-21 14:54:13 +01:00
await Promise.all((<any>this)._TEMP);
2019-01-20 09:25:41 +01:00
if (!this.el) {
this.el = document.createElement(vnode.sel!);
}
patch(this.vnode || this.el, vnode);
this.vnode = vnode;
2019-01-20 14:46:36 +01:00
return vnode;
2019-01-16 13:19:58 +01:00
}
2019-01-21 16:26:51 +01:00
2019-01-23 11:12:54 +01:00
private visitSubTree(callback: (w: Widget<T>) => void) {
2019-01-21 16:26:51 +01:00
callback(this);
for (let child of this.children) {
child.visitSubTree(callback);
}
}
2019-01-16 13:19:58 +01:00
}