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 {ContextWithVariableBindings} from './src/parser/context_with_variable_bindings';
|
||||||
|
|
||||||
export {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError} from './src/exceptions';
|
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 {ProtoChangeDetector, DynamicProtoChangeDetector, JitProtoChangeDetector} from './src/proto_change_detector';
|
||||||
export {DynamicChangeDetector} from './src/dynamic_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;
|
|
||||||
}
|
|
25
modules/core/src/compiler/binding_propagation_config.js
Normal file
25
modules/core/src/compiler/binding_propagation_config.js
Normal file
@ -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 {ViewPort} from 'core/src/compiler/viewport';
|
||||||
import {NgElement} from 'core/src/dom/element';
|
import {NgElement} from 'core/src/dom/element';
|
||||||
import {Directive} from 'core/src/annotations/annotations'
|
import {Directive} from 'core/src/annotations/annotations'
|
||||||
|
import {BindingPropagationConfig} from 'core/src/compiler/binding_propagation_config'
|
||||||
|
|
||||||
var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10;
|
var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10;
|
||||||
|
|
||||||
@ -20,11 +21,12 @@ var _undefined = new Object();
|
|||||||
var _staticKeys;
|
var _staticKeys;
|
||||||
|
|
||||||
class StaticKeys {
|
class StaticKeys {
|
||||||
viewId:int;
|
viewId:number;
|
||||||
ngElementId:int;
|
ngElementId:number;
|
||||||
viewPortId:int;
|
viewPortId:number;
|
||||||
destinationLightDomId:int;
|
destinationLightDomId:number;
|
||||||
sourceLightDomId:int;
|
sourceLightDomId:number;
|
||||||
|
bindingPropagationConfigId:number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
//TODO: vsavkin Key.annotate(Key.get(View), 'static')
|
//TODO: vsavkin Key.annotate(Key.get(View), 'static')
|
||||||
@ -33,6 +35,7 @@ class StaticKeys {
|
|||||||
this.viewPortId = Key.get(ViewPort).id;
|
this.viewPortId = Key.get(ViewPort).id;
|
||||||
this.destinationLightDomId = Key.get(DestinationLightDom).id;
|
this.destinationLightDomId = Key.get(DestinationLightDom).id;
|
||||||
this.sourceLightDomId = Key.get(SourceLightDom).id;
|
this.sourceLightDomId = Key.get(SourceLightDom).id;
|
||||||
|
this.bindingPropagationConfigId = Key.get(BindingPropagationConfig).id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static instance() {
|
static instance() {
|
||||||
@ -151,11 +154,14 @@ export class PreBuiltObjects {
|
|||||||
element:NgElement;
|
element:NgElement;
|
||||||
viewPort:ViewPort;
|
viewPort:ViewPort;
|
||||||
lightDom:LightDom;
|
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.view = view;
|
||||||
this.element = element;
|
this.element = element;
|
||||||
this.viewPort = viewPort;
|
this.viewPort = viewPort;
|
||||||
this.lightDom = lightDom;
|
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.viewId) return this._preBuiltObjects.view;
|
||||||
if (keyId === staticKeys.ngElementId) return this._preBuiltObjects.element;
|
if (keyId === staticKeys.ngElementId) return this._preBuiltObjects.element;
|
||||||
if (keyId === staticKeys.viewPortId) return this._preBuiltObjects.viewPort;
|
if (keyId === staticKeys.viewPortId) return this._preBuiltObjects.viewPort;
|
||||||
|
if (keyId === staticKeys.bindingPropagationConfigId) return this._preBuiltObjects.bindingPropagationConfig;
|
||||||
if (keyId === staticKeys.destinationLightDomId) {
|
if (keyId === staticKeys.destinationLightDomId) {
|
||||||
var p:ElementInjector = this.directParent();
|
var p:ElementInjector = this.directParent();
|
||||||
return isPresent(p) ? p._preBuiltObjects.lightDom : null;
|
return isPresent(p) ? p._preBuiltObjects.lightDom : null;
|
||||||
|
@ -4,6 +4,7 @@ import {AST, ContextWithVariableBindings, ChangeDispatcher, ProtoChangeDetector,
|
|||||||
from 'change_detection/change_detection';
|
from 'change_detection/change_detection';
|
||||||
|
|
||||||
import {ProtoElementInjector, ElementInjector, PreBuiltObjects} from './element_injector';
|
import {ProtoElementInjector, ElementInjector, PreBuiltObjects} from './element_injector';
|
||||||
|
import {BindingPropagationConfig} from './binding_propagation_config';
|
||||||
import {ElementBinder} from './element_binder';
|
import {ElementBinder} from './element_binder';
|
||||||
import {DirectiveMetadata} from './directive_metadata';
|
import {DirectiveMetadata} from './directive_metadata';
|
||||||
import {SetterFn} from 'reflection/src/types';
|
import {SetterFn} from 'reflection/src/types';
|
||||||
@ -350,6 +351,7 @@ export class ProtoView {
|
|||||||
|
|
||||||
// componentChildViews
|
// componentChildViews
|
||||||
var lightDom = null;
|
var lightDom = null;
|
||||||
|
var bindingPropagationConfig = null;
|
||||||
if (isPresent(binder.componentDirective)) {
|
if (isPresent(binder.componentDirective)) {
|
||||||
var childView = binder.nestedProtoView.instantiate(elementInjector);
|
var childView = binder.nestedProtoView.instantiate(elementInjector);
|
||||||
view.changeDetector.addChild(childView.changeDetector);
|
view.changeDetector.addChild(childView.changeDetector);
|
||||||
@ -357,6 +359,8 @@ export class ProtoView {
|
|||||||
lightDom = binder.componentDirective.shadowDomStrategy.constructLightDom(view, childView, element);
|
lightDom = binder.componentDirective.shadowDomStrategy.constructLightDom(view, childView, element);
|
||||||
binder.componentDirective.shadowDomStrategy.attachTemplate(element, childView);
|
binder.componentDirective.shadowDomStrategy.attachTemplate(element, childView);
|
||||||
|
|
||||||
|
bindingPropagationConfig = new BindingPropagationConfig(view.changeDetector);
|
||||||
|
|
||||||
ListWrapper.push(componentChildViews, childView);
|
ListWrapper.push(componentChildViews, childView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,7 +374,8 @@ export class ProtoView {
|
|||||||
|
|
||||||
// preBuiltObjects
|
// preBuiltObjects
|
||||||
if (isPresent(elementInjector)) {
|
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
|
// events
|
||||||
|
@ -12,6 +12,7 @@ import {ViewPort} from 'core/src/compiler/viewport';
|
|||||||
import {NgElement} from 'core/src/dom/element';
|
import {NgElement} from 'core/src/dom/element';
|
||||||
import {LightDom, SourceLightDom, DestinationLightDom} from 'core/src/compiler/shadow_dom_emulation/light_dom';
|
import {LightDom, SourceLightDom, DestinationLightDom} from 'core/src/compiler/shadow_dom_emulation/light_dom';
|
||||||
import {Directive} from 'core/src/annotations/annotations';
|
import {Directive} from 'core/src/annotations/annotations';
|
||||||
|
import {BindingPropagationConfig} from 'core/src/compiler/binding_propagation_config';
|
||||||
|
|
||||||
@proxy
|
@proxy
|
||||||
@IMPLEMENTS(View)
|
@IMPLEMENTS(View)
|
||||||
@ -95,7 +96,7 @@ class DirectiveWithDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
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) {
|
function humanize(tree, names:List) {
|
||||||
var lookupName = (item) =>
|
var lookupName = (item) =>
|
||||||
@ -245,7 +246,7 @@ export function main() {
|
|||||||
|
|
||||||
it("should instantiate directives that depend on pre built objects", function () {
|
it("should instantiate directives that depend on pre built objects", function () {
|
||||||
var view = new DummyView();
|
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);
|
expect(inj.get(NeedsView).view).toBe(view);
|
||||||
});
|
});
|
||||||
@ -365,31 +366,38 @@ export function main() {
|
|||||||
describe("pre built objects", function () {
|
describe("pre built objects", function () {
|
||||||
it("should return view", function () {
|
it("should return view", function () {
|
||||||
var view = new DummyView();
|
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);
|
expect(inj.get(View)).toEqual(view);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return element", function () {
|
it("should return element", function () {
|
||||||
var element = new NgElement(null);
|
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);
|
expect(inj.get(NgElement)).toEqual(element);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return viewPort', function () {
|
it('should return viewPort', function () {
|
||||||
var viewPort = new ViewPort(null, null, null, null);
|
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);
|
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", () => {
|
describe("light DOM", () => {
|
||||||
var lightDom, parentPreBuiltObjects;
|
var lightDom, parentPreBuiltObjects;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
lightDom = new DummyLightDom();
|
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 () {
|
it("should return destination light DOM from the parent's injector", function () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user