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/visibility';
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/compiler/compiler';

View File

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

View File

@ -1,25 +1,31 @@
import {ABSTRACT, CONST, Type} from 'angular2/src/facade/lang';
import {List} from 'angular2/src/facade/collection';
export class TemplateConfig {
export class Template {
url:any; //string;
inline:any; //string;
directives:any; //List<Type>;
formatters:any; //List<Type>;
source:any;//List<TemplateConfig>;
source:any;//List<Template>;
locale:any; //string
device:any; //string
@CONST()
constructor({
url,
inline,
directives,
formatters,
source
source,
locale,
device
}: {
url: string,
inline: string,
directives: List<Type>,
formatters: List<Type>,
source: List<TemplateConfig>
source: List<Template>,
locale: string,
device: string
})
{
this.url = url;
@ -27,5 +33,7 @@ export class TemplateConfig {
this.directives = directives;
this.formatters = formatters;
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 {Parser, Lexer, ChangeDetection, dynamicChangeDetection, jitChangeDetection} from 'angular2/change_detection';
import {TemplateLoader} from './compiler/template_loader';
import {TemplateResolver} from './compiler/template_resolver';
import {DirectiveMetadataReader} from './compiler/directive_metadata_reader';
import {DirectiveMetadata} from './compiler/directive_metadata';
import {List, ListWrapper} from 'angular2/src/facade/collection';
@ -28,6 +29,7 @@ var _rootBindings = [
Compiler,
CompilerCache,
TemplateLoader,
TemplateResolver,
DirectiveMetadataReader,
Parser,
Lexer,
@ -62,7 +64,7 @@ function _injectorBindings(appComponentType): List<Binding> {
bind(appViewToken).toAsyncFactory((changeDetection, compiler, injector, appElement,
appComponentAnnotatedType, strategy, eventManager) => {
return compiler.compile(appComponentAnnotatedType.type, null).then(
return compiler.compile(appComponentAnnotatedType.type).then(
(protoView) => {
var appProtoView = ProtoView.createRootProtoView(protoView, appElement,
appComponentAnnotatedType, changeDetection.createProtoChangeDetector('root'),

View File

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

View File

@ -1,9 +1,7 @@
import {Type, isPresent, BaseException, stringify} from 'angular2/src/facade/lang';
import {List, ListWrapper} from 'angular2/src/facade/collection';
import {Directive, Component} from '../annotations/annotations';
import {Directive} from '../annotations/annotations';
import {DirectiveMetadata} from './directive_metadata';
import {reflector} from 'angular2/src/reflection/reflection';
import {ShadowDom, ShadowDomStrategy, ShadowDomNative} from './shadow_dom_strategy';
export class DirectiveMetadataReader {
read(type:Type):DirectiveMetadata {
@ -12,39 +10,12 @@ export class DirectiveMetadataReader {
for (var i=0; i<annotations.length; i++) {
var annotation = annotations[i];
if (annotation instanceof Component) {
return new DirectiveMetadata(
type,
annotation,
this.componentDirectivesMetadata(annotation)
);
}
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)}`);
}
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 {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 {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 {Template} from 'angular2/src/core/annotations/template';
/**
* Strategy to load component templates.
*/
@ -23,16 +20,13 @@ export class TemplateLoader {
}
// TODO(vicb): union type: return an Element or a Promise<Element>
load(cmpMetadata: DirectiveMetadata) {
var annotation:Component = cmpMetadata.annotation;
var tplConfig:TemplateConfig = annotation.template;
if (isPresent(tplConfig.inline)) {
return DOM.createTemplate(tplConfig.inline);
load(template: Template) {
if (isPresent(template.inline)) {
return DOM.createTemplate(template.inline);
}
if (isPresent(tplConfig.url)) {
var url = tplConfig.url;
if (isPresent(template.url)) {
var url = template.url;
var promise = StringMapWrapper.get(this._cache, url);
if (isBlank(promise)) {
@ -46,6 +40,6 @@ export class TemplateLoader {
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 {isBlank, isPresent, CONST} from 'angular2/src/facade/lang';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
@ -164,11 +164,9 @@ export class ControlGroupDirective extends ControlGroupDirectiveBase {
selector: '[new-control-group]',
bind: {
'new-control-group' : 'initData'
},
template: new TemplateConfig({
inline: '<content>'
})
}
})
@Template({inline: '<content>'})
export class NewControlGroupDirective extends ControlGroupDirectiveBase {
_initData:any;
_controlGroup:ControlGroup;

View File

@ -6,16 +6,11 @@ import {DOM} from 'angular2/src/facade/dom';
import {ListWrapper} from 'angular2/src/facade/collection';
import {PromiseWrapper} from 'angular2/src/facade/async';
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';
@Component({
selector: 'hello-app',
template: new TemplateConfig({
inline: '{{greeting}} world!',
directives: []
})
})
@Component({selector: 'hello-app'})
@Template({inline: '{{greeting}} world!'})
class HelloRootCmp {
greeting:string;
constructor() {
@ -23,13 +18,8 @@ class HelloRootCmp {
}
}
@Component({
selector: 'hello-app-2',
template: new TemplateConfig({
inline: '{{greeting}} world, again!',
directives: []
})
})
@Component({selector: 'hello-app-2'})
@Template({inline: '{{greeting}} world, again!'})
class HelloRootCmp2 {
greeting:string;
constructor() {
@ -37,13 +27,8 @@ class HelloRootCmp2 {
}
}
@Component({
selector: 'hello-app',
template: new TemplateConfig({
inline: '',
directives: []
})
})
@Component({selector: 'hello-app'})
@Template({inline: ''})
class HelloRootCmp3 {
appBinding;
@ -52,13 +37,8 @@ class HelloRootCmp3 {
}
}
@Component({
selector: 'hello-app',
template: new TemplateConfig({
inline: '',
directives: []
})
})
@Component({selector: 'hello-app'})
@Template({inline: ''})
class HelloRootCmp4 {
lc;

View File

@ -1,7 +1,8 @@
import {describe, beforeEach, it, expect, ddescribe, iit, el, IS_DARTIUM} from 'angular2/test_lib';
import {DOM, Element, TemplateElement} from 'angular2/src/facade/dom';
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 {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 {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
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 {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step'
import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control';
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 {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {XHRMock} from 'angular2/src/mock/xhr_mock';
export function main() {
describe('compiler', function() {
var reader;
beforeEach( () => {
reader = new DirectiveMetadataReader();
});
var syncTemplateLoader = new FakeTemplateLoader();
syncTemplateLoader.forceSync();
var asyncTemplateLoader = new FakeTemplateLoader();
asyncTemplateLoader.forceAsync();
StringMapWrapper.forEach({
'(sync TemplateLoader)': syncTemplateLoader,
'(async TemplateLoader)': asyncTemplateLoader
}, (templateLoader, name) => {
'(sync TemplateLoader)': true,
'(async TemplateLoader)': false
}, (sync, name) => {
var reader, tplResolver;
beforeEach(() => {
reader = new DirectiveMetadataReader();
tplResolver = new FakeTemplateResolver();
if (sync) {
tplResolver.forceSync();
} else {
tplResolver.forceAsync();
}
});
describe(name, () => {
function createCompiler(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) => {
@ -49,43 +50,35 @@ export function main() {
var compiler = createCompiler( (parent, current, control) => {
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);
done();
});
});
it('should use the given element', (done) => {
var element = el('<div></div>');
it('should use the inline template', (done) => {
var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null);
});
compiler.compile(MainComponent, element).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) => {
compiler.compile(MainComponent).then( (protoView) => {
expect(DOM.getInnerHTML(protoView.element)).toEqual('inline component');
done();
});
});
it('should load nested components', (done) => {
var mainEl = el('<div></div>');
var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null);
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
if (current.element === mainEl) {
if (DOM.hasClass(current.element, 'nested')) {
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;
expect(DOM.getInnerHTML(nestedView.element)).toEqual('nested component');
done();
@ -93,14 +86,14 @@ export function main() {
});
it('should cache compiled components', (done) => {
var element = el('<div></div>');
var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null);
});
var firstProtoView;
compiler.compile(MainComponent, element).then( (protoView) => {
tplResolver.setTemplate(MainComponent, new Template({inline: '<div></div>'}));
compiler.compile(MainComponent).then( (protoView) => {
firstProtoView = protoView;
return compiler.compile(MainComponent, element);
return compiler.compile(MainComponent);
}).then( (protoView) => {
expect(firstProtoView).toBe(protoView);
done();
@ -109,7 +102,6 @@ export function main() {
it('should re-use components being compiled', (done) => {
var nestedElBinders = [];
var mainEl = el('<div><div class="nested"></div><div class="nested"></div></div>');
var compiler = createCompiler( (parent, current, control) => {
if (DOM.hasClass(current.element, 'nested')) {
current.inheritedProtoView = new ProtoView(current.element, null, null);
@ -118,7 +110,9 @@ export function main() {
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);
done();
});
@ -130,7 +124,7 @@ export function main() {
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
current.componentDirective = reader.read(RecursiveComponent);
});
compiler.compile(RecursiveComponent, null).then( (protoView) => {
compiler.compile(RecursiveComponent).then( (protoView) => {
expect(protoView.elementBinders[0].nestedProtoView).toBe(protoView);
done();
});
@ -139,12 +133,14 @@ export function main() {
});
describe('(mixed async, sync TemplateLoader)', () => {
function createCompiler(processClosure, templateLoader: TemplateLoader) {
var reader = new DirectiveMetadataReader();
function createCompiler(processClosure, resolver: TemplateResolver) {
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) => {
var compiler = createCompiler((parent, current, control) => {
@ -155,7 +151,7 @@ export function main() {
} else {
current.inheritedProtoView = new ProtoView(current.element, null, null);
}
}, loader);
}, resolver);
PromiseWrapper.then(compiler.compile(ParentComponent),
function(protoView) {
@ -172,89 +168,77 @@ export function main() {
});
}
var loader = new FakeTemplateLoader();
loader.setSync(ParentComponent);
loader.setSync(NestedComponent);
createNestedComponentSpec('(sync -> sync)', loader);
var resolver = new FakeTemplateResolver();
resolver.setSync(ParentComponent);
resolver.setSync(NestedComponent);
createNestedComponentSpec('(sync -> sync)', resolver);
loader = new FakeTemplateLoader();
loader.setAsync(ParentComponent);
loader.setSync(NestedComponent);
createNestedComponentSpec('(async -> sync)', loader);
resolver = new FakeTemplateResolver();
resolver.setAsync(ParentComponent);
resolver.setSync(NestedComponent);
createNestedComponentSpec('(async -> sync)', resolver);
loader = new FakeTemplateLoader();
loader.setSync(ParentComponent);
loader.setAsync(NestedComponent);
createNestedComponentSpec('(sync -> async)', loader);
resolver = new FakeTemplateResolver();
resolver.setSync(ParentComponent);
resolver.setAsync(NestedComponent);
createNestedComponentSpec('(sync -> async)', resolver);
loader = new FakeTemplateLoader();
loader.setAsync(ParentComponent);
loader.setAsync(NestedComponent);
createNestedComponentSpec('(async -> async)', loader);
resolver = new FakeTemplateResolver();
resolver.setAsync(ParentComponent);
resolver.setAsync(NestedComponent);
createNestedComponentSpec('(async -> async)', resolver);
loader = new FakeTemplateLoader();
loader.setError(ParentComponent);
loader.setSync(NestedComponent);
createNestedComponentSpec('(error -> sync)', loader,
resolver = new FakeTemplateResolver();
resolver.setError(ParentComponent);
resolver.setSync(NestedComponent);
createNestedComponentSpec('(error -> sync)', resolver,
'Failed to load the template for ParentComponent');
// 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
//loader = new FakeTemplateLoader();
//loader.setSync(ParentComponent);
//loader.setError(NestedComponent);
//createNestedComponentSpec('(sync -> error)', loader,
//resolver = new FakeTemplateResolver();
//resolver.setSync(ParentComponent);
//resolver.setError(NestedComponent);
//createNestedComponentSpec('(sync -> error)', resolver,
// 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent');
//
//loader = new FakeTemplateLoader();
//loader.setAsync(ParentComponent);
//loader.setError(NestedComponent);
//createNestedComponentSpec('(async -> error)', loader,
//resolver = new FakeTemplateResolver();
//resolver.setAsync(ParentComponent);
//resolver.setError(NestedComponent);
//createNestedComponentSpec('(async -> error)', resolver,
// 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent');
});
});
}
@Component({
template: new TemplateConfig({
inline: '<div class="parent"></div>'
})
})
@Component()
@Template({inline: '<div class="parent"></div>'})
class ParentComponent {}
@Component({
template: new TemplateConfig({
inline: 'inline component'
})
})
@Component()
@Template({inline: 'inline component'})
class MainComponent {}
@Component({
template: new TemplateConfig({
inline: 'nested component'
})
})
@Component()
@Template({inline: 'nested component'})
class NestedComponent {}
@Component({
template: new TemplateConfig({
inline: '<div rec-comp></div>'
}),
selector: 'rec-comp'
})
@Component({selector: 'rec-comp'})
@Template({inline: '<div rec-comp></div>'})
class RecursiveComponent {}
class TestableCompiler extends Compiler {
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(),
new NativeShadowDomStrategy());
new NativeShadowDomStrategy(), resolver);
this.steps = steps;
}
createSteps(component):List<CompileStep> {
createSteps(component:Type, template: Template):List<CompileStep> {
return this.steps;
}
}
@ -271,19 +255,70 @@ class MockStep extends CompileStep {
}
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;
_forceAsync: boolean;
_cmpTemplates: Map;
_syncCmp: List<Type>;
_asyncCmp: List<Type>;
_errorCmp: List<Type>;
constructor() {
super (new XHRMock());
super();
this._forceSync = false;
this._forceAsync = false;
this._syncCmp = [];
this._asyncCmp = [];
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() {
@ -308,31 +343,7 @@ class FakeTemplateLoader extends TemplateLoader {
ListWrapper.push(this._errorCmp, component);
}
load(cmpMetadata: DirectiveMetadata) {
var annotation:Component = cmpMetadata.annotation;
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)}`;
setTemplate(component: Type, template: Template) {
MapWrapper.set(this._cmpTemplates, component, template);
}
}

View File

@ -1,43 +1,25 @@
import {ddescribe, describe, it, iit, expect, beforeEach} from 'angular2/test_lib';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {Decorator, Component} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
import {Template} from 'angular2/src/core/annotations/template';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {CONST} from 'angular2/src/facade/lang';
import {If, Foreach} from 'angular2/directives';
@Decorator({
selector: 'someSelector'
})
class SomeDirective {
}
@Decorator({selector: 'someDecorator'})
class SomeDecorator {}
@Component({selector: 'someComponent'})
class SomeComponent {}
@Viewport({selector: 'someViewport'})
class SomeViewport {}
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() {
describe("DirectiveMetadataReader", () => {
var reader;
@ -46,10 +28,22 @@ export function main() {
reader = new DirectiveMetadataReader();
});
it('should read out the annotation', () => {
var directiveMetadata = reader.read(SomeDirective);
it('should read out the Decorator annotation', () => {
var directiveMetadata = reader.read(SomeDecorator);
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', () => {
@ -57,22 +51,5 @@ export function main() {
reader.read(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 {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 {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 {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 {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config';
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 {MapWrapper} from 'angular2/src/facade/collection';
import {XHRMock} from 'angular2/src/mock/xhr_mock';
export function main() {
describe('integration tests', function() {
var compiler;
var compiler, tplResolver;
beforeEach( () => {
tplResolver = new FakeTemplateResolver();
compiler = new Compiler(dynamicChangeDetection,
new TemplateLoader(new XHRMock()),
new TemplateLoader(null),
new DirectiveMetadataReader(),
new Parser(new Lexer()),
new CompilerCache(),
new NativeShadowDomStrategy()
new NativeShadowDomStrategy(),
tplResolver
);
});
@ -43,7 +45,9 @@ export function main() {
}
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);
ctx.ctxProp = 'Hello World!';
@ -54,7 +58,9 @@ export function main() {
});
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);
ctx.ctxProp = 'Hello World!';
@ -73,7 +79,9 @@ export function main() {
'<div my-dir elprop="Hi {{\'there!\'}}"></div>' +
'<div my-dir elprop="One more {{ctxProp}}"></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);
ctx.ctxProp = 'Hello World!';
@ -88,7 +96,12 @@ export function main() {
});
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);
cd.detectChanges();
@ -100,7 +113,13 @@ export function main() {
// GH issue 328 - https://github.com/angular/angular/issues/328
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);
ctx.ctxProp = 'Hello World!';
@ -115,7 +134,13 @@ export function main() {
});
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);
cd.detectChanges();
@ -130,7 +155,12 @@ export function main() {
});
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);
cd.detectChanges();
@ -145,7 +175,12 @@ export function main() {
});
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);
expect(view.contextWithLocals).not.toBe(null);
@ -156,9 +191,12 @@ export function main() {
});
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);
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) => {
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);
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) => {
// How is this supposed to work?
var element = el('<p></p>');
var div = el('<div var-alice></div>');
DOM.appendChild(div, el('<i>Hello</i>'));
DOM.appendChild(element, div);
tplResolver.setTemplate(MyComp,
new Template({inline: '<p><div var-alice><i>Hello</i></div></p>'}));
compiler.compile(MyComp, element).then((pv) => {
compiler.compile(MyComp).then((pv) => {
createView(pv);
expect(view.contextWithLocals).not.toBe(null);
@ -201,7 +241,12 @@ export function main() {
});
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);
var cmp = view.contextWithLocals.get('cmp');
@ -234,12 +279,8 @@ class MyDir {
}
}
@Component({
selector: 'push-cmp',
template: new TemplateConfig({
inline: '{{field}}'
})
})
@Component({selector: 'push-cmp'})
@Template({inline: '{{field}}'})
class PushBasedComp {
numberOfChecks:number;
bpc:BindingPropagationConfig;
@ -260,11 +301,7 @@ class PushBasedComp {
}
}
@Component({
template: new TemplateConfig({
directives: [MyDir, [[ChildComp], SomeViewport, PushBasedComp]]
})
})
@Component()
class MyComp {
ctxProp:string;
constructor() {
@ -274,11 +311,11 @@ class MyComp {
@Component({
selector: 'child-cmp',
componentServices: [MyService],
template: new TemplateConfig({
directives: [MyDir],
inline: '{{ctxProp}}'
})
componentServices: [MyService]
})
@Template({
directives: [MyDir],
inline: '{{ctxProp}}'
})
class ChildComp {
ctxProp:string;
@ -290,7 +327,7 @@ class ChildComp {
}
@Viewport({
selector: '[some-tmplate]'
selector: '[some-viewport]'
})
class SomeViewport {
constructor(container: ViewContainer) {
@ -305,3 +342,26 @@ class MyService {
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 {NativeShadowDomStrategy, ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
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 {Lexer, Parser} from 'angular2/change_detection';
@ -235,19 +235,14 @@ class SomeViewport {}
})
class SomeViewport2 {}
@Component({
selector: '[some-comp]'
})
@Component({selector: '[some-comp]'})
class SomeComponent {}
@Component({
selector: '[some-comp2]'
})
@Component({selector: '[some-comp2]'})
class SomeComponent2 {}
@Component({
template: new TemplateConfig({
@Component()
@Template({
directives: [SomeDecorator, SomeViewport, SomeViewport2, SomeComponent, SomeComponent2]
})
})
class MyComp {}

View File

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

View File

@ -14,7 +14,7 @@ export function main() {
describe('ShadowDomTransformer', () => {
function createPipeline(selector, strategy:ShadowDomStrategy, styleHost) {
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);
transformer.clearCache();
return new CompilePipeline([transformer]);

View File

@ -1,6 +1,8 @@
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib';
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 {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
@ -12,14 +14,12 @@ import {ShadowDomStrategy,
NativeShadowDomStrategy,
EmulatedShadowDomStrategy} 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 {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 {StringMapWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {XHRMock} from 'angular2/src/mock/xhr_mock';
export function main() {
describe('integration tests', function() {
@ -31,22 +31,28 @@ export function main() {
(strategy, name) => {
describe(`${name} shadow dom strategy`, () => {
var compiler;
var compiler, tplResolver;
beforeEach( () => {
beforeEach(() => {
tplResolver = new FakeTemplateResolver();
compiler = new Compiler(dynamicChangeDetection,
new TemplateLoader(new XHRMock()),
new TemplateLoader(null),
new DirectiveMetadataReader(),
new Parser(new Lexer()),
new CompilerCache(),
strategy
strategy,
tplResolver
);
});
function compile(template, assertions) {
compiler.compile(MyComp, el(template)).
then(createView).
then((view) => {
function compile(template, directives: List<Type>, assertions) {
tplResolver.setTemplate(MyComp, new Template({
inline: template,
directives: directives
}));
compiler.compile(MyComp)
.then(createView)
.then((view) => {
var lc = new LifeCycle(view.changeDetector, false);
assertions(view, lc);
});
@ -59,7 +65,7 @@ export function main() {
'<div class="left">A</div>' +
'</multiple-content-tags>';
compile(temp, (view, lc) => {
compile(temp, [MultipleContentTagsComponent], (view, lc) => {
expect(view.nodes).toHaveText('(A, BC)');
done();
});
@ -71,7 +77,7 @@ export function main() {
'<div>C</div>' +
'</multiple-content-tags>';
compile(temp, (view, lc) => {
compile(temp, [MultipleContentTagsComponent], (view, lc) => {
expect(view.nodes).toHaveText('(, BAC)');
done();
});
@ -83,7 +89,7 @@ export function main() {
'<div>B</div>' +
'</multiple-content-tags>';
compile(temp, (view, lc) => {
compile(temp, [MultipleContentTagsComponent, ManualViewportDirective], (view, lc) => {
var dir = view.elementInjectors[1].get(ManualViewportDirective);
expect(view.nodes).toHaveText('(, B)');
@ -108,7 +114,7 @@ export function main() {
'<div>B</div>' +
'</multiple-content-tags>';
compile(temp, (view, lc) => {
compile(temp, [MultipleContentTagsComponent, ManualViewportDirective], (view, lc) => {
var dir = view.elementInjectors[1].get(ManualViewportDirective);
expect(view.nodes).toHaveText('(, B)');
@ -133,7 +139,7 @@ export function main() {
'<div>B</div>' +
'</outer-with-indirect-nested>';
compile(temp, (view, lc) => {
compile(temp, [OuterWithIndirectNestedComponent], (view, lc) => {
expect(view.nodes).toHaveText('OUTER(SIMPLE(AB))');
done();
@ -147,7 +153,7 @@ export function main() {
'<div>C</div>' +
'</outer>';
compile(temp, (view, lc) => {
compile(temp, [OuterComponent, ManualViewportDirective], (view, lc) => {
var dir = view.elementInjectors[1].get(ManualViewportDirective);
expect(view.nodes).toHaveText('OUTER(INNER(INNERINNER(,BC)))');
@ -257,31 +263,23 @@ class AutoViewportDirective {
}
}
@Component({
selector: 'simple',
template: new TemplateConfig({
inline: 'SIMPLE(<content></content>)'
})
})
@Component({selector: 'simple'})
@Template({inline: 'SIMPLE(<content></content>)'})
class Simple {
}
@Component({
selector: 'multiple-content-tags',
template: new TemplateConfig({
inline: '(<content select=".left"></content>, <content></content>)'
})
@Component({selector: 'multiple-content-tags'})
@Template({
inline: '(<content select=".left"></content>, <content></content>)'
})
class MultipleContentTagsComponent {
}
@Component({
selector: 'conditional-content',
template: new TemplateConfig({
inline: '<div>(<div template="auto: cond"><content select=".left"></content></div>, <content></content>)</div>',
directives: [AutoViewportDirective]
})
@Component({selector: 'conditional-content'})
@Template({
inline: '<div>(<div template="auto: cond"><content select=".left"></content></div>, <content></content>)</div>',
directives: [AutoViewportDirective]
})
class ConditionalContentComponent {
cond:boolean;
@ -294,52 +292,42 @@ class ConditionalContentComponent {
hideLeft() { this.cond = false; }
}
@Component({
selector: 'outer-with-indirect-nested',
template: new TemplateConfig({
inline: 'OUTER(<simple><div><content></content></div></simple>)',
directives: [Simple]
})
@Component({selector: 'outer-with-indirect-nested'})
@Template({
inline: 'OUTER(<simple><div><content></content></div></simple>)',
directives: [Simple]
})
class OuterWithIndirectNestedComponent {
}
@Component({
selector: 'outer',
template: new TemplateConfig({
inline: 'OUTER(<inner><content></content></inner>)',
directives: [InnerComponent]
})
@Component({selector: 'outer'})
@Template({
inline: 'OUTER(<inner><content></content></inner>)',
directives: [InnerComponent]
})
class OuterComponent {
}
@Component({
selector: 'inner',
template: new TemplateConfig({
inline: 'INNER(<innerinner><content></content></innerinner>)',
directives: [InnerInnerComponent]
})
@Component({selector: 'inner'})
@Template({
inline: 'INNER(<innerinner><content></content></innerinner>)',
directives: [InnerInnerComponent]
})
class InnerComponent {
}
@Component({
selector: 'innerinner',
template: new TemplateConfig({
inline: 'INNERINNER(<content select=".left"></content>,<content></content>)'
})
@Component({selector: 'innerinner'})
@Template({
inline: 'INNERINNER(<content select=".left"></content>,<content></content>)'
})
class InnerInnerComponent {
}
@Component({
selector: 'my-comp',
template: new TemplateConfig({
directives: [MultipleContentTagsComponent, ManualViewportDirective,
ConditionalContentComponent, OuterWithIndirectNestedComponent, OuterComponent]
})
@Component({selector: 'my-comp'})
@Template({
directives: [MultipleContentTagsComponent, ManualViewportDirective,
ConditionalContentComponent, OuterWithIndirectNestedComponent, OuterComponent]
})
class MyComp {
}
@ -349,3 +337,26 @@ function createView(pv) {
view.hydrate(new Injector([]), null, {});
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 {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {Component} from 'angular2/src/core/annotations/annotations';
import {TemplateConfig} from 'angular2/src/core/annotations/template_config';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
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 {Type, stringify, isPresent} from 'angular2/src/facade/lang';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {XHRMock} from 'angular2/src/mock/xhr_mock';
@ -17,25 +22,16 @@ export function main() {
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', () => {
var template = 'inline template';
var md = createMetadata({inline: template});
expect(loader.load(md).content).toHaveText(template);
var template = new Template({inline: 'inline template'});
expect(loader.load(template).content).toHaveText('inline template');
});
it('should load templates through XHR', (done) => {
var url = '/foo';
var template = 'xhr template';
xhr.expect(url, template);
var md = createMetadata({url: '/foo'});
loader.load(md).then((el) => {
expect(el.content).toHaveText(template);
xhr.expect('/foo', 'xhr template');
var template = new Template({url: '/foo'});
loader.load(template).then((el) => {
expect(el.content).toHaveText('xhr template');
done();
});
xhr.flush();
@ -43,34 +39,31 @@ export function main() {
it('should cache template loaded through XHR', (done) => {
var firstEl;
var url = '/foo';
var template = 'xhr template';
xhr.expect(url, template);
var md = createMetadata({url: '/foo'});
loader.load(md)
xhr.expect('/foo', 'xhr template');
var template = new Template({url: '/foo'});
loader.load(template)
.then((el) => {
firstEl = el;
return loader.load(md);
return loader.load(template);
})
.then((el) =>{
expect(el).toBe(firstEl);
expect(el.content).toHaveText(template);
expect(el.content).toHaveText('xhr template');
done();
});
xhr.flush();
});
it('should throw when no template is defined', () => {
var md = createMetadata();
expect(() => loader.load(md))
.toThrowError('No template configured for component FakeComponent');
var template = new Template({inline: null, url: null});
expect(() => loader.load(template))
.toThrowError('Templates should have either their url or inline property set');
});
it('should return a rejected Promise when xhr loading fails', (done) => {
var url = '/foo';
xhr.expect(url, null);
var md = createMetadata({url: '/foo'});
PromiseWrapper.then(loader.load(md),
xhr.expect('/foo', null);
var template = new Template({url: '/foo'});
PromiseWrapper.then(loader.load(template),
function(_) { throw 'Unexpected response'; },
function(error) {
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 {Lexer, Parser, DynamicProtoChangeDetector,
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 {List, MapWrapper} from 'angular2/src/facade/collection';
import {DOM, Element} from 'angular2/src/facade/dom';
@ -649,9 +649,7 @@ class DirectiveImplementingOnChange {
class SomeService {}
@Component({
componentServices: [SomeService]
})
@Component({componentServices: [SomeService]})
class SomeComponent {
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 {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 {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 {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
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 {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 {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {Foreach} from 'angular2/src/directives/foreach';
export function main() {
describe('foreach', () => {
var view, cd, compiler, component;
var view, cd, compiler, component, tplResolver;
beforeEach(() => {
compiler = new Compiler(dynamicChangeDetection, null, new DirectiveMetadataReader(),
new Parser(new Lexer()), new CompilerCache(), new NativeShadowDomStrategy());
tplResolver = new FakeTemplateResolver();
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
new NativeShadowDomStrategy(), tplResolver);
});
function createView(pv) {
@ -31,8 +36,13 @@ export function main() {
cd = view.changeDetector;
}
function compileWithTemplate(template) {
return compiler.compile(TestComponent, el(template));
function compileWithTemplate(html) {
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>';
@ -217,13 +227,7 @@ class Foo {
}
}
@Component({
selector: 'test-cmp',
template: new TemplateConfig({
inline: '', // each test swaps with a custom template.
directives: [Foreach]
})
})
@Component({selector: 'test-cmp'})
class TestComponent {
items: any;
item: any;
@ -231,3 +235,26 @@ class TestComponent {
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 {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 {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 {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
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 {TemplateConfig} from 'angular2/src/core/annotations/template_config';
import {Template} from 'angular2/src/core/annotations/template';
import {If} from 'angular2/src/directives/if';
export function main() {
describe('if directive', () => {
var view, cd, compiler, component;
var view, cd, compiler, component, tplResolver;
beforeEach(() => {
compiler = new Compiler(dynamicChangeDetection, null, new DirectiveMetadataReader(),
new Parser(new Lexer()), new CompilerCache(), new NativeShadowDomStrategy());
tplResolver = new FakeTemplateResolver();
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
new NativeShadowDomStrategy(), tplResolver);
});
function createView(pv) {
@ -29,8 +36,13 @@ export function main() {
cd = view.changeDetector;
}
function compileWithTemplate(template) {
return compiler.compile(TestComponent, el(template));
function compileWithTemplate(html) {
var template = new Template({
inline: html,
directives: [If]
});
tplResolver.setTemplate(TestComponent, template);
return compiler.compile(TestComponent);
}
it('should work in a template attribute', (done) => {
@ -188,13 +200,7 @@ export function main() {
});
}
@Component({
selector: 'test-cmp',
template: new TemplateConfig({
inline: '', // each test swaps with a custom template.
directives: [If]
})
})
@Component({selector: 'test-cmp'})
class TestComponent {
booleanCondition: boolean;
numberCondition: number;
@ -213,3 +219,26 @@ class TestComponent {
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 {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 {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
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 {NonBindable} from 'angular2/src/directives/non_bindable';
export function main() {
describe('non-bindable', () => {
var view, cd, compiler, component;
var view, cd, compiler, component, tplResolver;
beforeEach(() => {
compiler = new Compiler(dynamicChangeDetection,
null, new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(), new NativeShadowDomStrategy());
tplResolver = new FakeTemplateResolver();
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
new NativeShadowDomStrategy(), tplResolver);
});
function createView(pv) {
@ -25,8 +31,13 @@ export function main() {
cd = view.changeDetector;
}
function compileWithTemplate(template) {
return compiler.compile(TestComponent, el(template));
function compileWithTemplate(html) {
var template = new Template({
inline: html,
directives: [NonBindable, TestDecorator]
});
tplResolver.setTemplate(TestComponent, template);
return compiler.compile(TestComponent);
}
it('should not interpolate children', (done) => {
@ -63,13 +74,7 @@ export function main() {
})
}
@Component({
selector: 'test-cmp',
template: new TemplateConfig({
inline: '', // each test swaps with a custom template.
directives: [NonBindable, TestDecorator]
})
})
@Component({selector: 'test-cmp'})
class TestComponent {
text: string;
constructor() {
@ -85,3 +90,26 @@ class TestDecorator {
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 {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 {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
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';
export function main() {
describe('switch', () => {
var view, cd, compiler, component;
var view, cd, compiler, component, tplResolver;
beforeEach(() => {
compiler = new Compiler(dynamicChangeDetection, null, new DirectiveMetadataReader(),
new Parser(new Lexer()), new CompilerCache(), new NativeShadowDomStrategy());
tplResolver = new FakeTemplateResolver();
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
new NativeShadowDomStrategy(), tplResolver);
});
function createView(pv) {
@ -24,8 +30,13 @@ export function main() {
cd = view.changeDetector;
}
function compileWithTemplate(template) {
return compiler.compile(TestComponent, el(template));
function compileWithTemplate(html) {
var template = new Template({
inline: html,
directives: [Switch, SwitchWhen, SwitchDefault]
});
tplResolver.setTemplate(TestComponent, template);
return compiler.compile(TestComponent);
}
describe('switch value changes', () => {
@ -143,13 +154,7 @@ export function main() {
});
}
@Component({
selector: 'test-cmp',
template: new TemplateConfig({
inline: '', // each test swaps with a custom template.
directives: [Switch, SwitchWhen, SwitchDefault]
})
})
@Component({selector: 'test-cmp'})
class TestComponent {
switchValue: any;
when1: any;
@ -161,3 +166,26 @@ class TestComponent {
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 {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {Injector} from 'angular2/di';
import {DOM} from 'angular2/src/facade/dom';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
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,
ControlDirective, NewControlGroupDirective,
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() {
function detectChanges(view) {
view.changeDetector.detectChanges();
}
function compile(componentType, template, context, callback) {
var tplResolver = new FakeTemplateResolver();
var compiler = new Compiler(dynamicChangeDetection,
new TemplateLoader(new XHRMock()),
new TemplateLoader(null),
new DirectiveMetadataReader(),
new Parser(new Lexer()),
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);
view.hydrate(new Injector([]), null, context);
detectChanges(view);
@ -198,14 +211,7 @@ export function main() {
});
}
@Component({
selector: "my-comp",
template: new TemplateConfig({
inline: "",
directives: [ControlGroupDirective, ControlNameDirective,
ControlDirective, NewControlGroupDirective, WrappedValue]
})
})
@Component({selector: "my-comp"})
class MyComp {
form:ControlGroup;
name:string;
@ -233,4 +239,27 @@ class WrappedValue {
constructor(cd:ControlNameDirective) {
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 {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 {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {reflector} from 'angular2/src/reflection/reflection';
import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util';
import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl';
function setupReflector() {
reflector.registerType(BenchmarkComponent, {
"factory": () => new BenchmarkComponent(),
"parameters": [],
"annotations" : [new Component({template: new TemplateConfig({directives: [Dir0, Dir1, Dir2, Dir3, Dir4]})})]
"annotations" : [new Component()]
});
reflector.registerType(Dir0, {
@ -83,37 +82,36 @@ export function main() {
setupReflector();
var reader = new DirectiveMetadataReader();
var cache = new CompilerCache();
var compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(new XHRImpl()),
reader, new Parser(new Lexer()), cache, new NativeShadowDomStrategy());
var templateNoBindings = loadTemplate('templateNoBindings', count);
var templateWithBindings = loadTemplate('templateWithBindings', count);
var templateResolver = new FakeTemplateResolver();
var compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
reader, new Parser(new Lexer()), cache, new NativeShadowDomStrategy(), templateResolver);
var templateNoBindings = createTemplateHtml('templateNoBindings', count);
var templateWithBindings = createTemplateHtml('templateWithBindings', count);
function compileNoBindings() {
// Need to clone every time as the compiler might modify the template!
var cloned = DOM.clone(templateNoBindings);
templateResolver.setTemplateHtml(templateNoBindings);
cache.clear();
compiler.compile(BenchmarkComponent, cloned);
compiler.compile(BenchmarkComponent);
}
function compileWithBindings() {
// Need to clone every time as the compiler might modify the template!
var cloned = DOM.clone(templateWithBindings);
templateResolver.setTemplateHtml(templateWithBindings);
cache.clear();
compiler.compile(BenchmarkComponent, cloned);
compiler.compile(BenchmarkComponent);
}
bindAction('#compileNoBindings', compileNoBindings);
bindAction('#compileWithBindings', compileWithBindings);
}
function loadTemplate(templateId, repeatCount) {
function createTemplateHtml(templateId, repeatCount) {
var template = DOM.querySelectorAll(document, `#${templateId}`)[0];
var content = DOM.getInnerHTML(template);
var result = '';
for (var i=0; i<repeatCount; i++) {
result += content;
}
return DOM.createTemplate(result);
return result;
}
@Decorator({
@ -164,10 +162,24 @@ class Dir4 {
constructor(dir3:Dir3) {}
}
@Component({
template: new TemplateConfig({
directives: [Dir0, Dir1, Dir2, Dir3, Dir4]
})
})
@Component()
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 {reflector} from 'angular2/src/reflection/reflection';
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';
import {PromiseWrapper} from 'angular2/src/facade/async';
import {ListWrapper} from 'angular2/src/facade/collection';
@ -83,26 +83,23 @@ export function setupReflectorForApp() {
'factory': () => { return new App(); },
'parameters': [],
'annotations': [
new Component({
selector: 'scroll-app',
template: new TemplateConfig({
directives: [ScrollAreaComponent, If, Foreach],
inline: `
<div>
<div style="display: flex">
<scroll-area id="testArea"></scroll-area>
<div style="padding-left: 20px">
<button id="run-btn">Run</button>
<button id="reset-btn">Reset</button>
</div>
new Component({selector: 'scroll-app'}),
new Template({
directives: [ScrollAreaComponent, If, Foreach],
inline: `
<div>
<div style="display: flex">
<scroll-area id="testArea"></scroll-area>
<div style="padding-left: 20px">
<button id="run-btn">Run</button>
<button id="reset-btn">Reset</button>
</div>
<div template="if scrollAreas.length > 0">
<p>Following tables are only here to add weight to the UI:</p>
<scroll-area template="foreach #scrollArea in scrollAreas"></scroll-area>
</div>
</div>`
})
})
]
</div>
<div template="if scrollAreas.length > 0">
<p>Following tables are only here to add weight to the UI:</p>
<scroll-area template="foreach #scrollArea in scrollAreas"></scroll-area>
</div>
</div>`
})]
});
}

View File

@ -1,7 +1,7 @@
import {int} from 'angular2/src/facade/lang';
import {reflector} from 'angular2/src/reflection/reflection';
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';
import {PromiseWrapper} from 'angular2/src/facade/async';
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
@ -103,14 +103,14 @@ export function setupReflectorForCells() {
'annotations': [
new Component({
selector: 'company-name',
template: new TemplateConfig({
directives: [],
inline: `<div [style]="style">{{company.name}}</div>`
}),
bind: {
'cell-width': 'width',
'company': 'company'
}
}),
new Template({
directives: [],
inline: `<div [style]="style">{{company.name}}</div>`
})
]
});
@ -121,14 +121,14 @@ export function setupReflectorForCells() {
'annotations': [
new Component({
selector: 'opportunity-name',
template: new TemplateConfig({
directives: [],
inline: `<div [style]="style">{{opportunity.name}}</div>`
}),
bind: {
'cell-width': 'width',
'opportunity': 'opportunity'
}
}),
new Template({
directives: [],
inline: `<div [style]="style">{{opportunity.name}}</div>`
})
]
});
@ -139,14 +139,14 @@ export function setupReflectorForCells() {
'annotations': [
new Component({
selector: 'offering-name',
template: new TemplateConfig({
directives: [],
inline: `<div [style]="style">{{offering.name}}</div>`
}),
bind: {
'cell-width': 'width',
'offering': 'offering'
}
}),
new Template({
directives: [],
inline: `<div [style]="style">{{offering.name}}</div>`
})
]
});
@ -157,22 +157,22 @@ export function setupReflectorForCells() {
'annotations': [
new Component({
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: {
'cell-width': 'width',
'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': [
new Component({
selector: 'account-cell',
template: new TemplateConfig({
directives: [],
inline: `
<div [style]="style">
<a href="/account/{{account.accountId}}">
{{account.accountId}}
</a>
</div>`
}),
bind: {
'cell-width': 'width',
'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': [
new Component({
selector: 'formatted-cell',
template: new TemplateConfig({
directives: [],
inline: `<div [style]="style">{{formattedValue}}</div>`
}),
bind: {
'cell-width': 'width',
'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}
from 'angular2/change_detection';
import {bootstrap, Component, Viewport, TemplateConfig, ViewContainer, Compiler}
import {bootstrap, Component, Viewport, Template, ViewContainer, Compiler}
from 'angular2/angular2';
import {reflector} from 'angular2/src/reflection/reflection';
import {CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {ShadowDomStrategy, 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 {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl';
@ -172,10 +173,12 @@ export function setupReflectorForAngular() {
});
reflector.registerType(Compiler, {
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy) =>
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy),
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
resolver) =>
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
resolver),
"parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser],
[CompilerCache], [ShadowDomStrategy]],
[CompilerCache], [ShadowDomStrategy], [TemplateResolver]],
"annotations": []
});
@ -197,6 +200,12 @@ export function setupReflectorForAngular() {
"annotations": []
});
reflector.registerType(TemplateResolver, {
"factory": () => new TemplateResolver(),
"parameters": [],
"annotations": []
});
reflector.registerType(XHR, {
"factory": () => new XHRImpl(),
"parameters": [],

View File

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

View File

@ -1,6 +1,6 @@
import {int} from 'angular2/src/facade/lang';
import {reflector} from 'angular2/src/reflection/reflection';
import {Component, Viewport, TemplateConfig, ViewContainer, Compiler}
import {Component, Viewport, Template, ViewContainer, Compiler}
from 'angular2/angular2';
import {PromiseWrapper} from 'angular2/src/facade/async';
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
@ -51,55 +51,55 @@ export function setupReflectorForScrollItem() {
'annotations': [
new Component({
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: {
'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}
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 {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
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 {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
@ -24,28 +25,26 @@ function setupReflector() {
reflector.registerType(AppComponent, {
'factory': () => new AppComponent(),
'parameters': [],
'annotations' : [new Component({
selector: 'app',
template: new TemplateConfig({
'annotations' : [
new Component({selector: 'app'}),
new Template({
directives: [TreeComponent],
inline: `<tree [data]='initData'></tree>`
})
})]
})]
});
reflector.registerType(TreeComponent, {
'factory': () => new TreeComponent(),
'parameters': [],
'annotations' : [new Component({
selector: 'tree',
bind: {
'data': 'data'
},
template: new TemplateConfig({
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>`
})
})]
'annotations' : [
new Component({
selector: 'tree',
bind: {'data': 'data'}
}),
new Template({
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>`
})]
});
reflector.registerType(NgIf, {
@ -60,9 +59,10 @@ function setupReflector() {
});
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],
[Parser], [CompilerCache], [ShadowDomStrategy]],
[Parser], [CompilerCache], [ShadowDomStrategy], [TemplateResolver]],
'annotations': []
});
@ -84,6 +84,12 @@ function setupReflector() {
'annotations': []
});
reflector.registerType(TemplateResolver, {
'factory': () => new TemplateResolver(),
'parameters': [],
'annotations': []
});
reflector.registerType(XHR, {
'factory': () => new XHRImpl(),
'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 {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabilities';
@Component({
selector: 'gestures-app',
template: new TemplateConfig({
url: 'template.html'
})
})
@Component({selector: 'gestures-app'})
@Template({url: 'template.html'})
class GesturesCmp {
swipeDirection: string;
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:
// - 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',
// These are services that would be created if a class in the component's
// template tries to inject them.
componentServices: [GreetingService],
template: new TemplateConfig({
// The template for the component.
// Expressions in the template (like {{greeting}}) are evaluated in the
// context of the HelloCmp class below.
inline: `<div class="greeting">{{greeting}} <span red>world</span>!</div>
<button class="changeButton" (click)="changeGreeting()">change greeting</button>`,
// All directives used in the template need to be specified. This allows for
// modularity (RedDec can only be used in this template)
// and better tooling (the template can be invalidated if the attribute is
// misspelled).
directives: [RedDec]
})
componentServices: [GreetingService]
})
// The template for the component.
@Template({
// Expressions in the template (like {{greeting}}) are evaluated in the
// context of the HelloCmp class below.
inline: `<div class="greeting">{{greeting}} <span red>world</span>!</div>
<button class="changeButton" (click)="changeGreeting()">change greeting</button>`,
// All directives used in the template need to be specified. This allows for
// modularity (RedDec can only be used in this template)
// and better tooling (the template can be invalidated if the attribute is
// misspelled).
directives: [RedDec]
})
class HelloCmp {
greeting: string;

View File

@ -1,6 +1,6 @@
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 {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 {ShadowDomStrategy, 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 {XHR} from 'angular2/src/core/compiler/xhr/xhr';
import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl';
@ -17,14 +18,16 @@ function setup() {
reflector.registerType(app.HelloCmp, {
"factory": (service) => new app.HelloCmp(service),
"parameters": [[app.GreetingService]],
"annotations" : [new Component({
selector: 'hello-app',
componentServices: [app.GreetingService],
template: new TemplateConfig({
"annotations" : [
new Component({
selector: 'hello-app',
componentServices: [app.GreetingService]
}),
new Template({
directives: [app.RedDec],
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, {
@ -40,10 +43,12 @@ function setup() {
});
reflector.registerType(Compiler, {
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy) =>
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy),
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
resolver) =>
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
resolver),
"parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser],
[CompilerCache], [ShadowDomStrategy]],
[CompilerCache], [ShadowDomStrategy], [TemplateResolver]],
"annotations": []
});
@ -65,6 +70,12 @@ function setup() {
"annotations": []
});
reflector.registerType(TemplateResolver, {
"factory": () => new TemplateResolver(),
"parameters": [],
"annotations": []
});
reflector.registerType(XHR, {
"factory": () => new XHRImpl(),
"parameters": [],