feat(view): add imperative views
This commit is contained in:
		
							parent
							
								
									817c79ca77
								
							
						
					
					
						commit
						ada1e642c5
					
				
							
								
								
									
										2
									
								
								modules/angular2/angular2.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								modules/angular2/angular2.js
									
									
									
									
										vendored
									
									
								
							| @ -4,3 +4,5 @@ export * from './annotations'; | |||||||
| export * from './directives'; | export * from './directives'; | ||||||
| export * from './forms'; | export * from './forms'; | ||||||
| export {Observable, EventEmitter} from 'angular2/src/facade/async'; | export {Observable, EventEmitter} from 'angular2/src/facade/async'; | ||||||
|  | export * from 'angular2/src/render/api'; | ||||||
|  | export {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer'; | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								modules/angular2/src/core/annotations/view.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								modules/angular2/src/core/annotations/view.js
									
									
									
									
										vendored
									
									
								
							| @ -71,19 +71,28 @@ export class View { | |||||||
|    */ |    */ | ||||||
|   directives:any; //List<Type>;
 |   directives:any; //List<Type>;
 | ||||||
| 
 | 
 | ||||||
|  |   /** | ||||||
|  |    * Specify a custom renderer for this View. | ||||||
|  |    * If this is set, neither `template`, `templateURL` nor `directives` are used. | ||||||
|  |    */ | ||||||
|  |   renderer:any; // string;
 | ||||||
|  | 
 | ||||||
|   @CONST() |   @CONST() | ||||||
|   constructor({ |   constructor({ | ||||||
|       templateUrl, |       templateUrl, | ||||||
|       template, |       template, | ||||||
|       directives |       directives, | ||||||
|  |       renderer | ||||||
|     }: { |     }: { | ||||||
|       templateUrl: string, |       templateUrl: string, | ||||||
|       template: string, |       template: string, | ||||||
|       directives: List<Type> |       directives: List<Type>, | ||||||
|  |       renderer: string | ||||||
|     }) |     }) | ||||||
|   { |   { | ||||||
|     this.templateUrl = templateUrl; |     this.templateUrl = templateUrl; | ||||||
|     this.template = template; |     this.template = template; | ||||||
|     this.directives = directives; |     this.directives = directives; | ||||||
|  |     this.renderer = renderer; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										7
									
								
								modules/angular2/src/core/application.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								modules/angular2/src/core/application.js
									
									
									
									
										vendored
									
									
								
							| @ -75,7 +75,7 @@ function _injectorBindings(appComponentType): List<Binding> { | |||||||
|         // We need to do this here to ensure that we create Testability and
 |         // We need to do this here to ensure that we create Testability and
 | ||||||
|         // it's ready on the window for users.
 |         // it's ready on the window for users.
 | ||||||
|         registry.registerApplication(appElement, testability); |         registry.registerApplication(appElement, testability); | ||||||
|         return dynamicComponentLoader.loadIntoNewLocation(appElement, appComponentAnnotatedType.type, injector); |         return dynamicComponentLoader.loadIntoNewLocation(appComponentAnnotatedType.type, null, appElement, injector); | ||||||
|       }, [DynamicComponentLoader, Injector, appElementToken, appComponentAnnotatedTypeToken, |       }, [DynamicComponentLoader, Injector, appElementToken, appComponentAnnotatedTypeToken, | ||||||
|         Testability, TestabilityRegistry]), |         Testability, TestabilityRegistry]), | ||||||
| 
 | 
 | ||||||
| @ -91,6 +91,7 @@ function _injectorBindings(appComponentType): List<Binding> { | |||||||
|       bind(ShadowDomStrategy).toFactory( |       bind(ShadowDomStrategy).toFactory( | ||||||
|           (styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head), |           (styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head), | ||||||
|           [StyleUrlResolver, appDocumentToken]), |           [StyleUrlResolver, appDocumentToken]), | ||||||
|  |       DirectDomRenderer, | ||||||
|       bind(Renderer).toClass(DirectDomRenderer), |       bind(Renderer).toClass(DirectDomRenderer), | ||||||
|       bind(rc.Compiler).toClass(rc.DefaultCompiler), |       bind(rc.Compiler).toClass(rc.DefaultCompiler), | ||||||
|       // TODO(tbosch): We need an explicit factory here, as
 |       // TODO(tbosch): We need an explicit factory here, as
 | ||||||
| @ -105,8 +106,8 @@ function _injectorBindings(appComponentType): List<Binding> { | |||||||
|       // TODO(tbosch): We need an explicit factory here, as
 |       // TODO(tbosch): We need an explicit factory here, as
 | ||||||
|       // we are getting errors in dart2js with mirrors...
 |       // we are getting errors in dart2js with mirrors...
 | ||||||
|       bind(ViewFactory).toFactory( |       bind(ViewFactory).toFactory( | ||||||
|         (capacity, renderer, appViewHydrator) => new ViewFactory(capacity, renderer, appViewHydrator), |         (capacity, renderer) => new ViewFactory(capacity, renderer), | ||||||
|         [VIEW_POOL_CAPACITY, Renderer, AppViewHydrator] |         [VIEW_POOL_CAPACITY, Renderer] | ||||||
|       ), |       ), | ||||||
|       bind(VIEW_POOL_CAPACITY).toValue(10000), |       bind(VIEW_POOL_CAPACITY).toValue(10000), | ||||||
|       AppViewHydrator, |       AppViewHydrator, | ||||||
|  | |||||||
| @ -114,6 +114,12 @@ export class Compiler { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     var template = this._templateResolver.resolve(component); |     var template = this._templateResolver.resolve(component); | ||||||
|  |     if (isPresent(template.renderer)) { | ||||||
|  |       var directives = []; | ||||||
|  |       pvPromise = this._renderer.createImperativeComponentProtoView(template.renderer).then( (renderPv) => { | ||||||
|  |         return this._compileNestedProtoViews(componentBinding, renderPv, directives, true); | ||||||
|  |       }); | ||||||
|  |     } else { | ||||||
|       var directives = ListWrapper.map( |       var directives = ListWrapper.map( | ||||||
|         this._flattenDirectives(template), |         this._flattenDirectives(template), | ||||||
|         (directive) => this._bindDirective(directive) |         (directive) => this._bindDirective(directive) | ||||||
| @ -122,6 +128,7 @@ export class Compiler { | |||||||
|       pvPromise = this._renderer.compile(renderTemplate).then( (renderPv) => { |       pvPromise = this._renderer.compile(renderTemplate).then( (renderPv) => { | ||||||
|         return this._compileNestedProtoViews(componentBinding, renderPv, directives, true); |         return this._compileNestedProtoViews(componentBinding, renderPv, directives, true); | ||||||
|       }); |       }); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     MapWrapper.set(this._compiling, component, pvPromise); |     MapWrapper.set(this._compiling, component, pvPromise); | ||||||
|     return pvPromise; |     return pvPromise; | ||||||
|  | |||||||
| @ -70,15 +70,10 @@ export class DynamicComponentLoader { | |||||||
| 
 | 
 | ||||||
|     return this._compiler.compile(type).then(componentProtoView => { |     return this._compiler.compile(type).then(componentProtoView => { | ||||||
|       var componentView = this._viewFactory.getView(componentProtoView); |       var componentView = this._viewFactory.getView(componentProtoView); | ||||||
|       var hostView = location.hostView; |  | ||||||
|       this._viewHydrator.hydrateDynamicComponentView( |       this._viewHydrator.hydrateDynamicComponentView( | ||||||
|         hostView, location.boundElementIndex, componentView, componentBinding, injector); |         location, componentView, componentBinding, injector); | ||||||
| 
 | 
 | ||||||
|       // TODO(vsavkin): return a component ref that dehydrates the component view and removes it
 |       var dispose = () => {throw new BaseException("Not implemented");}; | ||||||
|       // from the component child views
 |  | ||||||
|       // See ViewFactory.returnView
 |  | ||||||
|       // See AppViewHydrator.dehydrateDynamicComponentView
 |  | ||||||
|       var dispose = () => {throw "Not implemented";}; |  | ||||||
|       return new ComponentRef(location, location.elementInjector.getDynamicallyLoadedComponent(), componentView, dispose); |       return new ComponentRef(location, location.elementInjector.getDynamicallyLoadedComponent(), componentView, dispose); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| @ -87,19 +82,22 @@ export class DynamicComponentLoader { | |||||||
|    * Loads a component in the element specified by elementOrSelector. The loaded component receives |    * Loads a component in the element specified by elementOrSelector. The loaded component receives | ||||||
|    * injection normally as a hosted view. |    * injection normally as a hosted view. | ||||||
|    */ |    */ | ||||||
|   loadIntoNewLocation(elementOrSelector:any, type:Type, injector:Injector = null):Promise<ComponentRef> { |   loadIntoNewLocation(type:Type, parentComponentLocation:ElementRef, elementOrSelector:any, | ||||||
|  |                       injector:Injector = null):Promise<ComponentRef> { | ||||||
|     this._assertTypeIsComponent(type); |     this._assertTypeIsComponent(type); | ||||||
| 
 | 
 | ||||||
|     return  this._compiler.compileInHost(type).then(hostProtoView => { |     return  this._compiler.compileInHost(type).then(hostProtoView => { | ||||||
|       var hostView = this._viewFactory.getView(hostProtoView); |       var hostView = this._viewFactory.getView(hostProtoView); | ||||||
|       this._viewHydrator.hydrateInPlaceHostView(null, elementOrSelector, hostView, injector); |       this._viewHydrator.hydrateInPlaceHostView( | ||||||
|  |         parentComponentLocation, elementOrSelector, hostView, injector | ||||||
|  |       ); | ||||||
| 
 | 
 | ||||||
|       // TODO(vsavkin): return a component ref that dehydrates the host view
 |  | ||||||
|       // See ViewFactory.returnView
 |  | ||||||
|       // See AppViewHydrator.dehydrateInPlaceHostView
 |  | ||||||
|       var newLocation = hostView.elementInjectors[0].getElementRef(); |       var newLocation = hostView.elementInjectors[0].getElementRef(); | ||||||
|       var component = hostView.elementInjectors[0].getComponent(); |       var component = hostView.elementInjectors[0].getComponent(); | ||||||
|       var dispose = () => {throw "Not implemented";}; |       var dispose = () => { | ||||||
|  |         this._viewHydrator.dehydrateInPlaceHostView(parentComponentLocation, hostView); | ||||||
|  |         this._viewFactory.returnView(hostView); | ||||||
|  |       }; | ||||||
|       return new ComponentRef(newLocation, component, hostView.componentChildViews[0], dispose); |       return new ComponentRef(newLocation, component, hostView.componentChildViews[0], dispose); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -26,27 +26,21 @@ var _staticKeys; | |||||||
|  * @exportedAs angular2/view |  * @exportedAs angular2/view | ||||||
|  */ |  */ | ||||||
| export class ElementRef { | export class ElementRef { | ||||||
|  |   hostView:viewModule.AppView; | ||||||
|  |   boundElementIndex:number; | ||||||
|  |   injector:Injector; | ||||||
|   elementInjector:ElementInjector; |   elementInjector:ElementInjector; | ||||||
| 
 | 
 | ||||||
|   constructor(elementInjector:ElementInjector){ |   constructor(elementInjector, hostView, boundElementIndex, injector){ | ||||||
|     this.elementInjector = elementInjector; |     this.elementInjector = elementInjector; | ||||||
|   } |     this.hostView = hostView; | ||||||
| 
 |     this.boundElementIndex = boundElementIndex; | ||||||
|   get hostView() { |     this.injector = injector; | ||||||
|     return this.elementInjector._preBuiltObjects.view; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   get viewContainer() { |   get viewContainer() { | ||||||
|     return this.hostView.getOrCreateViewContainer(this.boundElementIndex); |     return this.hostView.getOrCreateViewContainer(this.boundElementIndex); | ||||||
|   } |   } | ||||||
| 
 |  | ||||||
|   get injector() { |  | ||||||
|     return this.elementInjector._lightDomAppInjector; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   get boundElementIndex() { |  | ||||||
|     return this.elementInjector._proto.index; |  | ||||||
|   } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class StaticKeys { | class StaticKeys { | ||||||
| @ -673,7 +667,7 @@ export class ElementInjector extends TreeNode { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   getElementRef() { |   getElementRef() { | ||||||
|     return new ElementRef(this); |     return new ElementRef(this, this._preBuiltObjects.view, this._proto.index, this._lightDomAppInjector); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   getDynamicallyLoadedComponent() { |   getDynamicallyLoadedComponent() { | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								modules/angular2/src/core/compiler/view.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								modules/angular2/src/core/compiler/view.js
									
									
									
									
										vendored
									
									
								
							| @ -25,6 +25,9 @@ export class AppView { | |||||||
|   elementInjectors:List<ElementInjector>; |   elementInjectors:List<ElementInjector>; | ||||||
|   changeDetector:ChangeDetector; |   changeDetector:ChangeDetector; | ||||||
|   componentChildViews: List<AppView>; |   componentChildViews: List<AppView>; | ||||||
|  |   /// Host views that were added by an imperative view.
 | ||||||
|  |   /// This is a dynamically growing / shrinking array.
 | ||||||
|  |   imperativeHostViews: List<AppView>; | ||||||
|   viewContainers: List<ViewContainer>; |   viewContainers: List<ViewContainer>; | ||||||
|   preBuiltObjects: List<PreBuiltObjects>; |   preBuiltObjects: List<PreBuiltObjects>; | ||||||
|   proto: AppProtoView; |   proto: AppProtoView; | ||||||
| @ -46,7 +49,7 @@ export class AppView { | |||||||
|    */ |    */ | ||||||
|   locals:Locals; |   locals:Locals; | ||||||
| 
 | 
 | ||||||
|   constructor(renderer:renderApi.Renderer, viewFactory:vfModule.ViewFactory, viewHydrator:vhModule.AppViewHydrator, proto:AppProtoView, protoLocals:Map) { |   constructor(renderer:renderApi.Renderer, viewFactory:vfModule.ViewFactory, proto:AppProtoView, protoLocals:Map) { | ||||||
|     this.render = null; |     this.render = null; | ||||||
|     this.proto = proto; |     this.proto = proto; | ||||||
|     this.changeDetector = null; |     this.changeDetector = null; | ||||||
| @ -59,7 +62,8 @@ export class AppView { | |||||||
|     this.locals = new Locals(null, MapWrapper.clone(protoLocals)); //TODO optimize this
 |     this.locals = new Locals(null, MapWrapper.clone(protoLocals)); //TODO optimize this
 | ||||||
|     this.renderer = renderer; |     this.renderer = renderer; | ||||||
|     this.viewFactory = viewFactory; |     this.viewFactory = viewFactory; | ||||||
|     this.viewHydrator = viewHydrator; |     this.viewHydrator = null; | ||||||
|  |     this.imperativeHostViews = []; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List, |   init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List, | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang'; | |||||||
| import {NgElement} from 'angular2/src/core/compiler/ng_element'; | import {NgElement} from 'angular2/src/core/compiler/ng_element'; | ||||||
| import * as viewModule from './view'; | import * as viewModule from './view'; | ||||||
| import {Renderer} from 'angular2/src/render/api'; | import {Renderer} from 'angular2/src/render/api'; | ||||||
| import {AppViewHydrator} from './view_hydrator'; |  | ||||||
| 
 | 
 | ||||||
| // TODO(tbosch): Make this an OpaqueToken as soon as our transpiler supports this!
 | // TODO(tbosch): Make this an OpaqueToken as soon as our transpiler supports this!
 | ||||||
| export const VIEW_POOL_CAPACITY = 'ViewFactory.viewPoolCapacity'; | export const VIEW_POOL_CAPACITY = 'ViewFactory.viewPoolCapacity'; | ||||||
| @ -15,13 +14,11 @@ export class ViewFactory { | |||||||
|   _poolCapacityPerProtoView:number; |   _poolCapacityPerProtoView:number; | ||||||
|   _pooledViewsPerProtoView:Map<viewModule.AppProtoView, List<viewModule.AppView>>; |   _pooledViewsPerProtoView:Map<viewModule.AppProtoView, List<viewModule.AppView>>; | ||||||
|   _renderer:Renderer; |   _renderer:Renderer; | ||||||
|   _viewHydrator:AppViewHydrator; |  | ||||||
| 
 | 
 | ||||||
|   constructor(@Inject(VIEW_POOL_CAPACITY) poolCapacityPerProtoView, renderer:Renderer, viewHydrator:AppViewHydrator) { |   constructor(@Inject(VIEW_POOL_CAPACITY) poolCapacityPerProtoView, renderer:Renderer) { | ||||||
|     this._poolCapacityPerProtoView = poolCapacityPerProtoView; |     this._poolCapacityPerProtoView = poolCapacityPerProtoView; | ||||||
|     this._pooledViewsPerProtoView = MapWrapper.create(); |     this._pooledViewsPerProtoView = MapWrapper.create(); | ||||||
|     this._renderer = renderer; |     this._renderer = renderer; | ||||||
|     this._viewHydrator = viewHydrator; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   getView(protoView:viewModule.AppProtoView):viewModule.AppView { |   getView(protoView:viewModule.AppProtoView):viewModule.AppView { | ||||||
| @ -48,7 +45,7 @@ export class ViewFactory { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   _createView(protoView:viewModule.AppProtoView): viewModule.AppView { |   _createView(protoView:viewModule.AppProtoView): viewModule.AppView { | ||||||
|     var view = new viewModule.AppView(this._renderer, this, this._viewHydrator, protoView, protoView.protoLocals); |     var view = new viewModule.AppView(this._renderer, this, protoView, protoView.protoLocals); | ||||||
|     var changeDetector = protoView.protoChangeDetector.instantiate(view, protoView.bindings, |     var changeDetector = protoView.protoChangeDetector.instantiate(view, protoView.bindings, | ||||||
|       protoView.getVariableBindings(), protoView.getdirectiveRecords()); |       protoView.getVariableBindings(), protoView.getdirectiveRecords()); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ import * as viewModule from './view'; | |||||||
| import {BindingPropagationConfig, Locals} from 'angular2/change_detection'; | import {BindingPropagationConfig, Locals} from 'angular2/change_detection'; | ||||||
| 
 | 
 | ||||||
| import * as renderApi from 'angular2/src/render/api'; | import * as renderApi from 'angular2/src/render/api'; | ||||||
|  | import {ViewFactory} from 'angular2/src/core/compiler/view_factory'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A dehydrated view is a state of the view that allows it to be moved around |  * A dehydrated view is a state of the view that allows it to be moved around | ||||||
| @ -27,13 +28,17 @@ import * as renderApi from 'angular2/src/render/api'; | |||||||
| @Injectable() | @Injectable() | ||||||
| export class AppViewHydrator { | export class AppViewHydrator { | ||||||
|   _renderer:renderApi.Renderer; |   _renderer:renderApi.Renderer; | ||||||
|  |   _viewFactory:ViewFactory; | ||||||
| 
 | 
 | ||||||
|   constructor(renderer:renderApi.Renderer) { |   constructor(renderer:renderApi.Renderer, viewFactory:ViewFactory) { | ||||||
|     this._renderer = renderer; |     this._renderer = renderer; | ||||||
|  |     this._viewFactory = viewFactory; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   hydrateDynamicComponentView(hostView:viewModule.AppView, boundElementIndex:number, |   hydrateDynamicComponentView(location:eli.ElementRef, | ||||||
|       componentView:viewModule.AppView, componentDirective:eli.DirectiveBinding, injector:Injector) { |       componentView:viewModule.AppView, componentDirective:eli.DirectiveBinding, injector:Injector) { | ||||||
|  |     var hostView = location.hostView; | ||||||
|  |     var boundElementIndex = location.boundElementIndex; | ||||||
|     var binder = hostView.proto.elementBinders[boundElementIndex]; |     var binder = hostView.proto.elementBinders[boundElementIndex]; | ||||||
|     if (!binder.hasDynamicComponent()) { |     if (!binder.hasDynamicComponent()) { | ||||||
|       throw new BaseException(`There is no dynamic component directive at element ${boundElementIndex}`); |       throw new BaseException(`There is no dynamic component directive at element ${boundElementIndex}`); | ||||||
| @ -84,16 +89,23 @@ export class AppViewHydrator { | |||||||
|     // parentView.componentChildViews[boundElementIndex] = null;
 |     // parentView.componentChildViews[boundElementIndex] = null;
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   hydrateInPlaceHostView(parentView:viewModule.AppView, hostElementSelector, hostView:viewModule.AppView, injector:Injector) { |   hydrateInPlaceHostView(parentComponentLocation:eli.ElementRef, | ||||||
|  |       hostElementSelector, hostView:viewModule.AppView, injector:Injector) { | ||||||
|     var parentRenderViewRef = null; |     var parentRenderViewRef = null; | ||||||
|     if (isPresent(parentView)) { |     if (isPresent(parentComponentLocation)) { | ||||||
|       // Needed for user views
 |       var parentView = parentComponentLocation.hostView.componentChildViews[parentComponentLocation.boundElementIndex]; | ||||||
|       throw new BaseException('Not yet supported'); |       parentRenderViewRef = parentView.render; | ||||||
|  |       parentView.changeDetector.addChild(hostView.changeDetector); | ||||||
|  |       ListWrapper.push(parentView.imperativeHostViews, hostView); | ||||||
|  | 
 | ||||||
|  |       if (isBlank(injector)) { | ||||||
|  |         injector = parentComponentLocation.injector; | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     var binder = hostView.proto.elementBinders[0]; |     var binder = hostView.proto.elementBinders[0]; | ||||||
|     var shadowDomAppInjector = this._createShadowDomAppInjector(binder.componentDirective, injector); |     var shadowDomAppInjector = this._createShadowDomAppInjector(binder.componentDirective, injector); | ||||||
| 
 | 
 | ||||||
|     // render views
 |  | ||||||
|     var renderViewRefs = this._renderer.createInPlaceHostView(parentRenderViewRef, hostElementSelector, hostView.proto.render); |     var renderViewRefs = this._renderer.createInPlaceHostView(parentRenderViewRef, hostElementSelector, hostView.proto.render); | ||||||
| 
 | 
 | ||||||
|     this._viewHydrateRecurse( |     this._viewHydrateRecurse( | ||||||
| @ -101,11 +113,13 @@ export class AppViewHydrator { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   dehydrateInPlaceHostView(parentView:viewModule.AppView, hostView:viewModule.AppView) { |   dehydrateInPlaceHostView(parentComponentLocation:eli.ElementRef, hostView:viewModule.AppView) { | ||||||
|     var parentRenderViewRef = null; |     var parentRenderViewRef = null; | ||||||
|     if (isPresent(parentView)) { |     if (isPresent(parentComponentLocation)) { | ||||||
|       // Needed for user views
 |       var parentView = parentComponentLocation.hostView.componentChildViews[parentComponentLocation.boundElementIndex]; | ||||||
|       throw new BaseException('Not yet supported'); |       parentRenderViewRef = parentView.render; | ||||||
|  |       ListWrapper.remove(parentView.imperativeHostViews, hostView); | ||||||
|  |       parentView.changeDetector.removeChild(hostView.changeDetector); | ||||||
|     } |     } | ||||||
|     var render = hostView.render; |     var render = hostView.render; | ||||||
|     this._viewDehydrateRecurse(hostView); |     this._viewDehydrateRecurse(hostView); | ||||||
| @ -137,7 +151,7 @@ export class AppViewHydrator { | |||||||
|       appInjector: Injector, hostElementInjector: eli.ElementInjector, |       appInjector: Injector, hostElementInjector: eli.ElementInjector, | ||||||
|       context: Object, locals:Locals):number { |       context: Object, locals:Locals):number { | ||||||
|     if (view.hydrated()) throw new BaseException('The view is already hydrated.'); |     if (view.hydrated()) throw new BaseException('The view is already hydrated.'); | ||||||
| 
 |     view.viewHydrator = this; | ||||||
|     view.render = renderComponentViewRefs[renderComponentIndex++]; |     view.render = renderComponentViewRefs[renderComponentIndex++]; | ||||||
| 
 | 
 | ||||||
|     view.context = context; |     view.context = context; | ||||||
| @ -215,12 +229,22 @@ export class AppViewHydrator { | |||||||
|         this._viewDehydrateRecurse(componentView); |         this._viewDehydrateRecurse(componentView); | ||||||
|         var binder = view.proto.elementBinders[i]; |         var binder = view.proto.elementBinders[i]; | ||||||
|         if (binder.hasDynamicComponent()) { |         if (binder.hasDynamicComponent()) { | ||||||
|           view.componentChildViews[i] = null; |  | ||||||
|           view.changeDetector.removeShadowDomChild(componentView.changeDetector); |           view.changeDetector.removeShadowDomChild(componentView.changeDetector); | ||||||
|  |           view.componentChildViews[i] = null; | ||||||
|  |           this._viewFactory.returnView(componentView); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // imperativeHostViews
 | ||||||
|  |     for (var i = 0; i < view.imperativeHostViews.length; i++) { | ||||||
|  |       var hostView = view.imperativeHostViews[i]; | ||||||
|  |       this._viewDehydrateRecurse(hostView); | ||||||
|  |       view.changeDetector.removeChild(hostView.changeDetector); | ||||||
|  |       this._viewFactory.returnView(hostView); | ||||||
|  |     } | ||||||
|  |     view.imperativeHostViews = []; | ||||||
|  | 
 | ||||||
|     // elementInjectors
 |     // elementInjectors
 | ||||||
|     for (var i = 0; i < view.elementInjectors.length; i++) { |     for (var i = 0; i < view.elementInjectors.length; i++) { | ||||||
|       if (isPresent(view.elementInjectors[i])) { |       if (isPresent(view.elementInjectors[i])) { | ||||||
|  | |||||||
| @ -151,7 +151,7 @@ class BrowserDomAdapter extends GenericBrowserDomAdapter { | |||||||
|   void appendChild(Node el, Node node) { |   void appendChild(Node el, Node node) { | ||||||
|     el.append(node); |     el.append(node); | ||||||
|   } |   } | ||||||
|   void removeChild(Element el, Node node) { |   void removeChild(el, Node node) { | ||||||
|     node.remove(); |     node.remove(); | ||||||
|   } |   } | ||||||
|   void replaceChild(Node el, Node newNode, Node oldNode) { |   void replaceChild(Node el, Node newNode, Node oldNode) { | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								modules/angular2/src/render/api.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								modules/angular2/src/render/api.js
									
									
									
									
										vendored
									
									
								
							| @ -165,6 +165,14 @@ export class Renderer { | |||||||
|    */ |    */ | ||||||
|   createHostProtoView(componentId):Promise<ProtoViewDto> { return null; } |   createHostProtoView(componentId):Promise<ProtoViewDto> { return null; } | ||||||
| 
 | 
 | ||||||
|  |   /** | ||||||
|  |    * Creats a ProtoViewDto for a component that will use an imperative View using the given | ||||||
|  |    * renderer. | ||||||
|  |    * Note: Rigth now, the renderer argument is ignored, but will be used in the future to define | ||||||
|  |    * a custom handler. | ||||||
|  |    */ | ||||||
|  |   createImperativeComponentProtoView(rendererId):Promise<ProtoViewDto> { return null; } | ||||||
|  | 
 | ||||||
|   /** |   /** | ||||||
|    * Compiles a single RenderProtoView. Non recursive so that |    * Compiles a single RenderProtoView. Non recursive so that | ||||||
|    * we don't need to serialize all possible components over the wire, |    * we don't need to serialize all possible components over the wire, | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ import {Compiler} from './compiler/compiler'; | |||||||
| import {ShadowDomStrategy} from './shadow_dom/shadow_dom_strategy'; | import {ShadowDomStrategy} from './shadow_dom/shadow_dom_strategy'; | ||||||
| import {ProtoViewBuilder} from './view/proto_view_builder'; | import {ProtoViewBuilder} from './view/proto_view_builder'; | ||||||
| import {DOM} from 'angular2/src/dom/dom_adapter'; | import {DOM} from 'angular2/src/dom/dom_adapter'; | ||||||
|  | import {ViewContainer} from './view/view_container'; | ||||||
| 
 | 
 | ||||||
| function _resolveViewContainer(vc:api.ViewContainerRef) { | function _resolveViewContainer(vc:api.ViewContainerRef) { | ||||||
|   return _resolveView(vc.view).getOrCreateViewContainer(vc.elementIndex); |   return _resolveView(vc.view).getOrCreateViewContainer(vc.elementIndex); | ||||||
| @ -90,6 +91,12 @@ export class DirectDomRenderer extends api.Renderer { | |||||||
|     return PromiseWrapper.resolve(hostProtoViewBuilder.build()); |     return PromiseWrapper.resolve(hostProtoViewBuilder.build()); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   createImperativeComponentProtoView(rendererId):Promise<api.ProtoViewDto> { | ||||||
|  |     var protoViewBuilder = new ProtoViewBuilder(null); | ||||||
|  |     protoViewBuilder.setImperativeRendererId(rendererId); | ||||||
|  |     return PromiseWrapper.resolve(protoViewBuilder.build()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   compile(template:api.ViewDefinition):Promise<api.ProtoViewDto> { |   compile(template:api.ViewDefinition):Promise<api.ProtoViewDto> { | ||||||
|     // Note: compiler already uses a DirectDomProtoViewRef, so we don't
 |     // Note: compiler already uses a DirectDomProtoViewRef, so we don't
 | ||||||
|     // need to do anything here
 |     // need to do anything here
 | ||||||
| @ -156,6 +163,21 @@ export class DirectDomRenderer extends api.Renderer { | |||||||
|     this._viewHydrator.dehydrateInPlaceHostView(parentView, hostView); |     this._viewHydrator.dehydrateInPlaceHostView(parentView, hostView); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   setImperativeComponentRootNodes(parentViewRef:api.ViewRef, elementIndex:number, nodes:List):void { | ||||||
|  |     var parentView = _resolveView(parentViewRef); | ||||||
|  |     var hostElement = parentView.boundElements[elementIndex]; | ||||||
|  |     var componentView = parentView.componentChildViews[elementIndex]; | ||||||
|  |     if (isBlank(componentView)) { | ||||||
|  |       throw new BaseException(`There is no componentChildView at index ${elementIndex}`); | ||||||
|  |     } | ||||||
|  |     if (isBlank(componentView.proto.imperativeRendererId)) { | ||||||
|  |       throw new BaseException(`This component view has no imperative renderer`); | ||||||
|  |     } | ||||||
|  |     ViewContainer.removeViewNodes(componentView); | ||||||
|  |     componentView.rootNodes = nodes; | ||||||
|  |     this._shadowDomStrategy.attachTemplate(hostElement, componentView); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   setElementProperty(viewRef:api.ViewRef, elementIndex:number, propertyName:string, propertyValue:any):void { |   setElementProperty(viewRef:api.ViewRef, elementIndex:number, propertyName:string, propertyValue:any):void { | ||||||
|     _resolveView(viewRef).setElementProperty(elementIndex, propertyName, propertyValue); |     _resolveView(viewRef).setElementProperty(elementIndex, propertyName, propertyValue); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -11,16 +11,24 @@ export class RenderProtoView { | |||||||
|   elementBinders:List<ElementBinder>; |   elementBinders:List<ElementBinder>; | ||||||
|   isTemplateElement:boolean; |   isTemplateElement:boolean; | ||||||
|   rootBindingOffset:int; |   rootBindingOffset:int; | ||||||
|  |   imperativeRendererId:string; | ||||||
| 
 | 
 | ||||||
|   constructor({ |   constructor({ | ||||||
|     elementBinders, |     elementBinders, | ||||||
|     element |     element, | ||||||
|  |     imperativeRendererId | ||||||
|   }) { |   }) { | ||||||
|     this.element = element; |     this.element = element; | ||||||
|     this.elementBinders = elementBinders; |     this.elementBinders = elementBinders; | ||||||
|  |     this.imperativeRendererId = imperativeRendererId; | ||||||
|  |     if (isPresent(imperativeRendererId)) { | ||||||
|  |       this.rootBindingOffset = 0; | ||||||
|  |       this.isTemplateElement = false; | ||||||
|  |     } else { | ||||||
|       this.isTemplateElement = DOM.isTemplateElement(this.element); |       this.isTemplateElement = DOM.isTemplateElement(this.element); | ||||||
|       this.rootBindingOffset = (isPresent(this.element) && DOM.hasClass(this.element, NG_BINDING_CLASS)) ? 1 : 0; |       this.rootBindingOffset = (isPresent(this.element) && DOM.hasClass(this.element, NG_BINDING_CLASS)) ? 1 : 0; | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   mergeChildComponentProtoViews(componentProtoViews:List<RenderProtoView>) { |   mergeChildComponentProtoViews(componentProtoViews:List<RenderProtoView>) { | ||||||
|     var componentProtoViewIndex = 0; |     var componentProtoViewIndex = 0; | ||||||
|  | |||||||
| @ -20,12 +20,18 @@ export class ProtoViewBuilder { | |||||||
|   rootElement; |   rootElement; | ||||||
|   variableBindings: Map<string, string>; |   variableBindings: Map<string, string>; | ||||||
|   elements:List<ElementBinderBuilder>; |   elements:List<ElementBinderBuilder>; | ||||||
|   isRootView:boolean; |   imperativeRendererId:string; | ||||||
| 
 | 
 | ||||||
|   constructor(rootElement) { |   constructor(rootElement) { | ||||||
|     this.rootElement = rootElement; |     this.rootElement = rootElement; | ||||||
|     this.elements = []; |     this.elements = []; | ||||||
|     this.variableBindings = MapWrapper.create(); |     this.variableBindings = MapWrapper.create(); | ||||||
|  |     this.imperativeRendererId = null; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setImperativeRendererId(id:string):ProtoViewBuilder { | ||||||
|  |     this.imperativeRendererId = id; | ||||||
|  |     return this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   bindElement(element, description = null):ElementBinderBuilder { |   bindElement(element, description = null):ElementBinderBuilder { | ||||||
| @ -90,7 +96,8 @@ export class ProtoViewBuilder { | |||||||
|     return new api.ProtoViewDto({ |     return new api.ProtoViewDto({ | ||||||
|       render: new directDomRenderer.DirectDomProtoViewRef(new RenderProtoView({ |       render: new directDomRenderer.DirectDomProtoViewRef(new RenderProtoView({ | ||||||
|         element: this.rootElement, |         element: this.rootElement, | ||||||
|         elementBinders: renderElementBinders |         elementBinders: renderElementBinders, | ||||||
|  |         imperativeRendererId: this.imperativeRendererId | ||||||
|       })), |       })), | ||||||
|       elementBinders: apiElementBinders, |       elementBinders: apiElementBinders, | ||||||
|       variableBindings: this.variableBindings |       variableBindings: this.variableBindings | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								modules/angular2/src/render/dom/view/view.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								modules/angular2/src/render/dom/view/view.js
									
									
									
									
										vendored
									
									
								
							| @ -31,6 +31,9 @@ export class RenderView { | |||||||
|   hydrated: boolean; |   hydrated: boolean; | ||||||
|   _eventDispatcher: any/*EventDispatcher*/; |   _eventDispatcher: any/*EventDispatcher*/; | ||||||
|   eventHandlerRemovers: List<Function>; |   eventHandlerRemovers: List<Function>; | ||||||
|  |   /// Host views that were added by an imperative view.
 | ||||||
|  |   /// This is a dynamically growing / shrinking array.
 | ||||||
|  |   imperativeHostViews: List<RenderView>; | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|       proto:RenderProtoView, rootNodes:List, |       proto:RenderProtoView, rootNodes:List, | ||||||
| @ -46,7 +49,8 @@ export class RenderView { | |||||||
|     this.componentChildViews = ListWrapper.createFixedSize(boundElements.length); |     this.componentChildViews = ListWrapper.createFixedSize(boundElements.length); | ||||||
|     this.hostLightDom = null; |     this.hostLightDom = null; | ||||||
|     this.hydrated = false; |     this.hydrated = false; | ||||||
|     this.eventHandlerRemovers = null; |     this.eventHandlerRemovers = []; | ||||||
|  |     this.imperativeHostViews = []; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   getDirectParentLightDom(boundElementIndex:number) { |   getDirectParentLightDom(boundElementIndex:number) { | ||||||
|  | |||||||
| @ -58,6 +58,12 @@ export class ViewFactory { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   _createView(protoView:pvModule.RenderProtoView, inplaceElement): viewModule.RenderView { |   _createView(protoView:pvModule.RenderProtoView, inplaceElement): viewModule.RenderView { | ||||||
|  |     if (isPresent(protoView.imperativeRendererId)) { | ||||||
|  |       return new viewModule.RenderView( | ||||||
|  |         protoView, [], [], [], [] | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     var rootElementClone = isPresent(inplaceElement) ? inplaceElement : DOM.importIntoDoc(protoView.element); |     var rootElementClone = isPresent(inplaceElement) ? inplaceElement : DOM.importIntoDoc(protoView.element); | ||||||
|     var elementsWithBindingsDynamic; |     var elementsWithBindingsDynamic; | ||||||
|     if (protoView.isTemplateElement) { |     if (protoView.isTemplateElement) { | ||||||
| @ -125,7 +131,7 @@ export class ViewFactory { | |||||||
|       // static child components
 |       // static child components
 | ||||||
|       if (binder.hasStaticComponent()) { |       if (binder.hasStaticComponent()) { | ||||||
|         var childView = this._createView(binder.nestedProtoView, null); |         var childView = this._createView(binder.nestedProtoView, null); | ||||||
|         this.setComponentView(view, binderIdx, childView); |         ViewFactory.setComponentView(this._shadowDomStrategy, view, binderIdx, childView); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       // events
 |       // events
 | ||||||
| @ -148,10 +154,10 @@ export class ViewFactory { | |||||||
|   // This method is used by the ViewFactory and the ViewHydrator
 |   // This method is used by the ViewFactory and the ViewHydrator
 | ||||||
|   // TODO(tbosch): change shadow dom emulation so that LightDom
 |   // TODO(tbosch): change shadow dom emulation so that LightDom
 | ||||||
|   // instances don't need to be recreated by instead hydrated/dehydrated
 |   // instances don't need to be recreated by instead hydrated/dehydrated
 | ||||||
|   setComponentView(hostView:viewModule.RenderView, elementIndex:number, componentView:viewModule.RenderView) { |   static setComponentView(shadowDomStrategy:ShadowDomStrategy, hostView:viewModule.RenderView, elementIndex:number, componentView:viewModule.RenderView) { | ||||||
|     var element = hostView.boundElements[elementIndex]; |     var element = hostView.boundElements[elementIndex]; | ||||||
|     var lightDom = this._shadowDomStrategy.constructLightDom(hostView, componentView, element); |     var lightDom = shadowDomStrategy.constructLightDom(hostView, componentView, element); | ||||||
|     this._shadowDomStrategy.attachTemplate(element, componentView); |     shadowDomStrategy.attachTemplate(element, componentView); | ||||||
|     hostView.lightDoms[elementIndex] = lightDom; |     hostView.lightDoms[elementIndex] = lightDom; | ||||||
|     hostView.componentChildViews[elementIndex] = componentView; |     hostView.componentChildViews[elementIndex] = componentView; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ import {EventManager} from '../events/event_manager'; | |||||||
| import {ViewFactory} from './view_factory'; | import {ViewFactory} from './view_factory'; | ||||||
| import * as vcModule from './view_container'; | import * as vcModule from './view_container'; | ||||||
| import * as viewModule from './view'; | import * as viewModule from './view'; | ||||||
|  | import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A dehydrated view is a state of the view that allows it to be moved around |  * A dehydrated view is a state of the view that allows it to be moved around | ||||||
| @ -23,14 +24,16 @@ import * as viewModule from './view'; | |||||||
| export class RenderViewHydrator { | export class RenderViewHydrator { | ||||||
|   _eventManager:EventManager; |   _eventManager:EventManager; | ||||||
|   _viewFactory:ViewFactory; |   _viewFactory:ViewFactory; | ||||||
|  |   _shadowDomStrategy:ShadowDomStrategy; | ||||||
| 
 | 
 | ||||||
|   constructor(eventManager:EventManager, viewFactory:ViewFactory) { |   constructor(eventManager:EventManager, viewFactory:ViewFactory, shadowDomStrategy:ShadowDomStrategy) { | ||||||
|     this._eventManager = eventManager; |     this._eventManager = eventManager; | ||||||
|     this._viewFactory = viewFactory; |     this._viewFactory = viewFactory; | ||||||
|  |     this._shadowDomStrategy = shadowDomStrategy; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   hydrateDynamicComponentView(hostView:viewModule.RenderView, boundElementIndex:number, componentView:viewModule.RenderView) { |   hydrateDynamicComponentView(hostView:viewModule.RenderView, boundElementIndex:number, componentView:viewModule.RenderView) { | ||||||
|     this._viewFactory.setComponentView(hostView, boundElementIndex, componentView); |     ViewFactory.setComponentView(this._shadowDomStrategy, hostView, boundElementIndex, componentView); | ||||||
|     var lightDom = hostView.lightDoms[boundElementIndex]; |     var lightDom = hostView.lightDoms[boundElementIndex]; | ||||||
|     this._viewHydrateRecurse(componentView, lightDom); |     this._viewHydrateRecurse(componentView, lightDom); | ||||||
|     if (isPresent(lightDom)) { |     if (isPresent(lightDom)) { | ||||||
| @ -50,15 +53,17 @@ export class RenderViewHydrator { | |||||||
| 
 | 
 | ||||||
|   hydrateInPlaceHostView(parentView:viewModule.RenderView, hostView:viewModule.RenderView) { |   hydrateInPlaceHostView(parentView:viewModule.RenderView, hostView:viewModule.RenderView) { | ||||||
|     if (isPresent(parentView)) { |     if (isPresent(parentView)) { | ||||||
|       throw new BaseException('Not supported yet'); |       ListWrapper.push(parentView.imperativeHostViews, hostView); | ||||||
|     } |     } | ||||||
|     this._viewHydrateRecurse(hostView, null); |     this._viewHydrateRecurse(hostView, null); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   dehydrateInPlaceHostView(parentView:viewModule.RenderView, hostView:viewModule.RenderView) { |   dehydrateInPlaceHostView(parentView:viewModule.RenderView, hostView:viewModule.RenderView) { | ||||||
|     if (isPresent(parentView)) { |     if (isPresent(parentView)) { | ||||||
|       throw new BaseException('Not supported yet'); |       ListWrapper.remove(parentView.imperativeHostViews, hostView); | ||||||
|     } |     } | ||||||
|  |     vcModule.ViewContainer.removeViewNodes(hostView); | ||||||
|  |     hostView.rootNodes = []; | ||||||
|     this._viewDehydrateRecurse(hostView); |     this._viewDehydrateRecurse(hostView); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -130,12 +135,24 @@ export class RenderViewHydrator { | |||||||
|         this._viewDehydrateRecurse(cv); |         this._viewDehydrateRecurse(cv); | ||||||
|         if (view.proto.elementBinders[i].hasDynamicComponent()) { |         if (view.proto.elementBinders[i].hasDynamicComponent()) { | ||||||
|           vcModule.ViewContainer.removeViewNodes(cv); |           vcModule.ViewContainer.removeViewNodes(cv); | ||||||
|  |           this._viewFactory.returnView(cv); | ||||||
|           view.lightDoms[i] = null; |           view.lightDoms[i] = null; | ||||||
|           view.componentChildViews[i] = null; |           view.componentChildViews[i] = null; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // imperativeHostViews
 | ||||||
|  |     for (var i = 0; i < view.imperativeHostViews.length; i++) { | ||||||
|  |       var hostView = view.imperativeHostViews[i]; | ||||||
|  |       this._viewDehydrateRecurse(hostView); | ||||||
|  |       vcModule.ViewContainer.removeViewNodes(hostView); | ||||||
|  |       hostView.rootNodes = []; | ||||||
|  |       this._viewFactory.returnView(hostView); | ||||||
|  |     } | ||||||
|  |     view.imperativeHostViews = []; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     // viewContainers and content tags
 |     // viewContainers and content tags
 | ||||||
|     if (isPresent(view.viewContainers)) { |     if (isPresent(view.viewContainers)) { | ||||||
|       for (var i = 0; i < view.viewContainers.length; i++) { |       for (var i = 0; i < view.viewContainers.length; i++) { | ||||||
|  | |||||||
| @ -79,6 +79,7 @@ function _getAppBindings() { | |||||||
|     bind(ShadowDomStrategy).toFactory( |     bind(ShadowDomStrategy).toFactory( | ||||||
|         (styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head), |         (styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head), | ||||||
|         [StyleUrlResolver, appDocumentToken]), |         [StyleUrlResolver, appDocumentToken]), | ||||||
|  |     bind(DirectDomRenderer).toClass(DirectDomRenderer), | ||||||
|     bind(Renderer).toClass(DirectDomRenderer), |     bind(Renderer).toClass(DirectDomRenderer), | ||||||
|     bind(rc.Compiler).toClass(rc.DefaultCompiler), |     bind(rc.Compiler).toClass(rc.DefaultCompiler), | ||||||
|     rvf.ViewFactory, |     rvf.ViewFactory, | ||||||
|  | |||||||
| @ -10,10 +10,11 @@ import { | |||||||
|   inject, |   inject, | ||||||
|   IS_DARTIUM, |   IS_DARTIUM, | ||||||
|   it, |   it, | ||||||
|  |   SpyObject, proxy | ||||||
| } from 'angular2/test_lib'; | } from 'angular2/test_lib'; | ||||||
| 
 | 
 | ||||||
| import {List, ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; | import {List, ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; | ||||||
| import {Type, isBlank, stringify, isPresent} from 'angular2/src/facade/lang'; | import {IMPLEMENTS, Type, isBlank, stringify, isPresent} from 'angular2/src/facade/lang'; | ||||||
| import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; | import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; | ||||||
| 
 | 
 | ||||||
| import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; | import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; | ||||||
| @ -30,20 +31,28 @@ import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory'; | |||||||
| 
 | 
 | ||||||
| import {UrlResolver} from 'angular2/src/services/url_resolver'; | import {UrlResolver} from 'angular2/src/services/url_resolver'; | ||||||
| import * as renderApi from 'angular2/src/render/api'; | import * as renderApi from 'angular2/src/render/api'; | ||||||
|  | // TODO(tbosch): Spys don't support named modules...
 | ||||||
|  | import {Renderer} from 'angular2/src/render/api'; | ||||||
| 
 | 
 | ||||||
| export function main() { | export function main() { | ||||||
|   describe('compiler', function() { |   describe('compiler', function() { | ||||||
|     var reader, tplResolver, renderer, protoViewFactory, cmpUrlMapper; |     var reader, tplResolver, renderer, protoViewFactory, cmpUrlMapper, renderCompileRequests; | ||||||
| 
 | 
 | ||||||
|     beforeEach(() => { |     beforeEach(() => { | ||||||
|       reader = new DirectiveMetadataReader(); |       reader = new DirectiveMetadataReader(); | ||||||
|       tplResolver = new FakeTemplateResolver(); |       tplResolver = new FakeTemplateResolver(); | ||||||
|       cmpUrlMapper = new RuntimeComponentUrlMapper(); |       cmpUrlMapper = new RuntimeComponentUrlMapper(); | ||||||
|  |       renderer = new SpyRenderer(); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     function createCompiler(renderCompileResults:List, protoViewFactoryResults:List<AppProtoView>) { |     function createCompiler(renderCompileResults:List, protoViewFactoryResults:List<AppProtoView>) { | ||||||
|       var urlResolver = new FakeUrlResolver(); |       var urlResolver = new FakeUrlResolver(); | ||||||
|       renderer = new FakeRenderer(renderCompileResults); |       renderCompileRequests = []; | ||||||
|  |       renderer.spy('compile').andCallFake( (template) => { | ||||||
|  |         ListWrapper.push(renderCompileRequests, template); | ||||||
|  |         return PromiseWrapper.resolve(ListWrapper.removeAt(renderCompileResults, 0)); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|       protoViewFactory = new FakeProtoViewFactory(protoViewFactoryResults) |       protoViewFactory = new FakeProtoViewFactory(protoViewFactoryResults) | ||||||
|       return new Compiler( |       return new Compiler( | ||||||
|         reader, |         reader, | ||||||
| @ -62,8 +71,8 @@ export function main() { | |||||||
|         tplResolver.setView(MainComponent, template); |         tplResolver.setView(MainComponent, template); | ||||||
|         var compiler = createCompiler([createRenderProtoView()], [createProtoView()]); |         var compiler = createCompiler([createRenderProtoView()], [createProtoView()]); | ||||||
|         return compiler.compile(MainComponent).then( (protoView) => { |         return compiler.compile(MainComponent).then( (protoView) => { | ||||||
|           expect(renderer.requests.length).toBe(1); |           expect(renderCompileRequests.length).toBe(1); | ||||||
|           return renderer.requests[0]; |           return renderCompileRequests[0]; | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
| @ -362,6 +371,11 @@ export function main() { | |||||||
|     })); |     })); | ||||||
| 
 | 
 | ||||||
|     it('should create host proto views', inject([AsyncTestCompleter], (async) => { |     it('should create host proto views', inject([AsyncTestCompleter], (async) => { | ||||||
|  |       renderer.spy('createHostProtoView').andCallFake( (componentId) => { | ||||||
|  |         return PromiseWrapper.resolve( | ||||||
|  |           createRenderProtoView([createRenderComponentElementBinder(0)]) | ||||||
|  |         ); | ||||||
|  |       }); | ||||||
|       tplResolver.setView(MainComponent, new View({template: '<div></div>'})); |       tplResolver.setView(MainComponent, new View({template: '<div></div>'})); | ||||||
|       var rootProtoView = createProtoView([ |       var rootProtoView = createProtoView([ | ||||||
|         createComponentElementBinder(reader, MainComponent) |         createComponentElementBinder(reader, MainComponent) | ||||||
| @ -379,6 +393,25 @@ export function main() { | |||||||
|         async.done(); |         async.done(); | ||||||
|       }); |       }); | ||||||
|     })); |     })); | ||||||
|  | 
 | ||||||
|  |     it('should create imperative proto views', inject([AsyncTestCompleter], (async) => { | ||||||
|  |       renderer.spy('createImperativeComponentProtoView').andCallFake( (rendererId) => { | ||||||
|  |         return PromiseWrapper.resolve( | ||||||
|  |           createRenderProtoView([]) | ||||||
|  |         ); | ||||||
|  |       }); | ||||||
|  |       tplResolver.setView(MainComponent, new View({renderer: 'some-renderer'})); | ||||||
|  |       var mainProtoView = createProtoView(); | ||||||
|  |       var compiler = createCompiler( | ||||||
|  |         [], | ||||||
|  |         [mainProtoView] | ||||||
|  |       ); | ||||||
|  |       compiler.compile(MainComponent).then( (protoView) => { | ||||||
|  |         expect(protoView).toBe(mainProtoView); | ||||||
|  |         expect(renderer.spy('createImperativeComponentProtoView')).toHaveBeenCalledWith('some-renderer'); | ||||||
|  |         async.done(); | ||||||
|  |       }); | ||||||
|  |     })); | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -482,26 +515,11 @@ class DirectiveWithAttributes { | |||||||
|   constructor(@Attribute('someAttr') someAttr:string) {} |   constructor(@Attribute('someAttr') someAttr:string) {} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class FakeRenderer extends renderApi.Renderer { | @proxy | ||||||
|   requests:List<renderApi.ViewDefinition>; | @IMPLEMENTS(Renderer) | ||||||
|   _results:List; | class SpyRenderer extends SpyObject { | ||||||
| 
 |   constructor(){super(Renderer);} | ||||||
|   constructor(results) { |   noSuchMethod(m){return super.noSuchMethod(m)} | ||||||
|     super(); |  | ||||||
|     this._results = results; |  | ||||||
|     this.requests = []; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   compile(template:renderApi.ViewDefinition):Promise<renderApi.ProtoViewDto> { |  | ||||||
|     ListWrapper.push(this.requests, template); |  | ||||||
|     return PromiseWrapper.resolve(ListWrapper.removeAt(this._results, 0)); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   createHostProtoView(componentId):Promise<renderApi.ProtoViewDto> { |  | ||||||
|     return PromiseWrapper.resolve( |  | ||||||
|       createRenderProtoView([createRenderComponentElementBinder(0)]) |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class FakeUrlResolver extends UrlResolver { | class FakeUrlResolver extends UrlResolver { | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ import {View} from 'angular2/src/core/annotations/view'; | |||||||
| import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; | import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; | ||||||
| import {ElementRef} from 'angular2/src/core/compiler/element_injector'; | import {ElementRef} from 'angular2/src/core/compiler/element_injector'; | ||||||
| import {If} from 'angular2/src/directives/if'; | import {If} from 'angular2/src/directives/if'; | ||||||
|  | import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer'; | ||||||
| 
 | 
 | ||||||
| export function main() { | export function main() { | ||||||
|   describe('DynamicComponentLoader', function () { |   describe('DynamicComponentLoader', function () { | ||||||
| @ -134,7 +135,69 @@ export function main() { | |||||||
|           }); |           }); | ||||||
|         })); |         })); | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
|  |     describe('loading into a new location', () => { | ||||||
|  |       it('should allow to create, update and destroy components', | ||||||
|  |           inject([TestBed, AsyncTestCompleter], (tb, async) => { | ||||||
|  |         tb.overrideView(MyComp, new View({ | ||||||
|  |           template: '<imp-ng-cmp #impview></imp-ng-cmp>', | ||||||
|  |           directives: [ImperativeViewComponentUsingNgComponent] | ||||||
|  |         })); | ||||||
|  |         tb.createView(MyComp).then((view) => { | ||||||
|  |           var userViewComponent = view.rawView.locals.get("impview"); | ||||||
|  | 
 | ||||||
|  |           userViewComponent.done.then((childComponentRef) => { | ||||||
|  |             view.detectChanges(); | ||||||
|  | 
 | ||||||
|  |             expect(view.rootNodes).toHaveText('hello'); | ||||||
|  | 
 | ||||||
|  |             childComponentRef.instance.ctxProp = 'new'; | ||||||
|  | 
 | ||||||
|  |             view.detectChanges(); | ||||||
|  | 
 | ||||||
|  |             expect(view.rootNodes).toHaveText('new'); | ||||||
|  | 
 | ||||||
|  |             childComponentRef.dispose(); | ||||||
|  | 
 | ||||||
|  |             expect(view.rootNodes).toHaveText(''); | ||||||
|  | 
 | ||||||
|  |             async.done(); | ||||||
|           }); |           }); | ||||||
|  |         }); | ||||||
|  |       })); | ||||||
|  | 
 | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |   selector: 'imp-ng-cmp' | ||||||
|  | }) | ||||||
|  | @View({ | ||||||
|  |   renderer: 'imp-ng-cmp-renderer' | ||||||
|  | }) | ||||||
|  | class ImperativeViewComponentUsingNgComponent { | ||||||
|  |   done; | ||||||
|  | 
 | ||||||
|  |   constructor(self:ElementRef, dynamicComponentLoader:DynamicComponentLoader, renderer:DirectDomRenderer) { | ||||||
|  |     var div = el('<div></div>'); | ||||||
|  |     renderer.setImperativeComponentRootNodes(self.hostView.render, self.boundElementIndex, [div]); | ||||||
|  |     this.done = dynamicComponentLoader.loadIntoNewLocation(ChildComp, self, div, null); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |   selector: 'child-cmp', | ||||||
|  | }) | ||||||
|  | @View({ | ||||||
|  |   template: '{{ctxProp}}' | ||||||
|  | }) | ||||||
|  | class ChildComp { | ||||||
|  |   ctxProp:string; | ||||||
|  |   constructor() { | ||||||
|  |     this.ctxProp = 'hello'; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -714,7 +714,7 @@ export function main() { | |||||||
|       beforeEach( () => { |       beforeEach( () => { | ||||||
|         renderer = new FakeRenderer(); |         renderer = new FakeRenderer(); | ||||||
|         var protoView = new AppProtoView(null, null); |         var protoView = new AppProtoView(null, null); | ||||||
|         view = new AppView(renderer, null, null, protoView, MapWrapper.create()); |         view = new AppView(renderer, null, protoView, MapWrapper.create()); | ||||||
|         view.render = new ViewRef(); |         view.render = new ViewRef(); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -33,6 +33,9 @@ import {If} from 'angular2/src/directives/if'; | |||||||
| 
 | 
 | ||||||
| import {ViewContainer} from 'angular2/src/core/compiler/view_container'; | import {ViewContainer} from 'angular2/src/core/compiler/view_container'; | ||||||
| import {Compiler} from 'angular2/src/core/compiler/compiler'; | import {Compiler} from 'angular2/src/core/compiler/compiler'; | ||||||
|  | import {ElementRef} from 'angular2/src/core/compiler/element_injector'; | ||||||
|  | 
 | ||||||
|  | import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer'; | ||||||
| 
 | 
 | ||||||
| export function main() { | export function main() { | ||||||
|   describe('integration tests', function() { |   describe('integration tests', function() { | ||||||
| @ -722,6 +725,18 @@ export function main() { | |||||||
|       })); |       })); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |     it('should support imperative views', | ||||||
|  |         inject([TestBed, AsyncTestCompleter], (tb, async) => { | ||||||
|  |       tb.overrideView(MyComp, new View({ | ||||||
|  |         template: '<simple-imp-cmp></simple-imp-cmp>', | ||||||
|  |         directives: [SimpleImperativeViewComponent] | ||||||
|  |       })); | ||||||
|  |       tb.createView(MyComp).then((view) => { | ||||||
|  |         expect(view.rootNodes).toHaveText('hello imp view'); | ||||||
|  |         async.done(); | ||||||
|  |       }); | ||||||
|  |     })); | ||||||
|  | 
 | ||||||
|     // Disabled until a solution is found, refs:
 |     // Disabled until a solution is found, refs:
 | ||||||
|     // - https://github.com/angular/angular/issues/776
 |     // - https://github.com/angular/angular/issues/776
 | ||||||
|     // - https://github.com/angular/angular/commit/81f3f32
 |     // - https://github.com/angular/angular/commit/81f3f32
 | ||||||
| @ -783,6 +798,21 @@ export function main() { | |||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @Component({ | ||||||
|  |   selector: 'simple-imp-cmp' | ||||||
|  | }) | ||||||
|  | @View({ | ||||||
|  |   renderer: 'simple-imp-cmp-renderer' | ||||||
|  | }) | ||||||
|  | class SimpleImperativeViewComponent { | ||||||
|  |   done; | ||||||
|  | 
 | ||||||
|  |   constructor(self:ElementRef, renderer:DirectDomRenderer) { | ||||||
|  |     renderer.setImperativeComponentRootNodes(self.hostView.render, self.boundElementIndex, [el('hello imp view')]); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @Decorator({ | @Decorator({ | ||||||
|   selector: 'dynamic-vp' |   selector: 'dynamic-vp' | ||||||
| }) | }) | ||||||
| @ -888,7 +918,7 @@ class ComponentWithPipes { | |||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'child-cmp', |   selector: 'child-cmp', | ||||||
|   injectables: [MyService] |   injectables: [MyService], | ||||||
| }) | }) | ||||||
| @View({ | @View({ | ||||||
|   directives: [MyDir], |   directives: [MyDir], | ||||||
|  | |||||||
| @ -35,7 +35,7 @@ export function main() { | |||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     function createViewFactory({capacity}):ViewFactory { |     function createViewFactory({capacity}):ViewFactory { | ||||||
|       return new ViewFactory(capacity, renderer, null); |       return new ViewFactory(capacity, renderer); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function createProtoChangeDetector() { |     function createProtoChangeDetector() { | ||||||
|  | |||||||
| @ -21,21 +21,24 @@ import {AppProtoView, AppView} from 'angular2/src/core/compiler/view'; | |||||||
| import {Renderer, ViewRef} from 'angular2/src/render/api'; | import {Renderer, ViewRef} from 'angular2/src/render/api'; | ||||||
| import {ChangeDetector} from 'angular2/change_detection'; | import {ChangeDetector} from 'angular2/change_detection'; | ||||||
| import {ElementBinder} from 'angular2/src/core/compiler/element_binder'; | import {ElementBinder} from 'angular2/src/core/compiler/element_binder'; | ||||||
| import {DirectiveBinding, ElementInjector} from 'angular2/src/core/compiler/element_injector'; | import {DirectiveBinding, ElementInjector, ElementRef} from 'angular2/src/core/compiler/element_injector'; | ||||||
| import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; | import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; | ||||||
| import {Component} from 'angular2/src/core/annotations/annotations'; | import {Component} from 'angular2/src/core/annotations/annotations'; | ||||||
| import {AppViewHydrator} from 'angular2/src/core/compiler/view_hydrator'; | import {AppViewHydrator} from 'angular2/src/core/compiler/view_hydrator'; | ||||||
|  | import {ViewFactory} from 'angular2/src/core/compiler/view_factory'; | ||||||
| 
 | 
 | ||||||
| export function main() { | export function main() { | ||||||
|   describe('AppViewHydrator', () => { |   describe('AppViewHydrator', () => { | ||||||
|     var renderer; |     var renderer; | ||||||
|     var reader; |     var reader; | ||||||
|     var hydrator; |     var hydrator; | ||||||
|  |     var viewFactory; | ||||||
| 
 | 
 | ||||||
|     beforeEach( () => { |     beforeEach( () => { | ||||||
|       renderer = new SpyRenderer(); |       renderer = new SpyRenderer(); | ||||||
|       reader = new DirectiveMetadataReader(); |       reader = new DirectiveMetadataReader(); | ||||||
|       hydrator = new AppViewHydrator(renderer); |       viewFactory = new SpyViewFactory(); | ||||||
|  |       hydrator = new AppViewHydrator(renderer, viewFactory); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     function createDirectiveBinding(type) { |     function createDirectiveBinding(type) { | ||||||
| @ -81,14 +84,14 @@ export function main() { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function createEmptyView() { |     function createEmptyView() { | ||||||
|       var view = new AppView(renderer, null, null, createProtoView(), MapWrapper.create()); |       var view = new AppView(renderer, null, createProtoView(), MapWrapper.create()); | ||||||
|       var changeDetector = new SpyChangeDetector(); |       var changeDetector = new SpyChangeDetector(); | ||||||
|       view.init(changeDetector, [], [], [], []); |       view.init(changeDetector, [], [], [], []); | ||||||
|       return view; |       return view; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function createHostView(pv, shadowView, componentInstance, elementInjectors = null) { |     function createHostView(pv, shadowView, componentInstance, elementInjectors = null) { | ||||||
|       var view = new AppView(renderer, null, null, pv, MapWrapper.create()); |       var view = new AppView(renderer, null, pv, MapWrapper.create()); | ||||||
|       var changeDetector = new SpyChangeDetector(); |       var changeDetector = new SpyChangeDetector(); | ||||||
| 
 | 
 | ||||||
|       var eis; |       var eis; | ||||||
| @ -117,7 +120,7 @@ export function main() { | |||||||
|         var view = createHostView(pv, null, null); |         var view = createHostView(pv, null, null); | ||||||
|         var shadowView = createEmptyView(); |         var shadowView = createEmptyView(); | ||||||
|         expect( |         expect( | ||||||
|           () => hydrator.hydrateDynamicComponentView(view, 0, shadowView, null, null) |           () => hydrator.hydrateDynamicComponentView(new ElementRef(null, view, 0, null), shadowView, null, null) | ||||||
|         ).toThrowError('There is no dynamic component directive at element 0'); |         ).toThrowError('There is no dynamic component directive at element 0'); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
| @ -126,7 +129,7 @@ export function main() { | |||||||
|         var view = createHostView(pv, null, null); |         var view = createHostView(pv, null, null); | ||||||
|         var shadowView = createEmptyView(); |         var shadowView = createEmptyView(); | ||||||
|         expect( |         expect( | ||||||
|           () => hydrator.hydrateDynamicComponentView(view, 0, shadowView, null, null) |           () => hydrator.hydrateDynamicComponentView(new ElementRef(null, view, 0, null), shadowView, null, null) | ||||||
|         ).toThrowError('There is no dynamic component directive at element 0'); |         ).toThrowError('There is no dynamic component directive at element 0'); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
| @ -135,9 +138,10 @@ export function main() { | |||||||
|         var shadowView = createEmptyView(); |         var shadowView = createEmptyView(); | ||||||
|         var view = createHostView(pv, null, null); |         var view = createHostView(pv, null, null); | ||||||
|         renderer.spy('createDynamicComponentView').andReturn([new ViewRef(), new ViewRef()]); |         renderer.spy('createDynamicComponentView').andReturn([new ViewRef(), new ViewRef()]); | ||||||
|         hydrator.hydrateDynamicComponentView(view, 0, shadowView, createDirectiveBinding(SomeComponent), null); |         var elRef = new ElementRef(null, view, 0, null); | ||||||
|  |         hydrator.hydrateDynamicComponentView(elRef, shadowView, createDirectiveBinding(SomeComponent), null); | ||||||
|         expect( |         expect( | ||||||
|           () => hydrator.hydrateDynamicComponentView(view, 0, shadowView, null, null) |           () => hydrator.hydrateDynamicComponentView(elRef, shadowView, null, null) | ||||||
|         ).toThrowError('There already is a bound component at element 0'); |         ).toThrowError('There already is a bound component at element 0'); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
| @ -217,6 +221,7 @@ export function main() { | |||||||
| 
 | 
 | ||||||
|         expect(hostView.componentChildViews[0]).toBe(shadowView); |         expect(hostView.componentChildViews[0]).toBe(shadowView); | ||||||
|         expect(hostView.changeDetector.spy('removeShadowDomChild')).not.toHaveBeenCalled(); |         expect(hostView.changeDetector.spy('removeShadowDomChild')).not.toHaveBeenCalled(); | ||||||
|  |         expect(viewFactory.spy('returnView')).not.toHaveBeenCalled(); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       it('should clear dynamic child components', () => { |       it('should clear dynamic child components', () => { | ||||||
| @ -225,6 +230,19 @@ export function main() { | |||||||
| 
 | 
 | ||||||
|         expect(hostView.componentChildViews[0]).toBe(null); |         expect(hostView.componentChildViews[0]).toBe(null); | ||||||
|         expect(hostView.changeDetector.spy('removeShadowDomChild')).toHaveBeenCalledWith(shadowView.changeDetector); |         expect(hostView.changeDetector.spy('removeShadowDomChild')).toHaveBeenCalledWith(shadowView.changeDetector); | ||||||
|  |         expect(viewFactory.spy('returnView')).toHaveBeenCalledWith(shadowView); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('should clear imperatively added child components', () => { | ||||||
|  |         createAndHydrate(createProtoView()); | ||||||
|  |         var impHostView = createHostView(createHostProtoView(createProtoView()), createEmptyView(), null); | ||||||
|  |         shadowView.imperativeHostViews = [impHostView]; | ||||||
|  | 
 | ||||||
|  |         dehydrate(hostView); | ||||||
|  | 
 | ||||||
|  |         expect(shadowView.imperativeHostViews).toEqual([]); | ||||||
|  |         expect(viewFactory.spy('returnView')).toHaveBeenCalledWith(impHostView); | ||||||
|  |         expect(shadowView.changeDetector.spy('removeChild')).toHaveBeenCalledWith(impHostView.changeDetector); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|     }); |     }); | ||||||
| @ -255,3 +273,10 @@ class SpyElementInjector extends SpyObject { | |||||||
|   constructor(){super(ElementInjector);} |   constructor(){super(ElementInjector);} | ||||||
|   noSuchMethod(m){return super.noSuchMethod(m)} |   noSuchMethod(m){return super.noSuchMethod(m)} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | @proxy | ||||||
|  | @IMPLEMENTS(ViewFactory) | ||||||
|  | class SpyViewFactory extends SpyObject { | ||||||
|  |   constructor(){super(ViewFactory);} | ||||||
|  |   noSuchMethod(m){return super.noSuchMethod(m)} | ||||||
|  | } | ||||||
| @ -57,7 +57,7 @@ export function main() { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function createViewWithOneBoundElement(pv) { |     function createViewWithOneBoundElement(pv) { | ||||||
|       var view = new AppView(renderer, null, null, pv, MapWrapper.create()); |       var view = new AppView(renderer, null, pv, MapWrapper.create()); | ||||||
|       var changeDetector = new SpyChangeDetector(); |       var changeDetector = new SpyChangeDetector(); | ||||||
|       var eij = createElementInjector(); |       var eij = createElementInjector(); | ||||||
|       view.init(changeDetector, [eij], [eij], |       view.init(changeDetector, [eij], [eij], | ||||||
|  | |||||||
| @ -50,6 +50,16 @@ export function main() { | |||||||
|       }); |       }); | ||||||
|     })); |     })); | ||||||
| 
 | 
 | ||||||
|  |     it('should create imperative proto views', inject([AsyncTestCompleter], (async) => { | ||||||
|  |       createRenderer(); | ||||||
|  |       renderer.createImperativeComponentProtoView('someRenderId').then( (rootProtoView) => { | ||||||
|  |         expect(rootProtoView.elementBinders).toEqual([]); | ||||||
|  | 
 | ||||||
|  |         expect(rootProtoView.render.delegate.imperativeRendererId).toBe('someRenderId'); | ||||||
|  |         async.done(); | ||||||
|  |       }); | ||||||
|  |     })); | ||||||
|  | 
 | ||||||
|     it('should add a static component', inject([AsyncTestCompleter], (async) => { |     it('should add a static component', inject([AsyncTestCompleter], (async) => { | ||||||
|       createRenderer(); |       createRenderer(); | ||||||
|       renderer.createHostProtoView('someComponentId').then( (rootProtoView) => { |       renderer.createHostProtoView('someComponentId').then( (rootProtoView) => { | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ export class IntegrationTestbed { | |||||||
|     this.eventPlugin = new FakeEventManagerPlugin(); |     this.eventPlugin = new FakeEventManagerPlugin(); | ||||||
|     var eventManager = new EventManager([this.eventPlugin], new FakeVmTurnZone()); |     var eventManager = new EventManager([this.eventPlugin], new FakeVmTurnZone()); | ||||||
|     var viewFactory = new ViewFactory(viewCacheCapacity, eventManager, shadowDomStrategy); |     var viewFactory = new ViewFactory(viewCacheCapacity, eventManager, shadowDomStrategy); | ||||||
|     var viewHydrator = new RenderViewHydrator(eventManager, viewFactory); |     var viewHydrator = new RenderViewHydrator(eventManager, viewFactory, shadowDomStrategy); | ||||||
|     this.renderer = new DirectDomRenderer(compiler, viewFactory, viewHydrator, shadowDomStrategy); |     this.renderer = new DirectDomRenderer(compiler, viewFactory, viewHydrator, shadowDomStrategy); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ import { | |||||||
|   xit, |   xit, | ||||||
|   SpyObject, proxy |   SpyObject, proxy | ||||||
| } from 'angular2/test_lib'; | } from 'angular2/test_lib'; | ||||||
| import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang'; | import {IMPLEMENTS, isBlank, isPresent} from 'angular2/src/facade/lang'; | ||||||
| 
 | 
 | ||||||
| import {RenderProtoView} from 'angular2/src/render/dom/view/proto_view'; | import {RenderProtoView} from 'angular2/src/render/dom/view/proto_view'; | ||||||
| import {ElementBinder} from 'angular2/src/render/dom/view/element_binder'; | import {ElementBinder} from 'angular2/src/render/dom/view/element_binder'; | ||||||
| @ -76,7 +76,7 @@ export function main() { | |||||||
|     function createHostView(pv, shadowDomView) { |     function createHostView(pv, shadowDomView) { | ||||||
|       var view = new RenderView(pv, [el('<div></div>')], |       var view = new RenderView(pv, [el('<div></div>')], | ||||||
|         [], [el('<div></div>')], [null]); |         [], [el('<div></div>')], [null]); | ||||||
|       viewFactory.setComponentView(view, 0, shadowDomView); |       ViewFactory.setComponentView(shadowDomStrategy, view, 0, shadowDomView); | ||||||
|       return view; |       return view; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -94,8 +94,8 @@ export function main() { | |||||||
|       shadowDomStrategy.spy('constructLightDom').andCallFake( (lightDomView, shadowDomView, el) => { |       shadowDomStrategy.spy('constructLightDom').andCallFake( (lightDomView, shadowDomView, el) => { | ||||||
|         return new SpyLightDom(); |         return new SpyLightDom(); | ||||||
|       }); |       }); | ||||||
|       viewFactory = new ViewFactory(1, eventManager, shadowDomStrategy); |       viewFactory = new SpyViewFactory(); | ||||||
|       viewHydrator = new RenderViewHydrator(eventManager, viewFactory); |       viewHydrator = new RenderViewHydrator(eventManager, viewFactory, shadowDomStrategy); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     describe('hydrateDynamicComponentView', () => { |     describe('hydrateDynamicComponentView', () => { | ||||||
| @ -111,6 +111,59 @@ export function main() { | |||||||
| 
 | 
 | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |     describe('hydrateInPlaceHostView', () => { | ||||||
|  | 
 | ||||||
|  |       function createInPlaceHostView() { | ||||||
|  |         var hostPv = createHostProtoView(createProtoView()); | ||||||
|  |         var shadowView = createEmptyView(); | ||||||
|  |         return createHostView(hostPv, shadowView); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       it('should hydrate the view', () => { | ||||||
|  |         var hostView = createInPlaceHostView(); | ||||||
|  |         viewHydrator.hydrateInPlaceHostView(null, hostView); | ||||||
|  | 
 | ||||||
|  |         expect(hostView.hydrated).toBe(true); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('should store the view in the parent view', () => { | ||||||
|  |         var parentView = createEmptyView(); | ||||||
|  |         var hostView = createInPlaceHostView(); | ||||||
|  | 
 | ||||||
|  |         viewHydrator.hydrateInPlaceHostView(parentView, hostView); | ||||||
|  | 
 | ||||||
|  |         expect(parentView.imperativeHostViews).toEqual([hostView]); | ||||||
|  | 
 | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     describe('dehydrateInPlaceHostView', () => { | ||||||
|  | 
 | ||||||
|  |       function createAndHydrateInPlaceHostView(parentView) { | ||||||
|  |         var hostPv = createHostProtoView(createProtoView()); | ||||||
|  |         var shadowView = createEmptyView(); | ||||||
|  |         var hostView = createHostView(hostPv, shadowView); | ||||||
|  |         viewHydrator.hydrateInPlaceHostView(parentView, hostView); | ||||||
|  |         return hostView; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       it('should clear the host view', () => { | ||||||
|  |         var parentView = createEmptyView(); | ||||||
|  |         var hostView = createAndHydrateInPlaceHostView(parentView); | ||||||
|  | 
 | ||||||
|  |         var rootNodes = hostView.rootNodes; | ||||||
|  |         expect(rootNodes[0].parentNode).toBeTruthy(); | ||||||
|  | 
 | ||||||
|  |         viewHydrator.dehydrateInPlaceHostView(parentView, hostView); | ||||||
|  | 
 | ||||||
|  |         expect(parentView.imperativeHostViews).toEqual([]); | ||||||
|  |         expect(rootNodes[0].parentNode).toBeFalsy(); | ||||||
|  |         expect(hostView.rootNodes).toEqual([]); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|     describe('hydrate... shared functionality', () => { |     describe('hydrate... shared functionality', () => { | ||||||
| 
 | 
 | ||||||
|       it('should hydrate existing child components', () => { |       it('should hydrate existing child components', () => { | ||||||
| @ -128,9 +181,12 @@ export function main() { | |||||||
|     describe('dehydrate... shared functionality', () => { |     describe('dehydrate... shared functionality', () => { | ||||||
|       var hostView; |       var hostView; | ||||||
| 
 | 
 | ||||||
|       function createAndHydrate(nestedProtoView, shadowView) { |       function createAndHydrate(nestedProtoView, shadowView, imperativeHostView = null) { | ||||||
|         var hostPv = createHostProtoView(nestedProtoView); |         var hostPv = createHostProtoView(nestedProtoView); | ||||||
|         hostView = createHostView(hostPv, shadowView); |         hostView = createHostView(hostPv, shadowView); | ||||||
|  |         if (isPresent(imperativeHostView)) { | ||||||
|  |           viewHydrator.hydrateInPlaceHostView(hostView, imperativeHostView); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         hydrate(hostView); |         hydrate(hostView); | ||||||
|       } |       } | ||||||
| @ -152,15 +208,36 @@ export function main() { | |||||||
| 
 | 
 | ||||||
|         expect(hostView.componentChildViews[0]).toBe(shadowView); |         expect(hostView.componentChildViews[0]).toBe(shadowView); | ||||||
|         expect(shadowView.rootNodes[0].parentNode).toBeTruthy(); |         expect(shadowView.rootNodes[0].parentNode).toBeTruthy(); | ||||||
|  |         expect(viewFactory.spy('returnView')).not.toHaveBeenCalled(); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       it('should clear dynamic child components', () => { |       it('should clear dynamic child components', () => { | ||||||
|         var shadowView = createEmptyView(); |         var shadowView = createEmptyView(); | ||||||
|         createAndHydrate(null, shadowView); |         createAndHydrate(null, shadowView); | ||||||
|  |         expect(shadowView.rootNodes[0].parentNode).toBeTruthy(); | ||||||
|  | 
 | ||||||
|         dehydrate(hostView); |         dehydrate(hostView); | ||||||
| 
 | 
 | ||||||
|         expect(hostView.componentChildViews[0]).toBe(null); |         expect(hostView.componentChildViews[0]).toBe(null); | ||||||
|         expect(shadowView.rootNodes[0].parentNode).toBe(null); |         expect(shadowView.rootNodes[0].parentNode).toBe(null); | ||||||
|  |         expect(viewFactory.spy('returnView')).toHaveBeenCalledWith(shadowView); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('should clear imperatively added child components', () => { | ||||||
|  |         var shadowView = createEmptyView(); | ||||||
|  |         createAndHydrate(createProtoView(), shadowView); | ||||||
|  |         var impHostView = createHostView(createHostProtoView(createProtoView()), createEmptyView()); | ||||||
|  |         shadowView.imperativeHostViews = [impHostView]; | ||||||
|  | 
 | ||||||
|  |         var rootNodes = impHostView.rootNodes; | ||||||
|  |         expect(rootNodes[0].parentNode).toBeTruthy(); | ||||||
|  | 
 | ||||||
|  |         dehydrate(hostView); | ||||||
|  | 
 | ||||||
|  |         expect(shadowView.imperativeHostViews).toEqual([]); | ||||||
|  |         expect(impHostView.rootNodes).toEqual([]); | ||||||
|  |         expect(rootNodes[0].parentNode).toBeFalsy(); | ||||||
|  |         expect(viewFactory.spy('returnView')).toHaveBeenCalledWith(impHostView); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|     }); |     }); | ||||||
| @ -189,3 +266,9 @@ class SpyLightDom extends SpyObject { | |||||||
|   noSuchMethod(m){return super.noSuchMethod(m)} |   noSuchMethod(m){return super.noSuchMethod(m)} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @proxy | ||||||
|  | @IMPLEMENTS(ViewFactory) | ||||||
|  | class SpyViewFactory extends SpyObject { | ||||||
|  |   constructor(){super(ViewFactory);} | ||||||
|  |   noSuchMethod(m){return super.noSuchMethod(m)} | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user