mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
make widget generic on State
This commit is contained in:
@@ -23,8 +23,8 @@ interface Meta<T extends WEnv> {
|
||||
isStarted: boolean;
|
||||
isMounted: boolean;
|
||||
isDestroyed: boolean;
|
||||
parent: Widget<T, {}> | null;
|
||||
children: { [key: number]: Widget<T, {}> };
|
||||
parent: BaseWidget<T, any, any> | null;
|
||||
children: { [key: number]: BaseWidget<T, any, any> };
|
||||
// children mapping: from templateID to widgetID
|
||||
// should it be a map number => Widget?
|
||||
cmap: { [key: number]: number };
|
||||
@@ -40,7 +40,7 @@ export interface Type<T> extends Function {
|
||||
// Widget
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export class Widget<T extends WEnv, Props> extends EventBus {
|
||||
export class BaseWidget<T extends WEnv, Props, State> extends EventBus {
|
||||
__widget__: Meta<WEnv>;
|
||||
template: string = "default";
|
||||
inlineTemplate: string | null = null;
|
||||
@@ -52,13 +52,15 @@ export class Widget<T extends WEnv, Props> extends EventBus {
|
||||
env: T;
|
||||
state: Object = {};
|
||||
props: Props;
|
||||
refs: { [key: string]: Widget<T, {}> | HTMLElement | undefined } = {};
|
||||
refs: {
|
||||
[key: string]: BaseWidget<T, any, any> | HTMLElement | undefined;
|
||||
} = {};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Lifecycle
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
constructor(parent: Widget<T, any> | T, props?: Props) {
|
||||
constructor(parent: BaseWidget<T, any, any> | T, props?: Props) {
|
||||
super();
|
||||
wl.push(this);
|
||||
|
||||
@@ -68,8 +70,8 @@ export class Widget<T extends WEnv, Props> extends EventBus {
|
||||
// Pro: but creating widget (by a template) is always unsafe anyway
|
||||
this.props = <Props>props;
|
||||
let id: number;
|
||||
let p: Widget<T, any> | null = null;
|
||||
if (parent instanceof Widget) {
|
||||
let p: BaseWidget<T, any, any> | null = null;
|
||||
if (parent instanceof BaseWidget) {
|
||||
p = parent;
|
||||
this.env = parent.env;
|
||||
id = this.env.getID();
|
||||
@@ -173,17 +175,11 @@ export class Widget<T extends WEnv, Props> extends EventBus {
|
||||
* - it is ok to call updateState before the widget is started. In that
|
||||
* case, it will simply update the state and will not rerender
|
||||
*/
|
||||
async updateState(nextState: Object) {
|
||||
async updateState(nextState: Partial<State>) {
|
||||
if (Object.keys(nextState).length === 0) {
|
||||
return;
|
||||
}
|
||||
for (let key in nextState) {
|
||||
if (key in this.state) {
|
||||
this.state[key] = nextState[key];
|
||||
} else {
|
||||
throw new Error(`Invalid key: '${key}' does not exist in widget state`);
|
||||
}
|
||||
}
|
||||
Object.assign(this.state, nextState);
|
||||
if (this.__widget__.isStarted) {
|
||||
return this.render();
|
||||
}
|
||||
@@ -259,7 +255,7 @@ export class Widget<T extends WEnv, Props> extends EventBus {
|
||||
}
|
||||
}
|
||||
|
||||
private visitSubTree(callback: (w: Widget<T, any>) => boolean) {
|
||||
private visitSubTree(callback: (w: BaseWidget<T, any, any>) => boolean) {
|
||||
const shouldVisitChildren = callback(this);
|
||||
if (shouldVisitChildren) {
|
||||
const children = this.__widget__.children;
|
||||
@@ -1,18 +1,22 @@
|
||||
import { QWeb } from "./core/qweb_vdom";
|
||||
import { idGenerator, memoize } from "./core/utils";
|
||||
import { WEnv } from "./core/widget";
|
||||
import { ActionManager, IActionManager } from "./services/action_manager";
|
||||
import { Ajax, IAjax } from "./core/ajax";
|
||||
import { WEnv } from "./core/base_widget";
|
||||
import {
|
||||
INotificationManager,
|
||||
NotificationManager
|
||||
} from "./core/notifications";
|
||||
import { actionRegistry } from "./registries";
|
||||
import { QWeb } from "./core/qweb_vdom";
|
||||
import { Registry } from "./core/registry";
|
||||
import { IRouter, Router } from "./core/router";
|
||||
import { idGenerator, memoize } from "./core/utils";
|
||||
import { actionRegistry } from "./registries";
|
||||
import {
|
||||
ActionManager,
|
||||
ActionWidget,
|
||||
IActionManager
|
||||
} from "./services/action_manager";
|
||||
import { CRM } from "./widgets/crm";
|
||||
import { Discuss } from "./widgets/discuss";
|
||||
import { Widget, Type } from "./core/widget";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -30,7 +34,7 @@ export interface Env extends WEnv {
|
||||
router: IRouter;
|
||||
|
||||
// registries
|
||||
actionRegistry: Registry<Type<Widget<Env, any>>>;
|
||||
actionRegistry: Registry<ActionWidget>;
|
||||
|
||||
// data
|
||||
menus: Menu[];
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Registry } from "./core/registry";
|
||||
import { Widget, Type } from "./core/widget";
|
||||
import { Env } from "./env";
|
||||
import { ActionWidget } from "./services/action_manager";
|
||||
|
||||
export const actionRegistry: Registry<Type<Widget<Env, any>>> = new Registry();
|
||||
export const actionRegistry: Registry<ActionWidget> = new Registry();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Type } from "../core/base_widget";
|
||||
import { EventBus } from "../core/event_bus";
|
||||
import { Registry } from "../core/registry";
|
||||
import { Type, Widget } from "../core/widget";
|
||||
import { Env } from "../env";
|
||||
import { Widget } from "../widgets/widget";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
@@ -18,10 +18,12 @@ export interface CommonActionInfo {
|
||||
target: "current" | "new";
|
||||
}
|
||||
|
||||
export type ActionWidget = Type<Widget<{}, {}>>;
|
||||
|
||||
export interface ClientActionInfo extends CommonActionInfo {
|
||||
type: "client";
|
||||
name: string;
|
||||
Widget: Type<Widget<Env, {}>>;
|
||||
Widget: ActionWidget;
|
||||
}
|
||||
|
||||
export interface ActWindowInfo extends CommonActionInfo {
|
||||
@@ -47,10 +49,10 @@ export interface IActionManager {
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export class ActionManager extends EventBus implements IActionManager {
|
||||
registry: Registry<Type<Widget<Env, any>>>;
|
||||
registry: Registry<ActionWidget>;
|
||||
stack: ActionStack;
|
||||
|
||||
constructor(registry: Registry<Type<Widget<Env, any>>>) {
|
||||
constructor(registry: Registry<ActionWidget>) {
|
||||
super();
|
||||
this.registry = registry;
|
||||
this.stack = [];
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Widget } from "../core/widget";
|
||||
import { Env } from "../env";
|
||||
import { Widget } from "./widget";
|
||||
|
||||
export class CRM extends Widget<Env, {}> {
|
||||
export class CRM extends Widget<{}, {}> {
|
||||
template = "web.crm";
|
||||
}
|
||||
|
||||
@@ -1,22 +1,34 @@
|
||||
import { Widget } from "../core/widget";
|
||||
import { Env } from "../env";
|
||||
import { Widget } from "./widget";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
interface Props {
|
||||
initialState?: number;
|
||||
}
|
||||
|
||||
export class Counter extends Widget<Env, Props> {
|
||||
interface State {
|
||||
counter: number;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Counter
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export class Counter extends Widget<Props, State> {
|
||||
inlineTemplate = `
|
||||
<div t-name="counter">
|
||||
<button t-on-click="increment(-1)">-</button>
|
||||
<span style="font-weight:bold">Value: <t t-esc="state.counter"/></span>
|
||||
<button t-on-click="increment(1)">+</button>
|
||||
</div>`;
|
||||
|
||||
state = {
|
||||
counter: 0
|
||||
};
|
||||
|
||||
constructor(parent: Widget<Env, {}>, props: Props) {
|
||||
constructor(parent: Widget<any, any>, props: Props) {
|
||||
super(parent, props);
|
||||
this.state.counter = props.initialState || 0;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
import { Widget } from "../core/widget";
|
||||
import { Env } from "../env";
|
||||
import { Clock } from "./clock";
|
||||
import { Counter } from "./counter";
|
||||
import { Widget } from "./widget";
|
||||
|
||||
export class Discuss extends Widget<Env, {}> {
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
interface State {
|
||||
validcounter: boolean;
|
||||
color: "red" | "blue";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Discuss
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export class Discuss extends Widget<{}, State> {
|
||||
template = "web.discuss";
|
||||
widgets = { Clock, Counter, ColorWidget };
|
||||
state = { validcounter: true, color: "red" };
|
||||
@@ -38,7 +50,7 @@ export class Discuss extends Widget<Env, {}> {
|
||||
}
|
||||
}
|
||||
|
||||
class ColorWidget extends Widget<Env, { color: "red" | "blue" }> {
|
||||
class ColorWidget extends Widget<{ color: "red" | "blue" }, {}> {
|
||||
inlineTemplate = `
|
||||
<div t-name="colorwidget">
|
||||
<span>Current Color: </span>
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
import { Widget } from "../core/widget";
|
||||
import { Env, Menu } from "../env";
|
||||
import { Menu } from "../env";
|
||||
import { MenuItem } from "../misc/menu_helpers";
|
||||
import { Widget } from "./widget";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export interface Props {
|
||||
inHome: boolean;
|
||||
app: MenuItem | null;
|
||||
}
|
||||
|
||||
export class Navbar extends Widget<Env, Props> {
|
||||
//------------------------------------------------------------------------------
|
||||
// Navbar
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export class Navbar extends Widget<Props, {}> {
|
||||
template = "web.navbar";
|
||||
|
||||
getUrl(menu: Menu) {
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { Widget } from "../core/widget";
|
||||
import { Env } from "../env";
|
||||
import { ActionStack } from "../services/action_manager";
|
||||
import { Widget } from "./widget";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export interface Props {
|
||||
stack: ActionStack;
|
||||
}
|
||||
|
||||
export class ActionContainer extends Widget<Env, Props> {
|
||||
//------------------------------------------------------------------------------
|
||||
// Action Container
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export class ActionContainer extends Widget<Props, {}> {
|
||||
template = "web.action_container";
|
||||
currentWidget: any;
|
||||
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
import { Widget } from "../core/widget";
|
||||
import { Env } from "../env";
|
||||
import { Widget } from "./widget";
|
||||
|
||||
export class Clock extends Widget<Env, {}> {
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
interface State {
|
||||
currentTime: string;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Clock
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export class Clock extends Widget<{}, State> {
|
||||
inlineTemplate = `<div class="o_clock"><t t-esc="state.currentTime"/></div>`;
|
||||
timeout: any | undefined;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Widget } from "../core/widget";
|
||||
import { Env } from "../env";
|
||||
import { MenuInfo, MenuItem } from "../misc/menu_helpers";
|
||||
import { Widget } from "./widget";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
@@ -14,7 +13,7 @@ export interface Props {
|
||||
// Home Menu
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export class HomeMenu extends Widget<Env, Props> {
|
||||
export class HomeMenu extends Widget<Props, {}> {
|
||||
template = "web.home_menu";
|
||||
|
||||
get apps(): MenuItem[] {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Widget } from "../core/widget";
|
||||
import { Env } from "../env";
|
||||
import { INotification } from "../core/notifications";
|
||||
import { Widget } from "./widget";
|
||||
|
||||
export class Notification extends Widget<Env, INotification> {
|
||||
export class Notification extends Widget<INotification, {}> {
|
||||
template = "web.notification";
|
||||
|
||||
close() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INotification } from "../core/notifications";
|
||||
import { Widget } from "../core/widget";
|
||||
import { Widget } from "./widget";
|
||||
import { Env } from "../env";
|
||||
import { MenuInfo, MenuItem, getAppAndAction } from "../misc/menu_helpers";
|
||||
import { ActionStack } from "../services/action_manager";
|
||||
@@ -28,7 +28,7 @@ interface Props {
|
||||
// Root Widget
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export class Root extends Widget<Env, Props> {
|
||||
export class Root extends Widget<Props, State> {
|
||||
template = "web.web_client";
|
||||
widgets = { Navbar, Notification, HomeMenu, ActionContainer };
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import { BaseWidget } from "../core/base_widget";
|
||||
import { Env } from "../env";
|
||||
|
||||
export class Widget<Props, State> extends BaseWidget<Env, Props, State> {}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { WEnv, Widget } from "../../src/ts/core/widget";
|
||||
import { makeTestWEnv, makeTestFixture } from "../helpers";
|
||||
import { normalize } from "../helpers";
|
||||
import { BaseWidget, WEnv } from "../../src/ts/core/base_widget";
|
||||
import { makeTestFixture, makeTestWEnv, normalize } from "../helpers";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Setup and helpers
|
||||
@@ -34,13 +33,16 @@ function nextTick(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function children(w: Widget<WEnv, {}>): Widget<WEnv, {}>[] {
|
||||
class Widget extends BaseWidget<WEnv, {}, {}> {}
|
||||
|
||||
function children(w: Widget): Widget[] {
|
||||
const childrenMap = w.__widget__.children;
|
||||
return Object.keys(childrenMap).map(id => childrenMap[id]);
|
||||
}
|
||||
|
||||
// Test widgets
|
||||
class Counter extends Widget<WEnv, {}> {
|
||||
class Counter extends Widget {
|
||||
// class Counter extends Widget<WEnv, {}, {counter: number}> {
|
||||
template = "counter";
|
||||
state = {
|
||||
counter: 0
|
||||
@@ -51,12 +53,12 @@ class Counter extends Widget<WEnv, {}> {
|
||||
}
|
||||
}
|
||||
|
||||
class WidgetA extends Widget<WEnv, {}> {
|
||||
class WidgetA extends Widget {
|
||||
template = "widgetA";
|
||||
widgets = { b: WidgetB };
|
||||
}
|
||||
|
||||
class WidgetB extends Widget<WEnv, {}> {
|
||||
class WidgetB extends Widget {
|
||||
template = "widgetB";
|
||||
}
|
||||
|
||||
@@ -88,7 +90,7 @@ describe("basic widget properties", () => {
|
||||
});
|
||||
|
||||
test("widget style and classname", async () => {
|
||||
class StyledWidget extends Widget<WEnv, {}> {
|
||||
class StyledWidget extends Widget {
|
||||
inlineTemplate = `<div style="font-weight:bold;" class="some-class">world</div>`;
|
||||
}
|
||||
const widget = new StyledWidget(env);
|
||||
@@ -100,7 +102,7 @@ describe("basic widget properties", () => {
|
||||
|
||||
test("updateState before first render does not trigger a render", async () => {
|
||||
let renderCalls = 0;
|
||||
class TestW extends Widget<WEnv, {}> {
|
||||
class TestW extends Widget {
|
||||
async willStart() {
|
||||
this.updateState({});
|
||||
}
|
||||
@@ -142,7 +144,7 @@ describe("basic widget properties", () => {
|
||||
describe("lifecycle hooks", () => {
|
||||
test("willStart hook is called", async () => {
|
||||
let willstart = false;
|
||||
class HookWidget extends Widget<WEnv, {}> {
|
||||
class HookWidget extends Widget {
|
||||
async willStart() {
|
||||
willstart = true;
|
||||
}
|
||||
@@ -154,7 +156,7 @@ describe("lifecycle hooks", () => {
|
||||
|
||||
test("mounted hook is not called if not in DOM", async () => {
|
||||
let mounted = false;
|
||||
class HookWidget extends Widget<WEnv, {}> {
|
||||
class HookWidget extends Widget {
|
||||
async mounted() {
|
||||
mounted = true;
|
||||
}
|
||||
@@ -167,7 +169,7 @@ describe("lifecycle hooks", () => {
|
||||
|
||||
test("mounted hook is called if mounted in DOM", async () => {
|
||||
let mounted = false;
|
||||
class HookWidget extends Widget<WEnv, {}> {
|
||||
class HookWidget extends Widget {
|
||||
async mounted() {
|
||||
mounted = true;
|
||||
}
|
||||
@@ -179,11 +181,11 @@ describe("lifecycle hooks", () => {
|
||||
|
||||
test("willStart hook is called on subwidget", async () => {
|
||||
let ok = false;
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
inlineTemplate = `<div><t t-widget="child"/></div>`;
|
||||
widgets = { child: ChildWidget };
|
||||
}
|
||||
class ChildWidget extends Widget<WEnv, {}> {
|
||||
class ChildWidget extends Widget {
|
||||
async willStart() {
|
||||
ok = true;
|
||||
}
|
||||
@@ -197,7 +199,7 @@ describe("lifecycle hooks", () => {
|
||||
expect.assertions(4);
|
||||
let parentMounted = false;
|
||||
let childMounted = false;
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
inlineTemplate = `<div><t t-widget="child"/></div>`;
|
||||
widgets = { child: ChildWidget };
|
||||
mounted() {
|
||||
@@ -205,7 +207,7 @@ describe("lifecycle hooks", () => {
|
||||
parentMounted = true;
|
||||
}
|
||||
}
|
||||
class ChildWidget extends Widget<WEnv, {}> {
|
||||
class ChildWidget extends Widget {
|
||||
mounted() {
|
||||
expect(document.body.contains(this.el)).toBe(true);
|
||||
expect(parentMounted).toBe(true);
|
||||
@@ -223,7 +225,7 @@ describe("lifecycle hooks", () => {
|
||||
// the t-else part in the template is important. This is
|
||||
// necessary to have a situation that could confuse the vdom
|
||||
// patching algorithm
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
inlineTemplate = `
|
||||
<div>
|
||||
<t t-if="state.ok">
|
||||
@@ -236,7 +238,7 @@ describe("lifecycle hooks", () => {
|
||||
state = { ok: false };
|
||||
widgets = { child: ChildWidget };
|
||||
}
|
||||
class ChildWidget extends Widget<WEnv, {}> {
|
||||
class ChildWidget extends Widget {
|
||||
async willStart() {
|
||||
hookCounter++;
|
||||
}
|
||||
@@ -261,13 +263,13 @@ describe("lifecycle hooks", () => {
|
||||
expect.assertions(1);
|
||||
const target = document.createElement("div");
|
||||
document.body.appendChild(target);
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
mounted() {
|
||||
const child = new ChildWidget(this);
|
||||
child.mount(this.el!);
|
||||
}
|
||||
}
|
||||
class ChildWidget extends Widget<WEnv, {}> {
|
||||
class ChildWidget extends Widget {
|
||||
mounted() {
|
||||
expect(this.el).toBeTruthy();
|
||||
done();
|
||||
@@ -279,7 +281,7 @@ describe("lifecycle hooks", () => {
|
||||
|
||||
test("widgets are unmounted and destroyed if no longer in DOM", async () => {
|
||||
let steps: string[] = [];
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
state = { ok: true };
|
||||
inlineTemplate = `<div>
|
||||
<t t-if="state.ok"><t t-widget="child"/></t>
|
||||
@@ -287,7 +289,7 @@ describe("lifecycle hooks", () => {
|
||||
widgets = { child: ChildWidget };
|
||||
}
|
||||
|
||||
class ChildWidget extends Widget<WEnv, {}> {
|
||||
class ChildWidget extends Widget {
|
||||
constructor(parent) {
|
||||
super(parent);
|
||||
steps.push("init");
|
||||
@@ -320,7 +322,7 @@ describe("lifecycle hooks", () => {
|
||||
|
||||
test("hooks are called in proper order in widget creation/destruction", async () => {
|
||||
let steps: string[] = [];
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
inlineTemplate = `<div><t t-widget="child"/></div>`;
|
||||
widgets = { child: ChildWidget };
|
||||
constructor(parent) {
|
||||
@@ -341,7 +343,7 @@ describe("lifecycle hooks", () => {
|
||||
}
|
||||
}
|
||||
|
||||
class ChildWidget extends Widget<WEnv, {}> {
|
||||
class ChildWidget extends Widget {
|
||||
constructor(parent) {
|
||||
super(parent);
|
||||
steps.push("c init");
|
||||
@@ -378,7 +380,7 @@ describe("lifecycle hooks", () => {
|
||||
|
||||
test("shouldUpdate hook prevent rerendering", async () => {
|
||||
let shouldUpdate = false;
|
||||
class TestWidget extends Widget<WEnv, {}> {
|
||||
class TestWidget extends Widget {
|
||||
inlineTemplate = `<div><t t-esc="props.val"/></div>`;
|
||||
shouldUpdate() {
|
||||
return shouldUpdate;
|
||||
@@ -408,7 +410,7 @@ describe("destroy method", () => {
|
||||
|
||||
test("destroying a widget twice only call destroyed once", async () => {
|
||||
let count = 0;
|
||||
class TestWidget extends Widget<WEnv, {}> {
|
||||
class TestWidget extends Widget {
|
||||
destroyed() {
|
||||
count++;
|
||||
}
|
||||
@@ -450,7 +452,7 @@ describe("destroy method", () => {
|
||||
let p: Promise<void> = new Promise(function(r) {
|
||||
resolve = r;
|
||||
});
|
||||
class DelayedWidget extends Widget<WEnv, {}> {
|
||||
class DelayedWidget extends Widget {
|
||||
willStart() {
|
||||
return p;
|
||||
}
|
||||
@@ -490,7 +492,7 @@ describe("composition", () => {
|
||||
});
|
||||
|
||||
test("t-refs on widget are widgets", async () => {
|
||||
class WidgetC extends Widget<WEnv, {}> {
|
||||
class WidgetC extends Widget {
|
||||
inlineTemplate = `<div>Hello<t t-ref="mywidgetb" t-widget="b"/></div>`;
|
||||
widgets = { b: WidgetB };
|
||||
}
|
||||
@@ -500,7 +502,7 @@ describe("composition", () => {
|
||||
});
|
||||
|
||||
test("modifying a sub widget", async () => {
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
inlineTemplate = `<div><t t-widget="Counter"/></div>`;
|
||||
widgets = { Counter };
|
||||
}
|
||||
@@ -538,7 +540,7 @@ describe("composition", () => {
|
||||
});
|
||||
|
||||
test("rerendering a widget with a sub widget", async () => {
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
inlineTemplate = `<div><t t-widget="Counter"/></div>`;
|
||||
widgets = { Counter };
|
||||
}
|
||||
@@ -557,7 +559,7 @@ describe("composition", () => {
|
||||
});
|
||||
|
||||
test("sub widgets are destroyed if no longer in dom, then recreated", async () => {
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
state = { ok: true };
|
||||
inlineTemplate = `<div><t t-if="state.ok"><t t-widget="counter"/></t></div>`;
|
||||
widgets = { counter: Counter };
|
||||
@@ -579,7 +581,7 @@ describe("composition", () => {
|
||||
});
|
||||
|
||||
test("sub widgets with t-keep-alive are not destroyed if no longer in dom", async () => {
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
state = { ok: true };
|
||||
inlineTemplate = `<div><t t-if="state.ok"><t t-widget="counter" t-keep-alive="1"/></t></div>`;
|
||||
widgets = { counter: Counter };
|
||||
@@ -605,12 +607,12 @@ describe("composition", () => {
|
||||
});
|
||||
|
||||
test("sub widgets dom state with t-keep-alive is preserved", async () => {
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
state = { ok: true };
|
||||
inlineTemplate = `<div><t t-if="state.ok"><t t-widget="InputWidget" t-keep-alive="1"/></t></div>`;
|
||||
widgets = { InputWidget };
|
||||
}
|
||||
class InputWidget extends Widget<WEnv, {}> {
|
||||
class InputWidget extends Widget {
|
||||
inlineTemplate = "<input/>";
|
||||
}
|
||||
const widget = new ParentWidget(env);
|
||||
@@ -627,11 +629,11 @@ describe("composition", () => {
|
||||
});
|
||||
|
||||
test("sub widgets rendered in a loop", async () => {
|
||||
class ChildWidget extends Widget<WEnv, { n: number }> {
|
||||
class ChildWidget extends Widget {
|
||||
inlineTemplate = `<span><t t-esc="props.n"/></span>`;
|
||||
}
|
||||
|
||||
class Parent extends Widget<WEnv, {}> {
|
||||
class Parent extends Widget {
|
||||
inlineTemplate = `
|
||||
<div>
|
||||
<t t-foreach="state.numbers" t-as="number">
|
||||
@@ -658,7 +660,7 @@ describe("composition", () => {
|
||||
|
||||
test("sub widgets with some state rendered in a loop", async () => {
|
||||
let n = 1;
|
||||
class ChildWidget extends Widget<WEnv, never> {
|
||||
class ChildWidget extends Widget {
|
||||
inlineTemplate = `<span><t t-esc="state.n"/></span>`;
|
||||
constructor(parent) {
|
||||
super(parent);
|
||||
@@ -667,7 +669,7 @@ describe("composition", () => {
|
||||
}
|
||||
}
|
||||
|
||||
class Parent extends Widget<WEnv, {}> {
|
||||
class Parent extends Widget {
|
||||
inlineTemplate = `<div>
|
||||
<t t-foreach="state.numbers" t-as="number">
|
||||
<t t-widget="ChildWidget" t-key="number"/>
|
||||
@@ -694,13 +696,13 @@ describe("composition", () => {
|
||||
|
||||
describe("props evaluation (with t-props directive)", () => {
|
||||
test("explicit object prop", async () => {
|
||||
class Parent extends Widget<WEnv, {}> {
|
||||
class Parent extends Widget {
|
||||
inlineTemplate = `<div><t t-widget="child" t-props="{value: state.val}"/></div>`;
|
||||
widgets = { child: Child };
|
||||
state = { val: 42 };
|
||||
}
|
||||
|
||||
class Child extends Widget<WEnv, {}> {
|
||||
class Child extends Widget {
|
||||
inlineTemplate = `<span><t t-esc="state.someval"/></span>`;
|
||||
state: { someval: number };
|
||||
constructor(parent: Parent, props: { value: number }) {
|
||||
@@ -715,13 +717,13 @@ describe("props evaluation (with t-props directive)", () => {
|
||||
});
|
||||
|
||||
test("object prop value", async () => {
|
||||
class Parent extends Widget<WEnv, {}> {
|
||||
class Parent extends Widget {
|
||||
inlineTemplate = `<div><t t-widget="child" t-props="state"/></div>`;
|
||||
widgets = { child: Child };
|
||||
state = { val: 42 };
|
||||
}
|
||||
|
||||
class Child extends Widget<WEnv, {}> {
|
||||
class Child extends Widget {
|
||||
inlineTemplate = `<span><t t-esc="state.someval"/></span>`;
|
||||
state: { someval: number };
|
||||
constructor(parent: Parent, props: { val: number }) {
|
||||
@@ -739,7 +741,7 @@ describe("props evaluation (with t-props directive)", () => {
|
||||
describe("t-on directive on widgets", () => {
|
||||
test("t-on works as expected", async () => {
|
||||
let n = 0;
|
||||
class ParentWidget extends Widget<WEnv, {}> {
|
||||
class ParentWidget extends Widget {
|
||||
inlineTemplate = `<div><t t-widget="child" t-on-customevent="someMethod"/></div>`;
|
||||
widgets = { child: Child };
|
||||
someMethod(arg) {
|
||||
@@ -747,7 +749,7 @@ describe("t-on directive on widgets", () => {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
class Child extends Widget<WEnv, {}> {}
|
||||
class Child extends Widget {}
|
||||
const widget = new ParentWidget(env);
|
||||
await widget.mount(fixture);
|
||||
let child = children(widget)[0];
|
||||
@@ -765,7 +767,7 @@ describe("random stuff/miscellaneous", () => {
|
||||
// this test makes sure that the foreach directive does not pollute sub
|
||||
// context with the inLoop variable, which is then used in the t-widget
|
||||
// directive as a key
|
||||
class Test extends Widget<WEnv, {}> {
|
||||
class Test extends Widget {
|
||||
inlineTemplate = `<div><t t-foreach="2">txt</t><t t-widget="widget"/></div>`;
|
||||
widgets = { widget: Widget };
|
||||
}
|
||||
@@ -778,13 +780,13 @@ describe("random stuff/miscellaneous", () => {
|
||||
// in this situation, we protect against a bug that occurred: because of the
|
||||
// interplay between widgets and vnodes, a sub widget vnode was patched
|
||||
// twice.
|
||||
class Parent extends Widget<WEnv, {}> {
|
||||
class Parent extends Widget {
|
||||
inlineTemplate = `<div><t t-widget="child" t-props="state"/></div>`;
|
||||
widgets = { child: Child };
|
||||
state = { flag: false };
|
||||
}
|
||||
|
||||
class Child extends Widget<WEnv, {}> {
|
||||
class Child extends Widget {
|
||||
inlineTemplate = `<span>abc<t t-if="props.flag">def</t></span>`;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { QWeb } from "../src/ts/core/qweb_vdom";
|
||||
import { idGenerator } from "../src/ts/core/utils";
|
||||
import { WEnv } from "../src/ts/core/widget";
|
||||
import { WEnv } from "../src/ts/core/base_widget";
|
||||
import { Env } from "../src/ts/env";
|
||||
import { IAjax, RPCQuery } from "../src/ts/core/ajax";
|
||||
import { Registry } from "../src/ts/core/registry";
|
||||
|
||||
Reference in New Issue
Block a user