[FIX] qweb: evaluate body of t-set immediately

This commit is contained in:
Lucas Perais (lpe)
2019-12-10 16:39:30 +01:00
committed by Géry Debongnie
parent ce9c2f8613
commit 9145799ae9
7 changed files with 453 additions and 171 deletions
+60 -32
View File
@@ -28,17 +28,14 @@ function compileValueNode(value: any, node: Element, qweb: QWeb, ctx: Compilatio
// the 'zero' magical symbol is where we can find the result of the rendering
// of the body of the t-call.
ctx.rootContext.shouldDefineUtils = true;
ctx.addLine(`c${ctx.parentNode}.push(...scope[utils.zero]);`);
const zeroArgs = ctx.escaping
? `{text: utils.vDomToString(scope[utils.zero])}`
: `...scope[utils.zero]`;
ctx.addLine(`c${ctx.parentNode}.push(${zeroArgs});`);
}
return;
}
if (value.xml instanceof NodeList && !value.id) {
for (let node of Array.from(value.xml)) {
qweb._compileNode(<ChildNode>node, ctx);
}
return;
}
let exprID: string;
if (typeof value === "string") {
exprID = `_${ctx.generateID()}`;
@@ -47,7 +44,15 @@ function compileValueNode(value: any, node: Element, qweb: QWeb, ctx: Compilatio
exprID = `scope.${value.id}`;
}
ctx.addIf(`${exprID} || ${exprID} === 0`);
if (ctx.escaping) {
let protectID;
if (value.hasBody) {
protectID = ctx.startProtectScope();
ctx.addLine(
`${exprID} = ${exprID} instanceof utils.VDomArray ? utils.vDomToString(${exprID}) : ${exprID};`
);
}
if (ctx.parentTextNode) {
ctx.addLine(`vn${ctx.parentTextNode}.text += ${exprID};`);
} else if (ctx.parentNode) {
@@ -61,21 +66,25 @@ function compileValueNode(value: any, node: Element, qweb: QWeb, ctx: Compilatio
ctx.addLine(`result = vn${nodeID}`);
}
}
if (value.hasBody) {
ctx.stopProtectScope(protectID);
}
} else {
ctx.rootContext.shouldDefineUtils = true;
ctx.addLine(`c${ctx.parentNode}.push(...utils.htmlToVDOM(${exprID}));`);
if (value.hasBody) {
ctx.addLine(
`const vnodeArray = ${exprID} instanceof utils.VDomArray ? ${exprID} : utils.htmlToVDOM(${exprID});`
);
ctx.addLine(`c${ctx.parentNode}.push(...vnodeArray);`);
} else {
ctx.addLine(`c${ctx.parentNode}.push(...utils.htmlToVDOM(${exprID}));`);
}
}
if (node.childNodes.length) {
ctx.addElse();
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();
}
@@ -106,25 +115,46 @@ QWeb.addDirective({
name: "set",
extraNames: ["value"],
priority: 60,
atNodeEncounter({ node, ctx }): boolean {
atNodeEncounter({ node, qweb, ctx }): boolean {
ctx.rootContext.shouldDefineScope = true;
const variable = node.getAttribute("t-set")!;
let value = node.getAttribute("t-value")!;
ctx.variables[variable] = ctx.variables[variable] || {};
let qwebvar = ctx.variables[variable];
const hasBody = node.hasChildNodes();
qwebvar.id = variable;
qwebvar.expr = `scope.${variable}`;
if (value) {
const formattedValue = ctx.formatExpression(value);
if (ctx.variables.hasOwnProperty(variable) && qwebvar.id) {
ctx.addLine(`${qwebvar.expr} = ${formattedValue}`);
} else {
ctx.addLine(`scope.${variable} = ${formattedValue};`);
qwebvar.id = variable;
qwebvar.expr = `scope.${variable}`;
qwebvar.value = formattedValue;
ctx.addLine(`${qwebvar.expr} = ${formattedValue};`);
qwebvar.value = formattedValue;
}
if (hasBody) {
ctx.rootContext.shouldDefineUtils = true;
if (value) {
ctx.addIf(`!(${qwebvar.expr})`);
}
const tempParentNodeID = ctx.generateID();
const _parentNode = ctx.parentNode;
ctx.parentNode = tempParentNodeID;
ctx.addLine(`const c${tempParentNodeID} = new utils.VDomArray();`);
const nodeCopy = node.cloneNode(true) as Element;
for (let attr of ["t-set", "t-value", "t-if", "t-else", "t-elif"]) {
nodeCopy.removeAttribute(attr);
}
qweb._compileNode(nodeCopy, ctx);
ctx.addLine(`${qwebvar.expr} = c${tempParentNodeID}`);
qwebvar.value = `c${tempParentNodeID}`;
qwebvar.hasBody = true;
ctx.parentNode = _parentNode;
if (value) {
ctx.closeIf();
}
} else {
qwebvar.xml = node.childNodes;
}
return true;
}
@@ -205,12 +235,12 @@ QWeb.addDirective({
// Step 3: compile t-call body if necessary
// ------------------------------------------------
let hasBody = node.hasChildNodes();
let protectID;
if (hasBody) {
// we add a sub scope to protect the ambient scope
ctx.addLine(`{`);
ctx.indent();
ctx.addLine(`let origScope = scope;`);
ctx.addLine(`scope = Object.assign(Object.create(context), scope);`);
protectID = ctx.startProtectScope();
const nodeCopy = node.cloneNode(true) as Element;
nodeCopy.removeAttribute("t-call");
const parentNode = ctx.parentNode;
@@ -229,7 +259,7 @@ QWeb.addDirective({
// Step 4: add the appropriate function call to current component
// ------------------------------------------------
const callingScope = hasBody ? 'scope' : 'Object.assign(Object.create(context), scope)';
const callingScope = hasBody ? "scope" : "Object.assign(Object.create(context), scope)";
if (ctx.parentNode) {
ctx.addLine(
`this.subTemplates['${subTemplate}'].call(this, ${callingScope}, Object.assign({}, extra, {parentNode: c${ctx.parentNode}}));`
@@ -247,7 +277,7 @@ QWeb.addDirective({
// Step 5: restore previous scope
// ------------------------------------------------
if (hasBody) {
ctx.addLine(`scope = origScope;`);
ctx.stopProtectScope(protectID);
ctx.dedent();
ctx.addLine(`}`);
}
@@ -279,9 +309,7 @@ QWeb.addDirective({
ctx.addLine(`_${valuesID} = Object.values(_${arrayID});`);
ctx.closeIf();
ctx.addLine(`var _length${keysID} = _${keysID}.length;`);
let varsID = ctx.generateID();
ctx.addLine(`let _scope${varsID} = scope;`);
ctx.addLine(`scope = Object.assign(Object.create(context), _scope${varsID});`);
let varsID = ctx.startProtectScope();
const loopVar = `i${ctx.loopNumber}`;
ctx.addLine(`for (let ${loopVar} = 0; ${loopVar} < _length${keysID}; ${loopVar}++) {`);
ctx.indent();
@@ -307,7 +335,7 @@ QWeb.addDirective({
qweb._compileNode(nodeCopy, ctx);
ctx.dedent();
ctx.addLine("}");
ctx.addLine(`scope = _scope${varsID};`);
ctx.stopProtectScope(varsID);
return true;
}
});
+10
View File
@@ -174,4 +174,14 @@ export class CompilationContext {
let r = s.replace(/\{\{.*?\}\}/g, s => "${" + this.formatExpression(s.slice(2, -2)) + "}");
return "`" + r + "`";
}
startProtectScope(): number {
const protectID = this.generateID();
this.rootContext.shouldDefineScope = true;
this.addLine(`const _origScope${protectID} = scope;`);
this.addLine(`scope = Object.assign(Object.create(context), scope);`);
return protectID;
}
stopProtectScope(protectID: number) {
this.addLine(`scope = _origScope${protectID};`);
}
}
+1
View File
@@ -42,6 +42,7 @@ export interface QWebVar {
id: string; // foo
expr: string; // scope.foo (local variables => only foo)
value?: string; // 1 + 3
hasBody?: boolean;
}
//------------------------------------------------------------------------------
+16 -2
View File
@@ -87,7 +87,7 @@ interface Utils {
}
const UTILS: Utils = {
zero: Symbol('zero'),
zero: Symbol("zero"),
toObj(expr) {
if (typeof expr === "string") {
expr = expr.trim();
@@ -106,6 +106,20 @@ const UTILS: Utils = {
shallowEqual,
addNameSpace(vnode) {
addNS(vnode.data, vnode.children, vnode.sel);
},
VDomArray: class VDomArray extends Array {},
vDomToString: function(vdom: VNode[]): string {
return vdom
.map(vnode => {
if (vnode.sel) {
const node = document.createElement(vnode.sel);
const result = patch(node, vnode);
return (<HTMLElement>result.elm).outerHTML;
} else {
return vnode.text;
}
})
.join();
}
};
@@ -383,7 +397,7 @@ export class QWeb extends EventBus {
let code = ctx.generateCode();
const templateName = ctx.templateName.replace(/`/g, "'").slice(0, 200);
code.unshift(` // Template name: "${templateName}"`)
code.unshift(` // Template name: "${templateName}"`);
let template;
try {
@@ -19,8 +19,8 @@ exports[`basic widget properties reconciliation alg works for t-foreach in t-for
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.section_first = i1 === 0
scope.section_last = i1 === _length3 - 1
@@ -35,8 +35,8 @@ exports[`basic widget properties reconciliation alg works for t-foreach in t-for
_8 = Object.values(_6);
}
var _length7 = _7.length;
let _scope9 = scope;
scope = Object.assign(Object.create(context), _scope9);
const _origScope9 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i2 = 0; i2 < _length7; i2++) {
scope.blip_first = i2 === 0
scope.blip_last = i2 === _length7 - 1
@@ -68,9 +68,9 @@ exports[`basic widget properties reconciliation alg works for t-foreach in t-for
}
w10.__owl__.parentLastFiberId = extra.fiber.id;
}
scope = _scope9;
scope = _origScope9;
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -318,8 +318,8 @@ exports[`composition sub components with some state rendered in a loop 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.number_first = i1 === 0
scope.number_last = i1 === _length3 - 1
@@ -352,7 +352,7 @@ exports[`composition sub components with some state rendered in a loop 1`] = `
}
w7.__owl__.parentLastFiberId = extra.fiber.id;
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -983,8 +983,8 @@ exports[`random stuff/miscellaneous t-on with handler bound to dynamic argument
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.item_first = i1 === 0
scope.item_last = i1 === _length3 - 1
@@ -1018,7 +1018,7 @@ exports[`random stuff/miscellaneous t-on with handler bound to dynamic argument
}
w7.__owl__.parentLastFiberId = extra.fiber.id;
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -1120,8 +1120,8 @@ exports[`t-model directive in a t-foreach 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.thing_first = i1 === 0
scope.thing_last = i1 === _length3 - 1
@@ -1139,7 +1139,7 @@ exports[`t-model directive in a t-foreach 1`] = `
extra.handlers[k9] = extra.handlers[k9] || ((ev) => {expr8.f = ev.target.checked});
p8.on['input'] = extra.handlers[k9];
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -1518,8 +1518,8 @@ exports[`t-slot directive slots are rendered with proper context, part 2 2`] = `
_5 = Object.values(_3);
}
var _length4 = _4.length;
let _scope6 = scope;
scope = Object.assign(Object.create(context), _scope6);
const _origScope6 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length4; i1++) {
scope.user_first = i1 === 0
scope.user_last = i1 === _length4 - 1
@@ -1556,7 +1556,7 @@ exports[`t-slot directive slots are rendered with proper context, part 2 2`] = `
}
w9.__owl__.parentLastFiberId = extra.fiber.id;
}
scope = _scope6;
scope = _origScope6;
return vn1;
}"
`;
@@ -1615,8 +1615,8 @@ exports[`t-slot directive slots are rendered with proper context, part 3 2`] = `
_5 = Object.values(_3);
}
var _length4 = _4.length;
let _scope6 = scope;
scope = Object.assign(Object.create(context), _scope6);
const _origScope6 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length4; i1++) {
scope.user_first = i1 === 0
scope.user_last = i1 === _length4 - 1
@@ -1654,7 +1654,7 @@ exports[`t-slot directive slots are rendered with proper context, part 3 2`] = `
}
w9.__owl__.parentLastFiberId = extra.fiber.id;
}
scope = _scope6;
scope = _origScope6;
return vn1;
}"
`;
+296 -114
View File
@@ -397,8 +397,8 @@ exports[`foreach does not pollute the rendering context 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.item_first = i1 === 0
scope.item_last = i1 === _length3 - 1
@@ -410,7 +410,7 @@ exports[`foreach does not pollute the rendering context 1`] = `
c1.push({text: _6});
}
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -431,8 +431,8 @@ exports[`foreach iterate on items (on a element node) 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.item_first = i1 === 0
scope.item_last = i1 === _length3 - 1
@@ -448,7 +448,7 @@ exports[`foreach iterate on items (on a element node) 1`] = `
c7.push({text: _8});
}
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -469,8 +469,8 @@ exports[`foreach iterate on items 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.item_first = i1 === 0
scope.item_last = i1 === _length3 - 1
@@ -494,7 +494,7 @@ exports[`foreach iterate on items 1`] = `
}
c1.push({text: \`] \`});
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -515,8 +515,8 @@ exports[`foreach iterate, dict param 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.item_first = i1 === 0
scope.item_last = i1 === _length3 - 1
@@ -540,7 +540,7 @@ exports[`foreach iterate, dict param 1`] = `
}
c1.push({text: \`] \`});
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -561,8 +561,8 @@ exports[`foreach iterate, position 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.elem_first = i1 === 0
scope.elem_last = i1 === _length3 - 1
@@ -583,7 +583,7 @@ exports[`foreach iterate, position 1`] = `
}
c1.push({text: \`) \`});
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -604,8 +604,8 @@ exports[`foreach t-foreach in t-forach 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.number_first = i1 === 0
scope.number_last = i1 === _length3 - 1
@@ -620,8 +620,8 @@ exports[`foreach t-foreach in t-forach 1`] = `
_8 = Object.values(_6);
}
var _length7 = _7.length;
let _scope9 = scope;
scope = Object.assign(Object.create(context), _scope9);
const _origScope9 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i2 = 0; i2 < _length7; i2++) {
scope.letter_first = i2 === 0
scope.letter_last = i2 === _length7 - 1
@@ -639,9 +639,9 @@ exports[`foreach t-foreach in t-forach 1`] = `
}
c1.push({text: \`] \`});
}
scope = _scope9;
scope = _origScope9;
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -662,8 +662,8 @@ exports[`foreach warn if no key in some case 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.item_first = i1 === 0
scope.item_last = i1 === _length3 - 1
@@ -678,7 +678,7 @@ exports[`foreach warn if no key in some case 1`] = `
c6.push({text: _7});
}
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -725,8 +725,8 @@ exports[`misc global 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.value_first = i1 === 0
scope.value_last = i1 === _length3 - 1
@@ -741,12 +741,12 @@ exports[`misc global 1`] = `
c6.push({text: _7});
}
{
let origScope = scope;
const _origScope10 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
{
let origScope = scope;
const _origScope13 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
@@ -754,18 +754,18 @@ exports[`misc global 1`] = `
scope[utils.zero] = c__0;
}
this.subTemplates['_callee-uses-foo'].call(this, scope, Object.assign({}, extra, {parentNode: c__0}));
scope = origScope;
scope = _origScope13;
}
this.subTemplates['_callee-uses-foo'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c__0}));
scope.foo = 'bbb'
scope.foo = 'bbb';
this.subTemplates['_callee-uses-foo'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c__0}));
scope[utils.zero] = c__0;
}
this.subTemplates['_callee-asc'].call(this, scope, Object.assign({}, extra, {parentNode: c1}));
scope = origScope;
scope = _origScope10;
}
}
scope = _scope5;
scope = _origScope5;
this.subTemplates['_callee-asc-toto'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1}));
return vn1;
}"
@@ -1059,23 +1059,23 @@ exports[`t-call (template calling call with several sub nodes on same line 1`] =
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
{
let origScope = scope;
const _origScope3 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
let c3 = [], p3 = {key:3};
var vn3 = h('span', p3, c3);
c__0.push(vn3);
c3.push({text: \`hey\`});
c__0.push({text: \` \`});
let c4 = [], p4 = {key:4};
var vn4 = h('span', p4, c4);
c__0.push(vn4);
c4.push({text: \`yay\`});
c4.push({text: \`hey\`});
c__0.push({text: \` \`});
let c5 = [], p5 = {key:5};
var vn5 = h('span', p5, c5);
c__0.push(vn5);
c5.push({text: \`yay\`});
scope[utils.zero] = c__0;
}
this.subTemplates['SubTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c1}));
scope = origScope;
scope = _origScope3;
}
return vn1;
}"
@@ -1106,23 +1106,23 @@ exports[`t-call (template calling cascading t-call t-raw='0' 1`] = `
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
{
let origScope = scope;
const _origScope10 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
let c8 = [], p8 = {key:8};
var vn8 = h('span', p8, c8);
c__0.push(vn8);
c8.push({text: \`hey\`});
let c11 = [], p11 = {key:11};
var vn11 = h('span', p11, c11);
c__0.push(vn11);
c11.push({text: \`hey\`});
c__0.push({text: \` \`});
let c9 = [], p9 = {key:9};
var vn9 = h('span', p9, c9);
c__0.push(vn9);
c9.push({text: \`yay\`});
let c12 = [], p12 = {key:12};
var vn12 = h('span', p12, c12);
c__0.push(vn12);
c12.push({text: \`yay\`});
scope[utils.zero] = c__0;
}
this.subTemplates['SubTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c1}));
scope = origScope;
scope = _origScope10;
}
return vn1;
}"
@@ -1191,7 +1191,7 @@ exports[`t-call (template calling recursive template, part 2 1`] = `
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
{
let origScope = scope;
const _origScope10 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
@@ -1199,7 +1199,7 @@ exports[`t-call (template calling recursive template, part 2 1`] = `
scope[utils.zero] = c__0;
}
this.subTemplates['nodeTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c1}));
scope = origScope;
scope = _origScope10;
}
return vn1;
}"
@@ -1231,8 +1231,8 @@ exports[`t-call (template calling recursive template, part 2 2`] = `
_7 = Object.values(_5);
}
var _length6 = _6.length;
let _scope8 = scope;
scope = Object.assign(Object.create(context), _scope8);
const _origScope8 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length6; i1++) {
scope.subtree_first = i1 === 0
scope.subtree_last = i1 === _length6 - 1
@@ -1240,7 +1240,7 @@ exports[`t-call (template calling recursive template, part 2 2`] = `
scope.subtree = _6[i1]
scope.subtree_value = _7[i1]
{
let origScope = scope;
const _origScope9 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
@@ -1248,10 +1248,10 @@ exports[`t-call (template calling recursive template, part 2 2`] = `
scope[utils.zero] = c__0;
}
this.subTemplates['nodeTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c2}));
scope = origScope;
scope = _origScope9;
}
}
scope = _scope8;
scope = _origScope8;
}"
`;
@@ -1265,7 +1265,7 @@ exports[`t-call (template calling recursive template, part 3 1`] = `
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
{
let origScope = scope;
const _origScope10 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
@@ -1273,7 +1273,7 @@ exports[`t-call (template calling recursive template, part 3 1`] = `
scope[utils.zero] = c__0;
}
this.subTemplates['nodeTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c1}));
scope = origScope;
scope = _origScope10;
}
return vn1;
}"
@@ -1305,8 +1305,8 @@ exports[`t-call (template calling recursive template, part 3 2`] = `
_7 = Object.values(_5);
}
var _length6 = _6.length;
let _scope8 = scope;
scope = Object.assign(Object.create(context), _scope8);
const _origScope8 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length6; i1++) {
scope.subtree_first = i1 === 0
scope.subtree_last = i1 === _length6 - 1
@@ -1314,7 +1314,7 @@ exports[`t-call (template calling recursive template, part 3 2`] = `
scope.subtree = _6[i1]
scope.subtree_value = _7[i1]
{
let origScope = scope;
const _origScope9 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
@@ -1322,10 +1322,10 @@ exports[`t-call (template calling recursive template, part 3 2`] = `
scope[utils.zero] = c__0;
}
this.subTemplates['nodeTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c2}));
scope = origScope;
scope = _origScope9;
}
}
scope = _scope8;
scope = _origScope8;
}"
`;
@@ -1339,7 +1339,7 @@ exports[`t-call (template calling scoped parameters 1`] = `
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
{
let origScope = scope;
const _origScope2 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
@@ -1347,7 +1347,7 @@ exports[`t-call (template calling scoped parameters 1`] = `
scope[utils.zero] = c__0;
}
this.subTemplates['_basic-callee'].call(this, scope, Object.assign({}, extra, {parentNode: c1}));
scope = origScope;
scope = _origScope2;
}
if (scope.foo || scope.foo === 0) {
c1.push({text: scope.foo});
@@ -1401,8 +1401,8 @@ exports[`t-call (template calling t-call with t-set inside and outside 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.v_first = i1 === 0
scope.v_last = i1 === _length3 - 1
@@ -1411,7 +1411,7 @@ exports[`t-call (template calling t-call with t-set inside and outside 1`] = `
scope.v_value = _4[i1]
scope.val = scope['v'].val;
{
let origScope = scope;
const _origScope8 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
@@ -1419,10 +1419,10 @@ exports[`t-call (template calling t-call with t-set inside and outside 1`] = `
scope[utils.zero] = c__0;
}
this.subTemplates['sub'].call(this, scope, Object.assign({}, extra, {parentNode: c1}));
scope = origScope;
scope = _origScope8;
}
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -1463,7 +1463,7 @@ exports[`t-call (template calling with unused body 1`] = `
let result;
var h = this.h;
{
let origScope = scope;
const _origScope3 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
@@ -1473,7 +1473,7 @@ exports[`t-call (template calling with unused body 1`] = `
result = []
this.subTemplates['_basic-callee'].call(this, scope, Object.assign({}, extra, {parentNode: result}));
result = result[0]
scope = origScope;
scope = _origScope3;
}
return result;
}"
@@ -1488,7 +1488,7 @@ exports[`t-call (template calling with unused setbody 1`] = `
let result;
var h = this.h;
{
let origScope = scope;
const _origScope3 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
@@ -1498,7 +1498,7 @@ exports[`t-call (template calling with unused setbody 1`] = `
result = []
this.subTemplates['_basic-callee'].call(this, scope, Object.assign({}, extra, {parentNode: result}));
result = result[0]
scope = origScope;
scope = _origScope3;
}
return result;
}"
@@ -1513,7 +1513,7 @@ exports[`t-call (template calling with used body 1`] = `
let result;
var h = this.h;
{
let origScope = scope;
const _origScope3 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
@@ -1523,7 +1523,7 @@ exports[`t-call (template calling with used body 1`] = `
result = []
this.subTemplates['_callee-printsbody'].call(this, scope, Object.assign({}, extra, {parentNode: result}));
result = result[0]
scope = origScope;
scope = _origScope3;
}
return result;
}"
@@ -1539,7 +1539,7 @@ exports[`t-call (template calling with used set body 1`] = `
let c1 = [], p1 = {key:1};
var vn1 = h('span', p1, c1);
{
let origScope = scope;
const _origScope3 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
@@ -1547,7 +1547,7 @@ exports[`t-call (template calling with used set body 1`] = `
scope[utils.zero] = c__0;
}
this.subTemplates['_callee-uses-foo'].call(this, scope, Object.assign({}, extra, {parentNode: c1}));
scope = origScope;
scope = _origScope3;
}
return vn1;
}"
@@ -1621,6 +1621,59 @@ exports[`t-esc literal 1`] = `
}"
`;
exports[`t-esc t-esc is escaped 1`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
const c2 = new utils.VDomArray();
let c3 = [], p3 = {key:3};
var vn3 = h('p', p3, c3);
c2.push(vn3);
c3.push({text: \`escaped\`});
scope.var = c2
if (scope.var || scope.var === 0) {
const _origScope4 = scope;
scope = Object.assign(Object.create(context), scope);
scope.var = scope.var instanceof utils.VDomArray ? utils.vDomToString(scope.var) : scope.var;
c1.push({text: scope.var});
scope = _origScope4;
}
return vn1;
}"
`;
exports[`t-esc t-esc=0 is escaped 1`] = `
"function anonymous(context, extra
) {
// Template name: \\"testCaller\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
{
const _origScope3 = scope;
scope = Object.assign(Object.create(context), scope);
{
let c__0 = [];
let c4 = [], p4 = {key:4};
var vn4 = h('p', p4, c4);
c__0.push(vn4);
c4.push({text: \`escaped\`});
scope[utils.zero] = c__0;
}
this.subTemplates['test'].call(this, scope, Object.assign({}, extra, {parentNode: c1}));
scope = _origScope3;
}
return vn1;
}"
`;
exports[`t-esc variable 1`] = `
"function anonymous(context, extra
) {
@@ -1930,8 +1983,8 @@ exports[`t-key t-key directive in a list 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.beer_first = i1 === 0
scope.beer_last = i1 === _length3 - 1
@@ -1947,7 +2000,7 @@ exports[`t-key t-key directive in a list 1`] = `
c7.push({text: _8});
}
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -2029,8 +2082,8 @@ exports[`t-on can bind handlers with loop variable as argument 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.action_first = i1 === 0
scope.action_last = i1 === _length3 - 1
@@ -2048,7 +2101,7 @@ exports[`t-on can bind handlers with loop variable as argument 1`] = `
p8.on['click'] = function (e) {if (!context.__owl__.isMounted){return}if (handler9) { handler9(e); } else { context.activate(action); }};
c8.push({text: \`link\`});
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -2251,8 +2304,8 @@ exports[`t-on t-on with prevent modifier in t-foreach 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.project_first = i1 === 0
scope.project_last = i1 === _length3 - 1
@@ -2272,7 +2325,7 @@ exports[`t-on t-on with prevent modifier in t-foreach 1`] = `
c8.push({text: _10});
}
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -2464,8 +2517,8 @@ exports[`t-ref refs in a loop 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.item_first = i1 === 0
scope.item_last = i1 === _length3 - 1
@@ -2490,7 +2543,7 @@ exports[`t-ref refs in a loop 1`] = `
c7.push({text: _9});
}
}
scope = _scope5;
scope = _origScope5;
return vn1;
}"
`;
@@ -2563,11 +2616,21 @@ exports[`t-set set from body literal 1`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
let result;
var h = this.h;
var vn1 = {text: \`ok\`};
result = vn1;
const c1 = new utils.VDomArray();
c1.push({text: \`ok\`});
scope.value = c1
if (scope.value || scope.value === 0) {
const _origScope2 = scope;
scope = Object.assign(Object.create(context), scope);
scope.value = scope.value instanceof utils.VDomArray ? utils.vDomToString(scope.value) : scope.value;
var vn3 = {text: scope.value};
result = vn3
scope = _origScope2;
}
return result;
}"
`;
@@ -2576,13 +2639,23 @@ exports[`t-set set from body lookup 1`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
var _2 = scope['value'];
if (_2 || _2 === 0) {
c1.push({text: _2});
const c2 = new utils.VDomArray();
var _3 = scope['value'];
if (_3 || _3 === 0) {
c2.push({text: _3});
}
scope.stuff = c2
if (scope.stuff || scope.stuff === 0) {
const _origScope4 = scope;
scope = Object.assign(Object.create(context), scope);
scope.stuff = scope.stuff instanceof utils.VDomArray ? utils.vDomToString(scope.stuff) : scope.stuff;
c1.push({text: scope.stuff});
scope = _origScope4;
}
return vn1;
}"
@@ -2596,6 +2669,9 @@ exports[`t-set set from empty body 1`] = `
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
if (scope.stuff || scope.stuff === 0) {
c1.push({text: scope.stuff});
}
return vn1;
}"
`;
@@ -2617,19 +2693,27 @@ exports[`t-set t-set and t-if 1`] = `
`;
exports[`t-set t-set body is evaluated immediately 1`] = `
"function anonymous(context,extra
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
scope.v1 = 'before';
scope.v1 = 'after'
let c2 = [], p2 = {key:2};
var vn2 = h('span', p2, c2);
c1.push(vn2);
const c2 = new utils.VDomArray();
let c3 = [], p3 = {key:3};
var vn3 = h('span', p3, c3);
c2.push(vn3);
if (scope.v1 || scope.v1 === 0) {
c2.push({text: scope.v1});
c3.push({text: scope.v1});
}
scope.v2 = c2
scope.v1 = 'after';
if (scope.v2 || scope.v2 === 0) {
const vnodeArray = scope.v2 instanceof utils.VDomArray ? scope.v2 : utils.htmlToVDOM(scope.v2);
c1.push(...vnodeArray);
}
return vn1;
}"
@@ -2671,8 +2755,8 @@ exports[`t-set t-set should reuse variable if possible 1`] = `
_4 = Object.values(_2);
}
var _length3 = _3.length;
let _scope5 = scope;
scope = Object.assign(Object.create(context), _scope5);
const _origScope5 = scope;
scope = Object.assign(Object.create(context), scope);
for (let i1 = 0; i1 < _length3; i1++) {
scope.elem_first = i1 === 0
scope.elem_last = i1 === _length3 - 1
@@ -2690,9 +2774,73 @@ exports[`t-set t-set should reuse variable if possible 1`] = `
if (scope.v || scope.v === 0) {
c8.push({text: scope.v});
}
scope.v = scope['elem']
scope.v = scope['elem'];
}
scope = _origScope5;
return vn1;
}"
`;
exports[`t-set t-set with t-value (falsy) and body 1`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
scope.v3 = false;
scope.v1 = 'before';
scope.v2 = scope.v3;
if (!(scope.v2)) {
const c2 = new utils.VDomArray();
let c3 = [], p3 = {key:3};
var vn3 = h('span', p3, c3);
c2.push(vn3);
if (scope.v1 || scope.v1 === 0) {
c3.push({text: scope.v1});
}
scope.v2 = c2
}
scope.v1 = 'after';
scope.v3 = true;
if (scope.v2 || scope.v2 === 0) {
const vnodeArray = scope.v2 instanceof utils.VDomArray ? scope.v2 : utils.htmlToVDOM(scope.v2);
c1.push(...vnodeArray);
}
return vn1;
}"
`;
exports[`t-set t-set with t-value (truthy) and body 1`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
scope.v3 = 'Truthy';
scope.v1 = 'before';
scope.v2 = scope.v3;
if (!(scope.v2)) {
const c2 = new utils.VDomArray();
let c3 = [], p3 = {key:3};
var vn3 = h('span', p3, c3);
c2.push(vn3);
if (scope.v1 || scope.v1 === 0) {
c3.push({text: scope.v1});
}
scope.v2 = c2
}
scope.v1 = 'after';
scope.v3 = false;
if (scope.v2 || scope.v2 === 0) {
const vnodeArray = scope.v2 instanceof utils.VDomArray ? scope.v2 : utils.htmlToVDOM(scope.v2);
c1.push(...vnodeArray);
}
scope = _scope5;
return vn1;
}"
`;
@@ -2701,19 +2849,25 @@ exports[`t-set t-set, t-if, and mix of expression/body lookup, 1 1`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
if (scope['flag']) {
const c2 = new utils.VDomArray();
c2.push({text: \`1\`});
scope.ourvar = c2
}
else {
scope.ourvar = 0;
}
if (scope.ourvar || scope.ourvar === 0) {
const _origScope3 = scope;
scope = Object.assign(Object.create(context), scope);
scope.ourvar = scope.ourvar instanceof utils.VDomArray ? utils.vDomToString(scope.ourvar) : scope.ourvar;
c1.push({text: scope.ourvar});
} else {
c1.push({text: \`1\`});
scope = _origScope3;
}
return vn1;
}"
@@ -2723,19 +2877,25 @@ exports[`t-set t-set, t-if, and mix of expression/body lookup, 1 2`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
if (scope['flag']) {
const c2 = new utils.VDomArray();
c2.push({text: \`1\`});
scope.ourvar = c2
}
else {
scope.ourvar = 0;
}
if (scope.ourvar || scope.ourvar === 0) {
const _origScope3 = scope;
scope = Object.assign(Object.create(context), scope);
scope.ourvar = scope.ourvar instanceof utils.VDomArray ? utils.vDomToString(scope.ourvar) : scope.ourvar;
c1.push({text: scope.ourvar});
} else {
c1.push({text: \`1\`});
scope = _origScope3;
}
return vn1;
}"
@@ -2745,6 +2905,7 @@ exports[`t-set t-set, t-if, and mix of expression/body lookup, 2 1`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
var h = this.h;
let c1 = [], p1 = {key:1};
@@ -2753,11 +2914,16 @@ exports[`t-set t-set, t-if, and mix of expression/body lookup, 2 1`] = `
scope.ourvar = 1;
}
else {
const c2 = new utils.VDomArray();
c2.push({text: \`0\`});
scope.ourvar = c2
}
if (scope.ourvar || scope.ourvar === 0) {
const _origScope3 = scope;
scope = Object.assign(Object.create(context), scope);
scope.ourvar = scope.ourvar instanceof utils.VDomArray ? utils.vDomToString(scope.ourvar) : scope.ourvar;
c1.push({text: scope.ourvar});
} else {
c1.push({text: \`0\`});
scope = _origScope3;
}
return vn1;
}"
@@ -2767,6 +2933,7 @@ exports[`t-set t-set, t-if, and mix of expression/body lookup, 2 2`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
var h = this.h;
let c1 = [], p1 = {key:1};
@@ -2775,11 +2942,16 @@ exports[`t-set t-set, t-if, and mix of expression/body lookup, 2 2`] = `
scope.ourvar = 1;
}
else {
const c2 = new utils.VDomArray();
c2.push({text: \`0\`});
scope.ourvar = c2
}
if (scope.ourvar || scope.ourvar === 0) {
const _origScope3 = scope;
scope = Object.assign(Object.create(context), scope);
scope.ourvar = scope.ourvar instanceof utils.VDomArray ? utils.vDomToString(scope.ourvar) : scope.ourvar;
c1.push({text: scope.ourvar});
} else {
c1.push({text: \`0\`});
scope = _origScope3;
}
return vn1;
}"
@@ -2789,13 +2961,23 @@ exports[`t-set value priority 1`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
scope.value = 1;
if (!(scope.value)) {
const c2 = new utils.VDomArray();
c2.push({text: \`2\`});
scope.value = c2
}
if (scope.value || scope.value === 0) {
const _origScope3 = scope;
scope = Object.assign(Object.create(context), scope);
scope.value = scope.value instanceof utils.VDomArray ? utils.vDomToString(scope.value) : scope.value;
c1.push({text: scope.value});
scope = _origScope3;
}
return vn1;
}"
+49 -2
View File
@@ -139,6 +139,17 @@ describe("t-esc", () => {
qweb.addTemplate("test", `<span t-esc="var">nope</span>`);
expect(renderToString(qweb, "test")).toBe("<span>nope</span>");
});
test("t-esc is escaped", () => {
qweb.addTemplate("test", `<div><t t-set="var"><p>escaped</p></t><t t-esc="var"/></div>`);
const domRendered = renderToDOM(qweb, "test");
expect(domRendered.textContent).toBe("<p>escaped</p>");
});
test("t-esc=0 is escaped", () => {
qweb.addTemplate("test", `<span><t t-esc="0"/></span>`);
qweb.addTemplate("testCaller", `<div><t t-call="test"><p>escaped</p></t></div>`);
const domRendered = renderToDOM(qweb, "testCaller") as HTMLElement;
expect(domRendered.querySelector("span")!.textContent).toBe("<p>escaped</p>");
});
});
describe("t-raw", () => {
@@ -289,10 +300,45 @@ describe("t-set", () => {
</t>
<t t-set="v1" t-value="'after'"/>
<t t-raw="v2"/>
</div>`
);
expect(renderToString(qweb, "test")).toBe("<div><span>before</span></div>");
});
test("t-set with t-value (falsy) and body", () => {
qweb.addTemplate(
"test",
`<div>
<t t-set="v3" t-value="false"/>
<t t-set="v1" t-value="'before'"/>
<t t-set="v2" t-value="v3">
<span><t t-esc="v1"/></span>
</t>
<t t-set="v1" t-value="'after'"/>
<t t-set="v3" t-value="true"/>
<t t-raw="v2"/>
</div>`);
expect(renderToString(qweb, "test")).toBe("<div><span>before</span></div>");
});
test("t-set with t-value (truthy) and body", () => {
qweb.addTemplate(
"test",
`<div>
<t t-set="v3" t-value="'Truthy'"/>
<t t-set="v1" t-value="'before'"/>
<t t-set="v2" t-value="v3">
<span><t t-esc="v1"/></span>
</t>
<t t-set="v1" t-value="'after'"/>
<t t-set="v3" t-value="false"/>
<t t-raw="v2"/>
</div>`);
expect(renderToString(qweb, "test")).toBe("<div>Truthy</div>");
});
});
describe("t-if", () => {
@@ -1611,11 +1657,12 @@ describe("debugging", () => {
const consoleLog = console.log;
console.log = jest.fn();
qweb.addTemplates(`
<templates>
<p t-name="sub" t-debug="1">coucou</p>
<div t-name="test">
<t t-call="sub"/>
</div>`
);
</div>
</templates>`);
qweb.render("test");
expect(console.log).toHaveBeenCalledTimes(1);