mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] qweb: turn handlers into function expressions only
For the sake of consistency with vanilla JS, and to allow some things that were previously not possible.
This commit is contained in:
committed by
Aaron Bohy
parent
756d32daa0
commit
bca6afeb90
@@ -93,7 +93,7 @@ export class ComponentNode<T extends typeof Component = any> implements VNode<Co
|
||||
this.level = parent ? parent.level + 1 : 0;
|
||||
applyDefaultProps(props, C);
|
||||
this.component = new C(props, app.env, this) as any;
|
||||
this.renderFn = app.getTemplate(C.template).bind(null, this.component, this);
|
||||
this.renderFn = app.getTemplate(C.template).bind(this.component, this.component, this);
|
||||
if (C.style) {
|
||||
applyStyles(C);
|
||||
}
|
||||
|
||||
@@ -26,12 +26,11 @@ export const mainEventHandler = (data: any, ev: Event, currentTarget?: EventTarg
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof data[0] === "function") {
|
||||
data[0](ev);
|
||||
} else if (data[0].__owl__) {
|
||||
const method = data[1];
|
||||
const args = data[2] || [];
|
||||
data[0].__owl__.component[method](...args, ev);
|
||||
// If handler is empty, the array slot 0 will also be empty, and data will not have the property 0
|
||||
// We check this rather than data[0] being truthy (or typeof function) so that it crashes
|
||||
// as expected when there is a handler expression that evaluates to a falsy value
|
||||
if (Object.hasOwnProperty.call(data, 0)) {
|
||||
data[0].call(data[1] ? data[1].__owl__.component : null, ev);
|
||||
}
|
||||
return stopped;
|
||||
};
|
||||
|
||||
+6
-24
@@ -118,7 +118,6 @@ class BlockDescription {
|
||||
// -----------------------------------------------------------------------------
|
||||
// Compiler code
|
||||
// -----------------------------------------------------------------------------
|
||||
const FNAMEREGEXP = /^[$A-Z_][0-9A-Z_$]*$/i;
|
||||
|
||||
interface Context {
|
||||
block: BlockDescription | null;
|
||||
@@ -372,7 +371,7 @@ export class QWebCompiler {
|
||||
const mapping = new Map<string, string>();
|
||||
return tokens
|
||||
.map((tok) => {
|
||||
if (tok.varName) {
|
||||
if (tok.varName && !tok.isLocal) {
|
||||
if (!mapping.has(tok.varName)) {
|
||||
const varId = this.generateId("v");
|
||||
mapping.set(tok.varName, varId);
|
||||
@@ -490,11 +489,6 @@ export class QWebCompiler {
|
||||
}
|
||||
|
||||
generateHandlerCode(rawEvent: string, handler: string): string {
|
||||
let args: string = "";
|
||||
const name: string = handler.replace(/\(.*\)/, function (_args) {
|
||||
args = _args.slice(1, -1);
|
||||
return "";
|
||||
});
|
||||
const modifiers = rawEvent
|
||||
.split(".")
|
||||
.slice(1)
|
||||
@@ -503,22 +497,7 @@ export class QWebCompiler {
|
||||
if (modifiers.length) {
|
||||
modifiersCode = `${modifiers.join(",")}, `;
|
||||
}
|
||||
const isMethodCall = name.match(FNAMEREGEXP);
|
||||
if (isMethodCall) {
|
||||
let handlerFn: string;
|
||||
if (args) {
|
||||
const argId = this.generateId("arg");
|
||||
this.addLine(`const ${argId} = [${compileExpr(args)}];`);
|
||||
handlerFn = `'${name}', ${argId}`;
|
||||
} else {
|
||||
handlerFn = `'${name}'`;
|
||||
}
|
||||
return `[${modifiersCode}ctx, ${handlerFn!}]`;
|
||||
} else {
|
||||
let code = this.captureExpression(handler);
|
||||
code = `{const res = (() => { return ${code} })(); if (typeof res === 'function') { res(e) }}`;
|
||||
return `[${modifiersCode}(e) => ${code}]`;
|
||||
}
|
||||
return `[${modifiersCode}${this.captureExpression(handler)}, ctx]`;
|
||||
}
|
||||
|
||||
compileTDomNode(ast: ASTDomNode, ctx: Context) {
|
||||
@@ -919,7 +898,10 @@ export class QWebCompiler {
|
||||
const id = this.generateId(`callTemplate_`);
|
||||
this.staticCalls.push({ id, template: subTemplate });
|
||||
block = this.createBlock(block, "multi", ctx);
|
||||
this.insertBlock(`${id}(ctx, node, ${key})`, block!, { ...ctx, forceNewBlock: !block });
|
||||
this.insertBlock(`${id}.call(this, ctx, node, ${key})`, block!, {
|
||||
...ctx,
|
||||
forceNewBlock: !block,
|
||||
});
|
||||
}
|
||||
if (ast.body && !ctx.isLast) {
|
||||
this.addLine(`ctx = ctx.__proto__;`);
|
||||
|
||||
@@ -70,6 +70,7 @@ interface Token {
|
||||
size?: number;
|
||||
varName?: string;
|
||||
replace?: Function;
|
||||
isLocal?: boolean;
|
||||
}
|
||||
|
||||
const STATIC_TOKEN_MAP: { [key: string]: TKind } = Object.assign(Object.create(null), {
|
||||
@@ -325,6 +326,13 @@ export function compileExprToArray(expr: string): Token[] {
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// Mark all variables that have been used locally.
|
||||
// This assumes the expression has only one scope (incorrect but "good enough for now")
|
||||
for (const token of tokens) {
|
||||
if (token.type === "SYMBOL" && localVars.has(token.value)) {
|
||||
token.isLocal = true;
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user