chore(typing): extract abstract superclasses to replace @private constructors

This commit is contained in:
Alex Eagle
2015-10-06 06:53:39 -07:00
committed by vsavkin
parent ee32b1bc37
commit 6075509f26
65 changed files with 994 additions and 797 deletions

View File

@ -15,12 +15,14 @@ import {CompiledHostTemplate} from 'angular2/src/core/linker/template_commands';
* Most applications should instead use higher-level {@link DynamicComponentLoader} service, which
* both compiles and instantiates a Component.
*/
export abstract class Compiler {
abstract compileInHost(componentType: Type): Promise<ProtoViewRef>;
abstract clearCache();
}
@Injectable()
export class Compiler {
/**
* @internal
*/
constructor(private _protoViewFactory: ProtoViewFactory) {}
export class Compiler_ extends Compiler {
constructor(private _protoViewFactory: ProtoViewFactory) { super(); }
compileInHost(componentType: Type): Promise<ProtoViewRef> {
var metadatas = reflector.annotations(componentType);

View File

@ -13,7 +13,7 @@ import {ViewRef, HostViewRef} from './view_ref';
* Component Instance and allows you to destroy the Component Instance via the {@link #dispose}
* method.
*/
export class ComponentRef {
export abstract class ComponentRef {
/**
* Location of the Host Element of this Component Instance.
*/
@ -31,43 +31,11 @@ export class ComponentRef {
*/
componentType: Type;
/**
* @internal
*
* The injector provided {@link DynamicComponentLoader#loadAsRoot}.
*
* TODO(i): this api is useless and should be replaced by an injector retrieved from
* the HostElementRef, which is currently not possible.
*/
injector: Injector;
/**
* @internal
*
* TODO(i): refactor into public/private fields
*/
constructor(location: ElementRef, instance: any, componentType: Type, injector: Injector,
private _dispose: () => void) {
this.location = location;
this.instance = instance;
this.componentType = componentType;
this.injector = injector;
}
/**
* The {@link ViewRef} of the Host View of this Component instance.
*/
get hostView(): HostViewRef { return this.location.parentView; }
/**
* @internal
*
* Returns the type of this Component instance.
*
* TODO(i): this api should be removed
*/
get hostComponentType(): Type { return this.componentType; }
/**
* @internal
*
@ -82,19 +50,46 @@ export class ComponentRef {
*
* TODO(i): rename to destroy to be consistent with AppViewManager and ViewContainerRef
*/
abstract dispose();
}
export class ComponentRef_ extends ComponentRef {
/**
* The injector provided {@link DynamicComponentLoader#loadAsRoot}.
*
* TODO(i): this api is useless and should be replaced by an injector retrieved from
* the HostElementRef, which is currently not possible.
*/
injector: Injector;
/**
* TODO(i): refactor into public/private fields
*/
constructor(location: ElementRef, instance: any, componentType: Type, injector: Injector,
private _dispose: () => void) {
super();
this.location = location;
this.instance = instance;
this.componentType = componentType;
this.injector = injector;
}
/**
* @internal
*
* Returns the type of this Component instance.
*
* TODO(i): this api should be removed
*/
get hostComponentType(): Type { return this.componentType; }
dispose() { this._dispose(); }
}
/**
* Service for instantiating a Component and attaching it to a View at a specified location.
*/
@Injectable()
export class DynamicComponentLoader {
/**
* @internal
*/
constructor(private _compiler: Compiler, private _viewManager: AppViewManager) {}
export abstract class DynamicComponentLoader {
/**
* Creates an instance of a Component `type` and attaches it to the first element in the
* platform-specific global view that matches the component's selector.
@ -155,23 +150,8 @@ export class DynamicComponentLoader {
* </my-app>
* ```
*/
loadAsRoot(type: Type, overrideSelector: string, injector: Injector,
onDispose?: () => void): Promise<ComponentRef> {
return this._compiler.compileInHost(type).then(hostProtoViewRef => {
var hostViewRef =
this._viewManager.createRootHostView(hostProtoViewRef, overrideSelector, injector);
var newLocation = this._viewManager.getHostElement(hostViewRef);
var component = this._viewManager.getComponent(newLocation);
var dispose = () => {
this._viewManager.destroyRootHostView(hostViewRef);
if (isPresent(onDispose)) {
onDispose();
}
};
return new ComponentRef(newLocation, component, type, injector, dispose);
});
}
abstract loadAsRoot(type: Type, overrideSelector: string, injector: Injector,
onDispose?: () => void): Promise<ComponentRef>;
/**
* Creates an instance of a Component and attaches it to a View Container located inside of the
@ -228,11 +208,8 @@ export class DynamicComponentLoader {
* </my-app>
* ```
*/
loadIntoLocation(type: Type, hostLocation: ElementRef, anchorName: string,
bindings: ResolvedBinding[] = null): Promise<ComponentRef> {
return this.loadNextToLocation(
type, this._viewManager.getNamedElementInComponentView(hostLocation, anchorName), bindings);
}
abstract loadIntoLocation(type: Type, hostLocation: ElementRef, anchorName: string,
bindings?: ResolvedBinding[]): Promise<ComponentRef>;
/**
* Creates an instance of a Component and attaches it to the View Container found at the
@ -279,6 +256,38 @@ export class DynamicComponentLoader {
* <child-component>Child</child-component>
* ```
*/
abstract loadNextToLocation(type: Type, location: ElementRef, bindings?: ResolvedBinding[]):
Promise<ComponentRef>;
}
@Injectable()
export class DynamicComponentLoader_ extends DynamicComponentLoader {
constructor(private _compiler: Compiler, private _viewManager: AppViewManager) { super(); }
loadAsRoot(type: Type, overrideSelector: string, injector: Injector,
onDispose?: () => void): Promise<ComponentRef> {
return this._compiler.compileInHost(type).then(hostProtoViewRef => {
var hostViewRef =
this._viewManager.createRootHostView(hostProtoViewRef, overrideSelector, injector);
var newLocation = this._viewManager.getHostElement(hostViewRef);
var component = this._viewManager.getComponent(newLocation);
var dispose = () => {
this._viewManager.destroyRootHostView(hostViewRef);
if (isPresent(onDispose)) {
onDispose();
}
};
return new ComponentRef_(newLocation, component, type, injector, dispose);
});
}
loadIntoLocation(type: Type, hostLocation: ElementRef, anchorName: string,
bindings: ResolvedBinding[] = null): Promise<ComponentRef> {
return this.loadNextToLocation(
type, this._viewManager.getNamedElementInComponentView(hostLocation, anchorName), bindings);
}
loadNextToLocation(type: Type, location: ElementRef,
bindings: ResolvedBinding[] = null): Promise<ComponentRef> {
return this._compiler.compileInHost(type).then(hostProtoViewRef => {
@ -294,7 +303,7 @@ export class DynamicComponentLoader {
viewContainer.remove(index);
}
};
return new ComponentRef(newLocation, component, type, null, dispose);
return new ComponentRef_(newLocation, component, type, null, dispose);
});
}
}

View File

@ -52,6 +52,8 @@ import {EventConfig} from 'angular2/src/core/linker/event_config';
import {PipeBinding} from '../pipes/pipe_binding';
import {LifecycleHooks} from './interfaces';
import {ViewContainerRef_} from "./view_container_ref";
import {ResolvedBinding_} from "../di/binding";
var _staticKeys;
@ -126,7 +128,7 @@ export class DirectiveDependency extends Dependency {
}
}
export class DirectiveBinding extends ResolvedBinding {
export class DirectiveBinding extends ResolvedBinding_ {
public callOnDestroy: boolean;
constructor(key: Key, factory: Function, deps: Dependency[], public metadata: DirectiveMetadata,
@ -435,7 +437,7 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
getElementRef(): ElementRef { return this._preBuiltObjects.elementRef; }
getViewContainerRef(): ViewContainerRef {
return new ViewContainerRef(this._preBuiltObjects.viewManager, this.getElementRef());
return new ViewContainerRef_(this._preBuiltObjects.viewManager, this.getElementRef());
}
getNestedView(): viewModule.AppView { return this._preBuiltObjects.nestedView; }

View File

@ -1,6 +1,7 @@
import {BaseException} from 'angular2/src/core/facade/exceptions';
import {ViewRef} from './view_ref';
import {BaseException, unimplemented} from 'angular2/src/core/facade/exceptions';
import {ViewRef, ViewRef_} from './view_ref';
import {RenderViewRef, RenderElementRef, Renderer} from 'angular2/src/core/render/api';
import {ChangeDetectorRef} from "../change_detection/change_detector_ref";
/**
* Represents a location in a View that has an injection, change-detection and render context
@ -12,7 +13,7 @@ import {RenderViewRef, RenderElementRef, Renderer} from 'angular2/src/core/rende
* An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
* element.
*/
export class ElementRef implements RenderElementRef {
export abstract class ElementRef implements RenderElementRef {
/**
* @internal
*
@ -20,7 +21,6 @@ export class ElementRef implements RenderElementRef {
*/
parentView: ViewRef;
/**
* @internal
*
@ -29,23 +29,6 @@ export class ElementRef implements RenderElementRef {
* This is used internally by the Angular framework to locate elements.
*/
boundElementIndex: number;
/**
* @internal
*/
constructor(parentView: ViewRef, boundElementIndex: number, private _renderer: Renderer) {
this.parentView = parentView;
this.boundElementIndex = boundElementIndex;
}
/**
* @internal
*/
get renderView(): RenderViewRef { return this.parentView.render; }
// TODO(tbosch): remove this once Typescript supports declaring interfaces
// that contain getters
// https://github.com/Microsoft/TypeScript/issues/3745
set renderView(viewRef: RenderViewRef) { throw new BaseException('Abstract setter'); }
/**
* The underlying native element or `null` if direct access to native elements is not supported
@ -66,5 +49,23 @@ export class ElementRef implements RenderElementRef {
* </p>
* </div>
*/
get nativeElement(): any { return unimplemented(); };
get renderView(): RenderViewRef { return unimplemented(); }
}
export class ElementRef_ extends ElementRef {
constructor(public parentView: ViewRef,
/**
* Index of the element inside the {@link ViewRef}.
*
* This is used internally by the Angular framework to locate elements.
*/
public boundElementIndex: number, private _renderer: Renderer) {
super();
}
get renderView(): RenderViewRef { return (<ViewRef_>this.parentView).render; }
get nativeElement(): any { return this._renderer.getNativeElementSync(this); }
}

View File

@ -1,5 +1,5 @@
import {internalView, ProtoViewRef} from './view_ref';
import {ElementRef} from './element_ref';
import {ElementRef, ElementRef_} from './element_ref';
import * as viewModule from './view';
/**
@ -14,7 +14,7 @@ import * as viewModule from './view';
* {@link ViewContainerRef#createEmbeddedView}, which will create the View and attach it to the
* View Container.
*/
export class TemplateRef {
export abstract class TemplateRef {
/**
* The location in the View where the Embedded View logically belongs to.
*
@ -30,28 +30,30 @@ export class TemplateRef {
elementRef: ElementRef;
/**
* @internal
* Allows you to check if this Embedded Template defines Local Variable with name matching `name`.
*/
constructor(elementRef: ElementRef) { this.elementRef = elementRef; }
abstract hasLocal(name: string): boolean;
}
export class TemplateRef_ extends TemplateRef {
constructor(elementRef: ElementRef) {
super();
this.elementRef = elementRef;
}
private _getProtoView(): viewModule.AppProtoView {
var parentView = internalView(this.elementRef.parentView);
return parentView.proto
.elementBinders[this.elementRef.boundElementIndex - parentView.elementOffset]
let elementRef = <ElementRef_>this.elementRef;
var parentView = internalView(elementRef.parentView);
return parentView.proto.elementBinders[elementRef.boundElementIndex - parentView.elementOffset]
.nestedProtoView;
}
/**
* @internal
*
* Reference to the ProtoView used for creating Embedded Views that are based on the compiled
* Embedded Template.
*/
get protoViewRef(): ProtoViewRef { return this._getProtoView().ref; }
/**
* Allows you to check if this Embedded Template defines Local Variable with name matching `name`.
*/
hasLocal(name: string): boolean {
return this._getProtoView().templateVariableBindings.has(name);
}

View File

@ -33,6 +33,8 @@ import {ElementRef} from './element_ref';
import {ProtoPipes} from 'angular2/src/core/pipes/pipes';
import {camelCaseToDashCase} from 'angular2/src/core/render/dom/util';
import {TemplateCmd} from './template_commands';
import {ViewRef_} from "./view_ref";
import {ProtoViewRef_} from "./view_ref";
export {DebugContext} from 'angular2/src/core/change_detection/interfaces';
@ -106,7 +108,7 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
protoLocals: Map<string, any>, public render: renderApi.RenderViewRef,
public renderFragment: renderApi.RenderFragmentRef,
public containerElementInjector: ElementInjector) {
this.ref = new ViewRef(this);
this.ref = new ViewRef_(this);
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); // TODO optimize this
}
@ -322,7 +324,7 @@ export class AppProtoView {
constructor(public templateCmds: TemplateCmd[], public type: ViewType, public isMergable: boolean,
public changeDetectorFactory: Function,
public templateVariableBindings: Map<string, string>, public pipes: ProtoPipes) {
this.ref = new ProtoViewRef(this);
this.ref = new ProtoViewRef_(this);
}
init(render: renderApi.RenderProtoViewRef, elementBinders: ElementBinder[],

View File

@ -1,11 +1,12 @@
import {ListWrapper} from 'angular2/src/core/facade/collection';
import {unimplemented} from 'angular2/src/core/facade/exceptions';
import {ResolvedBinding} from 'angular2/src/core/di';
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
import * as avmModule from './view_manager';
import * as viewModule from './view';
import {ElementRef} from './element_ref';
import {ElementRef, ElementRef_} from './element_ref';
import {TemplateRef} from './template_ref';
import {ViewRef, HostViewRef, ProtoViewRef, internalView} from './view_ref';
@ -29,26 +30,12 @@ import {ViewRef, HostViewRef, ProtoViewRef, internalView} from './view_ref';
*
* <!-- TODO(i): we are also considering ElementRef#viewContainer api -->
*/
export class ViewContainerRef {
export abstract class ViewContainerRef {
/**
* @internal
* Anchor element that specifies the location of this container in the containing View.
* <!-- TODO: rename to anchorElement -->
*/
constructor(
/**
* @internal
*/
public viewManager: avmModule.AppViewManager,
/**
* Anchor element that specifies the location of this container in the containing View.
* <!-- TODO: rename to anchorElement -->
*/
public element: ElementRef) {}
private _getViews(): Array<viewModule.AppView> {
var vc = internalView(this.element.parentView).viewContainers[this.element.boundElementIndex];
return isPresent(vc) ? vc.views : [];
}
public element: ElementRef;
/**
* Destroys all Views in this container.
@ -62,12 +49,12 @@ export class ViewContainerRef {
/**
* Returns the {@link ViewRef} for the View located in this container at the specified index.
*/
get(index: number): ViewRef { return this._getViews()[index].ref; }
abstract get(index: number): ViewRef;
/**
* Returns the number of Views currently attached to this container.
*/
get length(): number { return this._getViews().length; }
get length(): number { return unimplemented(); };
/**
* Instantiates an Embedded View based on the {@link TemplateRef `templateRef`} and inserts it
@ -77,12 +64,7 @@ export class ViewContainerRef {
*
* Returns the {@link ViewRef} for the newly created View.
*/
// TODO(rado): profile and decide whether bounds checks should be added
// to the methods below.
createEmbeddedView(templateRef: TemplateRef, index: number = -1): ViewRef {
if (index == -1) index = this.length;
return this.viewManager.createEmbeddedViewInContainer(this.element, index, templateRef);
}
abstract createEmbeddedView(templateRef: TemplateRef, index?: number): ViewRef;
/**
* Instantiates a single {@link Component} and inserts its Host View into this container at the
@ -98,12 +80,8 @@ export class ViewContainerRef {
*
* Returns the {@link HostViewRef} of the Host View created for the newly instantiated Component.
*/
createHostView(protoViewRef: ProtoViewRef = null, index: number = -1,
dynamicallyCreatedBindings: ResolvedBinding[] = null): HostViewRef {
if (index == -1) index = this.length;
return this.viewManager.createHostViewInContainer(this.element, index, protoViewRef,
dynamicallyCreatedBindings);
}
abstract createHostView(protoViewRef?: ProtoViewRef, index?: number,
dynamicallyCreatedBindings?: ResolvedBinding[]): HostViewRef;
/**
* Inserts a View identified by a {@link ViewRef} into the container at the specified `index`.
@ -112,25 +90,68 @@ export class ViewContainerRef {
*
* Returns the inserted {@link ViewRef}.
*/
// TODO(i): refactor insert+remove into move
insert(viewRef: ViewRef, index: number = -1): ViewRef {
if (index == -1) index = this.length;
return this.viewManager.attachViewInContainer(this.element, index, viewRef);
}
abstract insert(viewRef: ViewRef, index?: number): ViewRef;
/**
* Returns the index of the View, specified via {@link ViewRef}, within the current container or
* `-1` if this container doesn't contain the View.
*/
indexOf(viewRef: ViewRef): number {
return ListWrapper.indexOf(this._getViews(), internalView(viewRef));
}
abstract indexOf(viewRef: ViewRef): number;
/**
* Destroys a View attached to this container at the specified `index`.
*
* If `index` is not specified, the last View in the container will be removed.
*/
abstract remove(index?: number): void;
/**
* Use along with {@link #insert} to move a View within the current container.
*
* If the `index` param is omitted, the last {@link ViewRef} is detached.
*/
abstract detach(index?: number): ViewRef;
}
export class ViewContainerRef_ extends ViewContainerRef {
constructor(public viewManager: avmModule.AppViewManager, element: ElementRef) {
super();
this.element = element;
}
private _getViews(): Array<viewModule.AppView> {
let element = <ElementRef_>this.element;
var vc = internalView(element.parentView).viewContainers[element.boundElementIndex];
return isPresent(vc) ? vc.views : [];
}
get(index: number): ViewRef { return this._getViews()[index].ref; }
get length(): number { return this._getViews().length; }
// TODO(rado): profile and decide whether bounds checks should be added
// to the methods below.
createEmbeddedView(templateRef: TemplateRef, index: number = -1): ViewRef {
if (index == -1) index = this.length;
return this.viewManager.createEmbeddedViewInContainer(this.element, index, templateRef);
}
createHostView(protoViewRef: ProtoViewRef = null, index: number = -1,
dynamicallyCreatedBindings: ResolvedBinding[] = null): HostViewRef {
if (index == -1) index = this.length;
return this.viewManager.createHostViewInContainer(this.element, index, protoViewRef,
dynamicallyCreatedBindings);
}
// TODO(i): refactor insert+remove into move
insert(viewRef: ViewRef, index: number = -1): ViewRef {
if (index == -1) index = this.length;
return this.viewManager.attachViewInContainer(this.element, index, viewRef);
}
indexOf(viewRef: ViewRef): number {
return ListWrapper.indexOf(this._getViews(), internalView(viewRef));
}
// TODO(i): rename to destroy
remove(index: number = -1): void {
if (index == -1) index = this.length - 1;
@ -138,11 +159,6 @@ export class ViewContainerRef {
// view is intentionally not returned to the client.
}
/**
* Use along with {@link #insert} to move a View within the current container.
*
* If the `index` param is omitted, the last {@link ViewRef} is detached.
*/
// TODO(i): refactor insert+remove into move
detach(index: number = -1): ViewRef {
if (index == -1) index = this.length - 1;

View File

@ -9,10 +9,10 @@ import {
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
import {BaseException} from 'angular2/src/core/facade/exceptions';
import * as viewModule from './view';
import {ElementRef} from './element_ref';
import {ElementRef, ElementRef_} from './element_ref';
import {ProtoViewRef, ViewRef, HostViewRef, internalView, internalProtoView} from './view_ref';
import {ViewContainerRef} from './view_container_ref';
import {TemplateRef} from './template_ref';
import {TemplateRef, TemplateRef_} from './template_ref';
import {
Renderer,
RenderViewRef,
@ -31,25 +31,11 @@ import {ProtoViewFactory} from './proto_view_factory';
* Most applications should use higher-level abstractions like {@link DynamicComponentLoader} and
* {@link ViewContainerRef} instead.
*/
@Injectable()
export class AppViewManager {
private _protoViewFactory: ProtoViewFactory;
/**
* @internal
*/
constructor(private _viewPool: AppViewPool, private _viewListener: AppViewListener,
private _utils: AppViewManagerUtils, private _renderer: Renderer,
@Inject(forwardRef(() => ProtoViewFactory)) _protoViewFactory) {
this._protoViewFactory = _protoViewFactory;
}
export abstract class AppViewManager {
/**
* Returns a {@link ViewContainerRef} of the View Container at the specified location.
*/
getViewContainer(location: ElementRef): ViewContainerRef {
var hostView = internalView(location.parentView);
return hostView.elementInjectors[location.boundElementIndex].getViewContainerRef();
}
abstract getViewContainer(location: ElementRef): ViewContainerRef;
/**
* Returns the {@link ElementRef} that makes up the specified Host View.
@ -69,30 +55,14 @@ export class AppViewManager {
* Throws an exception if the specified `hostLocation` is not a Host Element of a Component, or if
* variable `variableName` couldn't be found in the Component View of this Component.
*/
getNamedElementInComponentView(hostLocation: ElementRef, variableName: string): ElementRef {
var hostView = internalView(hostLocation.parentView);
var boundElementIndex = hostLocation.boundElementIndex;
var componentView = hostView.getNestedView(boundElementIndex);
if (isBlank(componentView)) {
throw new BaseException(`There is no component directive at element ${boundElementIndex}`);
}
var binderIdx = componentView.proto.variableLocations.get(variableName);
if (isBlank(binderIdx)) {
throw new BaseException(`Could not find variable ${variableName}`);
}
return componentView.elementRefs[componentView.elementOffset + binderIdx];
}
abstract getNamedElementInComponentView(hostLocation: ElementRef, variableName: string):
ElementRef;
/**
* Returns the component instance for the provided Host Element.
*/
getComponent(hostLocation: ElementRef): any {
var hostView = internalView(hostLocation.parentView);
var boundElementIndex = hostLocation.boundElementIndex;
return this._utils.getComponentInstance(hostView, boundElementIndex);
}
abstract getComponent(hostLocation: ElementRef): any;
_createRootHostViewScope: WtfScopeFn = wtfCreateScope('AppViewManager#createRootHostView()');
/**
* Creates an instance of a Component and attaches it to the first element in the global View
* (usually DOM Document) that matches the component's selector or `overrideSelector`.
@ -145,6 +115,112 @@ export class AppViewManager {
* ng.bootstrap(MyApp);
* ```
*/
abstract createRootHostView(hostProtoViewRef: ProtoViewRef, overrideSelector: string,
injector: Injector): HostViewRef;
/**
* Destroys the Host View created via {@link AppViewManager#createRootHostView}.
*
* Along with the Host View, the Component Instance as well as all nested View and Components are
* destroyed as well.
*/
abstract destroyRootHostView(hostViewRef: HostViewRef);
/**
* Instantiates an Embedded View based on the {@link TemplateRef `templateRef`} and inserts it
* into the View Container specified via `viewContainerLocation` at the specified `index`.
*
* Returns the {@link ViewRef} for the newly created View.
*
* This as a low-level way to create and attach an Embedded via to a View Container. Most
* applications should used {@link ViewContainerRef#createEmbeddedView} instead.
*
* Use {@link AppViewManager#destroyViewInContainer} to destroy the created Embedded View.
*/
// TODO(i): this low-level version of ViewContainerRef#createEmbeddedView doesn't add anything new
// we should make it private, otherwise we have two apis to do the same thing.
abstract createEmbeddedViewInContainer(viewContainerLocation: ElementRef, index: number,
templateRef: TemplateRef): ViewRef;
/**
* Instantiates a single {@link Component} and inserts its Host View into the View Container
* found at `viewContainerLocation`. Within the container, the view will be inserted at position
* specified via `index`.
*
* The component is instantiated using its {@link ProtoViewRef `protoViewRef`} which can be
* obtained via {@link Compiler#compileInHost}.
*
* You can optionally specify `imperativelyCreatedInjector`, which configure the {@link Injector}
* that will be created for the Host View.
*
* Returns the {@link HostViewRef} of the Host View created for the newly instantiated Component.
*
* Use {@link AppViewManager#destroyViewInContainer} to destroy the created Host View.
*/
abstract createHostViewInContainer(viewContainerLocation: ElementRef, index: number,
protoViewRef: ProtoViewRef,
imperativelyCreatedInjector: ResolvedBinding[]): HostViewRef;
/**
* Destroys an Embedded or Host View attached to a View Container at the specified `index`.
*
* The View Container is located via `viewContainerLocation`.
*/
abstract destroyViewInContainer(viewContainerLocation: ElementRef, index: number);
/**
*
* See {@link AppViewManager#detachViewInContainer}.
*/
// TODO(i): refactor detachViewInContainer+attachViewInContainer to moveViewInContainer
abstract attachViewInContainer(viewContainerLocation: ElementRef, index: number,
viewRef: ViewRef): ViewRef;
/**
* See {@link AppViewManager#attachViewInContainer}.
*/
abstract detachViewInContainer(viewContainerLocation: ElementRef, index: number): ViewRef;
}
@Injectable()
export class AppViewManager_ extends AppViewManager {
private _protoViewFactory: ProtoViewFactory;
constructor(private _viewPool: AppViewPool, private _viewListener: AppViewListener,
private _utils: AppViewManagerUtils, private _renderer: Renderer,
@Inject(forwardRef(() => ProtoViewFactory)) _protoViewFactory) {
super();
this._protoViewFactory = _protoViewFactory;
}
getViewContainer(location: ElementRef): ViewContainerRef {
var hostView = internalView((<ElementRef_>location).parentView);
return hostView.elementInjectors[(<ElementRef_>location).boundElementIndex]
.getViewContainerRef();
}
getNamedElementInComponentView(hostLocation: ElementRef, variableName: string): ElementRef {
var hostView = internalView((<ElementRef_>hostLocation).parentView);
var boundElementIndex = (<ElementRef_>hostLocation).boundElementIndex;
var componentView = hostView.getNestedView(boundElementIndex);
if (isBlank(componentView)) {
throw new BaseException(`There is no component directive at element ${boundElementIndex}`);
}
var binderIdx = componentView.proto.variableLocations.get(variableName);
if (isBlank(binderIdx)) {
throw new BaseException(`Could not find variable ${variableName}`);
}
return componentView.elementRefs[componentView.elementOffset + binderIdx];
}
getComponent(hostLocation: ElementRef): any {
var hostView = internalView((<ElementRef_>hostLocation).parentView);
var boundElementIndex = (<ElementRef_>hostLocation).boundElementIndex;
return this._utils.getComponentInstance(hostView, boundElementIndex);
}
_createRootHostViewScope: WtfScopeFn = wtfCreateScope('AppViewManager#createRootHostView()');
createRootHostView(hostProtoViewRef: ProtoViewRef, overrideSelector: string,
injector: Injector): HostViewRef {
var s = this._createRootHostViewScope();
@ -165,12 +241,6 @@ export class AppViewManager {
_destroyRootHostViewScope: WtfScopeFn = wtfCreateScope('AppViewManager#destroyRootHostView()');
/**
* Destroys the Host View created via {@link AppViewManager#createRootHostView}.
*
* Along with the Host View, the Component Instance as well as all nested View and Components are
* destroyed as well.
*/
destroyRootHostView(hostViewRef: HostViewRef) {
// Note: Don't put the hostView into the view pool
// as it is depending on the element for which it was created.
@ -187,23 +257,10 @@ export class AppViewManager {
_createEmbeddedViewInContainerScope: WtfScopeFn =
wtfCreateScope('AppViewManager#createEmbeddedViewInContainer()');
/**
* Instantiates an Embedded View based on the {@link TemplateRef `templateRef`} and inserts it
* into the View Container specified via `viewContainerLocation` at the specified `index`.
*
* Returns the {@link ViewRef} for the newly created View.
*
* This as a low-level way to create and attach an Embedded via to a View Container. Most
* applications should used {@link ViewContainerRef#createEmbeddedView} instead.
*
* Use {@link AppViewManager#destroyViewInContainer} to destroy the created Embedded View.
*/
// TODO(i): this low-level version of ViewContainerRef#createEmbeddedView doesn't add anything new
// we should make it private, otherwise we have two apis to do the same thing.
createEmbeddedViewInContainer(viewContainerLocation: ElementRef, index: number,
templateRef: TemplateRef): ViewRef {
var s = this._createEmbeddedViewInContainerScope();
var protoView = internalProtoView(templateRef.protoViewRef);
var protoView = internalProtoView((<TemplateRef_>templateRef).protoViewRef);
if (protoView.type !== viewModule.ViewType.EMBEDDED) {
throw new BaseException('This method can only be called with embedded ProtoViews!');
}
@ -215,21 +272,6 @@ export class AppViewManager {
_createHostViewInContainerScope: WtfScopeFn =
wtfCreateScope('AppViewManager#createHostViewInContainer()');
/**
* Instantiates a single {@link Component} and inserts its Host View into the View Container
* found at `viewContainerLocation`. Within the container, the view will be inserted at position
* specified via `index`.
*
* The component is instantiated using its {@link ProtoViewRef `protoViewRef`} which can be
* obtained via {@link Compiler#compileInHost}.
*
* You can optionally specify `imperativelyCreatedInjector`, which configure the {@link Injector}
* that will be created for the Host View.
*
* Returns the {@link HostViewRef} of the Host View created for the newly instantiated Component.
*
* Use {@link AppViewManager#destroyViewInContainer} to destroy the created Host View.
*/
createHostViewInContainer(viewContainerLocation: ElementRef, index: number,
protoViewRef: ProtoViewRef,
imperativelyCreatedInjector: ResolvedBinding[]): HostViewRef {
@ -251,10 +293,10 @@ export class AppViewManager {
_createViewInContainer(viewContainerLocation: ElementRef, index: number,
protoView: viewModule.AppProtoView, context: ElementRef,
imperativelyCreatedInjector: ResolvedBinding[]): ViewRef {
var parentView = internalView(viewContainerLocation.parentView);
var boundElementIndex = viewContainerLocation.boundElementIndex;
var contextView = internalView(context.parentView);
var contextBoundElementIndex = context.boundElementIndex;
var parentView = internalView((<ElementRef_>viewContainerLocation).parentView);
var boundElementIndex = (<ElementRef_>viewContainerLocation).boundElementIndex;
var contextView = internalView((<ElementRef_>context).parentView);
var contextBoundElementIndex = (<ElementRef_>context).boundElementIndex;
var embeddedFragmentView = contextView.getNestedView(contextBoundElementIndex);
var view;
if (protoView.type === viewModule.ViewType.EMBEDDED && isPresent(embeddedFragmentView) &&
@ -291,32 +333,23 @@ export class AppViewManager {
_destroyViewInContainerScope = wtfCreateScope('AppViewMananger#destroyViewInContainer()');
/**
* Destroys an Embedded or Host View attached to a View Container at the specified `index`.
*
* The View Container is located via `viewContainerLocation`.
*/
destroyViewInContainer(viewContainerLocation: ElementRef, index: number) {
var s = this._destroyViewInContainerScope();
var parentView = internalView(viewContainerLocation.parentView);
var boundElementIndex = viewContainerLocation.boundElementIndex;
var parentView = internalView((<ElementRef_>viewContainerLocation).parentView);
var boundElementIndex = (<ElementRef_>viewContainerLocation).boundElementIndex;
this._destroyViewInContainer(parentView, boundElementIndex, index);
wtfLeave(s);
}
_attachViewInContainerScope = wtfCreateScope('AppViewMananger#attachViewInContainer()');
/**
*
* See {@link AppViewManager#detachViewInContainer}.
*/
// TODO(i): refactor detachViewInContainer+attachViewInContainer to moveViewInContainer
attachViewInContainer(viewContainerLocation: ElementRef, index: number,
viewRef: ViewRef): ViewRef {
var s = this._attachViewInContainerScope();
var view = internalView(viewRef);
var parentView = internalView(viewContainerLocation.parentView);
var boundElementIndex = viewContainerLocation.boundElementIndex;
var parentView = internalView((<ElementRef_>viewContainerLocation).parentView);
var boundElementIndex = (<ElementRef_>viewContainerLocation).boundElementIndex;
// TODO(tbosch): the public methods attachViewInContainer/detachViewInContainer
// are used for moving elements without the same container.
// We will change this into an atomic `move` operation, which should preserve the
@ -330,14 +363,11 @@ export class AppViewManager {
_detachViewInContainerScope = wtfCreateScope('AppViewMananger#detachViewInContainer()');
/**
* See {@link AppViewManager#attachViewInContainer}.
*/
// TODO(i): refactor detachViewInContainer+attachViewInContainer to moveViewInContainer
detachViewInContainer(viewContainerLocation: ElementRef, index: number): ViewRef {
var s = this._detachViewInContainerScope();
var parentView = internalView(viewContainerLocation.parentView);
var boundElementIndex = viewContainerLocation.boundElementIndex;
var parentView = internalView((<ElementRef_>viewContainerLocation).parentView);
var boundElementIndex = (<ElementRef_>viewContainerLocation).boundElementIndex;
var viewContainer = parentView.viewContainers[boundElementIndex];
var view = viewContainer.views[index];
this._utils.detachViewInContainer(parentView, boundElementIndex, index);

View File

@ -9,6 +9,8 @@ import {TemplateRef} from './template_ref';
import {Renderer, RenderViewWithFragments} from 'angular2/src/core/render/api';
import {Locals} from 'angular2/src/core/change_detection/change_detection';
import {Pipes} from 'angular2/src/core/pipes/pipes';
import {TemplateRef_} from "./template_ref";
import {ElementRef_} from "./element_ref";
@Injectable()
export class AppViewManagerUtils {
@ -86,14 +88,14 @@ export class AppViewManagerUtils {
elementInjectors[boundElementIndex] = elementInjector;
// elementRefs
var el = new ElementRef(currentView.ref, boundElementIndex, renderer);
var el = new ElementRef_(currentView.ref, boundElementIndex, renderer);
elementRefs[el.boundElementIndex] = el;
// preBuiltObjects
if (isPresent(elementInjector)) {
var templateRef = isPresent(binder.nestedProtoView) &&
binder.nestedProtoView.type === viewModule.ViewType.EMBEDDED ?
new TemplateRef(el) :
new TemplateRef_(el) :
null;
preBuiltObjects[boundElementIndex] =
new eli.PreBuiltObjects(viewManager, currentView, el, templateRef);

View File

@ -1,16 +1,17 @@
import {isPresent} from 'angular2/src/core/facade/lang';
import {unimplemented} from 'angular2/src/core/facade/exceptions';
import * as viewModule from './view';
import {ChangeDetectorRef} from '../change_detection/change_detector_ref';
import {RenderViewRef, RenderFragmentRef} from 'angular2/src/core/render/api';
// This is a workaround for privacy in Dart as we don't have library parts
export function internalView(viewRef: ViewRef): viewModule.AppView {
return viewRef._view;
return (<ViewRef_>viewRef)._view;
}
// This is a workaround for privacy in Dart as we don't have library parts
export function internalProtoView(protoViewRef: ProtoViewRef): viewModule.AppProtoView {
return isPresent(protoViewRef) ? protoViewRef._protoView : null;
return isPresent(protoViewRef) ? (<ProtoViewRef_>protoViewRef)._protoView : null;
}
@ -83,31 +84,34 @@ export interface HostViewRef {
* <!-- /ViewRef: outer-0 -->
* ```
*/
export class ViewRef implements HostViewRef {
export abstract class ViewRef implements HostViewRef {
/**
* Sets `value` of local variable called `variableName` in this View.
*/
abstract setLocal(variableName: string, value: any): void;
get changeDetectorRef(): ChangeDetectorRef { return unimplemented(); }
set changeDetectorRef(value: ChangeDetectorRef) {
unimplemented(); // TODO: https://github.com/Microsoft/TypeScript/issues/12
}
}
export class ViewRef_ extends ViewRef {
private _changeDetectorRef: ChangeDetectorRef = null;
/**
* @internal
*/
constructor(public _view: viewModule.AppView) {}
constructor(public _view: viewModule.AppView) { super(); }
/**
* @internal
*
* Return `RenderViewRef`
*/
get render(): RenderViewRef { return this._view.render; }
/**
* @internal
*
* Return `RenderFragmentRef`
*/
get renderFragment(): RenderFragmentRef { return this._view.renderFragment; }
/**
* @internal
*
* Return `ChangeDetectorRef`
*/
get changeDetectorRef(): ChangeDetectorRef {
@ -116,13 +120,7 @@ export class ViewRef implements HostViewRef {
}
return this._changeDetectorRef;
}
set changeDetectorRef(value: ChangeDetectorRef) {
throw "readonly"; // TODO: https://github.com/Microsoft/TypeScript/issues/12
}
/**
* Sets `value` of local variable called `variableName` in this View.
*/
setLocal(variableName: string, value: any): void { this._view.setLocal(variableName, value); }
}
@ -165,9 +163,8 @@ export class ViewRef implements HostViewRef {
*
* Notice that the original template is broken down into two separate ProtoViews.
*/
export class ProtoViewRef {
/**
* @internal
*/
constructor(public _protoView: viewModule.AppProtoView) {}
export abstract class ProtoViewRef {}
export class ProtoViewRef_ extends ProtoViewRef {
constructor(public _protoView: viewModule.AppProtoView) { super(); }
}