feat(change_detection): reimplement change detection
This commit is contained in:
@ -4,7 +4,7 @@ import {DOM, Element} from 'facade/dom';
|
||||
import {Compiler, CompilerCache} from './compiler/compiler';
|
||||
import {ProtoView} from './compiler/view';
|
||||
import {Reflector, reflector} from 'reflection/reflection';
|
||||
import {Parser, Lexer, ChangeDetector, RecordRange} from 'change_detection/change_detection';
|
||||
import {Parser, Lexer, ChangeDetector} from 'change_detection/change_detection';
|
||||
import {TemplateLoader} from './compiler/template_loader';
|
||||
import {DirectiveMetadataReader} from './compiler/directive_metadata_reader';
|
||||
import {DirectiveMetadata} from './compiler/directive_metadata';
|
||||
@ -21,7 +21,7 @@ var _rootBindings = [
|
||||
];
|
||||
|
||||
export var appViewToken = new OpaqueToken('AppView');
|
||||
export var appRecordRangeToken = new OpaqueToken('AppRecordRange');
|
||||
export var appChangeDetectorToken = new OpaqueToken('AppChangeDetector');
|
||||
export var appElementToken = new OpaqueToken('AppElement');
|
||||
export var appComponentAnnotatedTypeToken = new OpaqueToken('AppComponentAnnotatedType');
|
||||
export var appDocumentToken = new OpaqueToken('AppDocument');
|
||||
@ -49,24 +49,22 @@ function _injectorBindings(appComponentType) {
|
||||
appComponentAnnotatedType) => {
|
||||
return compiler.compile(appComponentAnnotatedType.type, null).then(
|
||||
(protoView) => {
|
||||
var appProtoView = ProtoView.createRootProtoView(protoView,
|
||||
var appProtoView = ProtoView.createRootProtoView(protoView,
|
||||
appElement, appComponentAnnotatedType);
|
||||
// The light Dom of the app element is not considered part of
|
||||
// the angular application. Thus the context and lightDomInjector are
|
||||
// empty.
|
||||
var view = appProtoView.instantiate(null);
|
||||
view.hydrate(injector, null, new Object());
|
||||
var view = appProtoView.instantiate(null);
|
||||
view.hydrate(injector, null, new Object());
|
||||
return view;
|
||||
});
|
||||
}, [Compiler, Injector, appElementToken, appComponentAnnotatedTypeToken]),
|
||||
|
||||
bind(appRecordRangeToken).toFactory((rootView) => rootView.recordRange,
|
||||
bind(appChangeDetectorToken).toFactory((rootView) => rootView.changeDetector,
|
||||
[appViewToken]),
|
||||
bind(ChangeDetector).toFactory((appRecordRange) =>
|
||||
new ChangeDetector(appRecordRange, assertionsEnabled()), [appRecordRangeToken]),
|
||||
bind(appComponentType).toFactory((rootView) => rootView.elementInjectors[0].getComponent(),
|
||||
[appViewToken]),
|
||||
bind(LifeCycle).toClass(LifeCycle)
|
||||
bind(LifeCycle).toFactory((cd) => new LifeCycle(cd, assertionsEnabled()), [appChangeDetectorToken])
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ import {ElementBinder} from '../element_binder';
|
||||
import {ProtoElementInjector} from '../element_injector';
|
||||
import {ProtoView} from '../view';
|
||||
|
||||
import {ASTWithSource} from 'change_detection/change_detection';
|
||||
import {AST} from 'change_detection/change_detection';
|
||||
|
||||
/**
|
||||
* Collects all data that is needed to process an element
|
||||
@ -86,14 +86,14 @@ export class CompileElement {
|
||||
return this._classList;
|
||||
}
|
||||
|
||||
addTextNodeBinding(indexInParent:int, expression:ASTWithSource) {
|
||||
addTextNodeBinding(indexInParent:int, expression:AST) {
|
||||
if (isBlank(this.textNodeBindings)) {
|
||||
this.textNodeBindings = MapWrapper.create();
|
||||
}
|
||||
MapWrapper.set(this.textNodeBindings, indexInParent, expression);
|
||||
}
|
||||
|
||||
addPropertyBinding(property:string, expression:ASTWithSource) {
|
||||
addPropertyBinding(property:string, expression:AST) {
|
||||
if (isBlank(this.propertyBindings)) {
|
||||
this.propertyBindings = MapWrapper.create();
|
||||
}
|
||||
@ -107,7 +107,7 @@ export class CompileElement {
|
||||
MapWrapper.set(this.variableBindings, contextName, templateName);
|
||||
}
|
||||
|
||||
addEventBinding(eventName:string, expression:ASTWithSource) {
|
||||
addEventBinding(eventName:string, expression:AST) {
|
||||
if (isBlank(this.eventBindings)) {
|
||||
this.eventBindings = MapWrapper.create();
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import {ListWrapper, List, MapWrapper, StringMapWrapper} from 'facade/collection
|
||||
|
||||
import {reflector} from 'reflection/reflection';
|
||||
|
||||
import {Parser, ProtoRecordRange} from 'change_detection/change_detection';
|
||||
import {Parser, ProtoChangeDetector} from 'change_detection/change_detection';
|
||||
|
||||
import {Component, Directive} from '../../annotations/annotations';
|
||||
import {DirectiveMetadata} from '../directive_metadata';
|
||||
@ -18,7 +18,7 @@ import {CompileControl} from './compile_control';
|
||||
|
||||
/**
|
||||
* Creates the ElementBinders and adds watches to the
|
||||
* ProtoRecordRange.
|
||||
* ProtoChangeDetector.
|
||||
*
|
||||
* Fills:
|
||||
* - CompileElement#inheritedElementBinder
|
||||
|
@ -2,7 +2,7 @@ import {isPresent, BaseException} from 'facade/lang';
|
||||
import {ListWrapper, MapWrapper} from 'facade/collection';
|
||||
|
||||
import {ProtoView} from '../view';
|
||||
import {ProtoRecordRange} from 'change_detection/change_detection';
|
||||
import {ProtoChangeDetector} from 'change_detection/change_detection';
|
||||
|
||||
import {CompileStep} from './compile_step';
|
||||
import {CompileElement} from './compile_element';
|
||||
@ -21,7 +21,7 @@ export class ProtoViewBuilder extends CompileStep {
|
||||
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
|
||||
var inheritedProtoView = null;
|
||||
if (current.isViewRoot) {
|
||||
inheritedProtoView = new ProtoView(current.element, new ProtoRecordRange());
|
||||
inheritedProtoView = new ProtoView(current.element, new ProtoChangeDetector());
|
||||
if (isPresent(parent)) {
|
||||
if (isPresent(parent.inheritedElementBinder.nestedProtoView)) {
|
||||
throw new BaseException('Only one nested view per element is allowed');
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {DOM, Element, Node, Text, DocumentFragment, TemplateElement} from 'facade/dom';
|
||||
import {ListWrapper, MapWrapper, StringMapWrapper, List} from 'facade/collection';
|
||||
import {ProtoRecordRange, RecordRange, Record,
|
||||
ChangeDispatcher, AST, ContextWithVariableBindings} from 'change_detection/change_detection';
|
||||
import {AST, ContextWithVariableBindings, ChangeDispatcher, ProtoChangeDetector, ChangeDetector, ChangeRecord}
|
||||
from 'change_detection/change_detection';
|
||||
|
||||
import {ProtoElementInjector, ElementInjector, PreBuiltObjects} from './element_injector';
|
||||
import {ElementBinder} from './element_binder';
|
||||
@ -30,7 +30,7 @@ export class View {
|
||||
elementInjectors:List<ElementInjector>;
|
||||
bindElements:List<Element>;
|
||||
textNodes:List<Text>;
|
||||
recordRange:RecordRange;
|
||||
changeDetector:ChangeDetector;
|
||||
/// When the view is part of render tree, the DocumentFragment is empty, which is why we need
|
||||
/// to keep track of the nodes.
|
||||
nodes:List<Node>;
|
||||
@ -41,10 +41,10 @@ export class View {
|
||||
context: any;
|
||||
contextWithLocals:ContextWithVariableBindings;
|
||||
|
||||
constructor(proto:ProtoView, nodes:List<Node>, protoRecordRange:ProtoRecordRange, protoContextLocals:Map) {
|
||||
constructor(proto:ProtoView, nodes:List<Node>, protoChangeDetector:ProtoChangeDetector, protoContextLocals:Map) {
|
||||
this.proto = proto;
|
||||
this.nodes = nodes;
|
||||
this.recordRange = protoRecordRange.instantiate(this, NO_FORMATTERS);
|
||||
this.changeDetector = protoChangeDetector.instantiate(this, NO_FORMATTERS);
|
||||
this.elementInjectors = null;
|
||||
this.rootElementInjectors = null;
|
||||
this.textNodes = null;
|
||||
@ -92,7 +92,7 @@ export class View {
|
||||
// TODO(tbosch): if we have a contextWithLocals we actually only need to
|
||||
// set the contextWithLocals once. Would it be faster to always use a contextWithLocals
|
||||
// even if we don't have locals and not update the recordRange here?
|
||||
this.recordRange.setContext(this.context);
|
||||
this.changeDetector.setContext(this.context);
|
||||
}
|
||||
|
||||
_dehydrateContext() {
|
||||
@ -195,20 +195,20 @@ export class View {
|
||||
this._dehydrateContext();
|
||||
}
|
||||
|
||||
onRecordChange(groupMemento, records:List<Record>) {
|
||||
this._invokeMementoForRecords(records);
|
||||
onRecordChange(groupMemento, records:List) {
|
||||
this._invokeMementos(records);
|
||||
if (groupMemento instanceof DirectivePropertyGroupMemento) {
|
||||
this._notifyDirectiveAboutChanges(groupMemento, records);
|
||||
}
|
||||
}
|
||||
|
||||
_invokeMementoForRecords(records:List<Record>) {
|
||||
_invokeMementos(records:List) {
|
||||
for(var i = 0; i < records.length; ++i) {
|
||||
this._invokeMementoFor(records[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_notifyDirectiveAboutChanges(groupMemento, records:List<Record>) {
|
||||
_notifyDirectiveAboutChanges(groupMemento, records:List) {
|
||||
var dir = groupMemento.directive(this.elementInjectors);
|
||||
if (dir instanceof OnChange) {
|
||||
dir.onChange(this._collectChanges(records));
|
||||
@ -216,8 +216,8 @@ export class View {
|
||||
}
|
||||
|
||||
// dispatch to element injector or text nodes based on context
|
||||
_invokeMementoFor(record:Record) {
|
||||
var memento = record.expressionMemento();
|
||||
_invokeMementoFor(record:ChangeRecord) {
|
||||
var memento = record.bindingMemento;
|
||||
if (memento instanceof DirectivePropertyMemento) {
|
||||
// we know that it is DirectivePropertyMemento
|
||||
var directiveMemento:DirectivePropertyMemento = memento;
|
||||
@ -234,12 +234,12 @@ export class View {
|
||||
}
|
||||
}
|
||||
|
||||
_collectChanges(records:List<Record>) {
|
||||
_collectChanges(records:List) {
|
||||
var changes = StringMapWrapper.create();
|
||||
for(var i = 0; i < records.length; ++i) {
|
||||
var record = records[i];
|
||||
var propertyUpdate = new PropertyUpdate(record.currentValue, record.previousValue);
|
||||
StringMapWrapper.set(changes, record.expressionMemento()._setterName, propertyUpdate);
|
||||
StringMapWrapper.set(changes, record.bindingMemento._setterName, propertyUpdate);
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
@ -248,7 +248,7 @@ export class View {
|
||||
export class ProtoView {
|
||||
element:Element;
|
||||
elementBinders:List<ElementBinder>;
|
||||
protoRecordRange:ProtoRecordRange;
|
||||
protoChangeDetector:ProtoChangeDetector;
|
||||
variableBindings: Map;
|
||||
protoContextLocals:Map;
|
||||
textNodesWithBindingCount:int;
|
||||
@ -258,12 +258,12 @@ export class ProtoView {
|
||||
isTemplateElement:boolean;
|
||||
constructor(
|
||||
template:Element,
|
||||
protoRecordRange:ProtoRecordRange) {
|
||||
protoChangeDetector:ProtoChangeDetector) {
|
||||
this.element = template;
|
||||
this.elementBinders = [];
|
||||
this.variableBindings = MapWrapper.create();
|
||||
this.protoContextLocals = MapWrapper.create();
|
||||
this.protoRecordRange = protoRecordRange;
|
||||
this.protoChangeDetector = protoChangeDetector;
|
||||
this.textNodesWithBindingCount = 0;
|
||||
this.elementsWithBindingCount = 0;
|
||||
this.instantiateInPlace = false;
|
||||
@ -299,8 +299,8 @@ export class ProtoView {
|
||||
} else {
|
||||
viewNodes = [rootElementClone];
|
||||
}
|
||||
var view = new View(this, viewNodes, this.protoRecordRange, this.protoContextLocals);
|
||||
|
||||
var view = new View(this, viewNodes, this.protoChangeDetector, this.protoContextLocals);
|
||||
var binders = this.elementBinders;
|
||||
var elementInjectors = ListWrapper.createFixedSize(binders.length);
|
||||
var rootElementInjectors = [];
|
||||
@ -353,7 +353,7 @@ export class ProtoView {
|
||||
var lightDom = null;
|
||||
if (isPresent(binder.componentDirective)) {
|
||||
var childView = binder.nestedProtoView.instantiate(elementInjector);
|
||||
view.recordRange.addRange(childView.recordRange);
|
||||
view.changeDetector.addChild(childView.changeDetector);
|
||||
|
||||
lightDom = binder.componentDirective.shadowDomStrategy.constructLightDom(view, childView, element);
|
||||
binder.componentDirective.shadowDomStrategy.attachTemplate(element, childView);
|
||||
@ -434,7 +434,7 @@ export class ProtoView {
|
||||
}
|
||||
ListWrapper.push(elBinder.textNodeIndices, indexInParent);
|
||||
var memento = this.textNodesWithBindingCount++;
|
||||
this.protoRecordRange.addRecordsFromAST(expression, memento, memento);
|
||||
this.protoChangeDetector.addAst(expression, memento, memento);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -447,7 +447,7 @@ export class ProtoView {
|
||||
this.elementsWithBindingCount++;
|
||||
}
|
||||
var memento = new ElementPropertyMemento(this.elementsWithBindingCount-1, setterName, setter);
|
||||
this.protoRecordRange.addRecordsFromAST(expression, memento, memento);
|
||||
this.protoChangeDetector.addAst(expression, memento, memento);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -478,7 +478,7 @@ export class ProtoView {
|
||||
setter
|
||||
);
|
||||
var groupMemento = DirectivePropertyGroupMemento.get(expMemento);
|
||||
this.protoRecordRange.addRecordsFromAST(expression, expMemento, groupMemento, isContentWatch);
|
||||
this.protoChangeDetector.addAst(expression, expMemento, groupMemento, isContentWatch);
|
||||
}
|
||||
|
||||
// Create a rootView as if the compiler encountered <rootcmp></rootcmp>,
|
||||
@ -487,7 +487,7 @@ export class ProtoView {
|
||||
static createRootProtoView(protoView: ProtoView,
|
||||
insertionElement, rootComponentAnnotatedType: DirectiveMetadata): ProtoView {
|
||||
DOM.addClass(insertionElement, 'ng-binding');
|
||||
var rootProtoView = new ProtoView(insertionElement, new ProtoRecordRange());
|
||||
var rootProtoView = new ProtoView(insertionElement, new ProtoChangeDetector());
|
||||
rootProtoView.instantiateInPlace = true;
|
||||
var binder = rootProtoView.bindElement(
|
||||
new ProtoElementInjector(null, 0, [rootComponentAnnotatedType.type], true));
|
||||
@ -507,7 +507,7 @@ export class ElementPropertyMemento {
|
||||
this._setter = setter;
|
||||
}
|
||||
|
||||
invoke(record:Record, bindElements:List<Element>) {
|
||||
invoke(record:ChangeRecord, bindElements:List<Element>) {
|
||||
var element:Element = bindElements[this._elementIndex];
|
||||
this._setter(element, record.currentValue);
|
||||
}
|
||||
@ -529,7 +529,7 @@ export class DirectivePropertyMemento {
|
||||
this._setter = setter;
|
||||
}
|
||||
|
||||
invoke(record:Record, elementInjectors:List<ElementInjector>) {
|
||||
invoke(record:ChangeRecord, elementInjectors:List<ElementInjector>) {
|
||||
var elementInjector:ElementInjector = elementInjectors[this._elementInjectorIndex];
|
||||
var directive = elementInjector.getAtIndex(this._directiveIndex);
|
||||
this._setter(directive, record.currentValue);
|
||||
|
@ -84,7 +84,7 @@ export class ViewPort {
|
||||
} else {
|
||||
this._lightDom.redistribute();
|
||||
}
|
||||
this.parentView.recordRange.addRange(view.recordRange);
|
||||
this.parentView.changeDetector.addChild(view.changeDetector);
|
||||
this._linkElementInjectors(view);
|
||||
return view;
|
||||
}
|
||||
@ -98,7 +98,7 @@ export class ViewPort {
|
||||
} else {
|
||||
this._lightDom.redistribute();
|
||||
}
|
||||
removedView.recordRange.remove();
|
||||
removedView.changeDetector.remove();
|
||||
this._unlinkElementInjectors(removedView);
|
||||
return removedView;
|
||||
}
|
||||
|
@ -5,9 +5,11 @@ import {ListWrapper} from 'facade/collection';
|
||||
|
||||
export class LifeCycle {
|
||||
_changeDetector:ChangeDetector;
|
||||
_enforceNoNewChanges:boolean;
|
||||
|
||||
constructor(changeDetector:ChangeDetector) {
|
||||
constructor(changeDetector:ChangeDetector, enforceNoNewChanges:boolean = false) {
|
||||
this._changeDetector = changeDetector;
|
||||
this._enforceNoNewChanges = enforceNoNewChanges;
|
||||
}
|
||||
|
||||
registerWith(zone:VmTurnZone) {
|
||||
@ -26,5 +28,8 @@ export class LifeCycle {
|
||||
|
||||
tick() {
|
||||
this._changeDetector.detectChanges();
|
||||
if (this._enforceNoNewChanges) {
|
||||
this._changeDetector.checkNoChanges();
|
||||
}
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ export function main() {
|
||||
ctx = new MyComp();
|
||||
view = pv.instantiate(null);
|
||||
view.hydrate(new Injector([]), null, ctx);
|
||||
cd = new ChangeDetector(view.recordRange);
|
||||
cd = view.changeDetector;
|
||||
}
|
||||
|
||||
it('should consume text node changes', (done) => {
|
||||
|
@ -16,7 +16,7 @@ import {ProtoView, ElementPropertyMemento, DirectivePropertyMemento} from 'core/
|
||||
import {ProtoElementInjector} from 'core/compiler/element_injector';
|
||||
import {DirectiveMetadataReader} from 'core/compiler/directive_metadata_reader';
|
||||
|
||||
import {ChangeDetector, Lexer, Parser, ProtoRecordRange} from 'change_detection/change_detection';
|
||||
import {ChangeDetector, Lexer, Parser, ProtoChangeDetector} from 'change_detection/change_detection';
|
||||
import {Injector} from 'di/di';
|
||||
|
||||
export function main() {
|
||||
@ -65,7 +65,7 @@ export function main() {
|
||||
}
|
||||
if (isPresent(current.element.getAttribute('viewroot'))) {
|
||||
current.isViewRoot = true;
|
||||
current.inheritedProtoView = new ProtoView(current.element, new ProtoRecordRange());
|
||||
current.inheritedProtoView = new ProtoView(current.element, new ProtoChangeDetector());
|
||||
} else if (isPresent(parent)) {
|
||||
current.inheritedProtoView = parent.inheritedProtoView;
|
||||
}
|
||||
@ -77,7 +77,7 @@ export function main() {
|
||||
evalContext = new Context();
|
||||
view = protoView.instantiate(null);
|
||||
view.hydrate(new Injector([]), null, evalContext);
|
||||
changeDetector = new ChangeDetector(view.recordRange);
|
||||
changeDetector = view.changeDetector;
|
||||
}
|
||||
|
||||
it('should not create an ElementBinder for elements that have no bindings', () => {
|
||||
@ -204,7 +204,7 @@ export function main() {
|
||||
var results = pipeline.process(el('<div viewroot prop-binding directives></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
results[0].inheritedElementBinder.nestedProtoView = new ProtoView(
|
||||
el('<div></div>'), new ProtoRecordRange());
|
||||
el('<div></div>'), new ProtoChangeDetector());
|
||||
|
||||
instantiateView(pv);
|
||||
evalContext.prop1 = 'a';
|
||||
|
@ -34,7 +34,7 @@ export function main() {
|
||||
compiler.compile(MyComp, el(template)).
|
||||
then(createView).
|
||||
then((view) => {
|
||||
var lc = new LifeCycle(new ChangeDetector(view.recordRange));
|
||||
var lc = new LifeCycle(view.changeDetector, false);
|
||||
assertions(view, lc);
|
||||
});
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import {ShadowDomEmulated} from 'core/compiler/shadow_dom';
|
||||
import {DirectiveMetadataReader} from 'core/compiler/directive_metadata_reader';
|
||||
import {Component, Decorator, Template} from 'core/annotations/annotations';
|
||||
import {OnChange} from 'core/core';
|
||||
import {Lexer, Parser, ProtoRecordRange, ChangeDetector} from 'change_detection/change_detection';
|
||||
import {Lexer, Parser, ProtoChangeDetector, ChangeDetector} from 'change_detection/change_detection';
|
||||
import {TemplateConfig} from 'core/annotations/template_config';
|
||||
import {List, MapWrapper} from 'facade/collection';
|
||||
import {DOM, Element} from 'facade/dom';
|
||||
@ -48,10 +48,10 @@ export function main() {
|
||||
someTemplateDirective = new DirectiveMetadataReader().read(SomeTemplate);
|
||||
});
|
||||
|
||||
describe('instatiated from protoView', () => {
|
||||
describe('instantiated from protoView', () => {
|
||||
var view;
|
||||
beforeEach(() => {
|
||||
var pv = new ProtoView(el('<div id="1"></div>'), new ProtoRecordRange());
|
||||
var pv = new ProtoView(el('<div id="1"></div>'), new ProtoChangeDetector());
|
||||
view = pv.instantiate(null);
|
||||
});
|
||||
|
||||
@ -72,7 +72,7 @@ export function main() {
|
||||
describe('with locals', function() {
|
||||
var view;
|
||||
beforeEach(() => {
|
||||
var pv = new ProtoView(el('<div id="1"></div>'), new ProtoRecordRange());
|
||||
var pv = new ProtoView(el('<div id="1"></div>'), new ProtoChangeDetector());
|
||||
pv.bindVariable('context-foo', 'template-foo');
|
||||
view = createView(pv);
|
||||
});
|
||||
@ -108,7 +108,7 @@ export function main() {
|
||||
}
|
||||
|
||||
it('should collect the root node in the ProtoView element', () => {
|
||||
var pv = new ProtoView(templateAwareCreateElement('<div id="1"></div>'), new ProtoRecordRange());
|
||||
var pv = new ProtoView(templateAwareCreateElement('<div id="1"></div>'), new ProtoChangeDetector());
|
||||
var view = pv.instantiate(null);
|
||||
view.hydrate(null, null, null);
|
||||
expect(view.nodes.length).toBe(1);
|
||||
@ -118,7 +118,7 @@ export function main() {
|
||||
describe('collect elements with property bindings', () => {
|
||||
|
||||
it('should collect property bindings on the root element if it has the ng-binding class', () => {
|
||||
var pv = new ProtoView(templateAwareCreateElement('<div [prop]="a" class="ng-binding"></div>'), new ProtoRecordRange());
|
||||
var pv = new ProtoView(templateAwareCreateElement('<div [prop]="a" class="ng-binding"></div>'), new ProtoChangeDetector());
|
||||
pv.bindElement(null);
|
||||
pv.bindElementProperty(parser.parseBinding('a', null), 'prop', reflector.setter('prop'));
|
||||
|
||||
@ -130,7 +130,7 @@ export function main() {
|
||||
|
||||
it('should collect property bindings on child elements with ng-binding class', () => {
|
||||
var pv = new ProtoView(templateAwareCreateElement('<div><span></span><span class="ng-binding"></span></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
pv.bindElement(null);
|
||||
pv.bindElementProperty(parser.parseBinding('b', null), 'a', reflector.setter('a'));
|
||||
|
||||
@ -145,7 +145,7 @@ export function main() {
|
||||
describe('collect text nodes with bindings', () => {
|
||||
|
||||
it('should collect text nodes under the root element', () => {
|
||||
var pv = new ProtoView(templateAwareCreateElement('<div class="ng-binding">{{}}<span></span>{{}}</div>'), new ProtoRecordRange());
|
||||
var pv = new ProtoView(templateAwareCreateElement('<div class="ng-binding">{{}}<span></span>{{}}</div>'), new ProtoChangeDetector());
|
||||
pv.bindElement(null);
|
||||
pv.bindTextNode(0, parser.parseBinding('a', null));
|
||||
pv.bindTextNode(2, parser.parseBinding('b', null));
|
||||
@ -159,7 +159,7 @@ export function main() {
|
||||
|
||||
it('should collect text nodes with bindings on child elements with ng-binding class', () => {
|
||||
var pv = new ProtoView(templateAwareCreateElement('<div><span> </span><span class="ng-binding">{{}}</span></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
pv.bindElement(null);
|
||||
pv.bindTextNode(0, parser.parseBinding('b', null));
|
||||
|
||||
@ -175,7 +175,7 @@ export function main() {
|
||||
describe('inplace instantiation', () => {
|
||||
it('should be supported.', () => {
|
||||
var template = el('<div></div>');
|
||||
var pv = new ProtoView(template, new ProtoRecordRange());
|
||||
var pv = new ProtoView(template, new ProtoChangeDetector());
|
||||
pv.instantiateInPlace = true;
|
||||
var view = pv.instantiate(null);
|
||||
view.hydrate(null, null, null);
|
||||
@ -184,8 +184,8 @@ export function main() {
|
||||
|
||||
it('should be off by default.', () => {
|
||||
var template = el('<div></div>')
|
||||
var view = new ProtoView(template, new ProtoRecordRange())
|
||||
.instantiate(null);
|
||||
var view = new ProtoView(template, new ProtoChangeDetector())
|
||||
.instantiate(null);
|
||||
view.hydrate(null, null, null);
|
||||
expect(view.nodes[0]).not.toBe(template);
|
||||
});
|
||||
@ -201,7 +201,7 @@ export function main() {
|
||||
|
||||
describe('create ElementInjectors', () => {
|
||||
it('should use the directives of the ProtoElementInjector', () => {
|
||||
var pv = new ProtoView(el('<div class="ng-binding"></div>'), new ProtoRecordRange());
|
||||
var pv = new ProtoView(el('<div class="ng-binding"></div>'), new ProtoChangeDetector());
|
||||
pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective]));
|
||||
|
||||
var view = pv.instantiate(null);
|
||||
@ -212,7 +212,7 @@ export function main() {
|
||||
|
||||
it('should use the correct parent', () => {
|
||||
var pv = new ProtoView(el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
|
||||
pv.bindElement(protoParent);
|
||||
pv.bindElement(new ProtoElementInjector(protoParent, 1, [AnotherDirective]));
|
||||
@ -226,7 +226,7 @@ export function main() {
|
||||
|
||||
it('should not pass the host injector when a parent injector exists', () => {
|
||||
var pv = new ProtoView(el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
|
||||
pv.bindElement(protoParent);
|
||||
var testProtoElementInjector = new TestProtoElementInjector(protoParent, 1, [AnotherDirective]);
|
||||
@ -242,7 +242,7 @@ export function main() {
|
||||
|
||||
it('should pass the host injector when there is no parent injector', () => {
|
||||
var pv = new ProtoView(el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
pv.bindElement(new ProtoElementInjector(null, 0, [SomeDirective]));
|
||||
var testProtoElementInjector = new TestProtoElementInjector(null, 1, [AnotherDirective]);
|
||||
pv.bindElement(testProtoElementInjector);
|
||||
@ -259,7 +259,7 @@ export function main() {
|
||||
|
||||
it('should collect a single root element injector', () => {
|
||||
var pv = new ProtoView(el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
|
||||
pv.bindElement(protoParent);
|
||||
pv.bindElement(new ProtoElementInjector(protoParent, 1, [AnotherDirective]));
|
||||
@ -272,7 +272,7 @@ export function main() {
|
||||
|
||||
it('should collect multiple root element injectors', () => {
|
||||
var pv = new ProtoView(el('<div><span class="ng-binding"></span><span class="ng-binding"></span></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective]));
|
||||
pv.bindElement(new ProtoElementInjector(null, 2, [AnotherDirective]));
|
||||
|
||||
@ -289,7 +289,7 @@ export function main() {
|
||||
var ctx;
|
||||
|
||||
function createComponentWithSubPV(subProtoView) {
|
||||
var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'), new ProtoRecordRange());
|
||||
var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'), new ProtoChangeDetector());
|
||||
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponent], true));
|
||||
binder.componentDirective = someComponentDirective;
|
||||
binder.nestedProtoView = subProtoView;
|
||||
@ -304,7 +304,7 @@ export function main() {
|
||||
}
|
||||
|
||||
it('should expose component services to the component', () => {
|
||||
var subpv = new ProtoView(el('<span></span>'), new ProtoRecordRange());
|
||||
var subpv = new ProtoView(el('<span></span>'), new ProtoChangeDetector());
|
||||
var pv = createComponentWithSubPV(subpv);
|
||||
|
||||
var view = createNestedView(pv);
|
||||
@ -316,7 +316,7 @@ export function main() {
|
||||
it('should expose component services and component instance to directives in the shadow Dom',
|
||||
() => {
|
||||
var subpv = new ProtoView(
|
||||
el('<div dec class="ng-binding">hello shadow dom</div>'), new ProtoRecordRange());
|
||||
el('<div dec class="ng-binding">hello shadow dom</div>'), new ProtoChangeDetector());
|
||||
subpv.bindElement(
|
||||
new ProtoElementInjector(null, 0, [ServiceDependentDecorator]));
|
||||
var pv = createComponentWithSubPV(subpv);
|
||||
@ -339,7 +339,7 @@ export function main() {
|
||||
|
||||
it('dehydration should dehydrate child component views too', () => {
|
||||
var subpv = new ProtoView(
|
||||
el('<div dec class="ng-binding">hello shadow dom</div>'), new ProtoRecordRange());
|
||||
el('<div dec class="ng-binding">hello shadow dom</div>'), new ProtoChangeDetector());
|
||||
subpv.bindElement(
|
||||
new ProtoElementInjector(null, 0, [ServiceDependentDecorator]));
|
||||
var pv = createComponentWithSubPV(subpv);
|
||||
@ -354,7 +354,7 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should create shadow dom', () => {
|
||||
var subpv = new ProtoView(el('<span>hello shadow dom</span>'), new ProtoRecordRange());
|
||||
var subpv = new ProtoView(el('<span>hello shadow dom</span>'), new ProtoChangeDetector());
|
||||
var pv = createComponentWithSubPV(subpv);
|
||||
|
||||
var view = createNestedView(pv);
|
||||
@ -363,9 +363,9 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should use the provided shadow DOM strategy', () => {
|
||||
var subpv = new ProtoView(el('<span>hello shadow dom</span>'), new ProtoRecordRange());
|
||||
var subpv = new ProtoView(el('<span>hello shadow dom</span>'), new ProtoChangeDetector());
|
||||
|
||||
var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'), new ProtoRecordRange());
|
||||
var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'), new ProtoChangeDetector());
|
||||
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponentWithEmulatedShadowDom], true));
|
||||
binder.componentDirective = new DirectiveMetadataReader().read(SomeComponentWithEmulatedShadowDom);
|
||||
binder.nestedProtoView = subpv;
|
||||
@ -379,8 +379,8 @@ export function main() {
|
||||
describe('with template views', () => {
|
||||
function createViewWithTemplate() {
|
||||
var templateProtoView = new ProtoView(
|
||||
el('<div id="1"></div>'), new ProtoRecordRange());
|
||||
var pv = new ProtoView(el('<someTmpl class="ng-binding"></someTmpl>'), new ProtoRecordRange());
|
||||
el('<div id="1"></div>'), new ProtoChangeDetector());
|
||||
var pv = new ProtoView(el('<someTmpl class="ng-binding"></someTmpl>'), new ProtoChangeDetector());
|
||||
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeTemplate]));
|
||||
binder.templateDirective = someTemplateDirective;
|
||||
binder.nestedProtoView = templateProtoView;
|
||||
@ -424,7 +424,7 @@ export function main() {
|
||||
|
||||
function createProtoView() {
|
||||
var pv = new ProtoView(el('<div class="ng-binding"><div></div></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
pv.bindElement(new TestProtoElementInjector(null, 0, []));
|
||||
pv.bindEvent('click', parser.parseBinding('callMe(\$event)', null));
|
||||
return pv;
|
||||
@ -464,12 +464,12 @@ export function main() {
|
||||
function createViewAndChangeDetector(protoView) {
|
||||
view = createView(protoView);
|
||||
ctx = view.context;
|
||||
cd = new ChangeDetector(view.recordRange);
|
||||
cd = view.changeDetector;
|
||||
}
|
||||
|
||||
it('should consume text node changes', () => {
|
||||
var pv = new ProtoView(el('<div class="ng-binding">{{}}</div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
pv.bindElement(null);
|
||||
pv.bindTextNode(0, parser.parseBinding('foo', null));
|
||||
createViewAndChangeDetector(pv);
|
||||
@ -481,7 +481,7 @@ export function main() {
|
||||
|
||||
it('should consume element binding changes', () => {
|
||||
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
pv.bindElement(null);
|
||||
pv.bindElementProperty(parser.parseBinding('foo', null), 'id', reflector.setter('id'));
|
||||
createViewAndChangeDetector(pv);
|
||||
@ -493,7 +493,7 @@ export function main() {
|
||||
|
||||
it('should consume directive watch expression change', () => {
|
||||
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
pv.bindElement(new ProtoElementInjector(null, 0, [SomeDirective]));
|
||||
pv.bindDirectiveProperty(0, parser.parseBinding('foo', null), 'prop', reflector.setter('prop'), false);
|
||||
createViewAndChangeDetector(pv);
|
||||
@ -505,7 +505,7 @@ export function main() {
|
||||
|
||||
it('should notify a directive about changes after all its properties have been set', () => {
|
||||
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
|
||||
pv.bindElement(new ProtoElementInjector(null, 0, [DirectiveImplementingOnChange]));
|
||||
pv.bindDirectiveProperty( 0, parser.parseBinding('a', null), 'a', reflector.setter('a'), false);
|
||||
@ -522,7 +522,7 @@ export function main() {
|
||||
|
||||
it('should provide a map of updated properties', () => {
|
||||
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
|
||||
pv.bindElement(new ProtoElementInjector(null, 0, [DirectiveImplementingOnChange]));
|
||||
pv.bindDirectiveProperty( 0, parser.parseBinding('a', null), 'a', reflector.setter('a'), false);
|
||||
@ -547,7 +547,7 @@ export function main() {
|
||||
var element, pv;
|
||||
beforeEach(() => {
|
||||
element = DOM.createElement('div');
|
||||
pv = new ProtoView(el('<div>hi</div>'), new ProtoRecordRange());
|
||||
pv = new ProtoView(el('<div>hi</div>'), new ProtoChangeDetector());
|
||||
});
|
||||
|
||||
it('should create the root component when instantiated', () => {
|
||||
|
@ -5,10 +5,10 @@ import {DOM} from 'facade/dom';
|
||||
import {ListWrapper, MapWrapper} from 'facade/collection';
|
||||
import {Injector} from 'di/di';
|
||||
import {ProtoElementInjector, ElementInjector} from 'core/compiler/element_injector';
|
||||
import {ProtoRecordRange, Lexer, Parser} from 'change_detection/change_detection';
|
||||
import {ProtoChangeDetector, Lexer, Parser} from 'change_detection/change_detection';
|
||||
|
||||
function createView(nodes) {
|
||||
var view = new View(null, nodes, new ProtoRecordRange(), MapWrapper.create());
|
||||
var view = new View(null, nodes, new ProtoChangeDetector(), MapWrapper.create());
|
||||
view.init([], [], [], [], [], [], []);
|
||||
return view;
|
||||
}
|
||||
@ -22,7 +22,7 @@ export function main() {
|
||||
dom = el(`<div><stuff></stuff><div insert-after-me></div><stuff></stuff></div>`);
|
||||
var insertionElement = dom.childNodes[1];
|
||||
parentView = createView([dom.childNodes[0]]);
|
||||
protoView = new ProtoView(el('<div>hi</div>'), new ProtoRecordRange());
|
||||
protoView = new ProtoView(el('<div>hi</div>'), new ProtoChangeDetector());
|
||||
elementInjector = new ElementInjector(null, null, null);
|
||||
viewPort = new ViewPort(parentView, insertionElement, protoView, elementInjector);
|
||||
customViewWithOneNode = createView([el('<div>single</div>')]);
|
||||
@ -117,25 +117,26 @@ export function main() {
|
||||
viewPort.hydrate(new Injector([]), null);
|
||||
|
||||
var pv = new ProtoView(el('<div class="ng-binding">{{}}</div>'),
|
||||
new ProtoRecordRange());
|
||||
new ProtoChangeDetector());
|
||||
pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective]));
|
||||
pv.bindTextNode(0, parser.parseBinding('foo', null));
|
||||
fancyView = pv.instantiate(null);
|
||||
});
|
||||
|
||||
it('hydrating should update rootElementInjectors and parent RR', () => {
|
||||
it('hydrating should update rootElementInjectors and parent change detector', () => {
|
||||
viewPort.insert(fancyView);
|
||||
ListWrapper.forEach(fancyView.rootElementInjectors, (inj) =>
|
||||
expect(inj.parent).toBe(elementInjector));
|
||||
expect(parentView.recordRange.findFirstEnabledRecord()).not.toBe(null);
|
||||
|
||||
expect(parentView.changeDetector.children.length).toBe(1);
|
||||
});
|
||||
|
||||
it('dehydrating should update rootElementInjectors and parent RR', () => {
|
||||
it('dehydrating should update rootElementInjectors and parent change detector', () => {
|
||||
viewPort.insert(fancyView);
|
||||
viewPort.remove();
|
||||
ListWrapper.forEach(fancyView.rootElementInjectors, (inj) =>
|
||||
expect(inj.parent).toBe(null));
|
||||
expect(parentView.recordRange.findFirstEnabledRecord()).toBe(null);
|
||||
expect(parentView.changeDetector.children.length).toBe(0);
|
||||
expect(viewPort.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user