[FIX] qweb: enclose interpolated expr in parentheses

Since rev 53e53e9b,
 <div class="o_app" t-attf-class="{{ true ? 'o_extra' : '' }}"/>
produced
 <div class="o_extra"/>
whereas it should have produced
 <div class="o_app o_extra"/>

This is because there were missing parentheses around the string
returned by `interpolate`, which produced instructions like

 var _1 = 'o_app ' + true ? 'o_extra' : '';

Fixes #132
This commit is contained in:
Aaron Bohy
2019-05-29 13:21:03 +02:00
committed by Géry Debongnie
parent a08deb895d
commit 4d72a4f240
4 changed files with 26 additions and 8 deletions
+5 -4
View File
@@ -754,19 +754,20 @@ export class Context {
/** /**
* Perform string interpolation on the given string. Note that if the whole * Perform string interpolation on the given string. Note that if the whole
* string is an expression, it simply returns it (formatted). * string is an expression, it simply returns it (formatted and enclosed in
* parentheses).
* For instance: * For instance:
* 'Hello {{x}}!' -> `Hello ${x}` * 'Hello {{x}}!' -> `Hello ${x}`
* '{{x}}' -> x * '{{x ? 'a': 'b'}}' -> (x ? 'a' : 'b')
*/ */
interpolate(s: string): string { interpolate(s: string): string {
let matches = s.match(/\{\{.*?\}\}/g); let matches = s.match(/\{\{.*?\}\}/g);
if (matches && matches[0].length === s.length) { if (matches && matches[0].length === s.length) {
return this.formatExpression(s.slice(2, -2)); return `(${this.formatExpression(s.slice(2, -2))})`;
} }
matches = s.match(/\#\{.*?\}/g); matches = s.match(/\#\{.*?\}/g);
if (matches && matches[0].length === s.length) { if (matches && matches[0].length === s.length) {
return this.formatExpression(s.slice(2, -1)); return `(${this.formatExpression(s.slice(2, -1))})`;
} }
let formatter = expr => "${" + this.formatExpression(expr) + "}"; let formatter = expr => "${" + this.formatExpression(expr) + "}";
+1 -1
View File
@@ -150,7 +150,7 @@ exports[`composition t-widget with dynamic value 1`] = `
w4 = false w4 = false
} }
if (!w4) { if (!w4) {
let widgetKey4 = context['state'].widget; let widgetKey4 = (context['state'].widget);
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4]; let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4];
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')} if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')}
w4 = new W4(owner, props4); w4 = new W4(owner, props4);
+14 -3
View File
@@ -1,5 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`attributes class and t-attf-class with ternary operation 1`] = `
"function anonymous(context,extra
) {
var h = this.utils.h;
var _1 = 'hello ' + (context['value'] ? 'world' : '');
let c2 = [], p2 = {key:2,attrs:{class: _1}};
var vn2 = h('div', p2, c2);
return vn2;
}"
`;
exports[`attributes dynamic attribute falsy variable 1`] = ` exports[`attributes dynamic attribute falsy variable 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
@@ -59,7 +70,7 @@ exports[`attributes format expression 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
var h = this.utils.h; var h = this.utils.h;
var _1 = context['value'] + 37; var _1 = (context['value'] + 37);
let c2 = [], p2 = {key:2,attrs:{foo: _1}}; let c2 = [], p2 = {key:2,attrs:{foo: _1}};
var vn2 = h('div', p2, c2); var vn2 = h('div', p2, c2);
return vn2; return vn2;
@@ -70,7 +81,7 @@ exports[`attributes format expression, other format 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
var h = this.utils.h; var h = this.utils.h;
var _1 = context['value'] + 37; var _1 = (context['value'] + 37);
let c2 = [], p2 = {key:2,attrs:{foo: _1}}; let c2 = [], p2 = {key:2,attrs:{foo: _1}};
var vn2 = h('div', p2, c2); var vn2 = h('div', p2, c2);
return vn2; return vn2;
@@ -1546,7 +1557,7 @@ exports[`t-ref refs in a loop 1`] = `
let c5 = [], p5 = {key:context['item']}; let c5 = [], p5 = {key:context['item']};
var vn5 = h('div', p5, c5); var vn5 = h('div', p5, c5);
c1.push(vn5); c1.push(vn5);
const ref6 = context['item']; const ref6 = (context['item']);
p5.hook = { p5.hook = {
create: (_, n) => { create: (_, n) => {
context.refs[ref6] = n.elm; context.refs[ref6] = n.elm;
+6
View File
@@ -522,6 +522,12 @@ describe("attributes", () => {
expect(result).toBe(`<div class="hello world"></div>`); expect(result).toBe(`<div class="hello world"></div>`);
}); });
test("class and t-attf-class with ternary operation", () => {
qweb.addTemplate("test", `<div class="hello" t-attf-class="#{value ? 'world' : ''}"/>`);
const result = renderToString(qweb, "test", { value: true });
expect(result).toBe(`<div class="hello world"></div>`);
});
test("t-att-class with object", () => { test("t-att-class with object", () => {
qweb.addTemplate( qweb.addTemplate(
"test", "test",