mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] qweb: cascading t-call and t-raw="0"
Have a t-call having a t-raw="0" that call is made to a template of the same form i.e. itself as a t-call t-raw="0" structure Before this commit, there was recursion crash This was because the caller to which a t-raw="0" referred to was incorrect. The caller here is the node which makes the t-call. In particular, the caller was always set to last caller of the context After this commit, there is no crash and this imbrication of t-call and t-raw="0" is well rendered. To sum up, we count the recursive calls to t-raw="0" and fetch the caller in the context accordingly closes #510
This commit is contained in:
committed by
Géry Debongnie
parent
6e5d6aa226
commit
7f6782d009
@@ -28,10 +28,13 @@ QWeb.utils.getFragment = function(str: string): DocumentFragment {
|
||||
QWeb.utils.htmlToVDOM = htmlToVDOM;
|
||||
|
||||
function compileValueNode(value: any, node: Element, qweb: QWeb, ctx: CompilationContext) {
|
||||
if (value === "0" && ctx.caller) {
|
||||
qweb._compileNode(ctx.caller, ctx);
|
||||
if (value === "0") {
|
||||
const caller = ctx.getCaller();
|
||||
if (caller) {
|
||||
qweb._compileNode(caller, ctx.getInliningContext());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (value.xml instanceof NodeList && !value.id) {
|
||||
for (let node of Array.from(value.xml)) {
|
||||
|
||||
@@ -32,6 +32,8 @@ export class CompilationContext {
|
||||
scopeVars: any[] = [];
|
||||
currentKey: string = "";
|
||||
templates: { [key: string]: boolean } = {};
|
||||
callingLevel: number = 0;
|
||||
inliningLevel: number = 0;
|
||||
|
||||
constructor(name?: string) {
|
||||
this.rootContext = this;
|
||||
@@ -129,6 +131,10 @@ export class CompilationContext {
|
||||
subContext(key: keyof CompilationContext, value: any): CompilationContext {
|
||||
const newContext = Object.create(this);
|
||||
newContext[key] = value;
|
||||
if (key === 'caller') {
|
||||
newContext.callingLevel++;
|
||||
newContext.inliningLevel++;
|
||||
}
|
||||
return newContext;
|
||||
}
|
||||
|
||||
@@ -166,6 +172,27 @@ export class CompilationContext {
|
||||
this.dedent();
|
||||
this.addLine("}");
|
||||
}
|
||||
/**
|
||||
* Recursively (inverse) fetches the `caller` of a context
|
||||
* Useful to determine to which t-call a t-raw="0" refers
|
||||
*/
|
||||
getCaller(targetLevel?: number): Element | null {
|
||||
if (targetLevel === undefined) {
|
||||
targetLevel = this.inliningLevel;
|
||||
}
|
||||
if (targetLevel === this.callingLevel) {
|
||||
return this.caller || null;
|
||||
}
|
||||
const proto = (this as any).__proto__;
|
||||
return proto ? proto.getCaller(targetLevel) : null;
|
||||
}
|
||||
/**
|
||||
* Marks the context with the current recursive level
|
||||
* in which we are for inlining archs (t-raw="0")
|
||||
*/
|
||||
getInliningContext(): CompilationContext {
|
||||
return this.subContext('inliningLevel', this.inliningLevel - 1);
|
||||
}
|
||||
|
||||
getValue(val: any): QWebVar | string {
|
||||
return val in this.variables ? this.getValue(this.variables[val]) : val;
|
||||
|
||||
@@ -910,6 +910,46 @@ exports[`t-call (template calling call with several sub nodes on same line 1`] =
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-call (template calling cascading t-call t-raw='0' 1`] = `
|
||||
"function anonymous(context,extra
|
||||
) {
|
||||
var h = this.h;
|
||||
let c1 = [], p1 = {key:1};
|
||||
var vn1 = h('div', p1, c1);
|
||||
let c5 = [], p5 = {key:5};
|
||||
var vn5 = h('div', p5, c5);
|
||||
c1.push(vn5);
|
||||
let c8 = [], p8 = {key:8};
|
||||
var vn8 = h('div', p8, c8);
|
||||
c5.push(vn8);
|
||||
let c11 = [], p11 = {key:11};
|
||||
var vn11 = h('div', p11, c11);
|
||||
c8.push(vn11);
|
||||
let c12 = [], p12 = {key:12};
|
||||
var vn12 = h('span', p12, c12);
|
||||
c11.push(vn12);
|
||||
c12.push({text: \`cascade 2\`});
|
||||
let c13 = [], p13 = {key:13};
|
||||
var vn13 = h('span', p13, c13);
|
||||
c11.push(vn13);
|
||||
c13.push({text: \`cascade 1\`});
|
||||
let c14 = [], p14 = {key:14};
|
||||
var vn14 = h('span', p14, c14);
|
||||
c11.push(vn14);
|
||||
c14.push({text: \`cascade 0\`});
|
||||
let c15 = [], p15 = {key:15};
|
||||
var vn15 = h('span', p15, c15);
|
||||
c11.push(vn15);
|
||||
c15.push({text: \`hey\`});
|
||||
c11.push({text: \` \`});
|
||||
let c16 = [], p16 = {key:16};
|
||||
var vn16 = h('span', p16, c16);
|
||||
c11.push(vn16);
|
||||
c16.push({text: \`yay\`});
|
||||
return vn1;
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`t-call (template calling inherit context 1`] = `
|
||||
"function anonymous(context,extra
|
||||
) {
|
||||
|
||||
@@ -673,6 +673,39 @@ describe("t-call (template calling", () => {
|
||||
expect(renderToString(qweb, "main")).toBe(expected);
|
||||
});
|
||||
|
||||
test("cascading t-call t-raw='0'", () => {
|
||||
qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="finalTemplate">
|
||||
<span>cascade 2</span>
|
||||
<t t-raw="0"/>
|
||||
</div>
|
||||
|
||||
<div t-name="subSubTemplate">
|
||||
<t t-call="finalTemplate">
|
||||
<span>cascade 1</span>
|
||||
<t t-raw="0"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<div t-name="SubTemplate">
|
||||
<t t-call="subSubTemplate">
|
||||
<span>cascade 0</span>
|
||||
<t t-raw="0"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<div t-name="main">
|
||||
<t t-call="SubTemplate">
|
||||
<span>hey</span> <span>yay</span>
|
||||
</t>
|
||||
</div>
|
||||
</templates>
|
||||
`);
|
||||
const expected = "<div><div><div><div><span>cascade 2</span><span>cascade 1</span><span>cascade 0</span><span>hey</span> <span>yay</span></div></div></div></div>";
|
||||
expect(renderToString(qweb, "main")).toBe(expected);
|
||||
});
|
||||
|
||||
test("recursive template, part 1", () => {
|
||||
qweb.addTemplates(`
|
||||
<templates>
|
||||
|
||||
Reference in New Issue
Block a user