1+ import { isBlank , isPresent } from 'angular2/src/core/facade/lang' ;
2+ import {
3+ RenderEventDispatcher ,
4+ RenderTemplateCmd ,
5+ RenderCommandVisitor ,
6+ RenderBeginElementCmd ,
7+ RenderBeginComponentCmd ,
8+ RenderNgContentCmd ,
9+ RenderTextCmd ,
10+ RenderEmbeddedTemplateCmd
11+ } from './api' ;
12+ import { DefaultRenderView , DefaultRenderFragmentRef } from './view' ;
13+
14+ export function createRenderView ( fragmentCmds : RenderTemplateCmd [ ] , inplaceElement : any ,
15+ nodeFactory : NodeFactory < any > ) : DefaultRenderView < any > {
16+ var builders : RenderViewBuilder < any > [ ] = [ ] ;
17+ visitAll ( new RenderViewBuilder < any > ( null , null , inplaceElement , builders , nodeFactory ) ,
18+ fragmentCmds ) ;
19+ var boundElements : any [ ] = [ ] ;
20+ var boundTextNodes : any [ ] = [ ] ;
21+ var nativeShadowRoots : any [ ] = [ ] ;
22+ var fragments : DefaultRenderFragmentRef < any > [ ] = [ ] ;
23+ var viewElementOffset = 0 ;
24+ var view : DefaultRenderView < any > ;
25+ var eventDispatcher = ( boundElementIndex : number , eventName : string , event : any ) =>
26+ view . dispatchRenderEvent ( boundElementIndex , eventName , event ) ;
27+ var globalEventAdders : Function [ ] = [ ] ;
28+
29+ for ( var i = 0 ; i < builders . length ; i ++ ) {
30+ var builder = builders [ i ] ;
31+ addAll ( builder . boundElements , boundElements ) ;
32+ addAll ( builder . boundTextNodes , boundTextNodes ) ;
33+ addAll ( builder . nativeShadowRoots , nativeShadowRoots ) ;
34+ if ( isBlank ( builder . rootNodesParent ) ) {
35+ fragments . push ( new DefaultRenderFragmentRef < any > ( builder . fragmentRootNodes ) ) ;
36+ }
37+ for ( var j = 0 ; j < builder . eventData . length ; j ++ ) {
38+ var eventData = builder . eventData [ j ] ;
39+ var boundElementIndex = eventData [ 0 ] + viewElementOffset ;
40+ var target = eventData [ 1 ] ;
41+ var eventName = eventData [ 2 ] ;
42+ if ( isPresent ( target ) ) {
43+ var handler =
44+ createEventHandler ( boundElementIndex , `${ target } :${ eventName } ` , eventDispatcher ) ;
45+ globalEventAdders . push ( createGlobalEventAdder ( target , eventName , handler , nodeFactory ) ) ;
46+ } else {
47+ var handler = createEventHandler ( boundElementIndex , eventName , eventDispatcher ) ;
48+ nodeFactory . on ( boundElements [ boundElementIndex ] , eventName , handler ) ;
49+ }
50+ }
51+ viewElementOffset += builder . boundElements . length ;
52+ }
53+ view = new DefaultRenderView < any > ( fragments , boundTextNodes , boundElements , nativeShadowRoots ,
54+ globalEventAdders ) ;
55+ return view ;
56+ }
57+
58+ function createEventHandler ( boundElementIndex : number , eventName : string ,
59+ eventDispatcher : Function ) : Function {
60+ return ( $event ) => eventDispatcher ( boundElementIndex , eventName , $event ) ;
61+ }
62+
63+ function createGlobalEventAdder ( target : string , eventName : string , eventHandler : Function ,
64+ nodeFactory : NodeFactory < any > ) : Function {
65+ return ( ) => nodeFactory . globalOn ( target , eventName , eventHandler ) ;
66+ }
67+
68+ export interface NodeFactory < N > {
69+ resolveComponentTemplate ( templateId : number ) : RenderTemplateCmd [ ] ;
70+ createTemplateAnchor ( attrNameAndValues : string [ ] ) : N ;
71+ createElement ( name : string , attrNameAndValues : string [ ] ) : N ;
72+ mergeElement ( existing : N , attrNameAndValues : string [ ] ) ;
73+ createShadowRoot ( host : N ) : N ;
74+ createText ( value : string ) : N ;
75+ appendChild ( parent : N , child : N ) ;
76+ on ( element : N , eventName : string , callback : Function ) ;
77+ globalOn ( target : string , eventName : string , callback : Function ) : Function ;
78+ }
79+
80+ class RenderViewBuilder < N > implements RenderCommandVisitor {
81+ parentStack : Array < N | Component < N > > ;
82+ boundTextNodes : N [ ] = [ ] ;
83+ boundElements : N [ ] = [ ] ;
84+ eventData : any [ ] [ ] = [ ] ;
85+
86+ fragmentRootNodes : N [ ] = [ ] ;
87+ nativeShadowRoots : N [ ] = [ ] ;
88+
89+ constructor ( public parentComponent : Component < N > , public rootNodesParent : N ,
90+ public inplaceElement : N , public allBuilders : RenderViewBuilder < N > [ ] ,
91+ public factory : NodeFactory < N > ) {
92+ this . parentStack = [ rootNodesParent ] ;
93+ allBuilders . push ( this ) ;
94+ }
95+
96+ get parent ( ) : N | Component < N > { return this . parentStack [ this . parentStack . length - 1 ] ; }
97+
98+ visitText ( cmd : RenderTextCmd , context : any ) : any {
99+ var text = this . factory . createText ( cmd . value ) ;
100+ this . _addChild ( text , cmd . ngContentIndex ) ;
101+ if ( cmd . isBound ) {
102+ this . boundTextNodes . push ( text ) ;
103+ }
104+ return null ;
105+ }
106+ visitNgContent ( cmd : RenderNgContentCmd , context : any ) : any {
107+ if ( isPresent ( this . parentComponent ) ) {
108+ var projectedNodes = this . parentComponent . project ( ) ;
109+ for ( var i = 0 ; i < projectedNodes . length ; i ++ ) {
110+ var node = projectedNodes [ i ] ;
111+ this . _addChild ( node , cmd . ngContentIndex ) ;
112+ }
113+ }
114+ return null ;
115+ }
116+ visitBeginElement ( cmd : RenderBeginElementCmd , context : any ) : any {
117+ this . parentStack . push ( this . _beginElement ( cmd ) ) ;
118+ return null ;
119+ }
120+ visitEndElement ( context : any ) : any {
121+ this . _endElement ( ) ;
122+ return null ;
123+ }
124+ visitBeginComponent ( cmd : RenderBeginComponentCmd , context : any ) : any {
125+ var el = this . _beginElement ( cmd ) ;
126+ var root = el ;
127+ if ( cmd . nativeShadow ) {
128+ root = this . factory . createShadowRoot ( el ) ;
129+ this . nativeShadowRoots . push ( root ) ;
130+ }
131+ this . parentStack . push ( new Component ( el , root , cmd , this . factory ) ) ;
132+ return null ;
133+ }
134+ visitEndComponent ( context : any ) : any {
135+ var c = < Component < N > > this . parent ;
136+ var template = this . factory . resolveComponentTemplate ( c . cmd . templateId ) ;
137+ this . _visitChildTemplate ( template , c , c . shadowRoot ) ;
138+ this . _endElement ( ) ;
139+ return null ;
140+ }
141+ visitEmbeddedTemplate ( cmd : RenderEmbeddedTemplateCmd , context : any ) : any {
142+ var el = this . factory . createTemplateAnchor ( cmd . attrNameAndValues ) ;
143+ this . _addChild ( el , cmd . ngContentIndex ) ;
144+ this . boundElements . push ( el ) ;
145+ if ( cmd . isMerged ) {
146+ this . _visitChildTemplate ( cmd . children , this . parentComponent , null ) ;
147+ }
148+ return null ;
149+ }
150+
151+ private _beginElement ( cmd : RenderBeginElementCmd ) : N {
152+ var el : N ;
153+ if ( isPresent ( this . inplaceElement ) ) {
154+ el = this . inplaceElement ;
155+ this . inplaceElement = null ;
156+ this . factory . mergeElement ( el , cmd . attrNameAndValues ) ;
157+ this . fragmentRootNodes . push ( el ) ;
158+ } else {
159+ el = this . factory . createElement ( cmd . name , cmd . attrNameAndValues ) ;
160+ this . _addChild ( el , cmd . ngContentIndex ) ;
161+ }
162+ if ( cmd . isBound ) {
163+ this . boundElements . push ( el ) ;
164+ for ( var i = 0 ; i < cmd . eventTargetAndNames . length ; i += 2 ) {
165+ var target = cmd . eventTargetAndNames [ i ] ;
166+ var eventName = cmd . eventTargetAndNames [ i + 1 ] ;
167+ this . eventData . push ( [ this . boundElements . length - 1 , target , eventName ] ) ;
168+ }
169+ }
170+ return el ;
171+ }
172+
173+ private _endElement ( ) { this . parentStack . pop ( ) ; }
174+
175+ private _visitChildTemplate ( cmds : RenderTemplateCmd [ ] , parent : Component < N > , rootNodesParent : N ) {
176+ visitAll ( new RenderViewBuilder ( parent , rootNodesParent , null , this . allBuilders , this . factory ) ,
177+ cmds ) ;
178+ }
179+
180+ private _addChild ( node : N , ngContentIndex : number ) {
181+ var parent = this . parent ;
182+ if ( isPresent ( parent ) ) {
183+ if ( parent instanceof Component ) {
184+ parent . addContentNode ( ngContentIndex , node ) ;
185+ } else {
186+ this . factory . appendChild ( < N > parent , node ) ;
187+ }
188+ } else {
189+ this . fragmentRootNodes . push ( node ) ;
190+ }
191+ }
192+ }
193+
194+ class Component < N > {
195+ private contentNodesByNgContentIndex : N [ ] [ ] = [ ] ;
196+ private projectingNgContentIndex : number = 0 ;
197+
198+ constructor ( public hostElement : N , public shadowRoot : N , public cmd : RenderBeginComponentCmd ,
199+ public factory : NodeFactory < N > ) { }
200+ addContentNode ( ngContentIndex : number , node : N ) {
201+ if ( isBlank ( ngContentIndex ) ) {
202+ if ( this . cmd . nativeShadow ) {
203+ this . factory . appendChild ( this . hostElement , node ) ;
204+ }
205+ } else {
206+ while ( this . contentNodesByNgContentIndex . length <= ngContentIndex ) {
207+ this . contentNodesByNgContentIndex . push ( [ ] ) ;
208+ }
209+ this . contentNodesByNgContentIndex [ ngContentIndex ] . push ( node ) ;
210+ }
211+ }
212+ project ( ) : N [ ] {
213+ var ngContentIndex = this . projectingNgContentIndex ++ ;
214+ return ngContentIndex < this . contentNodesByNgContentIndex . length ?
215+ this . contentNodesByNgContentIndex [ ngContentIndex ] :
216+ [ ] ;
217+ }
218+ }
219+
220+ function addAll ( source : any [ ] , target : any [ ] ) {
221+ for ( var i = 0 ; i < source . length ; i ++ ) {
222+ target . push ( source [ i ] ) ;
223+ }
224+ }
225+
226+ function visitAll ( visitor : RenderCommandVisitor , fragmentCmds : RenderTemplateCmd [ ] ) {
227+ for ( var i = 0 ; i < fragmentCmds . length ; i ++ ) {
228+ fragmentCmds [ i ] . visit ( visitor , null ) ;
229+ }
230+ }
0 commit comments