feat(core): drop `ChangeDetectionStrategy.OnPushObserve`
BREAKING CHANGE: `OnPushObserve` was an experimental feature for Dart and had conceptual performance problems, as setting up observables is slow. Use `OnPush` instead.
This commit is contained in:
parent
d900f5c075
commit
f60fa14767
|
@ -16,7 +16,6 @@ import {BindingTarget} from './binding_record';
|
||||||
import {Locals} from './parser/locals';
|
import {Locals} from './parser/locals';
|
||||||
import {ChangeDetectionStrategy, ChangeDetectorState} from './constants';
|
import {ChangeDetectionStrategy, ChangeDetectorState} from './constants';
|
||||||
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
|
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
|
||||||
import {isObservable} from './observable_facade';
|
|
||||||
import {ObservableWrapper} from 'angular2/src/facade/async';
|
import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
var _scope_check: WtfScopeFn = wtfCreateScope(`ChangeDetector#check(ascii id, bool throwOnChange)`);
|
var _scope_check: WtfScopeFn = wtfCreateScope(`ChangeDetector#check(ascii id, bool throwOnChange)`);
|
||||||
|
@ -42,10 +41,6 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
propertyBindingIndex: number;
|
propertyBindingIndex: number;
|
||||||
outputSubscriptions: any[];
|
outputSubscriptions: any[];
|
||||||
|
|
||||||
// This is an experimental feature. Works only in Dart.
|
|
||||||
subscriptions: any[];
|
|
||||||
streams: any[];
|
|
||||||
|
|
||||||
dispatcher: ChangeDispatcher;
|
dispatcher: ChangeDispatcher;
|
||||||
|
|
||||||
|
|
||||||
|
@ -158,10 +153,6 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
this.mode = ChangeDetectionUtil.changeDetectionMode(this.strategy);
|
this.mode = ChangeDetectionUtil.changeDetectionMode(this.strategy);
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
if (this.strategy === ChangeDetectionStrategy.OnPushObserve) {
|
|
||||||
this.observeComponent(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.locals = locals;
|
this.locals = locals;
|
||||||
this.pipes = pipes;
|
this.pipes = pipes;
|
||||||
this.hydrateDirectives(dispatcher);
|
this.hydrateDirectives(dispatcher);
|
||||||
|
@ -176,11 +167,6 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
dehydrate(): void {
|
dehydrate(): void {
|
||||||
this.dehydrateDirectives(true);
|
this.dehydrateDirectives(true);
|
||||||
|
|
||||||
// This is an experimental feature. Works only in Dart.
|
|
||||||
if (this.strategy === ChangeDetectionStrategy.OnPushObserve) {
|
|
||||||
this._unsubsribeFromObservables();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._unsubscribeFromOutputs();
|
this._unsubscribeFromOutputs();
|
||||||
|
|
||||||
this.dispatcher = null;
|
this.dispatcher = null;
|
||||||
|
@ -248,19 +234,6 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is an experimental feature. Works only in Dart.
|
|
||||||
private _unsubsribeFromObservables(): void {
|
|
||||||
if (isPresent(this.subscriptions)) {
|
|
||||||
for (var i = 0; i < this.subscriptions.length; ++i) {
|
|
||||||
var s = this.subscriptions[i];
|
|
||||||
if (isPresent(this.subscriptions[i])) {
|
|
||||||
s.cancel();
|
|
||||||
this.subscriptions[i] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _unsubscribeFromOutputs(): void {
|
private _unsubscribeFromOutputs(): void {
|
||||||
if (isPresent(this.outputSubscriptions)) {
|
if (isPresent(this.outputSubscriptions)) {
|
||||||
for (var i = 0; i < this.outputSubscriptions.length; ++i) {
|
for (var i = 0; i < this.outputSubscriptions.length; ++i) {
|
||||||
|
@ -270,53 +243,6 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is an experimental feature. Works only in Dart.
|
|
||||||
observeValue(value: any, index: number): any {
|
|
||||||
if (isObservable(value)) {
|
|
||||||
this._createArrayToStoreObservables();
|
|
||||||
if (isBlank(this.subscriptions[index])) {
|
|
||||||
this.streams[index] = value.changes;
|
|
||||||
this.subscriptions[index] = value.changes.listen((_) => this.ref.markForCheck());
|
|
||||||
} else if (this.streams[index] !== value.changes) {
|
|
||||||
this.subscriptions[index].cancel();
|
|
||||||
this.streams[index] = value.changes;
|
|
||||||
this.subscriptions[index] = value.changes.listen((_) => this.ref.markForCheck());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is an experimental feature. Works only in Dart.
|
|
||||||
observeDirective(value: any, index: number): any {
|
|
||||||
if (isObservable(value)) {
|
|
||||||
this._createArrayToStoreObservables();
|
|
||||||
var arrayIndex = this.numberOfPropertyProtoRecords + index + 2; // +1 is component
|
|
||||||
this.streams[arrayIndex] = value.changes;
|
|
||||||
this.subscriptions[arrayIndex] = value.changes.listen((_) => this.ref.markForCheck());
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is an experimental feature. Works only in Dart.
|
|
||||||
observeComponent(value: any): any {
|
|
||||||
if (isObservable(value)) {
|
|
||||||
this._createArrayToStoreObservables();
|
|
||||||
var index = this.numberOfPropertyProtoRecords + 1;
|
|
||||||
this.streams[index] = value.changes;
|
|
||||||
this.subscriptions[index] = value.changes.listen((_) => this.ref.markForCheck());
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _createArrayToStoreObservables(): void {
|
|
||||||
if (isBlank(this.subscriptions)) {
|
|
||||||
this.subscriptions = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords +
|
|
||||||
this.directiveIndices.length + 2);
|
|
||||||
this.streams = ListWrapper.createFixedSize(this.numberOfPropertyProtoRecords +
|
|
||||||
this.directiveIndices.length + 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getDirectiveFor(directives: any, index: number): any {
|
getDirectiveFor(directives: any, index: number): any {
|
||||||
return directives.getDirectiveFor(this.directiveIndices[index]);
|
return directives.getDirectiveFor(this.directiveIndices[index]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,9 +57,8 @@ export class ChangeDetectorJITGenerator {
|
||||||
this.directiveRecords = definition.directiveRecords;
|
this.directiveRecords = definition.directiveRecords;
|
||||||
this._names = new CodegenNameUtil(this.records, this.eventBindings, this.directiveRecords,
|
this._names = new CodegenNameUtil(this.records, this.eventBindings, this.directiveRecords,
|
||||||
this.changeDetectionUtilVarName);
|
this.changeDetectionUtilVarName);
|
||||||
this._logic =
|
this._logic = new CodegenLogicUtil(this._names, this.changeDetectionUtilVarName,
|
||||||
new CodegenLogicUtil(this._names, this.changeDetectionUtilVarName,
|
this.changeDetectorStateVarName);
|
||||||
this.changeDetectorStateVarName, this.changeDetectionStrategy);
|
|
||||||
this.typeName = sanitizeName(`ChangeDetector_${this.id}`);
|
this.typeName = sanitizeName(`ChangeDetector_${this.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ 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 {BindingTarget} from './binding_record';
|
||||||
import {DirectiveRecord} from './directive_record';
|
import {DirectiveRecord} from './directive_record';
|
||||||
import {ChangeDetectionStrategy} from './constants';
|
|
||||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,8 +11,7 @@ import {BaseException} from 'angular2/src/facade/exceptions';
|
||||||
*/
|
*/
|
||||||
export class CodegenLogicUtil {
|
export class CodegenLogicUtil {
|
||||||
constructor(private _names: CodegenNameUtil, private _utilName: string,
|
constructor(private _names: CodegenNameUtil, private _utilName: string,
|
||||||
private _changeDetectorStateName: string,
|
private _changeDetectorStateName: string) {}
|
||||||
private _changeDetection: ChangeDetectionStrategy) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a statement which updates the local variable representing `protoRec` with the current
|
* Generates a statement which updates the local variable representing `protoRec` with the current
|
||||||
|
@ -51,13 +49,12 @@ export class CodegenLogicUtil {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RecordType.PropertyRead:
|
case RecordType.PropertyRead:
|
||||||
rhs = this._observe(`${context}.${protoRec.name}`, protoRec);
|
rhs = `${context}.${protoRec.name}`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RecordType.SafeProperty:
|
case RecordType.SafeProperty:
|
||||||
var read = this._observe(`${context}.${protoRec.name}`, protoRec);
|
var read = `${context}.${protoRec.name}`;
|
||||||
rhs =
|
rhs = `${this._utilName}.isValueBlank(${context}) ? null : ${read}`;
|
||||||
`${this._utilName}.isValueBlank(${context}) ? null : ${this._observe(read, protoRec)}`;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RecordType.PropertyWrite:
|
case RecordType.PropertyWrite:
|
||||||
|
@ -65,17 +62,16 @@ export class CodegenLogicUtil {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RecordType.Local:
|
case RecordType.Local:
|
||||||
rhs = this._observe(`${localsAccessor}.get(${rawString(protoRec.name)})`, protoRec);
|
rhs = `${localsAccessor}.get(${rawString(protoRec.name)})`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RecordType.InvokeMethod:
|
case RecordType.InvokeMethod:
|
||||||
rhs = this._observe(`${context}.${protoRec.name}(${argString})`, protoRec);
|
rhs = `${context}.${protoRec.name}(${argString})`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RecordType.SafeMethodInvoke:
|
case RecordType.SafeMethodInvoke:
|
||||||
var invoke = `${context}.${protoRec.name}(${argString})`;
|
var invoke = `${context}.${protoRec.name}(${argString})`;
|
||||||
rhs =
|
rhs = `${this._utilName}.isValueBlank(${context}) ? null : ${invoke}`;
|
||||||
`${this._utilName}.isValueBlank(${context}) ? null : ${this._observe(invoke, protoRec)}`;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RecordType.InvokeClosure:
|
case RecordType.InvokeClosure:
|
||||||
|
@ -95,7 +91,7 @@ export class CodegenLogicUtil {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RecordType.KeyedRead:
|
case RecordType.KeyedRead:
|
||||||
rhs = this._observe(`${context}[${getLocalName(protoRec.args[0])}]`, protoRec);
|
rhs = `${context}[${getLocalName(protoRec.args[0])}]`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RecordType.KeyedWrite:
|
case RecordType.KeyedWrite:
|
||||||
|
@ -112,16 +108,6 @@ export class CodegenLogicUtil {
|
||||||
return `${getLocalName(protoRec.selfIndex)} = ${rhs};`;
|
return `${getLocalName(protoRec.selfIndex)} = ${rhs};`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
_observe(exp: string, rec: ProtoRecord): string {
|
|
||||||
// This is an experimental feature. Works only in Dart.
|
|
||||||
if (this._changeDetection === ChangeDetectionStrategy.OnPushObserve) {
|
|
||||||
return `this.observeValue(${exp}, ${rec.selfIndex})`;
|
|
||||||
} else {
|
|
||||||
return exp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
genPropertyBindingTargets(propertyBindingTargets: BindingTarget[],
|
genPropertyBindingTargets(propertyBindingTargets: BindingTarget[],
|
||||||
genDebugInfo: boolean): string {
|
genDebugInfo: boolean): string {
|
||||||
var bs = propertyBindingTargets.map(b => {
|
var bs = propertyBindingTargets.map(b => {
|
||||||
|
@ -202,15 +188,7 @@ export class CodegenLogicUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _genReadDirective(index: number) {
|
private _genReadDirective(index: number) { return `this.getDirectiveFor(directives, ${index})`; }
|
||||||
var directiveExpr = `this.getDirectiveFor(directives, ${index})`;
|
|
||||||
// This is an experimental feature. Works only in Dart.
|
|
||||||
if (this._changeDetection === ChangeDetectionStrategy.OnPushObserve) {
|
|
||||||
return `this.observeDirective(${directiveExpr}, ${index})`;
|
|
||||||
} else {
|
|
||||||
return directiveExpr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
genHydrateDetectors(directiveRecords: DirectiveRecord[]): string {
|
genHydrateDetectors(directiveRecords: DirectiveRecord[]): string {
|
||||||
var res = [];
|
var res = [];
|
||||||
|
|
|
@ -62,11 +62,6 @@ export enum ChangeDetectionStrategy {
|
||||||
* `Default` means that the change detector's mode will be set to `CheckAlways` during hydration.
|
* `Default` means that the change detector's mode will be set to `CheckAlways` during hydration.
|
||||||
*/
|
*/
|
||||||
Default,
|
Default,
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an experimental feature. Works only in Dart.
|
|
||||||
*/
|
|
||||||
OnPushObserve
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,8 +73,7 @@ export var CHANGE_DETECTION_STRATEGY_VALUES = [
|
||||||
ChangeDetectionStrategy.CheckAlways,
|
ChangeDetectionStrategy.CheckAlways,
|
||||||
ChangeDetectionStrategy.Detached,
|
ChangeDetectionStrategy.Detached,
|
||||||
ChangeDetectionStrategy.OnPush,
|
ChangeDetectionStrategy.OnPush,
|
||||||
ChangeDetectionStrategy.Default,
|
ChangeDetectionStrategy.Default
|
||||||
ChangeDetectionStrategy.OnPushObserve
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -110,12 +110,6 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
||||||
this.values[0] = this.context;
|
this.values[0] = this.context;
|
||||||
this.dispatcher = dispatcher;
|
this.dispatcher = dispatcher;
|
||||||
|
|
||||||
if (this.strategy === ChangeDetectionStrategy.OnPushObserve) {
|
|
||||||
for (var i = 0; i < this.directiveIndices.length; ++i) {
|
|
||||||
var index = this.directiveIndices[i];
|
|
||||||
super.observeDirective(this._getDirectiveFor(index), i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.outputSubscriptions = [];
|
this.outputSubscriptions = [];
|
||||||
for (var i = 0; i < this._directiveRecords.length; ++i) {
|
for (var i = 0; i < this._directiveRecords.length; ++i) {
|
||||||
var r = this._directiveRecords[i];
|
var r = this._directiveRecords[i];
|
||||||
|
@ -300,9 +294,6 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
|
||||||
}
|
}
|
||||||
|
|
||||||
var currValue = this._calculateCurrValue(proto, values, locals);
|
var currValue = this._calculateCurrValue(proto, values, locals);
|
||||||
if (this.strategy === ChangeDetectionStrategy.OnPushObserve) {
|
|
||||||
super.observeValue(currValue, proto.selfIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proto.shouldBeChecked()) {
|
if (proto.shouldBeChecked()) {
|
||||||
var prevValue = this._readSelf(proto, values);
|
var prevValue = this._readSelf(proto, values);
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
library change_detection.observable_facade;
|
|
||||||
|
|
||||||
import 'package:observe/observe.dart';
|
|
||||||
|
|
||||||
bool isObservable(value) => value is Observable;
|
|
|
@ -1,3 +0,0 @@
|
||||||
export function isObservable(value: any): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
|
@ -106,21 +106,6 @@ export function getDefinition(id: string): TestDefinition {
|
||||||
[_DirectiveUpdating.basicRecords[0], _DirectiveUpdating.basicRecords[1]], genConfig);
|
[_DirectiveUpdating.basicRecords[0], _DirectiveUpdating.basicRecords[1]], genConfig);
|
||||||
testDef = new TestDefinition(id, cdDef, null);
|
testDef = new TestDefinition(id, cdDef, null);
|
||||||
|
|
||||||
} else if (id == "onPushObserveBinding") {
|
|
||||||
var records = _createBindingRecords("a");
|
|
||||||
let cdDef = new ChangeDetectorDefinition(id, ChangeDetectionStrategy.OnPushObserve, [], records,
|
|
||||||
[], [], genConfig);
|
|
||||||
testDef = new TestDefinition(id, cdDef, null);
|
|
||||||
|
|
||||||
} else if (id == "onPushObserveComponent") {
|
|
||||||
let cdDef = new ChangeDetectorDefinition(id, ChangeDetectionStrategy.OnPushObserve, [], [], [],
|
|
||||||
[], genConfig);
|
|
||||||
testDef = new TestDefinition(id, cdDef, null);
|
|
||||||
|
|
||||||
} else if (id == "onPushObserveDirective") {
|
|
||||||
let cdDef = new ChangeDetectorDefinition(id, ChangeDetectionStrategy.OnPushObserve, [], [], [],
|
|
||||||
[_DirectiveUpdating.recordNoCallbacks], genConfig);
|
|
||||||
testDef = new TestDefinition(id, cdDef, null);
|
|
||||||
} else if (id == "updateElementProduction") {
|
} else if (id == "updateElementProduction") {
|
||||||
var genConfig = new ChangeDetectorGenConfig(false, false, true);
|
var genConfig = new ChangeDetectorGenConfig(false, false, true);
|
||||||
var records = _createBindingRecords("name");
|
var records = _createBindingRecords("name");
|
||||||
|
@ -151,12 +136,7 @@ export function getAllDefinitions(): TestDefinition[] {
|
||||||
allDefs = allDefs.concat(StringMapWrapper.keys(_DirectiveUpdating.availableDefinitions));
|
allDefs = allDefs.concat(StringMapWrapper.keys(_DirectiveUpdating.availableDefinitions));
|
||||||
allDefs = allDefs.concat(_availableEventDefinitions);
|
allDefs = allDefs.concat(_availableEventDefinitions);
|
||||||
allDefs = allDefs.concat(_availableHostEventDefinitions);
|
allDefs = allDefs.concat(_availableHostEventDefinitions);
|
||||||
allDefs = allDefs.concat([
|
allDefs = allDefs.concat(["updateElementProduction"]);
|
||||||
"onPushObserveBinding",
|
|
||||||
"onPushObserveComponent",
|
|
||||||
"onPushObserveDirective",
|
|
||||||
"updateElementProduction"
|
|
||||||
]);
|
|
||||||
return allDefs.map(getDefinition);
|
return allDefs.map(getDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,6 @@ import {JitProtoChangeDetector} from 'angular2/src/core/change_detection/jit_pro
|
||||||
import {OnDestroy} from 'angular2/src/core/linker/interfaces';
|
import {OnDestroy} from 'angular2/src/core/linker/interfaces';
|
||||||
|
|
||||||
import {getDefinition} from './change_detector_config';
|
import {getDefinition} from './change_detector_config';
|
||||||
import {createObservableModel} from './change_detector_spec_util';
|
|
||||||
import {getFactoryById} from './generated/change_detector_classes';
|
import {getFactoryById} from './generated/change_detector_classes';
|
||||||
import {IS_DART} from 'angular2/src/facade/lang';
|
import {IS_DART} from 'angular2/src/facade/lang';
|
||||||
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
@ -1105,102 +1104,6 @@ export function main() {
|
||||||
expect(childDirectiveDetectorOnPush.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
|
expect(childDirectiveDetectorOnPush.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (IS_DART) {
|
|
||||||
describe('OnPushObserve', () => {
|
|
||||||
it('should mark OnPushObserve detectors as CheckOnce when an observable fires an event',
|
|
||||||
fakeAsync(() => {
|
|
||||||
var context = new TestDirective();
|
|
||||||
context.a = createObservableModel();
|
|
||||||
|
|
||||||
var cd = _createWithoutHydrate('onPushObserveBinding').changeDetector;
|
|
||||||
cd.hydrate(context, null, directives, null);
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
expect(cd.mode).toEqual(ChangeDetectionStrategy.Checked);
|
|
||||||
|
|
||||||
context.a.pushUpdate();
|
|
||||||
tick();
|
|
||||||
|
|
||||||
expect(cd.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should mark OnPushObserve detectors as CheckOnce when an observable context fires an event',
|
|
||||||
fakeAsync(() => {
|
|
||||||
var context = createObservableModel();
|
|
||||||
|
|
||||||
var cd = _createWithoutHydrate('onPushObserveComponent').changeDetector;
|
|
||||||
cd.hydrate(context, null, directives, null);
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
expect(cd.mode).toEqual(ChangeDetectionStrategy.Checked);
|
|
||||||
|
|
||||||
context.pushUpdate();
|
|
||||||
tick();
|
|
||||||
|
|
||||||
expect(cd.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should mark OnPushObserve detectors as CheckOnce when an observable directive fires an event',
|
|
||||||
fakeAsync(() => {
|
|
||||||
var dir = createObservableModel();
|
|
||||||
var directives = new TestDispatcher([dir], []);
|
|
||||||
|
|
||||||
var cd = _createWithoutHydrate('onPushObserveDirective').changeDetector;
|
|
||||||
cd.hydrate(_DEFAULT_CONTEXT, null, directives, null);
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
expect(cd.mode).toEqual(ChangeDetectionStrategy.Checked);
|
|
||||||
|
|
||||||
dir.pushUpdate();
|
|
||||||
tick();
|
|
||||||
|
|
||||||
expect(cd.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should unsubscribe from an old observable when an object changes',
|
|
||||||
fakeAsync(() => {
|
|
||||||
var originalModel = createObservableModel();
|
|
||||||
var context = new TestDirective();
|
|
||||||
context.a = originalModel;
|
|
||||||
|
|
||||||
var cd = _createWithoutHydrate('onPushObserveBinding').changeDetector;
|
|
||||||
cd.hydrate(context, null, directives, null);
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
context.a = createObservableModel();
|
|
||||||
cd.mode = ChangeDetectionStrategy.CheckOnce;
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
// Updating this model will not reenable the detector. This model is not longer
|
|
||||||
// used.
|
|
||||||
originalModel.pushUpdate();
|
|
||||||
tick();
|
|
||||||
expect(cd.mode).toEqual(ChangeDetectionStrategy.Checked);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should unsubscribe from observables when dehydrating', fakeAsync(() => {
|
|
||||||
var originalModel = createObservableModel();
|
|
||||||
var context = new TestDirective();
|
|
||||||
context.a = originalModel;
|
|
||||||
|
|
||||||
var cd = _createWithoutHydrate('onPushObserveBinding').changeDetector;
|
|
||||||
cd.hydrate(context, null, directives, null);
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
cd.dehydrate();
|
|
||||||
|
|
||||||
context.a = "not an observable model";
|
|
||||||
cd.hydrate(context, null, directives, null);
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
// Updating this model will not reenable the detector. This model is not longer
|
|
||||||
// used.
|
|
||||||
originalModel.pushUpdate();
|
|
||||||
tick();
|
|
||||||
expect(cd.mode).toEqual(ChangeDetectionStrategy.Checked);
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
library angular.change_detection.change_detector_spec_util;
|
|
||||||
|
|
||||||
import 'package:observe/observe.dart' show Observable;
|
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
dynamic createObservableModel() {
|
|
||||||
return new Entity();
|
|
||||||
}
|
|
||||||
|
|
||||||
class Entity implements Observable {
|
|
||||||
Stream changes;
|
|
||||||
StreamController controller;
|
|
||||||
|
|
||||||
Entity() {
|
|
||||||
controller = new StreamController.broadcast();
|
|
||||||
changes = controller.stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
pushUpdate() {
|
|
||||||
controller.add("new");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get hasObservers => null;
|
|
||||||
bool deliverChanges() => null;
|
|
||||||
notifyPropertyChange(Symbol field, Object oldValue, Object newValue) => null;
|
|
||||||
void notifyChange(record) {}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
export function createObservableModel(): any {
|
|
||||||
return null;
|
|
||||||
}
|
|
|
@ -802,7 +802,6 @@ var NG_CORE = [
|
||||||
'ChangeDetectionStrategy#Default',
|
'ChangeDetectionStrategy#Default',
|
||||||
'ChangeDetectionStrategy#Detached',
|
'ChangeDetectionStrategy#Detached',
|
||||||
'ChangeDetectionStrategy#OnPush',
|
'ChangeDetectionStrategy#OnPush',
|
||||||
'ChangeDetectionStrategy#OnPushObserve',
|
|
||||||
'ChangeDetectionStrategy#values',
|
'ChangeDetectionStrategy#values',
|
||||||
'ChangeDetectionStrategy',
|
'ChangeDetectionStrategy',
|
||||||
'ChangeDetectionStrategy.index',
|
'ChangeDetectionStrategy.index',
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
library benchmarks.src.naive_infinite_scroll.app;
|
|
||||||
|
|
||||||
import "package:angular2/src/facade/collection.dart" show List, ListWrapper;
|
|
||||||
import "scroll_area.dart" show ScrollAreaComponent;
|
|
||||||
import "package:angular2/angular2.dart" show Component, Directive, View, IterableDiffers, SkipSelf, Binding;
|
|
||||||
import "package:angular2/common.dart" show ObservableListDiffFactory, NgIf, NgFor;
|
|
||||||
import 'package:observe/observe.dart' show ObservableList;
|
|
||||||
|
|
||||||
createDiffers(IterableDiffers parent) {
|
|
||||||
return IterableDiffers.create([const ObservableListDiffFactory()], parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
const binding = const Binding(IterableDiffers,
|
|
||||||
toFactory: createDiffers, deps: const [ const[IterableDiffers, const SkipSelf()]]);
|
|
||||||
|
|
||||||
@Component(
|
|
||||||
selector: "scroll-app",
|
|
||||||
bindings: const [binding]
|
|
||||||
)
|
|
||||||
@View(directives: const [ScrollAreaComponent, NgIf, NgFor], template: '''
|
|
||||||
<div>
|
|
||||||
<div style="display: flex">
|
|
||||||
<scroll-area id="testArea"></scroll-area>
|
|
||||||
</div>
|
|
||||||
<div template="ngIf scrollAreas.length > 0">
|
|
||||||
<p>Following tables are only here to add weight to the UI:</p>
|
|
||||||
<scroll-area template="ngFor #scrollArea of scrollAreas"></scroll-area>
|
|
||||||
</div>
|
|
||||||
</div>''')
|
|
||||||
class App {
|
|
||||||
List<int> scrollAreas;
|
|
||||||
App() {
|
|
||||||
var scrollAreas = [];
|
|
||||||
for (var i = 0; i < 300; i++) {
|
|
||||||
scrollAreas.add(i);
|
|
||||||
}
|
|
||||||
this.scrollAreas = new ObservableList.from(scrollAreas);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
library benchmarks.src.naive_infinite_scroll.cells;
|
|
||||||
|
|
||||||
import "package:angular2/src/facade/collection.dart"
|
|
||||||
show List, ListWrapper, Map;
|
|
||||||
import "common.dart"
|
|
||||||
show Company, Opportunity, Offering, Account, CustomDate, STATUS_LIST;
|
|
||||||
import "package:angular2/common.dart" show NgFor;
|
|
||||||
import "package:angular2/angular2.dart" show Component, Directive, View, ChangeDetectionStrategy;
|
|
||||||
|
|
||||||
class HasStyle {
|
|
||||||
int cellWidth;
|
|
||||||
HasStyle() {}
|
|
||||||
set width(int w) {
|
|
||||||
this.cellWidth = w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Component(
|
|
||||||
selector: "company-name",
|
|
||||||
inputs: const ["width: cell-width", "company"],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPushObserve
|
|
||||||
)
|
|
||||||
@View(
|
|
||||||
directives: const [],
|
|
||||||
template: '''<div [style.width.px]="cellWidth">{{company.name}}</div>'''
|
|
||||||
)
|
|
||||||
class CompanyNameComponent extends HasStyle {
|
|
||||||
Company company;
|
|
||||||
}
|
|
||||||
@Component(
|
|
||||||
selector: "opportunity-name",
|
|
||||||
inputs: const ["width: cell-width", "opportunity"],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPushObserve
|
|
||||||
)
|
|
||||||
@View(
|
|
||||||
directives: const [],
|
|
||||||
template: '''<div [style.width.px]="cellWidth">{{opportunity.name}}</div>'''
|
|
||||||
)
|
|
||||||
class OpportunityNameComponent extends HasStyle {
|
|
||||||
Opportunity opportunity;
|
|
||||||
}
|
|
||||||
@Component(
|
|
||||||
selector: "offering-name",
|
|
||||||
inputs: const ["width: cell-width", "offering"],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPushObserve
|
|
||||||
)
|
|
||||||
@View(
|
|
||||||
directives: const [],
|
|
||||||
template: '''<div [style.width.px]="cellWidth">{{offering.name}}</div>'''
|
|
||||||
)
|
|
||||||
class OfferingNameComponent extends HasStyle {
|
|
||||||
Offering offering;
|
|
||||||
}
|
|
||||||
class Stage {
|
|
||||||
String name;
|
|
||||||
bool isDisabled;
|
|
||||||
String backgroundColor;
|
|
||||||
Function apply;
|
|
||||||
}
|
|
||||||
@Component(
|
|
||||||
selector: "stage-buttons",
|
|
||||||
inputs: const ["width: cell-width", "offering"],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPushObserve
|
|
||||||
)
|
|
||||||
@View(directives: const [NgFor], template: '''
|
|
||||||
<div [style.width.px]="cellWidth">
|
|
||||||
<button template="ngFor #stage of stages"
|
|
||||||
[disabled]="stage.isDisabled"
|
|
||||||
[style.background-color]="stage.backgroundColor"
|
|
||||||
on-click="setStage(stage)">
|
|
||||||
{{stage.name}}
|
|
||||||
</button>
|
|
||||||
</div>''')
|
|
||||||
class StageButtonsComponent extends HasStyle {
|
|
||||||
Offering _offering;
|
|
||||||
List<Stage> stages;
|
|
||||||
Offering get offering {
|
|
||||||
return this._offering;
|
|
||||||
}
|
|
||||||
set offering(Offering offering) {
|
|
||||||
this._offering = offering;
|
|
||||||
this._computeStageButtons();
|
|
||||||
}
|
|
||||||
setStage(Stage stage) {
|
|
||||||
this._offering.status = stage.name;
|
|
||||||
this._offering.name = this._offering.name + "!";
|
|
||||||
this._computeStageButtons();
|
|
||||||
}
|
|
||||||
_computeStageButtons() {
|
|
||||||
var disabled = true;
|
|
||||||
this.stages = ListWrapper.clone(STATUS_LIST.map((status) {
|
|
||||||
var isCurrent = this._offering.status == status;
|
|
||||||
var stage = new Stage();
|
|
||||||
stage.name = status;
|
|
||||||
stage.isDisabled = disabled;
|
|
||||||
stage.backgroundColor = disabled ? "#DDD" : isCurrent ? "#DDF" : "#FDD";
|
|
||||||
if (isCurrent) {
|
|
||||||
disabled = false;
|
|
||||||
}
|
|
||||||
return stage;
|
|
||||||
}).toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Component(
|
|
||||||
selector: "account-cell",
|
|
||||||
inputs: const ["width: cell-width", "account"],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPushObserve
|
|
||||||
)
|
|
||||||
@View(directives: const [], template: '''
|
|
||||||
<div [style.width.px]="cellWidth">
|
|
||||||
<a href="/account/{{account.accountId}}">
|
|
||||||
{{account.accountId}}
|
|
||||||
</a>
|
|
||||||
</div>''')
|
|
||||||
class AccountCellComponent extends HasStyle {
|
|
||||||
Account account;
|
|
||||||
}
|
|
||||||
@Component(
|
|
||||||
selector: "formatted-cell",
|
|
||||||
inputs: const ["width: cell-width", "value"],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPushObserve
|
|
||||||
)
|
|
||||||
@View(
|
|
||||||
directives: const [],
|
|
||||||
template: '''<div [style.width.px]="cellWidth">{{formattedValue}}</div>''')
|
|
||||||
class FormattedCellComponent extends HasStyle {
|
|
||||||
String formattedValue;
|
|
||||||
set value(value) {
|
|
||||||
if (value is CustomDate) {
|
|
||||||
this.formattedValue =
|
|
||||||
'''${ value . month}/${ value . day}/${ value . year}''';
|
|
||||||
} else {
|
|
||||||
this.formattedValue = value.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,243 +0,0 @@
|
||||||
library benchmarks.src.naive_infinite_scroll.common;
|
|
||||||
|
|
||||||
import "package:angular2/src/facade/math.dart" show Math;
|
|
||||||
import "package:angular2/src/facade/collection.dart";
|
|
||||||
import 'package:observe/observe.dart';
|
|
||||||
import 'dart:collection';
|
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
var ITEMS = 1000;
|
|
||||||
var ITEM_HEIGHT = 40;
|
|
||||||
var VISIBLE_ITEMS = 17;
|
|
||||||
var HEIGHT = ITEMS * ITEM_HEIGHT;
|
|
||||||
var VIEW_PORT_HEIGHT = ITEM_HEIGHT * VISIBLE_ITEMS;
|
|
||||||
var COMPANY_NAME_WIDTH = 100;
|
|
||||||
var OPPORTUNITY_NAME_WIDTH = 100;
|
|
||||||
var OFFERING_NAME_WIDTH = 100;
|
|
||||||
var ACCOUNT_CELL_WIDTH = 50;
|
|
||||||
var BASE_POINTS_WIDTH = 50;
|
|
||||||
var KICKER_POINTS_WIDTH = 50;
|
|
||||||
var STAGE_BUTTONS_WIDTH = 220;
|
|
||||||
var BUNDLES_WIDTH = 120;
|
|
||||||
var DUE_DATE_WIDTH = 100;
|
|
||||||
var END_DATE_WIDTH = 100;
|
|
||||||
var AAT_STATUS_WIDTH = 100;
|
|
||||||
var ROW_WIDTH = COMPANY_NAME_WIDTH +
|
|
||||||
OPPORTUNITY_NAME_WIDTH +
|
|
||||||
OFFERING_NAME_WIDTH +
|
|
||||||
ACCOUNT_CELL_WIDTH +
|
|
||||||
BASE_POINTS_WIDTH +
|
|
||||||
KICKER_POINTS_WIDTH +
|
|
||||||
STAGE_BUTTONS_WIDTH +
|
|
||||||
BUNDLES_WIDTH +
|
|
||||||
DUE_DATE_WIDTH +
|
|
||||||
END_DATE_WIDTH +
|
|
||||||
AAT_STATUS_WIDTH;
|
|
||||||
var STATUS_LIST = ["Planned", "Pitched", "Won", "Lost"];
|
|
||||||
var AAT_STATUS_LIST = ["Active", "Passive", "Abandoned"];
|
|
||||||
// Imitate Streamy entities.
|
|
||||||
|
|
||||||
// Just a non-trivial object. Nothing fancy or correct.
|
|
||||||
class CustomDate {
|
|
||||||
num year;
|
|
||||||
num month;
|
|
||||||
num day;
|
|
||||||
CustomDate(num y, num m, num d) {
|
|
||||||
this.year = y;
|
|
||||||
this.month = m;
|
|
||||||
this.day = d;
|
|
||||||
}
|
|
||||||
CustomDate addDays(num days) {
|
|
||||||
var newDay = this.day + days;
|
|
||||||
var newMonth = this.month + Math.floor(newDay / 30);
|
|
||||||
newDay = newDay % 30;
|
|
||||||
var newYear = this.year + Math.floor(newMonth / 12);
|
|
||||||
return new CustomDate(newYear, newMonth, newDay);
|
|
||||||
}
|
|
||||||
static CustomDate now() {
|
|
||||||
return new CustomDate(2014, 1, 28);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class RawEntity extends Object
|
|
||||||
with MapMixin<String, dynamic>
|
|
||||||
implements ObservableMap<String, dynamic> {
|
|
||||||
ObservableMap _data = new ObservableMap();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Iterable<String> get keys => _data.keys;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void clear() {
|
|
||||||
_data.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
operator [](untypedKey) {
|
|
||||||
var key = untypedKey as String;
|
|
||||||
if (!key.contains('.')) {
|
|
||||||
return _data[key];
|
|
||||||
}
|
|
||||||
var pieces = key.split('.');
|
|
||||||
var last = pieces.removeLast();
|
|
||||||
var target = _resolve(pieces, this);
|
|
||||||
if (target == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return target[last];
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
operator []=(String key, value) {
|
|
||||||
if (!key.contains('.')) {
|
|
||||||
_data[key] = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var pieces = key.split('.');
|
|
||||||
var last = pieces.removeLast();
|
|
||||||
var target = _resolve(pieces, this);
|
|
||||||
target[last] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic get(String name) { return this[name]; }
|
|
||||||
|
|
||||||
set(String name, dynamic value) { this[name] = value; }
|
|
||||||
|
|
||||||
@override
|
|
||||||
remove(untypedKey) {
|
|
||||||
var key = untypedKey as String;
|
|
||||||
if (!key.contains('.')) {
|
|
||||||
return _data.remove(key);
|
|
||||||
}
|
|
||||||
var pieces = key.split('.');
|
|
||||||
var last = pieces.removeLast();
|
|
||||||
var target = _resolve(pieces, this);
|
|
||||||
return target.remove(last);
|
|
||||||
}
|
|
||||||
|
|
||||||
_resolve(List<String> pieces, start) {
|
|
||||||
var cur = start;
|
|
||||||
for (var i = 0; i < pieces.length; i++) {
|
|
||||||
cur = cur[pieces[i]];
|
|
||||||
if (cur == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<List<ChangeRecord>> get changes => _data.changes;
|
|
||||||
@override
|
|
||||||
bool get hasObservers => _data.hasObservers;
|
|
||||||
@override
|
|
||||||
bool deliverChanges() => _data.deliverChanges();
|
|
||||||
@override
|
|
||||||
notifyPropertyChange(Symbol field, Object oldValue, Object newValue) =>
|
|
||||||
_data.notifyPropertyChange(field, oldValue, newValue);
|
|
||||||
@override
|
|
||||||
void notifyChange(ChangeRecord record) {
|
|
||||||
_data.notifyChange(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void observed() {
|
|
||||||
_data.observed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void unobserved() {
|
|
||||||
_data.observed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class Company extends RawEntity {
|
|
||||||
String get name {
|
|
||||||
return this.get("name");
|
|
||||||
}
|
|
||||||
set name(String val) {
|
|
||||||
this.set("name", val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class Offering extends RawEntity {
|
|
||||||
String get name {
|
|
||||||
return this.get("name");
|
|
||||||
}
|
|
||||||
set name(String val) {
|
|
||||||
this.set("name", val);
|
|
||||||
}
|
|
||||||
Company get company {
|
|
||||||
return this.get("company");
|
|
||||||
}
|
|
||||||
set company(Company val) {
|
|
||||||
this.set("company", val);
|
|
||||||
}
|
|
||||||
Opportunity get opportunity {
|
|
||||||
return this.get("opportunity");
|
|
||||||
}
|
|
||||||
set opportunity(Opportunity val) {
|
|
||||||
this.set("opportunity", val);
|
|
||||||
}
|
|
||||||
Account get account {
|
|
||||||
return this.get("account");
|
|
||||||
}
|
|
||||||
set account(Account val) {
|
|
||||||
this.set("account", val);
|
|
||||||
}
|
|
||||||
num get basePoints {
|
|
||||||
return this.get("basePoints");
|
|
||||||
}
|
|
||||||
set basePoints(num val) {
|
|
||||||
this.set("basePoints", val);
|
|
||||||
}
|
|
||||||
num get kickerPoints {
|
|
||||||
return this.get("kickerPoints");
|
|
||||||
}
|
|
||||||
set kickerPoints(num val) {
|
|
||||||
this.set("kickerPoints", val);
|
|
||||||
}
|
|
||||||
String get status {
|
|
||||||
return this.get("status");
|
|
||||||
}
|
|
||||||
set status(String val) {
|
|
||||||
this.set("status", val);
|
|
||||||
}
|
|
||||||
String get bundles {
|
|
||||||
return this.get("bundles");
|
|
||||||
}
|
|
||||||
set bundles(String val) {
|
|
||||||
this.set("bundles", val);
|
|
||||||
}
|
|
||||||
CustomDate get dueDate {
|
|
||||||
return this.get("dueDate");
|
|
||||||
}
|
|
||||||
set dueDate(CustomDate val) {
|
|
||||||
this.set("dueDate", val);
|
|
||||||
}
|
|
||||||
CustomDate get endDate {
|
|
||||||
return this.get("endDate");
|
|
||||||
}
|
|
||||||
set endDate(CustomDate val) {
|
|
||||||
this.set("endDate", val);
|
|
||||||
}
|
|
||||||
String get aatStatus {
|
|
||||||
return this.get("aatStatus");
|
|
||||||
}
|
|
||||||
set aatStatus(String val) {
|
|
||||||
this.set("aatStatus", val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class Opportunity extends RawEntity {
|
|
||||||
String get name {
|
|
||||||
return this.get("name");
|
|
||||||
}
|
|
||||||
set name(String val) {
|
|
||||||
this.set("name", val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class Account extends RawEntity {
|
|
||||||
num get accountId {
|
|
||||||
return this.get("accountId");
|
|
||||||
}
|
|
||||||
set accountId(num val) {
|
|
||||||
this.set("accountId", val);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
library benchmarks.src.naive_infinite_scroll.index;
|
|
||||||
|
|
||||||
import "package:angular2/bootstrap.dart" show bootstrap;
|
|
||||||
import "app.dart" show App;
|
|
||||||
import "package:angular2/core.dart" show bind;
|
|
||||||
|
|
||||||
main() {
|
|
||||||
bootstrap(App, createBindings());
|
|
||||||
}
|
|
||||||
List<dynamic> createBindings() {
|
|
||||||
return [];
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>AngularDart Scrolling Benchmark</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<scroll-app></scroll-app>
|
|
||||||
|
|
||||||
<script src="url_params_to_form.js" type="text/javascript"></script>
|
|
||||||
<script src="index.dart" type="application/dart"></script>
|
|
||||||
<script src="naive_infinite_scroll/packages/browser/dart.js" type="text/javascript"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,86 +0,0 @@
|
||||||
library benchmarks.src.naive_infinite_scroll.random_data;
|
|
||||||
|
|
||||||
import "package:angular2/src/facade/lang.dart" show StringWrapper;
|
|
||||||
import "package:angular2/src/facade/collection.dart" show List, ListWrapper;
|
|
||||||
import "common.dart"
|
|
||||||
show
|
|
||||||
CustomDate,
|
|
||||||
Offering,
|
|
||||||
Company,
|
|
||||||
Opportunity,
|
|
||||||
Account,
|
|
||||||
STATUS_LIST,
|
|
||||||
AAT_STATUS_LIST;
|
|
||||||
|
|
||||||
List<Offering> generateOfferings(int count) {
|
|
||||||
var res = [];
|
|
||||||
for (var i = 0; i < count; i++) {
|
|
||||||
res.add(generateOffering(i));
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
Offering generateOffering(int seed) {
|
|
||||||
var res = new Offering();
|
|
||||||
res.name = generateName(seed++);
|
|
||||||
res.company = generateCompany(seed++);
|
|
||||||
res.opportunity = generateOpportunity(seed++);
|
|
||||||
res.account = generateAccount(seed++);
|
|
||||||
res.basePoints = seed % 10;
|
|
||||||
res.kickerPoints = seed % 4;
|
|
||||||
res.status = STATUS_LIST[seed % STATUS_LIST.length];
|
|
||||||
res.bundles = randomString(seed++);
|
|
||||||
res.dueDate = randomDate(seed++);
|
|
||||||
res.endDate = randomDate(seed++, res.dueDate);
|
|
||||||
res.aatStatus = AAT_STATUS_LIST[seed % AAT_STATUS_LIST.length];
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
Company generateCompany(int seed) {
|
|
||||||
var res = new Company();
|
|
||||||
res.name = generateName(seed);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
Opportunity generateOpportunity(int seed) {
|
|
||||||
var res = new Opportunity();
|
|
||||||
res.name = generateName(seed);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
Account generateAccount(int seed) {
|
|
||||||
var res = new Account();
|
|
||||||
res.accountId = seed;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
var names = [
|
|
||||||
"Foo",
|
|
||||||
"Bar",
|
|
||||||
"Baz",
|
|
||||||
"Qux",
|
|
||||||
"Quux",
|
|
||||||
"Garply",
|
|
||||||
"Waldo",
|
|
||||||
"Fred",
|
|
||||||
"Plugh",
|
|
||||||
"Xyzzy",
|
|
||||||
"Thud",
|
|
||||||
"Cruft",
|
|
||||||
"Stuff"
|
|
||||||
];
|
|
||||||
String generateName(int seed) {
|
|
||||||
return names[seed % names.length];
|
|
||||||
}
|
|
||||||
var offsets = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
||||||
CustomDate randomDate(int seed, [CustomDate minDate = null]) {
|
|
||||||
if (minDate == null) {
|
|
||||||
minDate = CustomDate.now();
|
|
||||||
}
|
|
||||||
return minDate.addDays(offsets[seed % offsets.length]);
|
|
||||||
}
|
|
||||||
var stringLengths = [5, 7, 9, 11, 13];
|
|
||||||
var charCodeOffsets = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
|
||||||
String randomString(int seed) {
|
|
||||||
var len = stringLengths[seed % 5];
|
|
||||||
var str = "";
|
|
||||||
for (var i = 0; i < len; i++) {
|
|
||||||
str += StringWrapper.fromCharCode(97 + charCodeOffsets[seed % 9] + i);
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
library benchmarks.src.naive_infinite_scroll.scroll_area;
|
|
||||||
|
|
||||||
import "package:angular2/src/facade/collection.dart" show ListWrapper;
|
|
||||||
import "package:angular2/src/facade/math.dart" show Math;
|
|
||||||
import "package:angular2/angular2.dart" show Component, Directive, View, ChangeDetectionStrategy;
|
|
||||||
import "common.dart"
|
|
||||||
show
|
|
||||||
Offering,
|
|
||||||
ITEMS,
|
|
||||||
ITEM_HEIGHT,
|
|
||||||
VISIBLE_ITEMS,
|
|
||||||
VIEW_PORT_HEIGHT,
|
|
||||||
ROW_WIDTH,
|
|
||||||
HEIGHT;
|
|
||||||
import "random_data.dart" show generateOfferings;
|
|
||||||
import "scroll_item.dart" show ScrollItemComponent;
|
|
||||||
import "package:angular2/common.dart" show NgFor;
|
|
||||||
|
|
||||||
@Component(selector: "scroll-area", changeDetection: ChangeDetectionStrategy.OnPushObserve)
|
|
||||||
@View(directives: const [ScrollItemComponent, NgFor], template: '''
|
|
||||||
<div>
|
|
||||||
<div id="scrollDiv"
|
|
||||||
[style.height.px]="viewPortHeight"
|
|
||||||
style="width: 1000px; border: 1px solid #000; overflow: scroll"
|
|
||||||
on-scroll="onScroll(\$event)">
|
|
||||||
<div id="padding"></div>
|
|
||||||
<div id="inner">
|
|
||||||
<scroll-item
|
|
||||||
template="ngFor #item of visibleItems"
|
|
||||||
[offering]="item">
|
|
||||||
</scroll-item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>''')
|
|
||||||
class ScrollAreaComponent {
|
|
||||||
List<Offering> _fullList;
|
|
||||||
List<Offering> visibleItems;
|
|
||||||
num viewPortHeight;
|
|
||||||
var paddingDiv;
|
|
||||||
var innerDiv;
|
|
||||||
ScrollAreaComponent() {
|
|
||||||
this._fullList = generateOfferings(ITEMS);
|
|
||||||
this.visibleItems = [];
|
|
||||||
this.viewPortHeight = VIEW_PORT_HEIGHT;
|
|
||||||
this.onScroll(null);
|
|
||||||
}
|
|
||||||
onScroll(evt) {
|
|
||||||
var scrollTop = 0;
|
|
||||||
if (evt != null) {
|
|
||||||
var scrollDiv = evt.target;
|
|
||||||
if (this.paddingDiv == null) {
|
|
||||||
this.paddingDiv = scrollDiv.querySelector("#padding");
|
|
||||||
}
|
|
||||||
if (this.innerDiv == null) {
|
|
||||||
this.innerDiv = scrollDiv.querySelector("#inner");
|
|
||||||
this.innerDiv.style.setProperty("width", '''${ ROW_WIDTH}px''');
|
|
||||||
}
|
|
||||||
scrollTop = scrollDiv.scrollTop;
|
|
||||||
}
|
|
||||||
var iStart = Math.floor(scrollTop / ITEM_HEIGHT);
|
|
||||||
var iEnd = Math.min(iStart + VISIBLE_ITEMS + 1, this._fullList.length);
|
|
||||||
var padding = iStart * ITEM_HEIGHT;
|
|
||||||
if (this.innerDiv != null) {
|
|
||||||
this.innerDiv.style.setProperty("height", '''${ HEIGHT - padding}px''');
|
|
||||||
}
|
|
||||||
if (this.paddingDiv != null) {
|
|
||||||
this.paddingDiv.style.setProperty("height", '''${ padding}px''');
|
|
||||||
}
|
|
||||||
this.visibleItems = ListWrapper.slice(this._fullList, iStart, iEnd);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,117 +0,0 @@
|
||||||
library benchmarks.src.naive_infinite_scroll.scroll_item;
|
|
||||||
|
|
||||||
import "cells.dart"
|
|
||||||
show
|
|
||||||
CompanyNameComponent,
|
|
||||||
OpportunityNameComponent,
|
|
||||||
OfferingNameComponent,
|
|
||||||
StageButtonsComponent,
|
|
||||||
AccountCellComponent,
|
|
||||||
FormattedCellComponent;
|
|
||||||
import "package:angular2/angular2.dart" show Component, Directive, View, ChangeDetectionStrategy;
|
|
||||||
import "common.dart"
|
|
||||||
show
|
|
||||||
Offering,
|
|
||||||
ITEM_HEIGHT,
|
|
||||||
COMPANY_NAME_WIDTH,
|
|
||||||
OPPORTUNITY_NAME_WIDTH,
|
|
||||||
OFFERING_NAME_WIDTH,
|
|
||||||
ACCOUNT_CELL_WIDTH,
|
|
||||||
BASE_POINTS_WIDTH,
|
|
||||||
KICKER_POINTS_WIDTH,
|
|
||||||
STAGE_BUTTONS_WIDTH,
|
|
||||||
BUNDLES_WIDTH,
|
|
||||||
DUE_DATE_WIDTH,
|
|
||||||
END_DATE_WIDTH,
|
|
||||||
AAT_STATUS_WIDTH;
|
|
||||||
|
|
||||||
@Component(selector: "scroll-item", inputs: const ["offering"],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPushObserve)
|
|
||||||
@View(
|
|
||||||
directives: const [
|
|
||||||
CompanyNameComponent,
|
|
||||||
OpportunityNameComponent,
|
|
||||||
OfferingNameComponent,
|
|
||||||
StageButtonsComponent,
|
|
||||||
AccountCellComponent,
|
|
||||||
FormattedCellComponent
|
|
||||||
],
|
|
||||||
template: '''
|
|
||||||
<div class="row"
|
|
||||||
[style.height.px]="itemHeight"
|
|
||||||
[style.line-height.px]="itemHeight"
|
|
||||||
style="font-size: 18px; display: flex; justify-content: space-between;">
|
|
||||||
<company-name [company]="offering.company"
|
|
||||||
[cell-width]="companyNameWidth">
|
|
||||||
</company-name>
|
|
||||||
<opportunity-name [opportunity]="offering.opportunity"
|
|
||||||
[cell-width]="opportunityNameWidth">
|
|
||||||
</opportunity-name>
|
|
||||||
<offering-name [offering]="offering"
|
|
||||||
[cell-width]="offeringNameWidth">
|
|
||||||
</offering-name>
|
|
||||||
<account-cell [account]="offering.account"
|
|
||||||
[cell-width]="accountCellWidth">
|
|
||||||
</account-cell>
|
|
||||||
<formatted-cell [value]="offering.basePoints"
|
|
||||||
[cell-width]="basePointsWidth">
|
|
||||||
</formatted-cell>
|
|
||||||
<formatted-cell [value]="offering.kickerPoints"
|
|
||||||
[cell-width]="kickerPointsWidth">
|
|
||||||
</formatted-cell>
|
|
||||||
<stage-buttons [offering]="offering"
|
|
||||||
[cell-width]="stageButtonsWidth">
|
|
||||||
</stage-buttons>
|
|
||||||
<formatted-cell [value]="offering.bundles"
|
|
||||||
[cell-width]="bundlesWidth">
|
|
||||||
</formatted-cell>
|
|
||||||
<formatted-cell [value]="offering.dueDate"
|
|
||||||
[cell-width]="dueDateWidth">
|
|
||||||
</formatted-cell>
|
|
||||||
<formatted-cell [value]="offering.endDate"
|
|
||||||
[cell-width]="endDateWidth">
|
|
||||||
</formatted-cell>
|
|
||||||
<formatted-cell [value]="offering.aatStatus"
|
|
||||||
[cell-width]="aatStatusWidth">
|
|
||||||
</formatted-cell>
|
|
||||||
</div>''')
|
|
||||||
class ScrollItemComponent {
|
|
||||||
Offering offering;
|
|
||||||
num itemHeight;
|
|
||||||
ScrollItemComponent() {
|
|
||||||
this.itemHeight = ITEM_HEIGHT;
|
|
||||||
}
|
|
||||||
get companyNameWidth {
|
|
||||||
return COMPANY_NAME_WIDTH;
|
|
||||||
}
|
|
||||||
get opportunityNameWidth {
|
|
||||||
return OPPORTUNITY_NAME_WIDTH;
|
|
||||||
}
|
|
||||||
get offeringNameWidth {
|
|
||||||
return OFFERING_NAME_WIDTH;
|
|
||||||
}
|
|
||||||
get accountCellWidth {
|
|
||||||
return ACCOUNT_CELL_WIDTH;
|
|
||||||
}
|
|
||||||
get basePointsWidth {
|
|
||||||
return BASE_POINTS_WIDTH;
|
|
||||||
}
|
|
||||||
get kickerPointsWidth {
|
|
||||||
return KICKER_POINTS_WIDTH;
|
|
||||||
}
|
|
||||||
get stageButtonsWidth {
|
|
||||||
return STAGE_BUTTONS_WIDTH;
|
|
||||||
}
|
|
||||||
get bundlesWidth {
|
|
||||||
return BUNDLES_WIDTH;
|
|
||||||
}
|
|
||||||
get dueDateWidth {
|
|
||||||
return DUE_DATE_WIDTH;
|
|
||||||
}
|
|
||||||
get endDateWidth {
|
|
||||||
return END_DATE_WIDTH;
|
|
||||||
}
|
|
||||||
get aatStatusWidth {
|
|
||||||
return AAT_STATUS_WIDTH;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
// helper script that will read out the url parameters
|
|
||||||
// and store them in appropriate form fields on the page
|
|
||||||
(function() {
|
|
||||||
var regex = /(\w+)=(\w+)/g;
|
|
||||||
var search = decodeURIComponent(location.search);
|
|
||||||
while (match = regex.exec(search)) {
|
|
||||||
var name = match[1];
|
|
||||||
var value = match[2];
|
|
||||||
var els = document.querySelectorAll('input[name="'+name+'"]');
|
|
||||||
var el;
|
|
||||||
for (var i=0; i<els.length; i++) {
|
|
||||||
el = els[i];
|
|
||||||
if (el.type === 'radio' || el.type === 'checkbox') {
|
|
||||||
el.checked = el.value === value;
|
|
||||||
} else {
|
|
||||||
el.value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
|
@ -124,7 +124,7 @@ class _CodegenState {
|
||||||
var names = new CodegenNameUtil(
|
var names = new CodegenNameUtil(
|
||||||
protoRecords, eventBindings, def.directiveRecords, '$genPrefix$_UTIL');
|
protoRecords, eventBindings, def.directiveRecords, '$genPrefix$_UTIL');
|
||||||
var logic = new CodegenLogicUtil(
|
var logic = new CodegenLogicUtil(
|
||||||
names, '$genPrefix$_UTIL', '$genPrefix$_STATE', def.strategy);
|
names, '$genPrefix$_UTIL', '$genPrefix$_STATE');
|
||||||
return new _CodegenState._(
|
return new _CodegenState._(
|
||||||
genPrefix,
|
genPrefix,
|
||||||
def.id,
|
def.id,
|
||||||
|
|
|
@ -70,7 +70,6 @@ const CORE = [
|
||||||
'ChangeDetectionStrategy.Default',
|
'ChangeDetectionStrategy.Default',
|
||||||
'ChangeDetectionStrategy.Detached',
|
'ChangeDetectionStrategy.Detached',
|
||||||
'ChangeDetectionStrategy.OnPush',
|
'ChangeDetectionStrategy.OnPush',
|
||||||
'ChangeDetectionStrategy.OnPushObserve',
|
|
||||||
'ChangeDetectorRef',
|
'ChangeDetectorRef',
|
||||||
'ChangeDetectorRef.checkNoChanges():void',
|
'ChangeDetectorRef.checkNoChanges():void',
|
||||||
'ChangeDetectorRef.detach():void',
|
'ChangeDetectorRef.detach():void',
|
||||||
|
|
Loading…
Reference in New Issue