mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
widget is now a bus, add t-on directive on widgets
This commit is contained in:
@@ -3,6 +3,7 @@ import sdListeners from "../../../libs/snabbdom/src/modules/eventlisteners";
|
|||||||
import { init } from "../../../libs/snabbdom/src/snabbdom";
|
import { init } from "../../../libs/snabbdom/src/snabbdom";
|
||||||
import { VNode } from "../../../libs/snabbdom/src/vnode";
|
import { VNode } from "../../../libs/snabbdom/src/vnode";
|
||||||
import { QWeb } from "./qweb_vdom";
|
import { QWeb } from "./qweb_vdom";
|
||||||
|
import { EventBus } from "./event_bus";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Types/helpers
|
// Types/helpers
|
||||||
@@ -39,7 +40,7 @@ export interface Type<T> extends Function {
|
|||||||
// Widget
|
// Widget
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
export class Widget<T extends WEnv, Props> {
|
export class Widget<T extends WEnv, Props> extends EventBus {
|
||||||
__widget__: Meta<WEnv>;
|
__widget__: Meta<WEnv>;
|
||||||
template: string = "default";
|
template: string = "default";
|
||||||
|
|
||||||
@@ -57,6 +58,7 @@ export class Widget<T extends WEnv, Props> {
|
|||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
constructor(parent: Widget<T, any> | T, props?: Props) {
|
constructor(parent: Widget<T, any> | T, props?: Props) {
|
||||||
|
super();
|
||||||
wl.push(this);
|
wl.push(this);
|
||||||
// is this a good idea?
|
// is this a good idea?
|
||||||
// Pro: if props is empty, we can create easily a widget
|
// Pro: if props is empty, we can create easily a widget
|
||||||
@@ -154,6 +156,7 @@ export class Widget<T extends WEnv, Props> {
|
|||||||
delete this.__widget__.parent.__widget__.children[id];
|
delete this.__widget__.parent.__widget__.children[id];
|
||||||
this.__widget__.parent = null;
|
this.__widget__.parent = null;
|
||||||
}
|
}
|
||||||
|
this.clear();
|
||||||
this.__widget__.isDestroyed = true;
|
this.__widget__.isDestroyed = true;
|
||||||
this.destroyed();
|
this.destroyed();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,4 +64,8 @@ export class EventBus {
|
|||||||
sub.callback.call(sub.owner, ...args);
|
sub.callback.call(sub.owner, ...args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.subscriptions = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -733,6 +733,17 @@ const widgetDirective: Directive = {
|
|||||||
ctx.rootContext.shouldDefineOwner = true;
|
ctx.rootContext.shouldDefineOwner = true;
|
||||||
let props = node.getAttribute("t-props");
|
let props = node.getAttribute("t-props");
|
||||||
let keepAlive = node.getAttribute("t-keep-alive") ? true : false;
|
let keepAlive = node.getAttribute("t-keep-alive") ? true : false;
|
||||||
|
|
||||||
|
// t-on- events...
|
||||||
|
const events: [string, string][] = [];
|
||||||
|
const attributes = (<Element>node).attributes;
|
||||||
|
for (let i = 0; i < attributes.length; i++) {
|
||||||
|
const name = attributes[i].name;
|
||||||
|
if (name.startsWith("t-on-")) {
|
||||||
|
events.push([name.slice(5), attributes[i].textContent!]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let key = node.getAttribute("t-key");
|
let key = node.getAttribute("t-key");
|
||||||
if (key) {
|
if (key) {
|
||||||
key = qweb._formatExpression(key);
|
key = qweb._formatExpression(key);
|
||||||
@@ -792,6 +803,10 @@ const widgetDirective: Directive = {
|
|||||||
ctx.addLine(
|
ctx.addLine(
|
||||||
`context.__widget__.cmap[${templateID}] = _${widgetID}.__widget__.id;`
|
`context.__widget__.cmap[${templateID}] = _${widgetID}.__widget__.id;`
|
||||||
);
|
);
|
||||||
|
for (let [event, method] of events) {
|
||||||
|
ctx.addLine(`_${widgetID}.on('${event}', owner, owner['${method}'])`);
|
||||||
|
}
|
||||||
|
|
||||||
ctx.addLine(
|
ctx.addLine(
|
||||||
`def${defID} = _${widgetID}._start().then(() => _${widgetID}._render()).then(vnode=>{let pvnode=h(vnode.sel, {key: ${templateID}});c${
|
`def${defID} = _${widgetID}._start().then(() => _${widgetID}._render()).then(vnode=>{let pvnode=h(vnode.sel, {key: ${templateID}});c${
|
||||||
ctx.parentNode
|
ctx.parentNode
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import { Widget } from "../core/widget";
|
|||||||
import { Env, Menu } from "../env";
|
import { Env, Menu } from "../env";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
toggleHome: () => void;
|
inHome: boolean;
|
||||||
inMenu: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Navbar extends Widget<Env, Props> {
|
export class Navbar extends Widget<Env, Props> {
|
||||||
@@ -16,6 +15,6 @@ export class Navbar extends Widget<Env, Props> {
|
|||||||
|
|
||||||
toggleHome(ev: MouseEvent) {
|
toggleHome(ev: MouseEvent) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.props.toggleHome();
|
this.trigger("toggle-home-menu");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { Notification } from "./notification";
|
|||||||
interface State {
|
interface State {
|
||||||
notifications: INotification[];
|
notifications: INotification[];
|
||||||
stack: ActionStack;
|
stack: ActionStack;
|
||||||
inMenu: boolean;
|
inHome: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -28,7 +28,7 @@ export class Root extends Widget<Env, {}> {
|
|||||||
state: State = {
|
state: State = {
|
||||||
notifications: [],
|
notifications: [],
|
||||||
stack: [],
|
stack: [],
|
||||||
inMenu: false
|
inHome: false
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(env: Env) {
|
constructor(env: Env) {
|
||||||
@@ -47,6 +47,6 @@ export class Root extends Widget<Env, {}> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleHome() {
|
toggleHome() {
|
||||||
this.updateState({ inMenu: !this.state.inMenu });
|
this.updateState({ inHome: !this.state.inHome });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -794,7 +794,35 @@ describe("props evaluation (with t-props directive)", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("random stuff", () => {
|
describe("t-on directive on widgets", () => {
|
||||||
|
test("t-on works as expected", async () => {
|
||||||
|
let n = 0;
|
||||||
|
env.qweb.addTemplate(
|
||||||
|
"parent",
|
||||||
|
`<div><t t-widget="child" t-on-customevent="someMethod"/></div>`
|
||||||
|
);
|
||||||
|
class ParentWidget extends Widget<WEnv, {}> {
|
||||||
|
template = "parent";
|
||||||
|
widgets = { child: Child };
|
||||||
|
someMethod(arg) {
|
||||||
|
expect(arg).toBe(43);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Child extends Widget<WEnv, {}> {}
|
||||||
|
const widget = new ParentWidget(env);
|
||||||
|
await widget.mount(fixture);
|
||||||
|
let child = children(widget)[0];
|
||||||
|
expect(n).toBe(0);
|
||||||
|
child.trigger("customevent", 43);
|
||||||
|
expect(n).toBe(1);
|
||||||
|
child.destroy();
|
||||||
|
child.trigger("customevent", 43);
|
||||||
|
expect(n).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("random stuff/miscellaneous", () => {
|
||||||
test("widget after a t-foreach", async () => {
|
test("widget after a t-foreach", async () => {
|
||||||
// this test makes sure that the foreach directive does not pollute sub
|
// 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
|
// context with the inLoop variable, which is then used in the t-widget
|
||||||
@@ -811,9 +839,7 @@ describe("random stuff", () => {
|
|||||||
await widget.mount(fixture);
|
await widget.mount(fixture);
|
||||||
expect(fixture.innerHTML).toBe("<div>txttxt<div></div></div>");
|
expect(fixture.innerHTML).toBe("<div>txttxt<div></div></div>");
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe("miscellaneous", () => {
|
|
||||||
test("updating widget immediately", async () => {
|
test("updating widget immediately", async () => {
|
||||||
// in this situation, we protect against a bug that occurred: because of the
|
// in this situation, we protect against a bug that occurred: because of the
|
||||||
// interplay between widgets and vnodes, a sub widget vnode was patched
|
// interplay between widgets and vnodes, a sub widget vnode was patched
|
||||||
|
|||||||
Reference in New Issue
Block a user