refactor(core): ts’ify core
This commit is contained in:
@ -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
modules/angular2/src/core/compiler/compiler.js
vendored
258
modules/angular2/src/core/compiler/compiler.js
vendored
@ -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.`);
|
||||
}
|
||||
}
|
||||
}
|
258
modules/angular2/src/core/compiler/compiler.ts
Normal file
258
modules/angular2/src/core/compiler/compiler.ts
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
118
modules/angular2/src/core/compiler/dynamic_component_loader.ts
Normal file
118
modules/angular2/src/core/compiler/dynamic_component_loader.ts
Normal file
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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));
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
/**
|
||||
* @exportedAs angular2/angular2
|
||||
*/
|
||||
export class OnChange {
|
||||
onChange(changes) {
|
||||
throw "OnChange.onChange is not implemented";
|
||||
}
|
||||
}
|
@ -1,54 +1,61 @@
|
||||
import {Injectable} from 'angular2/src/di/annotations_impl';
|
||||
import {Injectable} from 'angular2/di';
|
||||
|
||||
import {List, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {reflector} from 'angular2/src/reflection/reflection';
|
||||
|
||||
import {
|
||||
ChangeDetection, DirectiveIndex, BindingRecord, DirectiveRecord,
|
||||
ProtoChangeDetector, DEFAULT, ChangeDetectorDefinition
|
||||
ChangeDetection,
|
||||
DirectiveIndex,
|
||||
BindingRecord,
|
||||
DirectiveRecord,
|
||||
ProtoChangeDetector,
|
||||
DEFAULT,
|
||||
ChangeDetectorDefinition
|
||||
} from 'angular2/change_detection';
|
||||
|
||||
import * as renderApi from 'angular2/src/render/api';
|
||||
import {AppProtoView} from './view';
|
||||
import {ElementBinder} from './element_binder';
|
||||
import {ProtoElementInjector, DirectiveBinding} from './element_injector';
|
||||
|
||||
class BindingRecordsCreator {
|
||||
_directiveRecordsMap;
|
||||
_textNodeIndex:number;
|
||||
_directiveRecordsMap: Map<number, DirectiveRecord>;
|
||||
_textNodeIndex: number;
|
||||
|
||||
constructor() {
|
||||
this._directiveRecordsMap = MapWrapper.create();
|
||||
this._textNodeIndex = 0;
|
||||
}
|
||||
|
||||
getBindingRecords(elementBinders:List<renderApi.ElementBinder>,
|
||||
allDirectiveMetadatas:List<renderApi.DirectiveMetadata>
|
||||
):List<BindingRecord> {
|
||||
getBindingRecords(elementBinders: List<renderApi.ElementBinder>,
|
||||
allDirectiveMetadatas: List<renderApi.DirectiveMetadata>): List<BindingRecord> {
|
||||
var bindings = [];
|
||||
|
||||
for (var boundElementIndex = 0; boundElementIndex < elementBinders.length; boundElementIndex++) {
|
||||
for (var boundElementIndex = 0; boundElementIndex < elementBinders.length;
|
||||
boundElementIndex++) {
|
||||
var renderElementBinder = elementBinders[boundElementIndex];
|
||||
this._createTextNodeRecords(bindings, renderElementBinder);
|
||||
this._createElementPropertyRecords(bindings, boundElementIndex, renderElementBinder);
|
||||
this._createDirectiveRecords(bindings, boundElementIndex,
|
||||
renderElementBinder.directives, allDirectiveMetadatas);
|
||||
this._createDirectiveRecords(bindings, boundElementIndex, renderElementBinder.directives,
|
||||
allDirectiveMetadatas);
|
||||
}
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
getDirectiveRecords(
|
||||
elementBinders:List<renderApi.ElementBinder>,
|
||||
allDirectiveMetadatas:List<renderApi.DirectiveMetadata>): List<DirectiveRecord> {
|
||||
elementBinders: List<renderApi.ElementBinder>,
|
||||
allDirectiveMetadatas: List<renderApi.DirectiveMetadata>): List<DirectiveRecord> {
|
||||
var directiveRecords = [];
|
||||
|
||||
for (var elementIndex = 0; elementIndex < elementBinders.length; ++elementIndex) {
|
||||
var dirs = elementBinders[elementIndex].directives;
|
||||
for (var dirIndex = 0; dirIndex < dirs.length; ++dirIndex) {
|
||||
ListWrapper.push(directiveRecords,
|
||||
this._getDirectiveRecord(
|
||||
elementIndex, dirIndex, allDirectiveMetadatas[dirs[dirIndex].directiveIndex]));
|
||||
ListWrapper.push(
|
||||
directiveRecords,
|
||||
this._getDirectiveRecord(elementIndex, dirIndex,
|
||||
allDirectiveMetadatas[dirs[dirIndex].directiveIndex]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +63,7 @@ class BindingRecordsCreator {
|
||||
}
|
||||
|
||||
_createTextNodeRecords(bindings: List<BindingRecord>,
|
||||
renderElementBinder: renderApi.ElementBinder) {
|
||||
renderElementBinder: renderApi.ElementBinder) {
|
||||
if (isBlank(renderElementBinder.textBindings)) return;
|
||||
|
||||
ListWrapper.forEach(renderElementBinder.textBindings, (b) => {
|
||||
@ -64,17 +71,17 @@ class BindingRecordsCreator {
|
||||
});
|
||||
}
|
||||
|
||||
_createElementPropertyRecords(bindings: List<BindingRecord>,
|
||||
boundElementIndex:number, renderElementBinder:renderApi.ElementBinder) {
|
||||
_createElementPropertyRecords(bindings: List<BindingRecord>, boundElementIndex: number,
|
||||
renderElementBinder: renderApi.ElementBinder) {
|
||||
MapWrapper.forEach(renderElementBinder.propertyBindings, (astWithSource, propertyName) => {
|
||||
ListWrapper.push(bindings,
|
||||
BindingRecord.createForElement(astWithSource, boundElementIndex, propertyName));
|
||||
ListWrapper.push(
|
||||
bindings, BindingRecord.createForElement(astWithSource, boundElementIndex, propertyName));
|
||||
});
|
||||
}
|
||||
|
||||
_createDirectiveRecords(bindings: List<BindingRecord>,
|
||||
boundElementIndex:number, directiveBinders:List<renderApi.DirectiveBinder>,
|
||||
allDirectiveMetadatas:List<renderApi.DirectiveMetadata>) {
|
||||
_createDirectiveRecords(bindings: List<BindingRecord>, boundElementIndex: number,
|
||||
directiveBinders: List<renderApi.DirectiveBinder>,
|
||||
allDirectiveMetadatas: List<renderApi.DirectiveMetadata>) {
|
||||
for (var i = 0; i < directiveBinders.length; i++) {
|
||||
var directiveBinder = directiveBinders[i];
|
||||
var directiveMetadata = allDirectiveMetadatas[directiveBinder.directiveIndex];
|
||||
@ -85,28 +92,30 @@ class BindingRecordsCreator {
|
||||
// it monomorphic!
|
||||
var setter = reflector.setter(propertyName);
|
||||
var directiveRecord = this._getDirectiveRecord(boundElementIndex, i, directiveMetadata);
|
||||
ListWrapper.push(bindings,
|
||||
BindingRecord.createForDirective(astWithSource, propertyName, setter, directiveRecord));
|
||||
ListWrapper.push(bindings, BindingRecord.createForDirective(astWithSource, propertyName,
|
||||
setter, directiveRecord));
|
||||
});
|
||||
|
||||
// host properties
|
||||
MapWrapper.forEach(directiveBinder.hostPropertyBindings, (astWithSource, propertyName) => {
|
||||
var dirIndex = new DirectiveIndex(boundElementIndex, i);
|
||||
ListWrapper.push(bindings,
|
||||
BindingRecord.createForHostProperty(dirIndex, astWithSource, propertyName));
|
||||
ListWrapper.push(
|
||||
bindings, BindingRecord.createForHostProperty(dirIndex, astWithSource, propertyName));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_getDirectiveRecord(boundElementIndex:number, directiveIndex:number, directiveMetadata:renderApi.DirectiveMetadata): DirectiveRecord {
|
||||
_getDirectiveRecord(boundElementIndex: number, directiveIndex: number,
|
||||
directiveMetadata: renderApi.DirectiveMetadata): DirectiveRecord {
|
||||
var id = boundElementIndex * 100 + directiveIndex;
|
||||
|
||||
if (!MapWrapper.contains(this._directiveRecordsMap, id)) {
|
||||
var changeDetection = directiveMetadata.changeDetection;
|
||||
|
||||
MapWrapper.set(this._directiveRecordsMap, id,
|
||||
new DirectiveRecord(new DirectiveIndex(boundElementIndex, directiveIndex),
|
||||
directiveMetadata.callOnAllChangesDone, directiveMetadata.callOnChange, changeDetection));
|
||||
new DirectiveRecord(new DirectiveIndex(boundElementIndex, directiveIndex),
|
||||
directiveMetadata.callOnAllChangesDone,
|
||||
directiveMetadata.callOnChange, changeDetection));
|
||||
}
|
||||
|
||||
return MapWrapper.get(this._directiveRecordsMap, id);
|
||||
@ -117,30 +126,28 @@ class BindingRecordsCreator {
|
||||
export class ProtoViewFactory {
|
||||
_changeDetection: ChangeDetection;
|
||||
|
||||
constructor(changeDetection: ChangeDetection) {
|
||||
this._changeDetection = changeDetection;
|
||||
}
|
||||
constructor(changeDetection: ChangeDetection) { this._changeDetection = changeDetection; }
|
||||
|
||||
createAppProtoViews(hostComponentBinding:DirectiveBinding,
|
||||
rootRenderProtoView: renderApi.ProtoViewDto, allDirectives:List<DirectiveBinding>):List<AppProtoView> {
|
||||
var allRenderDirectiveMetadata = ListWrapper.map(allDirectives, directiveBinding => directiveBinding.metadata);
|
||||
createAppProtoViews(hostComponentBinding: DirectiveBinding,
|
||||
rootRenderProtoView: renderApi.ProtoViewDto,
|
||||
allDirectives: List<DirectiveBinding>): List<AppProtoView> {
|
||||
var allRenderDirectiveMetadata =
|
||||
ListWrapper.map(allDirectives, directiveBinding => directiveBinding.metadata);
|
||||
var nestedPvsWithIndex = _collectNestedProtoViews(rootRenderProtoView);
|
||||
var nestedPvVariableBindings = _collectNestedProtoViewsVariableBindings(nestedPvsWithIndex);
|
||||
var nestedPvVariableNames = _collectNestedProtoViewsVariableNames(nestedPvsWithIndex, nestedPvVariableBindings);
|
||||
var changeDetectorDefs = _getChangeDetectorDefinitions(
|
||||
hostComponentBinding.metadata, nestedPvsWithIndex, nestedPvVariableNames, allRenderDirectiveMetadata
|
||||
);
|
||||
var nestedPvVariableNames =
|
||||
_collectNestedProtoViewsVariableNames(nestedPvsWithIndex, nestedPvVariableBindings);
|
||||
var changeDetectorDefs =
|
||||
_getChangeDetectorDefinitions(hostComponentBinding.metadata, nestedPvsWithIndex,
|
||||
nestedPvVariableNames, allRenderDirectiveMetadata);
|
||||
var protoChangeDetectors = ListWrapper.map(
|
||||
changeDetectorDefs, changeDetectorDef => this._changeDetection.createProtoChangeDetector(changeDetectorDef)
|
||||
);
|
||||
changeDetectorDefs,
|
||||
changeDetectorDef => this._changeDetection.createProtoChangeDetector(changeDetectorDef));
|
||||
var appProtoViews = ListWrapper.createFixedSize(nestedPvsWithIndex.length);
|
||||
ListWrapper.forEach(nestedPvsWithIndex, (pvWithIndex) => {
|
||||
var appProtoView = _createAppProtoView(
|
||||
pvWithIndex.renderProtoView,
|
||||
protoChangeDetectors[pvWithIndex.index],
|
||||
nestedPvVariableBindings[pvWithIndex.index],
|
||||
allDirectives
|
||||
);
|
||||
var appProtoView =
|
||||
_createAppProtoView(pvWithIndex.renderProtoView, protoChangeDetectors[pvWithIndex.index],
|
||||
nestedPvVariableBindings[pvWithIndex.index], allDirectives);
|
||||
if (isPresent(pvWithIndex.parentIndex)) {
|
||||
var parentView = appProtoViews[pvWithIndex.parentIndex];
|
||||
parentView.elementBinders[pvWithIndex.boundElementIndex].nestedProtoView = appProtoView;
|
||||
@ -156,34 +163,31 @@ export class ProtoViewFactory {
|
||||
* for the given ProtoView and all nested ProtoViews.
|
||||
*/
|
||||
export function getChangeDetectorDefinitions(
|
||||
hostComponentMetadata:renderApi.DirectiveMetadata,
|
||||
rootRenderProtoView: renderApi.ProtoViewDto,
|
||||
allRenderDirectiveMetadata:List<renderApi.DirectiveMetadata>): List<ChangeDetectorDefinition> {
|
||||
hostComponentMetadata: renderApi.DirectiveMetadata, rootRenderProtoView: renderApi.ProtoViewDto,
|
||||
allRenderDirectiveMetadata: List<renderApi.DirectiveMetadata>): List<ChangeDetectorDefinition> {
|
||||
var nestedPvsWithIndex = _collectNestedProtoViews(rootRenderProtoView);
|
||||
var nestedPvVariableBindings = _collectNestedProtoViewsVariableBindings(nestedPvsWithIndex);
|
||||
var nestedPvVariableNames = _collectNestedProtoViewsVariableNames(nestedPvsWithIndex, nestedPvVariableBindings);
|
||||
var nestedPvVariableNames =
|
||||
_collectNestedProtoViewsVariableNames(nestedPvsWithIndex, nestedPvVariableBindings);
|
||||
|
||||
return _getChangeDetectorDefinitions(
|
||||
hostComponentMetadata,
|
||||
nestedPvsWithIndex,
|
||||
nestedPvVariableNames,
|
||||
allRenderDirectiveMetadata
|
||||
);
|
||||
return _getChangeDetectorDefinitions(hostComponentMetadata, nestedPvsWithIndex,
|
||||
nestedPvVariableNames, allRenderDirectiveMetadata);
|
||||
}
|
||||
|
||||
function _collectNestedProtoViews(renderProtoView:renderApi.ProtoViewDto,
|
||||
parentIndex:number = null,
|
||||
boundElementIndex = null,
|
||||
result:List<RenderProtoViewWithIndex> = null): List<RenderProtoViewWithIndex> {
|
||||
function _collectNestedProtoViews(
|
||||
renderProtoView: renderApi.ProtoViewDto, parentIndex: number = null, boundElementIndex = null,
|
||||
result: List<RenderProtoViewWithIndex> = null): List<RenderProtoViewWithIndex> {
|
||||
if (isBlank(result)) {
|
||||
result = [];
|
||||
}
|
||||
ListWrapper.push(result, new RenderProtoViewWithIndex(renderProtoView, result.length, parentIndex, boundElementIndex));
|
||||
ListWrapper.push(result, new RenderProtoViewWithIndex(renderProtoView, result.length, parentIndex,
|
||||
boundElementIndex));
|
||||
var currentIndex = result.length - 1;
|
||||
var childBoundElementIndex = 0;
|
||||
ListWrapper.forEach(renderProtoView.elementBinders, (elementBinder) => {
|
||||
if (isPresent(elementBinder.nestedProtoView)) {
|
||||
_collectNestedProtoViews(elementBinder.nestedProtoView, currentIndex, childBoundElementIndex, result);
|
||||
_collectNestedProtoViews(elementBinder.nestedProtoView, currentIndex, childBoundElementIndex,
|
||||
result);
|
||||
}
|
||||
childBoundElementIndex++;
|
||||
});
|
||||
@ -191,15 +195,16 @@ function _collectNestedProtoViews(renderProtoView:renderApi.ProtoViewDto,
|
||||
}
|
||||
|
||||
function _getChangeDetectorDefinitions(
|
||||
hostComponentMetadata:renderApi.DirectiveMetadata,
|
||||
nestedPvsWithIndex: List<RenderProtoViewWithIndex>,
|
||||
nestedPvVariableNames: List<List<string>>,
|
||||
allRenderDirectiveMetadata:List<renderApi.DirectiveMetadata>):List<ChangeDetectorDefinition> {
|
||||
hostComponentMetadata: renderApi.DirectiveMetadata,
|
||||
nestedPvsWithIndex: List<RenderProtoViewWithIndex>, nestedPvVariableNames: List<List<string>>,
|
||||
allRenderDirectiveMetadata: List<renderApi.DirectiveMetadata>): List<ChangeDetectorDefinition> {
|
||||
return ListWrapper.map(nestedPvsWithIndex, (pvWithIndex) => {
|
||||
var elementBinders = pvWithIndex.renderProtoView.elementBinders;
|
||||
var bindingRecordsCreator = new BindingRecordsCreator();
|
||||
var bindingRecords = bindingRecordsCreator.getBindingRecords(elementBinders, allRenderDirectiveMetadata);
|
||||
var directiveRecords = bindingRecordsCreator.getDirectiveRecords(elementBinders, allRenderDirectiveMetadata);
|
||||
var bindingRecords =
|
||||
bindingRecordsCreator.getBindingRecords(elementBinders, allRenderDirectiveMetadata);
|
||||
var directiveRecords =
|
||||
bindingRecordsCreator.getDirectiveRecords(elementBinders, allRenderDirectiveMetadata);
|
||||
var strategyName = DEFAULT;
|
||||
var typeString;
|
||||
if (pvWithIndex.renderProtoView.type === renderApi.ProtoViewDto.COMPONENT_VIEW_TYPE) {
|
||||
@ -212,16 +217,14 @@ function _getChangeDetectorDefinitions(
|
||||
}
|
||||
var id = `${hostComponentMetadata.id}_${typeString}_${pvWithIndex.index}`;
|
||||
var variableNames = nestedPvVariableNames[pvWithIndex.index];
|
||||
return new ChangeDetectorDefinition(id, strategyName, variableNames, bindingRecords, directiveRecords);
|
||||
return new ChangeDetectorDefinition(id, strategyName, variableNames, bindingRecords,
|
||||
directiveRecords);
|
||||
});
|
||||
}
|
||||
|
||||
function _createAppProtoView(
|
||||
renderProtoView: renderApi.ProtoViewDto,
|
||||
protoChangeDetector: ProtoChangeDetector,
|
||||
variableBindings: Map<string, string>,
|
||||
allDirectives:List<DirectiveBinding>
|
||||
):AppProtoView {
|
||||
renderProtoView: renderApi.ProtoViewDto, protoChangeDetector: ProtoChangeDetector,
|
||||
variableBindings: Map<string, string>, allDirectives: List<DirectiveBinding>): AppProtoView {
|
||||
var elementBinders = renderProtoView.elementBinders;
|
||||
var protoView = new AppProtoView(renderProtoView.render, protoChangeDetector, variableBindings);
|
||||
|
||||
@ -233,14 +236,13 @@ function _createAppProtoView(
|
||||
}
|
||||
|
||||
function _collectNestedProtoViewsVariableBindings(
|
||||
nestedPvsWithIndex: List<RenderProtoViewWithIndex>
|
||||
):List<Map<string, string>> {
|
||||
nestedPvsWithIndex: List<RenderProtoViewWithIndex>): List<Map<string, string>> {
|
||||
return ListWrapper.map(nestedPvsWithIndex, (pvWithIndex) => {
|
||||
return _createVariableBindings(pvWithIndex.renderProtoView);
|
||||
});
|
||||
}
|
||||
|
||||
function _createVariableBindings(renderProtoView):Map {
|
||||
function _createVariableBindings(renderProtoView): Map<string, string> {
|
||||
var variableBindings = MapWrapper.create();
|
||||
MapWrapper.forEach(renderProtoView.variableBindings, (mappedName, varName) => {
|
||||
MapWrapper.set(variableBindings, varName, mappedName);
|
||||
@ -255,48 +257,49 @@ function _createVariableBindings(renderProtoView):Map {
|
||||
|
||||
function _collectNestedProtoViewsVariableNames(
|
||||
nestedPvsWithIndex: List<RenderProtoViewWithIndex>,
|
||||
nestedPvVariableBindings:List<Map<string, string>>
|
||||
):List<List<string>> {
|
||||
nestedPvVariableBindings: List<Map<string, string>>): List<List<string>> {
|
||||
var nestedPvVariableNames = ListWrapper.createFixedSize(nestedPvsWithIndex.length);
|
||||
ListWrapper.forEach(nestedPvsWithIndex, (pvWithIndex) => {
|
||||
var parentVariableNames = isPresent(pvWithIndex.parentIndex) ? nestedPvVariableNames[pvWithIndex.parentIndex] : null;
|
||||
nestedPvVariableNames[pvWithIndex.index] = _createVariableNames(
|
||||
parentVariableNames, nestedPvVariableBindings[pvWithIndex.index]
|
||||
);
|
||||
var parentVariableNames =
|
||||
isPresent(pvWithIndex.parentIndex) ? nestedPvVariableNames[pvWithIndex.parentIndex] : null;
|
||||
nestedPvVariableNames[pvWithIndex.index] =
|
||||
_createVariableNames(parentVariableNames, nestedPvVariableBindings[pvWithIndex.index]);
|
||||
});
|
||||
return nestedPvVariableNames;
|
||||
}
|
||||
|
||||
function _createVariableNames(parentVariableNames, variableBindings):List {
|
||||
function _createVariableNames(parentVariableNames, variableBindings): List<string> {
|
||||
var variableNames = isPresent(parentVariableNames) ? ListWrapper.clone(parentVariableNames) : [];
|
||||
MapWrapper.forEach(variableBindings, (local, v) => {
|
||||
ListWrapper.push(variableNames, local);
|
||||
});
|
||||
MapWrapper.forEach(variableBindings, (local, v) => { ListWrapper.push(variableNames, local); });
|
||||
return variableNames;
|
||||
}
|
||||
|
||||
function _createElementBinders(protoView, elementBinders, allDirectiveBindings) {
|
||||
for (var i=0; i<elementBinders.length; i++) {
|
||||
for (var i = 0; i < elementBinders.length; i++) {
|
||||
var renderElementBinder = elementBinders[i];
|
||||
var dirs = elementBinders[i].directives;
|
||||
|
||||
var parentPeiWithDistance = _findParentProtoElementInjectorWithDistance(
|
||||
i, protoView.elementBinders, elementBinders);
|
||||
var directiveBindings = ListWrapper.map(dirs, (dir) => allDirectiveBindings[dir.directiveIndex] );
|
||||
var parentPeiWithDistance =
|
||||
_findParentProtoElementInjectorWithDistance(i, protoView.elementBinders, elementBinders);
|
||||
var directiveBindings =
|
||||
ListWrapper.map(dirs, (dir) => allDirectiveBindings[dir.directiveIndex]);
|
||||
var componentDirectiveBinding = null;
|
||||
if (directiveBindings.length > 0) {
|
||||
if (directiveBindings[0].metadata.type === renderApi.DirectiveMetadata.COMPONENT_TYPE) {
|
||||
componentDirectiveBinding = directiveBindings[0];
|
||||
}
|
||||
}
|
||||
var protoElementInjector = _createProtoElementInjector(
|
||||
i, parentPeiWithDistance, renderElementBinder, componentDirectiveBinding, directiveBindings);
|
||||
var protoElementInjector =
|
||||
_createProtoElementInjector(i, parentPeiWithDistance, renderElementBinder,
|
||||
componentDirectiveBinding, directiveBindings);
|
||||
|
||||
_createElementBinder(protoView, i, renderElementBinder, protoElementInjector, componentDirectiveBinding);
|
||||
_createElementBinder(protoView, i, renderElementBinder, protoElementInjector,
|
||||
componentDirectiveBinding);
|
||||
}
|
||||
}
|
||||
|
||||
function _findParentProtoElementInjectorWithDistance(binderIndex, elementBinders, renderElementBinders) {
|
||||
function _findParentProtoElementInjectorWithDistance(
|
||||
binderIndex, elementBinders, renderElementBinders): ParentProtoElementInjectorWithDistance {
|
||||
var distance = 0;
|
||||
do {
|
||||
var renderElementBinder = renderElementBinders[binderIndex];
|
||||
@ -305,14 +308,16 @@ function _findParentProtoElementInjectorWithDistance(binderIndex, elementBinders
|
||||
distance += renderElementBinder.distanceToParent;
|
||||
var elementBinder = elementBinders[binderIndex];
|
||||
if (isPresent(elementBinder.protoElementInjector)) {
|
||||
return new ParentProtoElementInjectorWithDistance(elementBinder.protoElementInjector, distance);
|
||||
return new ParentProtoElementInjectorWithDistance(elementBinder.protoElementInjector,
|
||||
distance);
|
||||
}
|
||||
}
|
||||
} while (binderIndex !== -1);
|
||||
return new ParentProtoElementInjectorWithDistance(null, -1);
|
||||
}
|
||||
|
||||
function _createProtoElementInjector(binderIndex, parentPeiWithDistance, renderElementBinder, componentDirectiveBinding, directiveBindings) {
|
||||
function _createProtoElementInjector(binderIndex, parentPeiWithDistance, renderElementBinder,
|
||||
componentDirectiveBinding, directiveBindings) {
|
||||
var protoElementInjector = null;
|
||||
// Create a protoElementInjector for any element that either has bindings *or* has one
|
||||
// or more var- defined. Elements with a var- defined need a their own element injector
|
||||
@ -320,10 +325,8 @@ function _createProtoElementInjector(binderIndex, parentPeiWithDistance, renderE
|
||||
var hasVariables = MapWrapper.size(renderElementBinder.variableBindings) > 0;
|
||||
if (directiveBindings.length > 0 || hasVariables) {
|
||||
protoElementInjector = ProtoElementInjector.create(
|
||||
parentPeiWithDistance.protoElementInjector, binderIndex,
|
||||
directiveBindings,
|
||||
isPresent(componentDirectiveBinding), parentPeiWithDistance.distance
|
||||
);
|
||||
parentPeiWithDistance.protoElementInjector, binderIndex, directiveBindings,
|
||||
isPresent(componentDirectiveBinding), parentPeiWithDistance.distance);
|
||||
protoElementInjector.attributes = renderElementBinder.readAttributes;
|
||||
if (hasVariables) {
|
||||
protoElementInjector.exportComponent = isPresent(componentDirectiveBinding);
|
||||
@ -339,17 +342,14 @@ function _createProtoElementInjector(binderIndex, parentPeiWithDistance, renderE
|
||||
return protoElementInjector;
|
||||
}
|
||||
|
||||
function _createElementBinder(protoView, boundElementIndex, renderElementBinder, protoElementInjector, componentDirectiveBinding) {
|
||||
function _createElementBinder(protoView, boundElementIndex, renderElementBinder,
|
||||
protoElementInjector, componentDirectiveBinding): ElementBinder {
|
||||
var parent = null;
|
||||
if (renderElementBinder.parentIndex !== -1) {
|
||||
parent = protoView.elementBinders[renderElementBinder.parentIndex];
|
||||
}
|
||||
var elBinder = protoView.bindElement(
|
||||
parent,
|
||||
renderElementBinder.distanceToParent,
|
||||
protoElementInjector,
|
||||
componentDirectiveBinding
|
||||
);
|
||||
var elBinder = protoView.bindElement(parent, renderElementBinder.distanceToParent,
|
||||
protoElementInjector, componentDirectiveBinding);
|
||||
protoView.bindEvent(renderElementBinder.eventBindings, boundElementIndex, -1);
|
||||
// variables
|
||||
// The view's locals needs to have a full set of variable names at construction time
|
||||
@ -362,7 +362,7 @@ function _createElementBinder(protoView, boundElementIndex, renderElementBinder,
|
||||
return elBinder;
|
||||
}
|
||||
|
||||
function _bindDirectiveEvents(protoView, elementBinders:List<renderApi.ElementBinder>) {
|
||||
function _bindDirectiveEvents(protoView, elementBinders: List<renderApi.ElementBinder>) {
|
||||
for (var boundElementIndex = 0; boundElementIndex < elementBinders.length; ++boundElementIndex) {
|
||||
var dirs = elementBinders[boundElementIndex].directives;
|
||||
for (var i = 0; i < dirs.length; i++) {
|
||||
@ -376,11 +376,12 @@ function _bindDirectiveEvents(protoView, elementBinders:List<renderApi.ElementBi
|
||||
|
||||
|
||||
class RenderProtoViewWithIndex {
|
||||
renderProtoView:renderApi.ProtoViewDto;
|
||||
index:number;
|
||||
parentIndex:number;
|
||||
boundElementIndex:number;
|
||||
constructor(renderProtoView:renderApi.ProtoViewDto, index:number, parentIndex:number, boundElementIndex:number) {
|
||||
renderProtoView: renderApi.ProtoViewDto;
|
||||
index: number;
|
||||
parentIndex: number;
|
||||
boundElementIndex: number;
|
||||
constructor(renderProtoView: renderApi.ProtoViewDto, index: number, parentIndex: number,
|
||||
boundElementIndex: number) {
|
||||
this.renderProtoView = renderProtoView;
|
||||
this.index = index;
|
||||
this.parentIndex = parentIndex;
|
||||
@ -389,9 +390,9 @@ class RenderProtoViewWithIndex {
|
||||
}
|
||||
|
||||
class ParentProtoElementInjectorWithDistance {
|
||||
protoElementInjector:ProtoElementInjector;
|
||||
distance:number;
|
||||
constructor(protoElementInjector:ProtoElementInjector, distance:number) {
|
||||
protoElementInjector: ProtoElementInjector;
|
||||
distance: number;
|
||||
constructor(protoElementInjector: ProtoElementInjector, distance: number) {
|
||||
this.protoElementInjector = protoElementInjector;
|
||||
this.distance = distance;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
61
modules/angular2/src/core/compiler/view_container_ref.ts
Normal file
61
modules/angular2/src/core/compiler/view_container_ref.ts
Normal file
@ -0,0 +1,61 @@
|
||||
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 * as viewModule from './view';
|
||||
|
||||
import {ElementRef} from './element_ref';
|
||||
import {ViewRef, ProtoViewRef, internalView} from './view_ref';
|
||||
/**
|
||||
* @exportedAs angular2/core
|
||||
*/
|
||||
export class ViewContainerRef {
|
||||
constructor(public viewManager: avmModule.AppViewManager, public element: ElementRef) {}
|
||||
|
||||
private _getViews(): List<viewModule.AppView> {
|
||||
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 = null,
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import {Injector, Binding} from 'angular2/di';
|
||||
import {Injectable} from 'angular2/src/di/annotations_impl';
|
||||
import {Injector, Binding, Injectable} from 'angular2/di';
|
||||
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import * as viewModule from './view';
|
||||
import {ElementRef} from './element_ref';
|
||||
@ -16,53 +15,56 @@ import {AppViewPool} from './view_pool';
|
||||
*/
|
||||
@Injectable()
|
||||
export class AppViewManager {
|
||||
_viewPool:AppViewPool;
|
||||
_utils:AppViewManagerUtils;
|
||||
_renderer:Renderer;
|
||||
_viewPool: AppViewPool;
|
||||
_utils: AppViewManagerUtils;
|
||||
_renderer: Renderer;
|
||||
|
||||
constructor(viewPool:AppViewPool, utils:AppViewManagerUtils, renderer:Renderer) {
|
||||
constructor(viewPool: AppViewPool, utils: AppViewManagerUtils, renderer: Renderer) {
|
||||
this._renderer = renderer;
|
||||
this._viewPool = viewPool;
|
||||
this._utils = utils;
|
||||
}
|
||||
|
||||
getComponentView(hostLocation:ElementRef):ViewRef {
|
||||
getComponentView(hostLocation: ElementRef): ViewRef {
|
||||
var hostView = internalView(hostLocation.parentView);
|
||||
var boundElementIndex = hostLocation.boundElementIndex;
|
||||
return new ViewRef(hostView.componentChildViews[boundElementIndex]);
|
||||
}
|
||||
|
||||
getViewContainer(location:ElementRef):ViewContainerRef {
|
||||
getViewContainer(location: ElementRef): ViewContainerRef {
|
||||
var hostView = internalView(location.parentView);
|
||||
return hostView.elementInjectors[location.boundElementIndex].getViewContainerRef();
|
||||
}
|
||||
|
||||
getComponent(hostLocation:ElementRef):any {
|
||||
getComponent(hostLocation: ElementRef): any {
|
||||
var hostView = internalView(hostLocation.parentView);
|
||||
var boundElementIndex = hostLocation.boundElementIndex;
|
||||
return this._utils.getComponentInstance(hostView, boundElementIndex);
|
||||
}
|
||||
|
||||
createDynamicComponentView(hostLocation:ElementRef,
|
||||
componentProtoViewRef:ProtoViewRef, componentBinding:Binding, injector:Injector):ViewRef {
|
||||
createDynamicComponentView(hostLocation: ElementRef, componentProtoViewRef: ProtoViewRef,
|
||||
componentBinding: Binding, injector: Injector): ViewRef {
|
||||
var componentProtoView = internalProtoView(componentProtoViewRef);
|
||||
var hostView = internalView(hostLocation.parentView);
|
||||
var boundElementIndex = hostLocation.boundElementIndex;
|
||||
var binder = hostView.proto.elementBinders[boundElementIndex];
|
||||
if (!binder.hasDynamicComponent()) {
|
||||
throw new BaseException(`There is no dynamic component directive at element ${boundElementIndex}`)
|
||||
throw new BaseException(
|
||||
`There is no dynamic component directive at element ${boundElementIndex}`)
|
||||
}
|
||||
var componentView = this._createPooledView(componentProtoView);
|
||||
this._renderer.attachComponentView(hostView.render, boundElementIndex, componentView.render);
|
||||
this._utils.attachComponentView(hostView, boundElementIndex, componentView);
|
||||
this._utils.hydrateDynamicComponentInElementInjector(hostView, boundElementIndex, componentBinding, injector);
|
||||
this._utils.hydrateDynamicComponentInElementInjector(hostView, boundElementIndex,
|
||||
componentBinding, injector);
|
||||
this._utils.hydrateComponentView(hostView, boundElementIndex);
|
||||
this._viewHydrateRecurse(componentView);
|
||||
|
||||
return new ViewRef(componentView);
|
||||
}
|
||||
|
||||
createRootHostView(hostProtoViewRef:ProtoViewRef, overrideSelector:string, injector:Injector):ViewRef {
|
||||
createRootHostView(hostProtoViewRef: ProtoViewRef, overrideSelector: string,
|
||||
injector: Injector): ViewRef {
|
||||
var hostProtoView = internalProtoView(hostProtoViewRef);
|
||||
var hostElementSelector = overrideSelector;
|
||||
if (isBlank(hostElementSelector)) {
|
||||
@ -78,7 +80,7 @@ export class AppViewManager {
|
||||
return new ViewRef(hostView);
|
||||
}
|
||||
|
||||
destroyRootHostView(hostViewRef:ViewRef) {
|
||||
destroyRootHostView(hostViewRef: ViewRef) {
|
||||
// Note: Don't detach the hostView as we want to leave the
|
||||
// root element in place. Also don't put the hostView into the view pool
|
||||
// as it is depending on the element for which it was created.
|
||||
@ -88,24 +90,28 @@ export class AppViewManager {
|
||||
this._renderer.destroyView(hostView.render);
|
||||
}
|
||||
|
||||
createFreeHostView(parentComponentLocation:ElementRef, hostProtoViewRef:ProtoViewRef, injector:Injector):ViewRef {
|
||||
createFreeHostView(parentComponentLocation: ElementRef, hostProtoViewRef: ProtoViewRef,
|
||||
injector: Injector): ViewRef {
|
||||
var hostProtoView = internalProtoView(hostProtoViewRef);
|
||||
var hostView = this._createPooledView(hostProtoView);
|
||||
var parentComponentHostView = internalView(parentComponentLocation.parentView);
|
||||
var parentComponentBoundElementIndex = parentComponentLocation.boundElementIndex;
|
||||
this._utils.attachAndHydrateFreeHostView(parentComponentHostView, parentComponentBoundElementIndex, hostView, injector);
|
||||
this._utils.attachAndHydrateFreeHostView(parentComponentHostView,
|
||||
parentComponentBoundElementIndex, hostView, injector);
|
||||
this._viewHydrateRecurse(hostView);
|
||||
return new ViewRef(hostView);
|
||||
}
|
||||
|
||||
destroyFreeHostView(parentComponentLocation:ElementRef, hostViewRef:ViewRef) {
|
||||
destroyFreeHostView(parentComponentLocation: ElementRef, hostViewRef: ViewRef) {
|
||||
var hostView = internalView(hostViewRef);
|
||||
var parentView = internalView(parentComponentLocation.parentView).componentChildViews[parentComponentLocation.boundElementIndex];
|
||||
var parentView = internalView(parentComponentLocation.parentView)
|
||||
.componentChildViews[parentComponentLocation.boundElementIndex];
|
||||
this._destroyFreeHostView(parentView, hostView);
|
||||
}
|
||||
|
||||
createViewInContainer(viewContainerLocation:ElementRef,
|
||||
atIndex:number, protoViewRef:ProtoViewRef, context:ElementRef = null, injector:Injector = null):ViewRef {
|
||||
createViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
|
||||
protoViewRef: ProtoViewRef, context: ElementRef = null,
|
||||
injector: Injector = null): ViewRef {
|
||||
var protoView = internalProtoView(protoViewRef);
|
||||
var parentView = internalView(viewContainerLocation.parentView);
|
||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||
@ -118,20 +124,24 @@ export class AppViewManager {
|
||||
|
||||
var view = this._createPooledView(protoView);
|
||||
|
||||
this._renderer.attachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||
this._utils.attachViewInContainer(parentView, boundElementIndex, contextView, contextBoundElementIndex, atIndex, view);
|
||||
this._utils.hydrateViewInContainer(parentView, boundElementIndex, contextView, contextBoundElementIndex, atIndex, injector);
|
||||
this._renderer.attachViewInContainer(parentView.render, boundElementIndex, atIndex,
|
||||
view.render);
|
||||
this._utils.attachViewInContainer(parentView, boundElementIndex, contextView,
|
||||
contextBoundElementIndex, atIndex, view);
|
||||
this._utils.hydrateViewInContainer(parentView, boundElementIndex, contextView,
|
||||
contextBoundElementIndex, atIndex, injector);
|
||||
this._viewHydrateRecurse(view);
|
||||
return new ViewRef(view);
|
||||
}
|
||||
|
||||
destroyViewInContainer(viewContainerLocation:ElementRef, atIndex:number) {
|
||||
destroyViewInContainer(viewContainerLocation: ElementRef, atIndex: number) {
|
||||
var parentView = internalView(viewContainerLocation.parentView);
|
||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||
this._destroyViewInContainer(parentView, boundElementIndex, atIndex);
|
||||
}
|
||||
|
||||
attachViewInContainer(viewContainerLocation:ElementRef, atIndex:number, viewRef:ViewRef):ViewRef {
|
||||
attachViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
|
||||
viewRef: ViewRef): ViewRef {
|
||||
var view = internalView(viewRef);
|
||||
var parentView = internalView(viewContainerLocation.parentView);
|
||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||
@ -142,31 +152,34 @@ export class AppViewManager {
|
||||
// Right now we are destroying any special
|
||||
// context view that might have been used.
|
||||
this._utils.attachViewInContainer(parentView, boundElementIndex, null, null, atIndex, view);
|
||||
this._renderer.attachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||
this._renderer.attachViewInContainer(parentView.render, boundElementIndex, atIndex,
|
||||
view.render);
|
||||
return viewRef;
|
||||
}
|
||||
|
||||
detachViewInContainer(viewContainerLocation:ElementRef, atIndex:number):ViewRef {
|
||||
detachViewInContainer(viewContainerLocation: ElementRef, atIndex: number): ViewRef {
|
||||
var parentView = internalView(viewContainerLocation.parentView);
|
||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||
var view = viewContainer.views[atIndex];
|
||||
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
|
||||
this._renderer.detachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||
this._renderer.detachViewInContainer(parentView.render, boundElementIndex, atIndex,
|
||||
view.render);
|
||||
return new ViewRef(view);
|
||||
}
|
||||
|
||||
_createPooledView(protoView:viewModule.AppProtoView):viewModule.AppView {
|
||||
_createPooledView(protoView: viewModule.AppProtoView): viewModule.AppView {
|
||||
var view = this._viewPool.getView(protoView);
|
||||
if (isBlank(view)) {
|
||||
view = this._utils.createView(protoView, this._renderer.createView(protoView.render), this, this._renderer);
|
||||
view = this._utils.createView(protoView, this._renderer.createView(protoView.render), this,
|
||||
this._renderer);
|
||||
this._renderer.setEventDispatcher(view.render, view);
|
||||
this._createViewRecurse(view);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
_createViewRecurse(view:viewModule.AppView) {
|
||||
_createViewRecurse(view: viewModule.AppView) {
|
||||
var binders = view.proto.elementBinders;
|
||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||
var binder = binders[binderIdx];
|
||||
@ -178,17 +191,18 @@ export class AppViewManager {
|
||||
}
|
||||
}
|
||||
|
||||
_destroyPooledView(view:viewModule.AppView) {
|
||||
_destroyPooledView(view: viewModule.AppView) {
|
||||
// TODO: if the pool is full, call renderer.destroyView as well!
|
||||
this._viewPool.returnView(view);
|
||||
}
|
||||
|
||||
_destroyViewInContainer(parentView, boundElementIndex, atIndex:number) {
|
||||
_destroyViewInContainer(parentView, boundElementIndex, atIndex: number) {
|
||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||
var view = viewContainer.views[atIndex];
|
||||
this._viewDehydrateRecurse(view, false);
|
||||
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
|
||||
this._renderer.detachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||
this._renderer.detachViewInContainer(parentView.render, boundElementIndex, atIndex,
|
||||
view.render);
|
||||
this._destroyPooledView(view);
|
||||
}
|
||||
|
||||
@ -206,22 +220,19 @@ export class AppViewManager {
|
||||
this._destroyPooledView(hostView);
|
||||
}
|
||||
|
||||
_viewHydrateRecurse(
|
||||
view:viewModule.AppView) {
|
||||
_viewHydrateRecurse(view: viewModule.AppView) {
|
||||
this._renderer.hydrateView(view.render);
|
||||
|
||||
var binders = view.proto.elementBinders;
|
||||
for (var i = 0; i < binders.length; ++i) {
|
||||
if (binders[i].hasStaticComponent()) {
|
||||
this._utils.hydrateComponentView(view, i);
|
||||
this._viewHydrateRecurse(
|
||||
view.componentChildViews[i]
|
||||
);
|
||||
this._viewHydrateRecurse(view.componentChildViews[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_viewDehydrateRecurse(view:viewModule.AppView, forceDestroyComponents) {
|
||||
_viewDehydrateRecurse(view: viewModule.AppView, forceDestroyComponents) {
|
||||
this._utils.dehydrateView(view);
|
||||
this._renderer.dehydrateView(view.render);
|
||||
var binders = view.proto.elementBinders;
|
||||
@ -243,7 +254,7 @@ export class AppViewManager {
|
||||
}
|
||||
|
||||
// freeHostViews
|
||||
for (var i = view.freeHostViews.length-1; i>=0; i--) {
|
||||
for (var i = view.freeHostViews.length - 1; i >= 0; i--) {
|
||||
var hostView = view.freeHostViews[i];
|
||||
this._destroyFreeHostView(view, hostView);
|
||||
}
|
@ -1,24 +1,21 @@
|
||||
import {Injector, Binding} from 'angular2/di';
|
||||
import {Injectable} from 'angular2/src/di/annotations_impl';
|
||||
import {Injector, Binding, Injectable} from 'angular2/di';
|
||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||
import * as eli from './element_injector';
|
||||
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import * as viewModule from './view';
|
||||
import * as avmModule from './view_manager';
|
||||
import {Renderer} from 'angular2/src/render/api';
|
||||
import {BindingPropagationConfig, Locals} from 'angular2/change_detection';
|
||||
import {Locals} from 'angular2/change_detection';
|
||||
import {DirectiveResolver} from './directive_resolver';
|
||||
import {RenderViewRef} from 'angular2/src/render/api';
|
||||
|
||||
@Injectable()
|
||||
export class AppViewManagerUtils {
|
||||
_directiveResolver:DirectiveResolver;
|
||||
_directiveResolver: DirectiveResolver;
|
||||
|
||||
constructor(metadataReader:DirectiveResolver) {
|
||||
this._directiveResolver = metadataReader;
|
||||
}
|
||||
constructor(metadataReader: DirectiveResolver) { this._directiveResolver = metadataReader; }
|
||||
|
||||
getComponentInstance(parentView:viewModule.AppView, boundElementIndex:number):any {
|
||||
getComponentInstance(parentView: viewModule.AppView, boundElementIndex: number): any {
|
||||
var binder = parentView.proto.elementBinders[boundElementIndex];
|
||||
var eli = parentView.elementInjectors[boundElementIndex];
|
||||
if (binder.hasDynamicComponent()) {
|
||||
@ -28,7 +25,8 @@ export class AppViewManagerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
createView(protoView:viewModule.AppProtoView, renderView:RenderViewRef, viewManager:avmModule.AppViewManager, renderer:Renderer): viewModule.AppView {
|
||||
createView(protoView: viewModule.AppProtoView, renderView: RenderViewRef,
|
||||
viewManager: avmModule.AppViewManager, renderer: Renderer): viewModule.AppView {
|
||||
var view = new viewModule.AppView(renderer, protoView, protoView.protoLocals);
|
||||
// TODO(tbosch): pass RenderViewRef as argument to AppView!
|
||||
view.render = renderView;
|
||||
@ -65,56 +63,56 @@ export class AppViewManagerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
view.init(changeDetector, elementInjectors, rootElementInjectors,
|
||||
preBuiltObjects, componentChildViews);
|
||||
view.init(changeDetector, elementInjectors, rootElementInjectors, preBuiltObjects,
|
||||
componentChildViews);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
attachComponentView(hostView:viewModule.AppView, boundElementIndex:number,
|
||||
componentView:viewModule.AppView) {
|
||||
attachComponentView(hostView: viewModule.AppView, boundElementIndex: number,
|
||||
componentView: viewModule.AppView) {
|
||||
var childChangeDetector = componentView.changeDetector;
|
||||
hostView.changeDetector.addShadowDomChild(childChangeDetector);
|
||||
hostView.componentChildViews[boundElementIndex] = componentView;
|
||||
}
|
||||
|
||||
detachComponentView(hostView:viewModule.AppView, boundElementIndex:number) {
|
||||
detachComponentView(hostView: viewModule.AppView, boundElementIndex: number) {
|
||||
var componentView = hostView.componentChildViews[boundElementIndex];
|
||||
hostView.changeDetector.removeShadowDomChild(componentView.changeDetector);
|
||||
hostView.componentChildViews[boundElementIndex] = null;
|
||||
}
|
||||
|
||||
hydrateComponentView(hostView:viewModule.AppView, boundElementIndex:number, injector:Injector = null) {
|
||||
hydrateComponentView(hostView: viewModule.AppView, boundElementIndex: number,
|
||||
injector: Injector = null) {
|
||||
var elementInjector = hostView.elementInjectors[boundElementIndex];
|
||||
var componentView = hostView.componentChildViews[boundElementIndex];
|
||||
var component = this.getComponentInstance(hostView, boundElementIndex);
|
||||
this._hydrateView(
|
||||
componentView, injector, elementInjector, component, null
|
||||
);
|
||||
this._hydrateView(componentView, injector, elementInjector, component, null);
|
||||
}
|
||||
|
||||
hydrateRootHostView(hostView:viewModule.AppView, injector:Injector = null) {
|
||||
hydrateRootHostView(hostView: viewModule.AppView, injector: Injector = null) {
|
||||
this._hydrateView(hostView, injector, null, new Object(), null);
|
||||
}
|
||||
|
||||
attachAndHydrateFreeHostView(parentComponentHostView:viewModule.AppView, parentComponentBoundElementIndex:number,
|
||||
hostView:viewModule.AppView, injector:Injector = null) {
|
||||
var hostElementInjector = parentComponentHostView.elementInjectors[parentComponentBoundElementIndex];
|
||||
attachAndHydrateFreeHostView(parentComponentHostView: viewModule.AppView,
|
||||
parentComponentBoundElementIndex: number,
|
||||
hostView: viewModule.AppView, injector: Injector = null) {
|
||||
var hostElementInjector =
|
||||
parentComponentHostView.elementInjectors[parentComponentBoundElementIndex];
|
||||
var parentView = parentComponentHostView.componentChildViews[parentComponentBoundElementIndex];
|
||||
parentView.changeDetector.addChild(hostView.changeDetector);
|
||||
ListWrapper.push(parentView.freeHostViews, hostView);
|
||||
this._hydrateView(hostView, injector, hostElementInjector, new Object(), null);
|
||||
}
|
||||
|
||||
detachFreeHostView(parentView:viewModule.AppView,
|
||||
hostView:viewModule.AppView) {
|
||||
detachFreeHostView(parentView: viewModule.AppView, hostView: viewModule.AppView) {
|
||||
parentView.changeDetector.removeChild(hostView.changeDetector);
|
||||
ListWrapper.remove(parentView.freeHostViews, hostView);
|
||||
}
|
||||
|
||||
attachViewInContainer(parentView:viewModule.AppView, boundElementIndex:number,
|
||||
contextView:viewModule.AppView, contextBoundElementIndex:number,
|
||||
atIndex:number, view:viewModule.AppView) {
|
||||
attachViewInContainer(parentView: viewModule.AppView, boundElementIndex: number,
|
||||
contextView: viewModule.AppView, contextBoundElementIndex: number,
|
||||
atIndex: number, view: viewModule.AppView) {
|
||||
if (isBlank(contextView)) {
|
||||
contextView = parentView;
|
||||
contextBoundElementIndex = boundElementIndex;
|
||||
@ -138,7 +136,8 @@ export class AppViewManagerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
detachViewInContainer(parentView:viewModule.AppView, boundElementIndex:number, atIndex:number) {
|
||||
detachViewInContainer(parentView: viewModule.AppView, boundElementIndex: number,
|
||||
atIndex: number) {
|
||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||
var view = viewContainer.views[atIndex];
|
||||
view.changeDetector.remove();
|
||||
@ -148,9 +147,9 @@ export class AppViewManagerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
hydrateViewInContainer(parentView:viewModule.AppView, boundElementIndex:number,
|
||||
contextView:viewModule.AppView, contextBoundElementIndex:number,
|
||||
atIndex:number, injector:Injector) {
|
||||
hydrateViewInContainer(parentView: viewModule.AppView, boundElementIndex: number,
|
||||
contextView: viewModule.AppView, contextBoundElementIndex: number,
|
||||
atIndex: number, injector: Injector) {
|
||||
if (isBlank(contextView)) {
|
||||
contextView = parentView;
|
||||
contextBoundElementIndex = boundElementIndex;
|
||||
@ -161,11 +160,12 @@ export class AppViewManagerUtils {
|
||||
this._hydrateView(view, injector, elementInjector, contextView.context, contextView.locals);
|
||||
}
|
||||
|
||||
hydrateDynamicComponentInElementInjector(hostView:viewModule.AppView, boundElementIndex:number,
|
||||
componentBinding:Binding, injector:Injector = null) {
|
||||
hydrateDynamicComponentInElementInjector(hostView: viewModule.AppView, boundElementIndex: number,
|
||||
componentBinding: Binding, injector: Injector = null) {
|
||||
var elementInjector = hostView.elementInjectors[boundElementIndex];
|
||||
if (isPresent(elementInjector.getDynamicallyLoadedComponent())) {
|
||||
throw new BaseException(`There already is a dynamic component loaded at element ${boundElementIndex}`);
|
||||
throw new BaseException(
|
||||
`There already is a dynamic component loaded at element ${boundElementIndex}`);
|
||||
}
|
||||
if (isBlank(injector)) {
|
||||
injector = elementInjector.getLightDomAppInjector();
|
||||
@ -175,7 +175,8 @@ export class AppViewManagerUtils {
|
||||
elementInjector.dynamicallyCreateComponent(componentDirective, injector);
|
||||
}
|
||||
|
||||
_hydrateView(view:viewModule.AppView, appInjector:Injector, hostElementInjector:eli.ElementInjector, context: Object, parentLocals:Locals) {
|
||||
_hydrateView(view: viewModule.AppView, appInjector: Injector,
|
||||
hostElementInjector: eli.ElementInjector, context: Object, parentLocals: Locals) {
|
||||
if (isBlank(appInjector)) {
|
||||
appInjector = hostElementInjector.getShadowDomAppInjector();
|
||||
}
|
||||
@ -207,7 +208,8 @@ export class AppViewManagerUtils {
|
||||
view.changeDetector.hydrate(view.context, view.locals, view);
|
||||
}
|
||||
|
||||
_setUpEventEmitters(view:viewModule.AppView, elementInjector:eli.ElementInjector, boundElementIndex:number) {
|
||||
_setUpEventEmitters(view: viewModule.AppView, elementInjector: eli.ElementInjector,
|
||||
boundElementIndex: number) {
|
||||
var emitters = elementInjector.getEventEmitterAccessors();
|
||||
for (var directiveIndex = 0; directiveIndex < emitters.length; ++directiveIndex) {
|
||||
var directiveEmitters = emitters[directiveIndex];
|
||||
@ -220,7 +222,8 @@ export class AppViewManagerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
_setUpHostActions(view:viewModule.AppView, elementInjector:eli.ElementInjector, boundElementIndex:number) {
|
||||
_setUpHostActions(view: viewModule.AppView, elementInjector: eli.ElementInjector,
|
||||
boundElementIndex: number) {
|
||||
var hostActions = elementInjector.getHostActionAccessors();
|
||||
for (var directiveIndex = 0; directiveIndex < hostActions.length; ++directiveIndex) {
|
||||
var directiveHostActions = hostActions[directiveIndex];
|
||||
@ -233,7 +236,7 @@ export class AppViewManagerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
dehydrateView(view:viewModule.AppView) {
|
||||
dehydrateView(view: viewModule.AppView) {
|
||||
var binders = view.proto.elementBinders;
|
||||
for (var i = 0; i < binders.length; ++i) {
|
||||
var elementInjector = view.elementInjectors[i];
|
||||
@ -247,5 +250,4 @@ export class AppViewManagerUtils {
|
||||
view.context = null;
|
||||
view.changeDetector.dehydrate();
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import {Inject} from 'angular2/src/di/annotations_impl';
|
||||
import {Inject} from 'angular2/di';
|
||||
|
||||
import {ListWrapper, MapWrapper, Map, List} from 'angular2/src/facade/collection';
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
@ -10,15 +10,15 @@ import * as viewModule from './view';
|
||||
export const APP_VIEW_POOL_CAPACITY = 'AppViewPool.viewPoolCapacity';
|
||||
|
||||
export class AppViewPool {
|
||||
_poolCapacityPerProtoView:number;
|
||||
_pooledViewsPerProtoView:Map<viewModule.AppProtoView, List<viewModule.AppView>>;
|
||||
_poolCapacityPerProtoView: number;
|
||||
_pooledViewsPerProtoView: Map<viewModule.AppProtoView, List<viewModule.AppView>>;
|
||||
|
||||
constructor(@Inject(APP_VIEW_POOL_CAPACITY) poolCapacityPerProtoView) {
|
||||
this._poolCapacityPerProtoView = poolCapacityPerProtoView;
|
||||
this._pooledViewsPerProtoView = MapWrapper.create();
|
||||
}
|
||||
|
||||
getView(protoView:viewModule.AppProtoView):viewModule.AppView {
|
||||
getView(protoView: viewModule.AppProtoView): viewModule.AppView {
|
||||
var pooledViews = MapWrapper.get(this._pooledViewsPerProtoView, protoView);
|
||||
if (isPresent(pooledViews) && pooledViews.length > 0) {
|
||||
return ListWrapper.removeLast(pooledViews);
|
||||
@ -26,7 +26,7 @@ export class AppViewPool {
|
||||
return null;
|
||||
}
|
||||
|
||||
returnView(view:viewModule.AppView) {
|
||||
returnView(view: viewModule.AppView) {
|
||||
var protoView = view.proto;
|
||||
var pooledViews = MapWrapper.get(this._pooledViewsPerProtoView, protoView);
|
||||
if (isBlank(pooledViews)) {
|
||||
@ -37,5 +37,4 @@ export class AppViewPool {
|
||||
ListWrapper.push(pooledViews, view);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -3,12 +3,12 @@ import * as viewModule from './view';
|
||||
import {RenderViewRef} from 'angular2/src/render/api';
|
||||
|
||||
// This is a workaround for privacy in Dart as we don't have library parts
|
||||
export function internalView(viewRef:ViewRef):viewModule.AppView {
|
||||
export function internalView(viewRef: ViewRef): viewModule.AppView {
|
||||
return viewRef._view;
|
||||
}
|
||||
|
||||
// This is a workaround for privacy in Dart as we don't have library parts
|
||||
export function internalProtoView(protoViewRef:ProtoViewRef):viewModule.AppProtoView {
|
||||
export function internalProtoView(protoViewRef: ProtoViewRef): viewModule.AppProtoView {
|
||||
return isPresent(protoViewRef) ? protoViewRef._protoView : null;
|
||||
}
|
||||
|
||||
@ -16,28 +16,20 @@ export function internalProtoView(protoViewRef:ProtoViewRef):viewModule.AppProto
|
||||
* @exportedAs angular2/view
|
||||
*/
|
||||
export class ViewRef {
|
||||
_view:viewModule.AppView;
|
||||
_view: viewModule.AppView;
|
||||
|
||||
constructor(view:viewModule.AppView) {
|
||||
this._view = view;
|
||||
}
|
||||
constructor(view: viewModule.AppView) { this._view = view; }
|
||||
|
||||
get render():RenderViewRef {
|
||||
return this._view.render;
|
||||
}
|
||||
get render(): RenderViewRef { return this._view.render; }
|
||||
|
||||
setLocal(contextName:string, value:any):void {
|
||||
this._view.setLocal(contextName, value);
|
||||
}
|
||||
setLocal(contextName: string, value: any): void { this._view.setLocal(contextName, value); }
|
||||
}
|
||||
|
||||
/**
|
||||
* @exportedAs angular2/view
|
||||
*/
|
||||
export class ProtoViewRef {
|
||||
_protoView:viewModule.AppProtoView;
|
||||
_protoView: viewModule.AppProtoView;
|
||||
|
||||
constructor(protoView) {
|
||||
this._protoView = protoView;
|
||||
}
|
||||
constructor(protoView) { this._protoView = protoView; }
|
||||
}
|
Reference in New Issue
Block a user