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 {
|
interface CompilationInfo {
|
||||||
nodeID?: number;
|
|
||||||
node: Element;
|
node: Element;
|
||||||
qweb: QWeb;
|
qweb: QWeb;
|
||||||
ctx: Context;
|
ctx: Context;
|
||||||
@@ -39,6 +38,11 @@ interface CompilationInfo {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface NodeCreationCompilationInfo extends CompilationInfo {
|
||||||
|
nodeID: number;
|
||||||
|
addNodeHook: Function;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Directive {
|
export interface Directive {
|
||||||
name: string;
|
name: string;
|
||||||
extraNames?: string[];
|
extraNames?: string[];
|
||||||
@@ -46,7 +50,7 @@ export interface Directive {
|
|||||||
// if return true, then directive is fully applied and there is no need to
|
// if return true, then directive is fully applied and there is no need to
|
||||||
// keep processing node. Otherwise, we keep going.
|
// keep processing node. Otherwise, we keep going.
|
||||||
atNodeEncounter?(info: CompilationInfo): boolean | void;
|
atNodeEncounter?(info: CompilationInfo): boolean | void;
|
||||||
atNodeCreation?(info: CompilationInfo): void;
|
atNodeCreation?(info: NodeCreationCompilationInfo): void;
|
||||||
finalize?(info: CompilationInfo): void;
|
finalize?(info: CompilationInfo): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +91,12 @@ const DIRECTIVE_NAMES = {
|
|||||||
|
|
||||||
const DIRECTIVES: Directive[] = [];
|
const DIRECTIVES: Directive[] = [];
|
||||||
|
|
||||||
|
const NODE_HOOKS_PARAMS = {
|
||||||
|
create: "(_, n)",
|
||||||
|
insert: "vn",
|
||||||
|
remove: "(vn, rm)"
|
||||||
|
};
|
||||||
|
|
||||||
export const UTILS = {
|
export const UTILS = {
|
||||||
h: h,
|
h: h,
|
||||||
objectToAttrString(obj: Object): string {
|
objectToAttrString(obj: Object): string {
|
||||||
@@ -497,6 +507,11 @@ export class QWeb {
|
|||||||
if (node.nodeName !== "t") {
|
if (node.nodeName !== "t") {
|
||||||
let nodeID = this._compileGenericNode(node, ctx, withHandlers);
|
let nodeID = this._compileGenericNode(node, ctx, withHandlers);
|
||||||
ctx = ctx.withParent(nodeID);
|
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) {
|
for (let { directive, value, fullName } of validDirectives) {
|
||||||
if (directive.atNodeCreation) {
|
if (directive.atNodeCreation) {
|
||||||
@@ -506,10 +521,23 @@ export class QWeb {
|
|||||||
ctx,
|
ctx,
|
||||||
fullName,
|
fullName,
|
||||||
value,
|
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") {
|
if (node.nodeName === "pre") {
|
||||||
ctx = ctx.subContext("inPreTag", true);
|
ctx = ctx.subContext("inPreTag", true);
|
||||||
|
|||||||
+16
-20
@@ -57,12 +57,10 @@ QWeb.addDirective({
|
|||||||
QWeb.addDirective({
|
QWeb.addDirective({
|
||||||
name: "ref",
|
name: "ref",
|
||||||
priority: 95,
|
priority: 95,
|
||||||
atNodeCreation({ ctx, nodeID, value }) {
|
atNodeCreation({ ctx, nodeID, value, addNodeHook }) {
|
||||||
const refKey = `ref${ctx.generateID()}`;
|
const refKey = `ref${ctx.generateID()}`;
|
||||||
ctx.addLine(`const ${refKey} = ${ctx.formatExpression(value)}`);
|
ctx.addLine(`const ${refKey} = ${ctx.formatExpression(value)}`);
|
||||||
ctx.addLine(`p${nodeID}.hook = {
|
addNodeHook("create", `context.refs[${refKey}] = n.elm;`);
|
||||||
create: (_, n) => context.refs[${refKey}] = n.elm,
|
|
||||||
};`);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -148,19 +146,16 @@ function whenTransitionEnd(elm: HTMLElement, cb) {
|
|||||||
QWeb.addDirective({
|
QWeb.addDirective({
|
||||||
name: "transition",
|
name: "transition",
|
||||||
priority: 96,
|
priority: 96,
|
||||||
atNodeCreation({ ctx, value, nodeID }) {
|
atNodeCreation({ ctx, value, addNodeHook }) {
|
||||||
let name = value;
|
let name = value;
|
||||||
ctx.addLine(`p${nodeID}.hook = {
|
const hooks = {
|
||||||
create: (_, n) => {
|
create: `this.utils.transitionCreate(n.elm, '${name}');`,
|
||||||
this.utils.transitionCreate(n.elm, '${name}');
|
insert: `this.utils.transitionInsert(vn.elm, '${name}');`,
|
||||||
},
|
remove: `this.utils.transitionRemove(vn.elm, '${name}', rm);`
|
||||||
insert: vn => {
|
};
|
||||||
this.utils.transitionInsert(vn.elm, '${name}');
|
for (let hookName in hooks) {
|
||||||
},
|
addNodeHook(hookName, hooks[hookName]);
|
||||||
remove: (vn, rm) => {
|
}
|
||||||
this.utils.transitionRemove(vn.elm, '${name}', rm);
|
|
||||||
}
|
|
||||||
};`);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -333,7 +328,7 @@ QWeb.addDirective({
|
|||||||
QWeb.addDirective({
|
QWeb.addDirective({
|
||||||
name: "mounted",
|
name: "mounted",
|
||||||
priority: 97,
|
priority: 97,
|
||||||
atNodeCreation({ ctx, fullName, value, nodeID }) {
|
atNodeCreation({ ctx, fullName, value, nodeID, addNodeHook }) {
|
||||||
ctx.rootContext.shouldDefineOwner = true;
|
ctx.rootContext.shouldDefineOwner = true;
|
||||||
const eventName = fullName.slice(5);
|
const eventName = fullName.slice(5);
|
||||||
if (!eventName) {
|
if (!eventName) {
|
||||||
@@ -359,8 +354,9 @@ QWeb.addDirective({
|
|||||||
`extra.mountedHandlers[${nodeID}] = extra.mountedHandlers[${nodeID}] || (context['${handler}'] || ${error}).bind(owner);`
|
`extra.mountedHandlers[${nodeID}] = extra.mountedHandlers[${nodeID}] || (context['${handler}'] || ${error}).bind(owner);`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ctx.addLine(`p${nodeID}.hook = {
|
addNodeHook(
|
||||||
insert: (vn) => { if (context.__owl__.isMounted) { extra.mountedHandlers[${nodeID}](); } },
|
"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);
|
var vn2 = h('span', p2, c2);
|
||||||
c1.push(vn2);
|
c1.push(vn2);
|
||||||
p2.hook = {
|
p2.hook = {
|
||||||
create: (_, n) => {
|
create: (_, n) => {
|
||||||
this.utils.transitionCreate(n.elm, 'chimay');
|
this.utils.transitionCreate(n.elm, 'chimay');
|
||||||
},
|
},
|
||||||
insert: vn => {
|
insert: vn => {
|
||||||
this.utils.transitionInsert(vn.elm, 'chimay');
|
this.utils.transitionInsert(vn.elm, 'chimay');
|
||||||
},
|
},
|
||||||
remove: (vn, rm) => {
|
remove: (vn, rm) => {
|
||||||
this.utils.transitionRemove(vn.elm, 'chimay', rm);
|
this.utils.transitionRemove(vn.elm, 'chimay', rm);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
c2.push({text: \`blue\`});
|
c2.push({text: \`blue\`});
|
||||||
return vn1;
|
return vn1;
|
||||||
}"
|
}"
|
||||||
@@ -1356,8 +1356,10 @@ exports[`t-ref can get a dynamic ref on a node 1`] = `
|
|||||||
c1.push(vn2);
|
c1.push(vn2);
|
||||||
const ref3 = 'myspan' + 3
|
const ref3 = 'myspan' + 3
|
||||||
p2.hook = {
|
p2.hook = {
|
||||||
create: (_, n) => context.refs[ref3] = n.elm,
|
create: (_, n) => {
|
||||||
};
|
context.refs[ref3] = n.elm;
|
||||||
|
},
|
||||||
|
};
|
||||||
return vn1;
|
return vn1;
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@@ -1373,8 +1375,10 @@ exports[`t-ref can get a ref on a node 1`] = `
|
|||||||
c1.push(vn2);
|
c1.push(vn2);
|
||||||
const ref3 = 'myspan'
|
const ref3 = 'myspan'
|
||||||
p2.hook = {
|
p2.hook = {
|
||||||
create: (_, n) => context.refs[ref3] = n.elm,
|
create: (_, n) => {
|
||||||
};
|
context.refs[ref3] = n.elm;
|
||||||
|
},
|
||||||
|
};
|
||||||
return vn1;
|
return vn1;
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@@ -1403,7 +1407,9 @@ exports[`t-ref refs in a loop 1`] = `
|
|||||||
c1.push(vn5);
|
c1.push(vn5);
|
||||||
const ref6 = context['item']
|
const ref6 = context['item']
|
||||||
p5.hook = {
|
p5.hook = {
|
||||||
create: (_, n) => context.refs[ref6] = n.elm,
|
create: (_, n) => {
|
||||||
|
context.refs[ref6] = n.elm;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
var _7 = context['item'];
|
var _7 = context['item'];
|
||||||
if (_7 || _7 === 0) {
|
if (_7 || _7 === 0) {
|
||||||
|
|||||||
@@ -2064,4 +2064,32 @@ describe("t-mounted directive", () => {
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
expect(widget.f).toHaveBeenCalledTimes(1);
|
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