mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] qweb: add support for template strings
in inline expressions, such as t-esc or t-value. closes #746
This commit is contained in:
@@ -57,6 +57,7 @@ type TKind =
|
|||||||
| "RIGHT_PAREN"
|
| "RIGHT_PAREN"
|
||||||
| "COMMA"
|
| "COMMA"
|
||||||
| "VALUE"
|
| "VALUE"
|
||||||
|
| "TEMPLATE_STRING"
|
||||||
| "SYMBOL"
|
| "SYMBOL"
|
||||||
| "OPERATOR"
|
| "OPERATOR"
|
||||||
| "COLON";
|
| "COLON";
|
||||||
@@ -67,6 +68,7 @@ interface Token {
|
|||||||
originalValue?: string;
|
originalValue?: string;
|
||||||
size?: number;
|
size?: number;
|
||||||
varName?: string;
|
varName?: string;
|
||||||
|
replace?: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
const STATIC_TOKEN_MAP: { [key: string]: TKind } = Object.assign(Object.create(null), {
|
const STATIC_TOKEN_MAP: { [key: string]: TKind } = Object.assign(Object.create(null), {
|
||||||
@@ -89,7 +91,7 @@ type Tokenizer = (expr: string) => Token | false;
|
|||||||
let tokenizeString: Tokenizer = function (expr) {
|
let tokenizeString: Tokenizer = function (expr) {
|
||||||
let s = expr[0];
|
let s = expr[0];
|
||||||
let start = s;
|
let start = s;
|
||||||
if (s !== "'" && s !== '"') {
|
if (s !== "'" && s !== '"' && s !== "`") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let i = 1;
|
let i = 1;
|
||||||
@@ -111,6 +113,17 @@ let tokenizeString: Tokenizer = function (expr) {
|
|||||||
throw new Error("Invalid expression");
|
throw new Error("Invalid expression");
|
||||||
}
|
}
|
||||||
s += start;
|
s += start;
|
||||||
|
if (start === "`") {
|
||||||
|
return {
|
||||||
|
type: "TEMPLATE_STRING",
|
||||||
|
value: s,
|
||||||
|
replace(replacer) {
|
||||||
|
return s.replace(/\$\{(.*?)\}/g, (match, group) => {
|
||||||
|
return "${" + replacer(group) + "}";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
return { type: "VALUE", value: s };
|
return { type: "VALUE", value: s };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -267,6 +280,9 @@ export function compileExprToArray(expr: string, scope: { [key: string]: QWebVar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (token.type === "TEMPLATE_STRING") {
|
||||||
|
token.value = token.replace((expr) => compileExpr(expr, scope));
|
||||||
|
}
|
||||||
if (nextToken && nextToken.type === "OPERATOR" && nextToken.value === "=>") {
|
if (nextToken && nextToken.type === "OPERATOR" && nextToken.value === "=>") {
|
||||||
if (token.type === "RIGHT_PAREN") {
|
if (token.type === "RIGHT_PAREN") {
|
||||||
let j = i - 1;
|
let j = i - 1;
|
||||||
|
|||||||
@@ -1236,6 +1236,55 @@ exports[`static templates empty div 1`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`static templates inline template string in t-esc 1`] = `
|
||||||
|
"function anonymous(context, extra
|
||||||
|
) {
|
||||||
|
// Template name: \\"test\\"
|
||||||
|
let scope = Object.create(context);
|
||||||
|
let result;
|
||||||
|
let h = this.h;
|
||||||
|
let _1 = \`text\`;
|
||||||
|
if (_1 != null) {
|
||||||
|
let vn2 = {text: _1};
|
||||||
|
result = vn2
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`static templates inline template string with content in t-esc 1`] = `
|
||||||
|
"function anonymous(context, extra
|
||||||
|
) {
|
||||||
|
// Template name: \\"test\\"
|
||||||
|
let scope = Object.create(context);
|
||||||
|
let result;
|
||||||
|
let h = this.h;
|
||||||
|
scope.v = 1;
|
||||||
|
let _1 = \`text\${scope.v}\`;
|
||||||
|
if (_1 != null) {
|
||||||
|
let vn2 = {text: _1};
|
||||||
|
result = vn2
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`static templates inline template string with variable in context 1`] = `
|
||||||
|
"function anonymous(context, extra
|
||||||
|
) {
|
||||||
|
// Template name: \\"test\\"
|
||||||
|
let scope = Object.create(context);
|
||||||
|
let result;
|
||||||
|
let h = this.h;
|
||||||
|
let _1 = \`text \${scope['v']}\`;
|
||||||
|
if (_1 != null) {
|
||||||
|
let vn2 = {text: _1};
|
||||||
|
result = vn2
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`static templates properly handle comments 1`] = `
|
exports[`static templates properly handle comments 1`] = `
|
||||||
"function anonymous(context, extra
|
"function anonymous(context, extra
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -31,6 +31,21 @@ describe("static templates", () => {
|
|||||||
expect(renderToString(qweb, "test", { text: "hello vdom" })).toBe("hello vdom");
|
expect(renderToString(qweb, "test", { text: "hello vdom" })).toBe("hello vdom");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("inline template string in t-esc", () => {
|
||||||
|
qweb.addTemplate("test", '<t><t t-esc="`text`"/></t>');
|
||||||
|
expect(renderToString(qweb, "test")).toBe("text");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("inline template string with content in t-esc", () => {
|
||||||
|
qweb.addTemplate("test", '<t><t t-set="v" t-value="1"/><t t-esc="`text${v}`"/></t>');
|
||||||
|
expect(renderToString(qweb, "test")).toBe("text1");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("inline template string with variable in context", () => {
|
||||||
|
qweb.addTemplate("test", '<t><t t-esc="`text ${v}`"/></t>');
|
||||||
|
expect(renderToString(qweb, "test", { v: "from context" })).toBe("text from context");
|
||||||
|
});
|
||||||
|
|
||||||
test("simple string, with some dynamic value", () => {
|
test("simple string, with some dynamic value", () => {
|
||||||
qweb.addTemplate("test", '<t>hello <t t-esc="text"/></t>');
|
qweb.addTemplate("test", '<t>hello <t t-esc="text"/></t>');
|
||||||
expect(renderToString(qweb, "test", { text: "vdom" })).toBe("hello vdom");
|
expect(renderToString(qweb, "test", { text: "vdom" })).toBe("hello vdom");
|
||||||
|
|||||||
@@ -206,4 +206,10 @@ describe("expression evaluation", () => {
|
|||||||
expect(compileExpr("{a,b}", {})).toBe("{a:scope['a'],b:scope['b']}");
|
expect(compileExpr("{a,b}", {})).toBe("{a:scope['a'],b:scope['b']}");
|
||||||
expect(compileExpr("{a,b:3,c}", {})).toBe("{a:scope['a'],b:3,c:scope['c']}");
|
expect(compileExpr("{a,b:3,c}", {})).toBe("{a:scope['a'],b:3,c:scope['c']}");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("template strings", () => {
|
||||||
|
expect(compileExpr("`hey`", {})).toBe("`hey`");
|
||||||
|
expect(compileExpr("`hey ${you}`", {})).toBe("`hey ${scope['you']}`");
|
||||||
|
expect(compileExpr("`hey ${1 + 2}`", {})).toBe("`hey ${1+2}`");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ if __name__ == "__main__":
|
|||||||
* Make an iframe, with all the js, css and xml properly injected.
|
* Make an iframe, with all the js, css and xml properly injected.
|
||||||
*/
|
*/
|
||||||
function makeCodeIframe(js, css, xml) {
|
function makeCodeIframe(js, css, xml) {
|
||||||
const sanitizedXML = xml.replace(/<!--[\s\S]*?-->/g, "");
|
const sanitizedXML = xml.replace(/<!--[\s\S]*?-->/g, "").replace(/`/g, '\\\`');
|
||||||
|
|
||||||
|
|
||||||
// create iframe
|
// create iframe
|
||||||
|
|||||||
Reference in New Issue
Block a user