feat(elementBinder): introduce element binder.
It is a plain-old-data class to seperate the protoInjector from the textNodes and elementBinding data.
This commit is contained in:
parent
ec7e8534c2
commit
8c566dcfb5
modules
benchmarks/src/element_injector
core
src/compiler
test/compiler
@ -8,7 +8,7 @@ export function run () {
|
|||||||
var appInjector = new Injector([]);
|
var appInjector = new Injector([]);
|
||||||
|
|
||||||
var bindings = [A, B, C];
|
var bindings = [A, B, C];
|
||||||
var proto = new ProtoElementInjector(null, bindings, [], false);
|
var proto = new ProtoElementInjector(null, bindings);
|
||||||
for (var i = 0; i < ITERATIONS; ++i) {
|
for (var i = 0; i < ITERATIONS; ++i) {
|
||||||
var ei = proto.instantiate({view:null});
|
var ei = proto.instantiate({view:null});
|
||||||
ei.instantiateDirectives(appInjector);
|
ei.instantiateDirectives(appInjector);
|
||||||
|
@ -16,7 +16,7 @@ export function run () {
|
|||||||
], false)];
|
], false)];
|
||||||
|
|
||||||
|
|
||||||
var proto = new ProtoElementInjector(null, bindings, [], false);
|
var proto = new ProtoElementInjector(null, bindings);
|
||||||
for (var i = 0; i < ITERATIONS; ++i) {
|
for (var i = 0; i < ITERATIONS; ++i) {
|
||||||
var ei = proto.instantiate({view:null});
|
var ei = proto.instantiate({view:null});
|
||||||
ei.instantiateDirectives(appInjector);
|
ei.instantiateDirectives(appInjector);
|
||||||
@ -39,4 +39,4 @@ class C {
|
|||||||
constructor(a:A, b:B) {
|
constructor(a:A, b:B) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ export function run () {
|
|||||||
var appInjector = new Injector([]);
|
var appInjector = new Injector([]);
|
||||||
|
|
||||||
var bindings = [A, B, C];
|
var bindings = [A, B, C];
|
||||||
var proto = new ProtoElementInjector(null, bindings, [], false);
|
var proto = new ProtoElementInjector(null, bindings);
|
||||||
var ei = proto.instantiate({view:null});
|
var ei = proto.instantiate({view:null});
|
||||||
|
|
||||||
for (var i = 0; i < ITERATIONS; ++i) {
|
for (var i = 0; i < ITERATIONS; ++i) {
|
||||||
@ -33,4 +33,4 @@ class C {
|
|||||||
constructor(a:A, b:B) {
|
constructor(a:A, b:B) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
modules/core/src/compiler/element_binder.js
Normal file
15
modules/core/src/compiler/element_binder.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import {ProtoElementInjector} from './element_injector';
|
||||||
|
import {FIELD} from 'facade/lang';
|
||||||
|
import {List} from 'facade/collection';
|
||||||
|
|
||||||
|
export class ElementBinder {
|
||||||
|
@FIELD('final protoElementInjector:ProtoElementInjector')
|
||||||
|
@FIELD('final textNodeIndices:List<int>')
|
||||||
|
@FIELD('final hasElementPropertyBindings:bool')
|
||||||
|
constructor(protoElementInjector: ProtoElementInjector,
|
||||||
|
textNodeIndices:List, hasElementPropertyBindings:boolean) {
|
||||||
|
this.protoElementInjector = protoElementInjector;
|
||||||
|
this.textNodeIndices = textNodeIndices;
|
||||||
|
this.hasElementPropertyBindings = hasElementPropertyBindings;
|
||||||
|
}
|
||||||
|
}
|
@ -146,10 +146,7 @@ export class ProtoElementInjector extends TreeNode {
|
|||||||
@FIELD('_key7:int')
|
@FIELD('_key7:int')
|
||||||
@FIELD('_key8:int')
|
@FIELD('_key8:int')
|
||||||
@FIELD('_key9:int')
|
@FIELD('_key9:int')
|
||||||
@FIELD('textNodeIndices:List<int>')
|
constructor(parent:ProtoElementInjector, bindings:List) {
|
||||||
@FIELD('hasElementPropertyBindings:bool')
|
|
||||||
constructor(parent:ProtoElementInjector, bindings:List, textNodeIndices:List,
|
|
||||||
hasElementPropertyBindings:boolean) {
|
|
||||||
super(parent);
|
super(parent);
|
||||||
|
|
||||||
this._elementInjector = null;
|
this._elementInjector = null;
|
||||||
@ -180,9 +177,6 @@ export class ProtoElementInjector extends TreeNode {
|
|||||||
if (length > 10) {
|
if (length > 10) {
|
||||||
throw 'Maximum number of directives per element has been reached.';
|
throw 'Maximum number of directives per element has been reached.';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.textNodeIndices = textNodeIndices;
|
|
||||||
this.hasElementPropertyBindings = hasElementPropertyBindings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
instantiate({view}):ElementInjector {
|
instantiate({view}):ElementInjector {
|
||||||
|
@ -3,6 +3,7 @@ import {ListWrapper} from 'facade/collection';
|
|||||||
import {ProtoWatchGroup, WatchGroup, WatchGroupDispatcher} from 'change_detection/watch_group';
|
import {ProtoWatchGroup, WatchGroup, WatchGroupDispatcher} from 'change_detection/watch_group';
|
||||||
import {Record} from 'change_detection/record';
|
import {Record} from 'change_detection/record';
|
||||||
import {ProtoElementInjector, ElementInjector} from './element_injector';
|
import {ProtoElementInjector, ElementInjector} from './element_injector';
|
||||||
|
import {ElementBinder} from './element_binder';
|
||||||
import {SetterFn} from 'change_detection/facade';
|
import {SetterFn} from 'change_detection/facade';
|
||||||
import {FIELD, IMPLEMENTS, int, isPresent, isBlank} from 'facade/lang';
|
import {FIELD, IMPLEMENTS, int, isPresent, isBlank} from 'facade/lang';
|
||||||
import {List} from 'facade/collection';
|
import {List} from 'facade/collection';
|
||||||
@ -57,19 +58,16 @@ export class View {
|
|||||||
|
|
||||||
export class ProtoView {
|
export class ProtoView {
|
||||||
@FIELD('final _template:TemplateElement')
|
@FIELD('final _template:TemplateElement')
|
||||||
@FIELD('final _bindings:List')
|
@FIELD('final _elementBinders:List<ElementBinder>')
|
||||||
@FIELD('final _protoElementInjectors:List<ProtoElementInjector>')
|
|
||||||
@FIELD('final _protoWatchGroup:ProtoWatchGroup')
|
@FIELD('final _protoWatchGroup:ProtoWatchGroup')
|
||||||
@FIELD('final _useRootElement:bool')
|
@FIELD('final _useRootElement:bool')
|
||||||
constructor(
|
constructor(
|
||||||
template:TemplateElement,
|
template:TemplateElement,
|
||||||
bindings:List,
|
elementBinders:List,
|
||||||
protoElementInjectors:List,
|
|
||||||
protoWatchGroup:ProtoWatchGroup,
|
protoWatchGroup:ProtoWatchGroup,
|
||||||
useRootElement:boolean) {
|
useRootElement:boolean) {
|
||||||
this._template = template;
|
this._template = template;
|
||||||
this._bindings = bindings;
|
this._elementBinders = elementBinders;
|
||||||
this._protoElementInjectors = protoElementInjectors;
|
|
||||||
this._protoWatchGroup = protoWatchGroup;
|
this._protoWatchGroup = protoWatchGroup;
|
||||||
|
|
||||||
// not implemented
|
// not implemented
|
||||||
@ -79,31 +77,32 @@ export class ProtoView {
|
|||||||
instantiate(context, appInjector:Injector):View {
|
instantiate(context, appInjector:Injector):View {
|
||||||
var fragment = DOM.clone(this._template.content);
|
var fragment = DOM.clone(this._template.content);
|
||||||
var elements = DOM.querySelectorAll(fragment, ".ng-binding");
|
var elements = DOM.querySelectorAll(fragment, ".ng-binding");
|
||||||
var protos = this._protoElementInjectors;
|
var binders = this._elementBinders;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: vsavkin: benchmark
|
* TODO: vsavkin: benchmark
|
||||||
* If this performs poorly, the five loops can be collapsed into one.
|
* If this performs poorly, the five loops can be collapsed into one.
|
||||||
*/
|
*/
|
||||||
var elementInjectors = ProtoView._createElementInjectors(elements, protos);
|
var elementInjectors = ProtoView._createElementInjectors(elements, binders);
|
||||||
var rootElementInjectors = ProtoView._rootElementInjectors(elementInjectors);
|
var rootElementInjectors = ProtoView._rootElementInjectors(elementInjectors);
|
||||||
var textNodes = ProtoView._textNodes(elements, protos);
|
var textNodes = ProtoView._textNodes(elements, binders);
|
||||||
var bindElements = ProtoView._bindElements(elements, protos);
|
var bindElements = ProtoView._bindElements(elements, binders);
|
||||||
ProtoView._instantiateDirectives(elementInjectors, appInjector);
|
ProtoView._instantiateDirectives(elementInjectors, appInjector);
|
||||||
|
|
||||||
return new View(fragment, elementInjectors, rootElementInjectors, textNodes,
|
return new View(fragment, elementInjectors, rootElementInjectors, textNodes,
|
||||||
bindElements, this._protoWatchGroup, context);
|
bindElements, this._protoWatchGroup, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _createElementInjectors(elements, protos) {
|
static _createElementInjectors(elements, binders) {
|
||||||
var injectors = ListWrapper.createFixedSize(protos.length);
|
var injectors = ListWrapper.createFixedSize(binders.length);
|
||||||
for (var i = 0; i < protos.length; ++i) {
|
for (var i = 0; i < binders.length; ++i) {
|
||||||
injectors[i] = ProtoView._createElementInjector(elements[i], protos[i]);
|
injectors[i] = ProtoView._createElementInjector(
|
||||||
|
elements[i], binders[i].protoElementInjector);
|
||||||
}
|
}
|
||||||
// Cannot be rolled into loop above, because parentInjector pointers need
|
// Cannot be rolled into loop above, because parentInjector pointers need
|
||||||
// to be set on the children.
|
// to be set on the children.
|
||||||
for (var i = 0; i < protos.length; ++i) {
|
for (var i = 0; i < binders.length; ++i) {
|
||||||
protos[i].clearElementInjector();
|
binders[i].protoElementInjector.clearElementInjector();
|
||||||
}
|
}
|
||||||
return injectors;
|
return injectors;
|
||||||
}
|
}
|
||||||
@ -124,19 +123,19 @@ export class ProtoView {
|
|||||||
return ListWrapper.filter(injectors, inj => isPresent(inj) && isBlank(inj.parent));
|
return ListWrapper.filter(injectors, inj => isPresent(inj) && isBlank(inj.parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
static _textNodes(elements, protos) {
|
static _textNodes(elements, binders) {
|
||||||
var textNodes = [];
|
var textNodes = [];
|
||||||
for (var i = 0; i < protos.length; ++i) {
|
for (var i = 0; i < binders.length; ++i) {
|
||||||
ProtoView._collectTextNodes(textNodes, elements[i],
|
ProtoView._collectTextNodes(textNodes, elements[i],
|
||||||
protos[i].textNodeIndices);
|
binders[i].textNodeIndices);
|
||||||
}
|
}
|
||||||
return textNodes;
|
return textNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static _bindElements(elements, protos):List<Element> {
|
static _bindElements(elements, binders):List<Element> {
|
||||||
var bindElements = [];
|
var bindElements = [];
|
||||||
for (var i = 0; i < protos.length; ++i) {
|
for (var i = 0; i < binders.length; ++i) {
|
||||||
if (protos[i].hasElementPropertyBindings) ListWrapper.push(
|
if (binders[i].hasElementPropertyBindings) ListWrapper.push(
|
||||||
bindElements, elements[i]);
|
bindElements, elements[i]);
|
||||||
}
|
}
|
||||||
return bindElements;
|
return bindElements;
|
||||||
|
@ -70,7 +70,7 @@ export function main() {
|
|||||||
if (isBlank(appInjector)) appInjector = new Injector([]);
|
if (isBlank(appInjector)) appInjector = new Injector([]);
|
||||||
if (isBlank(props)) props = {};
|
if (isBlank(props)) props = {};
|
||||||
|
|
||||||
var proto = new ProtoElementInjector(null, bindings, [], false);
|
var proto = new ProtoElementInjector(null, bindings);
|
||||||
var inj = proto.instantiate({view: props["view"]});
|
var inj = proto.instantiate({view: props["view"]});
|
||||||
inj.instantiateDirectives(appInjector);
|
inj.instantiateDirectives(appInjector);
|
||||||
return inj;
|
return inj;
|
||||||
@ -79,12 +79,11 @@ export function main() {
|
|||||||
function parentChildInjectors(parentBindings, childBindings) {
|
function parentChildInjectors(parentBindings, childBindings) {
|
||||||
var inj = new Injector([]);
|
var inj = new Injector([]);
|
||||||
|
|
||||||
var protoParent = new ProtoElementInjector(null, parentBindings, [], false);
|
var protoParent = new ProtoElementInjector(null, parentBindings);
|
||||||
var parent = protoParent.instantiate({view: null});
|
var parent = protoParent.instantiate({view: null});
|
||||||
parent.instantiateDirectives(inj);
|
parent.instantiateDirectives(inj);
|
||||||
|
|
||||||
var protoChild = new ProtoElementInjector(protoParent, childBindings, [],
|
var protoChild = new ProtoElementInjector(protoParent, childBindings);
|
||||||
false);
|
|
||||||
var child = protoChild.instantiate({view: null});
|
var child = protoChild.instantiate({view: null});
|
||||||
child.instantiateDirectives(inj);
|
child.instantiateDirectives(inj);
|
||||||
|
|
||||||
@ -94,9 +93,9 @@ export function main() {
|
|||||||
describe("ElementInjector", function () {
|
describe("ElementInjector", function () {
|
||||||
describe("proto injectors", function () {
|
describe("proto injectors", function () {
|
||||||
it("should construct a proto tree", function () {
|
it("should construct a proto tree", function () {
|
||||||
var p = new ProtoElementInjector(null, [], [], false);
|
var p = new ProtoElementInjector(null, []);
|
||||||
var c1 = new ProtoElementInjector(p, [], [], false);
|
var c1 = new ProtoElementInjector(p, []);
|
||||||
var c2 = new ProtoElementInjector(p, [], [], false);
|
var c2 = new ProtoElementInjector(p, []);
|
||||||
|
|
||||||
expect(humanize(p, [
|
expect(humanize(p, [
|
||||||
[p, 'parent'],
|
[p, 'parent'],
|
||||||
@ -108,9 +107,9 @@ export function main() {
|
|||||||
|
|
||||||
describe("instantiate", function () {
|
describe("instantiate", function () {
|
||||||
it("should create an element injector", function () {
|
it("should create an element injector", function () {
|
||||||
var protoParent = new ProtoElementInjector(null, [], [], false);
|
var protoParent = new ProtoElementInjector(null, []);
|
||||||
var protoChild1 = new ProtoElementInjector(protoParent, [], [], false);
|
var protoChild1 = new ProtoElementInjector(protoParent, []);
|
||||||
var protoChild2 = new ProtoElementInjector(protoParent, [], [], false);
|
var protoChild2 = new ProtoElementInjector(protoParent, []);
|
||||||
|
|
||||||
var p = protoParent.instantiate({view: null});
|
var p = protoParent.instantiate({view: null});
|
||||||
var c1 = protoChild1.instantiate({view: null});
|
var c1 = protoChild1.instantiate({view: null});
|
||||||
@ -126,12 +125,12 @@ export function main() {
|
|||||||
|
|
||||||
describe("hasBindings", function () {
|
describe("hasBindings", function () {
|
||||||
it("should be true when there are bindings", function () {
|
it("should be true when there are bindings", function () {
|
||||||
var p = new ProtoElementInjector(null, [Directive], [], false);
|
var p = new ProtoElementInjector(null, [Directive]);
|
||||||
expect(p.hasBindings).toBeTruthy();
|
expect(p.hasBindings).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be false otherwise", function () {
|
it("should be false otherwise", function () {
|
||||||
var p = new ProtoElementInjector(null, [], [], false);
|
var p = new ProtoElementInjector(null, []);
|
||||||
expect(p.hasBindings).toBeFalsy();
|
expect(p.hasBindings).toBeFalsy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -8,6 +8,7 @@ import {DOM, Element} from 'facade/dom';
|
|||||||
import {FIELD} from 'facade/lang';
|
import {FIELD} from 'facade/lang';
|
||||||
import {ImplicitReceiver, FieldRead} from 'change_detection/parser/ast';
|
import {ImplicitReceiver, FieldRead} from 'change_detection/parser/ast';
|
||||||
import {ClosureMap} from 'change_detection/parser/closure_map';
|
import {ClosureMap} from 'change_detection/parser/closure_map';
|
||||||
|
import {ElementBinder} from 'core/compiler/element_binder';
|
||||||
|
|
||||||
class Directive {
|
class Directive {
|
||||||
@FIELD('prop')
|
@FIELD('prop')
|
||||||
@ -30,10 +31,15 @@ export function main() {
|
|||||||
'</div>' +
|
'</div>' +
|
||||||
'</section>';
|
'</section>';
|
||||||
|
|
||||||
function templateElInj() {
|
function templateElementBinders() {
|
||||||
var sectionPI = new ProtoElementInjector(null, [], [0], false);
|
var sectionPI = new ElementBinder(new ProtoElementInjector(null, []),
|
||||||
var divPI = new ProtoElementInjector(sectionPI, [Directive], [], false);
|
[0], false);
|
||||||
var spanPI = new ProtoElementInjector(divPI, [], [], true);
|
|
||||||
|
var divPI = new ElementBinder(new ProtoElementInjector(
|
||||||
|
sectionPI.protoElementInjector, [Directive]), [], false);
|
||||||
|
|
||||||
|
var spanPI = new ElementBinder(new ProtoElementInjector(
|
||||||
|
divPI.protoElementInjector, []), [], true);
|
||||||
return [sectionPI, divPI, spanPI];
|
return [sectionPI, divPI, spanPI];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,9 +47,8 @@ export function main() {
|
|||||||
it('should create view instance and locate basic parts', function() {
|
it('should create view instance and locate basic parts', function() {
|
||||||
var template = DOM.createTemplate(tempalteWithThreeTypesOfBindings);
|
var template = DOM.createTemplate(tempalteWithThreeTypesOfBindings);
|
||||||
|
|
||||||
var diBindings = [];
|
|
||||||
var hasSingleRoot = false;
|
var hasSingleRoot = false;
|
||||||
var pv = new ProtoView(template, diBindings, templateElInj(),
|
var pv = new ProtoView(template, templateElementBinders(),
|
||||||
new ProtoWatchGroup(), hasSingleRoot);
|
new ProtoWatchGroup(), hasSingleRoot);
|
||||||
|
|
||||||
var view = pv.instantiate(null, null);
|
var view = pv.instantiate(null, null);
|
||||||
@ -68,10 +73,12 @@ export function main() {
|
|||||||
'<div directive class="ng-binding"></div>' +
|
'<div directive class="ng-binding"></div>' +
|
||||||
'</section>');
|
'</section>');
|
||||||
|
|
||||||
var sectionPI = new ProtoElementInjector(null, [Directive], [], false);
|
var sectionPI = new ElementBinder(new ProtoElementInjector(
|
||||||
var divPI = new ProtoElementInjector(sectionPI, [Directive], [], false);
|
null, [Directive]), [], false);
|
||||||
|
var divPI = new ElementBinder(new ProtoElementInjector(
|
||||||
|
sectionPI.protoElementInjector, [Directive]), [], false);
|
||||||
|
|
||||||
var pv = new ProtoView(template, [], [sectionPI, divPI],
|
var pv = new ProtoView(template, [sectionPI, divPI],
|
||||||
new ProtoWatchGroup(), false);
|
new ProtoWatchGroup(), false);
|
||||||
var view = pv.instantiate(null, null);
|
var view = pv.instantiate(null, null);
|
||||||
|
|
||||||
@ -82,7 +89,7 @@ export function main() {
|
|||||||
var view;
|
var view;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
var template = DOM.createTemplate(tempalteWithThreeTypesOfBindings);
|
var template = DOM.createTemplate(tempalteWithThreeTypesOfBindings);
|
||||||
var pv = new ProtoView(template, [], templateElInj(),
|
var pv = new ProtoView(template, templateElementBinders(),
|
||||||
new ProtoWatchGroup(), false);
|
new ProtoWatchGroup(), false);
|
||||||
view = pv.instantiate(null, null);
|
view = pv.instantiate(null, null);
|
||||||
});
|
});
|
||||||
@ -125,7 +132,7 @@ export function main() {
|
|||||||
var protoWatchGroup = new ProtoWatchGroup();
|
var protoWatchGroup = new ProtoWatchGroup();
|
||||||
protoWatchGroup.watch(oneFieldAst('foo'), memento);
|
protoWatchGroup.watch(oneFieldAst('foo'), memento);
|
||||||
|
|
||||||
var pv = new ProtoView(template, [], templateElInj(),
|
var pv = new ProtoView(template, templateElementBinders(),
|
||||||
protoWatchGroup, false);
|
protoWatchGroup, false);
|
||||||
|
|
||||||
ctx = new MyEvaluationContext();
|
ctx = new MyEvaluationContext();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user