diff --git a/modules/benchmarks/src/element_injector/instantiate_benchmark.js b/modules/benchmarks/src/element_injector/instantiate_benchmark.js index 0aba57230d..ac8edae8ab 100644 --- a/modules/benchmarks/src/element_injector/instantiate_benchmark.js +++ b/modules/benchmarks/src/element_injector/instantiate_benchmark.js @@ -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); diff --git a/modules/benchmarks/src/element_injector/instantiate_benchmark_codegen.js b/modules/benchmarks/src/element_injector/instantiate_benchmark_codegen.js index e810769fb6..1d326707e8 100644 --- a/modules/benchmarks/src/element_injector/instantiate_benchmark_codegen.js +++ b/modules/benchmarks/src/element_injector/instantiate_benchmark_codegen.js @@ -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++; } -} \ No newline at end of file +} diff --git a/modules/benchmarks/src/element_injector/instantiate_directive_benchmark.js b/modules/benchmarks/src/element_injector/instantiate_directive_benchmark.js index 7cca359d45..7e2eff9c49 100644 --- a/modules/benchmarks/src/element_injector/instantiate_directive_benchmark.js +++ b/modules/benchmarks/src/element_injector/instantiate_directive_benchmark.js @@ -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++; } -} \ No newline at end of file +} diff --git a/modules/core/src/compiler/element_binder.js b/modules/core/src/compiler/element_binder.js new file mode 100644 index 0000000000..2c9815a3c2 --- /dev/null +++ b/modules/core/src/compiler/element_binder.js @@ -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') + @FIELD('final hasElementPropertyBindings:bool') + constructor(protoElementInjector: ProtoElementInjector, + textNodeIndices:List, hasElementPropertyBindings:boolean) { + this.protoElementInjector = protoElementInjector; + this.textNodeIndices = textNodeIndices; + this.hasElementPropertyBindings = hasElementPropertyBindings; + } +} diff --git a/modules/core/src/compiler/element_injector.js b/modules/core/src/compiler/element_injector.js index 1fd809b54b..b41516aaaa 100644 --- a/modules/core/src/compiler/element_injector.js +++ b/modules/core/src/compiler/element_injector.js @@ -146,10 +146,7 @@ export class ProtoElementInjector extends TreeNode { @FIELD('_key7:int') @FIELD('_key8:int') @FIELD('_key9:int') - @FIELD('textNodeIndices:List') - @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 { diff --git a/modules/core/src/compiler/view.js b/modules/core/src/compiler/view.js index 9ff34a8cae..4db5327e63 100644 --- a/modules/core/src/compiler/view.js +++ b/modules/core/src/compiler/view.js @@ -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') + @FIELD('final _elementBinders:List') @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 { + static _bindElements(elements, binders):List { 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; diff --git a/modules/core/test/compiler/element_injector_spec.js b/modules/core/test/compiler/element_injector_spec.js index 7681d67542..99685a03ac 100644 --- a/modules/core/test/compiler/element_injector_spec.js +++ b/modules/core/test/compiler/element_injector_spec.js @@ -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(); }); }); diff --git a/modules/core/test/compiler/view_spec.js b/modules/core/test/compiler/view_spec.js index d9b79f9d65..75dadfece9 100644 --- a/modules/core/test/compiler/view_spec.js +++ b/modules/core/test/compiler/view_spec.js @@ -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() { '' + ''; - 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() { '
' + ''); - 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();