[FIX] qweb: allow mixing body and expression variables

closes #445
This commit is contained in:
Géry Debongnie
2019-11-14 13:38:38 +01:00
committed by aab-odoo
parent f2b3ebd1ec
commit bbdc9d90d7
5 changed files with 149 additions and 40 deletions
+18 -14
View File
@@ -1,5 +1,4 @@
import { CompilationContext } from "./compilation_context";
import { QWebExprVar } from "./expression_parser";
import { QWeb } from "./qweb";
import { htmlToVDOM } from "../vdom/html_to_vdom";
@@ -34,7 +33,7 @@ function compileValueNode(value: any, node: Element, qweb: QWeb, ctx: Compilatio
return;
}
if (value.xml instanceof NodeList) {
if (value.xml instanceof NodeList && !value.id) {
for (let node of Array.from(value.xml)) {
qweb._compileNode(<ChildNode>node, ctx);
}
@@ -71,6 +70,12 @@ function compileValueNode(value: any, node: Element, qweb: QWeb, ctx: Compilatio
qweb._compileChildren(node, ctx);
}
if (value.xml instanceof NodeList && value.id) {
ctx.addElse();
for (let node of Array.from(value.xml)) {
qweb._compileNode(<ChildNode>node, ctx);
}
}
ctx.closeIf();
}
@@ -104,22 +109,21 @@ QWeb.addDirective({
atNodeEncounter({ node, ctx }): boolean {
const variable = node.getAttribute("t-set")!;
let value = node.getAttribute("t-value")!;
ctx.variables[variable] = ctx.variables[variable] || {};
let qwebvar = ctx.variables[variable];
if (value) {
const formattedValue = ctx.formatExpression(value);
if (ctx.variables.hasOwnProperty(variable)) {
ctx.addLine(`${(<QWebExprVar>ctx.variables[variable]).id} = ${formattedValue}`);
if (ctx.variables.hasOwnProperty(variable) && qwebvar.id) {
ctx.addLine(`${qwebvar.id} = ${formattedValue}`);
} else {
const varName = `_${ctx.generateID()}`;
ctx.addLine(`var ${varName} = ${formattedValue};`);
ctx.variables[variable] = {
id: varName,
expr: formattedValue
};
qwebvar.id = varName;
qwebvar.expr = formattedValue;
}
} else {
ctx.variables[variable] = {
xml: node.childNodes
};
qwebvar.xml = node.childNodes;
}
return true;
}
@@ -133,7 +137,7 @@ QWeb.addDirective({
priority: 20,
atNodeEncounter({ node, ctx }): boolean {
let cond = ctx.getValue(node.getAttribute("t-if")!);
ctx.addIf(typeof cond === "string" ? ctx.formatExpression(cond) : cond.id);
ctx.addIf(typeof cond === "string" ? ctx.formatExpression(cond) : cond.id!);
return false;
},
finalize({ ctx }) {
@@ -244,8 +248,8 @@ QWeb.addDirective({
// add new variables, if any
for (let key in tempCtx.variables) {
const v = tempCtx.variables[key];
if ((<QWebExprVar>v).expr) {
ctx.addLine(`let ${(<QWebExprVar>v).id} = ${(<QWebExprVar>v).expr};`);
if (v.expr) {
ctx.addLine(`let ${v.id} = ${v.expr};`);
}
// todo: handle XML variables...
}
+2 -2
View File
@@ -1,4 +1,4 @@
import { compileExpr, QWebVar, QWebExprVar } from "./expression_parser";
import { compileExpr, QWebVar } from "./expression_parser";
export const INTERP_REGEXP = /\{\{.*?\}\}/g;
//------------------------------------------------------------------------------
@@ -149,7 +149,7 @@ export class CompilationContext {
this.addLine("}");
}
getValue(val: any): QWebExprVar | string {
getValue(val: any): QWebVar | string {
return val in this.variables ? this.getValue(this.variables[val]) : val;
}
+5 -10
View File
@@ -38,17 +38,12 @@ const WORD_REPLACEMENT = {
lte: "<="
};
export interface QWebExprVar {
id: string;
expr: string;
export interface QWebVar {
id?: string;
expr?: string;
xml?: NodeList;
}
export interface QWebXMLVar {
xml: NodeList;
}
export type QWebVar = QWebExprVar | QWebXMLVar;
//------------------------------------------------------------------------------
// Tokenizer
//------------------------------------------------------------------------------
@@ -252,7 +247,7 @@ export function compileExpr(expr: string, vars: { [key: string]: QWebVar }): str
}
if (isVar) {
if (token.value in vars && "id" in vars[token.value]) {
token.value = (<QWebExprVar>vars[token.value]).id;
token.value = vars[token.value].id!;
} else {
token.value = `context['${token.value}']`;
}
+98 -14
View File
@@ -699,25 +699,25 @@ exports[`misc global 1`] = `
} else {
c17.push({text: \`foo default\`});
}
var _19 = 'bbb';
let c20 = [], p20 = {key:20};
var vn20 = h('span', p20, c20);
c14.push(vn20);
if (_19 || _19 === 0) {
c20.push({text: _19});
_11 = 'bbb'
let c19 = [], p19 = {key:19};
var vn19 = h('span', p19, c19);
c14.push(vn19);
if (_11 || _11 === 0) {
c19.push({text: _11});
} else {
c20.push({text: \`foo default\`});
c19.push({text: \`foo default\`});
}
}
}
let c21 = [], p21 = {key:21};
var vn21 = h('div', p21, c21);
c1.push(vn21);
var _22 = context['toto'];
if (_22 || _22 === 0) {
c21.push(...utils.htmlToVDOM(_22));
let c20 = [], p20 = {key:20};
var vn20 = h('div', p20, c20);
c1.push(vn20);
var _21 = context['toto'];
if (_21 || _21 === 0) {
c20.push(...utils.htmlToVDOM(_21));
} else {
c21.push({text: \`toto default\`});
c20.push({text: \`toto default\`});
}
return vn1;
}"
@@ -2400,6 +2400,90 @@ exports[`t-set t-set should reuse variable if possible 1`] = `
}"
`;
exports[`t-set t-set, t-if, and mix of expression/body lookup, 1 1`] = `
"function anonymous(context,extra
) {
let sibling = null;
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
if (context['flag']) {
}
else {
var _2 = 0;
}
if (_2 || _2 === 0) {
c1.push({text: _2});
} else {
c1.push({text: \`1\`});
}
return vn1;
}"
`;
exports[`t-set t-set, t-if, and mix of expression/body lookup, 1 2`] = `
"function anonymous(context,extra
) {
let sibling = null;
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
if (context['flag']) {
}
else {
var _2 = 0;
}
if (_2 || _2 === 0) {
c1.push({text: _2});
} else {
c1.push({text: \`1\`});
}
return vn1;
}"
`;
exports[`t-set t-set, t-if, and mix of expression/body lookup, 2 1`] = `
"function anonymous(context,extra
) {
let sibling = null;
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
if (context['flag']) {
var _2 = 1;
}
else {
}
if (_2 || _2 === 0) {
c1.push({text: _2});
} else {
c1.push({text: \`0\`});
}
return vn1;
}"
`;
exports[`t-set t-set, t-if, and mix of expression/body lookup, 2 2`] = `
"function anonymous(context,extra
) {
let sibling = null;
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
if (context['flag']) {
var _2 = 1;
}
else {
}
if (_2 || _2 === 0) {
c1.push({text: _2});
} else {
c1.push({text: \`0\`});
}
return vn1;
}"
`;
exports[`t-set value priority 1`] = `
"function anonymous(context,extra
) {
+26
View File
@@ -242,6 +242,32 @@ describe("t-set", () => {
);
expect(renderToString(qweb, "test", { somevariable: 43 })).toBe("<div>45</div>");
});
test("t-set, t-if, and mix of expression/body lookup, 1", () => {
qweb.addTemplate(
"test",
`<div>
<t t-if="flag" t-set="ourvar">1</t>
<t t-else="" t-set="ourvar" t-value="0"></t>
<t t-esc="ourvar"/>
</div>`
);
expect(renderToString(qweb, "test", { flag: true })).toBe("<div>1</div>");
expect(renderToString(qweb, "test", { flag: false })).toBe("<div>0</div>");
});
test("t-set, t-if, and mix of expression/body lookup, 2", () => {
qweb.addTemplate(
"test",
`<div>
<t t-if="flag" t-set="ourvar" t-value="1"></t>
<t t-else="" t-set="ourvar">0</t>
<t t-esc="ourvar"/>
</div>`
);
expect(renderToString(qweb, "test", { flag: true })).toBe("<div>1</div>");
expect(renderToString(qweb, "test", { flag: false })).toBe("<div>0</div>");
});
});
describe("t-if", () => {