refactor(view): moved the logic from ProtoView to ProtoViewFactory
This commit is contained in:
@ -4,9 +4,13 @@ import {IterableChangesFactory} from './pipes/iterable_changes';
|
||||
import {KeyValueChangesFactory} from './pipes/keyvalue_changes';
|
||||
import {AsyncPipeFactory} from './pipes/async_pipe';
|
||||
import {NullPipeFactory} from './pipes/null_pipe';
|
||||
import {BindingRecord} from './binding_record';
|
||||
import {DirectiveRecord} from './directive_record';
|
||||
import {DEFAULT} from './constants';
|
||||
import {ChangeDetection, ProtoChangeDetector} from './interfaces';
|
||||
import {Injectable} from 'angular2/di';
|
||||
import {List} from 'angular2/src/facade/collection';
|
||||
|
||||
|
||||
/**
|
||||
* Structural diffing for `Object`s and `Map`s.
|
||||
@ -61,8 +65,9 @@ export class DynamicChangeDetection extends ChangeDetection {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
createProtoChangeDetector(name:string, changeControlStrategy:string = DEFAULT):ProtoChangeDetector{
|
||||
return new DynamicProtoChangeDetector(this.registry, changeControlStrategy);
|
||||
createProtoChangeDetector(name:string, bindingRecords:List<BindingRecord>, variableBindings:List<string>,
|
||||
directiveRecords:List<DirectiveRecord>, changeControlStrategy:string = DEFAULT):ProtoChangeDetector{
|
||||
return new DynamicProtoChangeDetector(this.registry, bindingRecords, variableBindings, directiveRecords, changeControlStrategy);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,8 +87,9 @@ export class JitChangeDetection extends ChangeDetection {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
createProtoChangeDetector(name:string, changeControlStrategy:string = DEFAULT):ProtoChangeDetector{
|
||||
return new JitProtoChangeDetector(this.registry, changeControlStrategy);
|
||||
createProtoChangeDetector(name:string, bindingRecords:List<BindingRecord>, variableBindings:List<string>,
|
||||
directiveRecords:List<DirectiveRecord>, changeControlStrategy:string = DEFAULT):ProtoChangeDetector{
|
||||
return new JitProtoChangeDetector(this.registry, bindingRecords, variableBindings, directiveRecords, changeControlStrategy);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import {DEFAULT} from './constants';
|
||||
import {BindingRecord} from './binding_record';
|
||||
|
||||
export class ProtoChangeDetector {
|
||||
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List, directiveRecords:List):ChangeDetector{
|
||||
instantiate(dispatcher:any):ChangeDetector{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -33,7 +33,8 @@ export class ProtoChangeDetector {
|
||||
* @exportedAs angular2/change_detection
|
||||
*/
|
||||
export class ChangeDetection {
|
||||
createProtoChangeDetector(name:string, changeControlStrategy:string=DEFAULT):ProtoChangeDetector{
|
||||
createProtoChangeDetector(name:string, bindingRecords:List, variableBindings:List, directiveRecords:List,
|
||||
changeControlStrategy:string=DEFAULT):ProtoChangeDetector{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ import {DynamicChangeDetector} from './dynamic_change_detector';
|
||||
import {ChangeDetectorJITGenerator} from './change_detection_jit_generator';
|
||||
import {PipeRegistry} from './pipes/pipe_registry';
|
||||
import {BindingRecord} from './binding_record';
|
||||
import {DirectiveIndex} from './directive_record';
|
||||
import {DirectiveRecord, DirectiveIndex} from './directive_record';
|
||||
|
||||
import {coalesce} from './coalesce';
|
||||
|
||||
@ -50,25 +50,31 @@ import {
|
||||
export class DynamicProtoChangeDetector extends ProtoChangeDetector {
|
||||
_pipeRegistry:PipeRegistry;
|
||||
_records:List<ProtoRecord>;
|
||||
_bindingRecords:List<BindingRecord>;
|
||||
_variableBindings:List<string>;
|
||||
_directiveRecords:List<DirectiveRecord>;
|
||||
_changeControlStrategy:string;
|
||||
|
||||
constructor(pipeRegistry:PipeRegistry, changeControlStrategy:string) {
|
||||
constructor(pipeRegistry:PipeRegistry, bindingRecords:List, variableBindings:List, directiveRecords:List, changeControlStrategy:string) {
|
||||
super();
|
||||
this._pipeRegistry = pipeRegistry;
|
||||
this._bindingRecords = bindingRecords;
|
||||
this._variableBindings = variableBindings;
|
||||
this._directiveRecords = directiveRecords;
|
||||
this._changeControlStrategy = changeControlStrategy;
|
||||
}
|
||||
|
||||
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List, directiveRecords:List) {
|
||||
this._createRecordsIfNecessary(bindingRecords, variableBindings);
|
||||
instantiate(dispatcher:any) {
|
||||
this._createRecordsIfNecessary();
|
||||
return new DynamicChangeDetector(this._changeControlStrategy, dispatcher,
|
||||
this._pipeRegistry, this._records, directiveRecords);
|
||||
this._pipeRegistry, this._records, this._directiveRecords);
|
||||
}
|
||||
|
||||
_createRecordsIfNecessary(bindingRecords:List, variableBindings:List) {
|
||||
_createRecordsIfNecessary() {
|
||||
if (isBlank(this._records)) {
|
||||
var recordBuilder = new ProtoRecordBuilder();
|
||||
ListWrapper.forEach(bindingRecords, (b) => {
|
||||
recordBuilder.addAst(b, variableBindings);
|
||||
ListWrapper.forEach(this._bindingRecords, (b) => {
|
||||
recordBuilder.addAst(b, this._variableBindings);
|
||||
});
|
||||
this._records = coalesce(recordBuilder.records);
|
||||
}
|
||||
@ -79,31 +85,37 @@ var _jitProtoChangeDetectorClassCounter:number = 0;
|
||||
export class JitProtoChangeDetector extends ProtoChangeDetector {
|
||||
_factory:Function;
|
||||
_pipeRegistry;
|
||||
_bindingRecords:List<BindingRecord>;
|
||||
_variableBindings:List<string>;
|
||||
_directiveRecords:List<DirectiveRecord>;
|
||||
_changeControlStrategy:string;
|
||||
|
||||
constructor(pipeRegistry, changeControlStrategy:string) {
|
||||
constructor(pipeRegistry, bindingRecords:List, variableBindings:List, directiveRecords:List, changeControlStrategy:string) {
|
||||
super();
|
||||
this._pipeRegistry = pipeRegistry;
|
||||
this._factory = null;
|
||||
this._bindingRecords = bindingRecords;
|
||||
this._variableBindings = variableBindings;
|
||||
this._directiveRecords = directiveRecords;
|
||||
this._changeControlStrategy = changeControlStrategy;
|
||||
}
|
||||
|
||||
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List, directiveRecords:List) {
|
||||
this._createFactoryIfNecessary(bindingRecords, variableBindings, directiveRecords);
|
||||
instantiate(dispatcher:any) {
|
||||
this._createFactoryIfNecessary();
|
||||
return this._factory(dispatcher, this._pipeRegistry);
|
||||
}
|
||||
|
||||
_createFactoryIfNecessary(bindingRecords:List, variableBindings:List, directiveRecords:List) {
|
||||
_createFactoryIfNecessary() {
|
||||
if (isBlank(this._factory)) {
|
||||
var recordBuilder = new ProtoRecordBuilder();
|
||||
ListWrapper.forEach(bindingRecords, (b) => {
|
||||
recordBuilder.addAst(b, variableBindings);
|
||||
ListWrapper.forEach(this._bindingRecords, (b) => {
|
||||
recordBuilder.addAst(b, this._variableBindings);
|
||||
});
|
||||
var c = _jitProtoChangeDetectorClassCounter++;
|
||||
var records = coalesce(recordBuilder.records);
|
||||
var typeName = `ChangeDetector${c}`;
|
||||
this._factory = new ChangeDetectorJITGenerator(typeName, this._changeControlStrategy, records,
|
||||
directiveRecords).generate();
|
||||
this._directiveRecords).generate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
modules/angular2/src/core/compiler/compiler.js
vendored
15
modules/angular2/src/core/compiler/compiler.js
vendored
@ -94,7 +94,7 @@ export class Compiler {
|
||||
|
||||
var directiveMetadata = Compiler.buildRenderDirective(componentBinding);
|
||||
return this._renderer.createHostProtoView(directiveMetadata).then( (hostRenderPv) => {
|
||||
return this._compileNestedProtoViews(null, hostRenderPv, [componentBinding], true);
|
||||
return this._compileNestedProtoViews(null, null, hostRenderPv, [componentBinding], true);
|
||||
}).then( (appProtoView) => {
|
||||
return new ProtoViewRef(appProtoView);
|
||||
});
|
||||
@ -135,7 +135,7 @@ export class Compiler {
|
||||
if (isPresent(template.renderer)) {
|
||||
var directives = [];
|
||||
pvPromise = this._renderer.createImperativeComponentProtoView(template.renderer).then( (renderPv) => {
|
||||
return this._compileNestedProtoViews(componentBinding, renderPv, directives, true);
|
||||
return this._compileNestedProtoViews(null, componentBinding, renderPv, directives, true);
|
||||
});
|
||||
} else {
|
||||
var directives = ListWrapper.map(
|
||||
@ -144,7 +144,7 @@ export class Compiler {
|
||||
);
|
||||
var renderTemplate = this._buildRenderTemplate(component, template, directives);
|
||||
pvPromise = this._renderer.compile(renderTemplate).then( (renderPv) => {
|
||||
return this._compileNestedProtoViews(componentBinding, renderPv, directives, true);
|
||||
return this._compileNestedProtoViews(null, componentBinding, renderPv, directives, true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -153,9 +153,9 @@ export class Compiler {
|
||||
}
|
||||
|
||||
// TODO(tbosch): union type return AppProtoView or Promise<AppProtoView>
|
||||
_compileNestedProtoViews(componentBinding, renderPv, directives, isComponentRootView) {
|
||||
_compileNestedProtoViews(parentProtoView, componentBinding, renderPv, directives, isComponentRootView) {
|
||||
var nestedPVPromises = [];
|
||||
var protoView = this._protoViewFactory.createProtoView(componentBinding, renderPv, directives);
|
||||
var protoView = this._protoViewFactory.createProtoView(parentProtoView, componentBinding, renderPv, directives);
|
||||
if (isComponentRootView && isPresent(componentBinding)) {
|
||||
// Populate the cache before compiling the nested components,
|
||||
// so that components can reference themselves in their template.
|
||||
@ -170,15 +170,12 @@ export class Compiler {
|
||||
var nestedRenderProtoView = renderPv.elementBinders[binderIndex].nestedProtoView;
|
||||
var elementBinderDone = (nestedPv) => {
|
||||
elementBinder.nestedProtoView = nestedPv;
|
||||
// Can't set the parentProtoView for components,
|
||||
// as their AppProtoView might be used in multiple other components.
|
||||
nestedPv.parentProtoView = isPresent(nestedComponent) ? null : protoView;
|
||||
};
|
||||
var nestedCall = null;
|
||||
if (isPresent(nestedComponent)) {
|
||||
nestedCall = this._compile(nestedComponent);
|
||||
} else if (isPresent(nestedRenderProtoView)) {
|
||||
nestedCall = this._compileNestedProtoViews(componentBinding, nestedRenderProtoView, directives, false);
|
||||
nestedCall = this._compileNestedProtoViews(protoView, componentBinding, nestedRenderProtoView, directives, false);
|
||||
}
|
||||
if (PromiseWrapper.isPromise(nestedCall)) {
|
||||
ListWrapper.push(nestedPVPromises, nestedCall.then(elementBinderDone));
|
||||
|
@ -3,13 +3,103 @@ 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} from 'angular2/change_detection';
|
||||
import {ChangeDetection, DirectiveIndex, BindingRecord, DirectiveRecord, ProtoChangeDetector} from 'angular2/change_detection';
|
||||
import {Component} from '../annotations_impl/annotations';
|
||||
|
||||
import * as renderApi from 'angular2/src/render/api';
|
||||
import {AppProtoView} from './view';
|
||||
import {ProtoElementInjector, DirectiveBinding} from './element_injector';
|
||||
|
||||
|
||||
class BindingRecordsCreator {
|
||||
_directiveRecordsMap;
|
||||
_textNodeIndex:number;
|
||||
|
||||
constructor() {
|
||||
this._directiveRecordsMap = MapWrapper.create();
|
||||
this._textNodeIndex = 0;
|
||||
}
|
||||
|
||||
getBindingRecords(elementBinders:List<renderApi.ElementBinder>, sortedDirectives:List<SortedDirectives>):List<BindingRecord> {
|
||||
var bindings = [];
|
||||
|
||||
for (var boundElementIndex = 0; boundElementIndex < elementBinders.length; boundElementIndex++) {
|
||||
var renderElementBinder = elementBinders[boundElementIndex];
|
||||
bindings = ListWrapper.concat(bindings, this._createTextNodeRecords(renderElementBinder));
|
||||
bindings = ListWrapper.concat(bindings, this._createElementPropertyRecords(boundElementIndex, renderElementBinder));
|
||||
bindings = ListWrapper.concat(bindings, this._createDirectiveRecords(boundElementIndex, sortedDirectives[boundElementIndex]));
|
||||
}
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
getDirectiveRecords(sortedDirectives:List<SortedDirectives>): List {
|
||||
var directiveRecords = [];
|
||||
|
||||
for (var elementIndex = 0; elementIndex < sortedDirectives.length; ++elementIndex) {
|
||||
var dirs = sortedDirectives[elementIndex].directives;
|
||||
for (var dirIndex = 0; dirIndex < dirs.length; ++dirIndex) {
|
||||
ListWrapper.push(directiveRecords, this._getDirectiveRecord(elementIndex, dirIndex, dirs[dirIndex]));
|
||||
}
|
||||
}
|
||||
|
||||
return directiveRecords;
|
||||
}
|
||||
|
||||
_createTextNodeRecords(renderElementBinder:renderApi.ElementBinder) {
|
||||
if (isBlank(renderElementBinder.textBindings)) return [];
|
||||
return ListWrapper.map(renderElementBinder.textBindings, b => BindingRecord.createForTextNode(b, this._textNodeIndex++));
|
||||
}
|
||||
|
||||
_createElementPropertyRecords(boundElementIndex:number, renderElementBinder:renderApi.ElementBinder) {
|
||||
var res = [];
|
||||
MapWrapper.forEach(renderElementBinder.propertyBindings, (astWithSource, propertyName) => {
|
||||
ListWrapper.push(res, BindingRecord.createForElement(astWithSource, boundElementIndex, propertyName));
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
_createDirectiveRecords(boundElementIndex:number, sortedDirectives:SortedDirectives) {
|
||||
var res = [];
|
||||
for (var i = 0; i < sortedDirectives.renderDirectives.length; i++) {
|
||||
var directiveBinder = sortedDirectives.renderDirectives[i];
|
||||
|
||||
// directive properties
|
||||
MapWrapper.forEach(directiveBinder.propertyBindings, (astWithSource, propertyName) => {
|
||||
// TODO: these setters should eventually be created by change detection, to make
|
||||
// it monomorphic!
|
||||
var setter = reflector.setter(propertyName);
|
||||
var directiveRecord = this._getDirectiveRecord(boundElementIndex, i, sortedDirectives.directives[i]);
|
||||
var b = BindingRecord.createForDirective(astWithSource, propertyName, setter, directiveRecord);
|
||||
ListWrapper.push(res, b);
|
||||
});
|
||||
|
||||
// host properties
|
||||
MapWrapper.forEach(directiveBinder.hostPropertyBindings, (astWithSource, propertyName) => {
|
||||
var dirIndex = new DirectiveIndex(boundElementIndex, i);
|
||||
var b = BindingRecord.createForHostProperty(dirIndex, astWithSource, propertyName);
|
||||
ListWrapper.push(res, b);
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
_getDirectiveRecord(boundElementIndex:number, directiveIndex:number, binding:DirectiveBinding): DirectiveRecord {
|
||||
var id = boundElementIndex * 100 + directiveIndex;
|
||||
|
||||
if (!MapWrapper.contains(this._directiveRecordsMap, id)) {
|
||||
var changeDetection = binding.changeDetection;
|
||||
|
||||
MapWrapper.set(this._directiveRecordsMap, id,
|
||||
new DirectiveRecord(new DirectiveIndex(boundElementIndex, directiveIndex),
|
||||
binding.callOnAllChangesDone, binding.callOnChange, changeDetection));
|
||||
}
|
||||
|
||||
return MapWrapper.get(this._directiveRecordsMap, id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class ProtoViewFactory {
|
||||
_changeDetection:ChangeDetection;
|
||||
@ -18,40 +108,85 @@ export class ProtoViewFactory {
|
||||
this._changeDetection = changeDetection;
|
||||
}
|
||||
|
||||
createProtoView(componentBinding:DirectiveBinding, renderProtoView: renderApi.ProtoViewDto,
|
||||
directives:List<DirectiveBinding>):AppProtoView {
|
||||
var protoChangeDetector;
|
||||
if (isBlank(componentBinding)) {
|
||||
protoChangeDetector = this._changeDetection.createProtoChangeDetector('root', null);
|
||||
} else {
|
||||
var componentAnnotation:Component = componentBinding.annotation;
|
||||
protoChangeDetector = this._changeDetection.createProtoChangeDetector(
|
||||
'dummy', componentAnnotation.changeDetection
|
||||
);
|
||||
}
|
||||
var protoView = new AppProtoView(renderProtoView.render, protoChangeDetector);
|
||||
createProtoView(parentProtoView:AppProtoView, componentBinding:DirectiveBinding,
|
||||
renderProtoView: renderApi.ProtoViewDto, directives:List<DirectiveBinding>):AppProtoView {
|
||||
|
||||
var elementBinders = renderProtoView.elementBinders;
|
||||
var sortedDirectives = ListWrapper.map(elementBinders, b => new SortedDirectives(b.directives, directives));
|
||||
|
||||
var variableBindings = this._createVariableBindings(renderProtoView);
|
||||
var protoLocals = this._createProtoLocals(renderProtoView);
|
||||
var variableNames = this._createVariableNames(parentProtoView, protoLocals);
|
||||
var protoChangeDetector = this._createProtoChangeDetector(elementBinders, sortedDirectives, componentBinding, variableNames);
|
||||
var protoView = new AppProtoView(renderProtoView.render, protoChangeDetector, variableBindings, protoLocals, variableNames);
|
||||
|
||||
// TODO: vsavkin refactor to pass element binders into proto view
|
||||
this._createElementBinders(protoView, elementBinders, sortedDirectives)
|
||||
this._bindDirectiveEvents(protoView, sortedDirectives);
|
||||
|
||||
for (var i=0; i<renderProtoView.elementBinders.length; i++) {
|
||||
var renderElementBinder = renderProtoView.elementBinders[i];
|
||||
var sortedDirectives = new SortedDirectives(renderElementBinder.directives, directives);
|
||||
var parentPeiWithDistance = this._findParentProtoElementInjectorWithDistance(
|
||||
i, protoView.elementBinders, renderProtoView.elementBinders
|
||||
);
|
||||
var protoElementInjector = this._createProtoElementInjector(
|
||||
i, parentPeiWithDistance,
|
||||
sortedDirectives, renderElementBinder
|
||||
);
|
||||
this._createElementBinder(
|
||||
protoView, renderElementBinder, protoElementInjector, sortedDirectives
|
||||
);
|
||||
this._createDirectiveBinders(protoView, i, sortedDirectives);
|
||||
}
|
||||
MapWrapper.forEach(renderProtoView.variableBindings, (mappedName, varName) => {
|
||||
protoView.bindVariable(varName, mappedName);
|
||||
});
|
||||
return protoView;
|
||||
}
|
||||
|
||||
_createProtoLocals(renderProtoView):Map {
|
||||
var protoLocals = MapWrapper.create();
|
||||
MapWrapper.forEach(renderProtoView.variableBindings, (mappedName, varName) => {
|
||||
MapWrapper.set(protoLocals, mappedName, null);
|
||||
});
|
||||
return protoLocals;
|
||||
}
|
||||
|
||||
_createVariableBindings(renderProtoView):Map {
|
||||
var variableBindings = MapWrapper.create();
|
||||
MapWrapper.forEach(renderProtoView.variableBindings, (mappedName, varName) => {
|
||||
MapWrapper.set(variableBindings, varName, mappedName);
|
||||
});
|
||||
return variableBindings;
|
||||
}
|
||||
|
||||
_createVariableNames(parentProtoView, protoLocals):List {
|
||||
var variableNames = isPresent(parentProtoView) ? ListWrapper.clone(parentProtoView.variableNames) : [];
|
||||
MapWrapper.forEach(protoLocals, (v, local) => {
|
||||
ListWrapper.push(variableNames, local);
|
||||
});
|
||||
return variableNames;
|
||||
}
|
||||
|
||||
_createProtoChangeDetector(elementBinders, sortedDirectives, componentBinding, variableNames):ProtoChangeDetector {
|
||||
var bindingRecordsCreator = new BindingRecordsCreator();
|
||||
var bindingRecords = bindingRecordsCreator.getBindingRecords(elementBinders, sortedDirectives);
|
||||
var directiveRecords = bindingRecordsCreator.getDirectiveRecords(sortedDirectives);
|
||||
|
||||
var changeDetection = null;
|
||||
var name = 'root';
|
||||
if (isPresent(componentBinding)) {
|
||||
var componentAnnotation:Component = componentBinding.annotation;
|
||||
changeDetection = componentAnnotation.changeDetection;
|
||||
name = 'dummy';
|
||||
}
|
||||
|
||||
return this._changeDetection.createProtoChangeDetector(
|
||||
name,
|
||||
bindingRecords,
|
||||
variableNames,
|
||||
directiveRecords,
|
||||
changeDetection
|
||||
);
|
||||
}
|
||||
|
||||
_createElementBinders(protoView, elementBinders, sortedDirectives) {
|
||||
for (var i=0; i<elementBinders.length; i++) {
|
||||
var renderElementBinder = elementBinders[i];
|
||||
var dirs = sortedDirectives[i];
|
||||
|
||||
var parentPeiWithDistance = this._findParentProtoElementInjectorWithDistance(
|
||||
i, protoView.elementBinders, elementBinders);
|
||||
var protoElementInjector = this._createProtoElementInjector(
|
||||
i, parentPeiWithDistance, dirs, renderElementBinder);
|
||||
|
||||
this._createElementBinder(protoView, i, renderElementBinder, protoElementInjector, dirs);
|
||||
}
|
||||
}
|
||||
|
||||
_findParentProtoElementInjectorWithDistance(binderIndex, elementBinders, renderElementBinders) {
|
||||
var distance = 0;
|
||||
do {
|
||||
@ -95,7 +230,7 @@ export class ProtoViewFactory {
|
||||
return protoElementInjector;
|
||||
}
|
||||
|
||||
_createElementBinder(protoView, renderElementBinder, protoElementInjector, sortedDirectives) {
|
||||
_createElementBinder(protoView, boundElementIndex, renderElementBinder, protoElementInjector, sortedDirectives) {
|
||||
var parent = null;
|
||||
if (renderElementBinder.parentIndex !== -1) {
|
||||
parent = protoView.elementBinders[renderElementBinder.parentIndex];
|
||||
@ -106,16 +241,7 @@ export class ProtoViewFactory {
|
||||
protoElementInjector,
|
||||
sortedDirectives.componentDirective
|
||||
);
|
||||
// text nodes
|
||||
for (var i=0; i<renderElementBinder.textBindings.length; i++) {
|
||||
protoView.bindTextNode(renderElementBinder.textBindings[i]);
|
||||
}
|
||||
// element properties
|
||||
MapWrapper.forEach(renderElementBinder.propertyBindings, (astWithSource, propertyName) => {
|
||||
protoView.bindElementProperty(astWithSource, propertyName);
|
||||
});
|
||||
// events
|
||||
protoView.bindEvent(renderElementBinder.eventBindings, -1);
|
||||
protoView.bindEvent(renderElementBinder.eventBindings, boundElementIndex, -1);
|
||||
// variables
|
||||
// The view's locals needs to have a full set of variable names at construction time
|
||||
// in order to prevent new variables from being set later in the lifecycle. Since we don't want
|
||||
@ -127,26 +253,15 @@ export class ProtoViewFactory {
|
||||
return elBinder;
|
||||
}
|
||||
|
||||
_createDirectiveBinders(protoView, boundElementIndex, sortedDirectives) {
|
||||
for (var i = 0; i < sortedDirectives.renderDirectives.length; i++) {
|
||||
var directiveBinder = sortedDirectives.renderDirectives[i];
|
||||
_bindDirectiveEvents(protoView, sortedDirectives:List<SortedDirectives>) {
|
||||
for (var boundElementIndex = 0; boundElementIndex < sortedDirectives.length; ++boundElementIndex) {
|
||||
var dirs = sortedDirectives[boundElementIndex].renderDirectives;
|
||||
for (var i = 0; i < dirs.length; i++) {
|
||||
var directiveBinder = dirs[i];
|
||||
|
||||
// directive properties
|
||||
MapWrapper.forEach(directiveBinder.propertyBindings, (astWithSource, propertyName) => {
|
||||
// TODO: these setters should eventually be created by change detection, to make
|
||||
// it monomorphic!
|
||||
var setter = reflector.setter(propertyName);
|
||||
protoView.bindDirectiveProperty(i, astWithSource, propertyName, setter);
|
||||
});
|
||||
|
||||
// host properties
|
||||
MapWrapper.forEach(directiveBinder.hostPropertyBindings, (astWithSource, propertyName) => {
|
||||
var directiveIndex = new DirectiveIndex(boundElementIndex, i);
|
||||
protoView.bindHostElementProperty(astWithSource, propertyName, directiveIndex);
|
||||
});
|
||||
|
||||
// directive events
|
||||
protoView.bindEvent(directiveBinder.eventBindings, i);
|
||||
// directive events
|
||||
protoView.bindEvent(directiveBinder.eventBindings, boundElementIndex, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
130
modules/angular2/src/core/compiler/view.js
vendored
130
modules/angular2/src/core/compiler/view.js
vendored
@ -4,7 +4,6 @@ import {AST, Locals, ChangeDispatcher, ProtoChangeDetector, ChangeDetector,
|
||||
|
||||
import {ProtoElementInjector, ElementInjector, PreBuiltObjects, DirectiveBinding} from './element_injector';
|
||||
import {ElementBinder} from './element_binder';
|
||||
import {SetterFn} from 'angular2/src/reflection/types';
|
||||
import {IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import * as renderApi from 'angular2/src/render/api';
|
||||
|
||||
@ -164,74 +163,22 @@ export class AppProtoView {
|
||||
protoChangeDetector:ProtoChangeDetector;
|
||||
variableBindings: Map;
|
||||
protoLocals:Map;
|
||||
textNodesWithBindingCount:int;
|
||||
bindings:List;
|
||||
parentProtoView:AppProtoView;
|
||||
_variableBindings:List;
|
||||
|
||||
_directiveRecordsMap:Map;
|
||||
_directiveRecords:List;
|
||||
variableNames:List;
|
||||
render:renderApi.RenderProtoViewRef;
|
||||
|
||||
constructor(
|
||||
render:renderApi.RenderProtoViewRef,
|
||||
protoChangeDetector:ProtoChangeDetector) {
|
||||
protoChangeDetector:ProtoChangeDetector,
|
||||
variableBindings:Map,
|
||||
protoLocals:Map,
|
||||
variableNames:List) {
|
||||
this.render = render;
|
||||
this.elementBinders = [];
|
||||
this.variableBindings = MapWrapper.create();
|
||||
this.protoLocals = MapWrapper.create();
|
||||
this.variableBindings = variableBindings;
|
||||
this.protoLocals = protoLocals;
|
||||
this.variableNames = variableNames;
|
||||
this.protoChangeDetector = protoChangeDetector;
|
||||
this.parentProtoView = null;
|
||||
this.textNodesWithBindingCount = 0;
|
||||
this.bindings = [];
|
||||
this._directiveRecordsMap = MapWrapper.create();
|
||||
this._variableBindings = null;
|
||||
this._directiveRecords = null;
|
||||
}
|
||||
|
||||
//TODO: Tobias or Victor. Moving it into the constructor.
|
||||
// this work should be done the constructor of AppProtoView once we separate
|
||||
// AppProtoView and ProtoViewBuilder
|
||||
getVariableBindings(): List {
|
||||
if (isPresent(this._variableBindings)) {
|
||||
return this._variableBindings;
|
||||
}
|
||||
|
||||
this._variableBindings = isPresent(this.parentProtoView) ?
|
||||
ListWrapper.clone(this.parentProtoView.getVariableBindings()) : [];
|
||||
|
||||
MapWrapper.forEach(this.protoLocals, (v, local) => {
|
||||
ListWrapper.push(this._variableBindings, local);
|
||||
});
|
||||
|
||||
return this._variableBindings;
|
||||
}
|
||||
|
||||
//TODO: Tobias or Victor. Moving it into the constructor.
|
||||
// this work should be done the constructor of ProtoView once we separate
|
||||
// AppProtoView and ProtoViewBuilder
|
||||
getdirectiveRecords(): List {
|
||||
if (isPresent(this._directiveRecords)) {
|
||||
return this._directiveRecords;
|
||||
}
|
||||
|
||||
this._directiveRecords = [];
|
||||
|
||||
for (var injectorIndex = 0; injectorIndex < this.elementBinders.length; ++injectorIndex) {
|
||||
var pei = this.elementBinders[injectorIndex].protoElementInjector;
|
||||
if (isPresent(pei)) {
|
||||
for (var directiveIndex = 0; directiveIndex < pei.numberOfDirectives; ++directiveIndex) {
|
||||
ListWrapper.push(this._directiveRecords, this._getDirectiveRecord(injectorIndex, directiveIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this._directiveRecords;
|
||||
}
|
||||
|
||||
bindVariable(contextName:string, templateName:string): void {
|
||||
MapWrapper.set(this.variableBindings, contextName, templateName);
|
||||
MapWrapper.set(this.protoLocals, templateName, null);
|
||||
}
|
||||
|
||||
bindElement(parent:ElementBinder, distanceToParent:int, protoElementInjector:ProtoElementInjector,
|
||||
@ -242,32 +189,6 @@ export class AppProtoView {
|
||||
return elBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a text node binding for the last created ElementBinder via bindElement
|
||||
*/
|
||||
bindTextNode(expression:AST):void {
|
||||
var textNodeIndex = this.textNodesWithBindingCount++;
|
||||
var b = BindingRecord.createForTextNode(expression, textNodeIndex);
|
||||
ListWrapper.push(this.bindings, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element property binding for the last created ElementBinder via bindElement
|
||||
*/
|
||||
bindElementProperty(expression:AST, setterName:string):void {
|
||||
var elementIndex = this.elementBinders.length-1;
|
||||
var b = BindingRecord.createForElement(expression, elementIndex, setterName);
|
||||
ListWrapper.push(this.bindings, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an host property binding for the last created ElementBinder via bindElement
|
||||
*/
|
||||
bindHostElementProperty(expression:AST, setterName:string, directiveIndex:DirectiveIndex):void {
|
||||
var b = BindingRecord.createForHostProperty(directiveIndex, expression, setterName);
|
||||
ListWrapper.push(this.bindings, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an event binding for the last created ElementBinder via bindElement.
|
||||
*
|
||||
@ -281,8 +202,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>, directiveIndex: int = -1): void {
|
||||
var elBinder = this.elementBinders[this.elementBinders.length - 1];
|
||||
bindEvent(eventBindings: List<renderApi.EventBinding>, boundElementIndex:number, directiveIndex: int = -1): void {
|
||||
var elBinder = this.elementBinders[boundElementIndex];
|
||||
var events = elBinder.hostListeners;
|
||||
if (isBlank(events)) {
|
||||
events = StringMapWrapper.create();
|
||||
@ -299,35 +220,4 @@ export class AppProtoView {
|
||||
MapWrapper.set(event, directiveIndex, eventBinding.source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a directive property binding for the last created ElementBinder via bindElement
|
||||
*/
|
||||
bindDirectiveProperty(
|
||||
directiveIndex:number,
|
||||
expression:AST,
|
||||
setterName:string,
|
||||
setter:SetterFn): void {
|
||||
|
||||
var elementIndex = this.elementBinders.length-1;
|
||||
var directiveRecord = this._getDirectiveRecord(elementIndex, directiveIndex);
|
||||
var b = BindingRecord.createForDirective(expression, setterName, setter, directiveRecord);
|
||||
ListWrapper.push(this.bindings, b);
|
||||
}
|
||||
|
||||
_getDirectiveRecord(elementInjectorIndex:number, directiveIndex:number): DirectiveRecord {
|
||||
var id = elementInjectorIndex * 100 + directiveIndex;
|
||||
var protoElementInjector = this.elementBinders[elementInjectorIndex].protoElementInjector;
|
||||
|
||||
if (!MapWrapper.contains(this._directiveRecordsMap, id)) {
|
||||
var binding = protoElementInjector.getDirectiveBindingAtIndex(directiveIndex);
|
||||
var changeDetection = binding.changeDetection;
|
||||
|
||||
MapWrapper.set(this._directiveRecordsMap, id,
|
||||
new DirectiveRecord(new DirectiveIndex(elementInjectorIndex, directiveIndex),
|
||||
binding.callOnAllChangesDone, binding.callOnChange, changeDetection));
|
||||
}
|
||||
|
||||
return MapWrapper.get(this._directiveRecordsMap, id);
|
||||
}
|
||||
}
|
||||
|
@ -28,8 +28,7 @@ export class AppViewManagerUtils {
|
||||
|
||||
createView(protoView:viewModule.AppProtoView, viewManager:avmModule.AppViewManager, renderer:Renderer): viewModule.AppView {
|
||||
var view = new viewModule.AppView(renderer, protoView, protoView.protoLocals);
|
||||
var changeDetector = protoView.protoChangeDetector.instantiate(view, protoView.bindings,
|
||||
protoView.getVariableBindings(), protoView.getdirectiveRecords());
|
||||
var changeDetector = protoView.protoChangeDetector.instantiate(view);
|
||||
|
||||
var binders = protoView.elementBinders;
|
||||
var elementInjectors = ListWrapper.createFixedSize(binders.length);
|
||||
|
Reference in New Issue
Block a user