ref: improve qweb implementation

This commit is contained in:
Géry Debongnie
2019-03-22 14:51:02 +01:00
parent 6ea9ccf56f
commit 597adb3981
+69 -69
View File
@@ -138,6 +138,65 @@ export class Context {
getValue(val: any): any {
return val in this.variables ? this.getValue(this.variables[val]) : val;
}
formatExpression(e: string): string {
e = e.trim();
if (e[0] === "{" && e[e.length - 1] === "}") {
const innerExpr = e
.slice(1, -1)
.split(",")
.map(p => {
let [key, val] = p.trim().split(":");
if (key === "") {
return "";
}
if (!val) {
val = key;
}
return `${key}: ${this.formatExpression(val)}`;
})
.join(",");
return "{" + innerExpr + "}";
}
// Thanks CHM for this code...
const chars = e.split("");
let instring = "";
let invar = "";
let invarPos = 0;
let r = "";
chars.push(" ");
for (var i = 0, ilen = chars.length; i < ilen; i++) {
var c = chars[i];
if (instring.length) {
if (c === instring && chars[i - 1] !== "\\") {
instring = "";
}
} else if (c === '"' || c === "'") {
instring = c;
} else if (c.match(/[a-zA-Z_\$]/) && !invar.length) {
invar = c;
invarPos = i;
continue;
} else if (c.match(/\W/) && invar.length) {
// TODO: Should check for possible spaces before dot
if (chars[invarPos - 1] !== "." && RESERVED_WORDS.indexOf(invar) < 0) {
invar =
WORD_REPLACEMENT[invar] ||
(invar in this.variables && this.variables[invar]) ||
"context['" + invar + "']";
}
r += invar;
invar = "";
} else if (invar.length) {
invar += c;
continue;
}
r += c;
}
const result = r.slice(0, -1);
return result;
}
}
//------------------------------------------------------------------------------
@@ -496,7 +555,7 @@ export class QWeb {
// dynamic attributes
if (name.startsWith("t-att-")) {
let attName = name.slice(6);
let formattedValue = this._formatExpression(ctx.getValue(value!), ctx);
let formattedValue = ctx.formatExpression(ctx.getValue(value!));
if (
formattedValue[0] === "{" &&
formattedValue[formattedValue.length - 1] === "}"
@@ -533,7 +592,7 @@ export class QWeb {
}
const formattedExpr = value!.replace(
/\{\{.*?\}\}/g,
s => "${" + this._formatExpression(s.slice(2, -2)) + "}"
s => "${" + ctx.formatExpression(s.slice(2, -2)) + "}"
);
const attID = ctx.generateID();
ctx.addLine(`let _${attID} = \`${formattedExpr}\`;`);
@@ -543,7 +602,7 @@ export class QWeb {
// t-att= attributes
if (name === "t-att") {
let id = ctx.generateID();
ctx.addLine(`let _${id} = ${this._formatExpression(value!)};`);
ctx.addLine(`let _${id} = ${ctx.formatExpression(value!)};`);
tattrs.push(id);
}
}
@@ -588,65 +647,6 @@ export class QWeb {
}
}
}
_formatExpression(e: string, ctx?: Context): string {
e = e.trim();
if (e[0] === "{" && e[e.length - 1] === "}") {
const innerExpr = e
.slice(1, -1)
.split(",")
.map(p => {
let [key, val] = p.trim().split(":");
if (key === "") {
return "";
}
if (!val) {
val = key;
}
return `${key}: ${this._formatExpression(val, ctx)}`;
})
.join(",");
return "{" + innerExpr + "}";
}
// Thanks CHM for this code...
const chars = e.split("");
let instring = "";
let invar = "";
let invarPos = 0;
let r = "";
chars.push(" ");
for (var i = 0, ilen = chars.length; i < ilen; i++) {
var c = chars[i];
if (instring.length) {
if (c === instring && chars[i - 1] !== "\\") {
instring = "";
}
} else if (c === '"' || c === "'") {
instring = c;
} else if (c.match(/[a-zA-Z_\$]/) && !invar.length) {
invar = c;
invarPos = i;
continue;
} else if (c.match(/\W/) && invar.length) {
// TODO: Should check for possible spaces before dot
if (chars[invarPos - 1] !== "." && RESERVED_WORDS.indexOf(invar) < 0) {
invar =
WORD_REPLACEMENT[invar] ||
(ctx && invar in ctx.variables && ctx.variables[invar]) ||
"context['" + invar + "']";
}
r += invar;
invar = "";
} else if (invar.length) {
invar += c;
continue;
}
r += c;
}
const result = r.slice(0, -1);
return result;
}
}
//------------------------------------------------------------------------------
@@ -680,7 +680,7 @@ function compileValueNode(value: any, node: Element, qweb: QWeb, ctx: Context) {
if (typeof value === "string") {
const exprID = ctx.generateID();
ctx.addLine(`let e${exprID} = ${qweb._formatExpression(value)};`);
ctx.addLine(`let e${exprID} = ${ctx.formatExpression(value)};`);
ctx.addIf(`e${exprID} || e${exprID} === 0`);
let text = `e${exprID}`;
@@ -763,7 +763,7 @@ const ifDirective: Directive = {
priority: 20,
atNodeEncounter({ node, qweb, ctx }): boolean {
let cond = ctx.getValue(node.getAttribute("t-if")!);
ctx.addIf(`${qweb._formatExpression(cond)}`);
ctx.addIf(`${ctx.formatExpression(cond)}`);
return false;
},
finalize({ ctx }) {
@@ -776,7 +776,7 @@ const elifDirective: Directive = {
priority: 30,
atNodeEncounter({ node, qweb, ctx }): boolean {
let cond = ctx.getValue(node.getAttribute("t-elif")!);
ctx.addLine(`else if (${qweb._formatExpression(cond)}) {`);
ctx.addLine(`else if (${ctx.formatExpression(cond)}) {`);
ctx.indent();
return false;
},
@@ -833,7 +833,7 @@ const forEachDirective: Directive = {
const elems = node.getAttribute("t-foreach")!;
const name = node.getAttribute("t-as")!;
let arrayID = ctx.generateID();
ctx.addLine(`let _${arrayID} = ${qweb._formatExpression(elems)};`);
ctx.addLine(`let _${arrayID} = ${ctx.formatExpression(elems)};`);
ctx.addLine(
`if (!_${arrayID}) { throw new Error('QWeb error: Invalid loop expression')}`
);
@@ -878,7 +878,7 @@ const onDirective: Directive = {
});
if (extraArgs) {
ctx.addLine(
`p${nodeID}.on['${eventName}'] = context['${handler}'].bind(owner, ${qweb._formatExpression(
`p${nodeID}.on['${eventName}'] = context['${handler}'].bind(owner, ${ctx.formatExpression(
extraArgs
)});`
);
@@ -929,11 +929,11 @@ const widgetDirective: Directive = {
} else {
key = node.getAttribute("t-att-key");
if (key) {
key = qweb._formatExpression(key);
key = ctx.formatExpression(key);
}
}
if (props) {
props = qweb._formatExpression(props, ctx);
props = ctx.formatExpression(props);
}
let dummyID = ctx.generateID();
let defID = ctx.generateID();