mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] allow to combine directives using node hooks
e.g. t-ref and t-transition, or t-mounted and t-transition.
This commit is contained in:
committed by
Géry Debongnie
parent
0aba9748c9
commit
1760d0d336
+31
-3
@@ -31,7 +31,6 @@ interface Template {
|
||||
}
|
||||
|
||||
interface CompilationInfo {
|
||||
nodeID?: number;
|
||||
node: Element;
|
||||
qweb: QWeb;
|
||||
ctx: Context;
|
||||
@@ -39,6 +38,11 @@ interface CompilationInfo {
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface NodeCreationCompilationInfo extends CompilationInfo {
|
||||
nodeID: number;
|
||||
addNodeHook: Function;
|
||||
}
|
||||
|
||||
export interface Directive {
|
||||
name: string;
|
||||
extraNames?: string[];
|
||||
@@ -46,7 +50,7 @@ export interface Directive {
|
||||
// if return true, then directive is fully applied and there is no need to
|
||||
// keep processing node. Otherwise, we keep going.
|
||||
atNodeEncounter?(info: CompilationInfo): boolean | void;
|
||||
atNodeCreation?(info: CompilationInfo): void;
|
||||
atNodeCreation?(info: NodeCreationCompilationInfo): void;
|
||||
finalize?(info: CompilationInfo): void;
|
||||
}
|
||||
|
||||
@@ -87,6 +91,12 @@ const DIRECTIVE_NAMES = {
|
||||
|
||||
const DIRECTIVES: Directive[] = [];
|
||||
|
||||
const NODE_HOOKS_PARAMS = {
|
||||
create: "(_, n)",
|
||||
insert: "vn",
|
||||
remove: "(vn, rm)"
|
||||
};
|
||||
|
||||
export const UTILS = {
|
||||
h: h,
|
||||
objectToAttrString(obj: Object): string {
|
||||
@@ -497,6 +507,11 @@ export class QWeb {
|
||||
if (node.nodeName !== "t") {
|
||||
let nodeID = this._compileGenericNode(node, ctx, withHandlers);
|
||||
ctx = ctx.withParent(nodeID);
|
||||
let nodeHooks = {};
|
||||
let addNodeHook = function(hook, handler) {
|
||||
nodeHooks[hook] = nodeHooks[hook] || [];
|
||||
nodeHooks[hook].push(handler);
|
||||
};
|
||||
|
||||
for (let { directive, value, fullName } of validDirectives) {
|
||||
if (directive.atNodeCreation) {
|
||||
@@ -506,10 +521,23 @@ export class QWeb {
|
||||
ctx,
|
||||
fullName,
|
||||
value,
|
||||
nodeID
|
||||
nodeID,
|
||||
addNodeHook
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(nodeHooks).length) {
|
||||
ctx.addLine(`p${nodeID}.hook = {`);
|
||||
for (let hook in nodeHooks) {
|
||||
ctx.addLine(` ${hook}: ${NODE_HOOKS_PARAMS[hook]} => {`);
|
||||
for (let handler of nodeHooks[hook]) {
|
||||
ctx.addLine(` ${handler}`);
|
||||
}
|
||||
ctx.addLine(` },`);
|
||||
}
|
||||
ctx.addLine(`};`);
|
||||
}
|
||||
}
|
||||
if (node.nodeName === "pre") {
|
||||
ctx = ctx.subContext("inPreTag", true);
|
||||
|
||||
+16
-20
@@ -57,12 +57,10 @@ QWeb.addDirective({
|
||||
QWeb.addDirective({
|
||||
name: "ref",
|
||||
priority: 95,
|
||||
atNodeCreation({ ctx, nodeID, value }) {
|
||||
atNodeCreation({ ctx, nodeID, value, addNodeHook }) {
|
||||
const refKey = `ref${ctx.generateID()}`;
|
||||
ctx.addLine(`const ${refKey} = ${ctx.formatExpression(value)}`);
|
||||
ctx.addLine(`p${nodeID}.hook = {
|
||||
create: (_, n) => context.refs[${refKey}] = n.elm,
|
||||
};`);
|
||||
addNodeHook("create", `context.refs[${refKey}] = n.elm;`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -148,19 +146,16 @@ function whenTransitionEnd(elm: HTMLElement, cb) {
|
||||
QWeb.addDirective({
|
||||
name: "transition",
|
||||
priority: 96,
|
||||
atNodeCreation({ ctx, value, nodeID }) {
|
||||
atNodeCreation({ ctx, value, addNodeHook }) {
|
||||
let name = value;
|
||||
ctx.addLine(`p${nodeID}.hook = {
|
||||
create: (_, n) => {
|
||||
this.utils.transitionCreate(n.elm, '${name}');
|
||||
},
|
||||
insert: vn => {
|
||||
this.utils.transitionInsert(vn.elm, '${name}');
|
||||
},
|
||||
remove: (vn, rm) => {
|
||||
this.utils.transitionRemove(vn.elm, '${name}', rm);
|
||||
}
|
||||
};`);
|
||||
const hooks = {
|
||||
create: `this.utils.transitionCreate(n.elm, '${name}');`,
|
||||
insert: `this.utils.transitionInsert(vn.elm, '${name}');`,
|
||||
remove: `this.utils.transitionRemove(vn.elm, '${name}', rm);`
|
||||
};
|
||||
for (let hookName in hooks) {
|
||||
addNodeHook(hookName, hooks[hookName]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -333,7 +328,7 @@ QWeb.addDirective({
|
||||
QWeb.addDirective({
|
||||
name: "mounted",
|
||||
priority: 97,
|
||||
atNodeCreation({ ctx, fullName, value, nodeID }) {
|
||||
atNodeCreation({ ctx, fullName, value, nodeID, addNodeHook }) {
|
||||
ctx.rootContext.shouldDefineOwner = true;
|
||||
const eventName = fullName.slice(5);
|
||||
if (!eventName) {
|
||||
@@ -359,8 +354,9 @@ QWeb.addDirective({
|
||||
`extra.mountedHandlers[${nodeID}] = extra.mountedHandlers[${nodeID}] || (context['${handler}'] || ${error}).bind(owner);`
|
||||
);
|
||||
}
|
||||
ctx.addLine(`p${nodeID}.hook = {
|
||||
insert: (vn) => { if (context.__owl__.isMounted) { extra.mountedHandlers[${nodeID}](); } },
|
||||
};`);
|
||||
addNodeHook(
|
||||
"insert",
|
||||
`if (context.__owl__.isMounted) { extra.mountedHandlers[${nodeID}](); }`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,16 +10,16 @@ exports[`animations t-transition, on a simple node 1`] = `
|
||||
var vn2 = h('span', p2, c2);
|
||||
c1.push(vn2);
|
||||
p2.hook = {
|
||||
create: (_, n) => {
|
||||
this.utils.transitionCreate(n.elm, 'chimay');
|
||||
},
|
||||
insert: vn => {
|
||||
this.utils.transitionInsert(vn.elm, 'chimay');
|
||||
},
|
||||
remove: (vn, rm) => {
|
||||
this.utils.transitionRemove(vn.elm, 'chimay', rm);
|
||||
}
|
||||
};
|
||||
create: (_, n) => {
|
||||
this.utils.transitionCreate(n.elm, 'chimay');
|
||||
},
|
||||
insert: vn => {
|
||||
this.utils.transitionInsert(vn.elm, 'chimay');
|
||||
},
|
||||
remove: (vn, rm) => {
|
||||
this.utils.transitionRemove(vn.elm, 'chimay', rm);
|
||||
},
|
||||
};
|
||||
c2.push({text: \`blue\`});
|
||||
return vn1;
|
||||
}"
|
||||
@@ -1356,8 +1356,10 @@ exports[`t-ref can get a dynamic ref on a node 1`] = `
|
||||
c1.push(vn2);
|
||||
const ref3 = 'myspan' + 3
|
||||
p2.hook = {
|
||||
create: (_, n) => context.refs[ref3] = n.elm,
|
||||
};
|
||||
create: (_, n) => {
|
||||
context.refs[ref3] = n.elm;
|
||||
},
|
||||
};
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1373,8 +1375,10 @@ exports[`t-ref can get a ref on a node 1`] = `
|
||||
c1.push(vn2);
|
||||
const ref3 = 'myspan'
|
||||
p2.hook = {
|
||||
create: (_, n) => context.refs[ref3] = n.elm,
|
||||
};
|
||||
create: (_, n) => {
|
||||
context.refs[ref3] = n.elm;
|
||||
},
|
||||
};
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
@@ -1403,7 +1407,9 @@ exports[`t-ref refs in a loop 1`] = `
|
||||
c1.push(vn5);
|
||||
const ref6 = context['item']
|
||||
p5.hook = {
|
||||
create: (_, n) => context.refs[ref6] = n.elm,
|
||||
create: (_, n) => {
|
||||
context.refs[ref6] = n.elm;
|
||||
},
|
||||
};
|
||||
var _7 = context['item'];
|
||||
if (_7 || _7 === 0) {
|
||||
|
||||
@@ -2064,4 +2064,32 @@ describe("t-mounted directive", () => {
|
||||
await nextTick();
|
||||
expect(widget.f).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("combined with a t-ref", async () => {
|
||||
class TestWidget extends Widget {
|
||||
inlineTemplate = `<div><input t-ref="'input'" t-mounted="f"/></div>`;
|
||||
f() {}
|
||||
}
|
||||
const widget = new TestWidget(env);
|
||||
widget.f = jest.fn();
|
||||
await widget.mount(fixture);
|
||||
expect(widget.refs.input).toBeDefined();
|
||||
expect(widget.f).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("combined with a t-transition", async () => {
|
||||
class TestWidget extends Widget {
|
||||
inlineTemplate = `<div><span t-if="state.flag" t-mounted="f" t-transition="chimay">blue</span></div>`;
|
||||
state = { flag: false };
|
||||
f() {}
|
||||
}
|
||||
const widget = new TestWidget(env);
|
||||
widget.f = jest.fn();
|
||||
await widget.mount(fixture);
|
||||
expect(widget.f).toHaveBeenCalledTimes(0);
|
||||
|
||||
widget.state.flag = true;
|
||||
await nextTick();
|
||||
expect(widget.f).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user