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, {});