feat(change_detection): do not reparse AST when using generated detectors
This commit is contained in:
parent
b986c54079
commit
d2d0715568
|
@ -2,7 +2,7 @@ import {isPresent, isBlank, BaseException, StringWrapper} from 'angular2/src/fac
|
||||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||||
import {ChangeDetectionUtil} from './change_detection_util';
|
import {ChangeDetectionUtil} from './change_detection_util';
|
||||||
import {ChangeDetectorRef} from './change_detector_ref';
|
import {ChangeDetectorRef} from './change_detector_ref';
|
||||||
import {DirectiveRecord} from './directive_record';
|
import {DirectiveIndex} from './directive_record';
|
||||||
import {ChangeDetector, ChangeDispatcher} from './interfaces';
|
import {ChangeDetector, ChangeDispatcher} from './interfaces';
|
||||||
import {Pipes} from './pipes';
|
import {Pipes} from './pipes';
|
||||||
import {
|
import {
|
||||||
|
@ -10,8 +10,7 @@ import {
|
||||||
ExpressionChangedAfterItHasBeenCheckedException,
|
ExpressionChangedAfterItHasBeenCheckedException,
|
||||||
DehydratedException
|
DehydratedException
|
||||||
} from './exceptions';
|
} from './exceptions';
|
||||||
import {ProtoRecord} from './proto_record';
|
import {BindingTarget} from './binding_record';
|
||||||
import {BindingRecord} from './binding_record';
|
|
||||||
import {Locals} from './parser/locals';
|
import {Locals} from './parser/locals';
|
||||||
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from './constants';
|
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from './constants';
|
||||||
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
|
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
|
||||||
|
@ -20,9 +19,8 @@ import {isObservable} from './observable_facade';
|
||||||
var _scope_check: WtfScopeFn = wtfCreateScope(`ChangeDetector#check(ascii id, bool throwOnChange)`);
|
var _scope_check: WtfScopeFn = wtfCreateScope(`ChangeDetector#check(ascii id, bool throwOnChange)`);
|
||||||
|
|
||||||
class _Context {
|
class _Context {
|
||||||
constructor(public element: any, public componentElement: any, public instance: any,
|
constructor(public element: any, public componentElement: any, public context: any,
|
||||||
public context: any, public locals: any, public injector: any,
|
public locals: any, public injector: any, public expression: any) {}
|
||||||
public expression: any) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AbstractChangeDetector<T> implements ChangeDetector {
|
export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
|
@ -35,24 +33,19 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
// change detection will fail.
|
// change detection will fail.
|
||||||
alreadyChecked: any = false;
|
alreadyChecked: any = false;
|
||||||
context: T;
|
context: T;
|
||||||
directiveRecords: List<DirectiveRecord>;
|
|
||||||
dispatcher: ChangeDispatcher;
|
|
||||||
locals: Locals = null;
|
locals: Locals = null;
|
||||||
mode: string = null;
|
mode: string = null;
|
||||||
pipes: Pipes = null;
|
pipes: Pipes = null;
|
||||||
firstProtoInCurrentBinding: number;
|
propertyBindingIndex: number;
|
||||||
protos: List<ProtoRecord>;
|
|
||||||
|
|
||||||
// This is an experimental feature. Works only in Dart.
|
// This is an experimental feature. Works only in Dart.
|
||||||
subscriptions: any[];
|
subscriptions: any[];
|
||||||
streams: any[];
|
streams: any[];
|
||||||
|
|
||||||
constructor(public id: string, dispatcher: ChangeDispatcher, protos: List<ProtoRecord>,
|
constructor(public id: string, public dispatcher: ChangeDispatcher,
|
||||||
directiveRecords: List<DirectiveRecord>, public modeOnHydrate: string) {
|
public numberOfPropertyProtoRecords: number, public bindingTargets: BindingTarget[],
|
||||||
|
public directiveIndices: DirectiveIndex[], public modeOnHydrate: string) {
|
||||||
this.ref = new ChangeDetectorRef(this);
|
this.ref = new ChangeDetectorRef(this);
|
||||||
this.directiveRecords = directiveRecords;
|
|
||||||
this.dispatcher = dispatcher;
|
|
||||||
this.protos = protos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addChild(cd: ChangeDetector): void {
|
addChild(cd: ChangeDetector): void {
|
||||||
|
@ -99,7 +92,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
// implementation of `detectChangesInRecordsInternal` which does the work of detecting changes
|
// implementation of `detectChangesInRecordsInternal` which does the work of detecting changes
|
||||||
// and which this method will call.
|
// and which this method will call.
|
||||||
// This method expects that `detectChangesInRecordsInternal` will set the property
|
// This method expects that `detectChangesInRecordsInternal` will set the property
|
||||||
// `this.firstProtoInCurrentBinding` to the selfIndex of the first proto record. This is to
|
// `this.propertyBindingIndex` to the propertyBindingIndex of the first proto record. This is to
|
||||||
// facilitate error reporting.
|
// facilitate error reporting.
|
||||||
detectChangesInRecords(throwOnChange: boolean): void {
|
detectChangesInRecords(throwOnChange: boolean): void {
|
||||||
if (!this.hydrated()) {
|
if (!this.hydrated()) {
|
||||||
|
@ -115,9 +108,9 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
// Subclasses should override this method to perform any work necessary to detect and report
|
// Subclasses should override this method to perform any work necessary to detect and report
|
||||||
// changes. For example, changes should be reported via `ChangeDetectionUtil.addChange`, lifecycle
|
// changes. For example, changes should be reported via `ChangeDetectionUtil.addChange`, lifecycle
|
||||||
// methods should be called, etc.
|
// methods should be called, etc.
|
||||||
// This implementation should also set `this.firstProtoInCurrentBinding` to the selfIndex of the
|
// This implementation should also set `this.propertyBindingIndex` to the propertyBindingIndex of
|
||||||
// first proto record
|
// the
|
||||||
// to facilitate error reporting. See {@link #detectChangesInRecords}.
|
// first proto record to facilitate error reporting. See {@link #detectChangesInRecords}.
|
||||||
detectChangesInRecordsInternal(throwOnChange: boolean): void {}
|
detectChangesInRecordsInternal(throwOnChange: boolean): void {}
|
||||||
|
|
||||||
// This method is not intended to be overridden. Subclasses should instead provide an
|
// This method is not intended to be overridden. Subclasses should instead provide an
|
||||||
|
@ -195,8 +188,8 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
protected observe(value: any, index: number): any {
|
protected observe(value: any, index: number): any {
|
||||||
if (isObservable(value)) {
|
if (isObservable(value)) {
|
||||||
if (isBlank(this.subscriptions)) {
|
if (isBlank(this.subscriptions)) {
|
||||||
this.subscriptions = ListWrapper.createFixedSize(this.protos.length + 1);
|
this.subscriptions = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords + 1);
|
||||||
this.streams = ListWrapper.createFixedSize(this.protos.length + 1);
|
this.streams = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords + 1);
|
||||||
}
|
}
|
||||||
if (isBlank(this.subscriptions[index])) {
|
if (isBlank(this.subscriptions[index])) {
|
||||||
this.streams[index] = value.changes;
|
this.streams[index] = value.changes;
|
||||||
|
@ -211,7 +204,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getDetectorFor(directives: any, index: number): ChangeDetector {
|
protected getDetectorFor(directives: any, index: number): ChangeDetector {
|
||||||
return directives.getDetectorFor(this.directiveRecords[index].directiveIndex);
|
return directives.getDetectorFor(this.directiveIndices[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected notifyDispatcher(value: any): void {
|
protected notifyDispatcher(value: any): void {
|
||||||
|
@ -223,31 +216,26 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
if (isBlank(changes)) {
|
if (isBlank(changes)) {
|
||||||
changes = {};
|
changes = {};
|
||||||
}
|
}
|
||||||
changes[this._currentBinding().propertyName] =
|
changes[this._currentBinding().name] = ChangeDetectionUtil.simpleChange(oldValue, newValue);
|
||||||
ChangeDetectionUtil.simpleChange(oldValue, newValue);
|
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _throwError(exception: any, stack: any): void {
|
private _throwError(exception: any, stack: any): void {
|
||||||
var proto = this._currentBindingProto();
|
var c = this.dispatcher.getDebugContext(this._currentBinding().elementIndex, null);
|
||||||
var c = this.dispatcher.getDebugContext(proto.bindingRecord.elementIndex, proto.directiveIndex);
|
var context = isPresent(c) ? new _Context(c.element, c.componentElement, c.context, c.locals,
|
||||||
var context = isPresent(c) ? new _Context(c.element, c.componentElement, c.directive, c.context,
|
c.injector, this._currentBinding().debug) :
|
||||||
c.locals, c.injector, proto.expressionAsString) :
|
|
||||||
null;
|
null;
|
||||||
throw new ChangeDetectionError(proto, exception, stack, context);
|
throw new ChangeDetectionError(this._currentBinding().debug, exception, stack, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected throwOnChangeError(oldValue: any, newValue: any): void {
|
protected throwOnChangeError(oldValue: any, newValue: any): void {
|
||||||
var change = ChangeDetectionUtil.simpleChange(oldValue, newValue);
|
throw new ExpressionChangedAfterItHasBeenCheckedException(this._currentBinding().debug,
|
||||||
throw new ExpressionChangedAfterItHasBeenCheckedException(this._currentBindingProto(), change,
|
oldValue, newValue, null);
|
||||||
null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected throwDehydratedError(): void { throw new DehydratedException(); }
|
protected throwDehydratedError(): void { throw new DehydratedException(); }
|
||||||
|
|
||||||
private _currentBinding(): BindingRecord { return this._currentBindingProto().bindingRecord; }
|
private _currentBinding(): BindingTarget {
|
||||||
|
return this.bindingTargets[this.propertyBindingIndex];
|
||||||
private _currentBindingProto(): ProtoRecord {
|
|
||||||
return ChangeDetectionUtil.protoByIndex(this.protos, this.firstProtoInCurrentBinding);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,10 @@ import {SetterFn} from 'angular2/src/reflection/types';
|
||||||
import {AST} from './parser/ast';
|
import {AST} from './parser/ast';
|
||||||
import {DirectiveIndex, DirectiveRecord} from './directive_record';
|
import {DirectiveIndex, DirectiveRecord} from './directive_record';
|
||||||
|
|
||||||
const DIRECTIVE = "directive";
|
|
||||||
const DIRECTIVE_LIFECYCLE = "directiveLifecycle";
|
const DIRECTIVE_LIFECYCLE = "directiveLifecycle";
|
||||||
|
const BINDING = "native";
|
||||||
|
|
||||||
|
const DIRECTIVE = "directive";
|
||||||
const ELEMENT_PROPERTY = "elementProperty";
|
const ELEMENT_PROPERTY = "elementProperty";
|
||||||
const ELEMENT_ATTRIBUTE = "elementAttribute";
|
const ELEMENT_ATTRIBUTE = "elementAttribute";
|
||||||
const ELEMENT_CLASS = "elementClass";
|
const ELEMENT_CLASS = "elementClass";
|
||||||
|
@ -13,24 +15,12 @@ const TEXT_NODE = "textNode";
|
||||||
const EVENT = "event";
|
const EVENT = "event";
|
||||||
const HOST_EVENT = "hostEvent";
|
const HOST_EVENT = "hostEvent";
|
||||||
|
|
||||||
export class BindingRecord {
|
export class BindingTarget {
|
||||||
constructor(public mode: string, public implicitReceiver: any, public ast: AST,
|
constructor(public mode: string, public elementIndex: number, public name: string,
|
||||||
public elementIndex: number, public propertyName: string, public propertyUnit: string,
|
public unit: string, public debug: string) {}
|
||||||
public eventName: string, public setter: SetterFn, public lifecycleEvent: string,
|
|
||||||
public directiveRecord: DirectiveRecord) {}
|
|
||||||
|
|
||||||
callOnChange(): boolean {
|
|
||||||
return isPresent(this.directiveRecord) && this.directiveRecord.callOnChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
isDefaultChangeDetection(): boolean {
|
|
||||||
return isBlank(this.directiveRecord) || this.directiveRecord.isDefaultChangeDetection();
|
|
||||||
}
|
|
||||||
|
|
||||||
isDirective(): boolean { return this.mode === DIRECTIVE; }
|
isDirective(): boolean { return this.mode === DIRECTIVE; }
|
||||||
|
|
||||||
isDirectiveLifecycle(): boolean { return this.mode === DIRECTIVE_LIFECYCLE; }
|
|
||||||
|
|
||||||
isElementProperty(): boolean { return this.mode === ELEMENT_PROPERTY; }
|
isElementProperty(): boolean { return this.mode === ELEMENT_PROPERTY; }
|
||||||
|
|
||||||
isElementAttribute(): boolean { return this.mode === ELEMENT_ATTRIBUTE; }
|
isElementAttribute(): boolean { return this.mode === ELEMENT_ATTRIBUTE; }
|
||||||
|
@ -40,87 +30,118 @@ export class BindingRecord {
|
||||||
isElementStyle(): boolean { return this.mode === ELEMENT_STYLE; }
|
isElementStyle(): boolean { return this.mode === ELEMENT_STYLE; }
|
||||||
|
|
||||||
isTextNode(): boolean { return this.mode === TEXT_NODE; }
|
isTextNode(): boolean { return this.mode === TEXT_NODE; }
|
||||||
|
|
||||||
static createForDirective(ast: AST, propertyName: string, setter: SetterFn,
|
|
||||||
directiveRecord: DirectiveRecord): BindingRecord {
|
|
||||||
return new BindingRecord(DIRECTIVE, 0, ast, 0, propertyName, null, null, setter, null,
|
|
||||||
directiveRecord);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class BindingRecord {
|
||||||
|
constructor(public mode: string, public target: BindingTarget, public implicitReceiver: any,
|
||||||
|
public ast: AST, public setter: SetterFn, public lifecycleEvent: string,
|
||||||
|
public directiveRecord: DirectiveRecord) {}
|
||||||
|
|
||||||
|
isDirectiveLifecycle(): boolean { return this.mode === DIRECTIVE_LIFECYCLE; }
|
||||||
|
|
||||||
|
callOnChange(): boolean {
|
||||||
|
return isPresent(this.directiveRecord) && this.directiveRecord.callOnChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
isDefaultChangeDetection(): boolean {
|
||||||
|
return isBlank(this.directiveRecord) || this.directiveRecord.isDefaultChangeDetection();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static createDirectiveOnCheck(directiveRecord: DirectiveRecord): BindingRecord {
|
static createDirectiveOnCheck(directiveRecord: DirectiveRecord): BindingRecord {
|
||||||
return new BindingRecord(DIRECTIVE_LIFECYCLE, 0, null, 0, null, null, null, null, "onCheck",
|
return new BindingRecord(DIRECTIVE_LIFECYCLE, null, 0, null, null, "onCheck", directiveRecord);
|
||||||
directiveRecord);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static createDirectiveOnInit(directiveRecord: DirectiveRecord): BindingRecord {
|
static createDirectiveOnInit(directiveRecord: DirectiveRecord): BindingRecord {
|
||||||
return new BindingRecord(DIRECTIVE_LIFECYCLE, 0, null, 0, null, null, null, null, "onInit",
|
return new BindingRecord(DIRECTIVE_LIFECYCLE, null, 0, null, null, "onInit", directiveRecord);
|
||||||
directiveRecord);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static createDirectiveOnChange(directiveRecord: DirectiveRecord): BindingRecord {
|
static createDirectiveOnChange(directiveRecord: DirectiveRecord): BindingRecord {
|
||||||
return new BindingRecord(DIRECTIVE_LIFECYCLE, 0, null, 0, null, null, null, null, "onChange",
|
return new BindingRecord(DIRECTIVE_LIFECYCLE, null, 0, null, null, "onChange", directiveRecord);
|
||||||
directiveRecord);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static createForDirective(ast: AST, propertyName: string, setter: SetterFn,
|
||||||
|
directiveRecord: DirectiveRecord): BindingRecord {
|
||||||
|
var t = new BindingTarget(DIRECTIVE, null, propertyName, null, ast.toString());
|
||||||
|
return new BindingRecord(DIRECTIVE, t, 0, ast, setter, null, directiveRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static createForElementProperty(ast: AST, elementIndex: number,
|
static createForElementProperty(ast: AST, elementIndex: number,
|
||||||
propertyName: string): BindingRecord {
|
propertyName: string): BindingRecord {
|
||||||
return new BindingRecord(ELEMENT_PROPERTY, 0, ast, elementIndex, propertyName, null, null, null,
|
var t = new BindingTarget(ELEMENT_PROPERTY, elementIndex, propertyName, null, ast.toString());
|
||||||
null, null);
|
return new BindingRecord(BINDING, t, 0, ast, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createForElementAttribute(ast: AST, elementIndex: number,
|
static createForElementAttribute(ast: AST, elementIndex: number,
|
||||||
attributeName: string): BindingRecord {
|
attributeName: string): BindingRecord {
|
||||||
return new BindingRecord(ELEMENT_ATTRIBUTE, 0, ast, elementIndex, attributeName, null, null,
|
var t = new BindingTarget(ELEMENT_ATTRIBUTE, elementIndex, attributeName, null, ast.toString());
|
||||||
null, null, null);
|
return new BindingRecord(BINDING, t, 0, ast, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createForElementClass(ast: AST, elementIndex: number, className: string): BindingRecord {
|
static createForElementClass(ast: AST, elementIndex: number, className: string): BindingRecord {
|
||||||
return new BindingRecord(ELEMENT_CLASS, 0, ast, elementIndex, className, null, null, null, null,
|
var t = new BindingTarget(ELEMENT_CLASS, elementIndex, className, null, ast.toString());
|
||||||
null);
|
return new BindingRecord(BINDING, t, 0, ast, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createForElementStyle(ast: AST, elementIndex: number, styleName: string,
|
static createForElementStyle(ast: AST, elementIndex: number, styleName: string,
|
||||||
unit: string): BindingRecord {
|
unit: string): BindingRecord {
|
||||||
return new BindingRecord(ELEMENT_STYLE, 0, ast, elementIndex, styleName, unit, null, null, null,
|
var t = new BindingTarget(ELEMENT_STYLE, elementIndex, styleName, unit, ast.toString());
|
||||||
null);
|
return new BindingRecord(BINDING, t, 0, ast, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static createForHostProperty(directiveIndex: DirectiveIndex, ast: AST,
|
static createForHostProperty(directiveIndex: DirectiveIndex, ast: AST,
|
||||||
propertyName: string): BindingRecord {
|
propertyName: string): BindingRecord {
|
||||||
return new BindingRecord(ELEMENT_PROPERTY, directiveIndex, ast, directiveIndex.elementIndex,
|
var t = new BindingTarget(ELEMENT_PROPERTY, directiveIndex.elementIndex, propertyName, null,
|
||||||
propertyName, null, null, null, null, null);
|
ast.toString());
|
||||||
|
return new BindingRecord(BINDING, t, directiveIndex, ast, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createForHostAttribute(directiveIndex: DirectiveIndex, ast: AST,
|
static createForHostAttribute(directiveIndex: DirectiveIndex, ast: AST,
|
||||||
attributeName: string): BindingRecord {
|
attributeName: string): BindingRecord {
|
||||||
return new BindingRecord(ELEMENT_ATTRIBUTE, directiveIndex, ast, directiveIndex.elementIndex,
|
var t = new BindingTarget(ELEMENT_ATTRIBUTE, directiveIndex.elementIndex, attributeName, null,
|
||||||
attributeName, null, null, null, null, null);
|
ast.toString());
|
||||||
|
return new BindingRecord(BINDING, t, directiveIndex, ast, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createForHostClass(directiveIndex: DirectiveIndex, ast: AST,
|
static createForHostClass(directiveIndex: DirectiveIndex, ast: AST,
|
||||||
className: string): BindingRecord {
|
className: string): BindingRecord {
|
||||||
return new BindingRecord(ELEMENT_CLASS, directiveIndex, ast, directiveIndex.elementIndex,
|
var t = new BindingTarget(ELEMENT_CLASS, directiveIndex.elementIndex, className, null,
|
||||||
className, null, null, null, null, null);
|
ast.toString());
|
||||||
|
return new BindingRecord(BINDING, t, directiveIndex, ast, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createForHostStyle(directiveIndex: DirectiveIndex, ast: AST, styleName: string,
|
static createForHostStyle(directiveIndex: DirectiveIndex, ast: AST, styleName: string,
|
||||||
unit: string): BindingRecord {
|
unit: string): BindingRecord {
|
||||||
return new BindingRecord(ELEMENT_STYLE, directiveIndex, ast, directiveIndex.elementIndex,
|
var t = new BindingTarget(ELEMENT_STYLE, directiveIndex.elementIndex, styleName, unit,
|
||||||
styleName, unit, null, null, null, null);
|
ast.toString());
|
||||||
|
return new BindingRecord(BINDING, t, directiveIndex, ast, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static createForTextNode(ast: AST, elementIndex: number): BindingRecord {
|
static createForTextNode(ast: AST, elementIndex: number): BindingRecord {
|
||||||
return new BindingRecord(TEXT_NODE, 0, ast, elementIndex, null, null, null, null, null, null);
|
var t = new BindingTarget(TEXT_NODE, elementIndex, null, null, ast.toString());
|
||||||
|
return new BindingRecord(BINDING, t, 0, ast, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static createForEvent(ast: AST, eventName: string, elementIndex: number): BindingRecord {
|
static createForEvent(ast: AST, eventName: string, elementIndex: number): BindingRecord {
|
||||||
return new BindingRecord(EVENT, 0, ast, elementIndex, null, null, eventName, null, null, null);
|
var t = new BindingTarget(EVENT, elementIndex, eventName, null, ast.toString());
|
||||||
|
return new BindingRecord(EVENT, t, 0, ast, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createForHostEvent(ast: AST, eventName: string,
|
static createForHostEvent(ast: AST, eventName: string,
|
||||||
directiveRecord: DirectiveRecord): BindingRecord {
|
directiveRecord: DirectiveRecord): BindingRecord {
|
||||||
var directiveIndex = directiveRecord.directiveIndex;
|
var directiveIndex = directiveRecord.directiveIndex;
|
||||||
return new BindingRecord(EVENT, directiveIndex, ast, directiveIndex.elementIndex, null, null,
|
var t =
|
||||||
eventName, null, null, directiveRecord);
|
new BindingTarget(HOST_EVENT, directiveIndex.elementIndex, eventName, null, ast.toString());
|
||||||
|
return new BindingRecord(HOST_EVENT, t, directiveIndex, ast, null, null, directiveRecord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ export {
|
||||||
} from './interfaces';
|
} from './interfaces';
|
||||||
export {CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED, ON_PUSH, DEFAULT} from './constants';
|
export {CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED, ON_PUSH, DEFAULT} from './constants';
|
||||||
export {DynamicProtoChangeDetector} from './proto_change_detector';
|
export {DynamicProtoChangeDetector} from './proto_change_detector';
|
||||||
export {BindingRecord} from './binding_record';
|
export {BindingRecord, BindingTarget} from './binding_record';
|
||||||
export {DirectiveIndex, DirectiveRecord} from './directive_record';
|
export {DirectiveIndex, DirectiveRecord} from './directive_record';
|
||||||
export {DynamicChangeDetector} from './dynamic_change_detector';
|
export {DynamicChangeDetector} from './dynamic_change_detector';
|
||||||
export {ChangeDetectorRef} from './change_detector_ref';
|
export {ChangeDetectorRef} from './change_detector_ref';
|
||||||
|
@ -93,13 +93,14 @@ export class PreGeneratedChangeDetection extends ChangeDetection {
|
||||||
|
|
||||||
static isSupported(): boolean { return PregenProtoChangeDetector.isSupported(); }
|
static isSupported(): boolean { return PregenProtoChangeDetector.isSupported(); }
|
||||||
|
|
||||||
createProtoChangeDetector(definition: ChangeDetectorDefinition): ProtoChangeDetector {
|
getProtoChangeDetector(id: string, definition: ChangeDetectorDefinition): ProtoChangeDetector {
|
||||||
var id = definition.id;
|
|
||||||
if (StringMapWrapper.contains(this._protoChangeDetectorFactories, id)) {
|
if (StringMapWrapper.contains(this._protoChangeDetectorFactories, id)) {
|
||||||
return StringMapWrapper.get(this._protoChangeDetectorFactories, id)(definition);
|
return StringMapWrapper.get(this._protoChangeDetectorFactories, id)(definition);
|
||||||
}
|
}
|
||||||
return this._dynamicChangeDetection.createProtoChangeDetector(definition);
|
return this._dynamicChangeDetection.getProtoChangeDetector(id, definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get generateDetectors(): boolean { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,9 +111,11 @@ export class PreGeneratedChangeDetection extends ChangeDetection {
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DynamicChangeDetection extends ChangeDetection {
|
export class DynamicChangeDetection extends ChangeDetection {
|
||||||
createProtoChangeDetector(definition: ChangeDetectorDefinition): ProtoChangeDetector {
|
getProtoChangeDetector(id: string, definition: ChangeDetectorDefinition): ProtoChangeDetector {
|
||||||
return new DynamicProtoChangeDetector(definition);
|
return new DynamicProtoChangeDetector(definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get generateDetectors(): boolean { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,7 +129,9 @@ export class DynamicChangeDetection extends ChangeDetection {
|
||||||
export class JitChangeDetection extends ChangeDetection {
|
export class JitChangeDetection extends ChangeDetection {
|
||||||
static isSupported(): boolean { return JitProtoChangeDetector.isSupported(); }
|
static isSupported(): boolean { return JitProtoChangeDetector.isSupported(); }
|
||||||
|
|
||||||
createProtoChangeDetector(definition: ChangeDetectorDefinition): ProtoChangeDetector {
|
getProtoChangeDetector(id: string, definition: ChangeDetectorDefinition): ProtoChangeDetector {
|
||||||
return new JitProtoChangeDetector(definition);
|
return new JitProtoChangeDetector(definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get generateDetectors(): boolean { return true; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {ProtoRecord, RecordType} from './proto_record';
|
||||||
import {CodegenNameUtil, sanitizeName} from './codegen_name_util';
|
import {CodegenNameUtil, sanitizeName} from './codegen_name_util';
|
||||||
import {CodegenLogicUtil} from './codegen_logic_util';
|
import {CodegenLogicUtil} from './codegen_logic_util';
|
||||||
import {EventBinding} from './event_binding';
|
import {EventBinding} from './event_binding';
|
||||||
|
import {BindingTarget} from './binding_record';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,9 +31,10 @@ export class ChangeDetectorJITGenerator {
|
||||||
_names: CodegenNameUtil;
|
_names: CodegenNameUtil;
|
||||||
_typeName: string;
|
_typeName: string;
|
||||||
|
|
||||||
constructor(public id: string, private changeDetectionStrategy: string,
|
constructor(private id: string, private changeDetectionStrategy: string,
|
||||||
public records: List<ProtoRecord>, public eventBindings: EventBinding[],
|
private records: List<ProtoRecord>, private propertyBindingTargets: BindingTarget[],
|
||||||
public directiveRecords: List<any>, private generateCheckNoChanges: boolean) {
|
private eventBindings: EventBinding[], private directiveRecords: List<any>,
|
||||||
|
private devMode: boolean) {
|
||||||
this._names =
|
this._names =
|
||||||
new CodegenNameUtil(this.records, this.eventBindings, this.directiveRecords, UTIL);
|
new CodegenNameUtil(this.records, this.eventBindings, this.directiveRecords, UTIL);
|
||||||
this._logic = new CodegenLogicUtil(this._names, UTIL, changeDetectionStrategy);
|
this._logic = new CodegenLogicUtil(this._names, UTIL, changeDetectionStrategy);
|
||||||
|
@ -41,9 +43,10 @@ export class ChangeDetectorJITGenerator {
|
||||||
|
|
||||||
generate(): Function {
|
generate(): Function {
|
||||||
var classDefinition = `
|
var classDefinition = `
|
||||||
var ${this._typeName} = function ${this._typeName}(dispatcher, protos, directiveRecords) {
|
var ${this._typeName} = function ${this._typeName}(dispatcher) {
|
||||||
${ABSTRACT_CHANGE_DETECTOR}.call(
|
${ABSTRACT_CHANGE_DETECTOR}.call(
|
||||||
this, ${JSON.stringify(this.id)}, dispatcher, protos, directiveRecords,
|
this, ${JSON.stringify(this.id)}, dispatcher, ${this.records.length},
|
||||||
|
${this._typeName}.gen_propertyBindingTargets, ${this._typeName}.gen_directiveIndices,
|
||||||
"${ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy)}");
|
"${ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy)}");
|
||||||
this.dehydrateDirectives(false);
|
this.dehydrateDirectives(false);
|
||||||
}
|
}
|
||||||
|
@ -70,13 +73,27 @@ export class ChangeDetectorJITGenerator {
|
||||||
|
|
||||||
${this._maybeGenDehydrateDirectives()}
|
${this._maybeGenDehydrateDirectives()}
|
||||||
|
|
||||||
|
${this._genPropertyBindingTargets()};
|
||||||
|
|
||||||
|
${this._genDirectiveIndices()};
|
||||||
|
|
||||||
return function(dispatcher) {
|
return function(dispatcher) {
|
||||||
return new ${this._typeName}(dispatcher, protos, directiveRecords);
|
return new ${this._typeName}(dispatcher);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos',
|
|
||||||
'directiveRecords', classDefinition)(
|
return new Function(ABSTRACT_CHANGE_DETECTOR, UTIL, classDefinition)(AbstractChangeDetector,
|
||||||
AbstractChangeDetector, ChangeDetectionUtil, this.records, this.directiveRecords);
|
ChangeDetectionUtil);
|
||||||
|
}
|
||||||
|
|
||||||
|
_genPropertyBindingTargets(): string {
|
||||||
|
var targets = this._logic.genPropertyBindingTargets(this.propertyBindingTargets, true);
|
||||||
|
return `${this._typeName}.gen_propertyBindingTargets = ${targets};`;
|
||||||
|
}
|
||||||
|
|
||||||
|
_genDirectiveIndices(): string {
|
||||||
|
var indices = this._logic.genDirectiveIndices(this.directiveRecords);
|
||||||
|
return `${this._typeName}.gen_directiveIndices = ${indices};`;
|
||||||
}
|
}
|
||||||
|
|
||||||
_maybeGenHandleEventInternal(): string {
|
_maybeGenHandleEventInternal(): string {
|
||||||
|
@ -156,7 +173,7 @@ export class ChangeDetectorJITGenerator {
|
||||||
var lines = ListWrapper.createFixedSize(directiveFieldNames.length);
|
var lines = ListWrapper.createFixedSize(directiveFieldNames.length);
|
||||||
for (var i = 0, iLen = directiveFieldNames.length; i < iLen; ++i) {
|
for (var i = 0, iLen = directiveFieldNames.length; i < iLen; ++i) {
|
||||||
lines[i] = `${directiveFieldNames[i]} = directives.getDirectiveFor(
|
lines[i] = `${directiveFieldNames[i]} = directives.getDirectiveFor(
|
||||||
${this._names.getDirectivesAccessorName()}[${i}].directiveIndex);`;
|
${this._names.getDirectivesAccessorName()}[${i}]);`;
|
||||||
}
|
}
|
||||||
return lines.join('\n');
|
return lines.join('\n');
|
||||||
}
|
}
|
||||||
|
@ -284,9 +301,9 @@ export class ChangeDetectorJITGenerator {
|
||||||
var oldValue = this._names.getFieldName(r.selfIndex);
|
var oldValue = this._names.getFieldName(r.selfIndex);
|
||||||
|
|
||||||
var br = r.bindingRecord;
|
var br = r.bindingRecord;
|
||||||
if (br.isDirective()) {
|
if (br.target.isDirective()) {
|
||||||
var directiveProperty =
|
var directiveProperty =
|
||||||
`${this._names.getDirectiveName(br.directiveRecord.directiveIndex)}.${br.propertyName}`;
|
`${this._names.getDirectiveName(br.directiveRecord.directiveIndex)}.${br.target.name}`;
|
||||||
return `
|
return `
|
||||||
${this._genThrowOnChangeCheck(oldValue, newValue)}
|
${this._genThrowOnChangeCheck(oldValue, newValue)}
|
||||||
${directiveProperty} = ${newValue};
|
${directiveProperty} = ${newValue};
|
||||||
|
@ -301,7 +318,7 @@ export class ChangeDetectorJITGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
_genThrowOnChangeCheck(oldValue: string, newValue: string): string {
|
_genThrowOnChangeCheck(oldValue: string, newValue: string): string {
|
||||||
if (this.generateCheckNoChanges) {
|
if (this.devMode) {
|
||||||
return `
|
return `
|
||||||
if(throwOnChange) {
|
if(throwOnChange) {
|
||||||
this.throwOnChangeError(${oldValue}, ${newValue});
|
this.throwOnChangeError(${oldValue}, ${newValue});
|
||||||
|
@ -313,7 +330,7 @@ export class ChangeDetectorJITGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
_genCheckNoChanges(): string {
|
_genCheckNoChanges(): string {
|
||||||
if (this.generateCheckNoChanges) {
|
if (this.devMode) {
|
||||||
return `${this._typeName}.prototype.checkNoChanges = function() { this.runDetectChanges(true); }`;
|
return `${this._typeName}.prototype.checkNoChanges = function() { this.runDetectChanges(true); }`;
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
|
@ -330,7 +347,9 @@ export class ChangeDetectorJITGenerator {
|
||||||
_maybeFirstInBinding(r: ProtoRecord): string {
|
_maybeFirstInBinding(r: ProtoRecord): string {
|
||||||
var prev = ChangeDetectionUtil.protoByIndex(this.records, r.selfIndex - 1);
|
var prev = ChangeDetectionUtil.protoByIndex(this.records, r.selfIndex - 1);
|
||||||
var firstInBindng = isBlank(prev) || prev.bindingRecord !== r.bindingRecord;
|
var firstInBindng = isBlank(prev) || prev.bindingRecord !== r.bindingRecord;
|
||||||
return firstInBindng ? `${this._names.getFirstProtoInCurrentBinding()} = ${r.selfIndex};` : '';
|
return firstInBindng && !r.bindingRecord.isDirectiveLifecycle() ?
|
||||||
|
`${this._names.getPropertyBindingIndex()} = ${r.propertyBindingIndex};` :
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
|
|
||||||
_maybeGenLastInDirective(r: ProtoRecord): string {
|
_maybeGenLastInDirective(r: ProtoRecord): string {
|
||||||
|
|
|
@ -16,6 +16,8 @@ import {
|
||||||
isDefaultChangeDetectionStrategy
|
isDefaultChangeDetectionStrategy
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import {implementsOnDestroy} from './pipe_lifecycle_reflector';
|
import {implementsOnDestroy} from './pipe_lifecycle_reflector';
|
||||||
|
import {BindingTarget} from './binding_record';
|
||||||
|
import {DirectiveIndex} from './directive_record';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -201,4 +203,13 @@ export class ChangeDetectionUtil {
|
||||||
pipe.onDestroy();
|
pipe.onDestroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bindingTarget(mode: string, elementIndex: number, name: string, unit: string,
|
||||||
|
debug: string): BindingTarget {
|
||||||
|
return new BindingTarget(mode, elementIndex, name, unit, debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
static directiveIndex(elementIndex: number, directiveIndex: number): DirectiveIndex {
|
||||||
|
return new DirectiveIndex(elementIndex, directiveIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,8 @@ export function coalesce(records: ProtoRecord[]): ProtoRecord[] {
|
||||||
|
|
||||||
function _selfRecord(r: ProtoRecord, contextIndex: number, selfIndex: number): ProtoRecord {
|
function _selfRecord(r: ProtoRecord, contextIndex: number, selfIndex: number): ProtoRecord {
|
||||||
return new ProtoRecord(RecordType.SELF, "self", null, [], r.fixedArgs, contextIndex,
|
return new ProtoRecord(RecordType.SELF, "self", null, [], r.fixedArgs, contextIndex,
|
||||||
r.directiveIndex, selfIndex, r.bindingRecord, r.expressionAsString,
|
r.directiveIndex, selfIndex, r.bindingRecord, r.lastInBinding,
|
||||||
r.lastInBinding, r.lastInDirective, false, false);
|
r.lastInDirective, false, false, r.propertyBindingIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _findMatching(r: ProtoRecord, rs: List<ProtoRecord>) {
|
function _findMatching(r: ProtoRecord, rs: List<ProtoRecord>) {
|
||||||
|
@ -70,9 +70,9 @@ function _replaceIndices(r: ProtoRecord, selfIndex: number, indexMap: Map<any, a
|
||||||
var args = ListWrapper.map(r.args, (a) => _map(indexMap, a));
|
var args = ListWrapper.map(r.args, (a) => _map(indexMap, a));
|
||||||
var contextIndex = _map(indexMap, r.contextIndex);
|
var contextIndex = _map(indexMap, r.contextIndex);
|
||||||
return new ProtoRecord(r.mode, r.name, r.funcOrValue, args, r.fixedArgs, contextIndex,
|
return new ProtoRecord(r.mode, r.name, r.funcOrValue, args, r.fixedArgs, contextIndex,
|
||||||
r.directiveIndex, selfIndex, r.bindingRecord, r.expressionAsString,
|
r.directiveIndex, selfIndex, r.bindingRecord, r.lastInBinding,
|
||||||
r.lastInBinding, r.lastInDirective, r.argumentToPureFunction,
|
r.lastInDirective, r.argumentToPureFunction, r.referencedBySelf,
|
||||||
r.referencedBySelf);
|
r.propertyBindingIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _map(indexMap: Map<any, any>, value: number) {
|
function _map(indexMap: Map<any, any>, value: number) {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||||
import {BaseException, Json, StringWrapper} from 'angular2/src/facade/lang';
|
import {BaseException, Json, StringWrapper, isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||||
import {CodegenNameUtil} from './codegen_name_util';
|
import {CodegenNameUtil} from './codegen_name_util';
|
||||||
import {codify, combineGeneratedStrings, rawString} from './codegen_facade';
|
import {codify, combineGeneratedStrings, rawString} from './codegen_facade';
|
||||||
import {ProtoRecord, RecordType} from './proto_record';
|
import {ProtoRecord, RecordType} from './proto_record';
|
||||||
|
import {BindingTarget} from './binding_record';
|
||||||
import {DirectiveRecord} from './directive_record';
|
import {DirectiveRecord} from './directive_record';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,6 +124,23 @@ export class CodegenLogicUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
genPropertyBindingTargets(propertyBindingTargets: BindingTarget[], devMode: boolean): string {
|
||||||
|
var bs = propertyBindingTargets.map(b => {
|
||||||
|
if (isBlank(b)) return "null";
|
||||||
|
|
||||||
|
var debug = devMode ? codify(b.debug) : "null";
|
||||||
|
return `${this._utilName}.bindingTarget(${codify(b.mode)}, ${b.elementIndex}, ${codify(b.name)}, ${codify(b.unit)}, ${debug})`;
|
||||||
|
});
|
||||||
|
return `[${bs.join(", ")}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
genDirectiveIndices(directiveRecords: DirectiveRecord[]): string {
|
||||||
|
var bs = directiveRecords.map(
|
||||||
|
b =>
|
||||||
|
`${this._utilName}.directiveIndex(${b.directiveIndex.elementIndex}, ${b.directiveIndex.directiveIndex})`);
|
||||||
|
return `[${bs.join(", ")}]`;
|
||||||
|
}
|
||||||
|
|
||||||
_genInterpolation(protoRec: ProtoRecord): string {
|
_genInterpolation(protoRec: ProtoRecord): string {
|
||||||
var iVals = [];
|
var iVals = [];
|
||||||
for (var i = 0; i < protoRec.args.length; ++i) {
|
for (var i = 0; i < protoRec.args.length; ++i) {
|
||||||
|
|
|
@ -10,8 +10,8 @@ import {EventBinding} from './event_binding';
|
||||||
// detection will fail.
|
// detection will fail.
|
||||||
const _ALREADY_CHECKED_ACCESSOR = "alreadyChecked";
|
const _ALREADY_CHECKED_ACCESSOR = "alreadyChecked";
|
||||||
const _CONTEXT_ACCESSOR = "context";
|
const _CONTEXT_ACCESSOR = "context";
|
||||||
const _FIRST_PROTO_IN_CURRENT_BINDING = "firstProtoInCurrentBinding";
|
const _PROP_BINDING_INDEX = "propertyBindingIndex";
|
||||||
const _DIRECTIVES_ACCESSOR = "directiveRecords";
|
const _DIRECTIVES_ACCESSOR = "directiveIndices";
|
||||||
const _DISPATCHER_ACCESSOR = "dispatcher";
|
const _DISPATCHER_ACCESSOR = "dispatcher";
|
||||||
const _LOCALS_ACCESSOR = "locals";
|
const _LOCALS_ACCESSOR = "locals";
|
||||||
const _MODE_ACCESSOR = "mode";
|
const _MODE_ACCESSOR = "mode";
|
||||||
|
@ -79,9 +79,7 @@ export class CodegenNameUtil {
|
||||||
|
|
||||||
getModeName(): string { return this._addFieldPrefix(_MODE_ACCESSOR); }
|
getModeName(): string { return this._addFieldPrefix(_MODE_ACCESSOR); }
|
||||||
|
|
||||||
getFirstProtoInCurrentBinding(): string {
|
getPropertyBindingIndex(): string { return this._addFieldPrefix(_PROP_BINDING_INDEX); }
|
||||||
return this._addFieldPrefix(_FIRST_PROTO_IN_CURRENT_BINDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
getLocalName(idx: number): string { return `l_${this._sanitizedNames[idx]}`; }
|
getLocalName(idx: number): string { return `l_${this._sanitizedNames[idx]}`; }
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,11 @@ import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/faca
|
||||||
|
|
||||||
import {AbstractChangeDetector} from './abstract_change_detector';
|
import {AbstractChangeDetector} from './abstract_change_detector';
|
||||||
import {EventBinding} from './event_binding';
|
import {EventBinding} from './event_binding';
|
||||||
import {BindingRecord} from './binding_record';
|
import {BindingRecord, BindingTarget} from './binding_record';
|
||||||
|
import {DirectiveRecord, DirectiveIndex} from './directive_record';
|
||||||
import {Locals} from './parser/locals';
|
import {Locals} from './parser/locals';
|
||||||
import {ChangeDetectionUtil, SimpleChange} from './change_detection_util';
|
import {ChangeDetectionUtil, SimpleChange} from './change_detection_util';
|
||||||
|
|
||||||
|
|
||||||
import {ProtoRecord, RecordType} from './proto_record';
|
import {ProtoRecord, RecordType} from './proto_record';
|
||||||
|
|
||||||
export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
||||||
|
@ -23,12 +23,13 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
||||||
prevContexts: List<any>;
|
prevContexts: List<any>;
|
||||||
directives: any = null;
|
directives: any = null;
|
||||||
|
|
||||||
constructor(id: string, changeDetectionStrategy: string, dispatcher: any,
|
constructor(id: string, dispatcher: any, numberOfPropertyProtoRecords: number,
|
||||||
protos: List<ProtoRecord>, public eventBindings: EventBinding[],
|
propertyBindingTargets: BindingTarget[], directiveIndices: DirectiveIndex[],
|
||||||
directiveRecords: List<any>) {
|
modeOnHydrate: string, private records: ProtoRecord[],
|
||||||
super(id, dispatcher, protos, directiveRecords,
|
private eventBindings: EventBinding[], private directiveRecords: DirectiveRecord[]) {
|
||||||
ChangeDetectionUtil.changeDetectionMode(changeDetectionStrategy));
|
super(id, dispatcher, numberOfPropertyProtoRecords, propertyBindingTargets, directiveIndices,
|
||||||
var len = protos.length + 1;
|
modeOnHydrate);
|
||||||
|
var len = records.length + 1;
|
||||||
this.values = ListWrapper.createFixedSize(len);
|
this.values = ListWrapper.createFixedSize(len);
|
||||||
this.localPipes = ListWrapper.createFixedSize(len);
|
this.localPipes = ListWrapper.createFixedSize(len);
|
||||||
this.prevContexts = ListWrapper.createFixedSize(len);
|
this.prevContexts = ListWrapper.createFixedSize(len);
|
||||||
|
@ -109,7 +110,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
||||||
checkNoChanges(): void { this.runDetectChanges(true); }
|
checkNoChanges(): void { this.runDetectChanges(true); }
|
||||||
|
|
||||||
detectChangesInRecordsInternal(throwOnChange: boolean) {
|
detectChangesInRecordsInternal(throwOnChange: boolean) {
|
||||||
var protos = this.protos;
|
var protos = this.records;
|
||||||
|
|
||||||
var changes = null;
|
var changes = null;
|
||||||
var isChanged = false;
|
var isChanged = false;
|
||||||
|
@ -119,7 +120,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
||||||
var directiveRecord = bindingRecord.directiveRecord;
|
var directiveRecord = bindingRecord.directiveRecord;
|
||||||
|
|
||||||
if (this._firstInBinding(proto)) {
|
if (this._firstInBinding(proto)) {
|
||||||
this.firstProtoInCurrentBinding = proto.selfIndex;
|
this.propertyBindingIndex = proto.propertyBindingIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proto.isLifeCycleRecord()) {
|
if (proto.isLifeCycleRecord()) {
|
||||||
|
@ -154,7 +155,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
||||||
}
|
}
|
||||||
|
|
||||||
_firstInBinding(r: ProtoRecord): boolean {
|
_firstInBinding(r: ProtoRecord): boolean {
|
||||||
var prev = ChangeDetectionUtil.protoByIndex(this.protos, r.selfIndex - 1);
|
var prev = ChangeDetectionUtil.protoByIndex(this.records, r.selfIndex - 1);
|
||||||
return isBlank(prev) || prev.bindingRecord !== r.bindingRecord;
|
return isBlank(prev) || prev.bindingRecord !== r.bindingRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +172,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
||||||
|
|
||||||
_updateDirectiveOrElement(change, bindingRecord) {
|
_updateDirectiveOrElement(change, bindingRecord) {
|
||||||
if (isBlank(bindingRecord.directiveRecord)) {
|
if (isBlank(bindingRecord.directiveRecord)) {
|
||||||
this.dispatcher.notifyOnBinding(bindingRecord, change.currentValue);
|
super.notifyDispatcher(change.currentValue);
|
||||||
} else {
|
} else {
|
||||||
var directiveIndex = bindingRecord.directiveRecord.directiveIndex;
|
var directiveIndex = bindingRecord.directiveRecord.directiveIndex;
|
||||||
bindingRecord.setter(this._getDirectiveFor(directiveIndex), change.currentValue);
|
bindingRecord.setter(this._getDirectiveFor(directiveIndex), change.currentValue);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import {ProtoRecord} from './proto_record';
|
|
||||||
import {BaseException} from "angular2/src/facade/lang";
|
import {BaseException} from "angular2/src/facade/lang";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,9 +10,9 @@ import {BaseException} from "angular2/src/facade/lang";
|
||||||
* This exception is only thrown in dev mode.
|
* This exception is only thrown in dev mode.
|
||||||
*/
|
*/
|
||||||
export class ExpressionChangedAfterItHasBeenCheckedException extends BaseException {
|
export class ExpressionChangedAfterItHasBeenCheckedException extends BaseException {
|
||||||
constructor(proto: ProtoRecord, change: any, context: any) {
|
constructor(exp: string, oldValue: any, currValue: any, context: any) {
|
||||||
super(`Expression '${proto.expressionAsString}' has changed after it was checked. ` +
|
super(`Expression '${exp}' has changed after it was checked. ` +
|
||||||
`Previous value: '${change.previousValue}'. Current value: '${change.currentValue}'`);
|
`Previous value: '${oldValue}'. Current value: '${currValue}'`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,10 +27,9 @@ export class ChangeDetectionError extends BaseException {
|
||||||
*/
|
*/
|
||||||
location: string;
|
location: string;
|
||||||
|
|
||||||
constructor(proto: ProtoRecord, originalException: any, originalStack: any, context: any) {
|
constructor(exp: string, originalException: any, originalStack: any, context: any) {
|
||||||
super(`${originalException} in [${proto.expressionAsString}]`, originalException, originalStack,
|
super(`${originalException} in [${exp}]`, originalException, originalStack, context);
|
||||||
context);
|
this.location = exp;
|
||||||
this.location = proto.expressionAsString;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {List} from 'angular2/src/facade/collection';
|
import {List} from 'angular2/src/facade/collection';
|
||||||
import {CONST} from 'angular2/src/facade/lang';
|
import {CONST} from 'angular2/src/facade/lang';
|
||||||
import {Locals} from './parser/locals';
|
import {Locals} from './parser/locals';
|
||||||
import {BindingRecord} from './binding_record';
|
import {BindingTarget, BindingRecord} from './binding_record';
|
||||||
import {DirectiveIndex, DirectiveRecord} from './directive_record';
|
import {DirectiveIndex, DirectiveRecord} from './directive_record';
|
||||||
import {ChangeDetectorRef} from './change_detector_ref';
|
import {ChangeDetectorRef} from './change_detector_ref';
|
||||||
|
|
||||||
|
@ -32,9 +32,11 @@ import {ChangeDetectorRef} from './change_detector_ref';
|
||||||
*/
|
*/
|
||||||
@CONST()
|
@CONST()
|
||||||
export class ChangeDetection {
|
export class ChangeDetection {
|
||||||
createProtoChangeDetector(definition: ChangeDetectorDefinition): ProtoChangeDetector {
|
getProtoChangeDetector(id: string, definition: ChangeDetectorDefinition): ProtoChangeDetector {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get generateDetectors(): boolean { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DebugContext {
|
export class DebugContext {
|
||||||
|
@ -44,7 +46,7 @@ export class DebugContext {
|
||||||
|
|
||||||
export interface ChangeDispatcher {
|
export interface ChangeDispatcher {
|
||||||
getDebugContext(elementIndex: number, directiveIndex: DirectiveIndex): DebugContext;
|
getDebugContext(elementIndex: number, directiveIndex: DirectiveIndex): DebugContext;
|
||||||
notifyOnBinding(bindingRecord: BindingRecord, value: any): void;
|
notifyOnBinding(bindingTarget: BindingTarget, value: any): void;
|
||||||
notifyOnAllChangesDone(): void;
|
notifyOnAllChangesDone(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,5 +74,5 @@ export interface ProtoChangeDetector { instantiate(dispatcher: ChangeDispatcher)
|
||||||
export class ChangeDetectorDefinition {
|
export class ChangeDetectorDefinition {
|
||||||
constructor(public id: string, public strategy: string, public variableNames: List<string>,
|
constructor(public id: string, public strategy: string, public variableNames: List<string>,
|
||||||
public bindingRecords: BindingRecord[], public eventRecords: BindingRecord[],
|
public bindingRecords: BindingRecord[], public eventRecords: BindingRecord[],
|
||||||
public directiveRecords: DirectiveRecord[], public generateCheckNoChanges: boolean) {}
|
public directiveRecords: DirectiveRecord[], public devMode: boolean) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||||
|
import {isPresent} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import {ProtoChangeDetector, ChangeDetector, ChangeDetectorDefinition} from './interfaces';
|
import {ProtoChangeDetector, ChangeDetector, ChangeDetectorDefinition} from './interfaces';
|
||||||
import {ChangeDetectorJITGenerator} from './change_detection_jit_generator';
|
import {ChangeDetectorJITGenerator} from './change_detection_jit_generator';
|
||||||
|
@ -20,9 +21,11 @@ export class JitProtoChangeDetector implements ProtoChangeDetector {
|
||||||
_createFactory(definition: ChangeDetectorDefinition) {
|
_createFactory(definition: ChangeDetectorDefinition) {
|
||||||
var propertyBindingRecords = createPropertyRecords(definition);
|
var propertyBindingRecords = createPropertyRecords(definition);
|
||||||
var eventBindingRecords = createEventRecords(definition);
|
var eventBindingRecords = createEventRecords(definition);
|
||||||
|
var propertyBindingTargets = this.definition.bindingRecords.map(b => b.target);
|
||||||
|
|
||||||
return new ChangeDetectorJITGenerator(
|
return new ChangeDetectorJITGenerator(
|
||||||
definition.id, definition.strategy, propertyBindingRecords, eventBindingRecords,
|
definition.id, definition.strategy, propertyBindingRecords, propertyBindingTargets,
|
||||||
this.definition.directiveRecords, this.definition.generateCheckNoChanges)
|
eventBindingRecords, this.definition.directiveRecords, this.definition.devMode)
|
||||||
.generate();
|
.generate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
library angular2.src.change_detection.pregen_proto_change_detector;
|
library angular2.src.change_detection.pregen_proto_change_detector;
|
||||||
|
|
||||||
import 'package:angular2/src/change_detection/coalesce.dart';
|
|
||||||
import 'package:angular2/src/change_detection/directive_record.dart';
|
|
||||||
import 'package:angular2/src/change_detection/interfaces.dart';
|
import 'package:angular2/src/change_detection/interfaces.dart';
|
||||||
import 'package:angular2/src/change_detection/proto_change_detector.dart';
|
|
||||||
import 'package:angular2/src/change_detection/proto_record.dart';
|
|
||||||
import 'package:angular2/src/facade/lang.dart' show looseIdentical;
|
import 'package:angular2/src/facade/lang.dart' show looseIdentical;
|
||||||
|
|
||||||
export 'dart:core' show List;
|
export 'dart:core' show List;
|
||||||
|
@ -26,8 +22,7 @@ export 'package:angular2/src/facade/lang.dart' show looseIdentical;
|
||||||
typedef ProtoChangeDetector PregenProtoChangeDetectorFactory(
|
typedef ProtoChangeDetector PregenProtoChangeDetectorFactory(
|
||||||
ChangeDetectorDefinition definition);
|
ChangeDetectorDefinition definition);
|
||||||
|
|
||||||
typedef ChangeDetector InstantiateMethod(dynamic dispatcher,
|
typedef ChangeDetector InstantiateMethod(dynamic dispatcher);
|
||||||
List<ProtoRecord> protoRecords, List<DirectiveRecord> directiveRecords);
|
|
||||||
|
|
||||||
/// Implementation of [ProtoChangeDetector] for use by pre-generated change
|
/// Implementation of [ProtoChangeDetector] for use by pre-generated change
|
||||||
/// detectors in Angular 2 Dart.
|
/// detectors in Angular 2 Dart.
|
||||||
|
@ -41,31 +36,18 @@ class PregenProtoChangeDetector extends ProtoChangeDetector {
|
||||||
/// Closure used to generate an actual [ChangeDetector].
|
/// Closure used to generate an actual [ChangeDetector].
|
||||||
final InstantiateMethod _instantiateMethod;
|
final InstantiateMethod _instantiateMethod;
|
||||||
|
|
||||||
// [ChangeDetector] dependencies.
|
|
||||||
final List<ProtoRecord> _protoRecords;
|
|
||||||
final List<DirectiveRecord> _directiveRecords;
|
|
||||||
|
|
||||||
/// Internal ctor.
|
/// Internal ctor.
|
||||||
PregenProtoChangeDetector._(this.id, this._instantiateMethod,
|
PregenProtoChangeDetector._(this.id, this._instantiateMethod);
|
||||||
this._protoRecords, this._directiveRecords);
|
|
||||||
|
|
||||||
static bool isSupported() => true;
|
static bool isSupported() => true;
|
||||||
|
|
||||||
factory PregenProtoChangeDetector(
|
factory PregenProtoChangeDetector(
|
||||||
InstantiateMethod instantiateMethod, ChangeDetectorDefinition def) {
|
InstantiateMethod instantiateMethod, ChangeDetectorDefinition def) {
|
||||||
// TODO(kegluneq): Pre-generate these (#2067).
|
return new PregenProtoChangeDetector._(def.id, instantiateMethod);
|
||||||
var recordBuilder = new ProtoRecordBuilder();
|
|
||||||
def.bindingRecords.forEach((b) {
|
|
||||||
recordBuilder.add(b, def.variableNames);
|
|
||||||
});
|
|
||||||
var protoRecords = coalesce(recordBuilder.records);
|
|
||||||
return new PregenProtoChangeDetector._(
|
|
||||||
def.id, instantiateMethod, protoRecords, def.directiveRecords);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
instantiate(dynamic dispatcher) =>
|
instantiate(dynamic dispatcher) => _instantiateMethod(dispatcher);
|
||||||
_instantiateMethod(dispatcher, _protoRecords, _directiveRecords);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provided as an optimization to cut down on '!' characters in generated
|
/// Provided as an optimization to cut down on '!' characters in generated
|
||||||
|
|
|
@ -29,7 +29,7 @@ import {
|
||||||
import {ChangeDetector, ProtoChangeDetector, ChangeDetectorDefinition} from './interfaces';
|
import {ChangeDetector, ProtoChangeDetector, ChangeDetectorDefinition} from './interfaces';
|
||||||
import {ChangeDetectionUtil} from './change_detection_util';
|
import {ChangeDetectionUtil} from './change_detection_util';
|
||||||
import {DynamicChangeDetector} from './dynamic_change_detector';
|
import {DynamicChangeDetector} from './dynamic_change_detector';
|
||||||
import {BindingRecord} from './binding_record';
|
import {BindingRecord, BindingTarget} from './binding_record';
|
||||||
import {DirectiveRecord, DirectiveIndex} from './directive_record';
|
import {DirectiveRecord, DirectiveIndex} from './directive_record';
|
||||||
import {EventBinding} from './event_binding';
|
import {EventBinding} from './event_binding';
|
||||||
|
|
||||||
|
@ -38,24 +38,30 @@ import {ProtoRecord, RecordType} from './proto_record';
|
||||||
|
|
||||||
export class DynamicProtoChangeDetector implements ProtoChangeDetector {
|
export class DynamicProtoChangeDetector implements ProtoChangeDetector {
|
||||||
_propertyBindingRecords: ProtoRecord[];
|
_propertyBindingRecords: ProtoRecord[];
|
||||||
|
_propertyBindingTargets: BindingTarget[];
|
||||||
_eventBindingRecords: EventBinding[];
|
_eventBindingRecords: EventBinding[];
|
||||||
|
_directiveIndices: DirectiveIndex[];
|
||||||
|
|
||||||
constructor(private definition: ChangeDetectorDefinition) {
|
constructor(private definition: ChangeDetectorDefinition) {
|
||||||
this._propertyBindingRecords = createPropertyRecords(definition);
|
this._propertyBindingRecords = createPropertyRecords(definition);
|
||||||
this._eventBindingRecords = createEventRecords(definition);
|
this._eventBindingRecords = createEventRecords(definition);
|
||||||
|
this._propertyBindingTargets = this.definition.bindingRecords.map(b => b.target);
|
||||||
|
this._directiveIndices = this.definition.directiveRecords.map(d => d.directiveIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
instantiate(dispatcher: any): ChangeDetector {
|
instantiate(dispatcher: any): ChangeDetector {
|
||||||
return new DynamicChangeDetector(this.definition.id, this.definition.strategy, dispatcher,
|
return new DynamicChangeDetector(
|
||||||
this._propertyBindingRecords, this._eventBindingRecords,
|
this.definition.id, dispatcher, this._propertyBindingRecords.length,
|
||||||
this.definition.directiveRecords);
|
this._propertyBindingTargets, this._directiveIndices,
|
||||||
|
ChangeDetectionUtil.changeDetectionMode(this.definition.strategy),
|
||||||
|
this._propertyBindingRecords, this._eventBindingRecords, this.definition.directiveRecords);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createPropertyRecords(definition: ChangeDetectorDefinition): ProtoRecord[] {
|
export function createPropertyRecords(definition: ChangeDetectorDefinition): ProtoRecord[] {
|
||||||
var recordBuilder = new ProtoRecordBuilder();
|
var recordBuilder = new ProtoRecordBuilder();
|
||||||
ListWrapper.forEach(definition.bindingRecords,
|
ListWrapper.forEachWithIndex(definition.bindingRecords,
|
||||||
(b) => { recordBuilder.add(b, definition.variableNames); });
|
(b, index) => recordBuilder.add(b, definition.variableNames, index));
|
||||||
return coalesce(recordBuilder.records);
|
return coalesce(recordBuilder.records);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +71,7 @@ export function createEventRecords(definition: ChangeDetectorDefinition): EventB
|
||||||
return definition.eventRecords.map(er => {
|
return definition.eventRecords.map(er => {
|
||||||
var records = _ConvertAstIntoProtoRecords.create(er, varNames);
|
var records = _ConvertAstIntoProtoRecords.create(er, varNames);
|
||||||
var dirIndex = er.implicitReceiver instanceof DirectiveIndex ? er.implicitReceiver : null;
|
var dirIndex = er.implicitReceiver instanceof DirectiveIndex ? er.implicitReceiver : null;
|
||||||
return new EventBinding(er.eventName, er.elementIndex, dirIndex, records);
|
return new EventBinding(er.target.name, er.target.elementIndex, dirIndex, records);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,13 +80,13 @@ export class ProtoRecordBuilder {
|
||||||
|
|
||||||
constructor() { this.records = []; }
|
constructor() { this.records = []; }
|
||||||
|
|
||||||
add(b: BindingRecord, variableNames: List<string> = null) {
|
add(b: BindingRecord, variableNames: string[], bindingIndex: number) {
|
||||||
var oldLast = ListWrapper.last(this.records);
|
var oldLast = ListWrapper.last(this.records);
|
||||||
if (isPresent(oldLast) && oldLast.bindingRecord.directiveRecord == b.directiveRecord) {
|
if (isPresent(oldLast) && oldLast.bindingRecord.directiveRecord == b.directiveRecord) {
|
||||||
oldLast.lastInDirective = false;
|
oldLast.lastInDirective = false;
|
||||||
}
|
}
|
||||||
var numberOfRecordsBefore = this.records.length;
|
var numberOfRecordsBefore = this.records.length;
|
||||||
this._appendRecords(b, variableNames);
|
this._appendRecords(b, variableNames, bindingIndex);
|
||||||
var newLast = ListWrapper.last(this.records);
|
var newLast = ListWrapper.last(this.records);
|
||||||
if (isPresent(newLast) && newLast !== oldLast) {
|
if (isPresent(newLast) && newLast !== oldLast) {
|
||||||
newLast.lastInBinding = true;
|
newLast.lastInBinding = true;
|
||||||
|
@ -99,29 +105,30 @@ export class ProtoRecordBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_appendRecords(b: BindingRecord, variableNames: List<string>) {
|
_appendRecords(b: BindingRecord, variableNames: string[], bindingIndex: number) {
|
||||||
if (b.isDirectiveLifecycle()) {
|
if (b.isDirectiveLifecycle()) {
|
||||||
this.records.push(new ProtoRecord(RecordType.DIRECTIVE_LIFECYCLE, b.lifecycleEvent, null, [],
|
this.records.push(new ProtoRecord(RecordType.DIRECTIVE_LIFECYCLE, b.lifecycleEvent, null, [],
|
||||||
[], -1, null, this.records.length + 1, b, null, false,
|
[], -1, null, this.records.length + 1, b, false, false,
|
||||||
false, false, false));
|
false, false, null));
|
||||||
} else {
|
} else {
|
||||||
_ConvertAstIntoProtoRecords.append(this.records, b, variableNames);
|
_ConvertAstIntoProtoRecords.append(this.records, b, variableNames, bindingIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ConvertAstIntoProtoRecords implements AstVisitor {
|
class _ConvertAstIntoProtoRecords implements AstVisitor {
|
||||||
constructor(private _records: List<ProtoRecord>, private _bindingRecord: BindingRecord,
|
constructor(private _records: List<ProtoRecord>, private _bindingRecord: BindingRecord,
|
||||||
private _expressionAsString: string, private _variableNames: List<any>) {}
|
private _variableNames: string[], private _bindingIndex: number) {}
|
||||||
|
|
||||||
static append(records: List<ProtoRecord>, b: BindingRecord, variableNames: List<any>) {
|
static append(records: List<ProtoRecord>, b: BindingRecord, variableNames: string[],
|
||||||
var c = new _ConvertAstIntoProtoRecords(records, b, b.ast.toString(), variableNames);
|
bindingIndex: number) {
|
||||||
|
var c = new _ConvertAstIntoProtoRecords(records, b, variableNames, bindingIndex);
|
||||||
b.ast.visit(c);
|
b.ast.visit(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static create(b: BindingRecord, variableNames: List<any>): ProtoRecord[] {
|
static create(b: BindingRecord, variableNames: List<any>): ProtoRecord[] {
|
||||||
var rec = [];
|
var rec = [];
|
||||||
_ConvertAstIntoProtoRecords.append(rec, b, variableNames);
|
_ConvertAstIntoProtoRecords.append(rec, b, variableNames, null);
|
||||||
rec[rec.length - 1].lastInBinding = true;
|
rec[rec.length - 1].lastInBinding = true;
|
||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
|
@ -261,12 +268,12 @@ class _ConvertAstIntoProtoRecords implements AstVisitor {
|
||||||
var selfIndex = this._records.length + 1;
|
var selfIndex = this._records.length + 1;
|
||||||
if (context instanceof DirectiveIndex) {
|
if (context instanceof DirectiveIndex) {
|
||||||
this._records.push(new ProtoRecord(type, name, funcOrValue, args, fixedArgs, -1, context,
|
this._records.push(new ProtoRecord(type, name, funcOrValue, args, fixedArgs, -1, context,
|
||||||
selfIndex, this._bindingRecord, this._expressionAsString,
|
selfIndex, this._bindingRecord, false, false, false, false,
|
||||||
false, false, false, false));
|
this._bindingIndex));
|
||||||
} else {
|
} else {
|
||||||
this._records.push(new ProtoRecord(type, name, funcOrValue, args, fixedArgs, context, null,
|
this._records.push(new ProtoRecord(type, name, funcOrValue, args, fixedArgs, context, null,
|
||||||
selfIndex, this._bindingRecord, this._expressionAsString,
|
selfIndex, this._bindingRecord, false, false, false, false,
|
||||||
false, false, false, false));
|
this._bindingIndex));
|
||||||
}
|
}
|
||||||
return selfIndex;
|
return selfIndex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,9 @@ export class ProtoRecord {
|
||||||
constructor(public mode: RecordType, public name: string, public funcOrValue,
|
constructor(public mode: RecordType, public name: string, public funcOrValue,
|
||||||
public args: List<any>, public fixedArgs: List<any>, public contextIndex: number,
|
public args: List<any>, public fixedArgs: List<any>, public contextIndex: number,
|
||||||
public directiveIndex: DirectiveIndex, public selfIndex: number,
|
public directiveIndex: DirectiveIndex, public selfIndex: number,
|
||||||
public bindingRecord: BindingRecord, public expressionAsString: string,
|
public bindingRecord: BindingRecord, public lastInBinding: boolean,
|
||||||
public lastInBinding: boolean, public lastInDirective: boolean,
|
public lastInDirective: boolean, public argumentToPureFunction: boolean,
|
||||||
public argumentToPureFunction: boolean, public referencedBySelf: boolean) {}
|
public referencedBySelf: boolean, public propertyBindingIndex: number) {}
|
||||||
|
|
||||||
isPureFunction(): boolean {
|
isPureFunction(): boolean {
|
||||||
return this.mode === RecordType.INTERPOLATE || this.mode === RecordType.COLLECTION_LITERAL;
|
return this.mode === RecordType.INTERPOLATE || this.mode === RecordType.COLLECTION_LITERAL;
|
||||||
|
|
|
@ -211,12 +211,10 @@ export class ProtoViewFactory {
|
||||||
var nestedPvVariableBindings = _collectNestedProtoViewsVariableBindings(nestedPvsWithIndex);
|
var nestedPvVariableBindings = _collectNestedProtoViewsVariableBindings(nestedPvsWithIndex);
|
||||||
var nestedPvVariableNames = _collectNestedProtoViewsVariableNames(nestedPvsWithIndex);
|
var nestedPvVariableNames = _collectNestedProtoViewsVariableNames(nestedPvsWithIndex);
|
||||||
|
|
||||||
var changeDetectorDefs =
|
var protoChangeDetectors =
|
||||||
_getChangeDetectorDefinitions(hostComponentBinding.metadata, nestedPvsWithIndex,
|
this._getProtoChangeDetectors(hostComponentBinding, nestedPvsWithIndex,
|
||||||
nestedPvVariableNames, allRenderDirectiveMetadata);
|
nestedPvVariableNames, allRenderDirectiveMetadata);
|
||||||
var protoChangeDetectors = ListWrapper.map(
|
|
||||||
changeDetectorDefs,
|
|
||||||
changeDetectorDef => this._changeDetection.createProtoChangeDetector(changeDetectorDef));
|
|
||||||
var appProtoViews = ListWrapper.createFixedSize(nestedPvsWithIndex.length);
|
var appProtoViews = ListWrapper.createFixedSize(nestedPvsWithIndex.length);
|
||||||
ListWrapper.forEach(nestedPvsWithIndex, (pvWithIndex: RenderProtoViewWithIndex) => {
|
ListWrapper.forEach(nestedPvsWithIndex, (pvWithIndex: RenderProtoViewWithIndex) => {
|
||||||
var appProtoView =
|
var appProtoView =
|
||||||
|
@ -230,6 +228,24 @@ export class ProtoViewFactory {
|
||||||
});
|
});
|
||||||
return appProtoViews;
|
return appProtoViews;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _getProtoChangeDetectors(hostComponentBinding: DirectiveBinding,
|
||||||
|
nestedPvsWithIndex: RenderProtoViewWithIndex[],
|
||||||
|
nestedPvVariableNames: string[][],
|
||||||
|
allRenderDirectiveMetadata: any[]): ProtoChangeDetector[] {
|
||||||
|
if (this._changeDetection.generateDetectors) {
|
||||||
|
var changeDetectorDefs =
|
||||||
|
_getChangeDetectorDefinitions(hostComponentBinding.metadata, nestedPvsWithIndex,
|
||||||
|
nestedPvVariableNames, allRenderDirectiveMetadata);
|
||||||
|
return changeDetectorDefs.map(changeDetectorDef =>
|
||||||
|
this._changeDetection.getProtoChangeDetector(
|
||||||
|
changeDetectorDef.id, changeDetectorDef));
|
||||||
|
} else {
|
||||||
|
var changeDetectorIds =
|
||||||
|
_getChangeDetectorDefinitionIds(hostComponentBinding.metadata, nestedPvsWithIndex);
|
||||||
|
return changeDetectorIds.map(id => this._changeDetection.getProtoChangeDetector(id, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -280,20 +296,33 @@ function _getChangeDetectorDefinitions(
|
||||||
var directiveRecords =
|
var directiveRecords =
|
||||||
bindingRecordsCreator.getDirectiveRecords(elementBinders, allRenderDirectiveMetadata);
|
bindingRecordsCreator.getDirectiveRecords(elementBinders, allRenderDirectiveMetadata);
|
||||||
var strategyName = DEFAULT;
|
var strategyName = DEFAULT;
|
||||||
var typeString;
|
|
||||||
if (pvWithIndex.renderProtoView.type === ViewType.COMPONENT) {
|
if (pvWithIndex.renderProtoView.type === ViewType.COMPONENT) {
|
||||||
strategyName = hostComponentMetadata.changeDetection;
|
strategyName = hostComponentMetadata.changeDetection;
|
||||||
|
}
|
||||||
|
var id = _protoViewId(hostComponentMetadata, pvWithIndex);
|
||||||
|
var variableNames = nestedPvVariableNames[pvWithIndex.index];
|
||||||
|
return new ChangeDetectorDefinition(id, strategyName, variableNames, propBindingRecords,
|
||||||
|
eventBindingRecords, directiveRecords, assertionsEnabled());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getChangeDetectorDefinitionIds(hostComponentMetadata: RenderDirectiveMetadata,
|
||||||
|
nestedPvsWithIndex: List<RenderProtoViewWithIndex>):
|
||||||
|
string[] {
|
||||||
|
return nestedPvsWithIndex.map(pvWithIndex => _protoViewId(hostComponentMetadata, pvWithIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
function _protoViewId(hostComponentMetadata: RenderDirectiveMetadata,
|
||||||
|
pvWithIndex: RenderProtoViewWithIndex): string {
|
||||||
|
var typeString;
|
||||||
|
if (pvWithIndex.renderProtoView.type === ViewType.COMPONENT) {
|
||||||
typeString = 'comp';
|
typeString = 'comp';
|
||||||
} else if (pvWithIndex.renderProtoView.type === ViewType.HOST) {
|
} else if (pvWithIndex.renderProtoView.type === ViewType.HOST) {
|
||||||
typeString = 'host';
|
typeString = 'host';
|
||||||
} else {
|
} else {
|
||||||
typeString = 'embedded';
|
typeString = 'embedded';
|
||||||
}
|
}
|
||||||
var id = `${hostComponentMetadata.id}_${typeString}_${pvWithIndex.index}`;
|
return `${hostComponentMetadata.id}_${typeString}_${pvWithIndex.index}`;
|
||||||
var variableNames = nestedPvVariableNames[pvWithIndex.index];
|
|
||||||
return new ChangeDetectorDefinition(id, strategyName, variableNames, propBindingRecords,
|
|
||||||
eventBindingRecords, directiveRecords, assertionsEnabled());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _createAppProtoView(
|
function _createAppProtoView(
|
||||||
|
|
|
@ -8,12 +8,12 @@ import {
|
||||||
} from 'angular2/src/facade/collection';
|
} from 'angular2/src/facade/collection';
|
||||||
import {
|
import {
|
||||||
AST,
|
AST,
|
||||||
BindingRecord,
|
|
||||||
ChangeDetector,
|
ChangeDetector,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
ChangeDispatcher,
|
ChangeDispatcher,
|
||||||
DirectiveIndex,
|
DirectiveIndex,
|
||||||
DirectiveRecord,
|
DirectiveRecord,
|
||||||
|
BindingTarget,
|
||||||
Locals,
|
Locals,
|
||||||
ProtoChangeDetector
|
ProtoChangeDetector
|
||||||
} from 'angular2/src/change_detection/change_detection';
|
} from 'angular2/src/change_detection/change_detection';
|
||||||
|
@ -171,7 +171,7 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
// dispatch to element injector or text nodes based on context
|
// dispatch to element injector or text nodes based on context
|
||||||
notifyOnBinding(b: BindingRecord, currentValue: any): void {
|
notifyOnBinding(b: BindingTarget, currentValue: any): void {
|
||||||
if (b.isTextNode()) {
|
if (b.isTextNode()) {
|
||||||
this.renderer.setText(
|
this.renderer.setText(
|
||||||
this.render, this.mainMergeMapping.renderTextIndices[b.elementIndex + this.textOffset],
|
this.render, this.mainMergeMapping.renderTextIndices[b.elementIndex + this.textOffset],
|
||||||
|
@ -179,14 +179,14 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
|
||||||
} else {
|
} else {
|
||||||
var elementRef = this.elementRefs[this.elementOffset + b.elementIndex];
|
var elementRef = this.elementRefs[this.elementOffset + b.elementIndex];
|
||||||
if (b.isElementProperty()) {
|
if (b.isElementProperty()) {
|
||||||
this.renderer.setElementProperty(elementRef, b.propertyName, currentValue);
|
this.renderer.setElementProperty(elementRef, b.name, currentValue);
|
||||||
} else if (b.isElementAttribute()) {
|
} else if (b.isElementAttribute()) {
|
||||||
this.renderer.setElementAttribute(elementRef, b.propertyName, currentValue);
|
this.renderer.setElementAttribute(elementRef, b.name, currentValue);
|
||||||
} else if (b.isElementClass()) {
|
} else if (b.isElementClass()) {
|
||||||
this.renderer.setElementClass(elementRef, b.propertyName, currentValue);
|
this.renderer.setElementClass(elementRef, b.name, currentValue);
|
||||||
} else if (b.isElementStyle()) {
|
} else if (b.isElementStyle()) {
|
||||||
var unit = isPresent(b.propertyUnit) ? b.propertyUnit : '';
|
var unit = isPresent(b.unit) ? b.unit : '';
|
||||||
this.renderer.setElementStyle(elementRef, b.propertyName, `${currentValue}${unit}`);
|
this.renderer.setElementStyle(elementRef, b.name, `${currentValue}${unit}`);
|
||||||
} else {
|
} else {
|
||||||
throw new BaseException('Unsupported directive record');
|
throw new BaseException('Unsupported directive record');
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,12 @@ class ListWrapper {
|
||||||
list.forEach(fn);
|
list.forEach(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void forEachWithIndex(List list, fn(item, index)) {
|
||||||
|
for (var i = 0; i < list.length; ++i) {
|
||||||
|
fn(list[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static reduce(List list, fn(a, b), init) {
|
static reduce(List list, fn(a, b), init) {
|
||||||
return list.fold(init, fn);
|
return list.fold(init, fn);
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,6 +182,11 @@ export class ListWrapper {
|
||||||
fn(array[i]);
|
fn(array[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static forEachWithIndex<T>(array: List<T>, fn: (T, number) => void) {
|
||||||
|
for (var i = 0; i < array.length; i++) {
|
||||||
|
fn(array[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
static first<T>(array: List<T>): T {
|
static first<T>(array: List<T>): T {
|
||||||
if (!array) return null;
|
if (!array) return null;
|
||||||
return array[0];
|
return array[0];
|
||||||
|
|
|
@ -9,6 +9,7 @@ import 'package:angular2/src/change_detection/interfaces.dart';
|
||||||
import 'package:angular2/src/change_detection/proto_change_detector.dart';
|
import 'package:angular2/src/change_detection/proto_change_detector.dart';
|
||||||
import 'package:angular2/src/change_detection/proto_record.dart';
|
import 'package:angular2/src/change_detection/proto_record.dart';
|
||||||
import 'package:angular2/src/change_detection/event_binding.dart';
|
import 'package:angular2/src/change_detection/event_binding.dart';
|
||||||
|
import 'package:angular2/src/change_detection/binding_record.dart';
|
||||||
import 'package:angular2/src/facade/lang.dart' show BaseException;
|
import 'package:angular2/src/facade/lang.dart' show BaseException;
|
||||||
|
|
||||||
/// Responsible for generating change detector classes for Angular 2.
|
/// Responsible for generating change detector classes for Angular 2.
|
||||||
|
@ -79,7 +80,8 @@ class _CodegenState {
|
||||||
final List<EventBinding> _eventBindings;
|
final List<EventBinding> _eventBindings;
|
||||||
final CodegenLogicUtil _logic;
|
final CodegenLogicUtil _logic;
|
||||||
final CodegenNameUtil _names;
|
final CodegenNameUtil _names;
|
||||||
final bool _generateCheckNoChanges;
|
final bool _devMode;
|
||||||
|
final List<BindingTarget> _propertyBindingTargets;
|
||||||
|
|
||||||
_CodegenState._(
|
_CodegenState._(
|
||||||
this._changeDetectorDefId,
|
this._changeDetectorDefId,
|
||||||
|
@ -87,11 +89,12 @@ class _CodegenState {
|
||||||
this._changeDetectorTypeName,
|
this._changeDetectorTypeName,
|
||||||
String changeDetectionStrategy,
|
String changeDetectionStrategy,
|
||||||
this._records,
|
this._records,
|
||||||
|
this._propertyBindingTargets,
|
||||||
this._eventBindings,
|
this._eventBindings,
|
||||||
this._directiveRecords,
|
this._directiveRecords,
|
||||||
this._logic,
|
this._logic,
|
||||||
this._names,
|
this._names,
|
||||||
this._generateCheckNoChanges)
|
this._devMode)
|
||||||
: _changeDetectionMode =
|
: _changeDetectionMode =
|
||||||
ChangeDetectionUtil.changeDetectionMode(changeDetectionStrategy);
|
ChangeDetectionUtil.changeDetectionMode(changeDetectionStrategy);
|
||||||
|
|
||||||
|
@ -99,6 +102,8 @@ class _CodegenState {
|
||||||
ChangeDetectorDefinition def) {
|
ChangeDetectorDefinition def) {
|
||||||
var protoRecords = createPropertyRecords(def);
|
var protoRecords = createPropertyRecords(def);
|
||||||
var eventBindings = createEventRecords(def);
|
var eventBindings = createEventRecords(def);
|
||||||
|
var propertyBindingTargets = def.bindingRecords.map((b) => b.target).toList();
|
||||||
|
|
||||||
var names = new CodegenNameUtil(protoRecords, eventBindings, def.directiveRecords, _UTIL);
|
var names = new CodegenNameUtil(protoRecords, eventBindings, def.directiveRecords, _UTIL);
|
||||||
var logic = new CodegenLogicUtil(names, _UTIL, def.strategy);
|
var logic = new CodegenLogicUtil(names, _UTIL, def.strategy);
|
||||||
return new _CodegenState._(
|
return new _CodegenState._(
|
||||||
|
@ -107,11 +112,12 @@ class _CodegenState {
|
||||||
changeDetectorTypeName,
|
changeDetectorTypeName,
|
||||||
def.strategy,
|
def.strategy,
|
||||||
protoRecords,
|
protoRecords,
|
||||||
|
propertyBindingTargets,
|
||||||
eventBindings,
|
eventBindings,
|
||||||
def.directiveRecords,
|
def.directiveRecords,
|
||||||
logic,
|
logic,
|
||||||
names,
|
names,
|
||||||
def.generateCheckNoChanges);
|
def.devMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _writeToBuf(StringBuffer buf) {
|
void _writeToBuf(StringBuffer buf) {
|
||||||
|
@ -119,9 +125,12 @@ class _CodegenState {
|
||||||
class $_changeDetectorTypeName extends $_BASE_CLASS<$_contextTypeName> {
|
class $_changeDetectorTypeName extends $_BASE_CLASS<$_contextTypeName> {
|
||||||
${_genDeclareFields()}
|
${_genDeclareFields()}
|
||||||
|
|
||||||
$_changeDetectorTypeName(dispatcher, protos, directiveRecords)
|
$_changeDetectorTypeName(dispatcher)
|
||||||
: super(${codify(_changeDetectorDefId)},
|
: super(${codify(_changeDetectorDefId)},
|
||||||
dispatcher, protos, directiveRecords, '$_changeDetectionMode') {
|
dispatcher, ${_records.length},
|
||||||
|
${_changeDetectorTypeName}.gen_propertyBindingTargets,
|
||||||
|
${_changeDetectorTypeName}.gen_directiveIndices,
|
||||||
|
'$_changeDetectionMode') {
|
||||||
dehydrateDirectives(false);
|
dehydrateDirectives(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,17 +154,31 @@ class _CodegenState {
|
||||||
|
|
||||||
${_maybeGenDehydrateDirectives()}
|
${_maybeGenDehydrateDirectives()}
|
||||||
|
|
||||||
|
${_genPropertyBindingTargets()};
|
||||||
|
|
||||||
|
${_genDirectiveIndices()};
|
||||||
|
|
||||||
static $_GEN_PREFIX.ProtoChangeDetector
|
static $_GEN_PREFIX.ProtoChangeDetector
|
||||||
$PROTO_CHANGE_DETECTOR_FACTORY_METHOD(
|
$PROTO_CHANGE_DETECTOR_FACTORY_METHOD(
|
||||||
$_GEN_PREFIX.ChangeDetectorDefinition def) {
|
$_GEN_PREFIX.ChangeDetectorDefinition def) {
|
||||||
return new $_GEN_PREFIX.PregenProtoChangeDetector(
|
return new $_GEN_PREFIX.PregenProtoChangeDetector(
|
||||||
(a, b, c) => new $_changeDetectorTypeName(a, b, c),
|
(a) => new $_changeDetectorTypeName(a),
|
||||||
def);
|
def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
''');
|
''');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _genPropertyBindingTargets() {
|
||||||
|
var targets = _logic.genPropertyBindingTargets(_propertyBindingTargets, this._devMode);
|
||||||
|
return "static var gen_propertyBindingTargets = ${targets}";
|
||||||
|
}
|
||||||
|
|
||||||
|
String _genDirectiveIndices() {
|
||||||
|
var indices = _logic.genDirectiveIndices(_directiveRecords);
|
||||||
|
return "static var gen_directiveIndices = ${indices}";
|
||||||
|
}
|
||||||
|
|
||||||
String _maybeGenHandleEventInternal() {
|
String _maybeGenHandleEventInternal() {
|
||||||
if (_eventBindings.length > 0) {
|
if (_eventBindings.length > 0) {
|
||||||
var handlers = _eventBindings.map((eb) => _genEventBinding(eb)).join("\n");
|
var handlers = _eventBindings.map((eb) => _genEventBinding(eb)).join("\n");
|
||||||
|
@ -239,7 +262,7 @@ class _CodegenState {
|
||||||
var directiveFieldNames = _names.getAllDirectiveNames();
|
var directiveFieldNames = _names.getAllDirectiveNames();
|
||||||
for (var i = 0; i < directiveFieldNames.length; ++i) {
|
for (var i = 0; i < directiveFieldNames.length; ++i) {
|
||||||
buf.writeln('${directiveFieldNames[i]} = directives.getDirectiveFor('
|
buf.writeln('${directiveFieldNames[i]} = directives.getDirectiveFor('
|
||||||
'${_names.getDirectivesAccessorName()}[$i].directiveIndex);');
|
'${_names.getDirectivesAccessorName()}[$i]);');
|
||||||
}
|
}
|
||||||
return '$buf';
|
return '$buf';
|
||||||
}
|
}
|
||||||
|
@ -378,9 +401,9 @@ class _CodegenState {
|
||||||
var oldValue = _names.getFieldName(r.selfIndex);
|
var oldValue = _names.getFieldName(r.selfIndex);
|
||||||
|
|
||||||
var br = r.bindingRecord;
|
var br = r.bindingRecord;
|
||||||
if (br.isDirective()) {
|
if (br.target.isDirective()) {
|
||||||
var directiveProperty =
|
var directiveProperty =
|
||||||
'${_names.getDirectiveName(br.directiveRecord.directiveIndex)}.${br.propertyName}';
|
'${_names.getDirectiveName(br.directiveRecord.directiveIndex)}.${br.target.name}';
|
||||||
return '''
|
return '''
|
||||||
${_genThrowOnChangeCheck(oldValue, newValue)}
|
${_genThrowOnChangeCheck(oldValue, newValue)}
|
||||||
$directiveProperty = $newValue;
|
$directiveProperty = $newValue;
|
||||||
|
@ -395,7 +418,7 @@ class _CodegenState {
|
||||||
}
|
}
|
||||||
|
|
||||||
String _genThrowOnChangeCheck(String oldValue, String newValue) {
|
String _genThrowOnChangeCheck(String oldValue, String newValue) {
|
||||||
if (this._generateCheckNoChanges) {
|
if (this._devMode) {
|
||||||
return '''
|
return '''
|
||||||
if(throwOnChange) {
|
if(throwOnChange) {
|
||||||
this.throwOnChangeError(${oldValue}, ${newValue});
|
this.throwOnChangeError(${oldValue}, ${newValue});
|
||||||
|
@ -407,7 +430,7 @@ class _CodegenState {
|
||||||
}
|
}
|
||||||
|
|
||||||
String _genCheckNoChanges() {
|
String _genCheckNoChanges() {
|
||||||
if (this._generateCheckNoChanges) {
|
if (this._devMode) {
|
||||||
return 'void checkNoChanges() { runDetectChanges(true); }';
|
return 'void checkNoChanges() { runDetectChanges(true); }';
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
|
@ -417,8 +440,8 @@ class _CodegenState {
|
||||||
String _maybeFirstInBinding(ProtoRecord r) {
|
String _maybeFirstInBinding(ProtoRecord r) {
|
||||||
var prev = ChangeDetectionUtil.protoByIndex(_records, r.selfIndex - 1);
|
var prev = ChangeDetectionUtil.protoByIndex(_records, r.selfIndex - 1);
|
||||||
var firstInBindng = prev == null || prev.bindingRecord != r.bindingRecord;
|
var firstInBindng = prev == null || prev.bindingRecord != r.bindingRecord;
|
||||||
return firstInBindng
|
return firstInBindng && !r.bindingRecord.isDirectiveLifecycle()
|
||||||
? "${_names.getFirstProtoInCurrentBinding()} = ${r.selfIndex};"
|
? "${_names.getPropertyBindingIndex()} = ${r.propertyBindingIndex};"
|
||||||
: '';
|
: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ class NullReflectionCapabilities implements ReflectionCapabilities {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Function factory(Type type) => _notImplemented('factory');
|
Function factory(Type type) => _notImplemented("factory");
|
||||||
|
|
||||||
List<List> parameters(typeOrFunc) => _notImplemented('parameters');
|
List<List> parameters(typeOrFunc) => _notImplemented('parameters');
|
||||||
|
|
||||||
|
|
|
@ -30,12 +30,12 @@ export function main() {
|
||||||
var map = {'id': (def) => proto};
|
var map = {'id': (def) => proto};
|
||||||
var cd = new PreGeneratedChangeDetection(map);
|
var cd = new PreGeneratedChangeDetection(map);
|
||||||
|
|
||||||
expect(cd.createProtoChangeDetector(def)).toBe(proto)
|
expect(cd.getProtoChangeDetector('id', def)).toBe(proto)
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should delegate to dynamic change detection otherwise", () => {
|
it("should delegate to dynamic change detection otherwise", () => {
|
||||||
var cd = new PreGeneratedChangeDetection({});
|
var cd = new PreGeneratedChangeDetection({});
|
||||||
expect(cd.createProtoChangeDetector(def)).toBeAnInstanceOf(DynamicProtoChangeDetector);
|
expect(cd.getProtoChangeDetector('id', def)).toBeAnInstanceOf(DynamicProtoChangeDetector);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1135,8 +1135,8 @@ class TestDispatcher implements ChangeDispatcher {
|
||||||
this.onAllChangesDoneCalled = true;
|
this.onAllChangesDoneCalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyOnBinding(binding, value) {
|
notifyOnBinding(target, value) {
|
||||||
this.log.push(`${binding.propertyName}=${this._asString(value)}`);
|
this.log.push(`${target.name}=${this._asString(value)}`);
|
||||||
this.loggedValues.push(value);
|
this.loggedValues.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,7 @@ export function main() {
|
||||||
if (isBlank(argumentToPureFunction)) argumentToPureFunction = false;
|
if (isBlank(argumentToPureFunction)) argumentToPureFunction = false;
|
||||||
|
|
||||||
return new ProtoRecord(mode, name, funcOrValue, args, null, contextIndex, directiveIndex,
|
return new ProtoRecord(mode, name, funcOrValue, args, null, contextIndex, directiveIndex,
|
||||||
selfIndex, null, null, lastInBinding, false, argumentToPureFunction,
|
selfIndex, null, lastInBinding, false, argumentToPureFunction, false, 0);
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("change detection - coalesce", () => {
|
describe("change detection - coalesce", () => {
|
||||||
|
@ -64,7 +63,7 @@ export function main() {
|
||||||
[r("user", [], 0, 1, {lastInBinding: true}), r("user", [], 0, 2, {lastInBinding: true})]);
|
[r("user", [], 0, 1, {lastInBinding: true}), r("user", [], 0, 2, {lastInBinding: true})]);
|
||||||
|
|
||||||
expect(rs[1]).toEqual(new ProtoRecord(RecordType.SELF, "self", null, [], null, 1, null, 2,
|
expect(rs[1]).toEqual(new ProtoRecord(RecordType.SELF, "self", null, [], null, 1, null, 2,
|
||||||
null, null, true, false, false, false));
|
null, true, false, false, false, 0));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set referencedBySelf", () => {
|
it("should set referencedBySelf", () => {
|
||||||
|
|
|
@ -19,7 +19,7 @@ export function main() {
|
||||||
it('should set argumentToPureFunction flag', inject([Parser], (p: Parser) => {
|
it('should set argumentToPureFunction flag', inject([Parser], (p: Parser) => {
|
||||||
var builder = new ProtoRecordBuilder();
|
var builder = new ProtoRecordBuilder();
|
||||||
var ast = p.parseBinding("[1,2]", "location"); // collection literal is a pure function
|
var ast = p.parseBinding("[1,2]", "location"); // collection literal is a pure function
|
||||||
builder.add(BindingRecord.createForElementProperty(ast, 0, "property"), []);
|
builder.add(BindingRecord.createForElementProperty(ast, 0, "property"), [], 0);
|
||||||
|
|
||||||
var isPureFunc = builder.records.map(r => r.argumentToPureFunction);
|
var isPureFunc = builder.records.map(r => r.argumentToPureFunction);
|
||||||
expect(isPureFunc).toEqual([true, true, false]);
|
expect(isPureFunc).toEqual([true, true, false]);
|
||||||
|
@ -29,7 +29,7 @@ export function main() {
|
||||||
inject([Parser], (p: Parser) => {
|
inject([Parser], (p: Parser) => {
|
||||||
var builder = new ProtoRecordBuilder();
|
var builder = new ProtoRecordBuilder();
|
||||||
var ast = p.parseBinding("f(1,2)", "location");
|
var ast = p.parseBinding("f(1,2)", "location");
|
||||||
builder.add(BindingRecord.createForElementProperty(ast, 0, "property"), []);
|
builder.add(BindingRecord.createForElementProperty(ast, 0, "property"), [], 0);
|
||||||
|
|
||||||
var isPureFunc = builder.records.map(r => r.argumentToPureFunction);
|
var isPureFunc = builder.records.map(r => r.argumentToPureFunction);
|
||||||
expect(isPureFunc).toEqual([false, false, false]);
|
expect(isPureFunc).toEqual([false, false, false]);
|
||||||
|
|
|
@ -20,8 +20,8 @@ export function main() {
|
||||||
if (isBlank(argumentToPureFunction)) argumentToPureFunction = false;
|
if (isBlank(argumentToPureFunction)) argumentToPureFunction = false;
|
||||||
if (isBlank(referencedBySelf)) referencedBySelf = false;
|
if (isBlank(referencedBySelf)) referencedBySelf = false;
|
||||||
|
|
||||||
return new ProtoRecord(mode, name, null, [], null, 0, directiveIndex, 0, null, null,
|
return new ProtoRecord(mode, name, null, [], null, 0, directiveIndex, 0, null, lastInBinding,
|
||||||
lastInBinding, false, argumentToPureFunction, referencedBySelf);
|
false, argumentToPureFunction, referencedBySelf, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("ProtoRecord", () => {
|
describe("ProtoRecord", () => {
|
||||||
|
|
|
@ -980,7 +980,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should inject ChangeDetectorRef of the component's view into the component", () => {
|
it("should inject ChangeDetectorRef of the component's view into the component", () => {
|
||||||
var cd = new DynamicChangeDetector(null, null, null, [], [], []);
|
var cd = new DynamicChangeDetector(null, null, 0, [], [], null, [], [], []);
|
||||||
var view = <any>new DummyView();
|
var view = <any>new DummyView();
|
||||||
var childView = new DummyView();
|
var childView = new DummyView();
|
||||||
childView.changeDetector = cd;
|
childView.changeDetector = cd;
|
||||||
|
@ -993,7 +993,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should inject ChangeDetectorRef of the containing component into directives", () => {
|
it("should inject ChangeDetectorRef of the containing component into directives", () => {
|
||||||
var cd = new DynamicChangeDetector(null, null, null, [], [], []);
|
var cd = new DynamicChangeDetector(null, null, 0, [], [], null, [], [], []);
|
||||||
var view = <any>new DummyView();
|
var view = <any>new DummyView();
|
||||||
view.changeDetector =cd;
|
view.changeDetector =cd;
|
||||||
var binding = DirectiveBinding.createFromType(DirectiveNeedsChangeDetectorRef, new DirectiveMetadata());
|
var binding = DirectiveBinding.createFromType(DirectiveNeedsChangeDetectorRef, new DirectiveMetadata());
|
||||||
|
|
|
@ -20,7 +20,8 @@ import {
|
||||||
ChangeDetection,
|
ChangeDetection,
|
||||||
ChangeDetectorDefinition,
|
ChangeDetectorDefinition,
|
||||||
BindingRecord,
|
BindingRecord,
|
||||||
DirectiveIndex
|
DirectiveIndex,
|
||||||
|
Parser
|
||||||
} from 'angular2/src/change_detection/change_detection';
|
} from 'angular2/src/change_detection/change_detection';
|
||||||
import {
|
import {
|
||||||
BindingRecordsCreator,
|
BindingRecordsCreator,
|
||||||
|
@ -177,39 +178,44 @@ export function main() {
|
||||||
beforeEach(() => { creator = new BindingRecordsCreator(); });
|
beforeEach(() => { creator = new BindingRecordsCreator(); });
|
||||||
|
|
||||||
describe('getEventBindingRecords', () => {
|
describe('getEventBindingRecords', () => {
|
||||||
it("should return template event records", () => {
|
it("should return template event records", inject([Parser], (p: Parser) => {
|
||||||
|
var ast1 = p.parseAction("1", null);
|
||||||
|
var ast2 = p.parseAction("2", null);
|
||||||
|
|
||||||
var rec = creator.getEventBindingRecords(
|
var rec = creator.getEventBindingRecords(
|
||||||
[
|
[
|
||||||
new RenderElementBinder(
|
new RenderElementBinder(
|
||||||
{eventBindings: [new EventBinding("a", null)], directives: []}),
|
{eventBindings: [new EventBinding("a", ast1)], directives: []}),
|
||||||
new RenderElementBinder(
|
new RenderElementBinder(
|
||||||
{eventBindings: [new EventBinding("b", null)], directives: []})
|
{eventBindings: [new EventBinding("b", ast2)], directives: []})
|
||||||
],
|
],
|
||||||
[]);
|
[]);
|
||||||
|
|
||||||
expect(rec).toEqual([
|
expect(rec).toEqual([
|
||||||
BindingRecord.createForEvent(null, "a", 0),
|
BindingRecord.createForEvent(ast1, "a", 0),
|
||||||
BindingRecord.createForEvent(null, "b", 1)
|
BindingRecord.createForEvent(ast2, "b", 1)
|
||||||
]);
|
]);
|
||||||
});
|
}));
|
||||||
|
|
||||||
|
it('should return host event records', inject([Parser], (p: Parser) => {
|
||||||
|
var ast1 = p.parseAction("1", null);
|
||||||
|
|
||||||
it('should return host event records', () => {
|
|
||||||
var rec = creator.getEventBindingRecords(
|
var rec = creator.getEventBindingRecords(
|
||||||
[
|
[
|
||||||
new RenderElementBinder({
|
new RenderElementBinder({
|
||||||
eventBindings: [],
|
eventBindings: [],
|
||||||
directives: [
|
directives: [
|
||||||
new DirectiveBinder(
|
new DirectiveBinder(
|
||||||
{directiveIndex: 0, eventBindings: [new EventBinding("a", null)]})
|
{directiveIndex: 0, eventBindings: [new EventBinding("a", ast1)]})
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
[RenderDirectiveMetadata.create({id: 'some-id'})]);
|
[RenderDirectiveMetadata.create({id: 'some-id'})]);
|
||||||
|
|
||||||
expect(rec.length).toEqual(1);
|
expect(rec.length).toEqual(1);
|
||||||
expect(rec[0].eventName).toEqual("a");
|
expect(rec[0].target.name).toEqual("a");
|
||||||
expect(rec[0].implicitReceiver).toBeAnInstanceOf(DirectiveIndex);
|
expect(rec[0].implicitReceiver).toBeAnInstanceOf(DirectiveIndex);
|
||||||
});
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -253,6 +259,7 @@ function createRenderViewportElementBinder(nestedProtoView) {
|
||||||
class ChangeDetectionSpy extends SpyObject {
|
class ChangeDetectionSpy extends SpyObject {
|
||||||
constructor() { super(ChangeDetection); }
|
constructor() { super(ChangeDetection); }
|
||||||
noSuchMethod(m) { return super.noSuchMethod(m) }
|
noSuchMethod(m) { return super.noSuchMethod(m) }
|
||||||
|
get generateDetectors() { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'main-comp'})
|
@Component({selector: 'main-comp'})
|
||||||
|
|
|
@ -90,6 +90,18 @@ export function main() {
|
||||||
it('should return null for an empty list',
|
it('should return null for an empty list',
|
||||||
() => { expect(ListWrapper.maximum([], x => x)).toEqual(null); });
|
() => { expect(ListWrapper.maximum([], x => x)).toEqual(null); });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('forEachWithIndex', () => {
|
||||||
|
var l;
|
||||||
|
|
||||||
|
beforeEach(() => { l = ["a", "b"]; });
|
||||||
|
|
||||||
|
it('should iterate over an array passing values and indices', () => {
|
||||||
|
var record = [];
|
||||||
|
ListWrapper.forEachWithIndex(l, (value, index) => record.push([value, index]));
|
||||||
|
expect(record).toEqual([["a", 0], ["b", 1]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('StringMapWrapper', () => {
|
describe('StringMapWrapper', () => {
|
||||||
|
|
|
@ -13,9 +13,7 @@ void initReflector() {
|
||||||
if (_visited) return;
|
if (_visited) return;
|
||||||
_visited = true;
|
_visited = true;
|
||||||
_ngRef.reflector
|
_ngRef.reflector
|
||||||
..registerType(
|
..registerType(MyComponent, new _ngRef.ReflectionInfo(const [
|
||||||
MyComponent,
|
|
||||||
new _ngRef.ReflectionInfo(const [
|
|
||||||
const Component(selector: '[soup]'),
|
const Component(selector: '[soup]'),
|
||||||
const View(template: 'Salad: {{myNum}} is awesome')
|
const View(template: 'Salad: {{myNum}} is awesome')
|
||||||
], const [], () => new MyComponent()))
|
], const [], () => new MyComponent()))
|
||||||
|
@ -28,19 +26,23 @@ class _MyComponent_ChangeDetector0
|
||||||
extends _gen.AbstractChangeDetector<MyComponent> {
|
extends _gen.AbstractChangeDetector<MyComponent> {
|
||||||
var myNum0, interpolate1;
|
var myNum0, interpolate1;
|
||||||
|
|
||||||
_MyComponent_ChangeDetector0(dispatcher, protos, directiveRecords)
|
_MyComponent_ChangeDetector0(dispatcher) : super(
|
||||||
: super("MyComponent_comp_0", dispatcher, protos, directiveRecords,
|
"MyComponent_comp_0", dispatcher, 2,
|
||||||
'ALWAYS_CHECK') {
|
_MyComponent_ChangeDetector0.gen_propertyBindingTargets,
|
||||||
|
_MyComponent_ChangeDetector0.gen_directiveIndices, 'ALWAYS_CHECK') {
|
||||||
dehydrateDirectives(false);
|
dehydrateDirectives(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void detectChangesInRecordsInternal(throwOnChange) {
|
void detectChangesInRecordsInternal(throwOnChange) {
|
||||||
var l_context = this.context, l_myNum0, c_myNum0, l_interpolate1;
|
var l_context = this.context,
|
||||||
|
l_myNum0,
|
||||||
|
c_myNum0,
|
||||||
|
l_interpolate1;
|
||||||
c_myNum0 = false;
|
c_myNum0 = false;
|
||||||
var isChanged = false;
|
var isChanged = false;
|
||||||
var changes = null;
|
var changes = null;
|
||||||
|
|
||||||
this.firstProtoInCurrentBinding = 1;
|
this.propertyBindingIndex = 0;
|
||||||
l_myNum0 = l_context.myNum;
|
l_myNum0 = l_context.myNum;
|
||||||
if (_gen.looseNotIdentical(l_myNum0, this.myNum0)) {
|
if (_gen.looseNotIdentical(l_myNum0, this.myNum0)) {
|
||||||
c_myNum0 = true;
|
c_myNum0 = true;
|
||||||
|
@ -75,9 +77,16 @@ class _MyComponent_ChangeDetector0
|
||||||
this.myNum0 = this.interpolate1 = _gen.ChangeDetectionUtil.uninitialized;
|
this.myNum0 = this.interpolate1 = _gen.ChangeDetectionUtil.uninitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static var gen_propertyBindingTargets = [
|
||||||
|
_gen.ChangeDetectionUtil.bindingTarget("textNode", 0, null, null,
|
||||||
|
"Salad: {{myNum}} is awesome in MyComponent: <template>")
|
||||||
|
];
|
||||||
|
|
||||||
|
static var gen_directiveIndices = [];
|
||||||
|
|
||||||
static _gen.ProtoChangeDetector newProtoChangeDetector(
|
static _gen.ProtoChangeDetector newProtoChangeDetector(
|
||||||
_gen.ChangeDetectorDefinition def) {
|
_gen.ChangeDetectorDefinition def) {
|
||||||
return new _gen.PregenProtoChangeDetector(
|
return new _gen.PregenProtoChangeDetector(
|
||||||
(a, b, c) => new _MyComponent_ChangeDetector0(a, b, c), def);
|
(a) => new _MyComponent_ChangeDetector0(a), def);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -249,8 +249,8 @@ function setUpChangeDetection(changeDetection: ChangeDetection, iterations, obje
|
||||||
var dispatcher = new DummyDispatcher();
|
var dispatcher = new DummyDispatcher();
|
||||||
var parser = new Parser(new Lexer());
|
var parser = new Parser(new Lexer());
|
||||||
|
|
||||||
var parentProto = changeDetection.createProtoChangeDetector(
|
var parentProto = changeDetection.getProtoChangeDetector(
|
||||||
new ChangeDetectorDefinition('parent', null, [], [], [], [], false));
|
"id", new ChangeDetectorDefinition('parent', null, [], [], [], [], false));
|
||||||
var parentCd = parentProto.instantiate(dispatcher);
|
var parentCd = parentProto.instantiate(dispatcher);
|
||||||
|
|
||||||
var directiveRecord = new DirectiveRecord({directiveIndex: new DirectiveIndex(0, 0)});
|
var directiveRecord = new DirectiveRecord({directiveIndex: new DirectiveIndex(0, 0)});
|
||||||
|
@ -277,7 +277,8 @@ function setUpChangeDetection(changeDetection: ChangeDetection, iterations, obje
|
||||||
reflector.setter("field9"), directiveRecord)
|
reflector.setter("field9"), directiveRecord)
|
||||||
];
|
];
|
||||||
|
|
||||||
var proto = changeDetection.createProtoChangeDetector(
|
var proto = changeDetection.getProtoChangeDetector(
|
||||||
|
"id",
|
||||||
new ChangeDetectorDefinition("proto", null, [], bindings, [], [directiveRecord], false));
|
new ChangeDetectorDefinition("proto", null, [], bindings, [], [directiveRecord], false));
|
||||||
|
|
||||||
var targetObj = new Obj();
|
var targetObj = new Obj();
|
||||||
|
|
Loading…
Reference in New Issue