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