From 5e0ff2cbb7ac70289290ac9fe71696cb00176261 Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Thu, 13 Nov 2014 15:15:55 -0800 Subject: [PATCH] refactor(ElementBinder): Store componentDirective and templateDirective as well. --- modules/core/src/annotations/component.js | 2 +- modules/core/src/compiler/element_binder.js | 8 ++- .../pipeline/element_binder_builder.js | 3 +- modules/core/src/compiler/view.js | 7 ++- .../pipeline/element_binder_builder_spec.js | 52 ++++++++++++++----- .../pipeline/proto_view_builder_spec.js | 2 +- 6 files changed, 54 insertions(+), 20 deletions(-) diff --git a/modules/core/src/annotations/component.js b/modules/core/src/annotations/component.js index 91a67a2344..e5f2e8ca3e 100644 --- a/modules/core/src/annotations/component.js +++ b/modules/core/src/annotations/component.js @@ -17,7 +17,7 @@ export class Component extends Directive { template:TemplateConfig, lightDomServices:DomServicesFunction, shadowDomServices:DomServicesFunction, - componentServices:ComponentServicesFunction, + componentServices:Array, implementsTypes:Array }={}) { diff --git a/modules/core/src/compiler/element_binder.js b/modules/core/src/compiler/element_binder.js index c7fa6df45a..b97ccb732b 100644 --- a/modules/core/src/compiler/element_binder.js +++ b/modules/core/src/compiler/element_binder.js @@ -1,16 +1,20 @@ import {ProtoElementInjector} from './element_injector'; import {FIELD} from 'facade/lang'; +import {AnnotatedType} from './annotated_type'; // Comment out as dartanalyzer does not look into @FIELD // import {List} from 'facade/collection'; // import {ProtoView} from './view'; export class ElementBinder { @FIELD('final protoElementInjector:ProtoElementInjector') + @FIELD('final componentDirective:AnnotatedType') + @FIELD('final templateDirective:AnnotatedType') @FIELD('final textNodeIndices:List') @FIELD('hasElementPropertyBindings:bool') - @FIELD('nestedProtoView:ProtoView') - constructor(protoElementInjector: ProtoElementInjector) { + constructor(protoElementInjector: ProtoElementInjector, componentDirective:AnnotatedType, templateDirective:AnnotatedType) { this.protoElementInjector = protoElementInjector; + this.componentDirective = componentDirective; + this.templateDirective = templateDirective; // updated later when text nodes are bound this.textNodeIndices = []; // updated later when element properties are bound diff --git a/modules/core/src/compiler/pipeline/element_binder_builder.js b/modules/core/src/compiler/pipeline/element_binder_builder.js index 2165d0a3d0..3d1d4f391a 100644 --- a/modules/core/src/compiler/pipeline/element_binder_builder.js +++ b/modules/core/src/compiler/pipeline/element_binder_builder.js @@ -52,7 +52,8 @@ export class ElementBinderBuilder extends CompileStep { var elementBinder; if (current.hasBindings) { var protoView = current.inheritedProtoView; - elementBinder = protoView.bindElement(current.inheritedProtoElementInjector); + elementBinder = protoView.bindElement(current.inheritedProtoElementInjector, + current.componentDirective, current.templateDirective); if (isPresent(current.textNodeBindings)) { this._bindTextNodes(protoView, current.textNodeBindings); diff --git a/modules/core/src/compiler/view.js b/modules/core/src/compiler/view.js index ef5e71c60f..0b8ff26138 100644 --- a/modules/core/src/compiler/view.js +++ b/modules/core/src/compiler/view.js @@ -3,8 +3,10 @@ import {ListWrapper} from 'facade/collection'; import {ProtoWatchGroup, WatchGroup, WatchGroupDispatcher} from 'change_detection/watch_group'; import {Record} from 'change_detection/record'; import {AST} from 'change_detection/parser/ast'; + import {ProtoElementInjector, ElementInjector} from './element_injector'; import {ElementBinder} from './element_binder'; +import {AnnotatedType} from './annotated_type'; import {SetterFn} from 'change_detection/parser/closure_map'; import {FIELD, IMPLEMENTS, int, isPresent, isBlank} from 'facade/lang'; import {List} from 'facade/collection'; @@ -99,8 +101,9 @@ export class ProtoView { bindElements, this.protoWatchGroup, context); } - bindElement(protoElementInjector:ProtoElementInjector):ElementBinder { - var elBinder = new ElementBinder(protoElementInjector); + bindElement(protoElementInjector:ProtoElementInjector, + componentDirective:AnnotatedType = null, templateDirective:AnnotatedType = null):ElementBinder { + var elBinder = new ElementBinder(protoElementInjector, componentDirective, templateDirective); ListWrapper.push(this.elementBinders, elBinder); return elBinder; } diff --git a/modules/core/test/compiler/pipeline/element_binder_builder_spec.js b/modules/core/test/compiler/pipeline/element_binder_builder_spec.js index b393987497..e8de27d5db 100644 --- a/modules/core/test/compiler/pipeline/element_binder_builder_spec.js +++ b/modules/core/test/compiler/pipeline/element_binder_builder_spec.js @@ -100,7 +100,7 @@ export function main() { }); it('should store the current protoElementInjector', () => { - var directives = [SomeSimpleDirective]; + var directives = [SomeDecoratorDirective]; var protoElementInjector = new ProtoElementInjector(null, 0, directives); var pipeline = createPipeline({protoElementInjector: protoElementInjector, directives: directives}); @@ -110,6 +110,24 @@ export function main() { expect(pv.elementBinders[0].protoElementInjector).toBe(protoElementInjector); }); + it('should store the component directive', () => { + var directives = [SomeComponentDirective]; + var pipeline = createPipeline({protoElementInjector: null, directives: directives}); + var results = pipeline.process(createElement('
')); + var pv = results[0].inheritedProtoView; + + expect(pv.elementBinders[0].componentDirective.type).toBe(SomeComponentDirective); + }); + + it('should store the template directive', () => { + var directives = [SomeTemplateDirective]; + var pipeline = createPipeline({protoElementInjector: null, directives: directives}); + var results = pipeline.process(createElement('
')); + var pv = results[0].inheritedProtoView; + + expect(pv.elementBinders[0].templateDirective.type).toBe(SomeTemplateDirective); + }); + it('should bind text nodes', () => { var textNodeBindings = MapWrapper.create(); MapWrapper.set(textNodeBindings, 0, 'prop1'); @@ -155,7 +173,7 @@ export function main() { 'boundprop2': 'prop2', 'boundprop3': 'prop3' }); - var directives = [SomeDecoratorDirective, SomeTemplateDirective, SomeComponentDirective]; + var directives = [SomeDecoratorDirectiveWithBinding, SomeTemplateDirectiveWithBinding, SomeComponentDirectiveWithBinding]; var protoElementInjector = new ProtoElementInjector(null, 0, directives); var pipeline = createPipeline({ propertyBindings: propertyBindings, @@ -171,16 +189,16 @@ export function main() { evalContext.prop3 = 'c'; changeDetector.detectChanges(); - expect(view.elementInjectors[0].get(SomeDecoratorDirective).decorProp).toBe('a'); - expect(view.elementInjectors[0].get(SomeTemplateDirective).templProp).toBe('b'); - expect(view.elementInjectors[0].get(SomeComponentDirective).compProp).toBe('c'); + expect(view.elementInjectors[0].get(SomeDecoratorDirectiveWithBinding).decorProp).toBe('a'); + expect(view.elementInjectors[0].get(SomeTemplateDirectiveWithBinding).templProp).toBe('b'); + expect(view.elementInjectors[0].get(SomeComponentDirectiveWithBinding).compProp).toBe('c'); }); it('should bind directive properties for sibling elements', () => { var propertyBindings = MapWrapper.createFromStringMap({ 'boundprop1': 'prop1' }); - var directives = [SomeDecoratorDirective]; + var directives = [SomeDecoratorDirectiveWithBinding]; var protoElementInjector = new ProtoElementInjector(null, 0, directives); var pipeline = createPipeline({ propertyBindings: propertyBindings, @@ -196,16 +214,16 @@ export function main() { evalContext.prop1 = 'a'; changeDetector.detectChanges(); - expect(view.elementInjectors[1].get(SomeDecoratorDirective).decorProp).toBe('a'); + expect(view.elementInjectors[1].get(SomeDecoratorDirectiveWithBinding).decorProp).toBe('a'); }); describe('errors', () => { it('should throw if there is no element property bindings for a directive property binding', () => { - var pipeline = createPipeline({propertyBindings: MapWrapper.create(), directives: [SomeDecoratorDirective]}); + var pipeline = createPipeline({propertyBindings: MapWrapper.create(), directives: [SomeDecoratorDirectiveWithBinding]}); expect( () => { pipeline.process(createElement('
')); - }).toThrowError('No element binding found for property boundprop1 which is required by directive SomeDecoratorDirective'); + }).toThrowError('No element binding found for property boundprop1 which is required by directive SomeDecoratorDirectiveWithBinding'); }); }); @@ -215,31 +233,39 @@ export function main() { } @Decorator() -class SomeSimpleDirective { +class SomeDecoratorDirective { } @Decorator({ bind: {'boundprop1': 'decorProp'} }) -class SomeDecoratorDirective { +class SomeDecoratorDirectiveWithBinding { constructor() { this.decorProp = null; } } +@Template() +class SomeTemplateDirective { +} + @Template({ bind: {'boundprop2': 'templProp'} }) -class SomeTemplateDirective { +class SomeTemplateDirectiveWithBinding { constructor() { this.templProp = null; } } +@Component() +class SomeComponentDirective { +} + @Component({ bind: {'boundprop3': 'compProp'} }) -class SomeComponentDirective { +class SomeComponentDirectiveWithBinding { constructor() { this.compProp = null; } diff --git a/modules/core/test/compiler/pipeline/proto_view_builder_spec.js b/modules/core/test/compiler/pipeline/proto_view_builder_spec.js index c7576feb06..aef96ff3ac 100644 --- a/modules/core/test/compiler/pipeline/proto_view_builder_spec.js +++ b/modules/core/test/compiler/pipeline/proto_view_builder_spec.js @@ -15,7 +15,7 @@ export function main() { if (isPresent(current.element.getAttribute('viewroot'))) { current.isViewRoot = true; } - current.inheritedElementBinder = new ElementBinder(null); + current.inheritedElementBinder = new ElementBinder(null, null, null); }), new ProtoViewBuilder()]); }