refactor(view): moved the logic from ProtoView to ProtoViewFactory

This commit is contained in:
vsavkin 2015-04-30 14:45:42 -07:00
parent 0f4a089c32
commit ce6a2ba836
16 changed files with 309 additions and 290 deletions

View File

@ -4,9 +4,13 @@ import {IterableChangesFactory} from './pipes/iterable_changes';
import {KeyValueChangesFactory} from './pipes/keyvalue_changes'; import {KeyValueChangesFactory} from './pipes/keyvalue_changes';
import {AsyncPipeFactory} from './pipes/async_pipe'; import {AsyncPipeFactory} from './pipes/async_pipe';
import {NullPipeFactory} from './pipes/null_pipe'; import {NullPipeFactory} from './pipes/null_pipe';
import {BindingRecord} from './binding_record';
import {DirectiveRecord} from './directive_record';
import {DEFAULT} from './constants'; import {DEFAULT} from './constants';
import {ChangeDetection, ProtoChangeDetector} from './interfaces'; import {ChangeDetection, ProtoChangeDetector} from './interfaces';
import {Injectable} from 'angular2/di'; import {Injectable} from 'angular2/di';
import {List} from 'angular2/src/facade/collection';
/** /**
* Structural diffing for `Object`s and `Map`s. * Structural diffing for `Object`s and `Map`s.
@ -61,8 +65,9 @@ export class DynamicChangeDetection extends ChangeDetection {
this.registry = registry; this.registry = registry;
} }
createProtoChangeDetector(name:string, changeControlStrategy:string = DEFAULT):ProtoChangeDetector{ createProtoChangeDetector(name:string, bindingRecords:List<BindingRecord>, variableBindings:List<string>,
return new DynamicProtoChangeDetector(this.registry, changeControlStrategy); 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; this.registry = registry;
} }
createProtoChangeDetector(name:string, changeControlStrategy:string = DEFAULT):ProtoChangeDetector{ createProtoChangeDetector(name:string, bindingRecords:List<BindingRecord>, variableBindings:List<string>,
return new JitProtoChangeDetector(this.registry, changeControlStrategy); directiveRecords:List<DirectiveRecord>, changeControlStrategy:string = DEFAULT):ProtoChangeDetector{
return new JitProtoChangeDetector(this.registry, bindingRecords, variableBindings, directiveRecords, changeControlStrategy);
} }
} }

View File

@ -4,7 +4,7 @@ import {DEFAULT} from './constants';
import {BindingRecord} from './binding_record'; import {BindingRecord} from './binding_record';
export class ProtoChangeDetector { export class ProtoChangeDetector {
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List, directiveRecords:List):ChangeDetector{ instantiate(dispatcher:any):ChangeDetector{
return null; return null;
} }
} }
@ -33,7 +33,8 @@ export class ProtoChangeDetector {
* @exportedAs angular2/change_detection * @exportedAs angular2/change_detection
*/ */
export class ChangeDetection { 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; return null;
} }
} }

View File

