feat(Compiler): Multiple template per component

fixes #596

- TemplateConfig becomes Template
- introduce a TemplateResolver to pick the cmp template,
- @Component and @Template are disociated
This commit is contained in:
Victor Berchet 2015-02-12 14:44:59 +01:00
parent 52b062621d
commit e6c8bde808
35 changed files with 953 additions and 724 deletions

View File

@ -1,7 +1,7 @@
export * from './src/core/annotations/annotations'; export * from './src/core/annotations/annotations';
export * from './src/core/annotations/visibility'; export * from './src/core/annotations/visibility';
export * from './src/core/compiler/interfaces'; export * from './src/core/compiler/interfaces';
export * from './src/core/annotations/template_config'; export * from './src/core/annotations/template';
export * from './src/core/application'; export * from './src/core/application';
export * from './src/core/compiler/compiler'; export * from './src/core/compiler/compiler';

View File

@ -1,6 +1,5 @@
import {ABSTRACT, CONST, normalizeBlank, isPresent} from 'angular2/src/facade/lang'; import {ABSTRACT, CONST, normalizeBlank, isPresent} from 'angular2/src/facade/lang';
import {ListWrapper, List} from 'angular2/src/facade/collection'; import {ListWrapper, List} from 'angular2/src/facade/collection';
import {TemplateConfig} from './template_config';
@ABSTRACT() @ABSTRACT()
export class Directive { export class Directive {
@ -38,7 +37,6 @@ export class Directive {
export class Component extends Directive { export class Component extends Directive {
//TODO: vsavkin: uncomment it once the issue with defining fields in a sublass works //TODO: vsavkin: uncomment it once the issue with defining fields in a sublass works
template:any; //TemplateConfig;
lightDomServices:any; //List; lightDomServices:any; //List;
shadowDomServices:any; //List; shadowDomServices:any; //List;
componentServices:any; //List; componentServices:any; //List;
@ -48,7 +46,6 @@ export class Component extends Directive {
constructor({ constructor({
selector, selector,
bind, bind,
template,
lightDomServices, lightDomServices,
shadowDomServices, shadowDomServices,
componentServices, componentServices,
@ -57,7 +54,6 @@ export class Component extends Directive {
}:{ }:{
selector:String, selector:String,
bind:Object, bind:Object,
template:TemplateConfig,
lightDomServices:List, lightDomServices:List,
shadowDomServices:List, shadowDomServices:List,
componentServices:List, componentServices:List,
@ -73,7 +69,6 @@ export class Component extends Directive {
lifecycle: lifecycle lifecycle: lifecycle
}); });
this.template = template;
this.lightDomServices = lightDomServices; this.lightDomServices = lightDomServices;
this.shadowDomServices = shadowDomServices; this.shadowDomServices = shadowDomServices;
this.componentServices = componentServices; this.componentServices = componentServices;

View File

@ -1,25 +1,31 @@
import {ABSTRACT, CONST, Type} from 'angular2/src/facade/lang'; import {ABSTRACT, CONST, Type} from 'angular2/src/facade/lang';
import {List} from 'angular2/src/facade/collection'; import {List} from 'angular2/src/facade/collection';
export class TemplateConfig { export class Template {
url:any; //string; url:any; //string;
inline:any; //string; inline:any; //string;
directives:any; //List<Type>; directives:any; //List<Type>;
formatters:any; //List<Type>; formatters:any; //List<Type>;
source:any;//List<TemplateConfig>; source:any;//List<Template>;
locale:any; //string
device:any; //string
@CONST() @CONST()
constructor({ constructor({
url, url,
inline, inline,
directives, directives,
formatters, formatters,
source source,
locale,
device
}: { }: {
url: string, url: string,
inline: string, inline: string,
directives: List<Type>, directives: List<Type>,
formatters: List<Type>, formatters: List<Type>,
source: List<TemplateConfig> source: List<Template>,
locale: string,
device: string
}) })
{ {
this.url = url; this.url = url;
@ -27,5 +33,7 @@ export class TemplateConfig {
this.directives = directives; this.directives = directives;
this.formatters = formatters; this.formatters = formatters;
this.source = source; this.source = source;
this.locale = locale;
this.device = device;
} }
} }

View File

@ -6,6 +6,7 @@ import {ProtoView} from './compiler/view';
import {Reflector, reflector} from 'angular2/src/reflection/reflection'; import {Reflector, reflector} from 'angular2/src/reflection/reflection';
import {Parser, Lexer, ChangeDetection, dynamicChangeDetection, jitChangeDetection} from 'angular2/change_detection'; import {Parser, Lexer, ChangeDetection, dynamicChangeDetection, jitChangeDetection} from 'angular2/change_detection';
import {TemplateLoader} from './compiler/template_loader'; import {TemplateLoader} from './compiler/template_loader';
import {TemplateResolver} from './compiler/template_resolver';
import {DirectiveMetadataReader} from './compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from './compiler/directive_metadata_reader';
import {DirectiveMetadata} from './compiler/directive_metadata'; import {DirectiveMetadata} from './compiler/directive_metadata';
import {List, ListWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper} from 'angular2/src/facade/collection';
@ -28,6 +29,7 @@ var _rootBindings = [
Compiler, Compiler,
CompilerCache, CompilerCache,
TemplateLoader, TemplateLoader,
TemplateResolver,
DirectiveMetadataReader, DirectiveMetadataReader,
Parser, Parser,
Lexer, Lexer,
@ -62,7 +64,7 @@ function _injectorBindings(appComponentType): List<Binding> {
bind(appViewToken).toAsyncFactory((changeDetection, compiler, injector, appElement, bind(appViewToken).toAsyncFactory((changeDetection, compiler, injector, appElement,
appComponentAnnotatedType, strategy, eventManager) => { appComponentAnnotatedType, strategy, eventManager) => {
return compiler.compile(appComponentAnnotatedType.type, null).then( return compiler.compile(appComponentAnnotatedType.type).then(
(protoView) => { (protoView) => {
var appProtoView = ProtoView.createRootProtoView(protoView, appElement, var appProtoView = ProtoView.createRootProtoView(protoView, appElement,
appComponentAnnotatedType, changeDetection.createProtoChangeDetector('root'), appComponentAnnotatedType, changeDetection.createProtoChangeDetector('root'),

View File

@ -11,8 +11,10 @@ import {CompilePipeline} from './pipeline/compile_pipeline';
import {CompileElement} from './pipeline/compile_element'; import {CompileElement} from './pipeline/compile_element';
import {createDefaultSteps} from './pipeline/default_steps'; import {createDefaultSteps} from './pipeline/default_steps';
import {TemplateLoader} from './template_loader'; import {TemplateLoader} from './template_loader';
import {TemplateResolver} from './template_resolver';
import {DirectiveMetadata} from './directive_metadata'; import {DirectiveMetadata} from './directive_metadata';
import {Component} from '../annotations/annotations'; import {Component} from '../annotations/annotations';
import {Template} from '../annotations/template';
import {Content} from './shadow_dom_emulation/content_tag'; import {Content} from './shadow_dom_emulation/content_tag';
import {ShadowDomStrategy} from './shadow_dom_strategy'; import {ShadowDomStrategy} from './shadow_dom_strategy';
import {CompileStep} from './pipeline/compile_step'; import {CompileStep} from './pipeline/compile_step';
@ -55,13 +57,15 @@ export class Compiler {
_compiling:Map<Type, Promise>; _compiling:Map<Type, Promise>;
_shadowDomStrategy: ShadowDomStrategy; _shadowDomStrategy: ShadowDomStrategy;
_shadowDomDirectives: List<DirectiveMetadata>; _shadowDomDirectives: List<DirectiveMetadata>;
_templateResolver: TemplateResolver;
constructor(changeDetection:ChangeDetection, constructor(changeDetection:ChangeDetection,
templateLoader:TemplateLoader, templateLoader:TemplateLoader,
reader: DirectiveMetadataReader, reader: DirectiveMetadataReader,
parser:Parser, parser:Parser,
cache:CompilerCache, cache:CompilerCache,
shadowDomStrategy: ShadowDomStrategy) { shadowDomStrategy: ShadowDomStrategy,
templateResolver: TemplateResolver) {
this._changeDetection = changeDetection; this._changeDetection = changeDetection;
this._reader = reader; this._reader = reader;
this._parser = parser; this._parser = parser;
@ -74,32 +78,38 @@ export class Compiler {
for (var i = 0; i < types.length; i++) { for (var i = 0; i < types.length; i++) {
ListWrapper.push(this._shadowDomDirectives, reader.read(types[i])); ListWrapper.push(this._shadowDomDirectives, reader.read(types[i]));
} }
this._templateResolver = templateResolver;
} }
createSteps(component:DirectiveMetadata):List<CompileStep> { createSteps(component:Type, template: Template):List<CompileStep> {
var directives = [] // Merge directive metadata (from the template and from the shadow dom strategy)
var cmpDirectives = ListWrapper.map(component.componentDirectives, (d) => this._reader.read(d)); var dirMetadata = [];
directives = ListWrapper.concat(directives, cmpDirectives); var tplMetadata = ListWrapper.map(this._flattenDirectives(template),
directives = ListWrapper.concat(directives, this._shadowDomDirectives); (d) => this._reader.read(d));
return createDefaultSteps(this._changeDetection, this._parser, component, directives, dirMetadata = ListWrapper.concat(dirMetadata, tplMetadata);
dirMetadata = ListWrapper.concat(dirMetadata, this._shadowDomDirectives);
var cmpMetadata = this._reader.read(component);
return createDefaultSteps(this._changeDetection, this._parser, cmpMetadata, dirMetadata,
this._shadowDomStrategy); this._shadowDomStrategy);
} }
compile(component:Type, templateRoot:Element = null):Promise<ProtoView> { compile(component: Type):Promise<ProtoView> {
var protoView = this._compile(this._reader.read(component), templateRoot); var protoView = this._compile(component);
return PromiseWrapper.isPromise(protoView) ? protoView : PromiseWrapper.resolve(protoView); return PromiseWrapper.isPromise(protoView) ? protoView : PromiseWrapper.resolve(protoView);
} }
// TODO(vicb): union type return ProtoView or Promise<ProtoView> // TODO(vicb): union type return ProtoView or Promise<ProtoView>
_compile(cmpMetadata: DirectiveMetadata, templateRoot:Element = null) { _compile(component: Type) {
var protoView = this._compilerCache.get(cmpMetadata.type); var protoView = this._compilerCache.get(component);
if (isPresent(protoView)) { if (isPresent(protoView)) {
// The component has already been compiled into a ProtoView, // The component has already been compiled into a ProtoView,
// returns a resolved Promise. // returns a resolved Promise.
return protoView; return protoView;
} }
var pvPromise = MapWrapper.get(this._compiling, cmpMetadata.type); var pvPromise = MapWrapper.get(this._compiling, component);
if (isPresent(pvPromise)) { if (isPresent(pvPromise)) {
// The component is already being compiled, attach to the existing Promise // The component is already being compiled, attach to the existing Promise
// instead of re-compiling the component. // instead of re-compiling the component.
@ -107,30 +117,32 @@ export class Compiler {
return pvPromise; return pvPromise;
} }
var template = isBlank(templateRoot) ? this._templateLoader.load(cmpMetadata) : templateRoot; var template = this._templateResolver.resolve(component);
if (PromiseWrapper.isPromise(template)) { var tplElement = this._templateLoader.load(template);
pvPromise = PromiseWrapper.then(template,
(el) => this._compileTemplate(el, cmpMetadata), if (PromiseWrapper.isPromise(tplElement)) {
(_) => { throw new BaseException(`Failed to load the template for ${stringify(cmpMetadata.type)}`); } pvPromise = PromiseWrapper.then(tplElement,
(el) => this._compileTemplate(template, el, component),
(_) => { throw new BaseException(`Failed to load the template for ${stringify(component)}`); }
); );
MapWrapper.set(this._compiling, cmpMetadata.type, pvPromise); MapWrapper.set(this._compiling, component, pvPromise);
return pvPromise; return pvPromise;
} }
return this._compileTemplate(template, cmpMetadata); return this._compileTemplate(template, tplElement, component);
} }
// TODO(vicb): union type return ProtoView or Promise<ProtoView> // TODO(vicb): union type return ProtoView or Promise<ProtoView>
_compileTemplate(template: Element, cmpMetadata) { _compileTemplate(template: Template, tplElement: Element, component: Type) {
var pipeline = new CompilePipeline(this.createSteps(cmpMetadata)); var pipeline = new CompilePipeline(this.createSteps(component, template));
var compileElements = pipeline.process(template); var compileElements = pipeline.process(tplElement);
var protoView = compileElements[0].inheritedProtoView; var protoView = compileElements[0].inheritedProtoView;
// Populate the cache before compiling the nested components, // Populate the cache before compiling the nested components,
// so that components can reference themselves in their template. // so that components can reference themselves in their template.
this._compilerCache.set(cmpMetadata.type, protoView); this._compilerCache.set(component, protoView);
MapWrapper.delete(this._compiling, cmpMetadata.type); MapWrapper.delete(this._compiling, component);
// Compile all the components from the template // Compile all the components from the template
var nestedPVPromises = []; var nestedPVPromises = [];
@ -146,7 +158,7 @@ export class Compiler {
// The promise will resolved after nested ProtoViews are compiled. // The promise will resolved after nested ProtoViews are compiled.
return PromiseWrapper.then(PromiseWrapper.all(nestedPVPromises), return PromiseWrapper.then(PromiseWrapper.all(nestedPVPromises),
(_) => protoView, (_) => protoView,
(e) => { throw new BaseException(`${e.message} -> Failed to compile ${stringify(cmpMetadata.type)}`); } (e) => { throw new BaseException(`${e.message} -> Failed to compile ${stringify(component)}`); }
); );
} }
@ -154,9 +166,8 @@ export class Compiler {
return protoView; return protoView;
} }
_compileNestedProtoView(ce: CompileElement, promises: List<Promise>) _compileNestedProtoView(ce: CompileElement, promises: List<Promise>) {
{ var protoView = this._compile(ce.componentDirective.type);
var protoView = this._compile(ce.componentDirective);
if (PromiseWrapper.isPromise(protoView)) { if (PromiseWrapper.isPromise(protoView)) {
ListWrapper.push(promises, protoView); ListWrapper.push(promises, protoView);
@ -167,4 +178,27 @@ export class Compiler {
ce.inheritedElementBinder.nestedProtoView = protoView; ce.inheritedElementBinder.nestedProtoView = protoView;
} }
} }
_flattenDirectives(template: Template):List<Type> {
if (isBlank(template.directives)) return [];
var directives = [];
this._flattenList(template.directives, directives);
return directives;
}
_flattenList(tree:List<any>, out:List<Type>) {
for (var i = 0; i < tree.length; i++) {
var item = tree[i];
if (ListWrapper.isList(item)) {
this._flattenList(item, out);
} else {
ListWrapper.push(out, item);
}
}
}
} }

View File

@ -1,7 +1,5 @@
import {Type} from 'angular2/src/facade/lang'; import {Type} from 'angular2/src/facade/lang';
import {Directive} from 'angular2/src/core/annotations/annotations' import {Directive} from 'angular2/src/core/annotations/annotations'
import {List} from 'angular2/src/facade/collection'
import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
/** /**
* Combination of a type with the Directive annotation * Combination of a type with the Directive annotation
@ -9,13 +7,9 @@ import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'
export class DirectiveMetadata { export class DirectiveMetadata {
type:Type; type:Type;
annotation:Directive; annotation:Directive;
componentDirectives:List<Type>;
constructor(type:Type, constructor(type:Type, annotation:Directive) {
annotation:Directive,
componentDirectives:List<Type>) {
this.annotation = annotation; this.annotation = annotation;
this.type = type; this.type = type;
this.componentDirectives = componentDirectives;
} }
} }

View File

@ -1,9 +1,7 @@
import {Type, isPresent, BaseException, stringify} from 'angular2/src/facade/lang'; import {Type, isPresent, BaseException, stringify} from 'angular2/src/facade/lang';
import {List, ListWrapper} from 'angular2/src/facade/collection'; import {Directive} from '../annotations/annotations';
import {Directive, Component} from '../annotations/annotations';
import {DirectiveMetadata} from './directive_metadata'; import {DirectiveMetadata} from './directive_metadata';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
import {ShadowDom, ShadowDomStrategy, ShadowDomNative} from './shadow_dom_strategy';
export class DirectiveMetadataReader { export class DirectiveMetadataReader {
read(type:Type):DirectiveMetadata { read(type:Type):DirectiveMetadata {
@ -12,39 +10,12 @@ export class DirectiveMetadataReader {
for (var i=0; i<annotations.length; i++) { for (var i=0; i<annotations.length; i++) {
var annotation = annotations[i]; var annotation = annotations[i];
if (annotation instanceof Component) {
return new DirectiveMetadata(
type,
annotation,
this.componentDirectivesMetadata(annotation)
);
}
if (annotation instanceof Directive) { if (annotation instanceof Directive) {
return new DirectiveMetadata(type, annotation, null); return new DirectiveMetadata(type, annotation);
} }
} }
} }
throw new BaseException(`No Directive annotation found on ${stringify(type)}`); throw new BaseException(`No Directive annotation found on ${stringify(type)}`);
} }
componentDirectivesMetadata(annotation:Component):List<Type> {
var template = annotation.template;
var result:List<Type> = ListWrapper.create();
if (isPresent(template) && isPresent(template.directives)) {
this._buildList(result, template.directives);
}
return result;
}
_buildList(out:List<Type>, tree:List<any>) {
for (var i = 0; i < tree.length; i++) {
var item = tree[i];
if (ListWrapper.isList(item)) {
this._buildList(out, item);
} else {
ListWrapper.push(out, item);
}
}
}
} }

View File

@ -1,15 +1,12 @@
import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {isBlank, isPresent, BaseException, stringify} from 'angular2/src/facade/lang'; import {isBlank, isPresent, BaseException, stringify} from 'angular2/src/facade/lang';
import {TemplateElement, DOM, Element} from 'angular2/src/facade/dom'; import {DOM, Element} from 'angular2/src/facade/dom';
import {StringMapWrapper} from 'angular2/src/facade/collection'; import {StringMapWrapper} from 'angular2/src/facade/collection';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config';
import {Component} from 'angular2/src/core/annotations/annotations';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {XHR} from './xhr/xhr'; import {XHR} from './xhr/xhr';
import {Template} from 'angular2/src/core/annotations/template';
/** /**
* Strategy to load component templates. * Strategy to load component templates.
*/ */
@ -23,16 +20,13 @@ export class TemplateLoader {
} }
// TODO(vicb): union type: return an Element or a Promise<Element> // TODO(vicb): union type: return an Element or a Promise<Element>
load(cmpMetadata: DirectiveMetadata) { load(template: Template) {
var annotation:Component = cmpMetadata.annotation; if (isPresent(template.inline)) {
var tplConfig:TemplateConfig = annotation.template; return DOM.createTemplate(template.inline);
if (isPresent(tplConfig.inline)) {
return DOM.createTemplate(tplConfig.inline);
} }
if (isPresent(tplConfig.url)) { if (isPresent(template.url)) {
var url = tplConfig.url; var url = template.url;
var promise = StringMapWrapper.get(this._cache, url); var promise = StringMapWrapper.get(this._cache, url);
if (isBlank(promise)) { if (isBlank(promise)) {
@ -46,6 +40,6 @@ export class TemplateLoader {
return promise; return promise;
} }
throw new BaseException(`No template configured for component ${stringify(cmpMetadata.type)}`); throw new BaseException(`Templates should have either their url or inline property set`);
} }
} }

View File

@ -0,0 +1,38 @@
import {Template} from 'angular2/src/core/annotations/template';
import {Type, stringify, isBlank, BaseException} from 'angular2/src/facade/lang';
import {Map, MapWrapper, List, ListWrapper} from 'angular2/src/facade/collection';
import {reflector} from 'angular2/src/reflection/reflection';
export class TemplateResolver {
_cache: Map;
constructor() {
this._cache = MapWrapper.create();
}
resolve(component: Type): Template {
var template = MapWrapper.get(this._cache, component);
if (isBlank(template)) {
template = this._resolve(component);
MapWrapper.set(this._cache, component, template);
}
return template;
}
_resolve(component: Type) {
var annotations = reflector.annotations(component);
for (var i = 0; i < annotations.length; i++) {
var annotation = annotations[i];
if (annotation instanceof Template) {
return annotation;
}
}
throw new BaseException(`No template found for ${stringify(component)}`);
}
}

View File

@ -1,4 +1,4 @@
import {TemplateConfig, Component, Decorator, NgElement, Ancestor, onChange} from 'angular2/core'; import {Template, Component, Decorator, NgElement, Ancestor, onChange} from 'angular2/core';
import {DOM} from 'angular2/src/facade/dom'; import {DOM} from 'angular2/src/facade/dom';
import {isBlank, isPresent, CONST} from 'angular2/src/facade/lang'; import {isBlank, isPresent, CONST} from 'angular2/src/facade/lang';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection'; import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
@ -164,11 +164,9 @@ export class ControlGroupDirective extends ControlGroupDirectiveBase {
selector: '[new-control-group]', selector: '[new-control-group]',
bind: { bind: {
'new-control-group' : 'initData' 'new-control-group' : 'initData'
}, }
template: new TemplateConfig({
inline: '<content>'
})
}) })
@Template({inline: '<content>'})
export class NewControlGroupDirective extends ControlGroupDirectiveBase { export class NewControlGroupDirective extends ControlGroupDirectiveBase {
_initData:any; _initData:any;
_controlGroup:ControlGroup; _controlGroup:ControlGroup;

View File

@ -6,16 +6,11 @@ import {DOM} from 'angular2/src/facade/dom';
import {ListWrapper} from 'angular2/src/facade/collection'; import {ListWrapper} from 'angular2/src/facade/collection';
import {PromiseWrapper} from 'angular2/src/facade/async'; import {PromiseWrapper} from 'angular2/src/facade/async';
import {bind, Inject} from 'angular2/di'; import {bind, Inject} from 'angular2/di';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
@Component({ @Component({selector: 'hello-app'})
selector: 'hello-app', @Template({inline: '{{greeting}} world!'})
template: new TemplateConfig({
inline: '{{greeting}} world!',
directives: []
})
})
class HelloRootCmp { class HelloRootCmp {
greeting:string; greeting:string;
constructor() { constructor() {
@ -23,13 +18,8 @@ class HelloRootCmp {
} }
} }
@Component({ @Component({selector: 'hello-app-2'})
selector: 'hello-app-2', @Template({inline: '{{greeting}} world, again!'})
template: new TemplateConfig({
inline: '{{greeting}} world, again!',
directives: []
})
})
class HelloRootCmp2 { class HelloRootCmp2 {
greeting:string; greeting:string;
constructor() { constructor() {
@ -37,13 +27,8 @@ class HelloRootCmp2 {
} }
} }
@Component({ @Component({selector: 'hello-app'})
selector: 'hello-app', @Template({inline: ''})
template: new TemplateConfig({
inline: '',
directives: []
})
})
class HelloRootCmp3 { class HelloRootCmp3 {
appBinding; appBinding;
@ -52,13 +37,8 @@ class HelloRootCmp3 {
} }
} }
@Component({ @Component({selector: 'hello-app'})
selector: 'hello-app', @Template({inline: ''})
template: new TemplateConfig({
inline: '',
directives: []
})
})
class HelloRootCmp4 { class HelloRootCmp4 {
lc; lc;

View File

@ -1,7 +1,8 @@
import {describe, beforeEach, it, expect, ddescribe, iit, el, IS_DARTIUM} from 'angular2/test_lib'; import {describe, beforeEach, it, expect, ddescribe, iit, el, IS_DARTIUM} from 'angular2/test_lib';
import {DOM, Element, TemplateElement} from 'angular2/src/facade/dom'; import {DOM, Element, TemplateElement} from 'angular2/src/facade/dom';
import {List, ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {Type, isBlank, stringify} from 'angular2/src/facade/lang'; import {Type, isBlank, stringify, isPresent} from 'angular2/src/facade/lang';
import {PromiseWrapper} from 'angular2/src/facade/async'; import {PromiseWrapper} from 'angular2/src/facade/async';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
@ -9,39 +10,39 @@ import {ProtoView} from 'angular2/src/core/compiler/view';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata'; import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {Component} from 'angular2/src/core/annotations/annotations'; import {Component} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {CompileElement} from 'angular2/src/core/compiler/pipeline/compile_element'; import {CompileElement} from 'angular2/src/core/compiler/pipeline/compile_element';
import {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step' import {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step'
import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control'; import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection'; import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection';
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {XHRMock} from 'angular2/src/mock/xhr_mock';
export function main() { export function main() {
describe('compiler', function() { describe('compiler', function() {
var reader;
beforeEach( () => {
reader = new DirectiveMetadataReader();
});
var syncTemplateLoader = new FakeTemplateLoader();
syncTemplateLoader.forceSync();
var asyncTemplateLoader = new FakeTemplateLoader();
asyncTemplateLoader.forceAsync();
StringMapWrapper.forEach({ StringMapWrapper.forEach({
'(sync TemplateLoader)': syncTemplateLoader, '(sync TemplateLoader)': true,
'(async TemplateLoader)': asyncTemplateLoader '(async TemplateLoader)': false
}, (templateLoader, name) => { }, (sync, name) => {
var reader, tplResolver;
beforeEach(() => {
reader = new DirectiveMetadataReader();
tplResolver = new FakeTemplateResolver();
if (sync) {
tplResolver.forceSync();
} else {
tplResolver.forceAsync();
}
});
describe(name, () => { describe(name, () => {
function createCompiler(processClosure) { function createCompiler(processClosure) {
var steps = [new MockStep(processClosure)]; var steps = [new MockStep(processClosure)];
return new TestableCompiler(reader, steps, templateLoader); return new TestableCompiler(reader, steps, new FakeTemplateLoader(), tplResolver);
} }
it('should run the steps and return the ProtoView of the root element', (done) => { it('should run the steps and return the ProtoView of the root element', (done) => {
@ -49,43 +50,35 @@ export function main() {
var compiler = createCompiler( (parent, current, control) => { var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = rootProtoView; current.inheritedProtoView = rootProtoView;
}); });
compiler.compile(MainComponent, el('<div></div>')).then( (protoView) => { tplResolver.setTemplate(MainComponent, new Template({inline: '<div></div>'}));
compiler.compile(MainComponent).then( (protoView) => {
expect(protoView).toBe(rootProtoView); expect(protoView).toBe(rootProtoView);
done(); done();
}); });
}); });
it('should use the given element', (done) => { it('should use the inline template', (done) => {
var element = el('<div></div>');
var compiler = createCompiler( (parent, current, control) => { var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null); current.inheritedProtoView = new ProtoView(current.element, null, null);
}); });
compiler.compile(MainComponent, element).then( (protoView) => { compiler.compile(MainComponent).then( (protoView) => {
expect(protoView.element).toBe(element);
done();
});
});
it('should use the inline template if no element is given explicitly', (done) => {
var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null);
});
compiler.compile(MainComponent, null).then( (protoView) => {
expect(DOM.getInnerHTML(protoView.element)).toEqual('inline component'); expect(DOM.getInnerHTML(protoView.element)).toEqual('inline component');
done(); done();
}); });
}); });
it('should load nested components', (done) => { it('should load nested components', (done) => {
var mainEl = el('<div></div>');
var compiler = createCompiler( (parent, current, control) => { var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null); if (DOM.hasClass(current.element, 'nested')) {
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
if (current.element === mainEl) {
current.componentDirective = reader.read(NestedComponent); current.componentDirective = reader.read(NestedComponent);
current.inheritedProtoView = parent.inheritedProtoView;
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
} else {
current.inheritedProtoView = new ProtoView(current.element, null, null);
} }
}); });
compiler.compile(MainComponent, mainEl).then( (protoView) => { tplResolver.setTemplate(MainComponent, new Template({inline: '<div class="nested"></div>'}));
compiler.compile(MainComponent).then( (protoView) => {
var nestedView = protoView.elementBinders[0].nestedProtoView; var nestedView = protoView.elementBinders[0].nestedProtoView;
expect(DOM.getInnerHTML(nestedView.element)).toEqual('nested component'); expect(DOM.getInnerHTML(nestedView.element)).toEqual('nested component');
done(); done();
@ -93,14 +86,14 @@ export function main() {
}); });
it('should cache compiled components', (done) => { it('should cache compiled components', (done) => {
var element = el('<div></div>');
var compiler = createCompiler( (parent, current, control) => { var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null); current.inheritedProtoView = new ProtoView(current.element, null, null);
}); });
var firstProtoView; var firstProtoView;
compiler.compile(MainComponent, element).then( (protoView) => { tplResolver.setTemplate(MainComponent, new Template({inline: '<div></div>'}));
compiler.compile(MainComponent).then( (protoView) => {
firstProtoView = protoView; firstProtoView = protoView;
return compiler.compile(MainComponent, element); return compiler.compile(MainComponent);
}).then( (protoView) => { }).then( (protoView) => {
expect(firstProtoView).toBe(protoView); expect(firstProtoView).toBe(protoView);
done(); done();
@ -109,7 +102,6 @@ export function main() {
it('should re-use components being compiled', (done) => { it('should re-use components being compiled', (done) => {
var nestedElBinders = []; var nestedElBinders = [];
var mainEl = el('<div><div class="nested"></div><div class="nested"></div></div>');
var compiler = createCompiler( (parent, current, control) => { var compiler = createCompiler( (parent, current, control) => {
if (DOM.hasClass(current.element, 'nested')) { if (DOM.hasClass(current.element, 'nested')) {
current.inheritedProtoView = new ProtoView(current.element, null, null); current.inheritedProtoView = new ProtoView(current.element, null, null);
@ -118,7 +110,9 @@ export function main() {
ListWrapper.push(nestedElBinders, current.inheritedElementBinder); ListWrapper.push(nestedElBinders, current.inheritedElementBinder);
} }
}); });
compiler.compile(MainComponent, mainEl).then( (protoView) => { tplResolver.setTemplate(MainComponent,
new Template({inline: '<div><div class="nested"></div><div class="nested"></div></div>'}));
compiler.compile(MainComponent).then( (protoView) => {
expect(nestedElBinders[0].nestedProtoView).toBe(nestedElBinders[1].nestedProtoView); expect(nestedElBinders[0].nestedProtoView).toBe(nestedElBinders[1].nestedProtoView);
done(); done();
}); });
@ -130,7 +124,7 @@ export function main() {
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null); current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
current.componentDirective = reader.read(RecursiveComponent); current.componentDirective = reader.read(RecursiveComponent);
}); });
compiler.compile(RecursiveComponent, null).then( (protoView) => { compiler.compile(RecursiveComponent).then( (protoView) => {
expect(protoView.elementBinders[0].nestedProtoView).toBe(protoView); expect(protoView.elementBinders[0].nestedProtoView).toBe(protoView);
done(); done();
}); });
@ -139,12 +133,14 @@ export function main() {
}); });
describe('(mixed async, sync TemplateLoader)', () => { describe('(mixed async, sync TemplateLoader)', () => {
function createCompiler(processClosure, templateLoader: TemplateLoader) { var reader = new DirectiveMetadataReader();
function createCompiler(processClosure, resolver: TemplateResolver) {
var steps = [new MockStep(processClosure)]; var steps = [new MockStep(processClosure)];
return new TestableCompiler(reader, steps, templateLoader); return new TestableCompiler(reader, steps, new FakeTemplateLoader(), resolver);
} }
function createNestedComponentSpec(name, loader: TemplateLoader, error:string = null) { function createNestedComponentSpec(name, resolver: TemplateResolver, error:string = null) {
it(`should load nested components ${name}`, (done) => { it(`should load nested components ${name}`, (done) => {
var compiler = createCompiler((parent, current, control) => { var compiler = createCompiler((parent, current, control) => {
@ -155,7 +151,7 @@ export function main() {
} else { } else {
current.inheritedProtoView = new ProtoView(current.element, null, null); current.inheritedProtoView = new ProtoView(current.element, null, null);
} }
}, loader); }, resolver);
PromiseWrapper.then(compiler.compile(ParentComponent), PromiseWrapper.then(compiler.compile(ParentComponent),
function(protoView) { function(protoView) {
@ -172,89 +168,77 @@ export function main() {
}); });
} }
var loader = new FakeTemplateLoader(); var resolver = new FakeTemplateResolver();
loader.setSync(ParentComponent); resolver.setSync(ParentComponent);
loader.setSync(NestedComponent); resolver.setSync(NestedComponent);
createNestedComponentSpec('(sync -> sync)', loader); createNestedComponentSpec('(sync -> sync)', resolver);
loader = new FakeTemplateLoader(); resolver = new FakeTemplateResolver();
loader.setAsync(ParentComponent); resolver.setAsync(ParentComponent);
loader.setSync(NestedComponent); resolver.setSync(NestedComponent);
createNestedComponentSpec('(async -> sync)', loader); createNestedComponentSpec('(async -> sync)', resolver);
loader = new FakeTemplateLoader(); resolver = new FakeTemplateResolver();
loader.setSync(ParentComponent); resolver.setSync(ParentComponent);
loader.setAsync(NestedComponent); resolver.setAsync(NestedComponent);
createNestedComponentSpec('(sync -> async)', loader); createNestedComponentSpec('(sync -> async)', resolver);
loader = new FakeTemplateLoader(); resolver = new FakeTemplateResolver();
loader.setAsync(ParentComponent); resolver.setAsync(ParentComponent);
loader.setAsync(NestedComponent); resolver.setAsync(NestedComponent);
createNestedComponentSpec('(async -> async)', loader); createNestedComponentSpec('(async -> async)', resolver);
loader = new FakeTemplateLoader(); resolver = new FakeTemplateResolver();
loader.setError(ParentComponent); resolver.setError(ParentComponent);
loader.setSync(NestedComponent); resolver.setSync(NestedComponent);
createNestedComponentSpec('(error -> sync)', loader, createNestedComponentSpec('(error -> sync)', resolver,
'Failed to load the template for ParentComponent'); 'Failed to load the template for ParentComponent');
// TODO(vicb): Check why errors this fails with Dart // TODO(vicb): Check why errors this fails with Dart
// TODO(vicb): The Promise is rejected with the correct error but an exc is thrown before // TODO(vicb): The Promise is rejected with the correct error but an exc is thrown before
//loader = new FakeTemplateLoader(); //resolver = new FakeTemplateResolver();
//loader.setSync(ParentComponent); //resolver.setSync(ParentComponent);
//loader.setError(NestedComponent); //resolver.setError(NestedComponent);
//createNestedComponentSpec('(sync -> error)', loader, //createNestedComponentSpec('(sync -> error)', resolver,
// 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent'); // 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent');
// //
//loader = new FakeTemplateLoader(); //resolver = new FakeTemplateResolver();
//loader.setAsync(ParentComponent); //resolver.setAsync(ParentComponent);
//loader.setError(NestedComponent); //resolver.setError(NestedComponent);
//createNestedComponentSpec('(async -> error)', loader, //createNestedComponentSpec('(async -> error)', resolver,
// 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent'); // 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent');
}); });
}); });
} }
@Component({ @Component()
template: new TemplateConfig({ @Template({inline: '<div class="parent"></div>'})
inline: '<div class="parent"></div>'
})
})
class ParentComponent {} class ParentComponent {}
@Component({ @Component()
template: new TemplateConfig({ @Template({inline: 'inline component'})
inline: 'inline component'
})
})
class MainComponent {} class MainComponent {}
@Component({ @Component()
template: new TemplateConfig({ @Template({inline: 'nested component'})
inline: 'nested component'
})
})
class NestedComponent {} class NestedComponent {}
@Component({ @Component({selector: 'rec-comp'})
template: new TemplateConfig({ @Template({inline: '<div rec-comp></div>'})
inline: '<div rec-comp></div>'
}),
selector: 'rec-comp'
})
class RecursiveComponent {} class RecursiveComponent {}
class TestableCompiler extends Compiler { class TestableCompiler extends Compiler {
steps:List; steps:List;
constructor(reader:DirectiveMetadataReader, steps:List<CompileStep>, loader: TemplateLoader) { constructor(reader:DirectiveMetadataReader, steps:List<CompileStep>, loader: TemplateLoader,
resolver: TemplateResolver) {
super(dynamicChangeDetection, loader, reader, new Parser(new Lexer()), new CompilerCache(), super(dynamicChangeDetection, loader, reader, new Parser(new Lexer()), new CompilerCache(),
new NativeShadowDomStrategy()); new NativeShadowDomStrategy(), resolver);
this.steps = steps; this.steps = steps;
} }
createSteps(component):List<CompileStep> { createSteps(component:Type, template: Template):List<CompileStep> {
return this.steps; return this.steps;
} }
} }
@ -271,19 +255,70 @@ class MockStep extends CompileStep {
} }
class FakeTemplateLoader extends TemplateLoader { class FakeTemplateLoader extends TemplateLoader {
constructor() {
super(null);
}
load(template: Template) {
if (isPresent(template.inline)) {
return DOM.createTemplate(template.inline);
}
if (isPresent(template.url)) {
var tplElement = DOM.createTemplate(template.url);
return PromiseWrapper.resolve(tplElement);
}
return PromiseWrapper.reject('Fail to load');
}
}
class FakeTemplateResolver extends TemplateResolver {
_forceSync: boolean; _forceSync: boolean;
_forceAsync: boolean; _forceAsync: boolean;
_cmpTemplates: Map;
_syncCmp: List<Type>; _syncCmp: List<Type>;
_asyncCmp: List<Type>; _asyncCmp: List<Type>;
_errorCmp: List<Type>; _errorCmp: List<Type>;
constructor() { constructor() {
super (new XHRMock()); super();
this._forceSync = false; this._forceSync = false;
this._forceAsync = false; this._forceAsync = false;
this._syncCmp = []; this._syncCmp = [];
this._asyncCmp = []; this._asyncCmp = [];
this._errorCmp = []; this._errorCmp = [];
this._cmpTemplates = MapWrapper.create();
}
resolve(component: Type): Template {
var template = MapWrapper.get(this._cmpTemplates, component);
if (isBlank(template)) {
template = super.resolve(component);
}
var html = template.inline;
if (isBlank(template.inline)) {
throw 'The tested component must define an inline template';
}
if (ListWrapper.contains(this._errorCmp, component)) {
return new Template({url: null, inline: null});
}
if (ListWrapper.contains(this._syncCmp, component)) {
return new Template({inline: html});
}
if (ListWrapper.contains(this._asyncCmp, component)) {
return new Template({url: html});
}
if (this._forceSync) return new Template({inline: html});
if (this._forceAsync) return new Template({url: html});
throw 'No template';
} }
forceSync() { forceSync() {
@ -308,31 +343,7 @@ class FakeTemplateLoader extends TemplateLoader {
ListWrapper.push(this._errorCmp, component); ListWrapper.push(this._errorCmp, component);
} }
load(cmpMetadata: DirectiveMetadata) { setTemplate(component: Type, template: Template) {
var annotation:Component = cmpMetadata.annotation; MapWrapper.set(this._cmpTemplates, component, template);
var tplConfig:TemplateConfig = annotation.template;
if (isBlank(tplConfig.inline)) {
throw 'The component must define an inline template';
}
var template = DOM.createTemplate(tplConfig.inline);
if (ListWrapper.contains(this._errorCmp, cmpMetadata.type)) {
return PromiseWrapper.reject('Fail to load');
}
if (ListWrapper.contains(this._syncCmp, cmpMetadata.type)) {
return template;
}
if (ListWrapper.contains(this._asyncCmp, cmpMetadata.type)) {
return PromiseWrapper.resolve(template);
}
if (this._forceSync) return template;
if (this._forceAsync) return PromiseWrapper.resolve(template);
throw `No template configured for ${stringify(cmpMetadata.type)}`;
} }
} }

View File

@ -1,43 +1,25 @@
import {ddescribe, describe, it, iit, expect, beforeEach} from 'angular2/test_lib'; import {ddescribe, describe, it, iit, expect, beforeEach} from 'angular2/test_lib';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {Decorator, Component} from 'angular2/src/core/annotations/annotations'; import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata'; import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {CONST} from 'angular2/src/facade/lang'; import {CONST} from 'angular2/src/facade/lang';
import {If, Foreach} from 'angular2/directives'; import {If, Foreach} from 'angular2/directives';
@Decorator({ @Decorator({selector: 'someDecorator'})
selector: 'someSelector' class SomeDecorator {}
})
class SomeDirective { @Component({selector: 'someComponent'})
} class SomeComponent {}
@Viewport({selector: 'someViewport'})
class SomeViewport {}
class SomeDirectiveWithoutAnnotation { class SomeDirectiveWithoutAnnotation {
} }
@Component({
selector: 'withoutDirectives'
})
class ComponentWithoutDirectives {}
@Component({
selector: 'withDirectives',
template: new TemplateConfig({
directives: [ComponentWithoutDirectives]
})
})
class ComponentWithDirectives {}
@Component({
selector: 'withDirectivesTree',
template: new TemplateConfig({
directives: [[SomeDirective, [Foreach, If]], ComponentWithoutDirectives]
})
})
class ComponentWithDirectivesTree {}
export function main() { export function main() {
describe("DirectiveMetadataReader", () => { describe("DirectiveMetadataReader", () => {
var reader; var reader;
@ -46,10 +28,22 @@ export function main() {
reader = new DirectiveMetadataReader(); reader = new DirectiveMetadataReader();
}); });
it('should read out the annotation', () => { it('should read out the Decorator annotation', () => {
var directiveMetadata = reader.read(SomeDirective); var directiveMetadata = reader.read(SomeDecorator);
expect(directiveMetadata).toEqual( expect(directiveMetadata).toEqual(
new DirectiveMetadata(SomeDirective, new Decorator({selector: 'someSelector'}), null)); new DirectiveMetadata(SomeDecorator, new Decorator({selector: 'someDecorator'})));
});
it('should read out the Viewport annotation', () => {
var directiveMetadata = reader.read(SomeViewport);
expect(directiveMetadata).toEqual(
new DirectiveMetadata(SomeViewport, new Viewport({selector: 'someViewport'})));
});
it('should read out the Component annotation', () => {
var directiveMetadata = reader.read(SomeComponent);
expect(directiveMetadata).toEqual(
new DirectiveMetadata(SomeComponent, new Component({selector: 'someComponent'})));
}); });
it('should throw if not matching annotation is found', () => { it('should throw if not matching annotation is found', () => {
@ -57,22 +51,5 @@ export function main() {
reader.read(SomeDirectiveWithoutAnnotation); reader.read(SomeDirectiveWithoutAnnotation);
}).toThrowError('No Directive annotation found on SomeDirectiveWithoutAnnotation'); }).toThrowError('No Directive annotation found on SomeDirectiveWithoutAnnotation');
}); });
describe("componentDirectives", () => {
it("should return an empty list when no directives specified", () => {
var cmp = reader.read(ComponentWithoutDirectives);
expect(cmp.componentDirectives).toEqual([]);
});
it("should return a list of directives specified in the template config", () => {
var cmp = reader.read(ComponentWithDirectives);
expect(cmp.componentDirectives).toEqual([ComponentWithoutDirectives]);
});
it("should return a list of directives specified in the template config as a tree", () => {
var cmp = reader.read(ComponentWithDirectivesTree);
expect(cmp.componentDirectives).toEqual([SomeDirective, Foreach, If, ComponentWithoutDirectives]);
});
});
}); });
} }

View File

@ -1,6 +1,8 @@
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib'; import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib';
import {DOM} from 'angular2/src/facade/dom'; import {DOM} from 'angular2/src/facade/dom';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {Type, isPresent} from 'angular2/src/facade/lang';
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection'; import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
@ -9,27 +11,27 @@ import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config'; import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations'; import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {ViewContainer} from 'angular2/src/core/compiler/view_container'; import {ViewContainer} from 'angular2/src/core/compiler/view_container';
import {MapWrapper} from 'angular2/src/facade/collection';
import {XHRMock} from 'angular2/src/mock/xhr_mock';
export function main() { export function main() {
describe('integration tests', function() { describe('integration tests', function() {
var compiler; var compiler, tplResolver;
beforeEach( () => { beforeEach( () => {
tplResolver = new FakeTemplateResolver();
compiler = new Compiler(dynamicChangeDetection, compiler = new Compiler(dynamicChangeDetection,
new TemplateLoader(new XHRMock()), new TemplateLoader(null),
new DirectiveMetadataReader(), new DirectiveMetadataReader(),
new Parser(new Lexer()), new Parser(new Lexer()),
new CompilerCache(), new CompilerCache(),
new NativeShadowDomStrategy() new NativeShadowDomStrategy(),
tplResolver
); );
}); });
@ -43,7 +45,9 @@ export function main() {
} }
it('should consume text node changes', (done) => { it('should consume text node changes', (done) => {
compiler.compile(MyComp, el('<div>{{ctxProp}}</div>')).then((pv) => { tplResolver.setTemplate(MyComp, new Template({inline: '<div>{{ctxProp}}</div>'}));
compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
ctx.ctxProp = 'Hello World!'; ctx.ctxProp = 'Hello World!';
@ -54,7 +58,9 @@ export function main() {
}); });
it('should consume element binding changes', (done) => { it('should consume element binding changes', (done) => {
compiler.compile(MyComp, el('<div [id]="ctxProp"></div>')).then((pv) => { tplResolver.setTemplate(MyComp, new Template({inline: '<div [id]="ctxProp"></div>'}));
compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
ctx.ctxProp = 'Hello World!'; ctx.ctxProp = 'Hello World!';
@ -73,7 +79,9 @@ export function main() {
'<div my-dir elprop="Hi {{\'there!\'}}"></div>' + '<div my-dir elprop="Hi {{\'there!\'}}"></div>' +
'<div my-dir elprop="One more {{ctxProp}}"></div>' + '<div my-dir elprop="One more {{ctxProp}}"></div>' +
'</div>' '</div>'
compiler.compile(MyComp, el(tpl)).then((pv) => { tplResolver.setTemplate(MyComp, new Template({inline: tpl, directives: [MyDir]}));
compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
ctx.ctxProp = 'Hello World!'; ctx.ctxProp = 'Hello World!';
@ -88,7 +96,12 @@ export function main() {
}); });
it('should support nested components.', (done) => { it('should support nested components.', (done) => {
compiler.compile(MyComp, el('<child-cmp></child-cmp>')).then((pv) => { tplResolver.setTemplate(MyComp, new Template({
inline: '<child-cmp></child-cmp>',
directives: [ChildComp]
}));
compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
cd.detectChanges(); cd.detectChanges();
@ -100,7 +113,13 @@ export function main() {
// GH issue 328 - https://github.com/angular/angular/issues/328 // GH issue 328 - https://github.com/angular/angular/issues/328
it('should support different directive types on a single node', (done) => { it('should support different directive types on a single node', (done) => {
compiler.compile(MyComp, el('<child-cmp my-dir [elprop]="ctxProp"></child-cmp>')).then((pv) => { tplResolver.setTemplate(MyComp,
new Template({
inline: '<child-cmp my-dir [elprop]="ctxProp"></child-cmp>',
directives: [MyDir, ChildComp]
}));
compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
ctx.ctxProp = 'Hello World!'; ctx.ctxProp = 'Hello World!';
@ -115,7 +134,13 @@ export function main() {
}); });
it('should support template directives via `<template>` elements.', (done) => { it('should support template directives via `<template>` elements.', (done) => {
compiler.compile(MyComp, el('<div><template some-tmplate var-greeting="some-tmpl"><copy-me>{{greeting}}</copy-me></template></div>')).then((pv) => { tplResolver.setTemplate(MyComp,
new Template({
inline: '<div><template some-viewport var-greeting="some-tmpl"><copy-me>{{greeting}}</copy-me></template></div>',
directives: [SomeViewport]
}));
compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
cd.detectChanges(); cd.detectChanges();
@ -130,7 +155,12 @@ export function main() {
}); });
it('should support template directives via `template` attribute.', (done) => { it('should support template directives via `template` attribute.', (done) => {
compiler.compile(MyComp, el('<div><copy-me template="some-tmplate: var greeting=some-tmpl">{{greeting}}</copy-me></div>')).then((pv) => { tplResolver.setTemplate(MyComp, new Template({
inline: '<div><copy-me template="some-viewport: var greeting=some-tmpl">{{greeting}}</copy-me></div>',
directives: [SomeViewport]
}));
compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
cd.detectChanges(); cd.detectChanges();
@ -145,7 +175,12 @@ export function main() {
}); });
it('should assign the component instance to a var-', (done) => { it('should assign the component instance to a var-', (done) => {
compiler.compile(MyComp, el('<p><child-cmp var-alice></child-cmp></p>')).then((pv) => { tplResolver.setTemplate(MyComp, new Template({
inline: '<p><child-cmp var-alice></child-cmp></p>',
directives: [ChildComp]
}));
compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
expect(view.contextWithLocals).not.toBe(null); expect(view.contextWithLocals).not.toBe(null);
@ -156,9 +191,12 @@ export function main() {
}); });
it('should assign two component instances each with a var-', (done) => { it('should assign two component instances each with a var-', (done) => {
var element = el('<p><child-cmp var-alice></child-cmp><child-cmp var-bob></p>'); tplResolver.setTemplate(MyComp, new Template({
inline: '<p><child-cmp var-alice></child-cmp><child-cmp var-bob></p>',
directives: [ChildComp]
}));
compiler.compile(MyComp, element).then((pv) => { compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
expect(view.contextWithLocals).not.toBe(null); expect(view.contextWithLocals).not.toBe(null);
@ -171,7 +209,12 @@ export function main() {
}); });
it('should assign the component instance to a var- with shorthand syntax', (done) => { it('should assign the component instance to a var- with shorthand syntax', (done) => {
compiler.compile(MyComp, el('<child-cmp #alice></child-cmp>')).then((pv) => { tplResolver.setTemplate(MyComp, new Template({
inline: '<child-cmp #alice></child-cmp>',
directives: [ChildComp]
}));
compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
expect(view.contextWithLocals).not.toBe(null); expect(view.contextWithLocals).not.toBe(null);
@ -182,13 +225,10 @@ export function main() {
}); });
it('should assign the element instance to a user-defined variable', (done) => { it('should assign the element instance to a user-defined variable', (done) => {
// How is this supposed to work? tplResolver.setTemplate(MyComp,
var element = el('<p></p>'); new Template({inline: '<p><div var-alice><i>Hello</i></div></p>'}));
var div = el('<div var-alice></div>');
DOM.appendChild(div, el('<i>Hello</i>'));
DOM.appendChild(element, div);
compiler.compile(MyComp, element).then((pv) => { compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
expect(view.contextWithLocals).not.toBe(null); expect(view.contextWithLocals).not.toBe(null);
@ -201,7 +241,12 @@ export function main() {
}); });
it('should provide binding configuration config to the component', (done) => { it('should provide binding configuration config to the component', (done) => {
compiler.compile(MyComp, el('<push-cmp #cmp></push-cmp>')).then((pv) => { tplResolver.setTemplate(MyComp, new Template({
inline: '<push-cmp #cmp></push-cmp>',
directives: [[[PushBasedComp]]]
}));
compiler.compile(MyComp).then((pv) => {
createView(pv); createView(pv);
var cmp = view.contextWithLocals.get('cmp'); var cmp = view.contextWithLocals.get('cmp');
@ -234,12 +279,8 @@ class MyDir {
} }
} }
@Component({ @Component({selector: 'push-cmp'})
selector: 'push-cmp', @Template({inline: '{{field}}'})
template: new TemplateConfig({
inline: '{{field}}'
})
})
class PushBasedComp { class PushBasedComp {
numberOfChecks:number; numberOfChecks:number;
bpc:BindingPropagationConfig; bpc:BindingPropagationConfig;
@ -260,11 +301,7 @@ class PushBasedComp {
} }
} }
@Component({ @Component()
template: new TemplateConfig({
directives: [MyDir, [[ChildComp], SomeViewport, PushBasedComp]]
})
})
class MyComp { class MyComp {
ctxProp:string; ctxProp:string;
constructor() { constructor() {
@ -274,11 +311,11 @@ class MyComp {
@Component({ @Component({
selector: 'child-cmp', selector: 'child-cmp',
componentServices: [MyService], componentServices: [MyService]
template: new TemplateConfig({ })
directives: [MyDir], @Template({
inline: '{{ctxProp}}' directives: [MyDir],
}) inline: '{{ctxProp}}'
}) })
class ChildComp { class ChildComp {
ctxProp:string; ctxProp:string;
@ -290,7 +327,7 @@ class ChildComp {
} }
@Viewport({ @Viewport({
selector: '[some-tmplate]' selector: '[some-viewport]'
}) })
class SomeViewport { class SomeViewport {
constructor(container: ViewContainer) { constructor(container: ViewContainer) {
@ -305,3 +342,26 @@ class MyService {
this.greeting = 'hello'; this.greeting = 'hello';
} }
} }
class FakeTemplateResolver extends TemplateResolver {
_cmpTemplates: Map;
constructor() {
super();
this._cmpTemplates = MapWrapper.create();
}
setTemplate(component: Type, template: Template) {
MapWrapper.set(this._cmpTemplates, component, template);
}
resolve(component: Type): Template {
var override = MapWrapper.get(this._cmpTemplates, component);
if (isPresent(override)) {
return override;
}
return super.resolve(component);
}
}

View File

@ -9,7 +9,7 @@ import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_contro
import {DOM} from 'angular2/src/facade/dom'; import {DOM} from 'angular2/src/facade/dom';
import {NativeShadowDomStrategy, ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy, ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {Component, Decorator, Viewport} from 'angular2/src/core/annotations/annotations'; import {Component, Decorator, Viewport} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {Lexer, Parser} from 'angular2/change_detection'; import {Lexer, Parser} from 'angular2/change_detection';
@ -235,19 +235,14 @@ class SomeViewport {}
}) })
class SomeViewport2 {} class SomeViewport2 {}
@Component({ @Component({selector: '[some-comp]'})
selector: '[some-comp]'
})
class SomeComponent {} class SomeComponent {}
@Component({ @Component({selector: '[some-comp2]'})
selector: '[some-comp2]'
})
class SomeComponent2 {} class SomeComponent2 {}
@Component({ @Component()
template: new TemplateConfig({ @Template({
directives: [SomeDecorator, SomeViewport, SomeViewport2, SomeComponent, SomeComponent2] directives: [SomeDecorator, SomeViewport, SomeViewport2, SomeComponent, SomeComponent2]
})
}) })
class MyComp {} class MyComp {}

View File

@ -405,9 +405,7 @@ class SomeViewportDirectiveWithBinding {
class SomeComponentDirective { class SomeComponentDirective {
} }
@Component({ @Component({bind: {'boundprop3': 'compProp'}})
bind: {'boundprop3': 'compProp'}
})
class SomeComponentDirectiveWithBinding { class SomeComponentDirectiveWithBinding {
compProp; compProp;
constructor() { constructor() {

View File

@ -14,7 +14,7 @@ export function main() {
describe('ShadowDomTransformer', () => { describe('ShadowDomTransformer', () => {
function createPipeline(selector, strategy:ShadowDomStrategy, styleHost) { function createPipeline(selector, strategy:ShadowDomStrategy, styleHost) {
var component = new Component({selector: selector}); var component = new Component({selector: selector});
var meta = new DirectiveMetadata(null, component, null); var meta = new DirectiveMetadata(null, component);
var transformer = new ShadowDomTransformer(meta, strategy, styleHost); var transformer = new ShadowDomTransformer(meta, strategy, styleHost);
transformer.clearCache(); transformer.clearCache();
return new CompilePipeline([transformer]); return new CompilePipeline([transformer]);

View File

@ -1,6 +1,8 @@
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib'; import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib';
import {DOM} from 'angular2/src/facade/dom'; import {DOM} from 'angular2/src/facade/dom';
import {StringMapWrapper, MapWrapper, List} from 'angular2/src/facade/collection';
import {isPresent, Type} from 'angular2/src/facade/lang';
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection'; import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
@ -12,14 +14,12 @@ import {ShadowDomStrategy,
NativeShadowDomStrategy, NativeShadowDomStrategy,
EmulatedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; EmulatedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations'; import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {ViewContainer} from 'angular2/src/core/compiler/view_container'; import {ViewContainer} from 'angular2/src/core/compiler/view_container';
import {StringMapWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {XHRMock} from 'angular2/src/mock/xhr_mock';
export function main() { export function main() {
describe('integration tests', function() { describe('integration tests', function() {
@ -31,22 +31,28 @@ export function main() {
(strategy, name) => { (strategy, name) => {
describe(`${name} shadow dom strategy`, () => { describe(`${name} shadow dom strategy`, () => {
var compiler; var compiler, tplResolver;
beforeEach( () => { beforeEach(() => {
tplResolver = new FakeTemplateResolver();
compiler = new Compiler(dynamicChangeDetection, compiler = new Compiler(dynamicChangeDetection,
new TemplateLoader(new XHRMock()), new TemplateLoader(null),
new DirectiveMetadataReader(), new DirectiveMetadataReader(),
new Parser(new Lexer()), new Parser(new Lexer()),
new CompilerCache(), new CompilerCache(),
strategy strategy,
tplResolver
); );
}); });
function compile(template, assertions) { function compile(template, directives: List<Type>, assertions) {
compiler.compile(MyComp, el(template)). tplResolver.setTemplate(MyComp, new Template({
then(createView). inline: template,
then((view) => { directives: directives
}));
compiler.compile(MyComp)
.then(createView)
.then((view) => {
var lc = new LifeCycle(view.changeDetector, false); var lc = new LifeCycle(view.changeDetector, false);
assertions(view, lc); assertions(view, lc);
}); });
@ -59,7 +65,7 @@ export function main() {
'<div class="left">A</div>' + '<div class="left">A</div>' +
'</multiple-content-tags>'; '</multiple-content-tags>';
compile(temp, (view, lc) => { compile(temp, [MultipleContentTagsComponent], (view, lc) => {
expect(view.nodes).toHaveText('(A, BC)'); expect(view.nodes).toHaveText('(A, BC)');
done(); done();
}); });
@ -71,7 +77,7 @@ export function main() {
'<div>C</div>' + '<div>C</div>' +
'</multiple-content-tags>'; '</multiple-content-tags>';
compile(temp, (view, lc) => { compile(temp, [MultipleContentTagsComponent], (view, lc) => {
expect(view.nodes).toHaveText('(, BAC)'); expect(view.nodes).toHaveText('(, BAC)');
done(); done();
}); });
@ -83,7 +89,7 @@ export function main() {
'<div>B</div>' + '<div>B</div>' +
'</multiple-content-tags>'; '</multiple-content-tags>';
compile(temp, (view, lc) => { compile(temp, [MultipleContentTagsComponent, ManualViewportDirective], (view, lc) => {
var dir = view.elementInjectors[1].get(ManualViewportDirective); var dir = view.elementInjectors[1].get(ManualViewportDirective);
expect(view.nodes).toHaveText('(, B)'); expect(view.nodes).toHaveText('(, B)');
@ -108,7 +114,7 @@ export function main() {
'<div>B</div>' + '<div>B</div>' +
'</multiple-content-tags>'; '</multiple-content-tags>';
compile(temp, (view, lc) => { compile(temp, [MultipleContentTagsComponent, ManualViewportDirective], (view, lc) => {
var dir = view.elementInjectors[1].get(ManualViewportDirective); var dir = view.elementInjectors[1].get(ManualViewportDirective);
expect(view.nodes).toHaveText('(, B)'); expect(view.nodes).toHaveText('(, B)');
@ -133,7 +139,7 @@ export function main() {
'<div>B</div>' + '<div>B</div>' +
'</outer-with-indirect-nested>'; '</outer-with-indirect-nested>';
compile(temp, (view, lc) => { compile(temp, [OuterWithIndirectNestedComponent], (view, lc) => {
expect(view.nodes).toHaveText('OUTER(SIMPLE(AB))'); expect(view.nodes).toHaveText('OUTER(SIMPLE(AB))');
done(); done();
@ -147,7 +153,7 @@ export function main() {
'<div>C</div>' + '<div>C</div>' +
'</outer>'; '</outer>';
compile(temp, (view, lc) => { compile(temp, [OuterComponent, ManualViewportDirective], (view, lc) => {
var dir = view.elementInjectors[1].get(ManualViewportDirective); var dir = view.elementInjectors[1].get(ManualViewportDirective);
expect(view.nodes).toHaveText('OUTER(INNER(INNERINNER(,BC)))'); expect(view.nodes).toHaveText('OUTER(INNER(INNERINNER(,BC)))');
@ -257,31 +263,23 @@ class AutoViewportDirective {
} }
} }
@Component({ @Component({selector: 'simple'})
selector: 'simple', @Template({inline: 'SIMPLE(<content></content>)'})
template: new TemplateConfig({
inline: 'SIMPLE(<content></content>)'
})
})
class Simple { class Simple {
} }
@Component({ @Component({selector: 'multiple-content-tags'})
selector: 'multiple-content-tags', @Template({
template: new TemplateConfig({ inline: '(<content select=".left"></content>, <content></content>)'
inline: '(<content select=".left"></content>, <content></content>)'
})
}) })
class MultipleContentTagsComponent { class MultipleContentTagsComponent {
} }
@Component({ @Component({selector: 'conditional-content'})
selector: 'conditional-content', @Template({
template: new TemplateConfig({ inline: '<div>(<div template="auto: cond"><content select=".left"></content></div>, <content></content>)</div>',
inline: '<div>(<div template="auto: cond"><content select=".left"></content></div>, <content></content>)</div>', directives: [AutoViewportDirective]
directives: [AutoViewportDirective]
})
}) })
class ConditionalContentComponent { class ConditionalContentComponent {
cond:boolean; cond:boolean;
@ -294,52 +292,42 @@ class ConditionalContentComponent {
hideLeft() { this.cond = false; } hideLeft() { this.cond = false; }
} }
@Component({ @Component({selector: 'outer-with-indirect-nested'})
selector: 'outer-with-indirect-nested', @Template({
template: new TemplateConfig({ inline: 'OUTER(<simple><div><content></content></div></simple>)',
inline: 'OUTER(<simple><div><content></content></div></simple>)', directives: [Simple]
directives: [Simple]
})
}) })
class OuterWithIndirectNestedComponent { class OuterWithIndirectNestedComponent {
} }
@Component({ @Component({selector: 'outer'})
selector: 'outer', @Template({
template: new TemplateConfig({ inline: 'OUTER(<inner><content></content></inner>)',
inline: 'OUTER(<inner><content></content></inner>)', directives: [InnerComponent]
directives: [InnerComponent]
})
}) })
class OuterComponent { class OuterComponent {
} }
@Component({ @Component({selector: 'inner'})
selector: 'inner', @Template({
template: new TemplateConfig({ inline: 'INNER(<innerinner><content></content></innerinner>)',
inline: 'INNER(<innerinner><content></content></innerinner>)', directives: [InnerInnerComponent]
directives: [InnerInnerComponent]
})
}) })
class InnerComponent { class InnerComponent {
} }
@Component({ @Component({selector: 'innerinner'})
selector: 'innerinner', @Template({
template: new TemplateConfig({ inline: 'INNERINNER(<content select=".left"></content>,<content></content>)'
inline: 'INNERINNER(<content select=".left"></content>,<content></content>)'
})
}) })
class InnerInnerComponent { class InnerInnerComponent {
} }
@Component({ @Component({selector: 'my-comp'})
selector: 'my-comp', @Template({
template: new TemplateConfig({ directives: [MultipleContentTagsComponent, ManualViewportDirective,
directives: [MultipleContentTagsComponent, ManualViewportDirective, ConditionalContentComponent, OuterWithIndirectNestedComponent, OuterComponent]
ConditionalContentComponent, OuterWithIndirectNestedComponent, OuterComponent]
})
}) })
class MyComp { class MyComp {
} }
@ -349,3 +337,26 @@ function createView(pv) {
view.hydrate(new Injector([]), null, {}); view.hydrate(new Injector([]), null, {});
return view; return view;
} }
class FakeTemplateResolver extends TemplateResolver {
_cmpTemplates: Map;
constructor() {
super();
this._cmpTemplates = MapWrapper.create();
}
setTemplate(component: Type, template: Template) {
MapWrapper.set(this._cmpTemplates, component, template);
}
resolve(component: Type): Template {
var override = MapWrapper.get(this._cmpTemplates, component);
if (isPresent(override)) {
return override;
}
return super.resolve(component);
}
}

View File

@ -1,10 +1,15 @@
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib'; import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {Component} from 'angular2/src/core/annotations/annotations'; import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata'; import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {Component} from 'angular2/src/core/annotations/annotations';
import {Template} from 'angular2/src/core/annotations/template';
import {PromiseWrapper} from 'angular2/src/facade/async'; import {PromiseWrapper} from 'angular2/src/facade/async';
import {Type, stringify, isPresent} from 'angular2/src/facade/lang';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {XHRMock} from 'angular2/src/mock/xhr_mock'; import {XHRMock} from 'angular2/src/mock/xhr_mock';
@ -17,25 +22,16 @@ export function main() {
loader = new TemplateLoader(xhr); loader = new TemplateLoader(xhr);
}); });
function createMetadata({inline = null, url = null}={}) {
var config = new TemplateConfig({url: url, inline: inline});
var component = new Component({template: config});
return new DirectiveMetadata(FakeComponent, component, null);
}
it('should load inline templates synchronously', () => { it('should load inline templates synchronously', () => {
var template = 'inline template'; var template = new Template({inline: 'inline template'});
var md = createMetadata({inline: template}); expect(loader.load(template).content).toHaveText('inline template');
expect(loader.load(md).content).toHaveText(template);
}); });
it('should load templates through XHR', (done) => { it('should load templates through XHR', (done) => {
var url = '/foo'; xhr.expect('/foo', 'xhr template');
var template = 'xhr template'; var template = new Template({url: '/foo'});
xhr.expect(url, template); loader.load(template).then((el) => {
var md = createMetadata({url: '/foo'}); expect(el.content).toHaveText('xhr template');
loader.load(md).then((el) => {
expect(el.content).toHaveText(template);
done(); done();
}); });
xhr.flush(); xhr.flush();
@ -43,34 +39,31 @@ export function main() {
it('should cache template loaded through XHR', (done) => { it('should cache template loaded through XHR', (done) => {
var firstEl; var firstEl;
var url = '/foo'; xhr.expect('/foo', 'xhr template');
var template = 'xhr template'; var template = new Template({url: '/foo'});
xhr.expect(url, template); loader.load(template)
var md = createMetadata({url: '/foo'});
loader.load(md)
.then((el) => { .then((el) => {
firstEl = el; firstEl = el;
return loader.load(md); return loader.load(template);
}) })
.then((el) =>{ .then((el) =>{
expect(el).toBe(firstEl); expect(el).toBe(firstEl);
expect(el.content).toHaveText(template); expect(el.content).toHaveText('xhr template');
done(); done();
}); });
xhr.flush(); xhr.flush();
}); });
it('should throw when no template is defined', () => { it('should throw when no template is defined', () => {
var md = createMetadata(); var template = new Template({inline: null, url: null});
expect(() => loader.load(md)) expect(() => loader.load(template))
.toThrowError('No template configured for component FakeComponent'); .toThrowError('Templates should have either their url or inline property set');
}); });
it('should return a rejected Promise when xhr loading fails', (done) => { it('should return a rejected Promise when xhr loading fails', (done) => {
var url = '/foo'; xhr.expect('/foo', null);
xhr.expect(url, null); var template = new Template({url: '/foo'});
var md = createMetadata({url: '/foo'}); PromiseWrapper.then(loader.load(template),
PromiseWrapper.then(loader.load(md),
function(_) { throw 'Unexpected response'; }, function(_) { throw 'Unexpected response'; },
function(error) { function(error) {
expect(error).toEqual('Failed to load /foo'); expect(error).toEqual('Failed to load /foo');
@ -83,5 +76,5 @@ export function main() {
}); });
} }
class FakeComponent { class SomeComponent {
} }

View File

@ -6,7 +6,7 @@ import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_meta
import {Component, Decorator, Viewport, Directive, onChange} from 'angular2/src/core/annotations/annotations'; import {Component, Decorator, Viewport, Directive, onChange} from 'angular2/src/core/annotations/annotations';
import {Lexer, Parser, DynamicProtoChangeDetector, import {Lexer, Parser, DynamicProtoChangeDetector,
ChangeDetector} from 'angular2/change_detection'; ChangeDetector} from 'angular2/change_detection';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {EventEmitter} from 'angular2/src/core/annotations/events'; import {EventEmitter} from 'angular2/src/core/annotations/events';
import {List, MapWrapper} from 'angular2/src/facade/collection'; import {List, MapWrapper} from 'angular2/src/facade/collection';
import {DOM, Element} from 'angular2/src/facade/dom'; import {DOM, Element} from 'angular2/src/facade/dom';
@ -649,9 +649,7 @@ class DirectiveImplementingOnChange {
class SomeService {} class SomeService {}
@Component({ @Component({componentServices: [SomeService]})
componentServices: [SomeService]
})
class SomeComponent { class SomeComponent {
service: SomeService; service: SomeService;
constructor(service: SomeService) { constructor(service: SomeService) {

View File

@ -1,6 +1,8 @@
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib'; import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib';
import {DOM} from 'angular2/src/facade/dom'; import {DOM} from 'angular2/src/facade/dom';
import {Map, MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {Type, isPresent} from 'angular2/src/facade/lang';
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection'; import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
@ -8,20 +10,23 @@ import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/ch
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations'; import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {ViewContainer} from 'angular2/src/core/compiler/view_container'; import {ViewContainer} from 'angular2/src/core/compiler/view_container';
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {Foreach} from 'angular2/src/directives/foreach'; import {Foreach} from 'angular2/src/directives/foreach';
export function main() { export function main() {
describe('foreach', () => { describe('foreach', () => {
var view, cd, compiler, component; var view, cd, compiler, component, tplResolver;
beforeEach(() => { beforeEach(() => {
compiler = new Compiler(dynamicChangeDetection, null, new DirectiveMetadataReader(), tplResolver = new FakeTemplateResolver();
new Parser(new Lexer()), new CompilerCache(), new NativeShadowDomStrategy()); compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
new NativeShadowDomStrategy(), tplResolver);
}); });
function createView(pv) { function createView(pv) {
@ -31,8 +36,13 @@ export function main() {
cd = view.changeDetector; cd = view.changeDetector;
} }
function compileWithTemplate(template) { function compileWithTemplate(html) {
return compiler.compile(TestComponent, el(template)); var template = new Template({
inline: html,
directives: [Foreach]
});
tplResolver.setTemplate(TestComponent, template);
return compiler.compile(TestComponent);
} }
var TEMPLATE = '<div><copy-me template="foreach #item in items">{{item.toString()}};</copy-me></div>'; var TEMPLATE = '<div><copy-me template="foreach #item in items">{{item.toString()}};</copy-me></div>';
@ -217,13 +227,7 @@ class Foo {
} }
} }
@Component({ @Component({selector: 'test-cmp'})
selector: 'test-cmp',
template: new TemplateConfig({
inline: '', // each test swaps with a custom template.
directives: [Foreach]
})
})
class TestComponent { class TestComponent {
items: any; items: any;
item: any; item: any;
@ -231,3 +235,26 @@ class TestComponent {
this.items = [1, 2]; this.items = [1, 2];
} }
} }
class FakeTemplateResolver extends TemplateResolver {
_cmpTemplates: Map;
constructor() {
super();
this._cmpTemplates = MapWrapper.create();
}
setTemplate(component: Type, template: Template) {
MapWrapper.set(this._cmpTemplates, component, template);
}
resolve(component: Type): Template {
var override = MapWrapper.get(this._cmpTemplates, component);
if (isPresent(override)) {
return override;
}
return super.resolve(component);
}
}

View File

@ -1,6 +1,8 @@
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el, IS_DARTIUM} from 'angular2/test_lib'; import {describe, xit, it, expect, beforeEach, ddescribe, iit, el, IS_DARTIUM} from 'angular2/test_lib';
import {DOM} from 'angular2/src/facade/dom'; import {DOM} from 'angular2/src/facade/dom';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {Type, isPresent} from 'angular2/src/facade/lang';
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection'; import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
@ -8,18 +10,23 @@ import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/ch
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {Component} from 'angular2/src/core/annotations/annotations'; import {Component} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {If} from 'angular2/src/directives/if'; import {If} from 'angular2/src/directives/if';
export function main() { export function main() {
describe('if directive', () => { describe('if directive', () => {
var view, cd, compiler, component; var view, cd, compiler, component, tplResolver;
beforeEach(() => { beforeEach(() => {
compiler = new Compiler(dynamicChangeDetection, null, new DirectiveMetadataReader(), tplResolver = new FakeTemplateResolver();
new Parser(new Lexer()), new CompilerCache(), new NativeShadowDomStrategy()); compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
new NativeShadowDomStrategy(), tplResolver);
}); });
function createView(pv) { function createView(pv) {
@ -29,8 +36,13 @@ export function main() {
cd = view.changeDetector; cd = view.changeDetector;
} }
function compileWithTemplate(template) { function compileWithTemplate(html) {
return compiler.compile(TestComponent, el(template)); var template = new Template({
inline: html,
directives: [If]
});
tplResolver.setTemplate(TestComponent, template);
return compiler.compile(TestComponent);
} }
it('should work in a template attribute', (done) => { it('should work in a template attribute', (done) => {
@ -188,13 +200,7 @@ export function main() {
}); });
} }
@Component({ @Component({selector: 'test-cmp'})
selector: 'test-cmp',
template: new TemplateConfig({
inline: '', // each test swaps with a custom template.
directives: [If]
})
})
class TestComponent { class TestComponent {
booleanCondition: boolean; booleanCondition: boolean;
numberCondition: number; numberCondition: number;
@ -213,3 +219,26 @@ class TestComponent {
this.nullCondition = null; this.nullCondition = null;
} }
} }
class FakeTemplateResolver extends TemplateResolver {
_cmpTemplates: Map;
constructor() {
super();
this._cmpTemplates = MapWrapper.create();
}
setTemplate(component: Type, template: Template) {
MapWrapper.set(this._cmpTemplates, component, template);
}
resolve(component: Type): Template {
var override = MapWrapper.get(this._cmpTemplates, component);
if (isPresent(override)) {
return override;
}
return super.resolve(component);
}
}

View File

@ -1,21 +1,27 @@
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib'; import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib';
import {DOM} from 'angular2/src/facade/dom'; import {DOM} from 'angular2/src/facade/dom';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {Type, isPresent} from 'angular2/src/facade/lang';
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection'; import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {Decorator, Component} from 'angular2/src/core/annotations/annotations'; import {Decorator, Component} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {NgElement} from 'angular2/src/core/dom/element'; import {NgElement} from 'angular2/src/core/dom/element';
import {NonBindable} from 'angular2/src/directives/non_bindable'; import {NonBindable} from 'angular2/src/directives/non_bindable';
export function main() { export function main() {
describe('non-bindable', () => { describe('non-bindable', () => {
var view, cd, compiler, component; var view, cd, compiler, component, tplResolver;
beforeEach(() => { beforeEach(() => {
compiler = new Compiler(dynamicChangeDetection, tplResolver = new FakeTemplateResolver();
null, new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(), new NativeShadowDomStrategy()); compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
new NativeShadowDomStrategy(), tplResolver);
}); });
function createView(pv) { function createView(pv) {
@ -25,8 +31,13 @@ export function main() {
cd = view.changeDetector; cd = view.changeDetector;
} }
function compileWithTemplate(template) { function compileWithTemplate(html) {
return compiler.compile(TestComponent, el(template)); var template = new Template({
inline: html,
directives: [NonBindable, TestDecorator]
});
tplResolver.setTemplate(TestComponent, template);
return compiler.compile(TestComponent);
} }
it('should not interpolate children', (done) => { it('should not interpolate children', (done) => {
@ -63,13 +74,7 @@ export function main() {
}) })
} }
@Component({ @Component({selector: 'test-cmp'})
selector: 'test-cmp',
template: new TemplateConfig({
inline: '', // each test swaps with a custom template.
directives: [NonBindable, TestDecorator]
})
})
class TestComponent { class TestComponent {
text: string; text: string;
constructor() { constructor() {
@ -85,3 +90,26 @@ class TestDecorator {
DOM.addClass(el.domElement, 'compiled'); DOM.addClass(el.domElement, 'compiled');
} }
} }
class FakeTemplateResolver extends TemplateResolver {
_cmpTemplates: Map;
constructor() {
super();
this._cmpTemplates = MapWrapper.create();
}
setTemplate(component: Type, template: Template) {
MapWrapper.set(this._cmpTemplates, component, template);
}
resolve(component: Type): Template {
var override = MapWrapper.get(this._cmpTemplates, component);
if (isPresent(override)) {
return override;
}
return super.resolve(component);
}
}

View File

@ -1,20 +1,26 @@
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib'; import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib';
import {DOM} from 'angular2/src/facade/dom'; import {DOM} from 'angular2/src/facade/dom';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {Type, isPresent} from 'angular2/src/facade/lang';
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection'; import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {Component} from 'angular2/src/core/annotations/annotations'; import {Component} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {TemplateLoader} from 'angular2/core';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {Switch, SwitchWhen, SwitchDefault} from 'angular2/src/directives/switch'; import {Switch, SwitchWhen, SwitchDefault} from 'angular2/src/directives/switch';
export function main() { export function main() {
describe('switch', () => { describe('switch', () => {
var view, cd, compiler, component; var view, cd, compiler, component, tplResolver;
beforeEach(() => { beforeEach(() => {
compiler = new Compiler(dynamicChangeDetection, null, new DirectiveMetadataReader(), tplResolver = new FakeTemplateResolver();
new Parser(new Lexer()), new CompilerCache(), new NativeShadowDomStrategy()); compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
new NativeShadowDomStrategy(), tplResolver);
}); });
function createView(pv) { function createView(pv) {
@ -24,8 +30,13 @@ export function main() {
cd = view.changeDetector; cd = view.changeDetector;
} }
function compileWithTemplate(template) { function compileWithTemplate(html) {
return compiler.compile(TestComponent, el(template)); var template = new Template({
inline: html,
directives: [Switch, SwitchWhen, SwitchDefault]
});
tplResolver.setTemplate(TestComponent, template);
return compiler.compile(TestComponent);
} }
describe('switch value changes', () => { describe('switch value changes', () => {
@ -143,13 +154,7 @@ export function main() {
}); });
} }
@Component({ @Component({selector: 'test-cmp'})
selector: 'test-cmp',
template: new TemplateConfig({
inline: '', // each test swaps with a custom template.
directives: [Switch, SwitchWhen, SwitchDefault]
})
})
class TestComponent { class TestComponent {
switchValue: any; switchValue: any;
when1: any; when1: any;
@ -161,3 +166,26 @@ class TestComponent {
this.when2 = null; this.when2 = null;
} }
} }
class FakeTemplateResolver extends TemplateResolver {
_cmpTemplates: Map;
constructor() {
super();
this._cmpTemplates = MapWrapper.create();
}
setTemplate(component: Type, template: Template) {
MapWrapper.set(this._cmpTemplates, component, template);
}
resolve(component: Type): Template {
var override = MapWrapper.get(this._cmpTemplates, component);
if (isPresent(override)) {
return override;
}
return super.resolve(component);
}
}

View File

@ -5,31 +5,44 @@ import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/ch
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {Injector} from 'angular2/di'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {DOM} from 'angular2/src/facade/dom'; import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {Component, Decorator, TemplateConfig} from 'angular2/core'; import {Injector} from 'angular2/di';
import {DOM} from 'angular2/src/facade/dom';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {Type, isPresent} from 'angular2/src/facade/lang';
import {Component, Decorator, Template} from 'angular2/core';
import {ControlGroupDirective, ControlNameDirective, import {ControlGroupDirective, ControlNameDirective,
ControlDirective, NewControlGroupDirective, ControlDirective, NewControlGroupDirective,
Control, ControlGroup, ControlValueAccessor} from 'angular2/forms'; Control, ControlGroup, ControlValueAccessor} from 'angular2/forms';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {XHRMock} from 'angular2/src/mock/xhr_mock';
export function main() { export function main() {
function detectChanges(view) { function detectChanges(view) {
view.changeDetector.detectChanges(); view.changeDetector.detectChanges();
} }
function compile(componentType, template, context, callback) { function compile(componentType, template, context, callback) {
var tplResolver = new FakeTemplateResolver();
var compiler = new Compiler(dynamicChangeDetection, var compiler = new Compiler(dynamicChangeDetection,
new TemplateLoader(new XHRMock()), new TemplateLoader(null),
new DirectiveMetadataReader(), new DirectiveMetadataReader(),
new Parser(new Lexer()), new Parser(new Lexer()),
new CompilerCache(), new CompilerCache(),
new NativeShadowDomStrategy()); new NativeShadowDomStrategy(),
tplResolver
);
compiler.compile(componentType, el(template)).then((pv) => { tplResolver.setTemplate(componentType, new Template({
inline: template,
directives: [ControlGroupDirective, ControlNameDirective, ControlDirective,
NewControlGroupDirective, WrappedValue]
}));
compiler.compile(componentType).then((pv) => {
var view = pv.instantiate(null, null); var view = pv.instantiate(null, null);
view.hydrate(new Injector([]), null, context); view.hydrate(new Injector([]), null, context);
detectChanges(view); detectChanges(view);
@ -198,14 +211,7 @@ export function main() {
}); });
} }
@Component({ @Component({selector: "my-comp"})
selector: "my-comp",
template: new TemplateConfig({
inline: "",
directives: [ControlGroupDirective, ControlNameDirective,
ControlDirective, NewControlGroupDirective, WrappedValue]
})
})
class MyComp { class MyComp {
form:ControlGroup; form:ControlGroup;
name:string; name:string;
@ -233,4 +239,27 @@ class WrappedValue {
constructor(cd:ControlNameDirective) { constructor(cd:ControlNameDirective) {
cd.valueAccessor = new WrappedValueAccessor(); cd.valueAccessor = new WrappedValueAccessor();
} }
} }
class FakeTemplateResolver extends TemplateResolver {
_cmpTemplates: Map;
constructor() {
super();
this._cmpTemplates = MapWrapper.create();
}
setTemplate(component: Type, template: Template) {
MapWrapper.set(this._cmpTemplates, component, template);
}
resolve(component: Type): Template {
var override = MapWrapper.get(this._cmpTemplates, component);
if (isPresent(override)) {
return override;
}
return super.resolve(component);
}
}

View File

@ -11,19 +11,18 @@ import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_meta
import {Component} from 'angular2/src/core/annotations/annotations'; import {Component} from 'angular2/src/core/annotations/annotations';
import {Decorator} from 'angular2/src/core/annotations/annotations'; import {Decorator} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config'; import {Template} from 'angular2/src/core/annotations/template';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util'; import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util';
import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl';
function setupReflector() { function setupReflector() {
reflector.registerType(BenchmarkComponent, { reflector.registerType(BenchmarkComponent, {
"factory": () => new BenchmarkComponent(), "factory": () => new BenchmarkComponent(),
"parameters": [], "parameters": [],
"annotations" : [new Component({template: new TemplateConfig({directives: [Dir0, Dir1, Dir2, Dir3, Dir4]})})] "annotations" : [new Component()]
}); });
reflector.registerType(Dir0, { reflector.registerType(Dir0, {
@ -83,37 +82,36 @@ export function main() {
setupReflector(); setupReflector();
var reader = new DirectiveMetadataReader(); var reader = new DirectiveMetadataReader();
var cache = new CompilerCache(); var cache = new CompilerCache();
var compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(new XHRImpl()), var templateResolver = new FakeTemplateResolver();
reader, new Parser(new Lexer()), cache, new NativeShadowDomStrategy()); var compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
var templateNoBindings = loadTemplate('templateNoBindings', count); reader, new Parser(new Lexer()), cache, new NativeShadowDomStrategy(), templateResolver);
var templateWithBindings = loadTemplate('templateWithBindings', count); var templateNoBindings = createTemplateHtml('templateNoBindings', count);
var templateWithBindings = createTemplateHtml('templateWithBindings', count);
function compileNoBindings() { function compileNoBindings() {
// Need to clone every time as the compiler might modify the template! templateResolver.setTemplateHtml(templateNoBindings);
var cloned = DOM.clone(templateNoBindings);
cache.clear(); cache.clear();
compiler.compile(BenchmarkComponent, cloned); compiler.compile(BenchmarkComponent);
} }
function compileWithBindings() { function compileWithBindings() {
// Need to clone every time as the compiler might modify the template! templateResolver.setTemplateHtml(templateWithBindings);
var cloned = DOM.clone(templateWithBindings);
cache.clear(); cache.clear();
compiler.compile(BenchmarkComponent, cloned); compiler.compile(BenchmarkComponent);
} }
bindAction('#compileNoBindings', compileNoBindings); bindAction('#compileNoBindings', compileNoBindings);
bindAction('#compileWithBindings', compileWithBindings); bindAction('#compileWithBindings', compileWithBindings);
} }
function loadTemplate(templateId, repeatCount) { function createTemplateHtml(templateId, repeatCount) {
var template = DOM.querySelectorAll(document, `#${templateId}`)[0]; var template = DOM.querySelectorAll(document, `#${templateId}`)[0];
var content = DOM.getInnerHTML(template); var content = DOM.getInnerHTML(template);
var result = ''; var result = '';
for (var i=0; i<repeatCount; i++) { for (var i=0; i<repeatCount; i++) {
result += content; result += content;
} }
return DOM.createTemplate(result); return result;
} }
@Decorator({ @Decorator({
@ -164,10 +162,24 @@ class Dir4 {
constructor(dir3:Dir3) {} constructor(dir3:Dir3) {}
} }
@Component({ @Component()
template: new TemplateConfig({
directives: [Dir0, Dir1, Dir2, Dir3, Dir4]
})
})
class BenchmarkComponent {} class BenchmarkComponent {}
class FakeTemplateResolver extends TemplateResolver {
_template: Template;
constructor() {
super();
}
setTemplateHtml(html: string) {
this._template = new Template({
inline: html,
directives: [Dir0, Dir1, Dir2, Dir3, Dir4]
});
}
resolve(component: Type): Template {
return this._template;
}
}

View File

@ -1,7 +1,7 @@
import {int, isPresent} from 'angular2/src/facade/lang'; import {int, isPresent} from 'angular2/src/facade/lang';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util'; import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util';
import {bootstrap, Component, Viewport, TemplateConfig, ViewContainer, Compiler} import {bootstrap, Component, Viewport, Template, ViewContainer, Compiler}
from 'angular2/angular2'; from 'angular2/angular2';
import {PromiseWrapper} from 'angular2/src/facade/async'; import {PromiseWrapper} from 'angular2/src/facade/async';
import {ListWrapper} from 'angular2/src/facade/collection'; import {ListWrapper} from 'angular2/src/facade/collection';
@ -83,26 +83,23 @@ export function setupReflectorForApp() {
'factory': () => { return new App(); }, 'factory': () => { return new App(); },
'parameters': [], 'parameters': [],
'annotations': [ 'annotations': [
new Component({ new Component({selector: 'scroll-app'}),
selector: 'scroll-app', new Template({
template: new TemplateConfig({ directives: [ScrollAreaComponent, If, Foreach],
directives: [ScrollAreaComponent, If, Foreach], inline: `
inline: ` <div>
<div> <div style="display: flex">
<div style="display: flex"> <scroll-area id="testArea"></scroll-area>
<scroll-area id="testArea"></scroll-area> <div style="padding-left: 20px">
<div style="padding-left: 20px"> <button id="run-btn">Run</button>
<button id="run-btn">Run</button> <button id="reset-btn">Reset</button>
<button id="reset-btn">Reset</button>
</div>
</div> </div>
<div template="if scrollAreas.length > 0"> </div>
<p>Following tables are only here to add weight to the UI:</p> <div template="if scrollAreas.length > 0">
<scroll-area template="foreach #scrollArea in scrollAreas"></scroll-area> <p>Following tables are only here to add weight to the UI:</p>
</div> <scroll-area template="foreach #scrollArea in scrollAreas"></scroll-area>
</div>` </div>
}) </div>`
}) })]
]
}); });
} }

View File

@ -1,7 +1,7 @@
import {int} from 'angular2/src/facade/lang'; import {int} from 'angular2/src/facade/lang';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util'; import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util';
import {bootstrap, Component, Viewport, TemplateConfig, ViewContainer, Compiler} import {bootstrap, Component, Viewport, Template, ViewContainer, Compiler}
from 'angular2/angular2'; from 'angular2/angular2';
import {PromiseWrapper} from 'angular2/src/facade/async'; import {PromiseWrapper} from 'angular2/src/facade/async';
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection'; import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
@ -103,14 +103,14 @@ export function setupReflectorForCells() {
'annotations': [ 'annotations': [
new Component({ new Component({
selector: 'company-name', selector: 'company-name',
template: new TemplateConfig({
directives: [],
inline: `<div [style]="style">{{company.name}}</div>`
}),
bind: { bind: {
'cell-width': 'width', 'cell-width': 'width',
'company': 'company' 'company': 'company'
} }
}),
new Template({
directives: [],
inline: `<div [style]="style">{{company.name}}</div>`
}) })
] ]
}); });
@ -121,14 +121,14 @@ export function setupReflectorForCells() {
'annotations': [ 'annotations': [
new Component({ new Component({
selector: 'opportunity-name', selector: 'opportunity-name',
template: new TemplateConfig({
directives: [],
inline: `<div [style]="style">{{opportunity.name}}</div>`
}),
bind: { bind: {
'cell-width': 'width', 'cell-width': 'width',
'opportunity': 'opportunity' 'opportunity': 'opportunity'
} }
}),
new Template({
directives: [],
inline: `<div [style]="style">{{opportunity.name}}</div>`
}) })
] ]
}); });
@ -139,14 +139,14 @@ export function setupReflectorForCells() {
'annotations': [ 'annotations': [
new Component({ new Component({
selector: 'offering-name', selector: 'offering-name',
template: new TemplateConfig({
directives: [],
inline: `<div [style]="style">{{offering.name}}</div>`
}),
bind: { bind: {
'cell-width': 'width', 'cell-width': 'width',
'offering': 'offering' 'offering': 'offering'
} }
}),
new Template({
directives: [],
inline: `<div [style]="style">{{offering.name}}</div>`
}) })
] ]
}); });
@ -157,22 +157,22 @@ export function setupReflectorForCells() {
'annotations': [ 'annotations': [
new Component({ new Component({
selector: 'stage-buttons', selector: 'stage-buttons',
template: new TemplateConfig({
directives: [Foreach],
inline: `
<div [style]="style">
<button template="foreach #stage in stages"
[disabled]="stage.isDisabled"
[style]="stage.style"
on-click="setStage(stage)">
{{stage.name}}
</button>
</div>`
}),
bind: { bind: {
'cell-width': 'width', 'cell-width': 'width',
'offering': 'offering' 'offering': 'offering'
} }
}),
new Template({
directives: [Foreach],
inline: `
<div [style]="style">
<button template="foreach #stage in stages"
[disabled]="stage.isDisabled"
[style]="stage.style"
on-click="setStage(stage)">
{{stage.name}}
</button>
</div>`
}) })
] ]
}); });
@ -183,19 +183,19 @@ export function setupReflectorForCells() {
'annotations': [ 'annotations': [
new Component({ new Component({
selector: 'account-cell', selector: 'account-cell',
template: new TemplateConfig({
directives: [],
inline: `
<div [style]="style">
<a href="/account/{{account.accountId}}">
{{account.accountId}}
</a>
</div>`
}),
bind: { bind: {
'cell-width': 'width', 'cell-width': 'width',
'account': 'account' 'account': 'account'
} }
}),
new Template({
directives: [],
inline: `
<div [style]="style">
<a href="/account/{{account.accountId}}">
{{account.accountId}}
</a>
</div>`
}) })
] ]
}); });
@ -206,14 +206,14 @@ export function setupReflectorForCells() {
'annotations': [ 'annotations': [
new Component({ new Component({
selector: 'formatted-cell', selector: 'formatted-cell',
template: new TemplateConfig({
directives: [],
inline: `<div [style]="style">{{formattedValue}}</div>`
}),
bind: { bind: {
'cell-width': 'width', 'cell-width': 'width',
'value': 'value' 'value': 'value'
} }
}),
new Template({
directives: [],
inline: `<div [style]="style">{{formattedValue}}</div>`
}) })
] ]
}); });

View File

@ -4,13 +4,14 @@ import {MapWrapper} from 'angular2/src/facade/collection';
import {Parser, Lexer, ChangeDetector, ChangeDetection} import {Parser, Lexer, ChangeDetector, ChangeDetection}
from 'angular2/change_detection'; from 'angular2/change_detection';
import {bootstrap, Component, Viewport, TemplateConfig, ViewContainer, Compiler} import {bootstrap, Component, Viewport, Template, ViewContainer, Compiler}
from 'angular2/angular2'; from 'angular2/angular2';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
import {CompilerCache} from 'angular2/src/core/compiler/compiler'; import {CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {XHR} from 'angular2/src/core/compiler/xhr/xhr'; import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl'; import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl';
@ -172,10 +173,12 @@ export function setupReflectorForAngular() {
}); });
reflector.registerType(Compiler, { reflector.registerType(Compiler, {
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy) => "factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy), resolver) =>
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
resolver),
"parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser], "parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser],
[CompilerCache], [ShadowDomStrategy]], [CompilerCache], [ShadowDomStrategy], [TemplateResolver]],
"annotations": [] "annotations": []
}); });
@ -197,6 +200,12 @@ export function setupReflectorForAngular() {
"annotations": [] "annotations": []
}); });
reflector.registerType(TemplateResolver, {
"factory": () => new TemplateResolver(),
"parameters": [],
"annotations": []
});
reflector.registerType(XHR, { reflector.registerType(XHR, {
"factory": () => new XHRImpl(), "factory": () => new XHRImpl(),
"parameters": [], "parameters": [],

View File

@ -1,7 +1,7 @@
import {int, FINAL} from 'angular2/src/facade/lang'; import {int, FINAL} from 'angular2/src/facade/lang';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util'; import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util';
import {Component, Viewport, TemplateConfig, ViewContainer, Compiler} import {Component, Viewport, Template, ViewContainer, Compiler}
from 'angular2/angular2'; from 'angular2/angular2';
import {PromiseWrapper} from 'angular2/src/facade/async'; import {PromiseWrapper} from 'angular2/src/facade/async';
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection'; import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
@ -67,23 +67,23 @@ export function setupReflectorForScrollArea() {
'annotations': [ 'annotations': [
new Component({ new Component({
selector: 'scroll-area', selector: 'scroll-area',
template: new TemplateConfig({ }),
directives: [ScrollItemComponent, Foreach], new Template({
inline: ` directives: [ScrollItemComponent, Foreach],
<div> inline: `
<div id="scrollDiv" <div>
[style]="scrollDivStyle" <div id="scrollDiv"
on-scroll="onScroll($event)"> [style]="scrollDivStyle"
<div id="padding"></div> on-scroll="onScroll($event)">
<div id="inner"> <div id="padding"></div>
<scroll-item <div id="inner">
template="foreach #item in visibleItems" <scroll-item
[offering]="item"> template="foreach #item in visibleItems"
</scroll-item> [offering]="item">
</div> </scroll-item>
</div> </div>
</div>` </div>
}) </div>`
}) })
] ]
}); });

View File

@ -1,6 +1,6 @@
import {int} from 'angular2/src/facade/lang'; import {int} from 'angular2/src/facade/lang';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
import {Component, Viewport, TemplateConfig, ViewContainer, Compiler} import {Component, Viewport, Template, ViewContainer, Compiler}
from 'angular2/angular2'; from 'angular2/angular2';
import {PromiseWrapper} from 'angular2/src/facade/async'; import {PromiseWrapper} from 'angular2/src/facade/async';
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection'; import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
@ -51,55 +51,55 @@ export function setupReflectorForScrollItem() {
'annotations': [ 'annotations': [
new Component({ new Component({
selector: 'scroll-item', selector: 'scroll-item',
template: new TemplateConfig({
directives: [
CompanyNameComponent,
OpportunityNameComponent,
OfferingNameComponent,
StageButtonsComponent,
AccountCellComponent,
FormattedCellComponent
],
inline: `
<div [style]="itemStyle">
<company-name [company]="offering.company"
[cell-width]="companyNameWidth">
</company-name>
<opportunity-name [opportunity]="offering.opportunity"
[cell-width]="opportunityNameWidth">
</opportunity-name>
<offering-name [offering]="offering"
[cell-width]="offeringNameWidth">
</offering-name>
<account-cell [account]="offering.account"
[cell-width]="accountCellWidth">
</account-cell>
<formatted-cell [value]="offering.basePoints"
[cell-width]="basePointsWidth">
</formatted-cell>
<formatted-cell [value]="offering.kickerPoints"
[cell-width]="kickerPointsWidth">
</formatted-cell>
<stage-buttons [offering]="offering"
[cell-width]="stageButtonsWidth">
</stage-buttons>
<formatted-cell [value]="offering.bundles"
[cell-width]="bundlesWidth">
</formatted-cell>
<formatted-cell [value]="offering.dueDate"
[cell-width]="dueDateWidth">
</formatted-cell>
<formatted-cell [value]="offering.endDate"
[cell-width]="endDateWidth">
</formatted-cell>
<formatted-cell [value]="offering.aatStatus"
[cell-width]="aatStatusWidth">
</formatted-cell>
</div>`
}),
bind: { bind: {
'offering': 'offering' 'offering': 'offering'
} }
}),
new Template({
directives: [
CompanyNameComponent,
OpportunityNameComponent,
OfferingNameComponent,
StageButtonsComponent,
AccountCellComponent,
FormattedCellComponent
],
inline: `
<div [style]="itemStyle">
<company-name [company]="offering.company"
[cell-width]="companyNameWidth">
</company-name>
<opportunity-name [opportunity]="offering.opportunity"
[cell-width]="opportunityNameWidth">
</opportunity-name>
<offering-name [offering]="offering"
[cell-width]="offeringNameWidth">
</offering-name>
<account-cell [account]="offering.account"
[cell-width]="accountCellWidth">
</account-cell>
<formatted-cell [value]="offering.basePoints"
[cell-width]="basePointsWidth">
</formatted-cell>
<formatted-cell [value]="offering.kickerPoints"
[cell-width]="kickerPointsWidth">
</formatted-cell>
<stage-buttons [offering]="offering"
[cell-width]="stageButtonsWidth">
</stage-buttons>
<formatted-cell [value]="offering.bundles"
[cell-width]="bundlesWidth">
</formatted-cell>
<formatted-cell [value]="offering.dueDate"
[cell-width]="dueDateWidth">
</formatted-cell>
<formatted-cell [value]="offering.endDate"
[cell-width]="endDateWidth">
</formatted-cell>
<formatted-cell [value]="offering.aatStatus"
[cell-width]="aatStatusWidth">
</formatted-cell>
</div>`
}) })
] ]
}); });

View File

@ -1,11 +1,12 @@
import {Parser, Lexer, ChangeDetector, ChangeDetection, jitChangeDetection} import {Parser, Lexer, ChangeDetector, ChangeDetection, jitChangeDetection}
from 'angular2/change_detection'; from 'angular2/change_detection';
import {bootstrap, Component, Viewport, TemplateConfig, ViewContainer, Compiler} from 'angular2/angular2'; import {bootstrap, Component, Viewport, Template, ViewContainer, Compiler} from 'angular2/angular2';
import {CompilerCache} from 'angular2/src/core/compiler/compiler'; import {CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
@ -24,28 +25,26 @@ function setupReflector() {
reflector.registerType(AppComponent, { reflector.registerType(AppComponent, {
'factory': () => new AppComponent(), 'factory': () => new AppComponent(),
'parameters': [], 'parameters': [],
'annotations' : [new Component({ 'annotations' : [
selector: 'app', new Component({selector: 'app'}),
template: new TemplateConfig({ new Template({
directives: [TreeComponent], directives: [TreeComponent],
inline: `<tree [data]='initData'></tree>` inline: `<tree [data]='initData'></tree>`
}) })]
})]
}); });
reflector.registerType(TreeComponent, { reflector.registerType(TreeComponent, {
'factory': () => new TreeComponent(), 'factory': () => new TreeComponent(),
'parameters': [], 'parameters': [],
'annotations' : [new Component({ 'annotations' : [
selector: 'tree', new Component({
bind: { selector: 'tree',
'data': 'data' bind: {'data': 'data'}
}, }),
template: new TemplateConfig({ new Template({
directives: [TreeComponent, NgIf], directives: [TreeComponent, NgIf],
inline: `<span> {{data.value}} <span template='ng-if data.right != null'><tree [data]='data.right'></tree></span><span template='ng-if data.left != null'><tree [data]='data.left'></tree></span></span>` inline: `<span> {{data.value}} <span template='ng-if data.right != null'><tree [data]='data.right'></tree></span><span template='ng-if data.left != null'><tree [data]='data.left'></tree></span></span>`
}) })]
})]
}); });
reflector.registerType(NgIf, { reflector.registerType(NgIf, {
@ -60,9 +59,10 @@ function setupReflector() {
}); });
reflector.registerType(Compiler, { reflector.registerType(Compiler, {
'factory': (cd, templateLoader, reader, parser, compilerCache, strategy) => new Compiler(cd, templateLoader, reader, parser, compilerCache, strategy), 'factory': (cd, templateLoader, reader, parser, compilerCache, strategy, resolver) =>
new Compiler(cd, templateLoader, reader, parser, compilerCache, strategy, resolver),
'parameters': [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], 'parameters': [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader],
[Parser], [CompilerCache], [ShadowDomStrategy]], [Parser], [CompilerCache], [ShadowDomStrategy], [TemplateResolver]],
'annotations': [] 'annotations': []
}); });
@ -84,6 +84,12 @@ function setupReflector() {
'annotations': [] 'annotations': []
}); });
reflector.registerType(TemplateResolver, {
'factory': () => new TemplateResolver(),
'parameters': [],
'annotations': []
});
reflector.registerType(XHR, { reflector.registerType(XHR, {
'factory': () => new XHRImpl(), 'factory': () => new XHRImpl(),
'parameters': [], 'parameters': [],

View File

@ -1,13 +1,9 @@
import {bootstrap, Component, TemplateConfig} from 'angular2/core'; import {bootstrap, Component, Template} from 'angular2/core';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
import {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabilities'; import {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabilities';
@Component({ @Component({selector: 'gestures-app'})
selector: 'gestures-app', @Template({url: 'template.html'})
template: new TemplateConfig({
url: 'template.html'
})
})
class GesturesCmp { class GesturesCmp {
swipeDirection: string; swipeDirection: string;
pinchScale: number; pinchScale: number;

View File

@ -1,4 +1,4 @@
import {bootstrap, Component, Decorator, TemplateConfig, NgElement} from 'angular2/angular2'; import {bootstrap, Component, Decorator, Template, NgElement} from 'angular2/angular2';
// Angular 2.0 supports 3 basic types of directives: // Angular 2.0 supports 3 basic types of directives:
// - Component - the basic building blocks of Angular 2.0 apps. Backed by // - Component - the basic building blocks of Angular 2.0 apps. Backed by
@ -15,19 +15,19 @@ import {bootstrap, Component, Decorator, TemplateConfig, NgElement} from 'angula
selector: 'hello-app', selector: 'hello-app',
// These are services that would be created if a class in the component's // These are services that would be created if a class in the component's
// template tries to inject them. // template tries to inject them.
componentServices: [GreetingService], componentServices: [GreetingService]
template: new TemplateConfig({ })
// The template for the component. // The template for the component.
// Expressions in the template (like {{greeting}}) are evaluated in the @Template({
// context of the HelloCmp class below. // Expressions in the template (like {{greeting}}) are evaluated in the
inline: `<div class="greeting">{{greeting}} <span red>world</span>!</div> // context of the HelloCmp class below.
<button class="changeButton" (click)="changeGreeting()">change greeting</button>`, inline: `<div class="greeting">{{greeting}} <span red>world</span>!</div>
// All directives used in the template need to be specified. This allows for <button class="changeButton" (click)="changeGreeting()">change greeting</button>`,
// modularity (RedDec can only be used in this template) // All directives used in the template need to be specified. This allows for
// and better tooling (the template can be invalidated if the attribute is // modularity (RedDec can only be used in this template)
// misspelled). // and better tooling (the template can be invalidated if the attribute is
directives: [RedDec] // misspelled).
}) directives: [RedDec]
}) })
class HelloCmp { class HelloCmp {
greeting: string; greeting: string;

View File

@ -1,6 +1,6 @@
import * as app from './index_common'; import * as app from './index_common';
import {Component, Decorator, TemplateConfig, NgElement} from 'angular2/angular2'; import {Component, Decorator, Template, NgElement} from 'angular2/angular2';
import {Lexer, Parser, ChangeDetection, ChangeDetector} from 'angular2/change_detection'; import {Lexer, Parser, ChangeDetection, ChangeDetector} from 'angular2/change_detection';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
@ -8,6 +8,7 @@ import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {XHR} from 'angular2/src/core/compiler/xhr/xhr'; import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl'; import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl';
@ -17,14 +18,16 @@ function setup() {
reflector.registerType(app.HelloCmp, { reflector.registerType(app.HelloCmp, {
"factory": (service) => new app.HelloCmp(service), "factory": (service) => new app.HelloCmp(service),
"parameters": [[app.GreetingService]], "parameters": [[app.GreetingService]],
"annotations" : [new Component({ "annotations" : [
selector: 'hello-app', new Component({
componentServices: [app.GreetingService], selector: 'hello-app',
template: new TemplateConfig({ componentServices: [app.GreetingService]
}),
new Template({
directives: [app.RedDec], directives: [app.RedDec],
inline: `<div class="greeting">{{greeting}} <span red>world</span>!</div> inline: `<div class="greeting">{{greeting}} <span red>world</span>!</div>
<button class="changeButton" (click)="changeGreeting()">change greeting</button>`}) <button class="changeButton" (click)="changeGreeting()">change greeting</button>`
})] })]
}); });
reflector.registerType(app.RedDec, { reflector.registerType(app.RedDec, {
@ -40,10 +43,12 @@ function setup() {
}); });
reflector.registerType(Compiler, { reflector.registerType(Compiler, {
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy) => "factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy), resolver) =>
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
resolver),
"parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser], "parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser],
[CompilerCache], [ShadowDomStrategy]], [CompilerCache], [ShadowDomStrategy], [TemplateResolver]],
"annotations": [] "annotations": []
}); });
@ -65,6 +70,12 @@ function setup() {
"annotations": [] "annotations": []
}); });
reflector.registerType(TemplateResolver, {
"factory": () => new TemplateResolver(),
"parameters": [],
"annotations": []
});
reflector.registerType(XHR, { reflector.registerType(XHR, {
"factory": () => new XHRImpl(), "factory": () => new XHRImpl(),
"parameters": [], "parameters": [],