From ce9c2f8613e2f7c51f5d7eb47b17066637c40a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Sat, 7 Dec 2019 22:56:00 +0100 Subject: [PATCH] [FIX] qweb/component: refactoring of scoping/variables/slots This commit is a significant refactoring of the internal of QWeb. It simplifies the way variables/scoping and slots interact together. The main idea is that we use a simple scope object instead of a context/var/scope object. This commit also implement the actual correct QWeb semantic for the t-call directive with a sub body. Before, we simply extracted the variables from the body and injected them at the top of the sub template. We now simply compile the body before the sub template. This is a joint work with Lucas (lpe). closes #541 closes #544 closes #545 closes #557 closes #556 --- src/component/component.ts | 14 +- src/component/directive.ts | 37 +- src/component/fiber.ts | 2 - src/qweb/base_directives.ts | 174 +- src/qweb/compilation_context.ts | 65 +- src/qweb/expression_parser.ts | 20 +- src/qweb/extensions.ts | 9 +- src/qweb/qweb.ts | 16 +- tests/__snapshots__/animations.test.ts.snap | 28 +- .../__snapshots__/component.test.ts.snap | 728 ++++---- .../props_validation.test.ts.snap | 8 +- tests/component/component.test.ts | 153 ++ tests/qweb/__snapshots__/qweb.test.ts.snap | 1468 ++++++++++------- tests/qweb/qweb.test.ts | 92 +- tests/qweb/qweb_expressions.test.ts | 64 +- tests/router/__snapshots__/link.test.ts.snap | 10 +- .../route_component.test.ts.snap | 14 +- tests/tooling/debug_script_3.test.ts | 2 +- 18 files changed, 1625 insertions(+), 1279 deletions(-) diff --git a/src/component/component.ts b/src/component/component.ts index 14d5ec5b..c4155a1e 100644 --- a/src/component/component.ts +++ b/src/component/component.ts @@ -70,10 +70,9 @@ interface Internal { parentLastFiberId: number; // when a rendering is initiated by a parent, it may set variables in 'scope' - // and 'vars' (typically when the component is rendered in a slot). We need to + // (typically when the component is rendered in a slot). We need to // store that information in case the component would be re-rendered later on. scope: any; - vars: any; boundHandlers: { [key: number]: any }; observer: Observer | null; @@ -198,8 +197,7 @@ export class Component { renderFn: qweb.render.bind(qweb, template), classObj: null, refs: null, - scope: null, - vars: null + scope: null }; } @@ -510,9 +508,8 @@ export class Component { * The __updateProps method is called by the t-component directive whenever * it updates a component (so, when the parent template is rerendered). */ - async __updateProps(nextProps: Props, parentFiber: Fiber, scope: any, vars: any): Promise { + async __updateProps(nextProps: Props, parentFiber: Fiber, scope: any): Promise { this.__owl__.scope = scope; - this.__owl__.vars = vars; const shouldUpdate = parentFiber.force || this.shouldUpdate(nextProps); if (shouldUpdate) { const __owl__ = this.__owl__; @@ -566,12 +563,11 @@ export class Component { /** * The __prepare method is only called by the t-component directive, when a - * subcomponent is created. It gets its scope and vars, if any, from the + * subcomponent is created. It gets its scope, if any, from the * parent template. */ - __prepare(parentFiber: Fiber, scope: any, vars: any, cb: CallableFunction): Fiber { + __prepare(parentFiber: Fiber, scope: any, cb: CallableFunction): Fiber { this.__owl__.scope = scope; - this.__owl__.vars = vars; const fiber = new Fiber(parentFiber, this, parentFiber.force, null); fiber.shouldPatch = false; if (!parentFiber.child) { diff --git a/src/component/directive.ts b/src/component/directive.ts index 6e149f05..1cb0744b 100644 --- a/src/component/directive.ts +++ b/src/component/directive.ts @@ -190,10 +190,10 @@ QWeb.addDirective({ priority: 100, atNodeEncounter({ ctx, value, node, qweb }): boolean { ctx.addLine("//COMPONENT"); - ctx.rootContext.shouldDefineOwner = true; ctx.rootContext.shouldDefineQWeb = true; ctx.rootContext.shouldDefineParent = true; ctx.rootContext.shouldDefineUtils = true; + ctx.rootContext.shouldDefineScope = true; let hasDynamicProps = node.getAttribute("t-props") ? true : false; // t-on- events and t-transition @@ -285,7 +285,7 @@ QWeb.addDirective({ } let eventsCode = events .map(function([eventName, mods, handlerValue, extraArgs]) { - let params = "owner"; + let params = "context"; if (extraArgs) { if (ctx.loopNumber) { let argId = ctx.generateID(); @@ -293,20 +293,20 @@ QWeb.addDirective({ // be set asynchronously later when the widget is ready, and the // context might be different. ctx.addLine(`let arg${argId} = ${ctx.formatExpression(extraArgs)};`); - params = `owner, arg${argId}`; + params = `context, arg${argId}`; } else { - params = `owner, ${ctx.formatExpression(extraArgs)}`; + params = `context, ${ctx.formatExpression(extraArgs)}`; } } - let handler = `function (e) {if(!owner.__owl__.isMounted){return}`; + let handler = `function (e) {if(!context.__owl__.isMounted){return}`; handler += mods .map(function(mod) { return T_COMPONENT_MODS_CODE[mod]; }) .join(""); if (handlerValue) { - handler += `const fn = owner['${handlerValue}'];`; - handler += `if (fn) { fn.call(${params}, e); } else { owner.${handlerValue}; }`; + handler += `const fn = context['${handlerValue}'];`; + handler += `if (fn) { fn.call(${params}, e); } else { context.${handlerValue}; }`; } handler += `}`; return `vn.elm.addEventListener('${eventName}', ${handler});`; @@ -348,25 +348,9 @@ QWeb.addDirective({ } // SLOTS - const varDefs: string[] = []; const hasSlots = node.childNodes.length; - if (hasSlots) { - ctx.rootContext.shouldTrackScope = true; - for (let v of Object.values(ctx.variables)) { - if (v["id"]) { - varDefs.push(v["id"]); - } - } - } - let scopeVars; - if (hasSlots) { - let scope = ctx.scopeVars.length ? `Object.assign({}, scope)` : `{}`; - let vars = varDefs.length ? `{${varDefs.join(",")}}` : "undefined"; - scopeVars = `${scope}, ${vars}`; - } else { - scopeVars = "undefined, undefined"; - } + let scope = hasSlots ? `Object.assign(Object.create(context), scope)` : "undefined"; ctx.addIf(`w${componentID}`); @@ -376,8 +360,7 @@ QWeb.addDirective({ styleCode = `.then(()=>{if (w${componentID}.__owl__.isDestroyed) {return};w${componentID}.el.style=${tattStyle};});`; } ctx.addLine( - `w${componentID}.__updateProps(props${componentID}, extra.fiber${scopeVars && - ", " + scopeVars})${styleCode};` + `w${componentID}.__updateProps(props${componentID}, extra.fiber, ${scope})${styleCode};` ); ctx.addLine(`let pvnode = w${componentID}.__owl__.pvnode;`); if (registerCode) { @@ -439,7 +422,7 @@ QWeb.addDirective({ } ctx.addLine( - `let fiber = w${componentID}.__prepare(extra.fiber, ${scopeVars}, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; ${createHook}});` + `let fiber = w${componentID}.__prepare(extra.fiber, ${scope}, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; ${createHook}});` ); // hack: specify empty remove hook to prevent the node from being removed from the DOM const insertHook = refExpr ? `insert(vn) {${refExpr}},` : ""; diff --git a/src/component/fiber.ts b/src/component/fiber.ts index 0e6d947a..0de55ef9 100644 --- a/src/component/fiber.ts +++ b/src/component/fiber.ts @@ -49,7 +49,6 @@ export class Fiber { inserter: (el: HTMLElement) => void | null; scope: any; - vars: any; component: Component; vnode: VNode | null = null; @@ -69,7 +68,6 @@ export class Fiber { const __owl__ = component.__owl__; this.scope = __owl__.scope; - this.vars = __owl__.vars; this.root = parent ? parent.root : this; this.parent = parent; diff --git a/src/qweb/base_directives.ts b/src/qweb/base_directives.ts index f977d736..d0ce4984 100644 --- a/src/qweb/base_directives.ts +++ b/src/qweb/base_directives.ts @@ -19,21 +19,18 @@ import { htmlToVDOM } from "../vdom/html_to_vdom"; //------------------------------------------------------------------------------ // t-esc and t-raw //------------------------------------------------------------------------------ -QWeb.utils.getFragment = function(str: string): DocumentFragment { - const temp = document.createElement("template"); - temp.innerHTML = str; - return temp.content; -}; - QWeb.utils.htmlToVDOM = htmlToVDOM; function compileValueNode(value: any, node: Element, qweb: QWeb, ctx: CompilationContext) { + ctx.rootContext.shouldDefineScope = true; if (value === "0") { - const caller = ctx.getCaller(); - if (caller) { - qweb._compileNode(caller, ctx.getInliningContext()); - return; + if (ctx.parentNode) { + // 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]);`); } + return; } if (value.xml instanceof NodeList && !value.id) { @@ -47,7 +44,7 @@ function compileValueNode(value: any, node: Element, qweb: QWeb, ctx: Compilatio exprID = `_${ctx.generateID()}`; ctx.addLine(`var ${exprID} = ${ctx.formatExpression(value)};`); } else { - exprID = value.id; + exprID = `scope.${value.id}`; } ctx.addIf(`${exprID} || ${exprID} === 0`); if (ctx.escaping) { @@ -110,6 +107,7 @@ QWeb.addDirective({ extraNames: ["value"], priority: 60, atNodeEncounter({ node, ctx }): boolean { + ctx.rootContext.shouldDefineScope = true; const variable = node.getAttribute("t-set")!; let value = node.getAttribute("t-value")!; ctx.variables[variable] = ctx.variables[variable] || {}; @@ -118,12 +116,12 @@ QWeb.addDirective({ if (value) { const formattedValue = ctx.formatExpression(value); if (ctx.variables.hasOwnProperty(variable) && qwebvar.id) { - ctx.addLine(`${qwebvar.id} = ${formattedValue}`); + ctx.addLine(`${qwebvar.expr} = ${formattedValue}`); } else { - const varName = `_${ctx.generateID()}`; - ctx.addLine(`var ${varName} = ${formattedValue};`); - qwebvar.id = varName; - qwebvar.expr = formattedValue; + ctx.addLine(`scope.${variable} = ${formattedValue};`); + qwebvar.id = variable; + qwebvar.expr = `scope.${variable}`; + qwebvar.value = formattedValue; } } else { qwebvar.xml = node.childNodes; @@ -140,7 +138,7 @@ QWeb.addDirective({ priority: 20, atNodeEncounter({ node, ctx }): boolean { let cond = ctx.getValue(node.getAttribute("t-if")!); - ctx.addIf(typeof cond === "string" ? ctx.formatExpression(cond) : cond.id!); + ctx.addIf(typeof cond === "string" ? ctx.formatExpression(cond) : `scope.${cond.id!}`); return false; }, finalize({ ctx }) { @@ -153,7 +151,9 @@ QWeb.addDirective({ priority: 30, atNodeEncounter({ node, ctx }): boolean { let cond = ctx.getValue(node.getAttribute("t-elif")!); - ctx.addLine(`else if (${typeof cond === "string" ? ctx.formatExpression(cond) : cond.id}) {`); + ctx.addLine( + `else if (${typeof cond === "string" ? ctx.formatExpression(cond) : `scope.${cond.id}`}) {` + ); ctx.indent(); return false; }, @@ -182,6 +182,9 @@ QWeb.addDirective({ name: "call", priority: 50, atNodeEncounter({ node, qweb, ctx }): boolean { + // Step 1: sanity checks + // ------------------------------------------------ + ctx.rootContext.shouldDefineScope = true; if (node.nodeName !== "t") { throw new Error("Invalid tag for t-call directive (should be 't')"); } @@ -190,77 +193,63 @@ QWeb.addDirective({ if (!nodeTemplate) { throw new Error(`Cannot find template "${subTemplate}" (t-call)`); } - const nodeCopy = node.cloneNode(true) as Element; - nodeCopy.removeAttribute("t-call"); - // extract variables from nodecopy - const tempCtx = new CompilationContext(); - tempCtx.allowMultipleRoots = true; - qweb._compileNode(nodeCopy, tempCtx); - const vars = Object.assign({}, ctx.variables, tempCtx.variables); - - const templateMap = Object.create(ctx.templates); - // open new scope, if necessary - const hasNewVariables = Object.keys(tempCtx.variables).length > 0; - - // compile sub template - let subCtx = ctx.subContext("caller", nodeCopy).subContext("variables", Object.create(vars)); - subCtx = subCtx.subContext("templates", templateMap); - - if (templateMap[subTemplate]) { - // OUCH, IT IS A RECURSIVE TEMPLATE SITUATION... - // This is a tricky situation... We obviously cannot inline the compiled - // template. So, what we need to do is to compile it, and make sure we - // properly transfer everything from the current scope to the sub template. - ctx.rootContext.shouldTrackScope = true; - ctx.rootContext.shouldDefineOwner = true; - let subTemplateName; - if (ctx.hasParentWidget) { - subTemplateName = ctx.templateName; - } else { - subTemplateName = `__${ctx.generateID()}`; - subCtx.variables = {}; - let id = 0; - for (let v in vars) { - subCtx.variables[v] = vars[v]; - (vars[v] as any).id = `_v${id++}`; - } - const subTemplateFn = qweb._compile(subTemplateName, nodeTemplate.elem, subCtx); - qweb.recursiveFns[subTemplateName] = subTemplateFn; - } - let varCode = `{}`; - if (Object.keys(vars).length) { - let id = 0; - const content = Object.values(vars) - .map((v: any) => `_v${id++}: ${v.expr}`) - .join(","); - varCode = `{${content}}`; - } - ctx.addLine( - `this.recursiveFns['${subTemplateName}'].call(this, context, Object.assign({}, extra, {parentNode: c${ctx.parentNode}, vars: ${varCode}, fiber: {scope}}));` - ); - return true; + // Step 2: compile target template in sub templates + // ------------------------------------------------ + if (!qweb.subTemplates[subTemplate]) { + qweb.subTemplates[subTemplate] = true; + const subTemplateFn = qweb._compile(subTemplate, nodeTemplate.elem, ctx); + qweb.subTemplates[subTemplate] = subTemplateFn; } - templateMap[subTemplate] = true; - if (hasNewVariables) { - ctx.addLine("{"); + // Step 3: compile t-call body if necessary + // ------------------------------------------------ + let hasBody = node.hasChildNodes(); + if (hasBody) { + // we add a sub scope to protect the ambient scope + ctx.addLine(`{`); ctx.indent(); - // add new variables, if any - for (let key in tempCtx.variables) { - const v = tempCtx.variables[key]; - if (v.expr) { - ctx.addLine(`let ${v.id} = ${v.expr};`); - } - // todo: handle XML variables... - } - } - qweb._compileNode(nodeTemplate.elem, subCtx); - - // close new scope - if (hasNewVariables) { + ctx.addLine(`let origScope = scope;`); + ctx.addLine(`scope = Object.assign(Object.create(context), scope);`); + const nodeCopy = node.cloneNode(true) as Element; + nodeCopy.removeAttribute("t-call"); + const parentNode = ctx.parentNode; + ctx.parentNode = "__0"; + // this local scope is intended to trap c__0 + ctx.addLine(`{`); + ctx.indent(); + ctx.addLine("let c__0 = [];"); + qweb._compileNode(nodeCopy, ctx); + ctx.rootContext.shouldDefineUtils = true; + ctx.addLine("scope[utils.zero] = c__0;"); + ctx.parentNode = parentNode; ctx.dedent(); - ctx.addLine("}"); + ctx.addLine(`}`); + } + + // Step 4: add the appropriate function call to current component + // ------------------------------------------------ + 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}}));` + ); + } else { + // this is a t-call with no parentnode, we need to extract the result + ctx.rootContext.shouldDefineResult = true; + ctx.addLine(`result = []`); + ctx.addLine( + `this.subTemplates['${subTemplate}'].call(this, ${callingScope}, Object.assign({}, extra, {parentNode: result}));` + ); + ctx.addLine(`result = result[0]`); + } + + // Step 5: restore previous scope + // ------------------------------------------------ + if (hasBody) { + ctx.addLine(`scope = origScope;`); + ctx.dedent(); + ctx.addLine(`}`); } return true; @@ -275,7 +264,7 @@ QWeb.addDirective({ extraNames: ["as"], priority: 10, atNodeEncounter({ node, qweb, ctx }): boolean { - ctx.rootContext.shouldProtectContext = true; + ctx.rootContext.shouldDefineScope = true; ctx = ctx.subContext("loopNumber", ctx.loopNumber + 1); const elems = node.getAttribute("t-foreach")!; const name = node.getAttribute("t-as")!; @@ -290,14 +279,18 @@ 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});`); const loopVar = `i${ctx.loopNumber}`; ctx.addLine(`for (let ${loopVar} = 0; ${loopVar} < _length${keysID}; ${loopVar}++) {`); ctx.indent(); - ctx.addToScope(name + "_first", `${loopVar} === 0`); - ctx.addToScope(name + "_last", `${loopVar} === _length${keysID} - 1`); - ctx.addToScope(name + "_index", loopVar); - ctx.addToScope(name, `_${keysID}[${loopVar}]`); - ctx.addToScope(name + "_value", `_${valuesID}[${loopVar}]`); + + ctx.addLine(`scope.${name}_first = ${loopVar} === 0`); + ctx.addLine(`scope.${name}_last = ${loopVar} === _length${keysID} - 1`); + ctx.addLine(`scope.${name}_index = ${loopVar}`); + ctx.addLine(`scope.${name} = _${keysID}[${loopVar}]`); + ctx.addLine(`scope.${name}_value = _${valuesID}[${loopVar}]`); const nodeCopy = node.cloneNode(true); let shouldWarn = !nodeCopy.hasAttribute("t-key") && @@ -314,6 +307,7 @@ QWeb.addDirective({ qweb._compileNode(nodeCopy, ctx); ctx.dedent(); ctx.addLine("}"); + ctx.addLine(`scope = _scope${varsID};`); return true; } }); diff --git a/src/qweb/compilation_context.ts b/src/qweb/compilation_context.ts index 8e2b25d2..9d9877eb 100644 --- a/src/qweb/compilation_context.ts +++ b/src/qweb/compilation_context.ts @@ -10,35 +10,27 @@ export class CompilationContext { code: string[] = []; variables: { [key: string]: QWebVar } = {}; escaping: boolean = false; - parentNode: number | null = null; + parentNode: number | null | string = null; parentTextNode: number | null = null; rootNode: number | null = null; indentLevel: number = 0; rootContext: CompilationContext; - caller: Element | undefined; - shouldDefineOwner: boolean = false; shouldDefineParent: boolean = false; + shouldDefineScope: boolean = false; shouldDefineQWeb: boolean = false; shouldDefineUtils: boolean = false; shouldDefineRefs: boolean = false; shouldDefineResult: boolean = true; - shouldProtectContext: boolean = false; - shouldTrackScope: boolean = false; loopNumber: number = 0; inPreTag: boolean = false; templateName: string; allowMultipleRoots: boolean = false; hasParentWidget: boolean = false; - scopeVars: any[] = []; currentKey: string = ""; - templates: { [key: string]: boolean } = {}; - callingLevel: number = 0; - inliningLevel: number = 0; constructor(name?: string) { this.rootContext = this; this.templateName = name || "noname"; - this.templates[this.templateName] = true; this.addLine("var h = this.h;"); } @@ -71,30 +63,16 @@ export class CompilationContext { } generateCode(): string[] { - const shouldTrackScope = this.shouldTrackScope && this.scopeVars.length; - if (shouldTrackScope) { - // add some vars to scope if needed - for (let scopeVar of this.scopeVars.reverse()) { - let { index, key, indent } = scopeVar; - const prefix = new Array(indent + 2).join(" "); - this.code.splice(index + 1, 0, prefix + `scope.${key} = context.${key};`); - } - this.code.unshift(" const scope = Object.create(null);"); - } - if (this.shouldProtectContext) { - this.code.unshift(" context = Object.create(context);"); - } if (this.shouldDefineResult) { this.code.unshift(" let result;"); } + + if (this.shouldDefineScope) { + this.code.unshift(" let scope = Object.create(context);"); + } if (this.shouldDefineRefs) { this.code.unshift(" context.__owl__.refs = context.__owl__.refs || {};"); } - if (this.shouldDefineOwner) { - // this is necessary to prevent some directives (t-forach for ex) to - // pollute the rendering context by adding some keys in it. - this.code.unshift(" let owner = context;"); - } if (this.shouldDefineParent) { if (this.hasParentWidget) { this.code.unshift(" let parent = extra.parent;"); @@ -131,10 +109,6 @@ export class CompilationContext { subContext(key: keyof CompilationContext, value: any): CompilationContext { const newContext = Object.create(this); newContext[key] = value; - if (key === "caller") { - newContext.callingLevel++; - newContext.inliningLevel++; - } return newContext; } @@ -152,11 +126,6 @@ export class CompilationContext { return this.code.length - 1; } - addToScope(key: string, expr: string) { - const index = this.addLine(`context.${key} = ${expr};`); - this.rootContext.scopeVars.push({ index, key, indent: this.indentLevel }); - } - addIf(condition: string) { this.addLine(`if (${condition}) {`); this.indent(); @@ -172,27 +141,6 @@ export class CompilationContext { this.dedent(); this.addLine("}"); } - /** - * Recursively (inverse) fetches the `caller` of a context - * Useful to determine to which t-call a t-raw="0" refers - */ - getCaller(targetLevel?: number): Element | null { - if (targetLevel === undefined) { - targetLevel = this.inliningLevel; - } - if (targetLevel === this.callingLevel) { - return this.caller || null; - } - const proto = (this as any).__proto__; - return proto ? proto.getCaller(targetLevel) : null; - } - /** - * Marks the context with the current recursive level - * in which we are for inlining archs (t-raw="0") - */ - getInliningContext(): CompilationContext { - return this.subContext("inliningLevel", this.inliningLevel - 1); - } getValue(val: any): QWebVar | string { return val in this.variables ? this.getValue(this.variables[val]) : val; @@ -205,6 +153,7 @@ export class CompilationContext { * - replace already defined variables by their internal name */ formatExpression(expr: string): string { + this.rootContext.shouldDefineScope = true; return compileExpr(expr, this.variables); } diff --git a/src/qweb/expression_parser.ts b/src/qweb/expression_parser.ts index 9fd8dd19..ef07a1da 100644 --- a/src/qweb/expression_parser.ts +++ b/src/qweb/expression_parser.ts @@ -39,9 +39,9 @@ const WORD_REPLACEMENT = { }; export interface QWebVar { - id?: string; - expr?: string; - xml?: NodeList; + id: string; // foo + expr: string; // scope.foo (local variables => only foo) + value?: string; // 1 + 3 } //------------------------------------------------------------------------------ @@ -233,8 +233,8 @@ export function tokenize(expr: string): Token[] { * the arrow operator, then we add the current (or some previous tokens) token to * the list of variables so it does not get replaced by a lookup in the context */ -export function compileExpr(expr: string, vars: { [key: string]: QWebVar }): string { - vars = Object.create(vars); +export function compileExpr(expr: string, scope: { [key: string]: QWebVar }): string { + scope = Object.create(scope); const tokens = tokenize(expr); for (let i = 0; i < tokens.length; i++) { let token = tokens[i]; @@ -258,21 +258,21 @@ export function compileExpr(expr: string, vars: { [key: string]: QWebVar }): str while (j > 0 && tokens[j].type !== "LEFT_PAREN") { if (tokens[j].type === "SYMBOL" && tokens[j].originalValue) { tokens[j].value = tokens[j].originalValue!; - vars[tokens[j].value] = { id: tokens[j].value }; + scope[tokens[j].value] = { id: tokens[j].value, expr: tokens[j].value }; } j--; } } else { - vars[token.value] = { id: token.value }; + scope[token.value] = { id: token.value, expr: token.value }; } } if (isVar) { - if (token.value in vars && "id" in vars[token.value]) { - token.value = vars[token.value].id!; + if (token.value in scope && "id" in scope[token.value]) { + token.value = scope[token.value].expr!; } else { token.originalValue = token.value; - token.value = `context['${token.value}']`; + token.value = `scope['${token.value}']`; } } } diff --git a/src/qweb/extensions.ts b/src/qweb/extensions.ts index 7b99ff66..0dab24f0 100644 --- a/src/qweb/extensions.ts +++ b/src/qweb/extensions.ts @@ -30,7 +30,6 @@ QWeb.addDirective({ name: "on", priority: 90, atNodeCreation({ ctx, fullName, value, nodeID }) { - ctx.rootContext.shouldDefineOwner = true; const [eventName, ...mods] = fullName.slice(5).split("."); if (!eventName) { throw new Error("Missing event name with t-on directive"); @@ -40,7 +39,7 @@ QWeb.addDirective({ extraArgs = args.slice(1, -1); return ""; }); - let params = extraArgs ? `owner, ${ctx.formatExpression(extraArgs)}` : "owner"; + let params = extraArgs ? `context, ${ctx.formatExpression(extraArgs)}` : "context"; let handler = `function (e) {if (!context.__owl__.isMounted){return}`; handler += mods .map(function(mod) { @@ -197,7 +196,6 @@ QWeb.addDirective({ priority: 80, atNodeEncounter({ ctx, value }): boolean { const slotKey = ctx.generateID(); - ctx.rootContext.shouldDefineOwner = true; ctx.addLine( `const slot${slotKey} = this.constructor.slots[context.__owl__.slotId + '_' + '${value}'];` ); @@ -210,11 +208,8 @@ QWeb.addDirective({ ctx.addLine(`let ${parentNode}= []`); ctx.addLine(`result = {}`); } - // if we are in a slot of a component, we need to get the vars from the - // parent fiber instead. - const vars = ctx.allowMultipleRoots ? "extra.fiber.parent.vars" : "extra.fiber.vars"; ctx.addLine( - `slot${slotKey}.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: ${parentNode}, parent: extra.parent || owner, vars: ${vars}}));` + `slot${slotKey}.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: ${parentNode}, parent: extra.parent || context}));` ); if (!ctx.parentNode) { ctx.addLine(`utils.defineProxy(result, ${parentNode}[0]);`); diff --git a/src/qweb/qweb.ts b/src/qweb/qweb.ts index 3afc4b96..0e3a527f 100644 --- a/src/qweb/qweb.ts +++ b/src/qweb/qweb.ts @@ -87,6 +87,7 @@ interface Utils { } const UTILS: Utils = { + zero: Symbol('zero'), toObj(expr) { if (typeof expr === "string") { expr = expr.trim(); @@ -171,7 +172,7 @@ export class QWeb extends EventBus { // recursiveTemplates contains sub templates called with t-call, but which // ends up in recursive situations. This is very similar to the slot situation, // as in we need to propagate the scope. - recursiveFns = {}; + subTemplates = {}; isUpdating: boolean = false; translateFn?: QWebConfig["translateFn"]; @@ -360,23 +361,12 @@ export class QWeb extends EventBus { ctx.shouldDefineResult = false; } if (parentContext) { - ctx.templates = Object.create(parentContext.templates); ctx.variables = Object.create(parentContext.variables); ctx.parentNode = parentContext.parentNode || ctx.generateID(); ctx.allowMultipleRoots = true; ctx.hasParentWidget = true; ctx.shouldDefineResult = false; ctx.addLine(`let c${ctx.parentNode} = extra.parentNode;`); - - for (let v in parentContext.variables) { - let variable = parentContext.variables[v]; - if (variable.id) { - ctx.addLine(`let ${variable.id} = extra.vars.${variable.id};`); - } - } - } - if (parentContext) { - ctx.addLine("Object.assign(context, extra.fiber.scope);"); } this._compileNode(elem, ctx); @@ -673,7 +663,7 @@ export class QWeb extends EventBus { if (name.startsWith("t-att-")) { let attName = name.slice(6); const v = ctx.getValue(value); - let formattedValue = typeof v === "string" ? ctx.formatExpression(v) : v.id; + let formattedValue = typeof v === "string" ? ctx.formatExpression(v) : `scope.${v.id}`; if (attName === "class") { ctx.rootContext.shouldDefineUtils = true; diff --git a/tests/__snapshots__/animations.test.ts.snap b/tests/__snapshots__/animations.test.ts.snap index 7ad1555d..78fc50ce 100644 --- a/tests/__snapshots__/animations.test.ts.snap +++ b/tests/__snapshots__/animations.test.ts.snap @@ -7,7 +7,7 @@ exports[`animations t-transition combined with component 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -20,18 +20,18 @@ exports[`animations t-transition combined with component 1`] = ` w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`Child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['Child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['Child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); const __patch2 = w2.__patch; w2.__patch = fiber => {__patch2.call(w2, fiber); if(!w2.__owl__.transitionInserted){w2.__owl__.transitionInserted = true;utils.transitionInsert(w2.__owl__.vnode, 'chimay');}}; parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {let finalize = () => { w2.destroy(); }; @@ -52,11 +52,11 @@ exports[`animations t-transition combined with t-component and t-if 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - if (context['state'].display) { + if (scope['state'].display) { //COMPONENT let k3 = \`__4__\`; let w2 = k3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k3]] : false; @@ -66,18 +66,18 @@ exports[`animations t-transition combined with t-component and t-if 1`] = ` w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`Child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['Child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['Child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); const __patch2 = w2.__patch; w2.__patch = fiber => {__patch2.call(w2, fiber); if(!w2.__owl__.transitionInserted){w2.__owl__.transitionInserted = true;utils.transitionInsert(w2.__owl__.vnode, 'chimay');}}; parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {let finalize = () => { w2.destroy(); }; @@ -99,11 +99,11 @@ exports[`animations t-transition combined with t-component, remove and re-add be let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - if (context['state'].flag) { + if (scope['state'].flag) { //COMPONENT let k3 = \`__4__\`; let w2 = k3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k3]] : false; @@ -113,18 +113,18 @@ exports[`animations t-transition combined with t-component, remove and re-add be w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`Child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['Child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['Child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); const __patch2 = w2.__patch; w2.__patch = fiber => {__patch2.call(w2, fiber); if(!w2.__owl__.transitionInserted){w2.__owl__.transitionInserted = true;utils.transitionInsert(w2.__owl__.vnode, 'chimay');}}; parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {let finalize = () => { w2.destroy(); }; diff --git a/tests/component/__snapshots__/component.test.ts.snap b/tests/component/__snapshots__/component.test.ts.snap index 95963b03..f9e53c5e 100644 --- a/tests/component/__snapshots__/component.test.ts.snap +++ b/tests/component/__snapshots__/component.test.ts.snap @@ -7,12 +7,11 @@ exports[`basic widget properties reconciliation alg works for t-foreach in t-for let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['state'].s; + var _2 = scope['state'].s; if (!_2) { throw new Error('QWeb error: Invalid loop expression')} var _3 = _4 = _2; if (!(_2 instanceof Array)) { @@ -20,52 +19,58 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.section_first = i1 === 0; - context.section_last = i1 === _length3 - 1; - context.section_index = i1; - context.section = _3[i1]; - context.section_value = _4[i1]; - var _5 = context['section'].blips; - if (!_5) { throw new Error('QWeb error: Invalid loop expression')} - var _6 = _7 = _5; - if (!(_5 instanceof Array)) { - _6 = Object.keys(_5); - _7 = Object.values(_5); + scope.section_first = i1 === 0 + scope.section_last = i1 === _length3 - 1 + scope.section_index = i1 + scope.section = _3[i1] + scope.section_value = _4[i1] + var _6 = scope['section'].blips; + if (!_6) { throw new Error('QWeb error: Invalid loop expression')} + var _7 = _8 = _6; + if (!(_6 instanceof Array)) { + _7 = Object.keys(_6); + _8 = Object.values(_6); } - var _length6 = _6.length; - for (let i2 = 0; i2 < _length6; i2++) { - context.blip_first = i2 === 0; - context.blip_last = i2 === _length6 - 1; - context.blip_index = i2; - context.blip = _6[i2]; - context.blip_value = _7[i2]; + var _length7 = _7.length; + let _scope9 = scope; + scope = Object.assign(Object.create(context), _scope9); + for (let i2 = 0; i2 < _length7; i2++) { + scope.blip_first = i2 === 0 + scope.blip_last = i2 === _length7 - 1 + scope.blip_index = i2 + scope.blip = _7[i2] + scope.blip_value = _8[i2] //COMPONENT - let k9 = \`__10__\${i1}__\${i2}__\`; - let w8 = k9 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k9]] : false; - let props8 = {blip:context['blip']}; - if (w8 && w8.__owl__.currentFiber && !w8.__owl__.vnode) { - w8.destroy(); - w8 = false; + let k11 = \`__12__\${i1}__\${i2}__\`; + let w10 = k11 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k11]] : false; + let props10 = {blip:scope['blip']}; + if (w10 && w10.__owl__.currentFiber && !w10.__owl__.vnode) { + w10.destroy(); + w10 = false; } - if (w8) { - w8.__updateProps(props8, extra.fiber, undefined, undefined); - let pvnode = w8.__owl__.pvnode; + if (w10) { + w10.__updateProps(props10, extra.fiber, undefined); + let pvnode = w10.__owl__.pvnode; c1.push(pvnode); } else { - let componentKey8 = \`Child\`; - let W8 = context.constructor.components[componentKey8] || QWeb.components[componentKey8]|| context['Child']; - if (!W8) {throw new Error('Cannot find the definition of component \\"' + componentKey8 + '\\"')} - w8 = new W8(parent, props8); - parent.__owl__.cmap[k9] = w8.__owl__.id; - let fiber = w8.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); - let pvnode = h('dummy', {key: k9, hook: {remove() {},destroy(vn) {w8.destroy();}}}); + let componentKey10 = \`Child\`; + let W10 = context.constructor.components[componentKey10] || QWeb.components[componentKey10]|| scope['Child']; + if (!W10) {throw new Error('Cannot find the definition of component \\"' + componentKey10 + '\\"')} + w10 = new W10(parent, props10); + parent.__owl__.cmap[k11] = w10.__owl__.id; + let fiber = w10.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let pvnode = h('dummy', {key: k11, hook: {remove() {},destroy(vn) {w10.destroy();}}}); c1.push(pvnode); - w8.__owl__.pvnode = pvnode; + w10.__owl__.pvnode = pvnode; } - w8.__owl__.parentLastFiberId = extra.fiber.id; + w10.__owl__.parentLastFiberId = extra.fiber.id; } + scope = _scope9; } + scope = _scope5; return vn1; }" `; @@ -77,7 +82,7 @@ exports[`basic widget properties t-key on a component with t-if, and a sibling c let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -92,16 +97,16 @@ exports[`basic widget properties t-key on a component with t-if, and a sibling c w3 = false; } if (w3) { - w3.__updateProps(props3, extra.fiber, undefined, undefined); + w3.__updateProps(props3, extra.fiber, undefined); let pvnode = w3.__owl__.pvnode; c1.push(pvnode); } else { let componentKey3 = \`Child\`; - let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| context['Child']; + let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| scope['Child']; if (!W3) {throw new Error('Cannot find the definition of component \\"' + componentKey3 + '\\"')} w3 = new W3(parent, props3); parent.__owl__.cmap[k4] = w3.__owl__.id; - let fiber = w3.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w3.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k4, hook: {remove() {},destroy(vn) {w3.destroy();}}}); c1.push(pvnode); w3.__owl__.pvnode = pvnode; @@ -117,16 +122,16 @@ exports[`basic widget properties t-key on a component with t-if, and a sibling c w6 = false; } if (w6) { - w6.__updateProps(props6, extra.fiber, undefined, undefined); + w6.__updateProps(props6, extra.fiber, undefined); let pvnode = w6.__owl__.pvnode; c1.push(pvnode); } else { let componentKey6 = \`Child\`; - let W6 = context.constructor.components[componentKey6] || QWeb.components[componentKey6]|| context['Child']; + let W6 = context.constructor.components[componentKey6] || QWeb.components[componentKey6]|| scope['Child']; if (!W6) {throw new Error('Cannot find the definition of component \\"' + componentKey6 + '\\"')} w6 = new W6(parent, props6); parent.__owl__.cmap[k7] = w6.__owl__.id; - let fiber = w6.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w6.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k7, hook: {remove() {},destroy(vn) {w6.destroy();}}}); c1.push(pvnode); w6.__owl__.pvnode = pvnode; @@ -143,13 +148,13 @@ exports[`class and style attributes with t-component dynamic t-att-style is prop let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); //COMPONENT let k3 = \`__4__\`; - const _5 = context['state'].style; + const _5 = scope['state'].style; let w2 = k3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k3]] : false; let props2 = {}; if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) { @@ -157,16 +162,16 @@ exports[`class and style attributes with t-component dynamic t-att-style is prop w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined).then(()=>{if (w2.__owl__.isDestroyed) {return};w2.el.style=_5;});; + w2.__updateProps(props2, extra.fiber, undefined).then(()=>{if (w2.__owl__.isDestroyed) {return};w2.el.style=_5;});; let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.style = _5;}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.style = _5;}};}); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -183,8 +188,8 @@ exports[`class and style attributes with t-component t-att-class is properly add let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; context.__owl__.refs = context.__owl__.refs || {}; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -192,7 +197,7 @@ exports[`class and style attributes with t-component t-att-class is properly add let k3 = \`__4__\`; const ref5 = \`child\`; let _6 = {'a':true}; - Object.assign(_6, {b:context['state'].b}) + Object.assign(_6, {b:scope['state'].b}) let w2 = k3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k3]] : false; let props2 = {}; if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) { @@ -200,16 +205,16 @@ exports[`class and style attributes with t-component t-att-class is properly add w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`Child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['Child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['Child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){}};}); let pvnode = h('dummy', {key: k3, hook: {insert(vn) {context.__owl__.refs[ref5] = w2;},remove() {},destroy(vn) {w2.destroy();delete context.__owl__.refs[ref5];}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -225,9 +230,10 @@ exports[`class and style attributes with t-component t-att-class is properly add ) { // Template name: \\"Child\\" let utils = this.constructor.utils; + let scope = Object.create(context); var h = this.h; let _8 = {'c':true}; - Object.assign(_8, utils.toObj({d:context['state'].d})) + Object.assign(_8, utils.toObj({d:scope['state'].d})) let c9 = [], p9 = {key:9,class:_8}; var vn9 = h('span', p9, c9); return vn9; @@ -241,8 +247,8 @@ exports[`class and style attributes with t-component t-att-class is properly add let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; context.__owl__.refs = context.__owl__.refs || {}; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -250,7 +256,7 @@ exports[`class and style attributes with t-component t-att-class is properly add let k3 = \`__4__\`; const ref5 = \`child\`; let _6 = {'a':true}; - Object.assign(_6, utils.toObj(context['state'].b?'b':'')) + Object.assign(_6, utils.toObj(scope['state'].b?'b':'')) let w2 = k3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k3]] : false; let props2 = {}; if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) { @@ -258,16 +264,16 @@ exports[`class and style attributes with t-component t-att-class is properly add w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`Child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['Child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['Child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){}};}); let pvnode = h('dummy', {key: k3, hook: {insert(vn) {context.__owl__.refs[ref5] = w2;},remove() {},destroy(vn) {w2.destroy();delete context.__owl__.refs[ref5];}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -283,9 +289,10 @@ exports[`class and style attributes with t-component t-att-class is properly add ) { // Template name: \\"Child\\" let utils = this.constructor.utils; + let scope = Object.create(context); var h = this.h; let _8 = {'c':true}; - Object.assign(_8, utils.toObj(context['state'].d?'d':'')) + Object.assign(_8, utils.toObj(scope['state'].d?'d':'')) let c9 = [], p9 = {key:9,class:_8}; var vn9 = h('span', p9, c9); return vn9; @@ -299,12 +306,11 @@ exports[`composition sub components with some state rendered in a loop 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['state'].numbers; + var _2 = scope['state'].numbers; if (!_2) { throw new Error('QWeb error: Invalid loop expression')} var _3 = _4 = _2; if (!(_2 instanceof Array)) { @@ -312,38 +318,41 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.number_first = i1 === 0; - context.number_last = i1 === _length3 - 1; - context.number_index = i1; - context.number = _3[i1]; - context.number_value = _4[i1]; - const nodeKey5 = context['number']; + scope.number_first = i1 === 0 + scope.number_last = i1 === _length3 - 1 + scope.number_index = i1 + scope.number = _3[i1] + scope.number_value = _4[i1] + const nodeKey6 = scope['number']; //COMPONENT - let k7 = \`__8__\` + nodeKey5; - let w6 = k7 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k7]] : false; - let props6 = {}; - if (w6 && w6.__owl__.currentFiber && !w6.__owl__.vnode) { - w6.destroy(); - w6 = false; + let k8 = \`__9__\` + nodeKey6; + let w7 = k8 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k8]] : false; + let props7 = {}; + if (w7 && w7.__owl__.currentFiber && !w7.__owl__.vnode) { + w7.destroy(); + w7 = false; } - if (w6) { - w6.__updateProps(props6, extra.fiber, undefined, undefined); - let pvnode = w6.__owl__.pvnode; + if (w7) { + w7.__updateProps(props7, extra.fiber, undefined); + let pvnode = w7.__owl__.pvnode; c1.push(pvnode); } else { - let componentKey6 = \`ChildWidget\`; - let W6 = context.constructor.components[componentKey6] || QWeb.components[componentKey6]|| context['ChildWidget']; - if (!W6) {throw new Error('Cannot find the definition of component \\"' + componentKey6 + '\\"')} - w6 = new W6(parent, props6); - parent.__owl__.cmap[k7] = w6.__owl__.id; - let fiber = w6.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); - let pvnode = h('dummy', {key: k7, hook: {remove() {},destroy(vn) {w6.destroy();}}}); + let componentKey7 = \`ChildWidget\`; + let W7 = context.constructor.components[componentKey7] || QWeb.components[componentKey7]|| scope['ChildWidget']; + if (!W7) {throw new Error('Cannot find the definition of component \\"' + componentKey7 + '\\"')} + w7 = new W7(parent, props7); + parent.__owl__.cmap[k8] = w7.__owl__.id; + let fiber = w7.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let pvnode = h('dummy', {key: k8, hook: {remove() {},destroy(vn) {w7.destroy();}}}); c1.push(pvnode); - w6.__owl__.pvnode = pvnode; + w7.__owl__.pvnode = pvnode; } - w6.__owl__.parentLastFiberId = extra.fiber.id; + w7.__owl__.parentLastFiberId = extra.fiber.id; } + scope = _scope5; return vn1; }" `; @@ -355,7 +364,7 @@ exports[`composition t-component with dynamic value 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -368,16 +377,16 @@ exports[`composition t-component with dynamic value 1`] = ` w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { - let componentKey2 = (context['state'].widget); + let componentKey2 = (scope['state'].widget); let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -394,7 +403,7 @@ exports[`composition t-component with dynamic value 2 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -407,16 +416,16 @@ exports[`composition t-component with dynamic value 2 1`] = ` w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { - let componentKey2 = \`Widget\${context['state'].widget}\`; + let componentKey2 = \`Widget\${scope['state'].widget}\`; let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -433,29 +442,29 @@ exports[`dynamic t-props basic use 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); //COMPONENT let k3 = \`__4__\`; let w2 = k3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k3]] : false; - let props2 = Object.assign({}, context['some'].obj); + let props2 = Object.assign({}, scope['some'].obj); if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) { w2.destroy(); w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`Child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['Child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['Child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -472,11 +481,11 @@ exports[`other directives with t-component t-on with getter as handler 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['state'].counter; + var _2 = scope['state'].counter; if (_2 || _2 === 0) { c1.push({text: _2}); } @@ -489,16 +498,16 @@ exports[`other directives with t-component t-on with getter as handler 1`] = ` w3 = false; } if (w3) { - w3.__updateProps(props3, extra.fiber, undefined, undefined); + w3.__updateProps(props3, extra.fiber, undefined); let pvnode = w3.__owl__.pvnode; c1.push(pvnode); } else { let componentKey3 = \`Child\`; - let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| context['Child']; + let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| scope['Child']; if (!W3) {throw new Error('Cannot find the definition of component \\"' + componentKey3 + '\\"')} w3 = new W3(parent, props3); parent.__owl__.cmap[k4] = w3.__owl__.id; - let fiber = w3.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!owner.__owl__.isMounted){return}const fn = owner['handler'];if (fn) { fn.call(owner, e); } else { owner.handler; }});}};}); + let fiber = w3.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!context.__owl__.isMounted){return}const fn = context['handler'];if (fn) { fn.call(context, e); } else { context.handler; }});}};}); let pvnode = h('dummy', {key: k4, hook: {remove() {},destroy(vn) {w3.destroy();}}}); c1.push(pvnode); w3.__owl__.pvnode = pvnode; @@ -515,7 +524,7 @@ exports[`other directives with t-component t-on with handler bound to argument 1 let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -528,16 +537,16 @@ exports[`other directives with t-component t-on with handler bound to argument 1 w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!owner.__owl__.isMounted){return}const fn = owner['onEv'];if (fn) { fn.call(owner, 3, e); } else { owner.onEv; }});}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!context.__owl__.isMounted){return}const fn = context['onEv'];if (fn) { fn.call(context, 3, e); } else { context.onEv; }});}};}); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -554,7 +563,7 @@ exports[`other directives with t-component t-on with handler bound to empty obje let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -567,16 +576,16 @@ exports[`other directives with t-component t-on with handler bound to empty obje w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!owner.__owl__.isMounted){return}const fn = owner['onEv'];if (fn) { fn.call(owner, {}, e); } else { owner.onEv; }});}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!context.__owl__.isMounted){return}const fn = context['onEv'];if (fn) { fn.call(context, {}, e); } else { context.onEv; }});}};}); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -593,7 +602,7 @@ exports[`other directives with t-component t-on with handler bound to empty obje let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -606,16 +615,16 @@ exports[`other directives with t-component t-on with handler bound to empty obje w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!owner.__owl__.isMounted){return}const fn = owner['onEv'];if (fn) { fn.call(owner, {}, e); } else { owner.onEv; }});}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!context.__owl__.isMounted){return}const fn = context['onEv'];if (fn) { fn.call(context, {}, e); } else { context.onEv; }});}};}); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -632,7 +641,7 @@ exports[`other directives with t-component t-on with handler bound to object 1`] let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -645,16 +654,16 @@ exports[`other directives with t-component t-on with handler bound to object 1`] w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!owner.__owl__.isMounted){return}const fn = owner['onEv'];if (fn) { fn.call(owner, {val:3}, e); } else { owner.onEv; }});}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!context.__owl__.isMounted){return}const fn = context['onEv'];if (fn) { fn.call(context, {val:3}, e); } else { context.onEv; }});}};}); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -671,11 +680,11 @@ exports[`other directives with t-component t-on with inline statement 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['state'].counter; + var _2 = scope['state'].counter; if (_2 || _2 === 0) { c1.push({text: _2}); } @@ -688,16 +697,16 @@ exports[`other directives with t-component t-on with inline statement 1`] = ` w3 = false; } if (w3) { - w3.__updateProps(props3, extra.fiber, undefined, undefined); + w3.__updateProps(props3, extra.fiber, undefined); let pvnode = w3.__owl__.pvnode; c1.push(pvnode); } else { let componentKey3 = \`Child\`; - let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| context['Child']; + let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| scope['Child']; if (!W3) {throw new Error('Cannot find the definition of component \\"' + componentKey3 + '\\"')} w3 = new W3(parent, props3); parent.__owl__.cmap[k4] = w3.__owl__.id; - let fiber = w3.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!owner.__owl__.isMounted){return}const fn = owner['state.counter++'];if (fn) { fn.call(owner, e); } else { owner.state.counter++; }});}};}); + let fiber = w3.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!context.__owl__.isMounted){return}const fn = context['state.counter++'];if (fn) { fn.call(context, e); } else { context.state.counter++; }});}};}); let pvnode = h('dummy', {key: k4, hook: {remove() {},destroy(vn) {w3.destroy();}}}); c1.push(pvnode); w3.__owl__.pvnode = pvnode; @@ -714,7 +723,7 @@ exports[`other directives with t-component t-on with no handler (only modifiers) let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -727,16 +736,16 @@ exports[`other directives with t-component t-on with no handler (only modifiers) w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`ComponentA\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['ComponentA']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['ComponentA']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!owner.__owl__.isMounted){return}const fn = owner['onEv'];if (fn) { fn.call(owner, e); } else { owner.onEv; }});}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!context.__owl__.isMounted){return}const fn = context['onEv'];if (fn) { fn.call(context, e); } else { context.onEv; }});}};}); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -753,7 +762,7 @@ exports[`other directives with t-component t-on with prevent and self modifiers let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -766,16 +775,16 @@ exports[`other directives with t-component t-on with prevent and self modifiers w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`Child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['Child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['Child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!owner.__owl__.isMounted){return}e.preventDefault();if (e.target !== vn.elm) {return}const fn = owner['onEv'];if (fn) { fn.call(owner, e); } else { owner.onEv; }});}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!context.__owl__.isMounted){return}e.preventDefault();if (e.target !== vn.elm) {return}const fn = context['onEv'];if (fn) { fn.call(context, e); } else { context.onEv; }});}};}); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -792,7 +801,7 @@ exports[`other directives with t-component t-on with self and prevent modifiers let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -805,16 +814,16 @@ exports[`other directives with t-component t-on with self and prevent modifiers w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!owner.__owl__.isMounted){return}if (e.target !== vn.elm) {return}e.preventDefault();const fn = owner['onEv'];if (fn) { fn.call(owner, e); } else { owner.onEv; }});}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!context.__owl__.isMounted){return}if (e.target !== vn.elm) {return}e.preventDefault();const fn = context['onEv'];if (fn) { fn.call(context, e); } else { context.onEv; }});}};}); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -831,7 +840,7 @@ exports[`other directives with t-component t-on with self modifier 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -844,16 +853,16 @@ exports[`other directives with t-component t-on with self modifier 1`] = ` w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev-1', function (e) {if(!owner.__owl__.isMounted){return}const fn = owner['onEv1'];if (fn) { fn.call(owner, e); } else { owner.onEv1; }});vn.elm.addEventListener('ev-2', function (e) {if(!owner.__owl__.isMounted){return}if (e.target !== vn.elm) {return}const fn = owner['onEv2'];if (fn) { fn.call(owner, e); } else { owner.onEv2; }});}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev-1', function (e) {if(!context.__owl__.isMounted){return}const fn = context['onEv1'];if (fn) { fn.call(context, e); } else { context.onEv1; }});vn.elm.addEventListener('ev-2', function (e) {if(!context.__owl__.isMounted){return}if (e.target !== vn.elm) {return}const fn = context['onEv2'];if (fn) { fn.call(context, e); } else { context.onEv2; }});}};}); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -870,7 +879,7 @@ exports[`other directives with t-component t-on with stop and/or prevent modifie let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -883,16 +892,16 @@ exports[`other directives with t-component t-on with stop and/or prevent modifie w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev-1', function (e) {if(!owner.__owl__.isMounted){return}e.stopPropagation();const fn = owner['onEv1'];if (fn) { fn.call(owner, e); } else { owner.onEv1; }});vn.elm.addEventListener('ev-2', function (e) {if(!owner.__owl__.isMounted){return}e.preventDefault();const fn = owner['onEv2'];if (fn) { fn.call(owner, e); } else { owner.onEv2; }});vn.elm.addEventListener('ev-3', function (e) {if(!owner.__owl__.isMounted){return}e.stopPropagation();e.preventDefault();const fn = owner['onEv3'];if (fn) { fn.call(owner, e); } else { owner.onEv3; }});}};}); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev-1', function (e) {if(!context.__owl__.isMounted){return}e.stopPropagation();const fn = context['onEv1'];if (fn) { fn.call(context, e); } else { context.onEv1; }});vn.elm.addEventListener('ev-2', function (e) {if(!context.__owl__.isMounted){return}e.preventDefault();const fn = context['onEv2'];if (fn) { fn.call(context, e); } else { context.onEv2; }});vn.elm.addEventListener('ev-3', function (e) {if(!context.__owl__.isMounted){return}e.stopPropagation();e.preventDefault();const fn = context['onEv3'];if (fn) { fn.call(context, e); } else { context.onEv3; }});}};}); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -906,16 +915,11 @@ exports[`random stuff/miscellaneous can inject values in tagged templates 1`] = "function anonymous(context, extra ) { // Template name: \\"__template__2\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - let c2 = [], p2 = {key:2}; - var vn2 = h('span', p2, c2); - c1.push(vn2); - var _3 = context['state'].n; - if (_3 || _3 === 0) { - c2.push({text: _3}); - } + this.subTemplates['__template__1'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1})); return vn1; }" `; @@ -927,7 +931,7 @@ exports[`random stuff/miscellaneous snapshotting compiled code 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -935,22 +939,22 @@ exports[`random stuff/miscellaneous snapshotting compiled code 1`] = ` //COMPONENT let k4 = \`__5__\` + nodeKey2; let w3 = k4 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k4]] : false; - let props3 = {flag:context['state'].flag}; + let props3 = {flag:scope['state'].flag}; if (w3 && w3.__owl__.currentFiber && !w3.__owl__.vnode) { w3.destroy(); w3 = false; } if (w3) { - w3.__updateProps(props3, extra.fiber, undefined, undefined); + w3.__updateProps(props3, extra.fiber, undefined); let pvnode = w3.__owl__.pvnode; c1.push(pvnode); } else { let componentKey3 = \`child\`; - let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| context['child']; + let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| scope['child']; if (!W3) {throw new Error('Cannot find the definition of component \\"' + componentKey3 + '\\"')} w3 = new W3(parent, props3); parent.__owl__.cmap[k4] = w3.__owl__.id; - let fiber = w3.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w3.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k4, hook: {remove() {},destroy(vn) {w3.destroy();}}}); c1.push(pvnode); w3.__owl__.pvnode = pvnode; @@ -967,12 +971,11 @@ exports[`random stuff/miscellaneous t-on with handler bound to dynamic argument let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['items']; + var _2 = scope['items']; if (!_2) { throw new Error('QWeb error: Invalid loop expression')} var _3 = _4 = _2; if (!(_2 instanceof Array)) { @@ -980,39 +983,42 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.item_first = i1 === 0; - context.item_last = i1 === _length3 - 1; - context.item_index = i1; - context.item = _3[i1]; - context.item_value = _4[i1]; - const nodeKey5 = context['item']; + scope.item_first = i1 === 0 + scope.item_last = i1 === _length3 - 1 + scope.item_index = i1 + scope.item = _3[i1] + scope.item_value = _4[i1] + const nodeKey6 = scope['item']; //COMPONENT - let k7 = \`__8__\` + nodeKey5; - let arg9 = context['item']; - let w6 = k7 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k7]] : false; - let props6 = {}; - if (w6 && w6.__owl__.currentFiber && !w6.__owl__.vnode) { - w6.destroy(); - w6 = false; + let k8 = \`__9__\` + nodeKey6; + let arg10 = scope['item']; + let w7 = k8 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k8]] : false; + let props7 = {}; + if (w7 && w7.__owl__.currentFiber && !w7.__owl__.vnode) { + w7.destroy(); + w7 = false; } - if (w6) { - w6.__updateProps(props6, extra.fiber, undefined, undefined); - let pvnode = w6.__owl__.pvnode; + if (w7) { + w7.__updateProps(props7, extra.fiber, undefined); + let pvnode = w7.__owl__.pvnode; c1.push(pvnode); } else { - let componentKey6 = \`Child\`; - let W6 = context.constructor.components[componentKey6] || QWeb.components[componentKey6]|| context['Child']; - if (!W6) {throw new Error('Cannot find the definition of component \\"' + componentKey6 + '\\"')} - w6 = new W6(parent, props6); - parent.__owl__.cmap[k7] = w6.__owl__.id; - let fiber = w6.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!owner.__owl__.isMounted){return}const fn = owner['onEv'];if (fn) { fn.call(owner, arg9, e); } else { owner.onEv; }});}};}); - let pvnode = h('dummy', {key: k7, hook: {remove() {},destroy(vn) {w6.destroy();}}}); + let componentKey7 = \`Child\`; + let W7 = context.constructor.components[componentKey7] || QWeb.components[componentKey7]|| scope['Child']; + if (!W7) {throw new Error('Cannot find the definition of component \\"' + componentKey7 + '\\"')} + w7 = new W7(parent, props7); + parent.__owl__.cmap[k8] = w7.__owl__.id; + let fiber = w7.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; vnode.data.hook = {create(_, vn){vn.elm.addEventListener('ev', function (e) {if(!context.__owl__.isMounted){return}const fn = context['onEv'];if (fn) { fn.call(context, arg10, e); } else { context.onEv; }});}};}); + let pvnode = h('dummy', {key: k8, hook: {remove() {},destroy(vn) {w7.destroy();}}}); c1.push(pvnode); - w6.__owl__.pvnode = pvnode; + w7.__owl__.pvnode = pvnode; } - w6.__owl__.parentLastFiberId = extra.fiber.id; + w7.__owl__.parentLastFiberId = extra.fiber.id; } + scope = _scope5; return vn1; }" `; @@ -1021,13 +1027,14 @@ exports[`t-model directive .lazy modifier 1`] = ` "function anonymous(context, extra ) { // Template name: \\"__template__1\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2,on:{}}; var vn2 = h('input', p2, c2); c1.push(vn2); - let expr2 = context['state']; + let expr2 = scope['state']; let k3 = \`__4__\`; p2.props = {value: expr2.text}; extra.handlers[k3] = extra.handlers[k3] || ((ev) => {expr2.text = ev.target.value}); @@ -1035,7 +1042,7 @@ exports[`t-model directive .lazy modifier 1`] = ` let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); - var _6 = context['state'].text; + var _6 = scope['state'].text; if (_6 || _6 === 0) { c5.push({text: _6}); } @@ -1047,13 +1054,14 @@ exports[`t-model directive basic use, on an input 1`] = ` "function anonymous(context, extra ) { // Template name: \\"__template__1\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2,on:{}}; var vn2 = h('input', p2, c2); c1.push(vn2); - let expr2 = context['state']; + let expr2 = scope['state']; let k3 = \`__4__\`; p2.props = {value: expr2.text}; extra.handlers[k3] = extra.handlers[k3] || ((ev) => {expr2.text = ev.target.value}); @@ -1061,7 +1069,7 @@ exports[`t-model directive basic use, on an input 1`] = ` let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); - var _6 = context['state'].text; + var _6 = scope['state'].text; if (_6 || _6 === 0) { c5.push({text: _6}); } @@ -1073,13 +1081,14 @@ exports[`t-model directive basic use, on another key in component 1`] = ` "function anonymous(context, extra ) { // Template name: \\"SomeComponent\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2,on:{}}; var vn2 = h('input', p2, c2); c1.push(vn2); - let expr2 = context['some']; + let expr2 = scope['some']; let k3 = \`__4__\`; p2.props = {value: expr2.text}; extra.handlers[k3] = extra.handlers[k3] || ((ev) => {expr2.text = ev.target.value}); @@ -1087,7 +1096,7 @@ exports[`t-model directive basic use, on another key in component 1`] = ` let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); - var _6 = context['some'].text; + var _6 = scope['some'].text; if (_6 || _6 === 0) { c5.push({text: _6}); } @@ -1099,11 +1108,11 @@ exports[`t-model directive in a t-foreach 1`] = ` "function anonymous(context, extra ) { // Template name: \\"__template__1\\" - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['state']; + var _2 = scope['state']; if (!_2) { throw new Error('QWeb error: Invalid loop expression')} var _3 = _4 = _2; if (!(_2 instanceof Array)) { @@ -1111,23 +1120,26 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.thing_first = i1 === 0; - context.thing_last = i1 === _length3 - 1; - context.thing_index = i1; - context.thing = _3[i1]; - context.thing_value = _4[i1]; - const nodeKey5 = context['thing'].id; - var _6 = 'checkbox'; - let c7 = [], p7 = {key:nodeKey5,attrs:{type: _6},on:{}}; - var vn7 = h('input', p7, c7); - c1.push(vn7); - let expr7 = context['thing']; - let k8 = \`__9__\` + nodeKey5; - p7.props = {checked: expr7.f}; - extra.handlers[k8] = extra.handlers[k8] || ((ev) => {expr7.f = ev.target.checked}); - p7.on['input'] = extra.handlers[k8]; + scope.thing_first = i1 === 0 + scope.thing_last = i1 === _length3 - 1 + scope.thing_index = i1 + scope.thing = _3[i1] + scope.thing_value = _4[i1] + const nodeKey6 = scope['thing'].id; + var _7 = 'checkbox'; + let c8 = [], p8 = {key:nodeKey6,attrs:{type: _7},on:{}}; + var vn8 = h('input', p8, c8); + c1.push(vn8); + let expr8 = scope['thing']; + let k9 = \`__10__\` + nodeKey6; + p8.props = {checked: expr8.f}; + extra.handlers[k9] = extra.handlers[k9] || ((ev) => {expr8.f = ev.target.checked}); + p8.on['input'] = extra.handlers[k9]; } + scope = _scope5; return vn1; }" `; @@ -1136,13 +1148,14 @@ exports[`t-model directive on a select 1`] = ` "function anonymous(context, extra ) { // Template name: \\"SomeComponent\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2,on:{}}; var vn2 = h('select', p2, c2); c1.push(vn2); - let expr2 = context['state']; + let expr2 = scope['state']; let k3 = \`__4__\`; p2.props = {value: expr2.color}; extra.handlers[k3] = extra.handlers[k3] || ((ev) => {expr2.color = ev.target.value}); @@ -1171,7 +1184,7 @@ exports[`t-model directive on a select 1`] = ` var vn11 = h('span', p11, c11); c1.push(vn11); c11.push({text: \`Choice: \`}); - var _12 = context['state'].color; + var _12 = scope['state'].color; if (_12 || _12 === 0) { c11.push({text: _12}); } @@ -1183,13 +1196,14 @@ exports[`t-model directive on a sub state key 1`] = ` "function anonymous(context, extra ) { // Template name: \\"__template__1\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2,on:{}}; var vn2 = h('input', p2, c2); c1.push(vn2); - let expr2 = context['state'].something; + let expr2 = scope['state'].something; let k3 = \`__4__\`; p2.props = {value: expr2.text}; extra.handlers[k3] = extra.handlers[k3] || ((ev) => {expr2.text = ev.target.value}); @@ -1197,7 +1211,7 @@ exports[`t-model directive on a sub state key 1`] = ` let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); - var _6 = context['state'].something.text; + var _6 = scope['state'].something.text; if (_6 || _6 === 0) { c5.push({text: _6}); } @@ -1209,6 +1223,7 @@ exports[`t-model directive on an input type=radio 1`] = ` "function anonymous(context, extra ) { // Template name: \\"SomeComponent\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -1218,7 +1233,7 @@ exports[`t-model directive on an input type=radio 1`] = ` let c5 = [], p5 = {key:5,attrs:{type: _2,id: _3,value: _4},on:{}}; var vn5 = h('input', p5, c5); c1.push(vn5); - let expr5 = context['state']; + let expr5 = scope['state']; let k6 = \`__7__\`; p5.props = {checked:expr5.choice === 'One'}; extra.handlers[k6] = extra.handlers[k6] || ((ev) => {expr5.choice = ev.target.value}); @@ -1229,7 +1244,7 @@ exports[`t-model directive on an input type=radio 1`] = ` let c11 = [], p11 = {key:11,attrs:{type: _8,id: _9,value: _10},on:{}}; var vn11 = h('input', p11, c11); c1.push(vn11); - let expr11 = context['state']; + let expr11 = scope['state']; let k12 = \`__13__\`; p11.props = {checked:expr11.choice === 'Two'}; extra.handlers[k12] = extra.handlers[k12] || ((ev) => {expr11.choice = ev.target.value}); @@ -1238,7 +1253,7 @@ exports[`t-model directive on an input type=radio 1`] = ` var vn14 = h('span', p14, c14); c1.push(vn14); c14.push({text: \`Choice: \`}); - var _15 = context['state'].choice; + var _15 = scope['state'].choice; if (_15 || _15 === 0) { c14.push({text: _15}); } @@ -1250,6 +1265,7 @@ exports[`t-model directive on an input, type=checkbox 1`] = ` "function anonymous(context, extra ) { // Template name: \\"SomeComponent\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -1257,7 +1273,7 @@ exports[`t-model directive on an input, type=checkbox 1`] = ` let c3 = [], p3 = {key:3,attrs:{type: _2},on:{}}; var vn3 = h('input', p3, c3); c1.push(vn3); - let expr3 = context['state']; + let expr3 = scope['state']; let k4 = \`__5__\`; p3.props = {checked: expr3.flag}; extra.handlers[k4] = extra.handlers[k4] || ((ev) => {expr3.flag = ev.target.checked}); @@ -1265,7 +1281,7 @@ exports[`t-model directive on an input, type=checkbox 1`] = ` let c6 = [], p6 = {key:6}; var vn6 = h('span', p6, c6); c1.push(vn6); - if (context['state'].flag) { + if (scope['state'].flag) { c6.push({text: \`yes\`}); } else { @@ -1282,7 +1298,7 @@ exports[`t-slot directive can define and call slots 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -1295,17 +1311,17 @@ exports[`t-slot directive can define and call slots 1`] = ` w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, {}, undefined); + w2.__updateProps(props2, extra.fiber, Object.assign(Object.create(context), scope)); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`Dialog\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['Dialog']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['Dialog']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; w2.__owl__.slotId = 1; - let fiber = w2.__prepare(extra.fiber, {}, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w2.__prepare(extra.fiber, Object.assign(Object.create(context), scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; @@ -1319,7 +1335,6 @@ exports[`t-slot directive can define and call slots 2`] = ` "function anonymous(context, extra ) { // Template name: \\"Dialog\\" - let owner = context; var h = this.h; let c7 = [], p7 = {key:7}; var vn7 = h('div', p7, c7); @@ -1328,14 +1343,14 @@ exports[`t-slot directive can define and call slots 2`] = ` c7.push(vn8); const slot9 = this.constructor.slots[context.__owl__.slotId + '_' + 'header']; if (slot9) { - slot9.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c8, parent: extra.parent || owner, vars: extra.fiber.vars})); + slot9.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c8, parent: extra.parent || context})); } let c10 = [], p10 = {key:10}; var vn10 = h('div', p10, c10); c7.push(vn10); const slot11 = this.constructor.slots[context.__owl__.slotId + '_' + 'footer']; if (slot11) { - slot11.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c10, parent: extra.parent || owner, vars: extra.fiber.vars})); + slot11.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c10, parent: extra.parent || context})); } return vn7; }" @@ -1347,7 +1362,6 @@ exports[`t-slot directive can define and call slots 3`] = ` // Template name: \\"slot_header_template\\" var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); @@ -1361,7 +1375,6 @@ exports[`t-slot directive can define and call slots 4`] = ` // Template name: \\"slot_footer_template\\" var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); let c6 = [], p6 = {key:6}; var vn6 = h('span', p6, c6); c1.push(vn6); @@ -1375,7 +1388,6 @@ exports[`t-slot directive content is the default slot 1`] = ` // Template name: \\"slot_default_template\\" var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); @@ -1389,7 +1401,6 @@ exports[`t-slot directive default slot work with text nodes 1`] = ` // Template name: \\"slot_default_template\\" var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); c1.push({text: \`sts rocks\`}); }" `; @@ -1400,7 +1411,6 @@ exports[`t-slot directive multiple roots are allowed in a default slot 1`] = ` // Template name: \\"slot_default_template\\" var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); @@ -1418,7 +1428,6 @@ exports[`t-slot directive multiple roots are allowed in a named slot 1`] = ` // Template name: \\"slot_content_template\\" var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); @@ -1434,15 +1443,13 @@ exports[`t-slot directive refs are properly bound in slots 1`] = ` "function anonymous(context, extra ) { // Template name: \\"slot_footer_template\\" - let owner = context; context.__owl__.refs = context.__owl__.refs || {}; var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); let c9 = [], p9 = {key:9,on:{}}; var vn9 = h('button', p9, c9); c1.push(vn9); - extra.handlers['click' + 9] = extra.handlers['click' + 9] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['doSomething'];if (fn) { fn.call(owner, e); } else { context.doSomething; }}; + extra.handlers['click' + 9] = extra.handlers['click' + 9] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['doSomething'];if (fn) { fn.call(context, e); } else { context.doSomething; }}; p9.on['click'] = extra.handlers['click' + 9]; const ref10 = \`myButton\`; p9.hook = { @@ -1461,14 +1468,12 @@ exports[`t-slot directive slots are rendered with proper context 1`] = ` "function anonymous(context, extra ) { // Template name: \\"slot_footer_template\\" - let owner = context; var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); let c9 = [], p9 = {key:9,on:{}}; var vn9 = h('button', p9, c9); c1.push(vn9); - extra.handlers['click' + 9] = extra.handlers['click' + 9] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['doSomething'];if (fn) { fn.call(owner, e); } else { context.doSomething; }}; + extra.handlers['click' + 9] = extra.handlers['click' + 9] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['doSomething'];if (fn) { fn.call(context, e); } else { context.doSomething; }}; p9.on['click'] = extra.handlers['click' + 9]; c9.push({text: \`do something\`}); }" @@ -1478,16 +1483,16 @@ exports[`t-slot directive slots are rendered with proper context, part 2 1`] = ` "function anonymous(context, extra ) { // Template name: \\"Link\\" - let owner = context; + let scope = Object.create(context); var h = this.h; - var _12 = context['props'].to; - let c13 = [], p13 = {key:13,attrs:{href: _12}}; - var vn13 = h('a', p13, c13); - const slot14 = this.constructor.slots[context.__owl__.slotId + '_' + 'default']; - if (slot14) { - slot14.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c13, parent: extra.parent || owner, vars: extra.fiber.vars})); + var _13 = scope['props'].to; + let c14 = [], p14 = {key:14,attrs:{href: _13}}; + var vn14 = h('a', p14, c14); + const slot15 = this.constructor.slots[context.__owl__.slotId + '_' + 'default']; + if (slot15) { + slot15.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c14, parent: extra.parent || context})); } - return vn13; + return vn14; }" `; @@ -1498,16 +1503,14 @@ exports[`t-slot directive slots are rendered with proper context, part 2 2`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; - context = Object.create(context); - const scope = Object.create(null); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2}; var vn2 = h('u', p2, c2); c1.push(vn2); - var _3 = context['state'].users; + var _3 = scope['state'].users; if (!_3) { throw new Error('QWeb error: Invalid loop expression')} var _4 = _5 = _3; if (!(_3 instanceof Array)) { @@ -1515,47 +1518,45 @@ 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); for (let i1 = 0; i1 < _length4; i1++) { - context.user_first = i1 === 0; - scope.user_first = context.user_first; - context.user_last = i1 === _length4 - 1; - scope.user_last = context.user_last; - context.user_index = i1; - scope.user_index = context.user_index; - context.user = _4[i1]; - scope.user = context.user; - context.user_value = _5[i1]; - scope.user_value = context.user_value; - const nodeKey6 = context['user'].id; - let c7 = [], p7 = {key:nodeKey6}; - var vn7 = h('li', p7, c7); - c2.push(vn7); + scope.user_first = i1 === 0 + scope.user_last = i1 === _length4 - 1 + scope.user_index = i1 + scope.user = _4[i1] + scope.user_value = _5[i1] + const nodeKey7 = scope['user'].id; + let c8 = [], p8 = {key:nodeKey7}; + var vn8 = h('li', p8, c8); + c2.push(vn8); //COMPONENT - let k9 = \`__10__\` + nodeKey6; - let w8 = k9 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k9]] : false; - let props8 = {to:'/user/'+context['user'].id}; - if (w8 && w8.__owl__.currentFiber && !w8.__owl__.vnode) { - w8.destroy(); - w8 = false; + let k10 = \`__11__\` + nodeKey7; + let w9 = k10 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k10]] : false; + let props9 = {to:'/user/'+scope['user'].id}; + if (w9 && w9.__owl__.currentFiber && !w9.__owl__.vnode) { + w9.destroy(); + w9 = false; } - if (w8) { - w8.__updateProps(props8, extra.fiber, Object.assign({}, scope), undefined); - let pvnode = w8.__owl__.pvnode; - c7.push(pvnode); + if (w9) { + w9.__updateProps(props9, extra.fiber, Object.assign(Object.create(context), scope)); + let pvnode = w9.__owl__.pvnode; + c8.push(pvnode); } else { - let componentKey8 = \`Link\`; - let W8 = context.constructor.components[componentKey8] || QWeb.components[componentKey8]|| context['Link']; - if (!W8) {throw new Error('Cannot find the definition of component \\"' + componentKey8 + '\\"')} - w8 = new W8(parent, props8); - parent.__owl__.cmap[k9] = w8.__owl__.id; - w8.__owl__.slotId = 1; - let fiber = w8.__prepare(extra.fiber, Object.assign({}, scope), undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); - let pvnode = h('dummy', {key: k9, hook: {remove() {},destroy(vn) {w8.destroy();}}}); - c7.push(pvnode); - w8.__owl__.pvnode = pvnode; + let componentKey9 = \`Link\`; + let W9 = context.constructor.components[componentKey9] || QWeb.components[componentKey9]|| scope['Link']; + if (!W9) {throw new Error('Cannot find the definition of component \\"' + componentKey9 + '\\"')} + w9 = new W9(parent, props9); + parent.__owl__.cmap[k10] = w9.__owl__.id; + w9.__owl__.slotId = 1; + let fiber = w9.__prepare(extra.fiber, Object.assign(Object.create(context), scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let pvnode = h('dummy', {key: k10, hook: {remove() {},destroy(vn) {w9.destroy();}}}); + c8.push(pvnode); + w9.__owl__.pvnode = pvnode; } - w8.__owl__.parentLastFiberId = extra.fiber.id; + w9.__owl__.parentLastFiberId = extra.fiber.id; } + scope = _scope6; return vn1; }" `; @@ -1564,13 +1565,13 @@ exports[`t-slot directive slots are rendered with proper context, part 2 3`] = ` "function anonymous(context, extra ) { // Template name: \\"slot_default_template\\" + let scope = Object.create(context); var h = this.h; - let c7 = extra.parentNode; - Object.assign(context, extra.fiber.scope); - c7.push({text: \`User \`}); - var _11 = context['user'].name; - if (_11 || _11 === 0) { - c7.push({text: _11}); + let c8 = extra.parentNode; + c8.push({text: \`User \`}); + var _12 = scope['user'].name; + if (_12 || _12 === 0) { + c8.push({text: _12}); } }" `; @@ -1579,14 +1580,14 @@ exports[`t-slot directive slots are rendered with proper context, part 3 1`] = ` "function anonymous(context, extra ) { // Template name: \\"Link\\" - let owner = context; + let scope = Object.create(context); var h = this.h; - var _12 = context['props'].to; + var _12 = scope['props'].to; let c13 = [], p13 = {key:13,attrs:{href: _12}}; var vn13 = h('a', p13, c13); const slot14 = this.constructor.slots[context.__owl__.slotId + '_' + 'default']; if (slot14) { - slot14.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c13, parent: extra.parent || owner, vars: extra.fiber.vars})); + slot14.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c13, parent: extra.parent || context})); } return vn13; }" @@ -1599,16 +1600,14 @@ exports[`t-slot directive slots are rendered with proper context, part 3 2`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; - context = Object.create(context); - const scope = Object.create(null); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2}; var vn2 = h('u', p2, c2); c1.push(vn2); - var _3 = context['state'].users; + var _3 = scope['state'].users; if (!_3) { throw new Error('QWeb error: Invalid loop expression')} var _4 = _5 = _3; if (!(_3 instanceof Array)) { @@ -1616,48 +1615,46 @@ 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); for (let i1 = 0; i1 < _length4; i1++) { - context.user_first = i1 === 0; - scope.user_first = context.user_first; - context.user_last = i1 === _length4 - 1; - scope.user_last = context.user_last; - context.user_index = i1; - scope.user_index = context.user_index; - context.user = _4[i1]; - scope.user = context.user; - context.user_value = _5[i1]; - scope.user_value = context.user_value; - const nodeKey6 = context['user'].id; - let c7 = [], p7 = {key:nodeKey6}; - var vn7 = h('li', p7, c7); - c2.push(vn7); - var _8 = 'User '+context['user'].name; + scope.user_first = i1 === 0 + scope.user_last = i1 === _length4 - 1 + scope.user_index = i1 + scope.user = _4[i1] + scope.user_value = _5[i1] + const nodeKey7 = scope['user'].id; + let c8 = [], p8 = {key:nodeKey7}; + var vn8 = h('li', p8, c8); + c2.push(vn8); + scope.userdescr = 'User '+scope['user'].name; //COMPONENT - let k10 = \`__11__\` + nodeKey6; + let k10 = \`__11__\` + nodeKey7; let w9 = k10 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k10]] : false; - let props9 = {to:'/user/'+context['user'].id}; + let props9 = {to:'/user/'+scope['user'].id}; if (w9 && w9.__owl__.currentFiber && !w9.__owl__.vnode) { w9.destroy(); w9 = false; } if (w9) { - w9.__updateProps(props9, extra.fiber, Object.assign({}, scope), {_8}); + w9.__updateProps(props9, extra.fiber, Object.assign(Object.create(context), scope)); let pvnode = w9.__owl__.pvnode; - c7.push(pvnode); + c8.push(pvnode); } else { let componentKey9 = \`Link\`; - let W9 = context.constructor.components[componentKey9] || QWeb.components[componentKey9]|| context['Link']; + let W9 = context.constructor.components[componentKey9] || QWeb.components[componentKey9]|| scope['Link']; if (!W9) {throw new Error('Cannot find the definition of component \\"' + componentKey9 + '\\"')} w9 = new W9(parent, props9); parent.__owl__.cmap[k10] = w9.__owl__.id; w9.__owl__.slotId = 1; - let fiber = w9.__prepare(extra.fiber, Object.assign({}, scope), {_8}, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w9.__prepare(extra.fiber, Object.assign(Object.create(context), scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k10, hook: {remove() {},destroy(vn) {w9.destroy();}}}); - c7.push(pvnode); + c8.push(pvnode); w9.__owl__.pvnode = pvnode; } w9.__owl__.parentLastFiberId = extra.fiber.id; } + scope = _scope6; return vn1; }" `; @@ -1666,12 +1663,11 @@ exports[`t-slot directive slots are rendered with proper context, part 3 3`] = ` "function anonymous(context, extra ) { // Template name: \\"slot_default_template\\" + let scope = Object.create(context); var h = this.h; - let c7 = extra.parentNode; - let _8 = extra.vars._8; - Object.assign(context, extra.fiber.scope); - if (_8 || _8 === 0) { - c7.push({text: _8}); + let c8 = extra.parentNode; + if (scope.userdescr || scope.userdescr === 0) { + c8.push({text: scope.userdescr}); } }" `; @@ -1683,36 +1679,36 @@ exports[`t-slot directive slots are rendered with proper context, part 4 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = 'User '+context['state'].user.name; + scope.userdescr = 'User '+scope['state'].user.name; //COMPONENT - let k4 = \`__5__\`; - let w3 = k4 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k4]] : false; - let props3 = {to:'/user/'+context['state'].user.id}; - if (w3 && w3.__owl__.currentFiber && !w3.__owl__.vnode) { - w3.destroy(); - w3 = false; + let k3 = \`__4__\`; + let w2 = k3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k3]] : false; + let props2 = {to:'/user/'+scope['state'].user.id}; + if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) { + w2.destroy(); + w2 = false; } - if (w3) { - w3.__updateProps(props3, extra.fiber, {}, {_2}); - let pvnode = w3.__owl__.pvnode; + if (w2) { + w2.__updateProps(props2, extra.fiber, Object.assign(Object.create(context), scope)); + let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { - let componentKey3 = \`Link\`; - let W3 = context.constructor.components[componentKey3] || QWeb.components[componentKey3]|| context['Link']; - if (!W3) {throw new Error('Cannot find the definition of component \\"' + componentKey3 + '\\"')} - w3 = new W3(parent, props3); - parent.__owl__.cmap[k4] = w3.__owl__.id; - w3.__owl__.slotId = 1; - let fiber = w3.__prepare(extra.fiber, {}, {_2}, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); - let pvnode = h('dummy', {key: k4, hook: {remove() {},destroy(vn) {w3.destroy();}}}); + let componentKey2 = \`Link\`; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['Link']; + if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} + w2 = new W2(parent, props2); + parent.__owl__.cmap[k3] = w2.__owl__.id; + w2.__owl__.slotId = 1; + let fiber = w2.__prepare(extra.fiber, Object.assign(Object.create(context), scope), () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); - w3.__owl__.pvnode = pvnode; + w2.__owl__.pvnode = pvnode; } - w3.__owl__.parentLastFiberId = extra.fiber.id; + w2.__owl__.parentLastFiberId = extra.fiber.id; return vn1; }" `; @@ -1721,12 +1717,11 @@ exports[`t-slot directive slots are rendered with proper context, part 4 2`] = ` "function anonymous(context, extra ) { // Template name: \\"slot_default_template\\" + let scope = Object.create(context); var h = this.h; let c1 = extra.parentNode; - let _2 = extra.vars._2; - Object.assign(context, extra.fiber.scope); - if (_2 || _2 === 0) { - c1.push({text: _2}); + if (scope.userdescr || scope.userdescr === 0) { + c1.push({text: scope.userdescr}); } }" `; @@ -1736,14 +1731,13 @@ exports[`t-slot directive template can just return a slot 1`] = ` ) { // Template name: \\"__template__2\\" let utils = this.constructor.utils; - let owner = context; let result; var h = this.h; const slot8 = this.constructor.slots[context.__owl__.slotId + '_' + 'default']; if (slot8) { let children9= [] result = {} - slot8.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: children9, parent: extra.parent || owner, vars: extra.fiber.vars})); + slot8.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: children9, parent: extra.parent || context})); utils.defineProxy(result, children9[0]); } return result; @@ -1757,7 +1751,7 @@ exports[`top level sub widgets basic use 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); let result; var h = this.h; //COMPONENT @@ -1771,16 +1765,16 @@ exports[`top level sub widgets basic use 1`] = ` w1 = false; } if (w1) { - w1.__updateProps(props1, extra.fiber, undefined, undefined); + w1.__updateProps(props1, extra.fiber, undefined); let pvnode = w1.__owl__.pvnode; utils.defineProxy(vn4, pvnode); } else { let componentKey1 = \`Child\`; - let W1 = context.constructor.components[componentKey1] || QWeb.components[componentKey1]|| context['Child']; + let W1 = context.constructor.components[componentKey1] || QWeb.components[componentKey1]|| scope['Child']; if (!W1) {throw new Error('Cannot find the definition of component \\"' + componentKey1 + '\\"')} w1 = new W1(parent, props1); parent.__owl__.cmap[k2] = w1.__owl__.id; - let fiber = w1.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w1.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k2, hook: {remove() {},destroy(vn) {w1.destroy();}}}); utils.defineProxy(vn4, pvnode); w1.__owl__.pvnode = pvnode; @@ -1797,10 +1791,10 @@ exports[`top level sub widgets can select a sub widget 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); let result; var h = this.h; - if (context['env'].flag) { + if (scope['env'].flag) { //COMPONENT let k2 = \`__3__\`; let w1 = k2 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k2]] : false; @@ -1812,23 +1806,23 @@ exports[`top level sub widgets can select a sub widget 1`] = ` w1 = false; } if (w1) { - w1.__updateProps(props1, extra.fiber, undefined, undefined); + w1.__updateProps(props1, extra.fiber, undefined); let pvnode = w1.__owl__.pvnode; utils.defineProxy(vn4, pvnode); } else { let componentKey1 = \`Child\`; - let W1 = context.constructor.components[componentKey1] || QWeb.components[componentKey1]|| context['Child']; + let W1 = context.constructor.components[componentKey1] || QWeb.components[componentKey1]|| scope['Child']; if (!W1) {throw new Error('Cannot find the definition of component \\"' + componentKey1 + '\\"')} w1 = new W1(parent, props1); parent.__owl__.cmap[k2] = w1.__owl__.id; - let fiber = w1.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w1.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k2, hook: {remove() {},destroy(vn) {w1.destroy();}}}); utils.defineProxy(vn4, pvnode); w1.__owl__.pvnode = pvnode; } w1.__owl__.parentLastFiberId = extra.fiber.id; } - if (!context['env'].flag) { + if (!scope['env'].flag) { //COMPONENT let k6 = \`__7__\`; let w5 = k6 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k6]] : false; @@ -1840,16 +1834,16 @@ exports[`top level sub widgets can select a sub widget 1`] = ` w5 = false; } if (w5) { - w5.__updateProps(props5, extra.fiber, undefined, undefined); + w5.__updateProps(props5, extra.fiber, undefined); let pvnode = w5.__owl__.pvnode; utils.defineProxy(vn8, pvnode); } else { let componentKey5 = \`OtherChild\`; - let W5 = context.constructor.components[componentKey5] || QWeb.components[componentKey5]|| context['OtherChild']; + let W5 = context.constructor.components[componentKey5] || QWeb.components[componentKey5]|| scope['OtherChild']; if (!W5) {throw new Error('Cannot find the definition of component \\"' + componentKey5 + '\\"')} w5 = new W5(parent, props5); parent.__owl__.cmap[k6] = w5.__owl__.id; - let fiber = w5.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w5.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k6, hook: {remove() {},destroy(vn) {w5.destroy();}}}); utils.defineProxy(vn8, pvnode); w5.__owl__.pvnode = pvnode; diff --git a/tests/component/__snapshots__/props_validation.test.ts.snap b/tests/component/__snapshots__/props_validation.test.ts.snap index ef724cb8..708e4a0a 100644 --- a/tests/component/__snapshots__/props_validation.test.ts.snap +++ b/tests/component/__snapshots__/props_validation.test.ts.snap @@ -7,7 +7,7 @@ exports[`props validation props are validated in dev mode (code snapshot) 1`] = let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -20,16 +20,16 @@ exports[`props validation props are validated in dev mode (code snapshot) 1`] = w2 = false; } if (w2) { - w2.__updateProps(props2, extra.fiber, undefined, undefined); + w2.__updateProps(props2, extra.fiber, undefined); let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { let componentKey2 = \`Child\`; - let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| context['Child']; + let W2 = context.constructor.components[componentKey2] || QWeb.components[componentKey2]|| scope['Child']; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); parent.__owl__.cmap[k3] = w2.__owl__.id; - let fiber = w2.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; diff --git a/tests/component/component.test.ts b/tests/component/component.test.ts index 6fa577aa..6db797b0 100644 --- a/tests/component/component.test.ts +++ b/tests/component/component.test.ts @@ -4586,6 +4586,159 @@ describe("t-slot directive", () => { expect(fixture.innerHTML).toBe("
B0B1
"); }); + test("nested slots in same template", async () => { + let child, child2, child3; + class Child extends Widget { + static template = xml` + +
+ +
+
`; + constructor(parent, props) { + super(parent, props); + child = this; + } + } + class Child2 extends Widget { + static template = xml` + + + `; + constructor(parent, props) { + super(parent, props); + child2 = this; + } + } + class Child3 extends Widget { + static template = xml` + Child 3`; + constructor(parent, props) { + super(parent, props); + child3 = this; + } + } + class Parent extends Widget { + static components = { Child, Child2, Child3 }; + static template = xml` + + + + + + + `; + } + + const widget = new Parent(); + await widget.mount(fixture); + expect(fixture.innerHTML).toBe( + '
Child 3
' + ); + + expect(child3.__owl__.parent).toStrictEqual(child2); + expect(child2.__owl__.parent).toStrictEqual(child); + expect(child.__owl__.parent).toStrictEqual(widget); + }); + + test("t-slot nested within another slot", async () => { + let portal, modal, child3; + class Child3 extends Widget { + static template = xml` + Child 3`; + constructor(parent, props) { + super(parent, props); + child3 = this; + } + } + class Modal extends Widget { + static template = xml` + + + `; + constructor(parent, props) { + super(parent, props); + modal = this; + } + } + class Portal extends Widget { + static template = xml` + + + `; + constructor(parent, props) { + super(parent, props); + portal = this; + } + } + class Dialog extends Widget { + static components = { Modal, Portal }; + static template = xml` + + + + + + + `; + } + class Parent extends Widget { + static components = { Child3, Dialog }; + static template = xml` + + + + + `; + } + + const widget = new Parent(); + await widget.mount(fixture); + expect(fixture.innerHTML).toBe( + 'Child 3' + ); + + expect(child3.__owl__.parent).toStrictEqual(portal); + expect(portal.__owl__.parent).toStrictEqual(modal); + }); + + test("t-slot supports many instances", async () => { + let child3; + class Child3 extends Widget { + static template = xml` + Child 3`; + constructor(parent, props) { + super(parent, props); + child3 = this; + } + } + class Dialog extends Widget { + static template = xml` + + + `; + } + class Parent extends Widget { + static components = { Child3, Dialog }; + static template = xml` + + + + + `; + state = { lol: "k" }; + } + + const widget = new Parent(); + await widget.mount(fixture); + expect(child3.props.val).toBe("k"); + + const widget_1 = new Parent(); + widget_1.state.lol = "m"; + await widget_1.mount(fixture); + expect(child3.props.val).toBe("m"); + }); + test("slots in slots, with vars", async () => { class B extends Component { static template = xml``; diff --git a/tests/qweb/__snapshots__/qweb.test.ts.snap b/tests/qweb/__snapshots__/qweb.test.ts.snap index 47056def..8058ef09 100644 --- a/tests/qweb/__snapshots__/qweb.test.ts.snap +++ b/tests/qweb/__snapshots__/qweb.test.ts.snap @@ -4,8 +4,9 @@ exports[`attributes class and t-attf-class with ternary operation 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - var _1 = 'hello ' + (context['value']?'world':''); + var _1 = 'hello ' + (scope['value']?'world':''); let c2 = [], p2 = {key:2,attrs:{class: _1}}; var vn2 = h('div', p2, c2); return vn2; @@ -16,8 +17,9 @@ exports[`attributes dynamic attribute falsy variable 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - var _1 = context['value']; + var _1 = scope['value']; let c2 = [], p2 = {key:2,attrs:{foo: _1}}; var vn2 = h('div', p2, c2); return vn2; @@ -28,8 +30,9 @@ exports[`attributes dynamic attribute with a dash 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - var _1 = context['id']; + var _1 = scope['id']; let c2 = [], p2 = {key:2,attrs:{\\"data-action-id\\": _1}}; var vn2 = h('div', p2, c2); return vn2; @@ -40,6 +43,7 @@ exports[`attributes dynamic attributes 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; var _1 = 'bar'; let c2 = [], p2 = {key:2,attrs:{foo: _1}}; @@ -53,8 +57,9 @@ exports[`attributes dynamic class attribute 1`] = ` ) { // Template name: \\"test\\" let utils = this.constructor.utils; + let scope = Object.create(context); var h = this.h; - let _1 = utils.toObj(context['c']); + let _1 = utils.toObj(scope['c']); let c2 = [], p2 = {key:2,class:_1}; var vn2 = h('div', p2, c2); return vn2; @@ -66,8 +71,9 @@ exports[`attributes dynamic empty class attribute 1`] = ` ) { // Template name: \\"test\\" let utils = this.constructor.utils; + let scope = Object.create(context); var h = this.h; - let _1 = utils.toObj(context['c']); + let _1 = utils.toObj(scope['c']); let c2 = [], p2 = {key:2,class:_1}; var vn2 = h('div', p2, c2); return vn2; @@ -78,8 +84,9 @@ exports[`attributes dynamic formatted attributes with a dash 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - var _1 = \`Some text \${context['id']}\`; + var _1 = \`Some text \${scope['id']}\`; let c2 = [], p2 = {key:2,attrs:{\\"aria-label\\": _1}}; var vn2 = h('div', p2, c2); return vn2; @@ -90,8 +97,9 @@ exports[`attributes fixed variable 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - var _1 = context['value']; + var _1 = scope['value']; let c2 = [], p2 = {key:2,attrs:{foo: _1}}; var vn2 = h('div', p2, c2); return vn2; @@ -102,8 +110,9 @@ exports[`attributes format expression 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - var _1 = (context['value']+37); + var _1 = (scope['value']+37); let c2 = [], p2 = {key:2,attrs:{foo: _1}}; var vn2 = h('div', p2, c2); return vn2; @@ -114,8 +123,9 @@ exports[`attributes format expression, other format 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - var _1 = (context['value']+37); + var _1 = (scope['value']+37); let c2 = [], p2 = {key:2,attrs:{foo: _1}}; var vn2 = h('div', p2, c2); return vn2; @@ -138,8 +148,9 @@ exports[`attributes format multiple 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - var _1 = \`a \${context['value1']} is \${context['value2']} of \${context['value3']} ]\`; + var _1 = \`a \${scope['value1']} is \${scope['value2']} of \${scope['value3']} ]\`; let c2 = [], p2 = {key:2,attrs:{foo: _1}}; var vn2 = h('div', p2, c2); return vn2; @@ -150,8 +161,9 @@ exports[`attributes format value 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - var _1 = \`b\${context['value']}r\`; + var _1 = \`b\${scope['value']}r\`; let c2 = [], p2 = {key:2,attrs:{foo: _1}}; var vn2 = h('div', p2, c2); return vn2; @@ -163,14 +175,15 @@ exports[`attributes from object variables set previously 1`] = ` ) { // 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 = {a:'b'}; - let _3 = utils.toObj(_2.a); - let c4 = [], p4 = {key:4,class:_3}; - var vn4 = h('span', p4, c4); - c1.push(vn4); + scope.o = {a:'b'}; + let _2 = utils.toObj(scope.o.a); + let c3 = [], p3 = {key:3,class:_2}; + var vn3 = h('span', p3, c3); + c1.push(vn3); return vn1; }" `; @@ -180,14 +193,15 @@ exports[`attributes from variables set previously 1`] = ` ) { // 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 = 'def'; - let _3 = utils.toObj(_2); - let c4 = [], p4 = {key:4,class:_3}; - var vn4 = h('span', p4, c4); - c1.push(vn4); + scope.abc = 'def'; + let _2 = utils.toObj(scope.abc); + let c3 = [], p3 = {key:3,class:_2}; + var vn3 = h('span', p3, c3); + c1.push(vn3); return vn1; }" `; @@ -196,8 +210,9 @@ exports[`attributes object 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - var _1 = context['value']; + var _1 = scope['value']; let c2 = [], p2 = {key:2,attrs:{}}; if (_1 instanceof Array) { p2.attrs[_1[0]] = _1[1]; @@ -255,9 +270,10 @@ exports[`attributes t-att-class and class should combine together 1`] = ` ) { // Template name: \\"test\\" let utils = this.constructor.utils; + let scope = Object.create(context); var h = this.h; let _2 = {'hello':true}; - Object.assign(_2, utils.toObj(context['value'])) + Object.assign(_2, utils.toObj(scope['value'])) let c3 = [], p3 = {key:3,class:_2}; var vn3 = h('div', p3, c3); return vn3; @@ -269,9 +285,10 @@ exports[`attributes t-att-class with object 1`] = ` ) { // Template name: \\"test\\" let utils = this.constructor.utils; + let scope = Object.create(context); var h = this.h; let _2 = {'static':true}; - Object.assign(_2, utils.toObj({a:context['b'],c:context['d'],e:context['f']})) + Object.assign(_2, utils.toObj({a:scope['b'],c:scope['d'],e:scope['f']})) let c3 = [], p3 = {key:3,class:_2}; var vn3 = h('div', p3, c3); return vn3; @@ -294,6 +311,7 @@ exports[`attributes tuple literal 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; var _1 = ['foo','bar']; let c2 = [], p2 = {key:2,attrs:{}}; @@ -313,8 +331,9 @@ exports[`attributes tuple variable 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - var _1 = context['value']; + var _1 = scope['value']; let c2 = [], p2 = {key:2,attrs:{}}; if (_1 instanceof Array) { p2.attrs[_1[0]] = _1[1]; @@ -332,6 +351,7 @@ exports[`debugging t-debug 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; debugger; let c1 = [], p1 = {key:1}; @@ -351,11 +371,12 @@ exports[`debugging t-log 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = 42; - console.log(_2+3) + scope.foo = 42; + console.log(scope.foo+3) return vn1; }" `; @@ -364,7 +385,7 @@ exports[`foreach does not pollute the rendering context 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -376,17 +397,20 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.item_first = i1 === 0; - context.item_last = i1 === _length3 - 1; - context.item_index = i1; - context.item = _3[i1]; - context.item_value = _4[i1]; - var _5 = context['item']; - if (_5 || _5 === 0) { - c1.push({text: _5}); + scope.item_first = i1 === 0 + scope.item_last = i1 === _length3 - 1 + scope.item_index = i1 + scope.item = _3[i1] + scope.item_value = _4[i1] + var _6 = scope['item']; + if (_6 || _6 === 0) { + c1.push({text: _6}); } } + scope = _scope5; return vn1; }" `; @@ -395,7 +419,7 @@ exports[`foreach iterate on items (on a element node) 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -407,21 +431,24 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.item_first = i1 === 0; - context.item_last = i1 === _length3 - 1; - context.item_index = i1; - context.item = _3[i1]; - context.item_value = _4[i1]; - const nodeKey5 = context['item']; - let c6 = [], p6 = {key:nodeKey5}; - var vn6 = h('span', p6, c6); - c1.push(vn6); - var _7 = context['item']; - if (_7 || _7 === 0) { - c6.push({text: _7}); + scope.item_first = i1 === 0 + scope.item_last = i1 === _length3 - 1 + scope.item_index = i1 + scope.item = _3[i1] + scope.item_value = _4[i1] + const nodeKey6 = scope['item']; + let c7 = [], p7 = {key:nodeKey6}; + var vn7 = h('span', p7, c7); + c1.push(vn7); + var _8 = scope['item']; + if (_8 || _8 === 0) { + c7.push({text: _8}); } } + scope = _scope5; return vn1; }" `; @@ -430,7 +457,7 @@ exports[`foreach iterate on items 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -442,29 +469,32 @@ exports[`foreach iterate on items 1`] = ` _4 = Object.values(_2); } var _length3 = _3.length; + let _scope5 = scope; + scope = Object.assign(Object.create(context), _scope5); for (let i1 = 0; i1 < _length3; i1++) { - context.item_first = i1 === 0; - context.item_last = i1 === _length3 - 1; - context.item_index = i1; - context.item = _3[i1]; - context.item_value = _4[i1]; + scope.item_first = i1 === 0 + scope.item_last = i1 === _length3 - 1 + scope.item_index = i1 + scope.item = _3[i1] + scope.item_value = _4[i1] c1.push({text: \` [\`}); - var _5 = context['item_index']; - if (_5 || _5 === 0) { - c1.push({text: _5}); - } - c1.push({text: \`: \`}); - var _6 = context['item']; + var _6 = scope['item_index']; if (_6 || _6 === 0) { c1.push({text: _6}); } - c1.push({text: \` \`}); - var _7 = context['item_value']; + c1.push({text: \`: \`}); + var _7 = scope['item']; if (_7 || _7 === 0) { c1.push({text: _7}); } + c1.push({text: \` \`}); + var _8 = scope['item_value']; + if (_8 || _8 === 0) { + c1.push({text: _8}); + } c1.push({text: \`] \`}); } + scope = _scope5; return vn1; }" `; @@ -473,11 +503,11 @@ exports[`foreach iterate, dict param 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['value']; + var _2 = scope['value']; if (!_2) { throw new Error('QWeb error: Invalid loop expression')} var _3 = _4 = _2; if (!(_2 instanceof Array)) { @@ -485,29 +515,32 @@ exports[`foreach iterate, dict param 1`] = ` _4 = Object.values(_2); } var _length3 = _3.length; + let _scope5 = scope; + scope = Object.assign(Object.create(context), _scope5); for (let i1 = 0; i1 < _length3; i1++) { - context.item_first = i1 === 0; - context.item_last = i1 === _length3 - 1; - context.item_index = i1; - context.item = _3[i1]; - context.item_value = _4[i1]; + scope.item_first = i1 === 0 + scope.item_last = i1 === _length3 - 1 + scope.item_index = i1 + scope.item = _3[i1] + scope.item_value = _4[i1] c1.push({text: \` [\`}); - var _5 = context['item_index']; - if (_5 || _5 === 0) { - c1.push({text: _5}); - } - c1.push({text: \`: \`}); - var _6 = context['item']; + var _6 = scope['item_index']; if (_6 || _6 === 0) { c1.push({text: _6}); } - c1.push({text: \` \`}); - var _7 = context['item_value']; + c1.push({text: \`: \`}); + var _7 = scope['item']; if (_7 || _7 === 0) { c1.push({text: _7}); } + c1.push({text: \` \`}); + var _8 = scope['item_value']; + if (_8 || _8 === 0) { + c1.push({text: _8}); + } c1.push({text: \`] \`}); } + scope = _scope5; return vn1; }" `; @@ -516,7 +549,7 @@ exports[`foreach iterate, position 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -528,26 +561,29 @@ exports[`foreach iterate, position 1`] = ` _4 = Object.values(_2); } var _length3 = _3.length; + let _scope5 = scope; + scope = Object.assign(Object.create(context), _scope5); for (let i1 = 0; i1 < _length3; i1++) { - context.elem_first = i1 === 0; - context.elem_last = i1 === _length3 - 1; - context.elem_index = i1; - context.elem = _3[i1]; - context.elem_value = _4[i1]; + scope.elem_first = i1 === 0 + scope.elem_last = i1 === _length3 - 1 + scope.elem_index = i1 + scope.elem = _3[i1] + scope.elem_value = _4[i1] c1.push({text: \` -\`}); - if (context['elem_first']) { + if (scope['elem_first']) { c1.push({text: \` first\`}); } - if (context['elem_last']) { + if (scope['elem_last']) { c1.push({text: \` last\`}); } c1.push({text: \` (\`}); - var _5 = context['elem_index']; - if (_5 || _5 === 0) { - c1.push({text: _5}); + var _6 = scope['elem_index']; + if (_6 || _6 === 0) { + c1.push({text: _6}); } c1.push({text: \`) \`}); } + scope = _scope5; return vn1; }" `; @@ -556,11 +592,11 @@ exports[`foreach t-foreach in t-forach 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['numbers']; + var _2 = scope['numbers']; if (!_2) { throw new Error('QWeb error: Invalid loop expression')} var _3 = _4 = _2; if (!(_2 instanceof Array)) { @@ -568,38 +604,44 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.number_first = i1 === 0; - context.number_last = i1 === _length3 - 1; - context.number_index = i1; - context.number = _3[i1]; - context.number_value = _4[i1]; - var _5 = context['letters']; - if (!_5) { throw new Error('QWeb error: Invalid loop expression')} - var _6 = _7 = _5; - if (!(_5 instanceof Array)) { - _6 = Object.keys(_5); - _7 = Object.values(_5); + scope.number_first = i1 === 0 + scope.number_last = i1 === _length3 - 1 + scope.number_index = i1 + scope.number = _3[i1] + scope.number_value = _4[i1] + var _6 = scope['letters']; + if (!_6) { throw new Error('QWeb error: Invalid loop expression')} + var _7 = _8 = _6; + if (!(_6 instanceof Array)) { + _7 = Object.keys(_6); + _8 = Object.values(_6); } - var _length6 = _6.length; - for (let i2 = 0; i2 < _length6; i2++) { - context.letter_first = i2 === 0; - context.letter_last = i2 === _length6 - 1; - context.letter_index = i2; - context.letter = _6[i2]; - context.letter_value = _7[i2]; + var _length7 = _7.length; + let _scope9 = scope; + scope = Object.assign(Object.create(context), _scope9); + for (let i2 = 0; i2 < _length7; i2++) { + scope.letter_first = i2 === 0 + scope.letter_last = i2 === _length7 - 1 + scope.letter_index = i2 + scope.letter = _7[i2] + scope.letter_value = _8[i2] c1.push({text: \` [\`}); - var _8 = context['number']; - if (_8 || _8 === 0) { - c1.push({text: _8}); + var _10 = scope['number']; + if (_10 || _10 === 0) { + c1.push({text: _10}); } - var _9 = context['letter']; - if (_9 || _9 === 0) { - c1.push({text: _9}); + var _11 = scope['letter']; + if (_11 || _11 === 0) { + c1.push({text: _11}); } c1.push({text: \`] \`}); } + scope = _scope9; } + scope = _scope5; return vn1; }" `; @@ -608,7 +650,7 @@ exports[`foreach warn if no key in some case 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -620,20 +662,23 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.item_first = i1 === 0; - context.item_last = i1 === _length3 - 1; - context.item_index = i1; - context.item = _3[i1]; - context.item_value = _4[i1]; - let c5 = [], p5 = {key:5}; - var vn5 = h('span', p5, c5); - c1.push(vn5); - var _6 = context['item']; - if (_6 || _6 === 0) { - c5.push({text: _6}); + scope.item_first = i1 === 0 + scope.item_last = i1 === _length3 - 1 + scope.item_index = i1 + scope.item = _3[i1] + scope.item_value = _4[i1] + let c6 = [], p6 = {key:6}; + var vn6 = h('span', p6, c6); + c1.push(vn6); + var _7 = scope['item']; + if (_7 || _7 === 0) { + c6.push({text: _7}); } } + scope = _scope5; return vn1; }" `; @@ -654,17 +699,11 @@ exports[`loading templates can load a few templates from a xml string 1`] = ` "function anonymous(context, extra ) { // Template name: \\"main\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('ul', p1, c1); - let c2 = [], p2 = {key:2}; - var vn2 = h('li', p2, c2); - c1.push(vn2); - c2.push({text: \`ok\`}); - let c3 = [], p3 = {key:3}; - var vn3 = h('li', p3, c3); - c1.push(vn3); - c3.push({text: \`foo\`}); + this.subTemplates['items'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1})); return vn1; }" `; @@ -674,7 +713,7 @@ exports[`misc global 1`] = ` ) { // Template name: \\"caller\\" let utils = this.constructor.utils; - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -686,65 +725,48 @@ exports[`misc global 1`] = ` _4 = Object.values(_2); } var _length3 = _3.length; + let _scope5 = scope; + scope = Object.assign(Object.create(context), _scope5); for (let i1 = 0; i1 < _length3; i1++) { - context.value_first = i1 === 0; - context.value_last = i1 === _length3 - 1; - context.value_index = i1; - context.value = _3[i1]; - context.value_value = _4[i1]; - let c5 = [], p5 = {key:5}; - var vn5 = h('span', p5, c5); - c1.push(vn5); - var _6 = context['value']; - if (_6 || _6 === 0) { - c5.push({text: _6}); + scope.value_first = i1 === 0 + scope.value_last = i1 === _length3 - 1 + scope.value_index = i1 + scope.value = _3[i1] + scope.value_value = _4[i1] + let c6 = [], p6 = {key:6}; + var vn6 = h('span', p6, c6); + c1.push(vn6); + var _7 = scope['value']; + if (_7 || _7 === 0) { + c6.push({text: _7}); } { - let _11 = 'bbb'; - var _13 = 'agüero'; - let c14 = [], p14 = {key:14,attrs:{\\"falló\\": _13}}; - var vn14 = h('año', p14, c14); - c1.push(vn14); + let origScope = scope; + scope = Object.assign(Object.create(context), scope); { - let _15 = 'aaa'; - let c16 = [], p16 = {key:16}; - var vn16 = h('span', p16, c16); - c14.push(vn16); - if (_15 || _15 === 0) { - c16.push({text: _15}); - } else { - c16.push({text: \`foo default\`}); + let c__0 = []; + { + let origScope = scope; + scope = Object.assign(Object.create(context), scope); + { + let c__0 = []; + scope.foo = 'aaa'; + scope[utils.zero] = c__0; + } + this.subTemplates['_callee-uses-foo'].call(this, scope, Object.assign({}, extra, {parentNode: c__0})); + scope = origScope; } + this.subTemplates['_callee-uses-foo'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c__0})); + 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; } - let c17 = [], p17 = {key:17}; - var vn17 = h('span', p17, c17); - c14.push(vn17); - var _18 = context['foo']; - if (_18 || _18 === 0) { - c17.push({text: _18}); - } else { - c17.push({text: \`foo default\`}); - } - _11 = 'bbb' - let c19 = [], p19 = {key:19}; - var vn19 = h('span', p19, c19); - c14.push(vn19); - if (_11 || _11 === 0) { - c19.push({text: _11}); - } else { - c19.push({text: \`foo default\`}); - } + this.subTemplates['_callee-asc'].call(this, scope, Object.assign({}, extra, {parentNode: c1})); + scope = origScope; } } - let c20 = [], p20 = {key:20}; - var vn20 = h('div', p20, c20); - c1.push(vn20); - var _21 = context['toto']; - if (_21 || _21 === 0) { - c20.push(...utils.htmlToVDOM(_21)); - } else { - c20.push({text: \`toto default\`}); - } + scope = _scope5; + this.subTemplates['_callee-asc-toto'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1})); return vn1; }" `; @@ -801,9 +823,10 @@ exports[`special cases for some boolean html attributes/properties input type= c "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; var _1 = 'checkbox'; - var _2 = context['flag']; + var _2 = scope['flag']; let c3 = [], p3 = {key:3,attrs:{type: _1,checked: _2},props:{checked: _2}}; var vn3 = h('input', p3, c3); return vn3; @@ -932,9 +955,10 @@ exports[`static templates simple dynamic value 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); let result; var h = this.h; - var _1 = context['text']; + var _1 = scope['text']; if (_1 || _1 === 0) { var vn2 = {text: _1}; result = vn2 @@ -959,11 +983,12 @@ exports[`static templates simple string, with some dynamic value 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); let result; var h = this.h; var vn1 = {text: \`hello \`}; result = vn1; - var _2 = context['text']; + var _2 = scope['text']; if (_2 || _2 === 0) { vn1.text += _2; } @@ -975,76 +1000,130 @@ exports[`t-call (template calling basic caller 1`] = ` "function anonymous(context, extra ) { // Template name: \\"caller\\" - let result; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - result = vn1; - c1.push({text: \`ok\`}); + this.subTemplates['_basic-callee'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1})); + return vn1; +}" +`; + +exports[`t-call (template calling basic caller 2`] = ` +"function anonymous(context, extra +) { + // Template name: \\"_basic-callee\\" + var h = this.h; + let c1 = extra.parentNode; + let c2 = [], p2 = {key:2}; + var vn2 = h('span', p2, c2); + c1.push(vn2); + c2.push({text: \`ok\`}); +}" +`; + +exports[`t-call (template calling basic caller, no parent node 1`] = ` +"function anonymous(context, extra +) { + // Template name: \\"caller\\" + let scope = Object.create(context); + let result; + var h = this.h; + result = [] + this.subTemplates['_basic-callee'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: result})); + result = result[0] return result; }" `; +exports[`t-call (template calling basic caller, no parent node 2`] = ` +"function anonymous(context, extra +) { + // Template name: \\"_basic-callee\\" + var h = this.h; + let c1 = extra.parentNode; + let c2 = [], p2 = {key:2}; + var vn2 = h('div', p2, c2); + c1.push(vn2); + c2.push({text: \`ok\`}); +}" +`; + exports[`t-call (template calling call with several sub nodes on same line 1`] = ` "function anonymous(context, extra ) { // Template name: \\"main\\" + 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); - let c5 = [], p5 = {key:5}; - var vn5 = h('div', p5, c5); - c1.push(vn5); - let c6 = [], p6 = {key:6}; - var vn6 = h('span', p6, c6); - c5.push(vn6); - c6.push({text: \`hey\`}); - c5.push({text: \` \`}); - let c7 = [], p7 = {key:7}; - var vn7 = h('span', p7, c7); - c5.push(vn7); - c7.push({text: \`yay\`}); + { + let origScope = 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\`}); + scope[utils.zero] = c__0; + } + this.subTemplates['SubTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c1})); + scope = origScope; + } return vn1; }" `; +exports[`t-call (template calling call with several sub nodes on same line 2`] = ` +"function anonymous(context, extra +) { + // Template name: \\"SubTemplate\\" + let utils = this.constructor.utils; + let scope = Object.create(context); + var h = this.h; + let c1 = extra.parentNode; + let c2 = [], p2 = {key:2}; + var vn2 = h('div', p2, c2); + c1.push(vn2); + c2.push(...scope[utils.zero]); +}" +`; + exports[`t-call (template calling cascading t-call t-raw='0' 1`] = ` "function anonymous(context, extra ) { // Template name: \\"main\\" + 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); - let c5 = [], p5 = {key:5}; - var vn5 = h('div', p5, c5); - c1.push(vn5); - let c8 = [], p8 = {key:8}; - var vn8 = h('div', p8, c8); - c5.push(vn8); - let c11 = [], p11 = {key:11}; - var vn11 = h('div', p11, c11); - c8.push(vn11); - let c12 = [], p12 = {key:12}; - var vn12 = h('span', p12, c12); - c11.push(vn12); - c12.push({text: \`cascade 2\`}); - let c13 = [], p13 = {key:13}; - var vn13 = h('span', p13, c13); - c11.push(vn13); - c13.push({text: \`cascade 1\`}); - let c14 = [], p14 = {key:14}; - var vn14 = h('span', p14, c14); - c11.push(vn14); - c14.push({text: \`cascade 0\`}); - let c15 = [], p15 = {key:15}; - var vn15 = h('span', p15, c15); - c11.push(vn15); - c15.push({text: \`hey\`}); - c11.push({text: \` \`}); - let c16 = [], p16 = {key:16}; - var vn16 = h('span', p16, c16); - c11.push(vn16); - c16.push({text: \`yay\`}); + { + let origScope = 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\`}); + c__0.push({text: \` \`}); + let c9 = [], p9 = {key:9}; + var vn9 = h('span', p9, c9); + c__0.push(vn9); + c9.push({text: \`yay\`}); + scope[utils.zero] = c__0; + } + this.subTemplates['SubTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c1})); + scope = origScope; + } return vn1; }" `; @@ -1053,13 +1132,12 @@ exports[`t-call (template calling inherit context 1`] = ` "function anonymous(context, extra ) { // Template name: \\"caller\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = 1; - if (_2 || _2 === 0) { - c1.push({text: _2}); - } + scope.foo = 1; + this.subTemplates['_callee-uses-foo'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1})); return vn1; }" `; @@ -1068,7 +1146,7 @@ exports[`t-call (template calling recursive template, part 1 1`] = ` "function anonymous(context, extra ) { // Template name: \\"recursive\\" - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -1077,7 +1155,7 @@ exports[`t-call (template calling recursive template, part 1 1`] = ` c1.push(vn2); c2.push({text: \`hey\`}); if (false) { - this.recursiveFns['__3'].call(this, context, Object.assign({}, extra, {parentNode: c1, vars: {}, fiber: {scope}})); + this.subTemplates['recursive'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1})); } return vn1; }" @@ -1086,20 +1164,19 @@ exports[`t-call (template calling recursive template, part 1 1`] = ` exports[`t-call (template calling recursive template, part 1 2`] = ` "function anonymous(context, extra ) { - // Template name: \\"__3\\" - let owner = context; + // Template name: \\"recursive\\" + let scope = Object.create(context); var h = this.h; let c1 = extra.parentNode; - Object.assign(context, extra.fiber.scope); + let c3 = [], p3 = {key:3}; + var vn3 = h('div', p3, c3); + c1.push(vn3); let c4 = [], p4 = {key:4}; - var vn4 = h('div', p4, c4); - c1.push(vn4); - let c5 = [], p5 = {key:5}; - var vn5 = h('span', p5, c5); - c4.push(vn5); - c5.push({text: \`hey\`}); + var vn4 = h('span', p4, c4); + c3.push(vn4); + c4.push({text: \`hey\`}); if (false) { - this.recursiveFns['__3'].call(this, context, Object.assign({}, extra, {parentNode: c4, vars: {}, fiber: {scope}})); + this.subTemplates['recursive'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c3})); } }" `; @@ -1108,45 +1185,21 @@ exports[`t-call (template calling recursive template, part 2 1`] = ` "function anonymous(context, extra ) { // Template name: \\"Parent\\" - let owner = context; - context = Object.create(context); - const scope = Object.create(null); + 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); { - let _2 = context['root']; - let c3 = [], p3 = {key:3}; - var vn3 = h('div', p3, c3); - c1.push(vn3); - let c4 = [], p4 = {key:4}; - var vn4 = h('p', p4, c4); - c3.push(vn4); - var _5 = _2.val; - if (_5 || _5 === 0) { - c4.push({text: _5}); - } - var _6 = _2.children||[]; - if (!_6) { throw new Error('QWeb error: Invalid loop expression')} - var _7 = _8 = _6; - if (!(_6 instanceof Array)) { - _7 = Object.keys(_6); - _8 = Object.values(_6); - } - var _length7 = _7.length; - for (let i1 = 0; i1 < _length7; i1++) { - context.subtree_first = i1 === 0; - scope.subtree_first = context.subtree_first; - context.subtree_last = i1 === _length7 - 1; - scope.subtree_last = context.subtree_last; - context.subtree_index = i1; - scope.subtree_index = context.subtree_index; - context.subtree = _7[i1]; - scope.subtree = context.subtree; - context.subtree_value = _8[i1]; - scope.subtree_value = context.subtree_value; - this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c3, vars: {_v0: context['subtree']}, fiber: {scope}})); + let origScope = scope; + scope = Object.assign(Object.create(context), scope); + { + let c__0 = []; + scope.node = scope['root']; + scope[utils.zero] = c__0; } + this.subTemplates['nodeTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c1})); + scope = origScope; } return vn1; }" @@ -1155,45 +1208,50 @@ exports[`t-call (template calling recursive template, part 2 1`] = ` exports[`t-call (template calling recursive template, part 2 2`] = ` "function anonymous(context, extra ) { - // Template name: \\"__10\\" - let owner = context; - context = Object.create(context); - const scope = Object.create(null); + // Template name: \\"nodeTemplate\\" + let utils = this.constructor.utils; + let scope = Object.create(context); var h = this.h; - let c3 = extra.parentNode; - let _v0 = extra.vars._v0; - Object.assign(context, extra.fiber.scope); - let c11 = [], p11 = {key:11}; - var vn11 = h('div', p11, c11); - c3.push(vn11); - let c12 = [], p12 = {key:12}; - var vn12 = h('p', p12, c12); - c11.push(vn12); - var _13 = _v0.val; - if (_13 || _13 === 0) { - c12.push({text: _13}); + let c1 = extra.parentNode; + let c2 = [], p2 = {key:2}; + var vn2 = h('div', p2, c2); + c1.push(vn2); + let c3 = [], p3 = {key:3}; + var vn3 = h('p', p3, c3); + c2.push(vn3); + var _4 = scope['node'].val; + if (_4 || _4 === 0) { + c3.push({text: _4}); } - var _14 = _v0.children||[]; - if (!_14) { throw new Error('QWeb error: Invalid loop expression')} - var _15 = _16 = _14; - if (!(_14 instanceof Array)) { - _15 = Object.keys(_14); - _16 = Object.values(_14); + var _5 = scope['node'].children||[]; + if (!_5) { throw new Error('QWeb error: Invalid loop expression')} + var _6 = _7 = _5; + if (!(_5 instanceof Array)) { + _6 = Object.keys(_5); + _7 = Object.values(_5); } - var _length15 = _15.length; - for (let i1 = 0; i1 < _length15; i1++) { - context.subtree_first = i1 === 0; - scope.subtree_first = context.subtree_first; - context.subtree_last = i1 === _length15 - 1; - scope.subtree_last = context.subtree_last; - context.subtree_index = i1; - scope.subtree_index = context.subtree_index; - context.subtree = _15[i1]; - scope.subtree = context.subtree; - context.subtree_value = _16[i1]; - scope.subtree_value = context.subtree_value; - this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c11, vars: {_v0: context['subtree']}, fiber: {scope}})); + var _length6 = _6.length; + let _scope8 = scope; + scope = Object.assign(Object.create(context), _scope8); + for (let i1 = 0; i1 < _length6; i1++) { + scope.subtree_first = i1 === 0 + scope.subtree_last = i1 === _length6 - 1 + scope.subtree_index = i1 + scope.subtree = _6[i1] + scope.subtree_value = _7[i1] + { + let origScope = scope; + scope = Object.assign(Object.create(context), scope); + { + let c__0 = []; + scope.node = scope['subtree']; + scope[utils.zero] = c__0; + } + this.subTemplates['nodeTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c2})); + scope = origScope; + } } + scope = _scope8; }" `; @@ -1201,45 +1259,21 @@ exports[`t-call (template calling recursive template, part 3 1`] = ` "function anonymous(context, extra ) { // Template name: \\"Parent\\" - let owner = context; - context = Object.create(context); - const scope = Object.create(null); + 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); { - let _2 = context['root']; - let c3 = [], p3 = {key:3}; - var vn3 = h('div', p3, c3); - c1.push(vn3); - let c4 = [], p4 = {key:4}; - var vn4 = h('p', p4, c4); - c3.push(vn4); - var _5 = _2.val; - if (_5 || _5 === 0) { - c4.push({text: _5}); - } - var _6 = _2.children||[]; - if (!_6) { throw new Error('QWeb error: Invalid loop expression')} - var _7 = _8 = _6; - if (!(_6 instanceof Array)) { - _7 = Object.keys(_6); - _8 = Object.values(_6); - } - var _length7 = _7.length; - for (let i1 = 0; i1 < _length7; i1++) { - context.subtree_first = i1 === 0; - scope.subtree_first = context.subtree_first; - context.subtree_last = i1 === _length7 - 1; - scope.subtree_last = context.subtree_last; - context.subtree_index = i1; - scope.subtree_index = context.subtree_index; - context.subtree = _7[i1]; - scope.subtree = context.subtree; - context.subtree_value = _8[i1]; - scope.subtree_value = context.subtree_value; - this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c3, vars: {_v0: context['subtree']}, fiber: {scope}})); + let origScope = scope; + scope = Object.assign(Object.create(context), scope); + { + let c__0 = []; + scope.node = scope['root']; + scope[utils.zero] = c__0; } + this.subTemplates['nodeTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c1})); + scope = origScope; } return vn1; }" @@ -1248,45 +1282,50 @@ exports[`t-call (template calling recursive template, part 3 1`] = ` exports[`t-call (template calling recursive template, part 3 2`] = ` "function anonymous(context, extra ) { - // Template name: \\"__10\\" - let owner = context; - context = Object.create(context); - const scope = Object.create(null); + // Template name: \\"nodeTemplate\\" + let utils = this.constructor.utils; + let scope = Object.create(context); var h = this.h; - let c3 = extra.parentNode; - let _v0 = extra.vars._v0; - Object.assign(context, extra.fiber.scope); - let c11 = [], p11 = {key:11}; - var vn11 = h('div', p11, c11); - c3.push(vn11); - let c12 = [], p12 = {key:12}; - var vn12 = h('p', p12, c12); - c11.push(vn12); - var _13 = _v0.val; - if (_13 || _13 === 0) { - c12.push({text: _13}); + let c1 = extra.parentNode; + let c2 = [], p2 = {key:2}; + var vn2 = h('div', p2, c2); + c1.push(vn2); + let c3 = [], p3 = {key:3}; + var vn3 = h('p', p3, c3); + c2.push(vn3); + var _4 = scope['node'].val; + if (_4 || _4 === 0) { + c3.push({text: _4}); } - var _14 = _v0.children||[]; - if (!_14) { throw new Error('QWeb error: Invalid loop expression')} - var _15 = _16 = _14; - if (!(_14 instanceof Array)) { - _15 = Object.keys(_14); - _16 = Object.values(_14); + var _5 = scope['node'].children||[]; + if (!_5) { throw new Error('QWeb error: Invalid loop expression')} + var _6 = _7 = _5; + if (!(_5 instanceof Array)) { + _6 = Object.keys(_5); + _7 = Object.values(_5); } - var _length15 = _15.length; - for (let i1 = 0; i1 < _length15; i1++) { - context.subtree_first = i1 === 0; - scope.subtree_first = context.subtree_first; - context.subtree_last = i1 === _length15 - 1; - scope.subtree_last = context.subtree_last; - context.subtree_index = i1; - scope.subtree_index = context.subtree_index; - context.subtree = _15[i1]; - scope.subtree = context.subtree; - context.subtree_value = _16[i1]; - scope.subtree_value = context.subtree_value; - this.recursiveFns['__10'].call(this, context, Object.assign({}, extra, {parentNode: c11, vars: {_v0: context['subtree']}, fiber: {scope}})); + var _length6 = _6.length; + let _scope8 = scope; + scope = Object.assign(Object.create(context), _scope8); + for (let i1 = 0; i1 < _length6; i1++) { + scope.subtree_first = i1 === 0 + scope.subtree_last = i1 === _length6 - 1 + scope.subtree_index = i1 + scope.subtree = _6[i1] + scope.subtree_value = _7[i1] + { + let origScope = scope; + scope = Object.assign(Object.create(context), scope); + { + let c__0 = []; + scope.node = scope['subtree']; + scope[utils.zero] = c__0; + } + this.subTemplates['nodeTemplate'].call(this, scope, Object.assign({}, extra, {parentNode: c2})); + scope = origScope; + } } + scope = _scope8; }" `; @@ -1294,16 +1333,24 @@ exports[`t-call (template calling scoped parameters 1`] = ` "function anonymous(context, extra ) { // Template name: \\"caller\\" + 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); { - let _2 = 42; - c1.push({text: \`ok\`}); + let origScope = scope; + scope = Object.assign(Object.create(context), scope); + { + let c__0 = []; + scope.foo = 42; + scope[utils.zero] = c__0; + } + this.subTemplates['_basic-callee'].call(this, scope, Object.assign({}, extra, {parentNode: c1})); + scope = origScope; } - var _3 = context['foo']; - if (_3 || _3 === 0) { - c1.push({text: _3}); + if (scope.foo || scope.foo === 0) { + c1.push({text: scope.foo}); } return vn1; }" @@ -1313,30 +1360,96 @@ exports[`t-call (template calling t-call with t-if 1`] = ` "function anonymous(context, extra ) { // Template name: \\"caller\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - if (context['flag']) { - let c2 = [], p2 = {key:2}; - var vn2 = h('span', p2, c2); - c1.push(vn2); - c2.push({text: \`ok\`}); + if (scope['flag']) { + this.subTemplates['sub'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1})); } return vn1; }" `; +exports[`t-call (template calling t-call with t-if 2`] = ` +"function anonymous(context, extra +) { + // Template name: \\"sub\\" + var h = this.h; + let c1 = extra.parentNode; + let c2 = [], p2 = {key:2}; + var vn2 = h('span', p2, c2); + c1.push(vn2); + c2.push({text: \`ok\`}); +}" +`; + +exports[`t-call (template calling t-call with t-set inside and outside 1`] = ` +"function anonymous(context, extra +) { + // Template name: \\"main\\" + 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['list']; + if (!_2) { throw new Error('QWeb error: Invalid loop expression')} + var _3 = _4 = _2; + if (!(_2 instanceof Array)) { + _3 = Object.keys(_2); + _4 = Object.values(_2); + } + var _length3 = _3.length; + let _scope5 = scope; + scope = Object.assign(Object.create(context), _scope5); + for (let i1 = 0; i1 < _length3; i1++) { + scope.v_first = i1 === 0 + scope.v_last = i1 === _length3 - 1 + scope.v_index = i1 + scope.v = _3[i1] + scope.v_value = _4[i1] + scope.val = scope['v'].val; + { + let origScope = scope; + scope = Object.assign(Object.create(context), scope); + { + let c__0 = []; + scope.val3 = scope.val*3; + scope[utils.zero] = c__0; + } + this.subTemplates['sub'].call(this, scope, Object.assign({}, extra, {parentNode: c1})); + scope = origScope; + } + } + scope = _scope5; + return vn1; +}" +`; + +exports[`t-call (template calling t-call with t-set inside and outside. 2 1`] = ` +"function anonymous(context, extra +) { + // Template name: \\"wrapper\\" + let scope = Object.create(context); + var h = this.h; + let c1 = [], p1 = {key:1}; + var vn1 = h('p', p1, c1); + scope.w = 'fromwrapper'; + this.subTemplates['main'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1})); + return vn1; +}" +`; + exports[`t-call (template calling t-call, global templates 1`] = ` "function anonymous(context, extra ) { // Template name: \\"abcd\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - let c2 = [], p2 = {key:2}; - var vn2 = h('span', p2, c2); - c1.push(vn2); - c2.push({text: \`desk\`}); + this.subTemplates['john'].call(this, Object.assign(Object.create(context), scope), Object.assign({}, extra, {parentNode: c1})); return vn1; }" `; @@ -1345,12 +1458,23 @@ exports[`t-call (template calling with unused body 1`] = ` "function anonymous(context, extra ) { // Template name: \\"caller\\" + let utils = this.constructor.utils; + let scope = Object.create(context); let result; var h = this.h; - let c2 = [], p2 = {key:2}; - var vn2 = h('div', p2, c2); - result = vn2; - c2.push({text: \`ok\`}); + { + let origScope = scope; + scope = Object.assign(Object.create(context), scope); + { + let c__0 = []; + c__0.push({text: \`WHEEE\`}); + scope[utils.zero] = c__0; + } + result = [] + this.subTemplates['_basic-callee'].call(this, scope, Object.assign({}, extra, {parentNode: result})); + result = result[0] + scope = origScope; + } return result; }" `; @@ -1359,14 +1483,22 @@ exports[`t-call (template calling with unused setbody 1`] = ` "function anonymous(context, extra ) { // Template name: \\"caller\\" + let utils = this.constructor.utils; + let scope = Object.create(context); let result; var h = this.h; { - let _1 = 3; - let c2 = [], p2 = {key:2}; - var vn2 = h('div', p2, c2); - result = vn2; - c2.push({text: \`ok\`}); + let origScope = scope; + scope = Object.assign(Object.create(context), scope); + { + let c__0 = []; + scope.qux = 3; + scope[utils.zero] = c__0; + } + result = [] + this.subTemplates['_basic-callee'].call(this, scope, Object.assign({}, extra, {parentNode: result})); + result = result[0] + scope = origScope; } return result; }" @@ -1376,12 +1508,23 @@ exports[`t-call (template calling with used body 1`] = ` "function anonymous(context, extra ) { // Template name: \\"caller\\" + let utils = this.constructor.utils; + let scope = Object.create(context); let result; var h = this.h; - let c2 = [], p2 = {key:2}; - var vn2 = h('h1', p2, c2); - result = vn2; - c2.push({text: \`ok\`}); + { + let origScope = scope; + scope = Object.assign(Object.create(context), scope); + { + let c__0 = []; + c__0.push({text: \`ok\`}); + scope[utils.zero] = c__0; + } + result = [] + this.subTemplates['_callee-printsbody'].call(this, scope, Object.assign({}, extra, {parentNode: result})); + result = result[0] + scope = origScope; + } return result; }" `; @@ -1390,14 +1533,21 @@ exports[`t-call (template calling with used set body 1`] = ` "function anonymous(context, extra ) { // Template name: \\"caller\\" + let utils = this.constructor.utils; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('span', p1, c1); { - let _2 = 'ok'; - if (_2 || _2 === 0) { - c1.push({text: _2}); + let origScope = scope; + scope = Object.assign(Object.create(context), scope); + { + let c__0 = []; + scope.foo = 'ok'; + scope[utils.zero] = c__0; } + this.subTemplates['_callee-uses-foo'].call(this, scope, Object.assign({}, extra, {parentNode: c1})); + scope = origScope; } return vn1; }" @@ -1407,6 +1557,7 @@ exports[`t-esc escaping on a node 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('span', p1, c1); @@ -1422,6 +1573,7 @@ exports[`t-esc escaping on a node with a body 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('span', p1, c1); @@ -1439,10 +1591,11 @@ exports[`t-esc escaping on a node with a body, as a default 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('span', p1, c1); - var _2 = context['var']; + var _2 = scope['var']; if (_2 || _2 === 0) { c1.push({text: _2}); } else { @@ -1456,6 +1609,7 @@ exports[`t-esc literal 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('span', p1, c1); @@ -1471,10 +1625,11 @@ exports[`t-esc variable 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('span', p1, c1); - var _2 = context['var']; + var _2 = scope['var']; if (_2 || _2 === 0) { c1.push({text: _2}); } @@ -1486,16 +1641,17 @@ exports[`t-if boolean value condition elif 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - if (context['color']=='black') { + if (scope['color']=='black') { c1.push({text: \`black pearl\`}); } - else if (context['color']=='yellow') { + else if (scope['color']=='yellow') { c1.push({text: \`yellow submarine\`}); } - else if (context['color']=='red') { + else if (scope['color']=='red') { c1.push({text: \`red is dead\`}); } else { @@ -1509,6 +1665,7 @@ exports[`t-if boolean value condition else 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -1516,7 +1673,7 @@ exports[`t-if boolean value condition else 1`] = ` var vn2 = h('span', p2, c2); c1.push(vn2); c2.push({text: \`begin\`}); - if (context['condition']) { + if (scope['condition']) { c1.push({text: \`ok\`}); } else { @@ -1534,6 +1691,7 @@ exports[`t-if boolean value condition false else 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -1541,7 +1699,7 @@ exports[`t-if boolean value condition false else 1`] = ` var vn2 = h('span', p2, c2); c1.push(vn2); c2.push({text: \`begin\`}); - if (context['condition']) { + if (scope['condition']) { c1.push({text: \`fail\`}); } else { @@ -1559,10 +1717,11 @@ exports[`t-if boolean value condition missing 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('span', p1, c1); - if (context['condition']) { + if (scope['condition']) { c1.push({text: \`fail\`}); } return vn1; @@ -1573,10 +1732,11 @@ exports[`t-if boolean value false condition 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - if (context['condition']) { + if (scope['condition']) { c1.push({text: \`ok\`}); } return vn1; @@ -1587,10 +1747,11 @@ exports[`t-if boolean value true condition 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - if (context['condition']) { + if (scope['condition']) { c1.push({text: \`ok\`}); } return vn1; @@ -1601,31 +1762,32 @@ exports[`t-if can use some boolean operators in expressions 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - if (context['cond1']&&context['cond2']) { + if (scope['cond1']&&scope['cond2']) { c1.push({text: \`and\`}); } - if (context['cond1']&&context['cond3']) { + if (scope['cond1']&&scope['cond3']) { c1.push({text: \`nope\`}); } - if (context['cond1']||context['cond3']) { + if (scope['cond1']||scope['cond3']) { c1.push({text: \`or\`}); } - if (context['cond3']||context['cond4']) { + if (scope['cond3']||scope['cond4']) { c1.push({text: \`nope\`}); } - if (context['m']>3) { + if (scope['m']>3) { c1.push({text: \`mgt\`}); } - if (context['n']>3) { + if (scope['n']>3) { c1.push({text: \`ngt\`}); } - if (context['m']<3) { + if (scope['m']<3) { c1.push({text: \`mlt\`}); } - if (context['n']<3) { + if (scope['n']<3) { c1.push({text: \`nlt\`}); } return vn1; @@ -1636,6 +1798,7 @@ exports[`t-if t-esc with t-elif 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -1656,6 +1819,7 @@ exports[`t-if t-esc with t-if 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -1673,22 +1837,23 @@ exports[`t-if t-set, then t-elif, part 3 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = false; - var _3 = _2; - if (_3) { - let c4 = [], p4 = {key:4}; - var vn4 = h('span', p4, c4); - c1.push(vn4); - c4.push({text: \`AAA\`}); + scope.y = false; + scope.x = scope.y; + if (scope.x) { + let c2 = [], p2 = {key:2}; + var vn2 = h('span', p2, c2); + c1.push(vn2); + c2.push({text: \`AAA\`}); } - else if (!_3) { - let c5 = [], p5 = {key:5}; - var vn5 = h('span', p5, c5); - c1.push(vn5); - c5.push({text: \`BBB\`}); + else if (!scope.x) { + let c3 = [], p3 = {key:3}; + var vn3 = h('span', p3, c3); + c1.push(vn3); + c3.push({text: \`BBB\`}); } return vn1; }" @@ -1698,13 +1863,14 @@ exports[`t-if t-set, then t-if 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = 'test'; - if (_2) { - if (_2 || _2 === 0) { - c1.push({text: _2}); + scope.title = 'test'; + if (scope.title) { + if (scope.title || scope.title === 0) { + c1.push({text: scope.title}); } } return vn1; @@ -1715,16 +1881,17 @@ exports[`t-if t-set, then t-if, part 2 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = true; - var _3 = _2; - if (_3) { - let c4 = [], p4 = {key:4}; - var vn4 = h('span', p4, c4); - c1.push(vn4); - c4.push({text: \`COUCOU\`}); + scope.y = true; + scope.x = scope.y; + if (scope.x) { + let c2 = [], p2 = {key:2}; + var vn2 = h('span', p2, c2); + c1.push(vn2); + c2.push({text: \`COUCOU\`}); } return vn1; }" @@ -1734,11 +1901,12 @@ exports[`t-key can use t-key directive on a node 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; - const nodeKey1 = context['beer'].id; + const nodeKey1 = scope['beer'].id; let c2 = [], p2 = {key:nodeKey1}; var vn2 = h('div', p2, c2); - var _3 = context['beer'].name; + var _3 = scope['beer'].name; if (_3 || _3 === 0) { c2.push({text: _3}); } @@ -1750,11 +1918,11 @@ exports[`t-key t-key directive in a list 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('ul', p1, c1); - var _2 = context['beers']; + var _2 = scope['beers']; if (!_2) { throw new Error('QWeb error: Invalid loop expression')} var _3 = _4 = _2; if (!(_2 instanceof Array)) { @@ -1762,21 +1930,24 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.beer_first = i1 === 0; - context.beer_last = i1 === _length3 - 1; - context.beer_index = i1; - context.beer = _3[i1]; - context.beer_value = _4[i1]; - const nodeKey5 = context['beer'].id; - let c6 = [], p6 = {key:nodeKey5}; - var vn6 = h('li', p6, c6); - c1.push(vn6); - var _7 = context['beer'].name; - if (_7 || _7 === 0) { - c6.push({text: _7}); + scope.beer_first = i1 === 0 + scope.beer_last = i1 === _length3 - 1 + scope.beer_index = i1 + scope.beer = _3[i1] + scope.beer_value = _4[i1] + const nodeKey6 = scope['beer'].id; + let c7 = [], p7 = {key:nodeKey6}; + var vn7 = h('li', p7, c7); + c1.push(vn7); + var _8 = scope['beer'].name; + if (_8 || _8 === 0) { + c7.push({text: _8}); } } + scope = _scope5; return vn1; }" `; @@ -1787,11 +1958,10 @@ exports[`t-on can bind event handler 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; var h = this.h; let c1 = [], p1 = {key:1,on:{}}; var vn1 = h('button', p1, c1); - extra.handlers['click' + 1] = extra.handlers['click' + 1] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['add'];if (fn) { fn.call(owner, e); } else { context.add; }}; + extra.handlers['click' + 1] = extra.handlers['click' + 1] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['add'];if (fn) { fn.call(context, e); } else { context.add; }}; p1.on['click'] = extra.handlers['click' + 1]; c1.push({text: \`Click\`}); return vn1; @@ -1802,11 +1972,11 @@ exports[`t-on can bind handlers with arguments 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1,on:{}}; var vn1 = h('button', p1, c1); - const handler2 = context['add'] && context['add'].bind(owner, 5); + const handler2 = context['add'] && context['add'].bind(context, 5); p1.on['click'] = function (e) {if (!context.__owl__.isMounted){return}if (handler2) { handler2(e); } else { context.add(5); }}; c1.push({text: \`Click\`}); return vn1; @@ -1817,11 +1987,11 @@ exports[`t-on can bind handlers with empty object (with non empty inner string) "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1,on:{}}; var vn1 = h('button', p1, c1); - const handler2 = context['doSomething'] && context['doSomething'].bind(owner, {}); + const handler2 = context['doSomething'] && context['doSomething'].bind(context, {}); p1.on['click'] = function (e) {if (!context.__owl__.isMounted){return}if (handler2) { handler2(e); } else { context.doSomething({ }); }}; c1.push({text: \`Click\`}); return vn1; @@ -1832,11 +2002,11 @@ exports[`t-on can bind handlers with empty object 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1,on:{}}; var vn1 = h('button', p1, c1); - const handler2 = context['doSomething'] && context['doSomething'].bind(owner, {}); + const handler2 = context['doSomething'] && context['doSomething'].bind(context, {}); p1.on['click'] = function (e) {if (!context.__owl__.isMounted){return}if (handler2) { handler2(e); } else { context.doSomething({}); }}; c1.push({text: \`Click\`}); return vn1; @@ -1847,8 +2017,7 @@ exports[`t-on can bind handlers with loop variable as argument 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('ul', p1, c1); @@ -1860,23 +2029,26 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.action_first = i1 === 0; - context.action_last = i1 === _length3 - 1; - context.action_index = i1; - context.action = _3[i1]; - context.action_value = _4[i1]; - const nodeKey5 = context['action_index']; - let c6 = [], p6 = {key:nodeKey5}; - var vn6 = h('li', p6, c6); - c1.push(vn6); - let c7 = [], p7 = {key:nodeKey5,on:{}}; - var vn7 = h('a', p7, c7); - c6.push(vn7); - const handler8 = context['activate'] && context['activate'].bind(owner, context['action']); - p7.on['click'] = function (e) {if (!context.__owl__.isMounted){return}if (handler8) { handler8(e); } else { context.activate(action); }}; - c7.push({text: \`link\`}); + scope.action_first = i1 === 0 + scope.action_last = i1 === _length3 - 1 + scope.action_index = i1 + scope.action = _3[i1] + scope.action_value = _4[i1] + const nodeKey6 = scope['action_index']; + let c7 = [], p7 = {key:nodeKey6}; + var vn7 = h('li', p7, c7); + c1.push(vn7); + let c8 = [], p8 = {key:nodeKey6,on:{}}; + var vn8 = h('a', p8, c8); + c7.push(vn8); + const handler9 = context['activate'] && context['activate'].bind(context, scope['action']); + p8.on['click'] = function (e) {if (!context.__owl__.isMounted){return}if (handler9) { handler9(e); } else { context.activate(action); }}; + c8.push({text: \`link\`}); } + scope = _scope5; return vn1; }" `; @@ -1885,11 +2057,11 @@ exports[`t-on can bind handlers with object arguments 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1,on:{}}; var vn1 = h('button', p1, c1); - const handler2 = context['add'] && context['add'].bind(owner, {val:5}); + const handler2 = context['add'] && context['add'].bind(context, {val:5}); p1.on['click'] = function (e) {if (!context.__owl__.isMounted){return}if (handler2) { handler2(e); } else { context.add({val: 5}); }}; c1.push({text: \`Click\`}); return vn1; @@ -1900,13 +2072,12 @@ exports[`t-on can bind two event handlers 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; var h = this.h; let c1 = [], p1 = {key:1,on:{}}; var vn1 = h('button', p1, c1); - extra.handlers['click' + 1] = extra.handlers['click' + 1] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['handleClick'];if (fn) { fn.call(owner, e); } else { context.handleClick; }}; + extra.handlers['click' + 1] = extra.handlers['click' + 1] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['handleClick'];if (fn) { fn.call(context, e); } else { context.handleClick; }}; p1.on['click'] = extra.handlers['click' + 1]; - extra.handlers['dblclick' + 1] = extra.handlers['dblclick' + 1] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['handleDblClick'];if (fn) { fn.call(owner, e); } else { context.handleDblClick; }}; + extra.handlers['dblclick' + 1] = extra.handlers['dblclick' + 1] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['handleDblClick'];if (fn) { fn.call(context, e); } else { context.handleDblClick; }}; p1.on['dblclick'] = extra.handlers['dblclick' + 1]; c1.push({text: \`Click\`}); return vn1; @@ -1917,11 +2088,10 @@ exports[`t-on handler is bound to proper owner 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; var h = this.h; let c1 = [], p1 = {key:1,on:{}}; var vn1 = h('button', p1, c1); - extra.handlers['click' + 1] = extra.handlers['click' + 1] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['add'];if (fn) { fn.call(owner, e); } else { context.add; }}; + extra.handlers['click' + 1] = extra.handlers['click' + 1] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['add'];if (fn) { fn.call(context, e); } else { context.add; }}; p1.on['click'] = extra.handlers['click' + 1]; c1.push({text: \`Click\`}); return vn1; @@ -1932,16 +2102,16 @@ exports[`t-on t-on combined with t-esc 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2,on:{}}; var vn2 = h('button', p2, c2); c1.push(vn2); - extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['onClick'];if (fn) { fn.call(owner, e); } else { context.onClick; }}; + extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['onClick'];if (fn) { fn.call(context, e); } else { context.onClick; }}; p2.on['click'] = extra.handlers['click' + 2]; - var _3 = context['text']; + var _3 = scope['text']; if (_3 || _3 === 0) { c2.push({text: _3}); } @@ -1954,16 +2124,16 @@ exports[`t-on t-on combined with t-raw 1`] = ` ) { // Template name: \\"test\\" let utils = this.constructor.utils; - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2,on:{}}; var vn2 = h('button', p2, c2); c1.push(vn2); - extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['onClick'];if (fn) { fn.call(owner, e); } else { context.onClick; }}; + extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['onClick'];if (fn) { fn.call(context, e); } else { context.onClick; }}; p2.on['click'] = extra.handlers['click' + 2]; - var _3 = context['html']; + var _3 = scope['html']; if (_3 || _3 === 0) { c2.push(...utils.htmlToVDOM(_3)); } @@ -1975,7 +2145,6 @@ exports[`t-on t-on with empty handler (only modifiers) 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -1992,11 +2161,11 @@ exports[`t-on t-on with inline statement (function call) 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1,on:{}}; var vn1 = h('button', p1, c1); - const handler2 = context['state.incrementCounter'] && context['state.incrementCounter'].bind(owner, 2); + const handler2 = context['state.incrementCounter'] && context['state.incrementCounter'].bind(context, 2); p1.on['click'] = function (e) {if (!context.__owl__.isMounted){return}if (handler2) { handler2(e); } else { context.state.incrementCounter(2); }}; c1.push({text: \`Click\`}); return vn1; @@ -2007,11 +2176,10 @@ exports[`t-on t-on with inline statement 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; var h = this.h; let c1 = [], p1 = {key:1,on:{}}; var vn1 = h('button', p1, c1); - extra.handlers['click' + 1] = extra.handlers['click' + 1] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['state.counter++'];if (fn) { fn.call(owner, e); } else { context.state.counter++; }}; + extra.handlers['click' + 1] = extra.handlers['click' + 1] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['state.counter++'];if (fn) { fn.call(context, e); } else { context.state.counter++; }}; p1.on['click'] = extra.handlers['click' + 1]; c1.push({text: \`Click\`}); return vn1; @@ -2022,14 +2190,13 @@ exports[`t-on t-on with prevent and self modifiers (order matters) 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2,on:{}}; var vn2 = h('button', p2, c2); c1.push(vn2); - extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}e.preventDefault();if (e.target !== this.elm) {return}const fn = context['onClick'];if (fn) { fn.call(owner, e); } else { context.onClick; }}; + extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}e.preventDefault();if (e.target !== this.elm) {return}const fn = context['onClick'];if (fn) { fn.call(context, e); } else { context.onClick; }}; p2.on['click'] = extra.handlers['click' + 2]; let c3 = [], p3 = {key:3}; var vn3 = h('span', p3, c3); @@ -2043,26 +2210,25 @@ exports[`t-on t-on with prevent and/or stop modifiers 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2,on:{}}; var vn2 = h('button', p2, c2); c1.push(vn2); - extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}e.preventDefault();const fn = context['onClickPrevented'];if (fn) { fn.call(owner, e); } else { context.onClickPrevented; }}; + extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}e.preventDefault();const fn = context['onClickPrevented'];if (fn) { fn.call(context, e); } else { context.onClickPrevented; }}; p2.on['click'] = extra.handlers['click' + 2]; c2.push({text: \`Button 1\`}); let c3 = [], p3 = {key:3,on:{}}; var vn3 = h('button', p3, c3); c1.push(vn3); - extra.handlers['click' + 3] = extra.handlers['click' + 3] || function (e) {if (!context.__owl__.isMounted){return}e.stopPropagation();const fn = context['onClickStopped'];if (fn) { fn.call(owner, e); } else { context.onClickStopped; }}; + extra.handlers['click' + 3] = extra.handlers['click' + 3] || function (e) {if (!context.__owl__.isMounted){return}e.stopPropagation();const fn = context['onClickStopped'];if (fn) { fn.call(context, e); } else { context.onClickStopped; }}; p3.on['click'] = extra.handlers['click' + 3]; c3.push({text: \`Button 2\`}); let c4 = [], p4 = {key:4,on:{}}; var vn4 = h('button', p4, c4); c1.push(vn4); - extra.handlers['click' + 4] = extra.handlers['click' + 4] || function (e) {if (!context.__owl__.isMounted){return}e.preventDefault();e.stopPropagation();const fn = context['onClickPreventedAndStopped'];if (fn) { fn.call(owner, e); } else { context.onClickPreventedAndStopped; }}; + extra.handlers['click' + 4] = extra.handlers['click' + 4] || function (e) {if (!context.__owl__.isMounted){return}e.preventDefault();e.stopPropagation();const fn = context['onClickPreventedAndStopped'];if (fn) { fn.call(context, e); } else { context.onClickPreventedAndStopped; }}; p4.on['click'] = extra.handlers['click' + 4]; c4.push({text: \`Button 3\`}); return vn1; @@ -2073,12 +2239,11 @@ exports[`t-on t-on with prevent modifier in t-foreach 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['projects']; + var _2 = scope['projects']; if (!_2) { throw new Error('QWeb error: Invalid loop expression')} var _3 = _4 = _2; if (!(_2 instanceof Array)) { @@ -2086,25 +2251,28 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.project_first = i1 === 0; - context.project_last = i1 === _length3 - 1; - context.project_index = i1; - context.project = _3[i1]; - context.project_value = _4[i1]; - const nodeKey5 = context['project']; - var _6 = '#'; - let c7 = [], p7 = {key:nodeKey5,attrs:{href: _6},on:{}}; - var vn7 = h('a', p7, c7); - c1.push(vn7); - const handler8 = context['onEdit'] && context['onEdit'].bind(owner, context['project'].id); - p7.on['click'] = function (e) {if (!context.__owl__.isMounted){return}e.preventDefault();if (handler8) { handler8(e); } else { context.onEdit(project.id); }}; - c7.push({text: \` Edit \`}); - var _9 = context['project'].name; - if (_9 || _9 === 0) { - c7.push({text: _9}); + scope.project_first = i1 === 0 + scope.project_last = i1 === _length3 - 1 + scope.project_index = i1 + scope.project = _3[i1] + scope.project_value = _4[i1] + const nodeKey6 = scope['project']; + var _7 = '#'; + let c8 = [], p8 = {key:nodeKey6,attrs:{href: _7},on:{}}; + var vn8 = h('a', p8, c8); + c1.push(vn8); + const handler9 = context['onEdit'] && context['onEdit'].bind(context, scope['project'].id); + p8.on['click'] = function (e) {if (!context.__owl__.isMounted){return}e.preventDefault();if (handler9) { handler9(e); } else { context.onEdit(project.id); }}; + c8.push({text: \` Edit \`}); + var _10 = scope['project'].name; + if (_10 || _10 === 0) { + c8.push({text: _10}); } } + scope = _scope5; return vn1; }" `; @@ -2113,14 +2281,13 @@ exports[`t-on t-on with self and prevent modifiers (order matters) 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2,on:{}}; var vn2 = h('button', p2, c2); c1.push(vn2); - extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}if (e.target !== this.elm) {return}e.preventDefault();const fn = context['onClick'];if (fn) { fn.call(owner, e); } else { context.onClick; }}; + extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}if (e.target !== this.elm) {return}e.preventDefault();const fn = context['onClick'];if (fn) { fn.call(context, e); } else { context.onClick; }}; p2.on['click'] = extra.handlers['click' + 2]; let c3 = [], p3 = {key:3}; var vn3 = h('span', p3, c3); @@ -2134,14 +2301,13 @@ exports[`t-on t-on with self modifier 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - let owner = context; var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2,on:{}}; var vn2 = h('button', p2, c2); c1.push(vn2); - extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['onClick'];if (fn) { fn.call(owner, e); } else { context.onClick; }}; + extra.handlers['click' + 2] = extra.handlers['click' + 2] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['onClick'];if (fn) { fn.call(context, e); } else { context.onClick; }}; p2.on['click'] = extra.handlers['click' + 2]; let c3 = [], p3 = {key:3}; var vn3 = h('span', p3, c3); @@ -2150,7 +2316,7 @@ exports[`t-on t-on with self modifier 1`] = ` let c4 = [], p4 = {key:4,on:{}}; var vn4 = h('button', p4, c4); c1.push(vn4); - extra.handlers['click' + 4] = extra.handlers['click' + 4] || function (e) {if (!context.__owl__.isMounted){return}if (e.target !== this.elm) {return}const fn = context['onClickSelf'];if (fn) { fn.call(owner, e); } else { context.onClickSelf; }}; + extra.handlers['click' + 4] = extra.handlers['click' + 4] || function (e) {if (!context.__owl__.isMounted){return}if (e.target !== this.elm) {return}const fn = context['onClickSelf'];if (fn) { fn.call(context, e); } else { context.onClickSelf; }}; p4.on['click'] = extra.handlers['click' + 4]; let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); @@ -2165,6 +2331,7 @@ exports[`t-raw literal 1`] = ` ) { // 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('span', p1, c1); @@ -2181,10 +2348,11 @@ exports[`t-raw not escaping 1`] = ` ) { // 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 = context['var']; + var _2 = scope['var']; if (_2 || _2 === 0) { c1.push(...utils.htmlToVDOM(_2)); } @@ -2197,6 +2365,7 @@ exports[`t-raw t-raw and another sibling node 1`] = ` ) { // 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('span', p1, c1); @@ -2204,7 +2373,7 @@ exports[`t-raw t-raw and another sibling node 1`] = ` var vn2 = h('span', p2, c2); c1.push(vn2); c2.push({text: \`hello\`}); - var _3 = context['var']; + var _3 = scope['var']; if (_3 || _3 === 0) { c1.push(...utils.htmlToVDOM(_3)); } @@ -2217,10 +2386,11 @@ exports[`t-raw variable 1`] = ` ) { // 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('span', p1, c1); - var _2 = context['var']; + var _2 = scope['var']; if (_2 || _2 === 0) { c1.push(...utils.htmlToVDOM(_2)); } @@ -2233,13 +2403,14 @@ exports[`t-ref can get a dynamic ref on a node 1`] = ` ) { // Template name: \\"test\\" context.__owl__.refs = context.__owl__.refs || {}; + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); let c2 = [], p2 = {key:2}; var vn2 = h('span', p2, c2); c1.push(vn2); - const ref3 = \`myspan\${context['id']}\`; + const ref3 = \`myspan\${scope['id']}\`; p2.hook = { create: (_, n) => { context.__owl__.refs[ref3] = n.elm; @@ -2281,11 +2452,11 @@ exports[`t-ref refs in a loop 1`] = ` ) { // Template name: \\"test\\" context.__owl__.refs = context.__owl__.refs || {}; - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['items']; + var _2 = scope['items']; if (!_2) { throw new Error('QWeb error: Invalid loop expression')} var _3 = _4 = _2; if (!(_2 instanceof Array)) { @@ -2293,30 +2464,33 @@ 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); for (let i1 = 0; i1 < _length3; i1++) { - context.item_first = i1 === 0; - context.item_last = i1 === _length3 - 1; - context.item_index = i1; - context.item = _3[i1]; - context.item_value = _4[i1]; - const nodeKey5 = context['item']; - let c6 = [], p6 = {key:nodeKey5}; - var vn6 = h('div', p6, c6); - c1.push(vn6); - const ref7 = (context['item']); - p6.hook = { + scope.item_first = i1 === 0 + scope.item_last = i1 === _length3 - 1 + scope.item_index = i1 + scope.item = _3[i1] + scope.item_value = _4[i1] + const nodeKey6 = scope['item']; + let c7 = [], p7 = {key:nodeKey6}; + var vn7 = h('div', p7, c7); + c1.push(vn7); + const ref8 = (scope['item']); + p7.hook = { create: (_, n) => { - context.__owl__.refs[ref7] = n.elm; + context.__owl__.refs[ref8] = n.elm; }, destroy: () => { - delete context.__owl__.refs[ref7]; + delete context.__owl__.refs[ref8]; }, }; - var _8 = context['item']; - if (_8 || _8 === 0) { - c6.push({text: _8}); + var _9 = scope['item']; + if (_9 || _9 === 0) { + c7.push({text: _9}); } } + scope = _scope5; return vn1; }" `; @@ -2325,12 +2499,13 @@ exports[`t-set evaluate value expression 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = 1+2; - if (_2 || _2 === 0) { - c1.push({text: _2}); + scope.value = 1+2; + if (scope.value || scope.value === 0) { + c1.push({text: scope.value}); } return vn1; }" @@ -2340,12 +2515,13 @@ exports[`t-set evaluate value expression, part 2 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['somevariable']+2; - if (_2 || _2 === 0) { - c1.push({text: _2}); + scope.value = scope['somevariable']+2; + if (scope.value || scope.value === 0) { + c1.push({text: scope.value}); } return vn1; }" @@ -2355,12 +2531,13 @@ exports[`t-set set from attribute literal 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = 'ok'; - if (_2 || _2 === 0) { - c1.push({text: _2}); + scope.value = 'ok'; + if (scope.value || scope.value === 0) { + c1.push({text: scope.value}); } return vn1; }" @@ -2370,12 +2547,13 @@ exports[`t-set set from attribute lookup 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['value']; - if (_2 || _2 === 0) { - c1.push({text: _2}); + scope.stuff = scope['value']; + if (scope.stuff || scope.stuff === 0) { + c1.push({text: scope.stuff}); } return vn1; }" @@ -2385,6 +2563,7 @@ exports[`t-set set from body literal 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); let result; var h = this.h; var vn1 = {text: \`ok\`}; @@ -2397,10 +2576,11 @@ exports[`t-set set from body lookup 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['value']; + var _2 = scope['value']; if (_2 || _2 === 0) { c1.push({text: _2}); } @@ -2412,6 +2592,7 @@ exports[`t-set set from empty body 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); @@ -2423,30 +2604,51 @@ exports[`t-set t-set and t-if 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['value']; - if (_2==='ok') { + scope.v = scope['value']; + if (scope.v==='ok') { c1.push({text: \`grimbergen\`}); } return vn1; }" `; +exports[`t-set t-set body is evaluated immediately 1`] = ` +"function anonymous(context,extra +) { + 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); + if (scope.v1 || scope.v1 === 0) { + c2.push({text: scope.v1}); + } + return vn1; +}" +`; + exports[`t-set t-set evaluates an expression only once 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = context['value']+' artois'; - if (_2 || _2 === 0) { - c1.push({text: _2}); + scope.v = scope['value']+' artois'; + if (scope.v || scope.v === 0) { + c1.push({text: scope.v}); } - if (_2 || _2 === 0) { - c1.push({text: _2}); + if (scope.v || scope.v === 0) { + c1.push({text: scope.v}); } return vn1; }" @@ -2456,26 +2658,28 @@ exports[`t-set t-set should reuse variable if possible 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" - context = Object.create(context); + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = 1; - var _3 = context['list']; - if (!_3) { throw new Error('QWeb error: Invalid loop expression')} - var _4 = _5 = _3; - if (!(_3 instanceof Array)) { - _4 = Object.keys(_3); - _5 = Object.values(_3); + scope.v = 1; + var _2 = scope['list']; + if (!_2) { throw new Error('QWeb error: Invalid loop expression')} + var _3 = _4 = _2; + if (!(_2 instanceof Array)) { + _3 = Object.keys(_2); + _4 = Object.values(_2); } - var _length4 = _4.length; - for (let i1 = 0; i1 < _length4; i1++) { - context.elem_first = i1 === 0; - context.elem_last = i1 === _length4 - 1; - context.elem_index = i1; - context.elem = _4[i1]; - context.elem_value = _5[i1]; - const nodeKey6 = context['elem_index']; + var _length3 = _3.length; + let _scope5 = scope; + scope = Object.assign(Object.create(context), _scope5); + for (let i1 = 0; i1 < _length3; i1++) { + scope.elem_first = i1 === 0 + scope.elem_last = i1 === _length3 - 1 + scope.elem_index = i1 + scope.elem = _3[i1] + scope.elem_value = _4[i1] + const nodeKey6 = scope['elem_index']; let c7 = [], p7 = {key:nodeKey6}; var vn7 = h('div', p7, c7); c1.push(vn7); @@ -2483,11 +2687,12 @@ exports[`t-set t-set should reuse variable if possible 1`] = ` var vn8 = h('span', p8, c8); c7.push(vn8); c8.push({text: \`v\`}); - if (_2 || _2 === 0) { - c8.push({text: _2}); + if (scope.v || scope.v === 0) { + c8.push({text: scope.v}); } - _2 = context['elem'] + scope.v = scope['elem'] } + scope = _scope5; return vn1; }" `; @@ -2496,16 +2701,17 @@ exports[`t-set t-set, t-if, and mix of expression/body lookup, 1 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - if (context['flag']) { + if (scope['flag']) { } else { - var _2 = 0; + scope.ourvar = 0; } - if (_2 || _2 === 0) { - c1.push({text: _2}); + if (scope.ourvar || scope.ourvar === 0) { + c1.push({text: scope.ourvar}); } else { c1.push({text: \`1\`}); } @@ -2517,16 +2723,17 @@ exports[`t-set t-set, t-if, and mix of expression/body lookup, 1 2`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - if (context['flag']) { + if (scope['flag']) { } else { - var _2 = 0; + scope.ourvar = 0; } - if (_2 || _2 === 0) { - c1.push({text: _2}); + if (scope.ourvar || scope.ourvar === 0) { + c1.push({text: scope.ourvar}); } else { c1.push({text: \`1\`}); } @@ -2538,16 +2745,17 @@ exports[`t-set t-set, t-if, and mix of expression/body lookup, 2 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - if (context['flag']) { - var _2 = 1; + if (scope['flag']) { + scope.ourvar = 1; } else { } - if (_2 || _2 === 0) { - c1.push({text: _2}); + if (scope.ourvar || scope.ourvar === 0) { + c1.push({text: scope.ourvar}); } else { c1.push({text: \`0\`}); } @@ -2559,16 +2767,17 @@ exports[`t-set t-set, t-if, and mix of expression/body lookup, 2 2`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - if (context['flag']) { - var _2 = 1; + if (scope['flag']) { + scope.ourvar = 1; } else { } - if (_2 || _2 === 0) { - c1.push({text: _2}); + if (scope.ourvar || scope.ourvar === 0) { + c1.push({text: scope.ourvar}); } else { c1.push({text: \`0\`}); } @@ -2580,12 +2789,13 @@ exports[`t-set value priority 1`] = ` "function anonymous(context, extra ) { // Template name: \\"test\\" + let scope = Object.create(context); var h = this.h; let c1 = [], p1 = {key:1}; var vn1 = h('div', p1, c1); - var _2 = 1; - if (_2 || _2 === 0) { - c1.push({text: _2}); + scope.value = 1; + if (scope.value || scope.value === 0) { + c1.push({text: scope.value}); } return vn1; }" diff --git a/tests/qweb/qweb.test.ts b/tests/qweb/qweb.test.ts index e637a636..b59212ef 100644 --- a/tests/qweb/qweb.test.ts +++ b/tests/qweb/qweb.test.ts @@ -278,6 +278,21 @@ describe("t-set", () => { expect(renderToString(qweb, "test", { flag: true })).toBe("
1
"); expect(renderToString(qweb, "test", { flag: false })).toBe("
0
"); }); + + test("t-set body is evaluated immediately", () => { + qweb.addTemplate( + "test", + `
+ + + + + + +
`); + + expect(renderToString(qweb, "test")).toBe("
before
"); + }); }); describe("t-if", () => { @@ -598,10 +613,19 @@ describe("attributes", () => { describe("t-call (template calling", () => { test("basic caller", () => { + qweb.addTemplate("_basic-callee", "ok"); + qweb.addTemplate("caller", '
'); + const expected = "
ok
"; + expect(renderToString(qweb, "caller")).toBe(expected); + expect(qweb.subTemplates["_basic-callee"].toString()).toMatchSnapshot(); + }); + + test("basic caller, no parent node", () => { qweb.addTemplate("_basic-callee", "
ok
"); qweb.addTemplate("caller", ''); const expected = "
ok
"; expect(renderToString(qweb, "caller")).toBe(expected); + expect(qweb.subTemplates["_basic-callee"].toString()).toMatchSnapshot(); }); test("t-call with t-if", () => { @@ -609,6 +633,7 @@ describe("t-call (template calling", () => { qweb.addTemplate("caller", '
'); const expected = "
ok
"; expect(renderToString(qweb, "caller", { flag: true })).toBe(expected); + expect(qweb.subTemplates["sub"].toString()).toMatchSnapshot(); }); test("t-call not allowed on a non t node", () => { @@ -693,6 +718,7 @@ describe("t-call (template calling", () => { `); const expected = "
hey yay
"; expect(renderToString(qweb, "main")).toBe(expected); + expect(qweb.subTemplates["SubTemplate"].toString()).toMatchSnapshot(); }); test("cascading t-call t-raw='0'", () => { @@ -742,7 +768,7 @@ describe("t-call (template calling", () => { `); const expected = "
hey
"; expect(renderToString(qweb, "recursive")).toBe(expected); - const recursiveFn = Object.values(qweb.recursiveFns)[0] as any; + const recursiveFn = Object.values(qweb.subTemplates)[0] as any; expect(recursiveFn.toString()).toMatchSnapshot(); }); @@ -770,7 +796,7 @@ describe("t-call (template calling", () => { expect(renderToString(qweb, "Parent", { root }, { fiber: { vars: {}, scope: {} } })).toBe( expected ); - const recursiveFn = Object.values(qweb.recursiveFns)[0] as any; + const recursiveFn = Object.values(qweb.subTemplates)[0] as any; expect(recursiveFn.toString()).toMatchSnapshot(); }); @@ -797,7 +823,7 @@ describe("t-call (template calling", () => { const expected = "

a

b

d

c

"; expect(renderToString(qweb, "Parent", { root }, { fiber: {} })).toBe(expected); - const recursiveFn = Object.values(qweb.recursiveFns)[0] as any; + const recursiveFn = Object.values(qweb.subTemplates)[0] as any; expect(recursiveFn.toString()).toMatchSnapshot(); }); @@ -807,6 +833,51 @@ describe("t-call (template calling", () => { const expected = "
desk
"; expect(trim(renderToString(qweb, "abcd"))).toBe(expected); }); + + test("t-call with t-set inside and outside", () => { + qweb.addTemplates(` + +
+ + + + + + +
+ + + +
+ `); + const expected = "
369
"; + const context = { list: [{ val: 1 }, { val: 2 }, { val: 3 }] }; + expect(trim(renderToString(qweb, "main", context))).toBe(expected); + }); + + test("t-call with t-set inside and outside. 2", () => { + qweb.addTemplates(` + +
+ + + + + + +
+ + + + +

+
+ `); + const expected = + "

3fromwrapper6fromwrapper9fromwrapper

"; + const context = { list: [{ val: 1 }, { val: 2 }, { val: 3 }] }; + expect(trim(renderToString(qweb, "wrapper", context))).toBe(expected); + }); }); describe("foreach", () => { @@ -1536,6 +1607,21 @@ describe("debugging", () => { console.log = consoleLog; }); + test("t-debug on sub template", () => { + const consoleLog = console.log; + console.log = jest.fn(); + qweb.addTemplates(` +

coucou

+
+ +
` + ); + qweb.render("test"); + + expect(console.log).toHaveBeenCalledTimes(1); + console.log = consoleLog; + }); + test("t-log", () => { const consoleLog = console.log; console.log = jest.fn(); diff --git a/tests/qweb/qweb_expressions.test.ts b/tests/qweb/qweb_expressions.test.ts index 20d2f8bd..52ba87ae 100644 --- a/tests/qweb/qweb_expressions.test.ts +++ b/tests/qweb/qweb_expressions.test.ts @@ -92,7 +92,7 @@ describe("expression evaluation", () => { test("parenthesis", () => { expect(compileExpr("(1)", {})).toBe("(1)"); - expect(compileExpr("a*(1 +3)", {})).toBe("context['a']*(1+3)"); + expect(compileExpr("a*(1 +3)", {})).toBe("scope['a']*(1+3)"); }); test("objects and sub objects", () => { @@ -100,8 +100,8 @@ describe("expression evaluation", () => { }); test("replacing variables", () => { - expect(compileExpr("a", {})).toBe("context['a']"); - expect(compileExpr("a", { a: { id: "_3", expr: "" } })).toBe("_3"); + expect(compileExpr("a", {})).toBe("scope['a']"); + expect(compileExpr("a", { a: { id: "_3", expr: "scope._3" } })).toBe("scope._3"); }); test("arrays and objects", () => { @@ -111,65 +111,63 @@ describe("expression evaluation", () => { }); test("dot operator", () => { - expect(compileExpr("a.b", {})).toBe("context['a'].b"); - expect(compileExpr("a.b.c", {})).toBe("context['a'].b.c"); + expect(compileExpr("a.b", {})).toBe("scope['a'].b"); + expect(compileExpr("a.b.c", {})).toBe("scope['a'].b.c"); }); test("various unary operators", () => { - expect(compileExpr("!flag", {})).toBe("!context['flag']"); + expect(compileExpr("!flag", {})).toBe("!scope['flag']"); expect(compileExpr("-3", {})).toBe("-3"); - expect(compileExpr("-a", {})).toBe("-context['a']"); - expect(compileExpr("typeof a", {})).toBe("typeof context['a']"); + expect(compileExpr("-a", {})).toBe("-scope['a']"); + expect(compileExpr("typeof a", {})).toBe("typeof scope['a']"); }); test("various binary operators", () => { - expect(compileExpr("color == 'black'", {})).toBe("context['color']=='black'"); - expect(compileExpr("a || b", {})).toBe("context['a']||context['b']"); - expect(compileExpr("color === 'black'", {})).toBe("context['color']==='black'"); - expect(compileExpr("'li_'+item", {})).toBe("'li_'+context['item']"); - expect(compileExpr("state.val > 1", {})).toBe("context['state'].val>1"); + expect(compileExpr("color == 'black'", {})).toBe("scope['color']=='black'"); + expect(compileExpr("a || b", {})).toBe("scope['a']||scope['b']"); + expect(compileExpr("color === 'black'", {})).toBe("scope['color']==='black'"); + expect(compileExpr("'li_'+item", {})).toBe("'li_'+scope['item']"); + expect(compileExpr("state.val > 1", {})).toBe("scope['state'].val>1"); }); test("boolean operations", () => { - expect(compileExpr("a && b", {})).toBe("context['a']&&context['b']"); + expect(compileExpr("a && b", {})).toBe("scope['a']&&scope['b']"); }); test("ternary operators", () => { - expect(compileExpr("a ? b: '2'", {})).toBe("context['a']?context['b']:'2'"); - expect(compileExpr("a ? b: (c or '2') ", {})).toBe( - "context['a']?context['b']:(context['c']||'2')" - ); + expect(compileExpr("a ? b: '2'", {})).toBe("scope['a']?scope['b']:'2'"); + expect(compileExpr("a ? b: (c or '2') ", {})).toBe("scope['a']?scope['b']:(scope['c']||'2')"); expect(compileExpr("a ? {test:c}: [1,u]", {})).toBe( - "context['a']?{test:context['c']}:[1,context['u']]" + "scope['a']?{test:scope['c']}:[1,scope['u']]" ); }); test("word replacement", () => { - expect(compileExpr("a or b", {})).toBe("context['a']||context['b']"); - expect(compileExpr("a and b", {})).toBe("context['a']&&context['b']"); + expect(compileExpr("a or b", {})).toBe("scope['a']||scope['b']"); + expect(compileExpr("a and b", {})).toBe("scope['a']&&scope['b']"); }); test("function calls", () => { - expect(compileExpr("a()", {})).toBe("context['a']()"); - expect(compileExpr("a(1)", {})).toBe("context['a'](1)"); - expect(compileExpr("a(1,2)", {})).toBe("context['a'](1,2)"); - expect(compileExpr("a(1,2,{a:[a]})", {})).toBe("context['a'](1,2,{a:[context['a']]})"); + expect(compileExpr("a()", {})).toBe("scope['a']()"); + expect(compileExpr("a(1)", {})).toBe("scope['a'](1)"); + expect(compileExpr("a(1,2)", {})).toBe("scope['a'](1,2)"); + expect(compileExpr("a(1,2,{a:[a]})", {})).toBe("scope['a'](1,2,{a:[scope['a']]})"); expect(compileExpr("'x'.toUpperCase()", {})).toBe("'x'.toUpperCase()"); expect(compileExpr("'x'.toUpperCase({a: 3})", {})).toBe("'x'.toUpperCase({a:3})"); - expect(compileExpr("'x'.toUpperCase(a)", { a: { id: "_v5", expr: "" } })).toBe( - "'x'.toUpperCase(_v5)" + expect(compileExpr("'x'.toUpperCase(a)", { a: { id: "_v5", expr: "scope._v5" } })).toBe( + "'x'.toUpperCase(scope._v5)" ); - expect(compileExpr("'x'.toUpperCase({b: a})", { a: { id: "_v5", expr: "" } })).toBe( - "'x'.toUpperCase({b:_v5})" + expect(compileExpr("'x'.toUpperCase({b: a})", { a: { id: "_v5", expr: "scope._v5" } })).toBe( + "'x'.toUpperCase({b:scope._v5})" ); }); test("arrow functions", () => { - expect(compileExpr("list.map(e => e.val)", {})).toBe("context['list'].map(e=>e.val)"); - expect(compileExpr("list.map(e => a + e)", {})).toBe("context['list'].map(e=>context['a']+e)"); - expect(compileExpr("list.map((e) => e)", {})).toBe("context['list'].map((e)=>e)"); + expect(compileExpr("list.map(e => e.val)", {})).toBe("scope['list'].map(e=>e.val)"); + expect(compileExpr("list.map(e => a + e)", {})).toBe("scope['list'].map(e=>scope['a']+e)"); + expect(compileExpr("list.map((e) => e)", {})).toBe("scope['list'].map((e)=>e)"); expect(compileExpr("list.map((elem, index) => elem + index)", {})).toBe( - "context['list'].map((elem,index)=>elem+index)" + "scope['list'].map((elem,index)=>elem+index)" ); }); }); diff --git a/tests/router/__snapshots__/link.test.ts.snap b/tests/router/__snapshots__/link.test.ts.snap index f574e108..27b99b9e 100644 --- a/tests/router/__snapshots__/link.test.ts.snap +++ b/tests/router/__snapshots__/link.test.ts.snap @@ -5,17 +5,17 @@ exports[`Link component can render simple cases 1`] = ` ) { // Template name: \\"__template__1\\" let utils = this.constructor.utils; - let owner = context; + let scope = Object.create(context); var h = this.h; - let _5 = utils.toObj({'router-link-active':context['isActive']}); - var _6 = context['href']; + let _5 = utils.toObj({'router-link-active':scope['isActive']}); + var _6 = scope['href']; let c7 = [], p7 = {key:7,attrs:{href: _6},class:_5,on:{}}; var vn7 = h('a', p7, c7); - extra.handlers['click' + 7] = extra.handlers['click' + 7] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['navigate'];if (fn) { fn.call(owner, e); } else { context.navigate; }}; + extra.handlers['click' + 7] = extra.handlers['click' + 7] || function (e) {if (!context.__owl__.isMounted){return}const fn = context['navigate'];if (fn) { fn.call(context, e); } else { context.navigate; }}; p7.on['click'] = extra.handlers['click' + 7]; const slot8 = this.constructor.slots[context.__owl__.slotId + '_' + 'default']; if (slot8) { - slot8.call(this, context.__owl__.parent, Object.assign({}, extra, {parentNode: c7, parent: extra.parent || owner, vars: extra.fiber.vars})); + slot8.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c7, parent: extra.parent || context})); } return vn7; }" diff --git a/tests/router/__snapshots__/route_component.test.ts.snap b/tests/router/__snapshots__/route_component.test.ts.snap index 1363cd08..ef0b4148 100644 --- a/tests/router/__snapshots__/route_component.test.ts.snap +++ b/tests/router/__snapshots__/route_component.test.ts.snap @@ -7,32 +7,32 @@ exports[`RouteComponent can render simple cases 1`] = ` let utils = this.constructor.utils; let QWeb = this.constructor; let parent = context; - let owner = context; + let scope = Object.create(context); let result; var h = this.h; - if (context['routeComponent']) { - const nodeKey5 = context['env'].router.currentRouteName; + if (scope['routeComponent']) { + const nodeKey5 = scope['env'].router.currentRouteName; //COMPONENT let k7 = \`__8__\` + nodeKey5; let w6 = k7 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k7]] : false; let vn9 = {}; result = vn9; - let props6 = Object.assign({}, context['env'].router.currentParams); + let props6 = Object.assign({}, scope['env'].router.currentParams); if (w6 && w6.__owl__.currentFiber && !w6.__owl__.vnode) { w6.destroy(); w6 = false; } if (w6) { - w6.__updateProps(props6, extra.fiber, undefined, undefined); + w6.__updateProps(props6, extra.fiber, undefined); let pvnode = w6.__owl__.pvnode; utils.defineProxy(vn9, pvnode); } else { let componentKey6 = \`routeComponent\`; - let W6 = context.constructor.components[componentKey6] || QWeb.components[componentKey6]|| context['routeComponent']; + let W6 = context.constructor.components[componentKey6] || QWeb.components[componentKey6]|| scope['routeComponent']; if (!W6) {throw new Error('Cannot find the definition of component \\"' + componentKey6 + '\\"')} w6 = new W6(parent, props6); parent.__owl__.cmap[k7] = w6.__owl__.id; - let fiber = w6.__prepare(extra.fiber, undefined, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let fiber = w6.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); let pvnode = h('dummy', {key: k7, hook: {remove() {},destroy(vn) {w6.destroy();}}}); utils.defineProxy(vn9, pvnode); w6.__owl__.pvnode = pvnode; diff --git a/tests/tooling/debug_script_3.test.ts b/tests/tooling/debug_script_3.test.ts index 0822bde8..821f89e7 100644 --- a/tests/tooling/debug_script_3.test.ts +++ b/tests/tooling/debug_script_3.test.ts @@ -23,7 +23,7 @@ test("log a specific message for render method calls if component is not mounted class Parent extends Component { static template = xml`
`; - state = owl.hooks.useState({value: 1}); + state = owl.hooks.useState({ value: 1 }); } const parent = new Parent(null, {});