import { Component, ComponentConstructor, Props } from "./component"; import { ComponentNode } from "./component_node"; import { nodeErrorHandlers, OwlError } from "./error_handling"; import { Fiber, MountOptions } from "./fibers"; import { Scheduler } from "./scheduler"; import { validateProps } from "./template_helpers"; import { TemplateSet, TemplateSetConfig } from "./template_set"; import { validateTarget } from "./utils"; // reimplement dev mode stuff see last change in 0f7a8289a6fb8387c3c1af41c6664b2a8448758f export interface Env { [key: string]: any; } export interface AppConfig
extends TemplateSetConfig { props?: P; env?: E; test?: boolean; warnIfNoStaticProps?: boolean; } let hasBeenLogged = false; export const DEV_MSG = () => { const hash = (window as any).owl ? (window as any).owl.__info__.hash : "master"; return `Owl is running in 'dev' mode. This is not suitable for production use. See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration for more information.`; }; export class App< T extends abstract new (...args: any) => any = any, P extends object = any, E = any > extends TemplateSet { static validateTarget = validateTarget; Root: ComponentConstructor
; props: P; env: E; scheduler = new Scheduler(); root: ComponentNode
| null = null; warnIfNoStaticProps: boolean; constructor(Root: ComponentConstructor
, config: AppConfig
= {}) {
super(config);
this.Root = Root;
if (config.test) {
this.dev = true;
}
this.warnIfNoStaticProps = config.warnIfNoStaticProps || false;
if (this.dev && !config.test && !hasBeenLogged) {
console.info(DEV_MSG());
hasBeenLogged = true;
}
const env = config.env || {};
const descrs = Object.getOwnPropertyDescriptors(env);
this.env = Object.freeze(Object.create(Object.getPrototypeOf(env), descrs));
this.props = config.props || ({} as P);
}
mount(target: HTMLElement, options?: MountOptions): Promise (
name: string | null,
isStatic: boolean,
hasSlotsProp: boolean,
hasDynamicPropList: boolean,
hasNoProp: boolean
) {
const isDynamic = !isStatic;
function _arePropsDifferent(props1: Props, props2: Props): boolean {
for (let k in props1) {
if (props1[k] !== props2[k]) {
return true;
}
}
return hasDynamicPropList && Object.keys(props1).length !== Object.keys(props2).length;
}
const arePropsDifferent = hasSlotsProp
? (_1: any, _2: any) => true
: hasNoProp
? (_1: any, _2: any) => false
: _arePropsDifferent;
const updateAndRender = ComponentNode.prototype.updateAndRender;
const initiateRender = ComponentNode.prototype.initiateRender;
return (props: P, key: string, ctx: ComponentNode, parent: any, C: any) => {
let children = ctx.children;
let node: any = children[key];
if (isDynamic && node && node.component.constructor !== C) {
node = undefined;
}
const parentFiber = ctx.fiber!;
if (node) {
if (arePropsDifferent(node.props, props) || parentFiber.deep || node.forceNextRender) {
node.forceNextRender = false;
updateAndRender.call(node, props, parentFiber);
}
} else {
// new component
if (isStatic) {
C = parent.constructor.components[name as any];
if (!C) {
throw new OwlError(`Cannot find the definition of component "${name}"`);
} else if (!(C.prototype instanceof Component)) {
throw new OwlError(
`"${name}" is not a Component. It must inherit from the Component class`
);
}
}
node = new ComponentNode(C, props, this, ctx, key);
children[key] = node;
initiateRender.call(node, new Fiber(node, parentFiber));
}
parentFiber.childrenMap[key] = node;
return node;
};
}
}
export async function mount<
T extends abstract new (...args: any) => any = any,
P extends object = any,
E = any
>(
C: T & ComponentConstructor ,
target: HTMLElement,
config: AppConfig & MountOptions = {}
): Promise