@ -28,7 +28,7 @@ import {DynamicChangeDetector} from './dynamic_change_detector';
import {ChangeDetectorJITGenerator} from './change_detection_jit_generator'; import {ChangeDetectorJITGenerator} from './change_detection_jit_generator';
import {PipeRegistry} from './pipes/pipe_registry'; import {PipeRegistry} from './pipes/pipe_registry';
import {BindingRecord} from './binding_record'; import {BindingRecord} from './binding_record';
import {DirectiveIndex} from './directive_record'; import {DirectiveRecord, DirectiveIndex} from './directive_record';
import {coalesce} from './coalesce'; import {coalesce} from './coalesce';
@ -50,25 +50,31 @@ import {
export class DynamicProtoChangeDetector extends ProtoChangeDetector { export class DynamicProtoChangeDetector extends ProtoChangeDetector {
_pipeRegistry:PipeRegistry; _pipeRegistry:PipeRegistry;
_records:List<ProtoRecord>; _records:List<ProtoRecord>;
_bindingRecords:List<BindingRecord>;
_variableBindings:List<string>;
_directiveRecords:List<DirectiveRecord>;
_changeControlStrategy:string; _changeControlStrategy:string;
constructor(pipeRegistry:PipeRegistry, changeControlStrategy:string) { constructor(pipeRegistry:PipeRegistry, bindingRecords:List, variableBindings:List, directiveRecords:List, changeControlStrategy:string) {
super(); super();
this._pipeRegistry = pipeRegistry; this._pipeRegistry = pipeRegistry;
this._bindingRecords = bindingRecords;
this._variableBindings = variableBindings;
this._directiveRecords = directiveRecords;
this._changeControlStrategy = changeControlStrategy; this._changeControlStrategy = changeControlStrategy;
} }
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List, directiveRecords:List) { instantiate(dispatcher:any) {
this._createRecordsIfNecessary(bindingRecords, variableBindings); this._createRecordsIfNecessary();
return new DynamicChangeDetector(this._changeControlStrategy, dispatcher, 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)) { if (isBlank(this._records)) {
var recordBuilder = new ProtoRecordBuilder(); var recordBuilder = new ProtoRecordBuilder();
ListWrapper.forEach(bindingRecords, (b) => { ListWrapper.forEach(this._bindingRecords, (b) => {
recordBuilder.addAst(b, variableBindings); recordBuilder.addAst(b, this._variableBindings);
}); });
this._records = coalesce(recordBuilder.records); this._records = coalesce(recordBuilder.records);
} }
@ -79,31 +85,37 @@ var _jitProtoChangeDetectorClassCounter:number = 0;
export class JitProtoChangeDetector extends ProtoChangeDetector { export class JitProtoChangeDetector extends ProtoChangeDetector {
_factory:Function; _factory:Function;
_pipeRegistry; _pipeRegistry;
_bindingRecords:List<BindingRecord>;
_variableBindings:List<string>;
_directiveRecords:List<DirectiveRecord>;
_changeControlStrategy:string; _changeControlStrategy:string;
constructor(pipeRegistry, changeControlStrategy:string) { constructor(pipeRegistry, bindingRecords:List, variableBindings:List, directiveRecords:List, changeControlStrategy:string) {
super(); super();
this._pipeRegistry = pipeRegistry; this._pipeRegistry = pipeRegistry;
this._factory = null; this._factory = null;
this._bindingRecords = bindingRecords;
this._variableBindings = variableBindings;
this._directiveRecords = directiveRecords;
this._changeControlStrategy = changeControlStrategy; this._changeControlStrategy = changeControlStrategy;
} }
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List, directiveRecords:List) { instantiate(dispatcher:any) {
this._createFactoryIfNecessary(bindingRecords, variableBindings, directiveRecords); this._createFactoryIfNecessary();
return this._factory(dispatcher, this._pipeRegistry); return this._factory(dispatcher, this._pipeRegistry);
} }
_createFactoryIfNecessary(bindingRecords:List, variableBindings:List, directiveRecords:List) { _createFactoryIfNecessary() {
if (isBlank(this._factory)) { if (isBlank(this._factory)) {
var recordBuilder = new ProtoRecordBuilder(); var recordBuilder = new ProtoRecordBuilder();
ListWrapper.forEach(bindingRecords, (b) => { ListWrapper.forEach(this._bindingRecords, (b) => {
recordBuilder.addAst(b, variableBindings); recordBuilder.addAst(b, this._variableBindings);
}); });
var c = _jitProtoChangeDetectorClassCounter++; var c = _jitProtoChangeDetectorClassCounter++;
var records = coalesce(recordBuilder.records); var records = coalesce(recordBuilder.records);
var typeName = `ChangeDetector${c}`; var typeName = `ChangeDetector${c}`;
this._factory = new ChangeDetectorJITGenerator(typeName, this._changeControlStrategy, records, this._factory = new ChangeDetectorJITGenerator(typeName, this._changeControlStrategy, records,
directiveRecords).generate(); this._directiveRecords).generate();
} }
} }
} }

View File

@ -94,7 +94,7 @@ export class Compiler {
var directiveMetadata = Compiler.buildRenderDirective(componentBinding); var directiveMetadata = Compiler.buildRenderDirective(componentBinding);
return this._renderer.createHostProtoView(directiveMetadata).then( (hostRenderPv) => { return this._renderer.createHostProtoView(directiveMetadata).then( (hostRenderPv) => {
return this._compileNestedProtoViews(null, hostRenderPv, [componentBinding], true); return this._compileNestedProtoViews(null, null, hostRenderPv, [componentBinding], true);
}).then( (appProtoView) => { }).then( (appProtoView) => {
return new ProtoViewRef(appProtoView); return new ProtoViewRef(appProtoView);
}); });
@ -135,7 +135,7 @@ export class Compiler {
if (isPresent(template.renderer)) { if (isPresent(template.renderer)) {
var directives = []; var directives = [];
pvPromise = this._renderer.createImperativeComponentProtoView(template.renderer).then( (renderPv) => { pvPromise = this._renderer.createImperativeComponentProtoView(template.renderer).then( (renderPv) => {
return this._compileNestedProtoViews(componentBinding, renderPv, directives, true); return this._compileNestedProtoViews(null, componentBinding, renderPv, directives, true);
}); });
} else { } else {
var directives = ListWrapper.map( var directives = ListWrapper.map(
@ -144,7 +144,7 @@ export class Compiler {
); );
var renderTemplate = this._buildRenderTemplate(component, template, directives); var renderTemplate = this._buildRenderTemplate(component, template, directives);
pvPromise = this._renderer.compile(renderTemplate).then( (renderPv) => { 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> // TODO(tbosch): union type return AppProtoView or Promise<AppProtoView>
_compileNestedProtoViews(componentBinding, renderPv, directives, isComponentRootView) { _compileNestedProtoViews(parentProtoView, componentBinding, renderPv, directives, isComponentRootView) {
var nestedPVPromises = []; var nestedPVPromises = [];
var protoView = this._protoViewFactory.createProtoView(componentBinding, renderPv, directives); var protoView = this._protoViewFactory.createProtoView(parentProtoView, componentBinding, renderPv, directives);
if (isComponentRootView && isPresent(componentBinding)) { if (isComponentRootView && isPresent(componentBinding)) {
// Populate the cache before compiling the nested components, // Populate the cache before compiling the nested components,
// so that components can reference themselves in their template. // so that components can reference themselves in their template.
@ -170,15 +170,12 @@ export class Compiler {
var nestedRenderProtoView = renderPv.elementBinders[binderIndex].nestedProtoView; var nestedRenderProtoView = renderPv.elementBinders[binderIndex].nestedProtoView;
var elementBinderDone = (nestedPv) => { var elementBinderDone = (nestedPv) => {
elementBinder.nestedProtoView = 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; var nestedCall = null;
if (isPresent(nestedComponent)) { if (isPresent(nestedComponent)) {
nestedCall = this._compile(nestedComponent); nestedCall = this._compile(nestedComponent);
} else if (isPresent(nestedRenderProtoView)) { } else if (isPresent(nestedRenderProtoView)) {
nestedCall = this._compileNestedProtoViews(componentBinding, nestedRenderProtoView, directives, false); nestedCall = this._compileNestedProtoViews(protoView, componentBinding, nestedRenderProtoView, directives, false);
} }
if (PromiseWrapper.isPromise(nestedCall)) { if (PromiseWrapper.isPromise(nestedCall)) {
ListWrapper.push(nestedPVPromises, nestedCall.then(elementBinderDone)); ListWrapper.push(nestedPVPromises, nestedCall.then(elementBinderDone));

View File

@ -3,13 +3,103 @@ import {List, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {isPresent, isBlank} from 'angular2/src/facade/lang'; import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {reflector} from 'angular2/src/reflection/reflection'; 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 {Component} from '../annotations_impl/annotations';
import * as renderApi from 'angular2/src/render/api'; import * as renderApi from 'angular2/src/render/api';
import {AppProtoView} from './view'; import {AppProtoView} from './view';
import {ProtoElementInjector, DirectiveBinding} from './element_injector'; 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() @Injectable()
export class ProtoViewFactory { export class ProtoViewFactory {
_changeDetection:ChangeDetection; _changeDetection:ChangeDetection;
@ -18,40 +108,85 @@ export class ProtoViewFactory {
this._changeDetection = changeDetection; this._changeDetection = changeDetection;
} }
createProtoView(componentBinding:DirectiveBinding, renderProtoView: renderApi.ProtoViewDto, createProtoView(parentProtoView:AppProtoView, componentBinding:DirectiveBinding,
directives:List<DirectiveBinding>):AppProtoView { renderProtoView: renderApi.ProtoViewDto, directives:List<DirectiveBinding>):AppProtoView {
var protoChangeDetector;
if (isBlank(componentBinding)) { var elementBinders = renderProtoView.elementBinders;
protoChangeDetector = this._changeDetection.createProtoChangeDetector('root', null); var sortedDirectives = ListWrapper.map(elementBinders, b => new SortedDirectives(b.directives, directives));
} else {
var componentAnnotation:Component = componentBinding.annotation; var variableBindings = this._createVariableBindings(renderProtoView);
protoChangeDetector = this._changeDetection.createProtoChangeDetector( var protoLocals = this._createProtoLocals(renderProtoView);
'dummy', componentAnnotation.changeDetection var variableNames = this._createVariableNames(parentProtoView, protoLocals);
); var protoChangeDetector = this._createProtoChangeDetector(elementBinders, sortedDirectives, componentBinding, variableNames);
} var protoView = new AppProtoView(renderProtoView.render, protoChangeDetector, variableBindings, protoLocals, variableNames);
var protoView = new AppProtoView(renderProtoView.render, protoChangeDetector);
// 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; 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) { _findParentProtoElementInjectorWithDistance(binderIndex, elementBinders, renderElementBinders) {
var distance = 0; var distance = 0;
do { do {
@ -95,7 +230,7 @@ export class ProtoViewFactory {
return protoElementInjector; return protoElementInjector;
} }
_createElementBinder(protoView, renderElementBinder, protoElementInjector, sortedDirectives) { _createElementBinder(protoView, boundElementIndex, renderElementBinder, protoElementInjector, sortedDirectives) {
var parent = null; var parent = null;
if (renderElementBinder.parentIndex !== -1) { if (renderElementBinder.parentIndex !== -1) {
parent = protoView.elementBinders[renderElementBinder.parentIndex]; parent = protoView.elementBinders[renderElementBinder.parentIndex];
@ -106,16 +241,7 @@ export class ProtoViewFactory {
protoElementInjector, protoElementInjector,
sortedDirectives.componentDirective sortedDirectives.componentDirective
); );
// text nodes protoView.bindEvent(renderElementBinder.eventBindings, boundElementIndex, -1);
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);
// variables // variables
// The view's locals needs to have a full set of variable names at construction time // 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 // 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; return elBinder;
} }
_createDirectiveBinders(protoView, boundElementIndex, sortedDirectives) { _bindDirectiveEvents(protoView, sortedDirectives:List<SortedDirectives>) {
for (var i = 0; i < sortedDirectives.renderDirectives.length; i++) { for (var boundElementIndex = 0; boundElementIndex < sortedDirectives.length; ++boundElementIndex) {
var directiveBinder = sortedDirectives.renderDirectives[i]; var dirs = sortedDirectives[boundElementIndex].renderDirectives;
for (var i = 0; i < dirs.length; i++) {
var directiveBinder = dirs[i];
// directive properties // directive events
MapWrapper.forEach(directiveBinder.propertyBindings, (astWithSource, propertyName) => { protoView.bindEvent(directiveBinder.eventBindings, boundElementIndex, i);
// 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);
} }
} }
} }

View File

@ -4,7 +4,6 @@ import {AST, Locals, ChangeDispatcher, ProtoChangeDetector, ChangeDetector,
import {ProtoElementInjector, ElementInjector, PreBuiltObjects, DirectiveBinding} from './element_injector'; import {ProtoElementInjector, ElementInjector, PreBuiltObjects, DirectiveBinding} from './element_injector';
import {ElementBinder} from './element_binder'; import {ElementBinder} from './element_binder';
import {SetterFn} from 'angular2/src/reflection/types';
import {IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang'; import {IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
import * as renderApi from 'angular2/src/render/api'; import * as renderApi from 'angular2/src/render/api';
@ -164,74 +163,22 @@ export class AppProtoView {
protoChangeDetector:ProtoChangeDetector; protoChangeDetector:ProtoChangeDetector;
variableBindings: Map; variableBindings: Map;
protoLocals:Map; protoLocals:Map;
textNodesWithBindingCount:int;
bindings:List; bindings:List;
parentProtoView:AppProtoView; variableNames:List;
_variableBindings:List;
_directiveRecordsMap:Map;
_directiveRecords:List;
render:renderApi.RenderProtoViewRef; render:renderApi.RenderProtoViewRef;
constructor( constructor(
render:renderApi.RenderProtoViewRef, render:renderApi.RenderProtoViewRef,
protoChangeDetector:ProtoChangeDetector) { protoChangeDetector:ProtoChangeDetector,
variableBindings:Map,
protoLocals:Map,
variableNames:List) {
this.render = render; this.render = render;
this.elementBinders = []; this.elementBinders = [];
this.variableBindings = MapWrapper.create(); this.variableBindings = variableBindings;
this.protoLocals = MapWrapper.create(); this.protoLocals = protoLocals;
this.variableNames = variableNames;
this.protoChangeDetector = protoChangeDetector; 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, bindElement(parent:ElementBinder, distanceToParent:int, protoElementInjector:ProtoElementInjector,
@ -242,32 +189,6 @@ export class AppProtoView {
return elBinder; 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. * 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 * @param {int} directiveIndex The directive index in the binder or -1 when the event is not bound
* to a directive * to a directive
*/ */
bindEvent(eventBindings: List<renderApi.EventBinding>, directiveIndex: int = -1): void { bindEvent(eventBindings: List<renderApi.EventBinding>, boundElementIndex:number, directiveIndex: int = -1): void {
var elBinder = this.elementBinders[this.elementBinders.length - 1]; var elBinder = this.elementBinders[boundElementIndex];
var events = elBinder.hostListeners; var events = elBinder.hostListeners;
if (isBlank(events)) { if (isBlank(events)) {
events = StringMapWrapper.create(); events = StringMapWrapper.create();
@ -299,35 +220,4 @@ export class AppProtoView {
MapWrapper.set(event, directiveIndex, eventBinding.source); 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);
}
} }

View File

@ -28,8 +28,7 @@ export class AppViewManagerUtils {
createView(protoView:viewModule.AppProtoView, viewManager:avmModule.AppViewManager, renderer:Renderer): viewModule.AppView { createView(protoView:viewModule.AppProtoView, viewManager:avmModule.AppViewManager, renderer:Renderer): viewModule.AppView {
var view = new viewModule.AppView(renderer, protoView, protoView.protoLocals); var view = new viewModule.AppView(renderer, protoView, protoView.protoLocals);
var changeDetector = protoView.protoChangeDetector.instantiate(view, protoView.bindings, var changeDetector = protoView.protoChangeDetector.instantiate(view);
protoView.getVariableBindings(), protoView.getdirectiveRecords());
var binders = protoView.elementBinders; var binders = protoView.elementBinders;
var elementInjectors = ListWrapper.createFixedSize(binders.length); var elementInjectors = ListWrapper.createFixedSize(binders.length);

View File

@ -16,8 +16,22 @@ import {JitProtoChangeDetector, DynamicProtoChangeDetector} from 'angular2/src/c
export function main() { export function main() {
describe("change detection", () => { describe("change detection", () => {
StringMapWrapper.forEach( StringMapWrapper.forEach(
{ "dynamic": (registry = null, strategy = null) => new DynamicProtoChangeDetector(registry, strategy), { "dynamic": (bindingRecords, variableBindings = null, directiveRecords = null, registry = null, strategy = null) =>
"JIT": (registry = null, strategy = null) => new JitProtoChangeDetector(registry, strategy) new DynamicProtoChangeDetector(
registry,
isBlank(bindingRecords) ? [] : bindingRecords,
isBlank(variableBindings) ? [] : variableBindings,
isBlank(directiveRecords) ? [] : directiveRecords,
strategy),
"JIT": (bindingRecords, variableBindings = null, directiveRecords = null, registry = null, strategy = null) =>
new JitProtoChangeDetector(
registry,
isBlank(bindingRecords) ? [] : bindingRecords,
isBlank(variableBindings) ? [] : variableBindings,
isBlank(directiveRecords) ? [] : directiveRecords,
strategy)
}, (createProtoChangeDetector, name) => { }, (createProtoChangeDetector, name) => {
if (name == "JIT" && IS_DARTIUM) return; if (name == "JIT" && IS_DARTIUM) return;
@ -43,13 +57,13 @@ export function main() {
} }
function createChangeDetector(propName:string, exp:string, context = null, locals = null, registry = null) { function createChangeDetector(propName:string, exp:string, context = null, locals = null, registry = null) {
var pcd = createProtoChangeDetector(registry);
var dispatcher = new TestDispatcher(); var dispatcher = new TestDispatcher();
var variableBindings = convertLocalsToVariableBindings(locals); var variableBindings = convertLocalsToVariableBindings(locals);
var records = [BindingRecord.createForElement(ast(exp), 0, propName)]; var records = [BindingRecord.createForElement(ast(exp), 0, propName)];
var cd = pcd.instantiate(dispatcher, records, variableBindings, []); var pcd = createProtoChangeDetector(records, variableBindings, [], registry);
var cd = pcd.instantiate(dispatcher);
cd.hydrate(context, locals, null); cd.hydrate(context, locals, null);
return {"changeDetector" : cd, "dispatcher" : dispatcher}; return {"changeDetector" : cd, "dispatcher" : dispatcher};
@ -61,11 +75,6 @@ export function main() {
return res["dispatcher"].log; return res["dispatcher"].log;
} }
function instantiate(protoChangeDetector, dispatcher, bindings, directiveRecords = null) {
if (isBlank(directiveRecords)) directiveRecords = [];
return protoChangeDetector.instantiate(dispatcher, bindings, null, directiveRecords);
}
describe(`${name} change detection`, () => { describe(`${name} change detection`, () => {
var dispatcher; var dispatcher;
@ -205,10 +214,10 @@ export function main() {
}); });
it("should support interpolation", () => { it("should support interpolation", () => {
var pcd = createProtoChangeDetector();
var ast = parser.parseInterpolation("B{{a}}A", "location"); var ast = parser.parseInterpolation("B{{a}}A", "location");
var pcd = createProtoChangeDetector([BindingRecord.createForElement(ast, 0, "memo")]);
var cd = instantiate(pcd, dispatcher, [BindingRecord.createForElement(ast, 0, "memo")]); var cd = pcd.instantiate(dispatcher);
cd.hydrate(new TestData("value"), null, null); cd.hydrate(new TestData("value"), null, null);
cd.detectChanges(); cd.detectChanges();
@ -267,10 +276,9 @@ export function main() {
}); });
it("should happen directly, without invoking the dispatcher", () => { it("should happen directly, without invoking the dispatcher", () => {
var pcd = createProtoChangeDetector(); var pcd = createProtoChangeDetector([updateA("42", dirRecord1)], [], [dirRecord1]);
var cd = instantiate(pcd, dispatcher, [updateA("42", dirRecord1)], var cd = pcd.instantiate(dispatcher);
[dirRecord1]);
cd.hydrate(null, null, dirs([directive1])); cd.hydrate(null, null, dirs([directive1]));
@ -282,13 +290,13 @@ export function main() {
describe("onChange", () => { describe("onChange", () => {
it("should notify the directive when a group of records changes", () => { it("should notify the directive when a group of records changes", () => {
var pcd = createProtoChangeDetector(); var pcd = createProtoChangeDetector([
var cd = instantiate(pcd, dispatcher, [
updateA("1", dirRecord1), updateA("1", dirRecord1),
updateB("2", dirRecord1), updateB("2", dirRecord1),
updateA("3", dirRecord2) updateA("3", dirRecord2)
], [dirRecord1, dirRecord2]); ], [], [dirRecord1, dirRecord2]);
var cd = pcd.instantiate(dispatcher);
cd.hydrate(null, null, dirs([directive1, directive2])); cd.hydrate(null, null, dirs([directive1, directive2]));
@ -299,11 +307,11 @@ export function main() {
}); });
it("should not call onChange when callOnChange is false", () => { it("should not call onChange when callOnChange is false", () => {
var pcd = createProtoChangeDetector(); var pcd = createProtoChangeDetector([
var cd = instantiate(pcd, dispatcher, [
updateA("1", dirRecordNoCallbacks) updateA("1", dirRecordNoCallbacks)
], [dirRecordNoCallbacks]); ], [], [dirRecordNoCallbacks]);
var cd = pcd.instantiate(dispatcher);
cd.hydrate(null, null, dirs([directive1])); cd.hydrate(null, null, dirs([directive1]));
@ -315,9 +323,9 @@ export function main() {
describe("onAllChangesDone", () => { describe("onAllChangesDone", () => {
it("should be called after processing all the children", () => { it("should be called after processing all the children", () => {
var pcd = createProtoChangeDetector(); var pcd = createProtoChangeDetector([], [], [dirRecord1, dirRecord2]);
var cd = instantiate(pcd, dispatcher, [], [dirRecord1, dirRecord2]); var cd = pcd.instantiate(dispatcher);
cd.hydrate(null, null, dirs([directive1, directive2])); cd.hydrate(null, null, dirs([directive1, directive2]));
cd.detectChanges(); cd.detectChanges();
@ -328,11 +336,11 @@ export function main() {
it("should not be called when onAllChangesDone is false", () => { it("should not be called when onAllChangesDone is false", () => {
var pcd = createProtoChangeDetector(); var pcd = createProtoChangeDetector([
var cd = instantiate(pcd, dispatcher, [
updateA("1", dirRecordNoCallbacks) updateA("1", dirRecordNoCallbacks)
], [dirRecordNoCallbacks]); ], [], [dirRecordNoCallbacks]);
var cd = pcd.instantiate(dispatcher);
cd.hydrate(null, null, dirs([directive1])); cd.hydrate(null, null, dirs([directive1]));
@ -342,8 +350,8 @@ export function main() {
}); });
it("should be called in reverse order so the child is always notified before the parent", () => { it("should be called in reverse order so the child is always notified before the parent", () => {
var pcd = createProtoChangeDetector(); var pcd = createProtoChangeDetector([], [], [dirRecord1, dirRecord2]);
var cd = instantiate(pcd, dispatcher, [], [dirRecord1, dirRecord2]); var cd = pcd.instantiate(dispatcher);
var onChangesDoneCalls = []; var onChangesDoneCalls = [];
var td1; var td1;
@ -358,13 +366,12 @@ export function main() {
}); });
it("should be called before processing shadow dom children", () => { it("should be called before processing shadow dom children", () => {
var pcd = createProtoChangeDetector(); var pcd = createProtoChangeDetector([], null, [dirRecord1]);
var shadowDomChildPCD = createProtoChangeDetector(); var shadowDomChildPCD = createProtoChangeDetector([updateA("1", dirRecord1)], null, [dirRecord1]);
var parent = pcd.instantiate(dispatcher, [], null, [dirRecord1]); var parent = pcd.instantiate(dispatcher);
var child = shadowDomChildPCD.instantiate(dispatcher, var child = shadowDomChildPCD.instantiate(dispatcher);
[updateA("1", dirRecord1)], null, [dirRecord1]);
parent.addShadowDomChild(child); parent.addShadowDomChild(child);
var directiveInShadowDom = new TestDirective(); var directiveInShadowDom = new TestDirective();
@ -389,8 +396,8 @@ export function main() {
var directive = new TestDirective(); var directive = new TestDirective();
directive.a = "aaa"; directive.a = "aaa";
var pcd = createProtoChangeDetector(); var pcd = createProtoChangeDetector([BindingRecord.createForHostProperty(index, ast("a"), "prop")], null, [dirRecord]);
var cd = instantiate(pcd, dispatcher, [BindingRecord.createForHostProperty(index, ast("a"), "prop")], [dirRecord]); var cd = pcd.instantiate(dispatcher);
cd.hydrate(null, null, dirs([directive])); cd.hydrate(null, null, dirs([directive]));
cd.detectChanges(); cd.detectChanges();
@ -401,12 +408,12 @@ export function main() {
describe("enforce no new changes", () => { describe("enforce no new changes", () => {
it("should throw when a record gets changed after it has been checked", () => { it("should throw when a record gets changed after it has been checked", () => {
var pcd = createProtoChangeDetector(); var pcd = createProtoChangeDetector([
var dispatcher = new TestDispatcher();
var cd = instantiate(pcd, dispatcher, [
BindingRecord.createForElement(ast("a"), 0, "a") BindingRecord.createForElement(ast("a"), 0, "a")
]); ]);
var dispatcher = new TestDispatcher();
var cd = pcd.instantiate(dispatcher);
cd.hydrate(new TestData('value'), null, null); cd.hydrate(new TestData('value'), null, null);
expect(() => { expect(() => {
@ -487,11 +494,8 @@ export function main() {
var parent, child; var parent, child;
beforeEach(() => { beforeEach(() => {
var protoParent = createProtoChangeDetector(); parent = createProtoChangeDetector([]).instantiate(null);
parent = instantiate(protoParent, null, []); child = createProtoChangeDetector([]).instantiate(null);
var protoChild = createProtoChangeDetector();
child = instantiate(protoChild, null, []);
}); });
it("should add light dom children", () => { it("should add light dom children", () => {
@ -526,8 +530,8 @@ export function main() {
describe("mode", () => { describe("mode", () => {
it("should set the mode to CHECK_ALWAYS when the default change detection is used", () => { it("should set the mode to CHECK_ALWAYS when the default change detection is used", () => {
var proto = createProtoChangeDetector(null, DEFAULT); var proto = createProtoChangeDetector([], [], [], null, DEFAULT);
var cd = proto.instantiate(null, [], [], []); var cd = proto.instantiate(null);
expect(cd.mode).toEqual(null); expect(cd.mode).toEqual(null);
@ -537,8 +541,8 @@ export function main() {
}); });
it("should set the mode to CHECK_ONCE when the push change detection is used", () => { it("should set the mode to CHECK_ONCE when the push change detection is used", () => {
var proto = createProtoChangeDetector(null, ON_PUSH); var proto = createProtoChangeDetector([], [], [], null, ON_PUSH);
var cd = proto.instantiate(null, [], [], []); var cd = proto.instantiate(null);
cd.hydrate(null, null, null); cd.hydrate(null, null, null);
expect(cd.mode).toEqual(CHECK_ONCE); expect(cd.mode).toEqual(CHECK_ONCE);
@ -567,7 +571,7 @@ export function main() {
}); });
it("should change CHECK_ONCE to CHECKED", () => { it("should change CHECK_ONCE to CHECKED", () => {
var cd = instantiate(createProtoChangeDetector(), null, []); var cd = createProtoChangeDetector([]).instantiate(null);
cd.mode = CHECK_ONCE; cd.mode = CHECK_ONCE;
cd.detectChanges(); cd.detectChanges();
@ -576,7 +580,7 @@ export function main() {
}); });
it("should not change the CHECK_ALWAYS", () => { it("should not change the CHECK_ALWAYS", () => {
var cd = instantiate(createProtoChangeDetector(), null, []); var cd = createProtoChangeDetector([]).instantiate(null);
cd.mode = CHECK_ALWAYS; cd.mode = CHECK_ALWAYS;
cd.detectChanges(); cd.detectChanges();
@ -591,8 +595,8 @@ export function main() {
var directives; var directives;
beforeEach(() => { beforeEach(() => {
var proto = createProtoChangeDetector(null, ON_PUSH); var proto = createProtoChangeDetector([], [], [], null, ON_PUSH);
checkedDetector = instantiate(proto, null, [], []); checkedDetector = proto.instantiate(null);
checkedDetector.hydrate(null, null, null); checkedDetector.hydrate(null, null, null);
checkedDetector.mode = CHECKED; checkedDetector.mode = CHECKED;
@ -608,9 +612,9 @@ export function main() {
}); });
it("should set the mode to CHECK_ONCE when a binding is updated", () => { it("should set the mode to CHECK_ONCE when a binding is updated", () => {
var proto = createProtoChangeDetector(null); var proto = createProtoChangeDetector([updateDirWithOnPushRecord], [], [dirRecordWithOnPush]);
var cd = instantiate(proto, null, [updateDirWithOnPushRecord], [dirRecordWithOnPush]); var cd = proto.instantiate(null);
cd.hydrate(null, null, directives); cd.hydrate(null, null, directives);
expect(checkedDetector.mode).toEqual(CHECKED); expect(checkedDetector.mode).toEqual(CHECKED);
@ -625,7 +629,7 @@ export function main() {
describe("markPathToRootAsCheckOnce", () => { describe("markPathToRootAsCheckOnce", () => {
function changeDetector(mode, parent) { function changeDetector(mode, parent) {
var cd = instantiate(createProtoChangeDetector(), null, []); var cd = createProtoChangeDetector([]).instantiate(null);
cd.mode = mode; cd.mode = mode;
if (isPresent(parent)) parent.addChild(cd); if (isPresent(parent)) parent.addChild(cd);
return cd; return cd;

View File

@ -283,9 +283,6 @@ export function main() {
compiler.compile(MainComponent).then( (protoViewRef) => { compiler.compile(MainComponent).then( (protoViewRef) => {
expect(internalProtoView(protoViewRef)).toBe(mainProtoView); expect(internalProtoView(protoViewRef)).toBe(mainProtoView);
expect(mainProtoView.elementBinders[0].nestedProtoView).toBe(nestedProtoView); expect(mainProtoView.elementBinders[0].nestedProtoView).toBe(nestedProtoView);
// parentProtoView of nested components has to be null as components can
// be used by multiple other components.
expect(nestedProtoView.parentProtoView).toBe(null);
async.done(); async.done();
}); });
})); }));
@ -316,11 +313,7 @@ export function main() {
compiler.compile(MainComponent).then( (protoViewRef) => { compiler.compile(MainComponent).then( (protoViewRef) => {
expect(internalProtoView(protoViewRef)).toBe(mainProtoView); expect(internalProtoView(protoViewRef)).toBe(mainProtoView);
expect(mainProtoView.elementBinders[0].nestedProtoView).toBe(viewportProtoView); expect(mainProtoView.elementBinders[0].nestedProtoView).toBe(viewportProtoView);
expect(viewportProtoView.parentProtoView).toBe(mainProtoView);
expect(viewportProtoView.elementBinders[0].nestedProtoView).toBe(nestedProtoView); expect(viewportProtoView.elementBinders[0].nestedProtoView).toBe(nestedProtoView);
// parentProtoView of nested components has to be null as components can
// be used by multiple other components.
expect(nestedProtoView.parentProtoView).toBe(null);
async.done(); async.done();
}); });
@ -432,7 +425,7 @@ function createDirectiveBinding(reader, type) {
} }
function createProtoView(elementBinders = null) { function createProtoView(elementBinders = null) {
var pv = new AppProtoView(null, null); var pv = new AppProtoView(null, null, null, null, null);
if (isBlank(elementBinders)) { if (isBlank(elementBinders)) {
elementBinders = []; elementBinders = [];
} }
@ -575,7 +568,7 @@ class FakeProtoViewFactory extends ProtoViewFactory {
this._results = results; this._results = results;
} }
createProtoView(componentBinding:DirectiveBinding, renderProtoView: renderApi.ProtoViewDto, createProtoView(parentProtoView, componentBinding:DirectiveBinding, renderProtoView: renderApi.ProtoViewDto,
directives:List<DirectiveBinding>):AppProtoView { directives:List<DirectiveBinding>):AppProtoView {
ListWrapper.push(this.requests, [componentBinding, renderProtoView, directives]); ListWrapper.push(this.requests, [componentBinding, renderProtoView, directives]);
return ListWrapper.removeAt(this._results, 0); return ListWrapper.removeAt(this._results, 0);

View File

@ -453,7 +453,7 @@ export function main() {
}); });
it("should instantiate directives that depend on pre built objects", function () { it("should instantiate directives that depend on pre built objects", function () {
var protoView = new AppProtoView(null, null); var protoView = new AppProtoView(null, null, null, null, null);
var inj = injector([NeedsProtoViewRef], null, null, new PreBuiltObjects(null, null, protoView)); var inj = injector([NeedsProtoViewRef], null, null, new PreBuiltObjects(null, null, protoView));
expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView)); expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView));
@ -700,7 +700,7 @@ export function main() {
}); });
it("should inject ProtoViewRef", function () { it("should inject ProtoViewRef", function () {
var protoView = new AppProtoView(null, null); var protoView = new AppProtoView(null, null, null, null, null);
var inj = injector([NeedsProtoViewRef], null, null, new PreBuiltObjects(null, null, protoView)); var inj = injector([NeedsProtoViewRef], null, null, new PreBuiltObjects(null, null, protoView));
expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView)); expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView));

View File

@ -14,6 +14,7 @@ import {
xit xit
} from 'angular2/test_lib'; } from 'angular2/test_lib';
import {TestBed} from 'angular2/src/test_lib/test_bed'; import {TestBed} from 'angular2/src/test_lib/test_bed';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
@ -46,6 +47,7 @@ export function main() {
ctx = new MyComp(); ctx = new MyComp();
}); });
describe('react to record changes', function() { describe('react to record changes', function() {
it('should consume text node changes', inject([TestBed, AsyncTestCompleter], (tb, async) => { it('should consume text node changes', inject([TestBed, AsyncTestCompleter], (tb, async) => {
tb.overrideView(MyComp, new View({template: '<div>{{ctxProp}}</div>'})); tb.overrideView(MyComp, new View({template: '<div>{{ctxProp}}</div>'}));

View File

@ -37,7 +37,7 @@ export function main() {
} }
function createProtoView() { function createProtoView() {
return new AppProtoView(null, null); return new AppProtoView(null, null, null, null, null);
} }
function createView() { function createView() {

View File

@ -80,7 +80,7 @@ export function main() {
staticChildComponentCount++; staticChildComponentCount++;
} }
} }
var res = new AppProtoView(new MockProtoViewRef(staticChildComponentCount), null); var res = new AppProtoView(new MockProtoViewRef(staticChildComponentCount), null, null, null, null);
res.elementBinders = binders; res.elementBinders = binders;
return res; return res;
} }

View File

@ -60,7 +60,7 @@ export function main() {
if (isBlank(binders)) { if (isBlank(binders)) {
binders = []; binders = [];
} }
var res = new AppProtoView(null, null); var res = new AppProtoView(null, null, null, null, null);
res.elementBinders = binders; res.elementBinders = binders;
return res; return res;
} }

View File

@ -26,7 +26,7 @@ export function main() {
} }
function createProtoView() { function createProtoView() {
return new AppProtoView(null, null); return new AppProtoView(null, null, null, null, null);
} }
function createView(pv) { function createView(pv) {

View File

@ -187,10 +187,8 @@ function setUpChangeDetection(changeDetection:ChangeDetection, iterations, objec
var dispatcher = new DummyDispatcher(); var dispatcher = new DummyDispatcher();
var parser = new Parser(new Lexer()); var parser = new Parser(new Lexer());
var parentProto = changeDetection.createProtoChangeDetector('parent'); var parentProto = changeDetection.createProtoChangeDetector('parent', [], [], []);
var parentCd = parentProto.instantiate(dispatcher, [], [], []); var parentCd = parentProto.instantiate(dispatcher);
var proto = changeDetection.createProtoChangeDetector("proto");
var directiveRecord = new DirectiveRecord(new DirectiveIndex(0, 0), false, false, DEFAULT); var directiveRecord = new DirectiveRecord(new DirectiveIndex(0, 0), false, false, DEFAULT);
var bindings = [ var bindings = [
@ -206,9 +204,11 @@ function setUpChangeDetection(changeDetection:ChangeDetection, iterations, objec
BindingRecord.createForDirective(parser.parseBinding('field9', null), "field9", reflector.setter("field9"), directiveRecord) BindingRecord.createForDirective(parser.parseBinding('field9', null), "field9", reflector.setter("field9"), directiveRecord)
]; ];
var proto = changeDetection.createProtoChangeDetector("proto", bindings, [], [directiveRecord]);
var targetObj = new Obj(); var targetObj = new Obj();
for (var i = 0; i < iterations; ++i) { for (var i = 0; i < iterations; ++i) {
var cd = proto.instantiate(dispatcher, bindings, [], [directiveRecord]); var cd = proto.instantiate(dispatcher);
cd.hydrate(object, null, new FakeDirectives(targetObj)); cd.hydrate(object, null, new FakeDirectives(targetObj));
parentCd.addChild(cd); parentCd.addChild(cd);
} }