refactor(core): ts’ify core

This commit is contained in:
Tobias Bosch
2015-05-20 16:30:41 -07:00
parent aabc898f3b
commit e61d82b9be
56 changed files with 2128 additions and 1922 deletions
@@ -6,5 +6,7 @@
export {
Component as ComponentAnnotation,
Directive as DirectiveAnnotation,
onDestroy, onChange, onAllChangesDone
onDestroy,
onChange,
onAllChangesDone
} from '../annotations_impl/annotations';
@@ -1,7 +1,4 @@
import {
ComponentAnnotation,
DirectiveAnnotation
} from './annotations';
import {ComponentAnnotation, DirectiveAnnotation} from './annotations';
import {ViewAnnotation} from './view';
import {AncestorAnnotation, ParentAnnotation} from './visibility';
import {AttributeAnnotation, QueryAnnotation} from './di';
@@ -1,3 +0,0 @@
export {
View as ViewAnnotation,
} from '../annotations_impl/view';
@@ -0,0 +1,3 @@
export {
View as ViewAnnotation,
} from '../annotations_impl/view';
@@ -1,4 +1,4 @@
export {
Ancestor as AncestorAnnotation,
Parent as ParentAnnotation,
} from '../annotations_impl/visibility';
} from '../annotations_impl/visibility';
@@ -29,19 +29,16 @@ import {DependencyAnnotation} from 'angular2/src/di/annotations_impl';
*
* @exportedAs angular2/annotations
*/
@CONST()
export class Attribute extends DependencyAnnotation {
attributeName: string;
@CONST()
constructor(attributeName) {
super();
this.attributeName = attributeName;
}
constructor(public attributeName: string) { super(); }
get token() {
//Normally one would default a token to a type of an injected value but here
//the type of a variable is "string" and we can't use primitive type as a return value
//so we use instance of Attribute instead. This doesn't matter much in practice as arguments
//with @Attribute annotation are injected by ElementInjector that doesn't take tokens into account.
// Normally one would default a token to a type of an injected value but here
// the type of a variable is "string" and we can't use primitive type as a return value
// so we use instance of Attribute instead. This doesn't matter much in practice as arguments
// with @Attribute annotation are injected by ElementInjector that doesn't take tokens into
// account.
return this;
}
}
@@ -53,11 +50,7 @@ export class Attribute extends DependencyAnnotation {
*
* @exportedAs angular2/annotations
*/
@CONST()
export class Query extends DependencyAnnotation {
directive;
@CONST()
constructor(directive) {
super();
this.directive = directive;
}
constructor(public directive: any) { super(); }
}
@@ -3,10 +3,13 @@ import {ABSTRACT, CONST, Type} from 'angular2/src/facade/lang';
/**
* Declares the available HTML templates for an application.
*
* Each angular component requires a single `@Component` and at least one `@View` annotation. The @View
* annotation specifies the HTML template to use, and lists the directives that are active within the template.
* Each angular component requires a single `@Component` and at least one `@View` annotation. The
* @View
* annotation specifies the HTML template to use, and lists the directives that are active within
* the template.
*
* When a component is instantiated, the template is loaded into the component's shadow root, and the
* When a component is instantiated, the template is loaded into the component's shadow root, and
* the
* expressions and statements in the template are evaluated against the component.
*
* For details on the `@Component` annotation, see {@link Component}.
@@ -32,20 +35,21 @@ import {ABSTRACT, CONST, Type} from 'angular2/src/facade/lang';
*
* @exportedAs angular2/annotations
*/
@CONST()
export class View {
/**
* Specifies a template URL for an angular component.
*
* NOTE: either `templateUrl` or `template` should be used, but not both.
*/
templateUrl:string;
templateUrl: string;
/**
* Specifies an inline template for an angular component.
*
* NOTE: either `templateUrl` or `template` should be used, but not both.
*/
template:string;
template: string;
/**
* Specifies a list of directives that can be used within a template.
@@ -69,26 +73,25 @@ export class View {
* }
* ```
*/
directives:List<Type>;
directives: List<Type>;
/**
* Specify a custom renderer for this View.
* If this is set, neither `template`, `templateURL` nor `directives` are used.
*/
renderer:any; // string;
renderer: string;
@CONST()
constructor({
templateUrl,
template,
directives,
renderer
}: {
templateUrl: string,
template: string,
directives: List<Type>,
renderer: string
})
templateUrl?: string,
template?: string,
directives?: List<Type>,
renderer?: string
} = {})
{
this.templateUrl = templateUrl;
this.template = template;
@@ -1,20 +1,11 @@
import {CONST, CONST_EXPR} from 'angular2/src/facade/lang';
import {DependencyAnnotation} from 'angular2/src/di/annotations_impl';
@CONST()
export class Visibility extends DependencyAnnotation {
depth: number;
crossComponentBoundaries: boolean;
constructor(public depth: number, public crossComponentBoundaries: boolean) { super(); }
@CONST()
constructor(depth:number, crossComponentBoundaries:boolean) {
super();
this.depth = depth;
this.crossComponentBoundaries = crossComponentBoundaries;
}
shouldIncludeSelf():boolean {
return this.depth === 0;
}
shouldIncludeSelf(): boolean { return this.depth === 0; }
}
/**
@@ -54,11 +45,9 @@ export class Visibility extends DependencyAnnotation {
*
* @exportedAs angular2/annotations
*/
@CONST()
export class Self extends Visibility {
@CONST()
constructor() {
super(0, false);
}
constructor() { super(0, false); }
}
// make constants after switching to ts2dart
@@ -100,20 +89,21 @@ export var self = new Self();
* <div dependency="2" my-directive></div>
* </div>
* ```
* The `@Parent()` annotation in our constructor forces the injector to retrieve the dependency from the
* parent element (even thought the current element could resolve it): Angular injects `dependency=1`.
* The `@Parent()` annotation in our constructor forces the injector to retrieve the dependency from
* the
* parent element (even thought the current element could resolve it): Angular injects
* `dependency=1`.
*
* @exportedAs angular2/annotations
*/
@CONST()
export class Parent extends Visibility {
@CONST()
constructor() {
super(1, false);
}
constructor() { super(1, false); }
}
/**
* Specifies that an injector should retrieve a dependency from any ancestor element within the same shadow boundary.
* Specifies that an injector should retrieve a dependency from any ancestor element within the same
* shadow boundary.
*
* An ancestor is any element between the parent element and shadow root.
*
@@ -156,7 +146,8 @@ export class Parent extends Visibility {
* </div>
* ```
*
* The `@Ancestor()` annotation in our constructor forces the injector to retrieve the dependency from the
* The `@Ancestor()` annotation in our constructor forces the injector to retrieve the dependency
* from the
* nearest ancestor element:
* - The current element `dependency="3"` is skipped because it is not an ancestor.
* - Next parent has no directives `<div>`
@@ -166,11 +157,9 @@ export class Parent extends Visibility {
*
* @exportedAs angular2/annotations
*/
@CONST()
export class Ancestor extends Visibility {
@CONST()
constructor() {
super(999999, false);
}
constructor() { super(999999, false); }
}
/**
@@ -207,9 +196,7 @@ export class Ancestor extends Visibility {
*
* @exportedAs angular2/annotations
*/
@CONST()
export class Unbounded extends Visibility {
@CONST()
constructor() {
super(999999, true);
}
constructor() { super(999999, true); }
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-4
View File
@@ -1,4 +0,0 @@
import {OpaqueToken} from 'angular2/di';
export var appComponentRefToken:OpaqueToken = new OpaqueToken('ComponentRef');
export var appComponentTypeToken:OpaqueToken = new OpaqueToken('RootComponent');
@@ -0,0 +1,4 @@
import {OpaqueToken} from 'angular2/di';
export var appComponentRefToken: OpaqueToken = new OpaqueToken('ComponentRef');
export var appComponentTypeToken: OpaqueToken = new OpaqueToken('RootComponent');
@@ -21,9 +21,7 @@ export class BaseQueryList {
this._dirty = false;
}
[Symbol.iterator]() {
return this._results[Symbol.iterator]();
}
[Symbol.iterator]() { return this._results[Symbol.iterator](); }
reset(newList) {
this._results = newList;
@@ -43,11 +41,7 @@ export class BaseQueryList {
}
}
onChange(callback) {
ListWrapper.push(this._callbacks, callback);
}
onChange(callback) { ListWrapper.push(this._callbacks, callback); }
removeCallback(callback) {
ListWrapper.remove(this._callbacks, callback);
}
removeCallback(callback) { ListWrapper.remove(this._callbacks, callback); }
}
-258
View File
@@ -1,258 +0,0 @@
import {Binding, resolveForwardRef} from 'angular2/di';
import {Injectable} from 'angular2/src/di/annotations_impl';
import {Type, isBlank, isPresent, BaseException, normalizeBlank, stringify} from 'angular2/src/facade/lang';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection';
import {DirectiveResolver} from './directive_resolver';
import {AppProtoView} from './view';
import {ElementBinder} from './element_binder';
import {ProtoViewRef} from './view_ref';
import {DirectiveBinding} from './element_injector';
import {TemplateResolver} from './template_resolver';
import {View} from '../annotations_impl/view';
import {ComponentUrlMapper} from './component_url_mapper';
import {ProtoViewFactory} from './proto_view_factory';
import {UrlResolver} from 'angular2/src/services/url_resolver';
import * as renderApi from 'angular2/src/render/api';
/**
* Cache that stores the AppProtoView of the template of a component.
* Used to prevent duplicate work and resolve cyclic dependencies.
*/
@Injectable()
export class CompilerCache {
_cache:Map;
constructor() {
this._cache = MapWrapper.create();
}
set(component:Type, protoView:AppProtoView):void {
MapWrapper.set(this._cache, component, protoView);
}
get(component:Type):AppProtoView {
var result = MapWrapper.get(this._cache, component);
return normalizeBlank(result);
}
clear():void {
MapWrapper.clear(this._cache);
}
}
/**
* @exportedAs angular2/view
*/
@Injectable()
export class Compiler {
_reader: DirectiveResolver;
_compilerCache:CompilerCache;
_compiling:Map<Type, Promise>;
_templateResolver: TemplateResolver;
_componentUrlMapper: ComponentUrlMapper;
_urlResolver: UrlResolver;
_appUrl: string;
_render: renderApi.RenderCompiler;
_protoViewFactory:ProtoViewFactory;
constructor(reader: DirectiveResolver,
cache:CompilerCache,
templateResolver: TemplateResolver,
componentUrlMapper: ComponentUrlMapper,
urlResolver: UrlResolver,
render: renderApi.RenderCompiler,
protoViewFactory: ProtoViewFactory) {
this._reader = reader;
this._compilerCache = cache;
this._compiling = MapWrapper.create();
this._templateResolver = templateResolver;
this._componentUrlMapper = componentUrlMapper;
this._urlResolver = urlResolver;
this._appUrl = urlResolver.resolve(null, './');
this._render = render;
this._protoViewFactory = protoViewFactory;
}
_bindDirective(directiveTypeOrBinding):DirectiveBinding {
if (directiveTypeOrBinding instanceof DirectiveBinding) {
return directiveTypeOrBinding;
} else if (directiveTypeOrBinding instanceof Binding) {
let annotation = this._reader.resolve(directiveTypeOrBinding.token);
return DirectiveBinding.createFromBinding(directiveTypeOrBinding, annotation);
} else {
let annotation = this._reader.resolve(directiveTypeOrBinding);
return DirectiveBinding.createFromType(directiveTypeOrBinding, annotation);
}
}
// Create a hostView as if the compiler encountered <hostcmp></hostcmp>.
// Used for bootstrapping.
compileInHost(componentTypeOrBinding:any):Promise<ProtoViewRef> {
var componentBinding = this._bindDirective(componentTypeOrBinding);
Compiler._assertTypeIsComponent(componentBinding);
var directiveMetadata = componentBinding.metadata;
return this._render.compileHost(directiveMetadata).then( (hostRenderPv) => {
return this._compileNestedProtoViews(componentBinding, hostRenderPv, [componentBinding]);
}).then( (appProtoView) => {
return new ProtoViewRef(appProtoView);
});
}
compile(component: Type):Promise<ProtoViewRef> {
var componentBinding = this._bindDirective(component);
Compiler._assertTypeIsComponent(componentBinding);
var protoView = this._compile(componentBinding);
var pvPromise = PromiseWrapper.isPromise(protoView) ? protoView : PromiseWrapper.resolve(protoView);
return pvPromise.then( (appProtoView) => {
return new ProtoViewRef(appProtoView);
});
}
// TODO(vicb): union type return AppProtoView or Promise<AppProtoView>
_compile(componentBinding: DirectiveBinding) {
var component = componentBinding.key.token;
var protoView = this._compilerCache.get(component);
if (isPresent(protoView)) {
// The component has already been compiled into an AppProtoView,
// returns a plain AppProtoView, not wrapped inside of a Promise.
// Needed for recursive components.
return protoView;
}
var pvPromise = MapWrapper.get(this._compiling, component);
if (isPresent(pvPromise)) {
// The component is already being compiled, attach to the existing Promise
// instead of re-compiling the component.
// It happens when a template references a component multiple times.
return pvPromise;
}
var template = this._templateResolver.resolve(component);
if (isBlank(template)) {
return null;
}
var directives = this._flattenDirectives(template);
for (var i = 0; i < directives.length; i++) {
if (!Compiler._isValidDirective(directives[i])) {
throw new BaseException(
`Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
}
}
var boundDirectives = ListWrapper.map(directives, (directive) => this._bindDirective(directive));
var renderTemplate = this._buildRenderTemplate(component, template, boundDirectives);
pvPromise = this._render.compile(renderTemplate).then( (renderPv) => {
return this._compileNestedProtoViews(componentBinding, renderPv, boundDirectives);
});
MapWrapper.set(this._compiling, component, pvPromise);
return pvPromise;
}
// TODO(tbosch): union type return AppProtoView or Promise<AppProtoView>
_compileNestedProtoViews(componentBinding, renderPv, directives) {
var protoViews = this._protoViewFactory.createAppProtoViews(componentBinding, renderPv, directives);
var protoView = protoViews[0];
// TODO(tbosch): we should be caching host protoViews as well!
// -> need a separate cache for this...
if (renderPv.type === renderApi.ProtoViewDto.COMPONENT_VIEW_TYPE && isPresent(componentBinding)) {
// Populate the cache before compiling the nested components,
// so that components can reference themselves in their template.
var component = componentBinding.key.token;
this._compilerCache.set(component, protoView);
MapWrapper.delete(this._compiling, component);
}
var nestedPVPromises = [];
ListWrapper.forEach(this._collectComponentElementBinders(protoViews), (elementBinder) => {
var nestedComponent = elementBinder.componentDirective;
var elementBinderDone = (nestedPv) => {
elementBinder.nestedProtoView = nestedPv;
};
var nestedCall = this._compile(nestedComponent);
if (PromiseWrapper.isPromise(nestedCall)) {
ListWrapper.push(nestedPVPromises, nestedCall.then(elementBinderDone));
} else if (isPresent(nestedCall)) {
elementBinderDone(nestedCall);
}
});
var protoViewDone = (_) => {
return protoView;
};
if (nestedPVPromises.length > 0) {
return PromiseWrapper.all(nestedPVPromises).then(protoViewDone);
} else {
return protoViewDone(null);
}
}
_collectComponentElementBinders(protoViews:List<AppProtoView>):List<ElementBinder> {
var componentElementBinders = [];
ListWrapper.forEach(protoViews, (protoView) => {
ListWrapper.forEach(protoView.elementBinders, (elementBinder) => {
if (isPresent(elementBinder.componentDirective)) {
ListWrapper.push(componentElementBinders, elementBinder);
}
});
});
return componentElementBinders;
}
_buildRenderTemplate(component, view, directives): renderApi.ViewDefinition {
var componentUrl = this._urlResolver.resolve(
this._appUrl, this._componentUrlMapper.getUrl(component)
);
var templateAbsUrl = null;
if (isPresent(view.templateUrl)) {
templateAbsUrl = this._urlResolver.resolve(componentUrl, view.templateUrl);
} else if (isPresent(view.template)) {
// Note: If we have an inline template, we also need to send
// the url for the component to the render so that it
// is able to resolve urls in stylesheets.
templateAbsUrl = componentUrl;
}
return new renderApi.ViewDefinition({
componentId: stringify(component),
absUrl: templateAbsUrl,
template: view.template,
directives: ListWrapper.map(directives, directiveBinding => directiveBinding.metadata )
});
}
_flattenDirectives(template: View):List<Type> {
if (isBlank(template.directives)) return [];
var directives = [];
this._flattenList(template.directives, directives);
return directives;
}
_flattenList(tree:List<any>, out:List<any> /*<Type|Binding>*/):void {
for (var i = 0; i < tree.length; i++) {
var item = resolveForwardRef(tree[i]);
if (ListWrapper.isList(item)) {
this._flattenList(item, out);
} else {
ListWrapper.push(out, item);
}
}
}
static _isValidDirective(value: any): boolean {
return isPresent(value) && (value instanceof Type || value instanceof Binding);
}
static _assertTypeIsComponent(directiveBinding:DirectiveBinding):void {
if (directiveBinding.metadata.type !== renderApi.DirectiveMetadata.COMPONENT_TYPE) {
throw new BaseException(`Could not load '${stringify(directiveBinding.key.token)}' because it is not a component.`);
}
}
}
@@ -0,0 +1,258 @@
import {Binding, resolveForwardRef, Injectable} from 'angular2/di';
import {
Type,
isBlank,
isPresent,
BaseException,
normalizeBlank,
stringify
} from 'angular2/src/facade/lang';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection';
import {DirectiveResolver} from './directive_resolver';
import {AppProtoView} from './view';
import {ElementBinder} from './element_binder';
import {ProtoViewRef} from './view_ref';
import {DirectiveBinding} from './element_injector';
import {TemplateResolver} from './template_resolver';
import {View} from '../annotations_impl/view';
import {ComponentUrlMapper} from './component_url_mapper';
import {ProtoViewFactory} from './proto_view_factory';
import {UrlResolver} from 'angular2/src/services/url_resolver';
import * as renderApi from 'angular2/src/render/api';
/**
* Cache that stores the AppProtoView of the template of a component.
* Used to prevent duplicate work and resolve cyclic dependencies.
*/
@Injectable()
export class CompilerCache {
_cache: Map<Type, AppProtoView>;
constructor() { this._cache = MapWrapper.create(); }
set(component: Type, protoView: AppProtoView): void {
MapWrapper.set(this._cache, component, protoView);
}
get(component: Type): AppProtoView {
var result = MapWrapper.get(this._cache, component);
return normalizeBlank(result);
}
clear(): void { MapWrapper.clear(this._cache); }
}
/**
* @exportedAs angular2/view
*/
@Injectable()
export class Compiler {
private _reader: DirectiveResolver;
private _compilerCache: CompilerCache;
private _compiling: Map<Type, Promise<AppProtoView>>;
private _templateResolver: TemplateResolver;
private _componentUrlMapper: ComponentUrlMapper;
private _urlResolver: UrlResolver;
private _appUrl: string;
private _render: renderApi.RenderCompiler;
private _protoViewFactory: ProtoViewFactory;
constructor(reader: DirectiveResolver, cache: CompilerCache, templateResolver: TemplateResolver,
componentUrlMapper: ComponentUrlMapper, urlResolver: UrlResolver,
render: renderApi.RenderCompiler, protoViewFactory: ProtoViewFactory) {
this._reader = reader;
this._compilerCache = cache;
this._compiling = MapWrapper.create();
this._templateResolver = templateResolver;
this._componentUrlMapper = componentUrlMapper;
this._urlResolver = urlResolver;
this._appUrl = urlResolver.resolve(null, './');
this._render = render;
this._protoViewFactory = protoViewFactory;
}
private _bindDirective(directiveTypeOrBinding): DirectiveBinding {
if (directiveTypeOrBinding instanceof DirectiveBinding) {
return directiveTypeOrBinding;
} else if (directiveTypeOrBinding instanceof Binding) {
let annotation = this._reader.resolve(directiveTypeOrBinding.token);
return DirectiveBinding.createFromBinding(directiveTypeOrBinding, annotation);
} else {
let annotation = this._reader.resolve(directiveTypeOrBinding);
return DirectiveBinding.createFromType(directiveTypeOrBinding, annotation);
}
}
// Create a hostView as if the compiler encountered <hostcmp></hostcmp>.
// Used for bootstrapping.
compileInHost(componentTypeOrBinding: Type | Binding): Promise<ProtoViewRef> {
var componentBinding = this._bindDirective(componentTypeOrBinding);
Compiler._assertTypeIsComponent(componentBinding);
var directiveMetadata = componentBinding.metadata;
return this._render.compileHost(directiveMetadata)
.then((hostRenderPv) =>
{
return this._compileNestedProtoViews(componentBinding, hostRenderPv,
[componentBinding]);
})
.then((appProtoView) => { return new ProtoViewRef(appProtoView); });
}
compile(component: Type): Promise<ProtoViewRef> {
var componentBinding = this._bindDirective(component);
Compiler._assertTypeIsComponent(componentBinding);
var pvOrPromise = this._compile(componentBinding);
var pvPromise = PromiseWrapper.isPromise(pvOrPromise) ? <Promise<AppProtoView>>pvOrPromise :
PromiseWrapper.resolve(pvOrPromise);
return pvPromise.then((appProtoView) => { return new ProtoViewRef(appProtoView); });
}
private _compile(componentBinding: DirectiveBinding): Promise<AppProtoView>| AppProtoView {
var component = <Type>componentBinding.key.token;
var protoView = this._compilerCache.get(component);
if (isPresent(protoView)) {
// The component has already been compiled into an AppProtoView,
// returns a plain AppProtoView, not wrapped inside of a Promise.
// Needed for recursive components.
return protoView;
}
var pvPromise = MapWrapper.get(this._compiling, component);
if (isPresent(pvPromise)) {
// The component is already being compiled, attach to the existing Promise
// instead of re-compiling the component.
// It happens when a template references a component multiple times.
return pvPromise;
}
var template = this._templateResolver.resolve(component);
if (isBlank(template)) {
return null;
}
var directives = this._flattenDirectives(template);
for (var i = 0; i < directives.length; i++) {
if (!Compiler._isValidDirective(directives[i])) {
throw new BaseException(
`Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
}
}
var boundDirectives =
ListWrapper.map(directives, (directive) => this._bindDirective(directive));
var renderTemplate = this._buildRenderTemplate(component, template, boundDirectives);
pvPromise =
this._render.compile(renderTemplate)
.then((renderPv) => {
return this._compileNestedProtoViews(componentBinding, renderPv, boundDirectives);
});
MapWrapper.set(this._compiling, component, pvPromise);
return pvPromise;
}
private _compileNestedProtoViews(componentBinding, renderPv, directives): Promise<AppProtoView>|
AppProtoView {
var protoViews =
this._protoViewFactory.createAppProtoViews(componentBinding, renderPv, directives);
var protoView = protoViews[0];
// TODO(tbosch): we should be caching host protoViews as well!
// -> need a separate cache for this...
if (renderPv.type === renderApi.ProtoViewDto.COMPONENT_VIEW_TYPE &&
isPresent(componentBinding)) {
// Populate the cache before compiling the nested components,
// so that components can reference themselves in their template.
var component = componentBinding.key.token;
this._compilerCache.set(component, protoView);
MapWrapper.delete(this._compiling, component);
}
var nestedPVPromises = [];
ListWrapper.forEach(this._collectComponentElementBinders(protoViews), (elementBinder) => {
var nestedComponent = elementBinder.componentDirective;
var elementBinderDone = (nestedPv: AppProtoView) => {
elementBinder.nestedProtoView = nestedPv;
};
var nestedCall = this._compile(nestedComponent);
if (PromiseWrapper.isPromise(nestedCall)) {
ListWrapper.push(nestedPVPromises,
(<Promise<AppProtoView>>nestedCall).then(elementBinderDone));
} else if (isPresent(nestedCall)) {
elementBinderDone(<AppProtoView>nestedCall);
}
});
if (nestedPVPromises.length > 0) {
return PromiseWrapper.all(nestedPVPromises).then((_) => protoView);
} else {
return protoView;
}
}
private _collectComponentElementBinders(protoViews: List<AppProtoView>): List<ElementBinder> {
var componentElementBinders = [];
ListWrapper.forEach(protoViews, (protoView) => {
ListWrapper.forEach(protoView.elementBinders, (elementBinder) => {
if (isPresent(elementBinder.componentDirective)) {
ListWrapper.push(componentElementBinders, elementBinder);
}
});
});
return componentElementBinders;
}
private _buildRenderTemplate(component, view, directives): renderApi.ViewDefinition {
var componentUrl =
this._urlResolver.resolve(this._appUrl, this._componentUrlMapper.getUrl(component));
var templateAbsUrl = null;
if (isPresent(view.templateUrl)) {
templateAbsUrl = this._urlResolver.resolve(componentUrl, view.templateUrl);
} else if (isPresent(view.template)) {
// Note: If we have an inline template, we also need to send
// the url for the component to the render so that it
// is able to resolve urls in stylesheets.
templateAbsUrl = componentUrl;
}
return new renderApi.ViewDefinition({
componentId: stringify(component),
absUrl: templateAbsUrl, template: view.template,
directives: ListWrapper.map(directives, directiveBinding => directiveBinding.metadata)
});
}
private _flattenDirectives(template: View): List<Type> {
if (isBlank(template.directives)) return [];
var directives = [];
this._flattenList(template.directives, directives);
return directives;
}
private _flattenList(tree: List<any>, out: List<Type | Binding | List<any>>): void {
for (var i = 0; i < tree.length; i++) {
var item = resolveForwardRef(tree[i]);
if (ListWrapper.isList(item)) {
this._flattenList(item, out);
} else {
ListWrapper.push(out, item);
}
}
}
private static _isValidDirective(value: Type | Binding): boolean {
return isPresent(value) && (value instanceof Type || value instanceof Binding);
}
private static _assertTypeIsComponent(directiveBinding: DirectiveBinding): void {
if (directiveBinding.metadata.type !== renderApi.DirectiveMetadata.COMPONENT_TYPE) {
throw new BaseException(
`Could not load '${stringify(directiveBinding.key.token)}' because it is not a component.`);
}
}
}
@@ -1,4 +1,4 @@
import {Injectable} from 'angular2/src/di/annotations_impl';
import {Injectable} from 'angular2/di';
import {Type, isPresent} from 'angular2/src/facade/lang';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
@@ -8,13 +8,11 @@ export class ComponentUrlMapper {
// The returned URL could be:
// - an absolute URL,
// - a path relative to the application
getUrl(component: Type): string {
return './';
}
getUrl(component: Type): string { return './'; }
}
export class RuntimeComponentUrlMapper extends ComponentUrlMapper {
_componentUrls: Map;
_componentUrls: Map<Type, string>;
constructor() {
super();
@@ -1,15 +1,14 @@
import {Injectable} from 'angular2/src/di/annotations_impl';
import {resolveForwardRef} from 'angular2/di';
import {resolveForwardRef, Injectable} from 'angular2/di';
import {Type, isPresent, BaseException, stringify} from 'angular2/src/facade/lang';
import {Directive} from '../annotations_impl/annotations';
import {reflector} from 'angular2/src/reflection/reflection';
@Injectable()
export class DirectiveResolver {
resolve(type:Type):Directive {
resolve(type: Type): Directive {
var annotations = reflector.annotations(resolveForwardRef(type));
if (isPresent(annotations)) {
for (var i=0; i<annotations.length; i++) {
for (var i = 0; i < annotations.length; i++) {
var annotation = annotations[i];
if (annotation instanceof Directive) {
@@ -19,5 +18,4 @@ export class DirectiveResolver {
}
throw new BaseException(`No Directive annotation found on ${stringify(type)}`);
}
}
@@ -1,132 +0,0 @@
import {Key, Injector, ResolvedBinding, Binding, bind} from 'angular2/di'
import {Injectable} from 'angular2/src/di/annotations_impl';
import {Compiler} from './compiler';
import {Type, BaseException, stringify, isPresent} from 'angular2/src/facade/lang';
import {Promise} from 'angular2/src/facade/async';
import {AppViewManager, ComponentCreateResult} from 'angular2/src/core/compiler/view_manager';
import {ElementRef} from './element_ref';
/**
* @exportedAs angular2/view
*/
export class ComponentRef {
location:ElementRef;
instance:any;
_dispose:Function;
constructor(location:ElementRef, instance:any, dispose:Function) {
this.location = location;
this.instance = instance;
this._dispose = dispose;
}
get hostView() {
return this.location.parentView;
}
dispose() {
this._dispose();
}
}
/**
* Service for dynamically loading a Component into an arbitrary position in the internal Angular
* application tree.
*
* @exportedAs angular2/view
*/
@Injectable()
export class DynamicComponentLoader {
_compiler:Compiler;
_viewManager:AppViewManager;
constructor(compiler:Compiler,
viewManager: AppViewManager) {
this._compiler = compiler;
this._viewManager = viewManager;
}
/**
* Loads a component into the location given by the provided ElementRef. The loaded component
* receives injection as if it in the place of the provided ElementRef.
*/
loadIntoExistingLocation(typeOrBinding, location:ElementRef, injector:Injector = null):Promise<ComponentRef> {
var binding = this._getBinding(typeOrBinding);
return this._compiler.compile(binding.token).then(componentProtoViewRef => {
this._viewManager.createDynamicComponentView(
location, componentProtoViewRef, binding, injector);
var component = this._viewManager.getComponent(location);
var dispose = () => {throw new BaseException("Not implemented");};
return new ComponentRef(location, component, dispose);
});
}
/**
* Loads a root component that is placed at the first element that matches the
* component's selector.
* The loaded component receives injection normally as a hosted view.
*/
loadAsRoot(typeOrBinding, overrideSelector = null, injector:Injector = null):Promise<ComponentRef> {
return this._compiler.compileInHost(this._getBinding(typeOrBinding)).then(hostProtoViewRef => {
var hostViewRef = this._viewManager.createRootHostView(hostProtoViewRef, overrideSelector, injector);
var newLocation = new ElementRef(hostViewRef, 0);
var component = this._viewManager.getComponent(newLocation);
var dispose = () => {
this._viewManager.destroyRootHostView(hostViewRef);
};
return new ComponentRef(newLocation, component, dispose);
});
}
/**
* Loads a component into a free host view that is not yet attached to
* a parent on the render side, although it is attached to a parent in the injector hierarchy.
* The loaded component receives injection normally as a hosted view.
*/
loadIntoNewLocation(typeOrBinding, parentComponentLocation:ElementRef,
injector:Injector = null):Promise<ComponentRef> {
return this._compiler.compileInHost(this._getBinding(typeOrBinding)).then(hostProtoViewRef => {
var hostViewRef = this._viewManager.createFreeHostView(
parentComponentLocation, hostProtoViewRef, injector);
var newLocation = new ElementRef(hostViewRef, 0);
var component = this._viewManager.getComponent(newLocation);
var dispose = () => {
this._viewManager.destroyFreeHostView(parentComponentLocation, hostViewRef);
};
return new ComponentRef(newLocation, component, dispose);
});
}
/**
* Loads a component next to the provided ElementRef. The loaded component receives
* injection normally as a hosted view.
*/
loadNextToExistingLocation(typeOrBinding, location:ElementRef, injector:Injector = null):Promise<ComponentRef> {
var binding = this._getBinding(typeOrBinding);
return this._compiler.compileInHost(binding).then(hostProtoViewRef => {
var viewContainer = this._viewManager.getViewContainer(location);
var hostViewRef = viewContainer.create(hostProtoViewRef, viewContainer.length, null, injector);
var newLocation = new ElementRef(hostViewRef, 0);
var component = this._viewManager.getComponent(newLocation);
var dispose = () => {
var index = viewContainer.indexOf(hostViewRef);
viewContainer.remove(index);
};
return new ComponentRef(newLocation, component, dispose);
});
}
_getBinding(typeOrBinding) {
var binding;
if (typeOrBinding instanceof Binding) {
binding = typeOrBinding;
} else {
binding = bind(typeOrBinding).toClass(typeOrBinding);
}
return binding;
}
}
@@ -0,0 +1,118 @@
import {Key, Injector, ResolvedBinding, Binding, bind, Injectable} from 'angular2/di';
import {Compiler} from './compiler';
import {Type, BaseException, stringify, isPresent} from 'angular2/src/facade/lang';
import {Promise} from 'angular2/src/facade/async';
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
import {ElementRef} from './element_ref';
import {ViewRef} from './view_ref';
/**
* @exportedAs angular2/view
*/
export class ComponentRef {
constructor(public location: ElementRef, public instance: any, public dispose: Function) {}
get hostView(): ViewRef { return this.location.parentView; }
}
/**
* Service for dynamically loading a Component into an arbitrary position in the internal Angular
* application tree.
*
* @exportedAs angular2/view
*/
@Injectable()
export class DynamicComponentLoader {
private _compiler: Compiler;
private _viewManager: AppViewManager;
constructor(compiler: Compiler, viewManager: AppViewManager) {
this._compiler = compiler;
this._viewManager = viewManager;
}
/**
* Loads a component into the location given by the provided ElementRef. The loaded component
* receives injection as if it in the place of the provided ElementRef.
*/
loadIntoExistingLocation(typeOrBinding, location: ElementRef,
injector: Injector = null): Promise<ComponentRef> {
var binding = this._getBinding(typeOrBinding);
return this._compiler.compile(binding.token).then(componentProtoViewRef => {
this._viewManager.createDynamicComponentView(location, componentProtoViewRef, binding,
injector);
var component = this._viewManager.getComponent(location);
var dispose = () => { throw new BaseException("Not implemented");};
return new ComponentRef(location, component, dispose);
});
}
/**
* Loads a root component that is placed at the first element that matches the
* component's selector.
* The loaded component receives injection normally as a hosted view.
*/
loadAsRoot(typeOrBinding, overrideSelector = null,
injector: Injector = null): Promise<ComponentRef> {
return this._compiler.compileInHost(this._getBinding(typeOrBinding)).then(hostProtoViewRef => {
var hostViewRef =
this._viewManager.createRootHostView(hostProtoViewRef, overrideSelector, injector);
var newLocation = new ElementRef(hostViewRef, 0);
var component = this._viewManager.getComponent(newLocation);
var dispose = () => { this._viewManager.destroyRootHostView(hostViewRef);
};
return new ComponentRef(newLocation, component, dispose);
});
}
/**
* Loads a component into a free host view that is not yet attached to
* a parent on the render side, although it is attached to a parent in the injector hierarchy.
* The loaded component receives injection normally as a hosted view.
*/
loadIntoNewLocation(typeOrBinding, parentComponentLocation: ElementRef,
injector: Injector = null): Promise<ComponentRef> {
return this._compiler.compileInHost(this._getBinding(typeOrBinding)).then(hostProtoViewRef => {
var hostViewRef =
this._viewManager.createFreeHostView(parentComponentLocation, hostProtoViewRef, injector);
var newLocation = new ElementRef(hostViewRef, 0);
var component = this._viewManager.getComponent(newLocation);
var dispose = () => {
this._viewManager.destroyFreeHostView(parentComponentLocation, hostViewRef);
};
return new ComponentRef(newLocation, component, dispose);
});
}
/**
* Loads a component next to the provided ElementRef. The loaded component receives
* injection normally as a hosted view.
*/
loadNextToExistingLocation(typeOrBinding, location: ElementRef,
injector: Injector = null): Promise<ComponentRef> {
var binding = this._getBinding(typeOrBinding);
return this._compiler.compileInHost(binding).then(hostProtoViewRef => {
var viewContainer = this._viewManager.getViewContainer(location);
var hostViewRef = viewContainer.create(hostProtoViewRef, viewContainer.length, null, injector);
var newLocation = new ElementRef(hostViewRef, 0);
var component = this._viewManager.getComponent(newLocation);
var dispose = () => { var index = viewContainer.indexOf(hostViewRef);
viewContainer.remove(index);
};
return new ComponentRef(newLocation, component, dispose);
});
}
private _getBinding(typeOrBinding): Binding {
var binding;
if (typeOrBinding instanceof Binding) {
binding = typeOrBinding;
} else {
binding = bind(typeOrBinding).toClass(typeOrBinding);
}
return binding;
}
}
@@ -1,3 +1,4 @@
import {AST} from 'angular2/change_detection';
import {int, isBlank, isPresent, BaseException} from 'angular2/src/facade/lang';
import * as eiModule from './element_injector';
import {DirectiveBinding} from './element_injector';
@@ -5,25 +6,14 @@ import {List, StringMap} from 'angular2/src/facade/collection';
import * as viewModule from './view';
export class ElementBinder {
protoElementInjector:eiModule.ProtoElementInjector;
componentDirective:DirectiveBinding;
nestedProtoView: viewModule.AppProtoView;
hostListeners:StringMap;
parent:ElementBinder;
index:int;
distanceToParent:int;
constructor(
index:int, parent:ElementBinder, distanceToParent: int,
protoElementInjector: eiModule.ProtoElementInjector, componentDirective:DirectiveBinding) {
hostListeners: StringMap<string, Map<number, AST>>;
constructor(public index: int, public parent: ElementBinder, public distanceToParent: int,
public protoElementInjector: eiModule.ProtoElementInjector,
public componentDirective: DirectiveBinding) {
if (isBlank(index)) {
throw new BaseException('null index not allowed.');
}
this.protoElementInjector = protoElementInjector;
this.componentDirective = componentDirective;
this.parent = parent;
this.index = index;
this.distanceToParent = distanceToParent;
// updated later when events are bound
this.hostListeners = null;
// updated later, so we are able to resolve cycles
@@ -7,10 +7,10 @@ import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
* @exportedAs angular2/view
*/
export class ElementRef {
parentView:ViewRef;
boundElementIndex:number;
parentView: ViewRef;
boundElementIndex: number;
constructor(parentView:ViewRef, boundElementIndex:number) {
constructor(parentView: ViewRef, boundElementIndex: number) {
this.parentView = parentView;
this.boundElementIndex = boundElementIndex;
}
@@ -33,7 +33,7 @@ export class ElementRef {
// TODO(tbosch): Here we expose the real DOM element.
// We need a more general way to read/write to the DOM element
// via a proper abstraction in the render layer
getAttribute(name:string):string {
getAttribute(name: string): string {
return normalizeBlank(DOM.getAttribute(this.domElement, name));
}
}
-8
View File
@@ -1,8 +0,0 @@
/**
* @exportedAs angular2/angular2
*/
export class OnChange {
onChange(changes) {
throw "OnChange.onChange is not implemented";
}
}
@@ -6,15 +6,18 @@ import {BaseQueryList} from './base_query_list';
* Injectable Objects that contains a live list of child directives in the light DOM of a directive.
* The directives are kept in depth-first pre-order traversal of the DOM.
*
* The `QueryList` is iterable, therefore it can be used in both javascript code with `for..of` loop as well as in
* The `QueryList` is iterable, therefore it can be used in both javascript code with `for..of` loop
* as well as in
* template with `*ng-for="of"` directive.
*
* NOTE: In the future this class will implement an `Observable` interface. For now it uses a plain list of observable
* NOTE: In the future this class will implement an `Observable` interface. For now it uses a plain
* list of observable
* callbacks.
*
* # Example:
*
* Assume that `<tabs>` component would like to get a list its children which are `<pane>` components as shown in this
* Assume that `<tabs>` component would like to get a list its children which are `<pane>`
* components as shown in this
* example:
*
* ```html
@@ -24,15 +27,21 @@ import {BaseQueryList} from './base_query_list';
* </tabs>
* ```
*
* In the above example the list of `<tabs>` elements needs to get a list of `<pane>` elements so that it could render
* In the above example the list of `<tabs>` elements needs to get a list of `<pane>` elements so
* that it could render
* tabs with the correct titles and in the correct order.
*
* A possible solution would be for a `<pane>` to inject `<tabs>` component and then register itself with `<tabs>`
* component's on `hydrate` and deregister on `dehydrate` event. While a reasonable approach, this would only work
* partialy since `*ng-for` could rearange the list of `<pane>` components which would not be reported to `<tabs>`
* component and thus the list of `<pane>` componets would be out of sync with respect to the list of `<pane>` elements.
* A possible solution would be for a `<pane>` to inject `<tabs>` component and then register itself
* with `<tabs>`
* component's on `hydrate` and deregister on `dehydrate` event. While a reasonable approach, this
* would only work
* partialy since `*ng-for` could rearange the list of `<pane>` components which would not be
* reported to `<tabs>`
* component and thus the list of `<pane>` componets would be out of sync with respect to the list
* of `<pane>` elements.
*
* A preferred solution is to inject a `QueryList` which is a live list of directives in the component`s light DOM.
* A preferred solution is to inject a `QueryList` which is a live list of directives in the
* component`s light DOM.
*
* ```javascript
* @Component({
@@ -67,17 +76,11 @@ import {BaseQueryList} from './base_query_list';
* @exportedAs angular2/view
*/
export class QueryList extends BaseQueryList {
/**
*/
onChange(callback) { return super.onChange(callback); }
/**
*/
onChange(callback) {
return super.onChange(callback);
}
/**
*/
removeCallback(callback) {
return super.removeCallback(callback);
}
removeCallback(callback) { return super.removeCallback(callback); }
}
@@ -1,4 +1,4 @@
import {Injectable} from 'angular2/src/di/annotations_impl';
import {Injectable} from 'angular2/di';
import {View} from 'angular2/src/core/annotations_impl/view';
import {Type, stringify, isBlank, BaseException} from 'angular2/src/facade/lang';
@@ -9,11 +9,9 @@ import {reflector} from 'angular2/src/reflection/reflection';
@Injectable()
export class TemplateResolver {
_cache: Map;
_cache: Map<Type, /*node*/ any>;
constructor() {
this._cache = MapWrapper.create();
}
constructor() { this._cache = MapWrapper.create(); }
resolve(component: Type): View {
var view = MapWrapper.get(this._cache, component);
@@ -1,10 +1,24 @@
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
import {AST, Locals, ChangeDispatcher, ProtoChangeDetector, ChangeDetector,
ChangeRecord, BindingRecord, DirectiveRecord, DirectiveIndex, ChangeDetectorRef} from 'angular2/change_detection';
import {
AST,
Locals,
ChangeDispatcher,
ProtoChangeDetector,
ChangeDetector,
BindingRecord,
DirectiveRecord,
DirectiveIndex,
ChangeDetectorRef
} from 'angular2/change_detection';
import {ProtoElementInjector, ElementInjector, PreBuiltObjects, DirectiveBinding} from './element_injector';
import {
ProtoElementInjector,
ElementInjector,
PreBuiltObjects,
DirectiveBinding
} from './element_injector';
import {ElementBinder} from './element_binder';
import {IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
import {int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
import * as renderApi from 'angular2/src/render/api';
import {EventDispatcher} from 'angular2/src/render/api';
@@ -21,22 +35,18 @@ export class AppViewContainer {
* Const of making objects: http://jsperf.com/instantiate-size-of-object
*
*/
@IMPLEMENTS(ChangeDispatcher)
@IMPLEMENTS(EventDispatcher)
export class AppView {
render:renderApi.RenderViewRef;
export class AppView implements ChangeDispatcher, EventDispatcher {
render: renderApi.RenderViewRef;
/// This list matches the _nodes list. It is sparse, since only Elements have ElementInjector
rootElementInjectors:List<ElementInjector>;
elementInjectors:List<ElementInjector>;
changeDetector:ChangeDetector;
rootElementInjectors: List<ElementInjector>;
elementInjectors: List<ElementInjector>;
changeDetector: ChangeDetector;
componentChildViews: List<AppView>;
/// Host views that were added by an imperative view.
/// This is a dynamically growing / shrinking array.
freeHostViews: List<AppView>;
viewContainers: List<AppViewContainer>;
preBuiltObjects: List<PreBuiltObjects>;
proto: AppProtoView;
renderer: renderApi.Renderer;
/**
* The context against which data-binding expressions in this view are evaluated against.
@@ -50,11 +60,11 @@ export class AppView {
* context). This is used for thing like `<video #player>` or
* `<li template="for #item of items">`, where "player" and "item" are locals, respectively.
*/
locals:Locals;
locals: Locals;
constructor(renderer:renderApi.Renderer, proto:AppProtoView, protoLocals:Map) {
constructor(public renderer: renderApi.Renderer, public proto: AppProtoView,
protoLocals: Map<string, any>) {
this.render = null;
this.proto = proto;
this.changeDetector = null;
this.elementInjectors = null;
this.rootElementInjectors = null;
@@ -62,13 +72,13 @@ export class AppView {
this.viewContainers = ListWrapper.createFixedSize(this.proto.elementBinders.length);
this.preBuiltObjects = null;
this.context = null;
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); //TODO optimize this
this.renderer = renderer;
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); // TODO optimize this
this.freeHostViews = [];
}
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List,
preBuiltObjects:List, componentChildViews:List) {
init(changeDetector: ChangeDetector, elementInjectors: List<ElementInjector>,
rootElementInjectors: List<ElementInjector>, preBuiltObjects: List<PreBuiltObjects>,
componentChildViews: List<AppView>) {
this.changeDetector = changeDetector;
this.elementInjectors = elementInjectors;
this.rootElementInjectors = rootElementInjectors;
@@ -76,7 +86,7 @@ export class AppView {
this.componentChildViews = componentChildViews;
}
setLocal(contextName: string, value):void {
setLocal(contextName: string, value): void {
if (!this.hydrated()) throw new BaseException('Cannot set locals on dehydrated view.');
if (!MapWrapper.contains(this.proto.variableBindings, contextName)) {
return;
@@ -85,9 +95,7 @@ export class AppView {
this.locals.set(templateName, value);
}
hydrated():boolean {
return isPresent(this.context);
}
hydrated(): boolean { return isPresent(this.context); }
/**
* Triggers the event handlers for the element and the directives.
@@ -105,34 +113,32 @@ export class AppView {
}
// dispatch to element injector or text nodes based on context
notifyOnBinding(b:BindingRecord, currentValue:any): void {
notifyOnBinding(b: BindingRecord, currentValue: any): void {
if (b.isElement()) {
this.renderer.setElementProperty(
this.render, b.elementIndex, b.propertyName, currentValue
);
this.renderer.setElementProperty(this.render, b.elementIndex, b.propertyName, currentValue);
} else {
// we know it refers to _textNodes.
this.renderer.setText(this.render, b.elementIndex, currentValue);
}
}
getDirectiveFor(directive:DirectiveIndex) {
getDirectiveFor(directive: DirectiveIndex) {
var elementInjector = this.elementInjectors[directive.elementIndex];
return elementInjector.getDirectiveAtIndex(directive.directiveIndex);
}
getDetectorFor(directive:DirectiveIndex) {
getDetectorFor(directive: DirectiveIndex) {
var childView = this.componentChildViews[directive.elementIndex];
return isPresent(childView) ? childView.changeDetector : null;
}
callAction(elementIndex:number, actionExpression:string, action:Object) {
callAction(elementIndex: number, actionExpression: string, action: Object) {
this.renderer.callAction(this.render, elementIndex, actionExpression, action);
}
// implementation of EventDispatcher#dispatchEvent
// returns false if preventDefault must be applied to the DOM event
dispatchEvent(elementIndex:number, eventName:string, locals:Map<string, any>): boolean {
dispatchEvent(elementIndex: number, eventName: string, locals: Map<string, any>): boolean {
// Most of the time the event will be fired only when the view is in the live document.
// However, in a rare circumstance the view might get dehydrated, in between the event
// queuing up and firing.
@@ -163,33 +169,26 @@ export class AppView {
*
*/
export class AppProtoView {
elementBinders:List<ElementBinder>;
protoChangeDetector:ProtoChangeDetector;
variableBindings: Map;
protoLocals:Map;
bindings:List;
render:renderApi.RenderProtoViewRef;
elementBinders: List<ElementBinder>;
protoLocals: Map<string, any>;
constructor(
render:renderApi.RenderProtoViewRef,
protoChangeDetector:ProtoChangeDetector,
variableBindings:Map) {
this.render = render;
constructor(public render: renderApi.RenderProtoViewRef,
public protoChangeDetector: ProtoChangeDetector,
public variableBindings: Map<string, string>) {
this.elementBinders = [];
this.variableBindings = variableBindings;
this.protoLocals = MapWrapper.create();
if (isPresent(variableBindings)) {
MapWrapper.forEach(variableBindings, (templateName, _) => {
MapWrapper.set(this.protoLocals, templateName, null);
});
}
this.protoChangeDetector = protoChangeDetector;
}
bindElement(parent:ElementBinder, distanceToParent:int, protoElementInjector:ProtoElementInjector,
componentDirective:DirectiveBinding = null):ElementBinder {
bindElement(parent: ElementBinder, distanceToParent: int,
protoElementInjector: ProtoElementInjector,
componentDirective: DirectiveBinding = null): ElementBinder {
var elBinder = new ElementBinder(this.elementBinders.length, parent, distanceToParent,
protoElementInjector, componentDirective);
protoElementInjector, componentDirective);
ListWrapper.push(this.elementBinders, elBinder);
return elBinder;
}
@@ -207,7 +206,8 @@ export class AppProtoView {
* @param {int} directiveIndex The directive index in the binder or -1 when the event is not bound
* to a directive
*/
bindEvent(eventBindings: List<renderApi.EventBinding>, boundElementIndex:number, directiveIndex: int = -1): void {
bindEvent(eventBindings: List<renderApi.EventBinding>, boundElementIndex: number,
directiveIndex: int = -1): void {
var elBinder = this.elementBinders[boundElementIndex];
var events = elBinder.hostListeners;
if (isBlank(events)) {
@@ -1,71 +0,0 @@
import {ListWrapper, List} from 'angular2/src/facade/collection';
import {Injector} from 'angular2/di';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import * as avmModule from './view_manager';
import {ElementRef} from './element_ref';
import {ViewRef, ProtoViewRef, internalView} from './view_ref';
/**
* @exportedAs angular2/core
*/
export class ViewContainerRef {
_viewManager: avmModule.AppViewManager;
_element: ElementRef;
constructor(viewManager: avmModule.AppViewManager,
element: ElementRef) {
this._viewManager = viewManager;
this._element = element;
}
_getViews() {
var vc = internalView(this._element.parentView).viewContainers[this._element.boundElementIndex];
return isPresent(vc) ? vc.views : [];
}
clear():void {
for (var i = this.length - 1; i >= 0; i--) {
this.remove(i);
}
}
get(index: number): ViewRef {
return new ViewRef(this._getViews()[index]);
}
get length() /* :int */ {
return this._getViews().length;
}
// TODO(rado): profile and decide whether bounds checks should be added
// to the methods below.
create(protoViewRef:ProtoViewRef = null, atIndex:number=-1, context:ElementRef, injector:Injector = null): ViewRef {
if (atIndex == -1) atIndex = this.length;
return this._viewManager.createViewInContainer(this._element, atIndex, protoViewRef, context, injector);
}
insert(viewRef:ViewRef, atIndex:number=-1): ViewRef {
if (atIndex == -1) atIndex = this.length;
return this._viewManager.attachViewInContainer(this._element, atIndex, viewRef);
}
indexOf(viewRef:ViewRef) {
return ListWrapper.indexOf(this._getViews(), internalView(viewRef));
}
remove(atIndex:number=-1):void {
if (atIndex == -1) atIndex = this.length - 1;
this._viewManager.destroyViewInContainer(this._element, atIndex);
// view is intentionally not returned to the client.
}
/**
* The method can be used together with insert to implement a view move, i.e.
* moving the dom nodes while the directives in the view stay intact.
*/
detach(atIndex:number=-1): ViewRef {
if (atIndex == -1) atIndex = this.length - 1;
return this._viewManager.detachViewInContainer(this._element, atIndex);
}
}

Some files were not shown because too many files have changed in this diff Show More