@@ -32,6 +32,8 @@ import {
3232} from "./parser" ;
3333import { OwlError } from "../common/owl_error" ;
3434
35+ const zero = Symbol ( "" ) ;
36+
3537type BlockType = "block" | "text" | "multi" | "list" | "html" | "comment" ;
3638const whitespaceRE = / \s + / g;
3739
@@ -279,7 +281,7 @@ export class CodeGenerator {
279281 translatableAttributes : string [ ] = TRANSLATABLE_ATTRS ;
280282 ast : AST ;
281283 staticDefs : { id : string ; expr : string } [ ] = [ ] ;
282- slotNames : Set < String > = new Set ( ) ;
284+ slotNames : Set < String | Symbol > = new Set ( ) ;
283285 helpers : Set < string > = new Set ( ) ;
284286
285287 constructor ( ast : AST , options : CodeGenOptions ) {
@@ -791,12 +793,24 @@ export class CodeGenerator {
791793 return block ! . varName ;
792794 }
793795
796+ compileZero ( ) {
797+ this . helpers . add ( "zero" ) ;
798+ this . helpers . add ( "zero2" ) ;
799+ this . helpers . add ( "callLazyBlock" ) ;
800+ const isMultiple = this . slotNames . has ( zero ) ;
801+ this . slotNames . add ( zero ) ;
802+ let key = this . target . loopLevel ? `key${ this . target . loopLevel } ` : "key" ;
803+ if ( isMultiple ) {
804+ key = this . generateComponentKey ( key ) ;
805+ }
806+ return `zero2 in ctx ? callLazyBlock(ctx[zero2], node, ${ key } ) : ctx[zero]` ;
807+ }
808+
794809 compileTEsc ( ast : ASTTEsc , ctx : Context ) : string {
795810 let { block, forceNewBlock } = ctx ;
796811 let expr : string ;
797812 if ( ast . expr === "0" ) {
798- this . helpers . add ( "zero" ) ;
799- expr = `ctx[zero]` ;
813+ expr = this . compileZero ( ) ;
800814 } else {
801815 expr = compileExpr ( ast . expr ) ;
802816 if ( ast . defaultValue ) {
@@ -824,8 +838,7 @@ export class CodeGenerator {
824838 block = this . createBlock ( block , "html" , ctx ) ;
825839 let blockStr ;
826840 if ( ast . expr === "0" ) {
827- this . helpers . add ( "zero" ) ;
828- blockStr = `ctx[zero]` ;
841+ blockStr = this . compileZero ( ) ;
829842 } else if ( ast . body ) {
830843 let bodyValue = null ;
831844 bodyValue = BlockDescription . nextBlockId ;
@@ -1044,50 +1057,76 @@ export class CodeGenerator {
10441057
10451058 compileTCall ( ast : ASTTCall , ctx : Context ) : string {
10461059 let { block, forceNewBlock } = ctx ;
1060+
1061+ const attrs : string [ ] = ast . attrs
1062+ ? this . formatPropObject ( ast . attrs , ast . attrsTranslationCtx , ctx . translationCtx )
1063+ : [ ] ;
10471064 let ctxVar = ctx . ctxVar || "ctx" ;
1048- if ( ast . context ) {
1065+ if ( ! ast . attrs && ast . context ) {
10491066 ctxVar = generateId ( "ctx" ) ;
10501067 this . addLine ( `let ${ ctxVar } = ${ compileExpr ( ast . context ) } ;` ) ;
10511068 }
1069+
10521070 const isDynamic = INTERP_REGEXP . test ( ast . name ) ;
10531071 const subTemplate = isDynamic ? interpolate ( ast . name ) : "`" + ast . name + "`" ;
10541072 if ( block && ! forceNewBlock ) {
10551073 this . insertAnchor ( block ) ;
10561074 }
10571075 block = this . createBlock ( block , "multi" , ctx ) ;
1076+
10581077 if ( ast . body ) {
1059- this . addLine ( `${ ctxVar } = Object.create(${ ctxVar } );` ) ;
1060- this . addLine ( `${ ctxVar } [isBoundary] = 1;` ) ;
1061- this . helpers . add ( "isBoundary" ) ;
1062- const subCtx = createContext ( ctx , { ctxVar } ) ;
1063- const bl = this . compileMulti ( { type : ASTType . Multi , content : ast . body } , subCtx ) ;
1064- if ( bl ) {
1065- this . helpers . add ( "zero" ) ;
1066- this . addLine ( `${ ctxVar } [zero] = ${ bl } ;` ) ;
1078+ if ( ast . attrs ) {
1079+ let ctxStr = "ctx" ;
1080+ if ( this . target . loopLevel || ! this . hasSafeContext ) {
1081+ ctxStr = generateId ( "ctx" ) ;
1082+ this . helpers . add ( "capture" ) ;
1083+ this . define ( ctxStr , `capture(ctx)` ) ;
1084+ }
1085+ const name = this . compileInNewTarget ( "call_body" , ast . body , ctx ) ;
1086+ this . helpers . add ( "zero2" ) ;
1087+ attrs . push ( `[zero2]: {__render: ${ name } .bind(this), __ctx: ${ ctxStr } }` ) ;
1088+ } else {
1089+ this . addLine ( `${ ctxVar } = Object.create(${ ctxVar } );` ) ;
1090+ this . addLine ( `${ ctxVar } [isBoundary] = 1;` ) ;
1091+ this . helpers . add ( "isBoundary" ) ;
1092+ const subCtx = createContext ( ctx , { ctxVar } ) ;
1093+ const bl = this . compileAST ( ast . body , subCtx ) ;
1094+ if ( bl ) {
1095+ this . helpers . add ( "zero" ) ;
1096+ this . addLine ( `${ ctxVar } [zero] = ${ bl } ;` ) ;
1097+ }
10671098 }
10681099 }
10691100
1101+ let ctxString = `{${ attrs . join ( ", " ) } }` ;
1102+ if ( ast . attrs && ast . context ) {
1103+ const dynCtxVar = generateId ( "ctx" ) ;
1104+ this . addLine ( `let ${ dynCtxVar } = ${ compileExpr ( ast . context ) } ;` ) ;
1105+ ctxString = `Object.assign({}, ${ dynCtxVar } ${ attrs . length ? ", " + ctxString : "" } )` ;
1106+ }
1107+
1108+ const ctxExpr = ast . attrs ? ctxString : ctxVar ;
10701109 const key = this . generateComponentKey ( ) ;
10711110 if ( isDynamic ) {
10721111 const templateVar = generateId ( "template" ) ;
10731112 if ( ! this . staticDefs . find ( ( d ) => d . id === "call" ) ) {
10741113 this . staticDefs . push ( { id : "call" , expr : `app.callTemplate.bind(app)` } ) ;
10751114 }
10761115 this . define ( templateVar , subTemplate ) ;
1077- this . insertBlock ( `call(this, ${ templateVar } , ${ ctxVar } , node, ${ key } )` , block ! , {
1116+ this . insertBlock ( `call(this, ${ templateVar } , ${ ctxExpr } , node, ${ key } )` , block ! , {
10781117 ...ctx ,
10791118 forceNewBlock : ! block ,
10801119 } ) ;
10811120 } else {
10821121 const id = generateId ( `callTemplate_` ) ;
10831122 this . staticDefs . push ( { id, expr : `app.getTemplate(${ subTemplate } )` } ) ;
1084- this . insertBlock ( `${ id } .call(this, ${ ctxVar } , node, ${ key } )` , block ! , {
1123+ this . insertBlock ( `${ id } .call(this, ${ ctxExpr } , node, ${ key } )` , block ! , {
10851124 ...ctx ,
10861125 forceNewBlock : ! block ,
10871126 } ) ;
10881127 }
1089- if ( ast . body && ! ctx . isLast ) {
1090- this . addLine ( `${ ctxVar } = ${ ctxVar } .__proto__;` ) ;
1128+ if ( ! ast . attrs && ast . body && ! ctx . isLast ) {
1129+ this . addLine ( `${ ctxExpr } = ${ ctxExpr } .__proto__;` ) ;
10911130 }
10921131 return block . varName ;
10931132 }
0 commit comments