refactor(view): provide ViewContainers dynamically on any element
This commit is contained in:
parent
eac5c88893
commit
f830cfca12
|
@ -105,8 +105,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) => new ViewFactory(capacity, renderer),
|
(capacity, renderer, appViewHydrator) => new ViewFactory(capacity, renderer, appViewHydrator),
|
||||||
[VIEW_POOL_CAPACITY, Renderer]
|
[VIEW_POOL_CAPACITY, Renderer, AppViewHydrator]
|
||||||
),
|
),
|
||||||
bind(VIEW_POOL_CAPACITY).toValue(10000),
|
bind(VIEW_POOL_CAPACITY).toValue(10000),
|
||||||
AppViewHydrator,
|
AppViewHydrator,
|
||||||
|
|
|
@ -35,6 +35,10 @@ export class ElementRef {
|
||||||
return this.elementInjector._preBuiltObjects.view;
|
return this.elementInjector._preBuiltObjects.view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get viewContainer() {
|
||||||
|
return this.hostView.getOrCreateViewContainer(this.boundElementIndex);
|
||||||
|
}
|
||||||
|
|
||||||
get injector() {
|
get injector() {
|
||||||
return this.elementInjector._lightDomAppInjector;
|
return this.elementInjector._lightDomAppInjector;
|
||||||
}
|
}
|
||||||
|
@ -298,13 +302,10 @@ export class DirectiveBinding extends ResolvedBinding {
|
||||||
export class PreBuiltObjects {
|
export class PreBuiltObjects {
|
||||||
view:viewModule.AppView;
|
view:viewModule.AppView;
|
||||||
element:NgElement;
|
element:NgElement;
|
||||||
viewContainer:ViewContainer;
|
|
||||||
changeDetector:ChangeDetector;
|
changeDetector:ChangeDetector;
|
||||||
constructor(view, element:NgElement, viewContainer:ViewContainer,
|
constructor(view, element:NgElement, changeDetector:ChangeDetector) {
|
||||||
changeDetector:ChangeDetector) {
|
|
||||||
this.view = view;
|
this.view = view;
|
||||||
this.element = element;
|
this.element = element;
|
||||||
this.viewContainer = viewContainer;
|
|
||||||
this.changeDetector = changeDetector;
|
this.changeDetector = changeDetector;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -929,7 +930,7 @@ export class ElementInjector extends TreeNode {
|
||||||
// TODO: AppView should not be injectable. Remove it.
|
// TODO: AppView should not be injectable. Remove it.
|
||||||
if (keyId === staticKeys.viewId) return this._preBuiltObjects.view;
|
if (keyId === staticKeys.viewId) return this._preBuiltObjects.view;
|
||||||
if (keyId === staticKeys.ngElementId) return this._preBuiltObjects.element;
|
if (keyId === staticKeys.ngElementId) return this._preBuiltObjects.element;
|
||||||
if (keyId === staticKeys.viewContainerId) return this._preBuiltObjects.viewContainer;
|
if (keyId === staticKeys.viewContainerId) return this._preBuiltObjects.view.getOrCreateViewContainer(this._proto.index);
|
||||||
if (keyId === staticKeys.changeDetectorRefId) return this._preBuiltObjects.changeDetector.ref;
|
if (keyId === staticKeys.changeDetectorRefId) return this._preBuiltObjects.changeDetector.ref;
|
||||||
|
|
||||||
//TODO add other objects as needed
|
//TODO add other objects as needed
|
||||||
|
@ -984,6 +985,18 @@ export class ElementInjector extends TreeNode {
|
||||||
getExportImplicitName() {
|
getExportImplicitName() {
|
||||||
return this._proto.exportImplicitName;
|
return this._proto.exportImplicitName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLightDomAppInjector() {
|
||||||
|
return this._lightDomAppInjector;
|
||||||
|
}
|
||||||
|
|
||||||
|
getHost() {
|
||||||
|
return this._host;
|
||||||
|
}
|
||||||
|
|
||||||
|
getBoundElementIndex() {
|
||||||
|
return this._proto.index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OutOfBoundsAccess extends Error {
|
class OutOfBoundsAccess extends Error {
|
||||||
|
|
|
@ -8,6 +8,8 @@ import {SetterFn} from 'angular2/src/reflection/types';
|
||||||
import {IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
import {IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||||
import {ViewContainer} from './view_container';
|
import {ViewContainer} from './view_container';
|
||||||
import * as renderApi from 'angular2/src/render/api';
|
import * as renderApi from 'angular2/src/render/api';
|
||||||
|
import * as vfModule from './view_factory';
|
||||||
|
import * as vhModule from './view_hydrator';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Const of making objects: http://jsperf.com/instantiate-size-of-object
|
* Const of making objects: http://jsperf.com/instantiate-size-of-object
|
||||||
|
@ -17,7 +19,6 @@ import * as renderApi from 'angular2/src/render/api';
|
||||||
// TODO(tbosch): this is not supported in dart2js (no '.' is allowed)
|
// TODO(tbosch): this is not supported in dart2js (no '.' is allowed)
|
||||||
// @IMPLEMENTS(renderApi.EventDispatcher)
|
// @IMPLEMENTS(renderApi.EventDispatcher)
|
||||||
export class AppView {
|
export class AppView {
|
||||||
|
|
||||||
render:renderApi.ViewRef;
|
render:renderApi.ViewRef;
|
||||||
/// This list matches the _nodes list. It is sparse, since only Elements have ElementInjector
|
/// This list matches the _nodes list. It is sparse, since only Elements have ElementInjector
|
||||||
rootElementInjectors:List<ElementInjector>;
|
rootElementInjectors:List<ElementInjector>;
|
||||||
|
@ -28,6 +29,8 @@ export class AppView {
|
||||||
preBuiltObjects: List<PreBuiltObjects>;
|
preBuiltObjects: List<PreBuiltObjects>;
|
||||||
proto: AppProtoView;
|
proto: AppProtoView;
|
||||||
renderer: renderApi.Renderer;
|
renderer: renderApi.Renderer;
|
||||||
|
viewFactory: vfModule.ViewFactory;
|
||||||
|
viewHydrator: vhModule.AppViewHydrator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The context against which data-binding expressions in this view are evaluated against.
|
* The context against which data-binding expressions in this view are evaluated against.
|
||||||
|
@ -43,30 +46,40 @@ export class AppView {
|
||||||
*/
|
*/
|
||||||
locals:Locals;
|
locals:Locals;
|
||||||
|
|
||||||
constructor(renderer:renderApi.Renderer, proto:AppProtoView, protoLocals:Map) {
|
constructor(renderer:renderApi.Renderer, viewFactory:vfModule.ViewFactory, viewHydrator:vhModule.AppViewHydrator, proto:AppProtoView, protoLocals:Map) {
|
||||||
this.render = null;
|
this.render = null;
|
||||||
this.proto = proto;
|
this.proto = proto;
|
||||||
this.changeDetector = null;
|
this.changeDetector = null;
|
||||||
this.elementInjectors = null;
|
this.elementInjectors = null;
|
||||||
this.rootElementInjectors = null;
|
this.rootElementInjectors = null;
|
||||||
this.componentChildViews = null;
|
this.componentChildViews = null;
|
||||||
this.viewContainers = null;
|
this.viewContainers = ListWrapper.createFixedSize(this.proto.elementBinders.length);
|
||||||
this.preBuiltObjects = null;
|
this.preBuiltObjects = null;
|
||||||
this.context = null;
|
this.context = null;
|
||||||
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.viewHydrator = viewHydrator;
|
||||||
}
|
}
|
||||||
|
|
||||||
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List,
|
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List,
|
||||||
viewContainers:List, preBuiltObjects:List, componentChildViews:List) {
|
preBuiltObjects:List, componentChildViews:List) {
|
||||||
this.changeDetector = changeDetector;
|
this.changeDetector = changeDetector;
|
||||||
this.elementInjectors = elementInjectors;
|
this.elementInjectors = elementInjectors;
|
||||||
this.rootElementInjectors = rootElementInjectors;
|
this.rootElementInjectors = rootElementInjectors;
|
||||||
this.viewContainers = viewContainers;
|
|
||||||
this.preBuiltObjects = preBuiltObjects;
|
this.preBuiltObjects = preBuiltObjects;
|
||||||
this.componentChildViews = componentChildViews;
|
this.componentChildViews = componentChildViews;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOrCreateViewContainer(boundElementIndex:number) {
|
||||||
|
var viewContainer = this.viewContainers[boundElementIndex];
|
||||||
|
if (isBlank(viewContainer)) {
|
||||||
|
viewContainer = new ViewContainer(this, this.proto.elementBinders[boundElementIndex].nestedProtoView, this.elementInjectors[boundElementIndex]);
|
||||||
|
this.viewContainers[boundElementIndex] = viewContainer;
|
||||||
|
}
|
||||||
|
return viewContainer;
|
||||||
|
}
|
||||||
|
|
||||||
setLocal(contextName: string, value) {
|
setLocal(contextName: string, value) {
|
||||||
if (!this.hydrated()) throw new BaseException('Cannot set locals on dehydrated view.');
|
if (!this.hydrated()) throw new BaseException('Cannot set locals on dehydrated view.');
|
||||||
if (!MapWrapper.contains(this.proto.variableBindings, contextName)) {
|
if (!MapWrapper.contains(this.proto.variableBindings, contextName)) {
|
||||||
|
|
|
@ -4,45 +4,31 @@ import {Injector} from 'angular2/di';
|
||||||
import * as eiModule from 'angular2/src/core/compiler/element_injector';
|
import * as eiModule from 'angular2/src/core/compiler/element_injector';
|
||||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import * as renderApi from 'angular2/src/render/api';
|
|
||||||
import * as viewModule from './view';
|
import * as viewModule from './view';
|
||||||
import * as vfModule from './view_factory';
|
import {ViewContainerRef} from 'angular2/src/render/api';
|
||||||
import * as vhModule from './view_hydrator';
|
|
||||||
import {Renderer} from 'angular2/src/render/api';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @exportedAs angular2/view
|
* @exportedAs angular2/view
|
||||||
*/
|
*/
|
||||||
export class ViewContainer {
|
export class ViewContainer {
|
||||||
viewFactory: vfModule.ViewFactory;
|
|
||||||
viewHydrator: vhModule.AppViewHydrator;
|
|
||||||
renderer: Renderer;
|
|
||||||
|
|
||||||
render:renderApi.ViewContainerRef;
|
|
||||||
parentView: viewModule.AppView;
|
parentView: viewModule.AppView;
|
||||||
defaultProtoView: viewModule.AppProtoView;
|
defaultProtoView: viewModule.AppProtoView;
|
||||||
_views: List<viewModule.AppView>;
|
_views: List<viewModule.AppView>;
|
||||||
elementInjector: eiModule.ElementInjector;
|
elementInjector: eiModule.ElementInjector;
|
||||||
appInjector: Injector;
|
|
||||||
hostElementInjector: eiModule.ElementInjector;
|
|
||||||
|
|
||||||
constructor(viewFactory:vfModule.ViewFactory,
|
constructor(parentView: viewModule.AppView,
|
||||||
renderer: Renderer,
|
|
||||||
parentView: viewModule.AppView,
|
|
||||||
defaultProtoView: viewModule.AppProtoView,
|
defaultProtoView: viewModule.AppProtoView,
|
||||||
elementInjector: eiModule.ElementInjector) {
|
elementInjector: eiModule.ElementInjector) {
|
||||||
this.viewFactory = viewFactory;
|
|
||||||
this.viewHydrator = null;
|
|
||||||
this.renderer = renderer;
|
|
||||||
this.render = null;
|
|
||||||
this.parentView = parentView;
|
this.parentView = parentView;
|
||||||
this.defaultProtoView = defaultProtoView;
|
this.defaultProtoView = defaultProtoView;
|
||||||
this.elementInjector = elementInjector;
|
this.elementInjector = elementInjector;
|
||||||
|
|
||||||
// The order in this list matches the DOM order.
|
// The order in this list matches the DOM order.
|
||||||
this._views = [];
|
this._views = [];
|
||||||
this.appInjector = null;
|
}
|
||||||
this.hostElementInjector = null;
|
|
||||||
|
getRender() {
|
||||||
|
return new ViewContainerRef(this.parentView.render, this.elementInjector.getBoundElementIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
internalClearWithoutRender() {
|
internalClearWithoutRender() {
|
||||||
|
@ -71,22 +57,22 @@ export class ViewContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
hydrated() {
|
hydrated() {
|
||||||
return isPresent(this.appInjector);
|
return this.parentView.hydrated();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(rado): profile and decide whether bounds checks should be added
|
// TODO(rado): profile and decide whether bounds checks should be added
|
||||||
// to the methods below.
|
// to the methods below.
|
||||||
create(atIndex=-1, protoView:viewModule.AppProtoView = null): viewModule.AppView {
|
create(atIndex=-1, protoView:viewModule.AppProtoView = null, injector:Injector = null): viewModule.AppView {
|
||||||
if (atIndex == -1) atIndex = this._views.length;
|
if (atIndex == -1) atIndex = this._views.length;
|
||||||
if (!this.hydrated()) throw new BaseException(
|
if (!this.hydrated()) throw new BaseException(
|
||||||
'Cannot create views on a dehydrated ViewContainer');
|
'Cannot create views on a dehydrated ViewContainer');
|
||||||
if (isBlank(protoView)) {
|
if (isBlank(protoView)) {
|
||||||
protoView = this.defaultProtoView;
|
protoView = this.defaultProtoView;
|
||||||
}
|
}
|
||||||
var newView = this.viewFactory.getView(protoView);
|
var newView = this.parentView.viewFactory.getView(protoView);
|
||||||
// insertion must come before hydration so that element injector trees are attached.
|
// insertion must come before hydration so that element injector trees are attached.
|
||||||
this._insertInjectors(newView, atIndex);
|
this._insertInjectors(newView, atIndex);
|
||||||
this.viewHydrator.hydrateViewInViewContainer(this, atIndex, newView);
|
this.parentView.viewHydrator.hydrateViewInViewContainer(this, atIndex, newView, injector);
|
||||||
|
|
||||||
return newView;
|
return newView;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +81,7 @@ export class ViewContainer {
|
||||||
if (atIndex == -1) atIndex = this._views.length;
|
if (atIndex == -1) atIndex = this._views.length;
|
||||||
this._insertInjectors(view, atIndex);
|
this._insertInjectors(view, atIndex);
|
||||||
this.parentView.changeDetector.addChild(view.changeDetector);
|
this.parentView.changeDetector.addChild(view.changeDetector);
|
||||||
this.renderer.insertViewIntoContainer(this.render, atIndex, view.render);
|
this.parentView.renderer.insertViewIntoContainer(this.getRender(), atIndex, view.render);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,9 +96,9 @@ export class ViewContainer {
|
||||||
if (atIndex == -1) atIndex = this._views.length - 1;
|
if (atIndex == -1) atIndex = this._views.length - 1;
|
||||||
var view = this._views[atIndex];
|
var view = this._views[atIndex];
|
||||||
// opposite order as in create
|
// opposite order as in create
|
||||||
this.viewHydrator.dehydrateViewInViewContainer(this, atIndex, view);
|
this.parentView.viewHydrator.dehydrateViewInViewContainer(this, atIndex, view);
|
||||||
this._detachInjectors(atIndex);
|
this._detachInjectors(atIndex);
|
||||||
this.viewFactory.returnView(view);
|
this.parentView.viewFactory.returnView(view);
|
||||||
// view is intentionally not returned to the client.
|
// view is intentionally not returned to the client.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +110,7 @@ export class ViewContainer {
|
||||||
if (atIndex == -1) atIndex = this._views.length - 1;
|
if (atIndex == -1) atIndex = this._views.length - 1;
|
||||||
var detachedView = this._detachInjectors(atIndex);
|
var detachedView = this._detachInjectors(atIndex);
|
||||||
detachedView.changeDetector.remove();
|
detachedView.changeDetector.remove();
|
||||||
this.renderer.detachViewFromContainer(this.render, atIndex);
|
this.parentView.renderer.detachViewFromContainer(this.getRender(), atIndex);
|
||||||
return detachedView;
|
return detachedView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@ import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src
|
||||||
import * as eli from './element_injector';
|
import * as eli from './element_injector';
|
||||||
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
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 vcModule from './view_container';
|
|
||||||
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,11 +15,13 @@ 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) {
|
constructor(@Inject(VIEW_POOL_CAPACITY) poolCapacityPerProtoView, renderer:Renderer, viewHydrator:AppViewHydrator) {
|
||||||
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 {
|
||||||
|
@ -50,7 +52,7 @@ export class ViewFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
_createView(protoView:viewModule.AppProtoView): viewModule.AppView {
|
_createView(protoView:viewModule.AppProtoView): viewModule.AppView {
|
||||||
var view = new viewModule.AppView(this._renderer, protoView, protoView.protoLocals);
|
var view = new viewModule.AppView(this._renderer, this, this._viewHydrator, 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());
|
||||||
|
|
||||||
|
@ -58,7 +60,6 @@ export class ViewFactory {
|
||||||
var elementInjectors = ListWrapper.createFixedSize(binders.length);
|
var elementInjectors = ListWrapper.createFixedSize(binders.length);
|
||||||
var rootElementInjectors = [];
|
var rootElementInjectors = [];
|
||||||
var preBuiltObjects = ListWrapper.createFixedSize(binders.length);
|
var preBuiltObjects = ListWrapper.createFixedSize(binders.length);
|
||||||
var viewContainers = ListWrapper.createFixedSize(binders.length);
|
|
||||||
var componentChildViews = ListWrapper.createFixedSize(binders.length);
|
var componentChildViews = ListWrapper.createFixedSize(binders.length);
|
||||||
|
|
||||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||||
|
@ -88,22 +89,14 @@ export class ViewFactory {
|
||||||
componentChildViews[binderIdx] = childView;
|
componentChildViews[binderIdx] = childView;
|
||||||
}
|
}
|
||||||
|
|
||||||
// viewContainers
|
|
||||||
var viewContainer = null;
|
|
||||||
if (isPresent(binder.viewportDirective)) {
|
|
||||||
viewContainer = new vcModule.ViewContainer(this, this._renderer, view, binder.nestedProtoView, elementInjector);
|
|
||||||
}
|
|
||||||
viewContainers[binderIdx] = viewContainer;
|
|
||||||
|
|
||||||
// preBuiltObjects
|
// preBuiltObjects
|
||||||
if (isPresent(elementInjector)) {
|
if (isPresent(elementInjector)) {
|
||||||
preBuiltObjects[binderIdx] = new eli.PreBuiltObjects(view, new NgElement(view, binderIdx), viewContainer,
|
preBuiltObjects[binderIdx] = new eli.PreBuiltObjects(view, new NgElement(view, binderIdx), childChangeDetector);
|
||||||
childChangeDetector);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view.init(changeDetector, elementInjectors, rootElementInjectors,
|
view.init(changeDetector, elementInjectors, rootElementInjectors,
|
||||||
viewContainers, preBuiltObjects, componentChildViews);
|
preBuiltObjects, componentChildViews);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,7 @@ export class AppViewHydrator {
|
||||||
}
|
}
|
||||||
var hostElementInjector = hostView.elementInjectors[boundElementIndex];
|
var hostElementInjector = hostView.elementInjectors[boundElementIndex];
|
||||||
if (isBlank(injector)) {
|
if (isBlank(injector)) {
|
||||||
// TODO: We should have another way of accesing the app injector at hostView place.
|
injector = hostElementInjector.getLightDomAppInjector();
|
||||||
injector = new eli.ElementRef(hostElementInjector).injector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// shadowDomAppInjector
|
// shadowDomAppInjector
|
||||||
|
@ -114,19 +113,22 @@ export class AppViewHydrator {
|
||||||
this._renderer.destroyInPlaceHostView(parentRenderViewRef, render);
|
this._renderer.destroyInPlaceHostView(parentRenderViewRef, render);
|
||||||
}
|
}
|
||||||
|
|
||||||
hydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, atIndex:number, view:viewModule.AppView) {
|
hydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, atIndex:number, view:viewModule.AppView, injector:Injector = null) {
|
||||||
if (!viewContainer.hydrated()) throw new BaseException(
|
if (!viewContainer.hydrated()) throw new BaseException(
|
||||||
'Cannot create views on a dehydrated ViewContainer');
|
'Cannot create views on a dehydrated ViewContainer');
|
||||||
var renderViewRefs = this._renderer.createViewInContainer(viewContainer.render, atIndex, view.proto.render);
|
if (isBlank(injector)) {
|
||||||
|
injector = viewContainer.elementInjector.getLightDomAppInjector();
|
||||||
|
}
|
||||||
|
var renderViewRefs = this._renderer.createViewInContainer(viewContainer.getRender(), atIndex, view.proto.render);
|
||||||
viewContainer.parentView.changeDetector.addChild(view.changeDetector);
|
viewContainer.parentView.changeDetector.addChild(view.changeDetector);
|
||||||
this._viewHydrateRecurse(view, renderViewRefs, 0, viewContainer.appInjector, viewContainer.hostElementInjector,
|
this._viewHydrateRecurse(view, renderViewRefs, 0, injector, viewContainer.elementInjector.getHost(),
|
||||||
viewContainer.parentView.context, viewContainer.parentView.locals);
|
viewContainer.parentView.context, viewContainer.parentView.locals);
|
||||||
}
|
}
|
||||||
|
|
||||||
dehydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, atIndex:number, view:viewModule.AppView) {
|
dehydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, atIndex:number, view:viewModule.AppView) {
|
||||||
view.changeDetector.remove();
|
view.changeDetector.remove();
|
||||||
this._viewDehydrateRecurse(view);
|
this._viewDehydrateRecurse(view);
|
||||||
this._renderer.destroyViewInContainer(viewContainer.render, atIndex);
|
this._renderer.destroyViewInContainer(viewContainer.getRender(), atIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
_viewHydrateRecurse(
|
_viewHydrateRecurse(
|
||||||
|
@ -142,14 +144,6 @@ export class AppViewHydrator {
|
||||||
view.context = context;
|
view.context = context;
|
||||||
view.locals.parent = locals;
|
view.locals.parent = locals;
|
||||||
|
|
||||||
// viewContainers
|
|
||||||
for (var i = 0; i < view.viewContainers.length; i++) {
|
|
||||||
var vc = view.viewContainers[i];
|
|
||||||
if (isPresent(vc)) {
|
|
||||||
this._viewContainerHydrateRecurse(vc, new renderApi.ViewContainerRef(view.render, i), appInjector, hostElementInjector);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var binders = view.proto.elementBinders;
|
var binders = view.proto.elementBinders;
|
||||||
for (var i = 0; i < binders.length; ++i) {
|
for (var i = 0; i < binders.length; ++i) {
|
||||||
var componentDirective = binders[i].componentDirective;
|
var componentDirective = binders[i].componentDirective;
|
||||||
|
@ -273,16 +267,6 @@ export class AppViewHydrator {
|
||||||
return shadowDomAppInjector;
|
return shadowDomAppInjector;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This should only be called by View or ViewContainer.
|
|
||||||
*/
|
|
||||||
_viewContainerHydrateRecurse(viewContainer:vcModule.ViewContainer, render:renderApi.ViewContainerRef, appInjector: Injector, hostElementInjector: eli.ElementInjector) {
|
|
||||||
viewContainer.viewHydrator = this;
|
|
||||||
viewContainer.render = render;
|
|
||||||
viewContainer.appInjector = appInjector;
|
|
||||||
viewContainer.hostElementInjector = hostElementInjector;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This should only be called by View or ViewContainer.
|
* This should only be called by View or ViewContainer.
|
||||||
*/
|
*/
|
||||||
|
@ -296,10 +280,6 @@ export class AppViewHydrator {
|
||||||
// as we don't want to change the render side
|
// as we don't want to change the render side
|
||||||
// as the render side does its own recursion.
|
// as the render side does its own recursion.
|
||||||
viewContainer.internalClearWithoutRender();
|
viewContainer.internalClearWithoutRender();
|
||||||
viewContainer.viewHydrator = null;
|
|
||||||
viewContainer.appInjector = null;
|
|
||||||
viewContainer.hostElementInjector = null;
|
|
||||||
viewContainer.render = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {ProtoViewBuilder} from './view/proto_view_builder';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
function _resolveViewContainer(vc:api.ViewContainerRef) {
|
function _resolveViewContainer(vc:api.ViewContainerRef) {
|
||||||
return _resolveView(vc.view).viewContainers[vc.elementIndex];
|
return _resolveView(vc.view).getOrCreateViewContainer(vc.elementIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _resolveView(viewRef:DirectDomViewRef) {
|
function _resolveView(viewRef:DirectDomViewRef) {
|
||||||
|
|
|
@ -9,13 +9,11 @@ export class DestinationLightDom {}
|
||||||
|
|
||||||
class _Root {
|
class _Root {
|
||||||
node;
|
node;
|
||||||
viewContainer;
|
boundElementIndex:number;
|
||||||
content;
|
|
||||||
|
|
||||||
constructor(node, viewContainer, content) {
|
constructor(node, boundElementIndex) {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.viewContainer = viewContainer;
|
this.boundElementIndex = boundElementIndex;
|
||||||
this.content = content;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,11 +77,16 @@ export class LightDom {
|
||||||
for (var i = 0; i < roots.length; ++i) {
|
for (var i = 0; i < roots.length; ++i) {
|
||||||
|
|
||||||
var root = roots[i];
|
var root = roots[i];
|
||||||
|
if (isPresent(root.boundElementIndex)) {
|
||||||
if (isPresent(root.viewContainer)) {
|
var vc = this.lightDomView.viewContainers[root.boundElementIndex];
|
||||||
res = ListWrapper.concat(res, root.viewContainer.nodes());
|
var content = this.lightDomView.contentTags[root.boundElementIndex];
|
||||||
} else if (isPresent(root.content)) {
|
if (isPresent(vc)) {
|
||||||
res = ListWrapper.concat(res, root.content.nodes());
|
res = ListWrapper.concat(res, vc.nodes());
|
||||||
|
} else if (isPresent(content)) {
|
||||||
|
res = ListWrapper.concat(res, content.nodes());
|
||||||
|
} else {
|
||||||
|
ListWrapper.push(res, root.node);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ListWrapper.push(res, root.node);
|
ListWrapper.push(res, root.node);
|
||||||
}
|
}
|
||||||
|
@ -92,27 +95,22 @@ export class LightDom {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a list of Roots for all the nodes of the light DOM.
|
// Returns a list of Roots for all the nodes of the light DOM.
|
||||||
// The Root object contains the DOM node and its corresponding injector (could be null).
|
// The Root object contains the DOM node and its corresponding boundElementIndex
|
||||||
_roots() {
|
_roots() {
|
||||||
if (isPresent(this.roots)) return this.roots;
|
if (isPresent(this.roots)) return this.roots;
|
||||||
|
|
||||||
var viewContainers = this.lightDomView.viewContainers;
|
var boundElements = this.lightDomView.boundElements;
|
||||||
var contentTags = this.lightDomView.contentTags;
|
|
||||||
|
|
||||||
this.roots = ListWrapper.map(this.nodes, (n) => {
|
this.roots = ListWrapper.map(this.nodes, (n) => {
|
||||||
var foundVc = null;
|
var boundElementIndex = null;
|
||||||
var foundContentTag = null;
|
for (var i=0; i<boundElements.length; i++) {
|
||||||
for (var i=0; i<viewContainers.length; i++) {
|
var boundEl = boundElements[i];
|
||||||
var vc = viewContainers[i];
|
if (isPresent(boundEl) && boundEl === n) {
|
||||||
var contentTag = contentTags[i];
|
boundElementIndex = i;
|
||||||
if (isPresent(vc) && vc.templateElement === n) {
|
break;
|
||||||
foundVc = vc;
|
|
||||||
}
|
|
||||||
if (isPresent(contentTag) && contentTag.contentStartElement === n) {
|
|
||||||
foundContentTag = contentTag;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new _Root(n, foundVc, foundContentTag);
|
return new _Root(n, boundElementIndex);
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.roots;
|
return this.roots;
|
||||||
|
|
|
@ -27,7 +27,7 @@ export class ElementBinder {
|
||||||
parentIndex,
|
parentIndex,
|
||||||
distanceToParent,
|
distanceToParent,
|
||||||
propertySetters
|
propertySetters
|
||||||
}) {
|
} = {}) {
|
||||||
this.textNodeIndices = textNodeIndices;
|
this.textNodeIndices = textNodeIndices;
|
||||||
this.contentTagSelector = contentTagSelector;
|
this.contentTagSelector = contentTagSelector;
|
||||||
this.nestedProtoView = nestedProtoView;
|
this.nestedProtoView = nestedProtoView;
|
||||||
|
|
|
@ -26,6 +26,7 @@ export class RenderView {
|
||||||
viewContainers: List<ViewContainer>;
|
viewContainers: List<ViewContainer>;
|
||||||
contentTags: List<Content>;
|
contentTags: List<Content>;
|
||||||
lightDoms: List<LightDom>;
|
lightDoms: List<LightDom>;
|
||||||
|
hostLightDom: LightDom;
|
||||||
proto: RenderProtoView;
|
proto: RenderProtoView;
|
||||||
hydrated: boolean;
|
hydrated: boolean;
|
||||||
_eventDispatcher: any/*EventDispatcher*/;
|
_eventDispatcher: any/*EventDispatcher*/;
|
||||||
|
@ -33,20 +34,39 @@ export class RenderView {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
proto:RenderProtoView, rootNodes:List,
|
proto:RenderProtoView, rootNodes:List,
|
||||||
boundTextNodes: List, boundElements:List, viewContainers:List, contentTags:List) {
|
boundTextNodes: List, boundElements:List, contentTags:List) {
|
||||||
this.proto = proto;
|
this.proto = proto;
|
||||||
this.rootNodes = rootNodes;
|
this.rootNodes = rootNodes;
|
||||||
this.boundTextNodes = boundTextNodes;
|
this.boundTextNodes = boundTextNodes;
|
||||||
this.boundElements = boundElements;
|
this.boundElements = boundElements;
|
||||||
this.viewContainers = viewContainers;
|
this.viewContainers = ListWrapper.createFixedSize(boundElements.length);
|
||||||
this.contentTags = contentTags;
|
this.contentTags = contentTags;
|
||||||
this.lightDoms = ListWrapper.createFixedSize(boundElements.length);
|
this.lightDoms = ListWrapper.createFixedSize(boundElements.length);
|
||||||
ListWrapper.fill(this.lightDoms, null);
|
ListWrapper.fill(this.lightDoms, null);
|
||||||
this.componentChildViews = ListWrapper.createFixedSize(boundElements.length);
|
this.componentChildViews = ListWrapper.createFixedSize(boundElements.length);
|
||||||
|
this.hostLightDom = null;
|
||||||
this.hydrated = false;
|
this.hydrated = false;
|
||||||
this.eventHandlerRemovers = null;
|
this.eventHandlerRemovers = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDirectParentLightDom(boundElementIndex:number) {
|
||||||
|
var binder = this.proto.elementBinders[boundElementIndex];
|
||||||
|
var destLightDom = null;
|
||||||
|
if (binder.parentIndex !== -1 && binder.distanceToParent === 1) {
|
||||||
|
destLightDom = this.lightDoms[binder.parentIndex];
|
||||||
|
}
|
||||||
|
return destLightDom;
|
||||||
|
}
|
||||||
|
|
||||||
|
getOrCreateViewContainer(binderIndex) {
|
||||||
|
var vc = this.viewContainers[binderIndex];
|
||||||
|
if (isBlank(vc)) {
|
||||||
|
vc = new ViewContainer(this, binderIndex);
|
||||||
|
this.viewContainers[binderIndex] = vc;
|
||||||
|
}
|
||||||
|
return vc;
|
||||||
|
}
|
||||||
|
|
||||||
setElementProperty(elementIndex:number, propertyName:string, value:any) {
|
setElementProperty(elementIndex:number, propertyName:string, value:any) {
|
||||||
var setter = MapWrapper.get(this.proto.elementBinders[elementIndex].propertySetters, propertyName);
|
var setter = MapWrapper.get(this.proto.elementBinders[elementIndex].propertySetters, propertyName);
|
||||||
setter(this.boundElements[elementIndex], value);
|
setter(this.boundElements[elementIndex], value);
|
||||||
|
|
|
@ -3,22 +3,17 @@ import {ListWrapper, MapWrapper, List} from 'angular2/src/facade/collection';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
import * as viewModule from './view';
|
import * as viewModule from './view';
|
||||||
import * as ldModule from '../shadow_dom/light_dom';
|
|
||||||
|
|
||||||
export class ViewContainer {
|
export class ViewContainer {
|
||||||
templateElement;
|
parentView: viewModule.RenderView;
|
||||||
|
boundElementIndex: number;
|
||||||
views: List<viewModule.RenderView>;
|
views: List<viewModule.RenderView>;
|
||||||
lightDom: ldModule.LightDom;
|
|
||||||
hostLightDom: ldModule.LightDom;
|
|
||||||
hydrated: boolean;
|
|
||||||
|
|
||||||
constructor(templateElement) {
|
|
||||||
this.templateElement = templateElement;
|
|
||||||
|
|
||||||
|
constructor(parentView: viewModule.RenderView, boundElementIndex: number) {
|
||||||
|
this.parentView = parentView;
|
||||||
|
this.boundElementIndex = boundElementIndex;
|
||||||
// The order in this list matches the DOM order.
|
// The order in this list matches the DOM order.
|
||||||
this.views = [];
|
this.views = [];
|
||||||
this.hostLightDom = null;
|
|
||||||
this.hydrated = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get(index: number): viewModule.RenderView {
|
get(index: number): viewModule.RenderView {
|
||||||
|
@ -30,22 +25,26 @@ export class ViewContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
_siblingToInsertAfter(index: number) {
|
_siblingToInsertAfter(index: number) {
|
||||||
if (index == 0) return this.templateElement;
|
if (index == 0) return this.parentView.boundElements[this.boundElementIndex];
|
||||||
return ListWrapper.last(this.views[index - 1].rootNodes);
|
return ListWrapper.last(this.views[index - 1].rootNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
_checkHydrated() {
|
_checkHydrated() {
|
||||||
if (!this.hydrated) throw new BaseException(
|
if (!this.parentView.hydrated) throw new BaseException(
|
||||||
'Cannot change dehydrated ViewContainer');
|
'Cannot change dehydrated ViewContainer');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getDirectParentLightDom() {
|
||||||
|
return this.parentView.getDirectParentLightDom(this.boundElementIndex);
|
||||||
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
this._checkHydrated();
|
this._checkHydrated();
|
||||||
for (var i=this.views.length-1; i>=0; i--) {
|
for (var i=this.views.length-1; i>=0; i--) {
|
||||||
this.detach(i);
|
this.detach(i);
|
||||||
}
|
}
|
||||||
if (isPresent(this.lightDom)) {
|
if (isPresent(this._getDirectParentLightDom())) {
|
||||||
this.lightDom.redistribute();
|
this._getDirectParentLightDom().redistribute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,14 +53,14 @@ export class ViewContainer {
|
||||||
if (atIndex == -1) atIndex = this.views.length;
|
if (atIndex == -1) atIndex = this.views.length;
|
||||||
ListWrapper.insert(this.views, atIndex, view);
|
ListWrapper.insert(this.views, atIndex, view);
|
||||||
|
|
||||||
if (isBlank(this.lightDom)) {
|
if (isBlank(this._getDirectParentLightDom())) {
|
||||||
ViewContainer.moveViewNodesAfterSibling(this._siblingToInsertAfter(atIndex), view);
|
ViewContainer.moveViewNodesAfterSibling(this._siblingToInsertAfter(atIndex), view);
|
||||||
} else {
|
} else {
|
||||||
this.lightDom.redistribute();
|
this._getDirectParentLightDom().redistribute();
|
||||||
}
|
}
|
||||||
// new content tags might have appeared, we need to redistribute.
|
// new content tags might have appeared, we need to redistribute.
|
||||||
if (isPresent(this.hostLightDom)) {
|
if (isPresent(this.parentView.hostLightDom)) {
|
||||||
this.hostLightDom.redistribute();
|
this.parentView.hostLightDom.redistribute();
|
||||||
}
|
}
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
@ -74,14 +73,14 @@ export class ViewContainer {
|
||||||
this._checkHydrated();
|
this._checkHydrated();
|
||||||
var detachedView = this.get(atIndex);
|
var detachedView = this.get(atIndex);
|
||||||
ListWrapper.removeAt(this.views, atIndex);
|
ListWrapper.removeAt(this.views, atIndex);
|
||||||
if (isBlank(this.lightDom)) {
|
if (isBlank(this._getDirectParentLightDom())) {
|
||||||
ViewContainer.removeViewNodes(detachedView);
|
ViewContainer.removeViewNodes(detachedView);
|
||||||
} else {
|
} else {
|
||||||
this.lightDom.redistribute();
|
this._getDirectParentLightDom().redistribute();
|
||||||
}
|
}
|
||||||
// content tags might have disappeared we need to do redistribution.
|
// content tags might have disappeared we need to do redistribution.
|
||||||
if (isPresent(this.hostLightDom)) {
|
if (isPresent(this.parentView.hostLightDom)) {
|
||||||
this.hostLightDom.redistribute();
|
this.parentView.hostLightDom.redistribute();
|
||||||
}
|
}
|
||||||
return detachedView;
|
return detachedView;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import {Content} from '../shadow_dom/content_tag';
|
||||||
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
|
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
|
||||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
||||||
|
|
||||||
import * as vcModule from './view_container';
|
|
||||||
import * as pvModule from './proto_view';
|
import * as pvModule from './proto_view';
|
||||||
import * as viewModule from './view';
|
import * as viewModule from './view';
|
||||||
import {NG_BINDING_CLASS_SELECTOR, NG_BINDING_CLASS} from '../util';
|
import {NG_BINDING_CLASS_SELECTOR, NG_BINDING_CLASS} from '../util';
|
||||||
|
@ -91,7 +90,6 @@ export class ViewFactory {
|
||||||
var binders = protoView.elementBinders;
|
var binders = protoView.elementBinders;
|
||||||
var boundTextNodes = [];
|
var boundTextNodes = [];
|
||||||
var boundElements = ListWrapper.createFixedSize(binders.length);
|
var boundElements = ListWrapper.createFixedSize(binders.length);
|
||||||
var viewContainers = ListWrapper.createFixedSize(binders.length);
|
|
||||||
var contentTags = ListWrapper.createFixedSize(binders.length);
|
var contentTags = ListWrapper.createFixedSize(binders.length);
|
||||||
|
|
||||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||||
|
@ -111,13 +109,6 @@ export class ViewFactory {
|
||||||
ListWrapper.push(boundTextNodes, childNodes[textNodeIndices[i]]);
|
ListWrapper.push(boundTextNodes, childNodes[textNodeIndices[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// viewContainers
|
|
||||||
var viewContainer = null;
|
|
||||||
if (isBlank(binder.componentId) && isPresent(binder.nestedProtoView)) {
|
|
||||||
viewContainer = new vcModule.ViewContainer(element);
|
|
||||||
}
|
|
||||||
viewContainers[binderIdx] = viewContainer;
|
|
||||||
|
|
||||||
// contentTags
|
// contentTags
|
||||||
var contentTag = null;
|
var contentTag = null;
|
||||||
if (isPresent(binder.contentTagSelector)) {
|
if (isPresent(binder.contentTagSelector)) {
|
||||||
|
@ -128,7 +119,7 @@ export class ViewFactory {
|
||||||
|
|
||||||
var view = new viewModule.RenderView(
|
var view = new viewModule.RenderView(
|
||||||
protoView, viewRootNodes,
|
protoView, viewRootNodes,
|
||||||
boundTextNodes, boundElements, viewContainers, contentTags
|
boundTextNodes, boundElements, contentTags
|
||||||
);
|
);
|
||||||
|
|
||||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||||
|
|
|
@ -63,33 +63,21 @@ export class RenderViewHydrator {
|
||||||
}
|
}
|
||||||
|
|
||||||
hydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, view:viewModule.RenderView) {
|
hydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, view:viewModule.RenderView) {
|
||||||
this._viewHydrateRecurse(view, viewContainer.hostLightDom);
|
this._viewHydrateRecurse(view, viewContainer.parentView.hostLightDom);
|
||||||
}
|
}
|
||||||
|
|
||||||
dehydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, view:viewModule.RenderView) {
|
dehydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, view:viewModule.RenderView) {
|
||||||
this._viewDehydrateRecurse(view);
|
this._viewDehydrateRecurse(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
_getViewDestLightDom(view, binderIndex) {
|
|
||||||
var binder = view.proto.elementBinders[binderIndex];
|
|
||||||
var destLightDom = null;
|
|
||||||
if (binder.parentIndex !== -1 && binder.distanceToParent === 1) {
|
|
||||||
destLightDom = view.lightDoms[binder.parentIndex];
|
|
||||||
}
|
|
||||||
return destLightDom;
|
|
||||||
}
|
|
||||||
|
|
||||||
_viewHydrateRecurse(view, hostLightDom: ldModule.LightDom) {
|
_viewHydrateRecurse(view, hostLightDom: ldModule.LightDom) {
|
||||||
if (view.hydrated) throw new BaseException('The view is already hydrated.');
|
if (view.hydrated) throw new BaseException('The view is already hydrated.');
|
||||||
view.hydrated = true;
|
view.hydrated = true;
|
||||||
|
view.hostLightDom = hostLightDom;
|
||||||
|
|
||||||
// viewContainers and content tags
|
// content tags
|
||||||
for (var i = 0; i < view.viewContainers.length; i++) {
|
for (var i = 0; i < view.contentTags.length; i++) {
|
||||||
var vc = view.viewContainers[i];
|
var destLightDom = view.getDirectParentLightDom(i);
|
||||||
var destLightDom = this._getViewDestLightDom(view, i);
|
|
||||||
if (isPresent(vc)) {
|
|
||||||
this._viewContainerHydrateRecurse(vc, destLightDom, hostLightDom);
|
|
||||||
}
|
|
||||||
var ct = view.contentTags[i];
|
var ct = view.contentTags[i];
|
||||||
if (isPresent(ct)) {
|
if (isPresent(ct)) {
|
||||||
ct.hydrate(destLightDom);
|
ct.hydrate(destLightDom);
|
||||||
|
@ -167,26 +155,17 @@ export class RenderViewHydrator {
|
||||||
view.eventHandlerRemovers[i]();
|
view.eventHandlerRemovers[i]();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
view.hostLightDom = null;
|
||||||
view.eventHandlerRemovers = null;
|
view.eventHandlerRemovers = null;
|
||||||
view.setEventDispatcher(null);
|
view.setEventDispatcher(null);
|
||||||
view.hydrated = false;
|
view.hydrated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_viewContainerHydrateRecurse(viewContainer, destLightDom: ldModule.LightDom, hostLightDom: ldModule.LightDom) {
|
|
||||||
viewContainer.hydrated = true;
|
|
||||||
viewContainer.hostLightDom = hostLightDom;
|
|
||||||
viewContainer.lightDom = destLightDom;
|
|
||||||
}
|
|
||||||
|
|
||||||
_viewContainerDehydrateRecurse(viewContainer) {
|
_viewContainerDehydrateRecurse(viewContainer) {
|
||||||
for (var i=0; i<viewContainer.views.length; i++) {
|
for (var i=0; i<viewContainer.views.length; i++) {
|
||||||
this._viewDehydrateRecurse(viewContainer.views[i]);
|
this._viewDehydrateRecurse(viewContainer.views[i]);
|
||||||
}
|
}
|
||||||
viewContainer.clear();
|
viewContainer.clear();
|
||||||
|
|
||||||
viewContainer.hostLightDom = null;
|
|
||||||
viewContainer.lightDom = null;
|
|
||||||
viewContainer.hydrated = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,15 +47,15 @@ export function main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEmptyView() {
|
function createEmptyView() {
|
||||||
var view = new AppView(null, createProtoView(), MapWrapper.create());
|
var view = new AppView(null, null, null, createProtoView(), MapWrapper.create());
|
||||||
view.init(null, [], [], [], [], []);
|
view.init(null, [], [], [], []);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createElementRef(view, boundElementIndex) {
|
function createElementRef(view, boundElementIndex) {
|
||||||
var peli = new ProtoElementInjector(null, boundElementIndex, []);
|
var peli = new ProtoElementInjector(null, boundElementIndex, []);
|
||||||
var eli = new ElementInjector(peli, null);
|
var eli = new ElementInjector(peli, null);
|
||||||
var preBuiltObjects = new PreBuiltObjects(view, null, null, null);
|
var preBuiltObjects = new PreBuiltObjects(view, null, null);
|
||||||
eli.instantiateDirectives(null, null, null, preBuiltObjects);
|
eli.instantiateDirectives(null, null, null, preBuiltObjects);
|
||||||
return new ElementRef(eli);
|
return new ElementRef(eli);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ class DummyDirective extends Directive {
|
||||||
|
|
||||||
@proxy
|
@proxy
|
||||||
@IMPLEMENTS(AppView)
|
@IMPLEMENTS(AppView)
|
||||||
class DummyView extends SpyObject {noSuchMethod(m){super.noSuchMethod(m)}}
|
class DummyView extends SpyObject {noSuchMethod(m){return super.noSuchMethod(m)}}
|
||||||
|
|
||||||
|
|
||||||
class SimpleDirective {
|
class SimpleDirective {
|
||||||
|
@ -203,7 +203,7 @@ class TestNode extends TreeNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null, null);
|
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null);
|
||||||
var appInjector = Injector.resolveAndCreate([]);
|
var appInjector = Injector.resolveAndCreate([]);
|
||||||
|
|
||||||
function humanize(tree, names:List) {
|
function humanize(tree, names:List) {
|
||||||
|
@ -476,7 +476,7 @@ export function main() {
|
||||||
|
|
||||||
it("should instantiate directives that depend on pre built objects", function () {
|
it("should instantiate directives that depend on pre built objects", function () {
|
||||||
var view = new DummyView();
|
var view = new DummyView();
|
||||||
var inj = injector([NeedsView], null, null, new PreBuiltObjects(view, null, null, null));
|
var inj = injector([NeedsView], null, null, new PreBuiltObjects(view, null, null));
|
||||||
|
|
||||||
expect(inj.get(NeedsView).view).toBe(view);
|
expect(inj.get(NeedsView).view).toBe(view);
|
||||||
});
|
});
|
||||||
|
@ -602,28 +602,32 @@ export function main() {
|
||||||
describe("pre built objects", function () {
|
describe("pre built objects", function () {
|
||||||
it("should return view", function () {
|
it("should return view", function () {
|
||||||
var view = new DummyView();
|
var view = new DummyView();
|
||||||
var inj = injector([], null, null, new PreBuiltObjects(view, null, null, null));
|
var inj = injector([], null, null, new PreBuiltObjects(view, null, null));
|
||||||
|
|
||||||
expect(inj.get(AppView)).toEqual(view);
|
expect(inj.get(AppView)).toEqual(view);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return element", function () {
|
it("should return element", function () {
|
||||||
var element = new NgElement(null, null);
|
var element = new NgElement(null, null);
|
||||||
var inj = injector([], null, null, new PreBuiltObjects(null, element, null, null));
|
var inj = injector([], null, null, new PreBuiltObjects(null, element, null));
|
||||||
|
|
||||||
expect(inj.get(NgElement)).toEqual(element);
|
expect(inj.get(NgElement)).toEqual(element);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return viewContainer', function () {
|
it('should return viewContainer', function () {
|
||||||
var viewContainer = new ViewContainer(null, null, null, null, null);
|
var viewContainer = new ViewContainer(null, null, null);
|
||||||
var inj = injector([], null, null, new PreBuiltObjects(null, null, viewContainer, null));
|
var view = new DummyView();
|
||||||
|
view.spy('getOrCreateViewContainer').andCallFake( (index) => {
|
||||||
|
return viewContainer;
|
||||||
|
});
|
||||||
|
var inj = injector([], null, null, new PreBuiltObjects(view, null, null));
|
||||||
|
|
||||||
expect(inj.get(ViewContainer)).toEqual(viewContainer);
|
expect(inj.get(ViewContainer)).toEqual(viewContainer);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return changeDetectorRef', function () {
|
it('should return changeDetectorRef', function () {
|
||||||
var cd = new DynamicChangeDetector(null, null, null, [], []);
|
var cd = new DynamicChangeDetector(null, null, null, [], []);
|
||||||
var inj = injector([], null, null, new PreBuiltObjects(null, null, null, cd));
|
var inj = injector([], null, null, new PreBuiltObjects(null, null, cd));
|
||||||
|
|
||||||
expect(inj.get(ChangeDetectorRef)).toBe(cd.ref);
|
expect(inj.get(ChangeDetectorRef)).toBe(cd.ref);
|
||||||
});
|
});
|
||||||
|
@ -710,12 +714,12 @@ 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, protoView, MapWrapper.create());
|
view = new AppView(renderer, null, null, protoView, MapWrapper.create());
|
||||||
view.render = new ViewRef();
|
view.render = new ViewRef();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be injectable and callable', () => {
|
it('should be injectable and callable', () => {
|
||||||
var preBuildObject = new PreBuiltObjects(view, null, null, null);
|
var preBuildObject = new PreBuiltObjects(view, null, null);
|
||||||
var inj = injector([NeedsPropertySetter], null, null, preBuildObject);
|
var inj = injector([NeedsPropertySetter], null, null, preBuildObject);
|
||||||
var component = inj.get(NeedsPropertySetter);
|
var component = inj.get(NeedsPropertySetter);
|
||||||
component.setProp('foobar');
|
component.setProp('foobar');
|
||||||
|
@ -734,7 +738,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be injectable and callable without specifying param type annotation', () => {
|
it('should be injectable and callable without specifying param type annotation', () => {
|
||||||
var preBuildObject = new PreBuiltObjects(view, null, null, null);
|
var preBuildObject = new PreBuiltObjects(view, null, null);
|
||||||
var inj = injector([NeedsPropertySetterNoType], null, null, preBuildObject);
|
var inj = injector([NeedsPropertySetterNoType], null, null, preBuildObject);
|
||||||
var component = inj.get(NeedsPropertySetterNoType);
|
var component = inj.get(NeedsPropertySetterNoType);
|
||||||
component.setProp('foobar');
|
component.setProp('foobar');
|
||||||
|
@ -773,6 +777,16 @@ export function main() {
|
||||||
var inj = injector([NeedsElementRef]);
|
var inj = injector([NeedsElementRef]);
|
||||||
expect(inj.get(NeedsElementRef).elementRef).toBeAnInstanceOf(ElementRef);
|
expect(inj.get(NeedsElementRef).elementRef).toBeAnInstanceOf(ElementRef);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return the viewContainer from the view', () => {
|
||||||
|
var viewContainer = new ViewContainer(null, null, null);
|
||||||
|
var view = new DummyView();
|
||||||
|
view.spy('getOrCreateViewContainer').andCallFake( (index) => {
|
||||||
|
return viewContainer;
|
||||||
|
});
|
||||||
|
var inj = injector([NeedsElementRef], null, null, new PreBuiltObjects(view, null, null));
|
||||||
|
expect(inj.get(NeedsElementRef).elementRef.viewContainer).toBe(viewContainer);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('directive queries', () => {
|
describe('directive queries', () => {
|
||||||
|
|
|
@ -34,6 +34,7 @@ import {ElementRef} from 'angular2/src/core/compiler/element_injector';
|
||||||
import {If} from 'angular2/src/directives/if';
|
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';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('integration tests', function() {
|
describe('integration tests', function() {
|
||||||
|
@ -694,6 +695,27 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('dynamic ViewContainers', () => {
|
||||||
|
|
||||||
|
it('should allow to create a ViewContainer at any bound location',
|
||||||
|
inject([TestBed, AsyncTestCompleter, Compiler], (tb, async, compiler) => {
|
||||||
|
tb.overrideView(MyComp, new View({
|
||||||
|
template: '<div><dynamic-vp #dynamic></dynamic-vp></div>',
|
||||||
|
directives: [DynamicViewport]
|
||||||
|
}));
|
||||||
|
|
||||||
|
tb.createView(MyComp).then((view) => {
|
||||||
|
var dynamicVp = view.rawView.elementInjectors[0].get(DynamicViewport);
|
||||||
|
dynamicVp.done.then( (_) => {
|
||||||
|
view.detectChanges();
|
||||||
|
expect(view.rootNodes).toHaveText('dynamic greet');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
it('should support static attributes', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
it('should support static attributes', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||||
tb.overrideView(MyComp, new View({
|
tb.overrideView(MyComp, new View({
|
||||||
template: '<input static type="text" title>',
|
template: '<input static type="text" title>',
|
||||||
|
@ -774,9 +796,22 @@ export function main() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class DynamicallyCreatedComponentService {
|
@Decorator({
|
||||||
|
selector: 'dynamic-vp'
|
||||||
|
})
|
||||||
|
class DynamicViewport {
|
||||||
|
done;
|
||||||
|
constructor(vc:ViewContainer, inj:Injector, compiler:Compiler) {
|
||||||
|
var myService = new MyService();
|
||||||
|
myService.greeting = 'dynamic greet';
|
||||||
|
this.done = compiler.compileInHost(ChildCompUsingService).then( (hostPv) => {
|
||||||
|
vc.create(0, hostPv, inj.createChildFromResolved(Injector.resolve([bind(MyService).toValue(myService)])))
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DynamicallyCreatedComponentService {}
|
||||||
|
|
||||||
@DynamicComponent({
|
@DynamicComponent({
|
||||||
selector: 'dynamic-comp'
|
selector: 'dynamic-comp'
|
||||||
})
|
})
|
||||||
|
@ -909,6 +944,19 @@ class ChildComp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'child-cmp-svc'
|
||||||
|
})
|
||||||
|
@View({
|
||||||
|
template: '{{ctxProp}}'
|
||||||
|
})
|
||||||
|
class ChildCompUsingService {
|
||||||
|
ctxProp:string;
|
||||||
|
constructor(service: MyService) {
|
||||||
|
this.ctxProp = service.greeting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Decorator({
|
@Decorator({
|
||||||
selector: 'some-directive'
|
selector: 'some-directive'
|
||||||
})
|
})
|
||||||
|
|
|
@ -35,7 +35,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
function createViewFactory({capacity}):ViewFactory {
|
function createViewFactory({capacity}):ViewFactory {
|
||||||
return new ViewFactory(capacity, renderer);
|
return new ViewFactory(capacity, renderer, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createProtoChangeDetector() {
|
function createProtoChangeDetector() {
|
||||||
|
|
|
@ -80,19 +80,19 @@ export function main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEmptyView() {
|
function createEmptyView() {
|
||||||
var view = new AppView(renderer, createProtoView(), MapWrapper.create());
|
var view = new AppView(renderer, null, 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) {
|
function createHostView(pv, shadowView, componentInstance) {
|
||||||
var view = new AppView(renderer, pv, MapWrapper.create());
|
var view = new AppView(renderer, null, null, pv, MapWrapper.create());
|
||||||
var changeDetector = new SpyChangeDetector();
|
var changeDetector = new SpyChangeDetector();
|
||||||
var eij = createElementInjector();
|
var eij = createElementInjector();
|
||||||
eij.spy('getComponent').andCallFake( () => componentInstance );
|
eij.spy('getComponent').andCallFake( () => componentInstance );
|
||||||
view.init(changeDetector, [eij], [eij],
|
view.init(changeDetector, [eij], [eij],
|
||||||
[null], [null], [shadowView]);
|
[null], [shadowView]);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
import {
|
||||||
|
AsyncTestCompleter,
|
||||||
|
beforeEach,
|
||||||
|
ddescribe,
|
||||||
|
xdescribe,
|
||||||
|
describe,
|
||||||
|
el,
|
||||||
|
dispatchEvent,
|
||||||
|
expect,
|
||||||
|
iit,
|
||||||
|
inject,
|
||||||
|
beforeEachBindings,
|
||||||
|
it,
|
||||||
|
xit,
|
||||||
|
SpyObject, proxy
|
||||||
|
} from 'angular2/test_lib';
|
||||||
|
|
||||||
|
import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang';
|
||||||
|
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
|
import {AppProtoView, AppView} from 'angular2/src/core/compiler/view';
|
||||||
|
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||||
|
import {Renderer} from 'angular2/src/render/api';
|
||||||
|
import {ChangeDetector} from 'angular2/change_detection';
|
||||||
|
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
|
||||||
|
import {ElementInjector} from 'angular2/src/core/compiler/element_injector';
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
describe('AppView', () => {
|
||||||
|
var renderer;
|
||||||
|
|
||||||
|
beforeEach( () => {
|
||||||
|
renderer = new SpyRenderer();
|
||||||
|
});
|
||||||
|
|
||||||
|
function createElementInjector() {
|
||||||
|
return new SpyElementInjector();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEmptyElBinder() {
|
||||||
|
return new ElementBinder(0, null, 0, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEmbeddedProtoViewElBinder(nestedProtoView) {
|
||||||
|
var binder = new ElementBinder(0, null, 0, null, null, null);
|
||||||
|
binder.nestedProtoView = nestedProtoView;
|
||||||
|
return binder;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createProtoView(binders = null) {
|
||||||
|
if (isBlank(binders)) {
|
||||||
|
binders = [];
|
||||||
|
}
|
||||||
|
var res = new AppProtoView(null, null);
|
||||||
|
res.elementBinders = binders;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createViewWithOneBoundElement(pv) {
|
||||||
|
var view = new AppView(renderer, null, null, pv, MapWrapper.create());
|
||||||
|
var changeDetector = new SpyChangeDetector();
|
||||||
|
var eij = createElementInjector();
|
||||||
|
view.init(changeDetector, [eij], [eij],
|
||||||
|
[null], [null]);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('getOrCreateViewContainer()', () => {
|
||||||
|
|
||||||
|
it('should create a new container', () => {
|
||||||
|
var pv = createProtoView([createEmptyElBinder()]);
|
||||||
|
var view = createViewWithOneBoundElement(pv);
|
||||||
|
expect(view.getOrCreateViewContainer(0) instanceof ViewContainer).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an existing container', () => {
|
||||||
|
var pv = createProtoView([createEmptyElBinder()]);
|
||||||
|
var view = createViewWithOneBoundElement(pv);
|
||||||
|
var vc = view.getOrCreateViewContainer(0);
|
||||||
|
expect(view.getOrCreateViewContainer(0)).toBe(vc);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should store an existing nestedProtoView in the container', () => {
|
||||||
|
var defaultProtoView = createProtoView();
|
||||||
|
var pv = createProtoView([createEmbeddedProtoViewElBinder(defaultProtoView)]);
|
||||||
|
var view = createViewWithOneBoundElement(pv);
|
||||||
|
var vc = view.getOrCreateViewContainer(0);
|
||||||
|
expect(vc.defaultProtoView).toBe(defaultProtoView);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@proxy
|
||||||
|
@IMPLEMENTS(Renderer)
|
||||||
|
class SpyRenderer extends SpyObject {
|
||||||
|
constructor(){super(Renderer);}
|
||||||
|
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||||
|
}
|
||||||
|
|
||||||
|
@proxy
|
||||||
|
@IMPLEMENTS(ChangeDetector)
|
||||||
|
class SpyChangeDetector extends SpyObject {
|
||||||
|
constructor(){super(ChangeDetector);}
|
||||||
|
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||||
|
}
|
||||||
|
|
||||||
|
@proxy
|
||||||
|
@IMPLEMENTS(ElementInjector)
|
||||||
|
class SpyElementInjector extends SpyObject {
|
||||||
|
constructor(){super(ElementInjector);}
|
||||||
|
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||||
|
}
|
|
@ -47,7 +47,7 @@ export function main() {
|
||||||
it('should attach the view nodes as child of the host element', () => {
|
it('should attach the view nodes as child of the host element', () => {
|
||||||
var host = el('<div><span>original content</span></div>');
|
var host = el('<div><span>original content</span></div>');
|
||||||
var nodes = el('<div>view</div>');
|
var nodes = el('<div>view</div>');
|
||||||
var view = new RenderView(null, [nodes], [], [], [], []);
|
var view = new RenderView(null, [nodes], [], [], []);
|
||||||
|
|
||||||
strategy.attachTemplate(host, view);
|
strategy.attachTemplate(host, view);
|
||||||
var firstChild = DOM.firstChild(host);
|
var firstChild = DOM.firstChild(host);
|
||||||
|
|
|
@ -42,7 +42,7 @@ export function main() {
|
||||||
it('should attach the view nodes as child of the host element', () => {
|
it('should attach the view nodes as child of the host element', () => {
|
||||||
var host = el('<div><span>original content</span></div>');
|
var host = el('<div><span>original content</span></div>');
|
||||||
var nodes = el('<div>view</div>');
|
var nodes = el('<div>view</div>');
|
||||||
var view = new RenderView(null, [nodes], [], [], [], []);
|
var view = new RenderView(null, [nodes], [], [], []);
|
||||||
|
|
||||||
strategy.attachTemplate(host, view);
|
strategy.attachTemplate(host, view);
|
||||||
var firstChild = DOM.firstChild(host);
|
var firstChild = DOM.firstChild(host);
|
||||||
|
|
|
@ -10,24 +10,30 @@ import {ViewContainer} from 'angular2/src/render/dom/view/view_container';
|
||||||
@proxy
|
@proxy
|
||||||
@IMPLEMENTS(RenderView)
|
@IMPLEMENTS(RenderView)
|
||||||
class FakeView {
|
class FakeView {
|
||||||
|
boundElements;
|
||||||
contentTags;
|
contentTags;
|
||||||
viewContainers;
|
viewContainers;
|
||||||
|
|
||||||
constructor(containers = null) {
|
constructor(containers = null) {
|
||||||
|
this.boundElements = [];
|
||||||
this.contentTags = [];
|
this.contentTags = [];
|
||||||
this.viewContainers = [];
|
this.viewContainers = [];
|
||||||
if (isPresent(containers)) {
|
if (isPresent(containers)) {
|
||||||
ListWrapper.forEach(containers, (c) => {
|
ListWrapper.forEach(containers, (c) => {
|
||||||
|
var boundElement = null;
|
||||||
|
var contentTag = null;
|
||||||
|
var vc = null;
|
||||||
if (c instanceof FakeContentTag) {
|
if (c instanceof FakeContentTag) {
|
||||||
ListWrapper.push(this.contentTags, c);
|
contentTag = c;
|
||||||
} else {
|
boundElement = c.contentStartElement;
|
||||||
ListWrapper.push(this.contentTags, null);
|
|
||||||
}
|
}
|
||||||
if (c instanceof FakeViewContainer) {
|
if (c instanceof FakeViewContainer) {
|
||||||
ListWrapper.push(this.viewContainers, c);
|
vc = c;
|
||||||
} else {
|
boundElement = c.templateElement;
|
||||||
ListWrapper.push(this.viewContainers, null);
|
|
||||||
}
|
}
|
||||||
|
ListWrapper.push(this.contentTags, contentTag);
|
||||||
|
ListWrapper.push(this.viewContainers, vc);
|
||||||
|
ListWrapper.push(this.boundElements, boundElement);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,9 +46,9 @@ class FakeView {
|
||||||
@proxy
|
@proxy
|
||||||
@IMPLEMENTS(ViewContainer)
|
@IMPLEMENTS(ViewContainer)
|
||||||
class FakeViewContainer {
|
class FakeViewContainer {
|
||||||
templateElement;
|
|
||||||
_nodes;
|
_nodes;
|
||||||
_contentTagContainers;
|
_contentTagContainers;
|
||||||
|
templateElement;
|
||||||
|
|
||||||
constructor(templateEl, nodes = null, views = null) {
|
constructor(templateEl, nodes = null, views = null) {
|
||||||
this.templateElement = templateEl;
|
this.templateElement = templateEl;
|
||||||
|
|
|
@ -35,7 +35,7 @@ export function main() {
|
||||||
it('should attach the view nodes to the shadow root', () => {
|
it('should attach the view nodes to the shadow root', () => {
|
||||||
var host = el('<div><span>original content</span></div>');
|
var host = el('<div><span>original content</span></div>');
|
||||||
var nodes = el('<div>view</div>');
|
var nodes = el('<div>view</div>');
|
||||||
var view = new RenderView(null, [nodes], [], [], [], []);
|
var view = new RenderView(null, [nodes], [], [], []);
|
||||||
|
|
||||||
strategy.attachTemplate(host, view);
|
strategy.attachTemplate(host, view);
|
||||||
var shadowRoot = DOM.getShadowRoot(host);
|
var shadowRoot = DOM.getShadowRoot(host);
|
||||||
|
|
|
@ -70,12 +70,12 @@ export function main() {
|
||||||
function createEmptyView() {
|
function createEmptyView() {
|
||||||
var root = el('<div><div></div></div>');
|
var root = el('<div><div></div></div>');
|
||||||
return new RenderView(createProtoView(), [DOM.childNodes(root)[0]],
|
return new RenderView(createProtoView(), [DOM.childNodes(root)[0]],
|
||||||
[], [], [], []);
|
[], [], []);
|
||||||
}
|
}
|
||||||
|
|
||||||
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>')], [], []);
|
[], [el('<div></div>')], [null]);
|
||||||
viewFactory.setComponentView(view, 0, shadowDomView);
|
viewFactory.setComponentView(view, 0, shadowDomView);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
import {
|
||||||
|
AsyncTestCompleter,
|
||||||
|
beforeEach,
|
||||||
|
ddescribe,
|
||||||
|
xdescribe,
|
||||||
|
describe,
|
||||||
|
el,
|
||||||
|
dispatchEvent,
|
||||||
|
expect,
|
||||||
|
iit,
|
||||||
|
inject,
|
||||||
|
beforeEachBindings,
|
||||||
|
it,
|
||||||
|
xit,
|
||||||
|
SpyObject, proxy
|
||||||
|
} from 'angular2/test_lib';
|
||||||
|
import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang';
|
||||||
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
|
import {RenderProtoView} from 'angular2/src/render/dom/view/proto_view';
|
||||||
|
import {ElementBinder} from 'angular2/src/render/dom/view/element_binder';
|
||||||
|
import {RenderView} from 'angular2/src/render/dom/view/view';
|
||||||
|
import {ViewContainer} from 'angular2/src/render/dom/view/view_container';
|
||||||
|
import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom';
|
||||||
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
|
||||||
|
describe('RenderView', () => {
|
||||||
|
function createProtoView(binders = null) {
|
||||||
|
if (isBlank(binders)) {
|
||||||
|
binders = [];
|
||||||
|
}
|
||||||
|
var rootEl = el('<div></div>');
|
||||||
|
return new RenderProtoView({
|
||||||
|
element: rootEl,
|
||||||
|
elementBinders: binders
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createView(pv=null, boundElementCount=0) {
|
||||||
|
if (isBlank(pv)) {
|
||||||
|
pv = createProtoView();
|
||||||
|
}
|
||||||
|
var root = el('<div><div></div></div>');
|
||||||
|
var boundElements = [];
|
||||||
|
for (var i=0; i<boundElementCount; i++) {
|
||||||
|
ListWrapper.push(boundElements, el('<span></span'));
|
||||||
|
}
|
||||||
|
return new RenderView(pv, [DOM.childNodes(root)[0]],
|
||||||
|
[], boundElements, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('getDirectParentLightDom', () => {
|
||||||
|
|
||||||
|
it('should return the LightDom of the direct parent', () => {
|
||||||
|
var pv = createProtoView(
|
||||||
|
[new ElementBinder(), new ElementBinder({
|
||||||
|
parentIndex: 0,
|
||||||
|
distanceToParent: 1
|
||||||
|
})]
|
||||||
|
);
|
||||||
|
var view = createView(pv, 2);
|
||||||
|
view.lightDoms[0] = new SpyLightDom();
|
||||||
|
view.lightDoms[1] = new SpyLightDom();
|
||||||
|
expect(view.getDirectParentLightDom(1)).toBe(view.lightDoms[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return null if the direct parent is not bound', () => {
|
||||||
|
var pv = createProtoView(
|
||||||
|
[new ElementBinder(), new ElementBinder(), new ElementBinder({
|
||||||
|
parentIndex: 0,
|
||||||
|
distanceToParent: 2
|
||||||
|
})]
|
||||||
|
);
|
||||||
|
var view = createView(pv, 3);
|
||||||
|
view.lightDoms[0] = new SpyLightDom();
|
||||||
|
view.lightDoms[1] = new SpyLightDom();
|
||||||
|
view.lightDoms[2] = new SpyLightDom();
|
||||||
|
expect(view.getDirectParentLightDom(2)).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getOrCreateViewContainer', () => {
|
||||||
|
it('should create a new container', () => {
|
||||||
|
var pv = createProtoView([new ElementBinder()]);
|
||||||
|
var view = createView(pv, 1);
|
||||||
|
expect(view.getOrCreateViewContainer(0) instanceof ViewContainer).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an existing container', () => {
|
||||||
|
var pv = createProtoView([new ElementBinder()]);
|
||||||
|
var view = createView(pv, 1);
|
||||||
|
var vc = view.getOrCreateViewContainer(0);
|
||||||
|
expect(view.getOrCreateViewContainer(0)).toBe(vc);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@proxy
|
||||||
|
@IMPLEMENTS(LightDom)
|
||||||
|
class SpyLightDom extends SpyObject {
|
||||||
|
constructor(){super(LightDom);}
|
||||||
|
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||||
|
}
|
||||||
|
|
|
@ -218,8 +218,8 @@ function setup() {
|
||||||
|
|
||||||
reflector.registerType(ViewFactory, {
|
reflector.registerType(ViewFactory, {
|
||||||
"factory": (capacity, renderer) =>
|
"factory": (capacity, renderer) =>
|
||||||
new ViewFactory(capacity, renderer),
|
new ViewFactory(capacity, renderer, appViewHydrator),
|
||||||
"parameters": [[new Inject(VIEW_POOL_CAPACITY)],[Renderer]],
|
"parameters": [[new Inject(VIEW_POOL_CAPACITY)],[Renderer],[AppViewHydrator]],
|
||||||
"annotations": []
|
"annotations": []
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -281,13 +281,6 @@ function setup() {
|
||||||
"annotations": []
|
"annotations": []
|
||||||
});
|
});
|
||||||
|
|
||||||
reflector.registerType(ViewFactory, {
|
|
||||||
"factory": (capacity, renderer) =>
|
|
||||||
new ViewFactory(capacity, renderer),
|
|
||||||
"parameters": [[new Inject(VIEW_POOL_CAPACITY)],[Renderer]],
|
|
||||||
"annotations": []
|
|
||||||
});
|
|
||||||
|
|
||||||
reflector.registerType(VIEW_POOL_CAPACITY, {
|
reflector.registerType(VIEW_POOL_CAPACITY, {
|
||||||
"factory": () => 10000,
|
"factory": () => 10000,
|
||||||
"parameters": [],
|
"parameters": [],
|
||||||
|
|
Loading…
Reference in New Issue