feat(compiler): add BindingPropagationConfig to the list of pre-built objects
This commit is contained in:
parent
23a080026a
commit
fc6e421e7e
|
@ -4,7 +4,8 @@ export {Parser} from './src/parser/parser';
|
|||
export {ContextWithVariableBindings} from './src/parser/context_with_variable_bindings';
|
||||
|
||||
export {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError} from './src/exceptions';
|
||||
export {ChangeRecord, ChangeDispatcher, ChangeDetector} from './src/interfaces';
|
||||
export {ChangeRecord, ChangeDispatcher, ChangeDetector,
|
||||
CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED} from './src/interfaces';
|
||||
export {ProtoChangeDetector, DynamicProtoChangeDetector, JitProtoChangeDetector} from './src/proto_change_detector';
|
||||
export {DynamicChangeDetector} from './src/dynamic_change_detector';
|
||||
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
import {isPresent} from 'facade/lang';
|
||||
import {List, ListWrapper, Map, MapWrapper} from 'facade/collection';
|
||||
import {RECORD_TYPE_SELF, ProtoRecord} from './proto_change_detector';
|
||||
|
||||
/**
|
||||
* Removes "duplicate" records. It assuming that record evaluation does not
|
||||
* have side-effects.
|
||||
*
|
||||
* Records that are not last in bindings are removed and all the indices
|
||||
* of the records that depend on them are updated.
|
||||
*
|
||||
* Records that are last in bindings CANNOT be removed, and instead are
|
||||
* replaced with very cheap SELF records.
|
||||
*/
|
||||
export function coalesce(records:List<ProtoRecord>):List<ProtoRecord> {
|
||||
var res = ListWrapper.create();
|
||||
var indexMap = MapWrapper.create();
|
||||
|
||||
for (var i = 0; i < records.length; ++i) {
|
||||
var r = records[i];
|
||||
var record = _replaceIndices(r, res.length + 1, indexMap);
|
||||
var matchingRecord = _findMatching(record, res);
|
||||
|
||||
if (isPresent(matchingRecord) && record.lastInBinding) {
|
||||
ListWrapper.push(res, _selfRecord(record, matchingRecord.selfIndex, res.length + 1));
|
||||
MapWrapper.set(indexMap, r.selfIndex, matchingRecord.selfIndex);
|
||||
|
||||
} else if (isPresent(matchingRecord) && !record.lastInBinding) {
|
||||
MapWrapper.set(indexMap, r.selfIndex, matchingRecord.selfIndex);
|
||||
|
||||
} else {
|
||||
ListWrapper.push(res, record);
|
||||
MapWrapper.set(indexMap, r.selfIndex, record.selfIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function _selfRecord(r:ProtoRecord, contextIndex:number, selfIndex:number):ProtoRecord {
|
||||
return new ProtoRecord(
|
||||
RECORD_TYPE_SELF,
|
||||
"self",
|
||||
null,
|
||||
[],
|
||||
r.fixedArgs,
|
||||
contextIndex,
|
||||
selfIndex,
|
||||
r.bindingMemento,
|
||||
r.groupMemento,
|
||||
r.expressionAsString,
|
||||
r.lastInBinding,
|
||||
r.lastInGroup
|
||||
);
|
||||
}
|
||||
|
||||
function _findMatching(r:ProtoRecord, rs:List<ProtoRecord>){
|
||||
return ListWrapper.find(rs, (rr) =>
|
||||
rr.mode === r.mode &&
|
||||
rr.funcOrValue === r.funcOrValue &&
|
||||
rr.contextIndex === r.contextIndex &&
|
||||
ListWrapper.equals(rr.args, r.args)
|
||||
);
|
||||
}
|
||||
|
||||
function _replaceIndices(r:ProtoRecord, selfIndex:number, indexMap:Map) {
|
||||
var args = ListWrapper.map(r.args, (a) => _map(indexMap, a));
|
||||
var contextIndex = _map(indexMap, r.contextIndex);
|
||||
return new ProtoRecord(
|
||||
r.mode,
|
||||
r.name,
|
||||
r.funcOrValue,
|
||||
args,
|
||||
r.fixedArgs,
|
||||
contextIndex,
|
||||
selfIndex,
|
||||
r.bindingMemento,
|
||||
r.groupMemento,
|
||||
r.expressionAsString,
|
||||
r.lastInBinding,
|
||||
r.lastInGroup
|
||||
);
|
||||
}
|
||||
|
||||
function _map(indexMap:Map, value:number) {
|
||||
var r = MapWrapper.get(indexMap, value)
|
||||
return isPresent(r) ? r : value;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import {ChangeDetector, CHECK_ONCE, DETACHED, CHECK_ALWAYS} from 'change_detection/change_detection';
|
||||
|
||||
export class BindingPropagationConfig {
|
||||
_cd:ChangeDetector;
|
||||
|
||||
constructor(cd:ChangeDetector) {
|
||||
this._cd = cd;
|
||||
}
|
||||
|
||||
shouldBePropagated() {
|
||||
this._cd.mode = CHECK_ONCE;
|
||||
}
|
||||
|
||||
shouldBePropagatedFromRoot() {
|
||||
this._cd.markAsCheckOnce();
|
||||
}
|
||||
|
||||
shouldNotPropagate() {
|
||||
this._cd.mode = DETACHED;
|
||||
}
|
||||
|
||||
shouldAlwaysPropagate() {
|
||||
this._cd.mode = CHECK_ALWAYS;
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import {LightDom, SourceLightDom, DestinationLightDom} from 'core/src/compiler/s
|
|||
import {ViewPort} from 'core/src/compiler/viewport';
|
||||
import {NgElement} from 'core/src/dom/element';
|
||||
import {Directive} from 'core/src/annotations/annotations'
|
||||
import {BindingPropagationConfig} from 'core/src/compiler/binding_propagation_config'
|
||||
|
||||
var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10;
|
||||
|
||||
|
@ -20,11 +21,12 @@ var _undefined = new Object();
|
|||
var _staticKeys;
|
||||
|
||||
class StaticKeys {
|
||||
viewId:int;
|
||||
ngElementId:int;
|
||||
viewPortId:int;
|
||||
destinationLightDomId:int;
|
||||
sourceLightDomId:int;
|
||||
viewId:number;
|
||||
ngElementId:number;
|
||||
viewPortId:number;
|
||||
destinationLightDomId:number;
|
||||
sourceLightDomId:number;
|
||||
bindingPropagationConfigId:number;
|
||||
|
||||
constructor() {
|
||||
//TODO: vsavkin Key.annotate(Key.get(View), 'static')
|
||||
|
@ -33,6 +35,7 @@ class StaticKeys {
|
|||
this.viewPortId = Key.get(ViewPort).id;
|
||||
this.destinationLightDomId = Key.get(DestinationLightDom).id;
|
||||
this.sourceLightDomId = Key.get(SourceLightDom).id;
|
||||
this.bindingPropagationConfigId = Key.get(BindingPropagationConfig).id;
|
||||
}
|
||||
|
||||
static instance() {
|
||||
|
@ -151,11 +154,14 @@ export class PreBuiltObjects {
|
|||
element:NgElement;
|
||||
viewPort:ViewPort;
|
||||
lightDom:LightDom;
|
||||
constructor(view, element:NgElement, viewPort:ViewPort, lightDom:LightDom) {
|
||||
bindingPropagationConfig:BindingPropagationConfig;
|
||||
constructor(view, element:NgElement, viewPort:ViewPort, lightDom:LightDom,
|
||||
bindingPropagationConfig:BindingPropagationConfig) {
|
||||
this.view = view;
|
||||
this.element = element;
|
||||
this.viewPort = viewPort;
|
||||
this.lightDom = lightDom;
|
||||
this.bindingPropagationConfig = bindingPropagationConfig;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -532,6 +538,7 @@ export class ElementInjector extends TreeNode {
|
|||
if (keyId === staticKeys.viewId) return this._preBuiltObjects.view;
|
||||
if (keyId === staticKeys.ngElementId) return this._preBuiltObjects.element;
|
||||
if (keyId === staticKeys.viewPortId) return this._preBuiltObjects.viewPort;
|
||||
if (keyId === staticKeys.bindingPropagationConfigId) return this._preBuiltObjects.bindingPropagationConfig;
|
||||
if (keyId === staticKeys.destinationLightDomId) {
|
||||
var p:ElementInjector = this.directParent();
|
||||
return isPresent(p) ? p._preBuiltObjects.lightDom : null;
|
||||
|
|
|
@ -4,6 +4,7 @@ import {AST, ContextWithVariableBindings, ChangeDispatcher, ProtoChangeDetector,
|
|||
from 'change_detection/change_detection';
|
||||
|
||||
import {ProtoElementInjector, ElementInjector, PreBuiltObjects} from './element_injector';
|
||||
import {BindingPropagationConfig} from './binding_propagation_config';
|
||||
import {ElementBinder} from './element_binder';
|
||||
import {DirectiveMetadata} from './directive_metadata';
|
||||
import {SetterFn} from 'reflection/src/types';
|
||||
|
@ -350,6 +351,7 @@ export class ProtoView {
|
|||
|
||||
// componentChildViews
|
||||
var lightDom = null;
|
||||
var bindingPropagationConfig = null;
|
||||
if (isPresent(binder.componentDirective)) {
|
||||
var childView = binder.nestedProtoView.instantiate(elementInjector);
|
||||
view.changeDetector.addChild(childView.changeDetector);
|
||||
|
@ -357,6 +359,8 @@ export class ProtoView {
|
|||
lightDom = binder.componentDirective.shadowDomStrategy.constructLightDom(view, childView, element);
|
||||
binder.componentDirective.shadowDomStrategy.attachTemplate(element, childView);
|
||||
|
||||
bindingPropagationConfig = new BindingPropagationConfig(view.changeDetector);
|
||||
|
||||
ListWrapper.push(componentChildViews, childView);
|
||||
}
|
||||
|
||||
|
@ -370,7 +374,8 @@ export class ProtoView {
|
|||
|
||||
// preBuiltObjects
|
||||
if (isPresent(elementInjector)) {
|
||||
preBuiltObjects[i] = new PreBuiltObjects(view, new NgElement(element), viewPort, lightDom);
|
||||
preBuiltObjects[i] = new PreBuiltObjects(view, new NgElement(element), viewPort,
|
||||
lightDom, bindingPropagationConfig);
|
||||
}
|
||||
|
||||
// events
|
||||
|
|
|
@ -12,6 +12,7 @@ import {ViewPort} from 'core/src/compiler/viewport';
|
|||
import {NgElement} from 'core/src/dom/element';
|
||||
import {LightDom, SourceLightDom, DestinationLightDom} from 'core/src/compiler/shadow_dom_emulation/light_dom';
|
||||
import {Directive} from 'core/src/annotations/annotations';
|
||||
import {BindingPropagationConfig} from 'core/src/compiler/binding_propagation_config';
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(View)
|
||||
|
@ -95,7 +96,7 @@ class DirectiveWithDestroy {
|
|||
}
|
||||
|
||||
export function main() {
|
||||
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null, null);
|
||||
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null, null, null);
|
||||
|
||||
function humanize(tree, names:List) {
|
||||
var lookupName = (item) =>
|
||||
|
@ -245,7 +246,7 @@ export function main() {
|
|||
|
||||
it("should instantiate directives that depend on pre built objects", function () {
|
||||
var view = new DummyView();
|
||||
var inj = injector([NeedsView], null, null, new PreBuiltObjects(view, null, null, null));
|
||||
var inj = injector([NeedsView], null, null, new PreBuiltObjects(view, null, null, null, null));
|
||||
|
||||
expect(inj.get(NeedsView).view).toBe(view);
|
||||
});
|
||||
|
@ -365,31 +366,38 @@ export function main() {
|
|||
describe("pre built objects", function () {
|
||||
it("should return view", function () {
|
||||
var view = new DummyView();
|
||||
var inj = injector([], null, null, new PreBuiltObjects(view, null, null, null));
|
||||
var inj = injector([], null, null, new PreBuiltObjects(view, null, null, null, null));
|
||||
|
||||
expect(inj.get(View)).toEqual(view);
|
||||
});
|
||||
|
||||
it("should return element", function () {
|
||||
var element = new NgElement(null);
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, element, null, null));
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, element, null, null, null));
|
||||
|
||||
expect(inj.get(NgElement)).toEqual(element);
|
||||
});
|
||||
|
||||
it('should return viewPort', function () {
|
||||
var viewPort = new ViewPort(null, null, null, null);
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, null, viewPort, null));
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, null, viewPort, null, null));
|
||||
|
||||
expect(inj.get(ViewPort)).toEqual(viewPort);
|
||||
});
|
||||
|
||||
it('should return bindingPropagationConfig', function () {
|
||||
var config = new BindingPropagationConfig(null);
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, null, null, null, config));
|
||||
|
||||
expect(inj.get(BindingPropagationConfig)).toEqual(config);
|
||||
});
|
||||
|
||||
describe("light DOM", () => {
|
||||
var lightDom, parentPreBuiltObjects;
|
||||
|
||||
beforeEach(() => {
|
||||
lightDom = new DummyLightDom();
|
||||
parentPreBuiltObjects = new PreBuiltObjects(null, null, null, lightDom);
|
||||
parentPreBuiltObjects = new PreBuiltObjects(null, null, null, lightDom, null);
|
||||
});
|
||||
|
||||
it("should return destination light DOM from the parent's injector", function () {
|
||||
|
|
Loading…
Reference in New Issue