refactor(template loading): add support for base URLs, css rewriting

fixes #654
This commit is contained in:
Victor Berchet 2015-02-24 16:05:45 +01:00
parent 26872f60e6
commit 929fc65493
42 changed files with 1147 additions and 634 deletions

View File

@ -19,6 +19,10 @@ import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl';
import {EventManager, DomEventsPlugin} from 'angular2/src/core/events/event_manager'; import {EventManager, DomEventsPlugin} from 'angular2/src/core/events/event_manager';
import {HammerGesturesPlugin} from 'angular2/src/core/events/hammer_gestures'; import {HammerGesturesPlugin} from 'angular2/src/core/events/hammer_gestures';
import {Binding} from 'angular2/src/di/binding'; import {Binding} from 'angular2/src/di/binding';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
var _rootInjector: Injector; var _rootInjector: Injector;
@ -78,7 +82,7 @@ function _injectorBindings(appComponentType): List<Binding> {
var plugins = [new HammerGesturesPlugin(), new DomEventsPlugin()]; var plugins = [new HammerGesturesPlugin(), new DomEventsPlugin()];
return new EventManager(plugins, zone); return new EventManager(plugins, zone);
}, [VmTurnZone]), }, [VmTurnZone]),
bind(ShadowDomStrategy).toValue(new NativeShadowDomStrategy()), bind(ShadowDomStrategy).toClass(NativeShadowDomStrategy),
Compiler, Compiler,
CompilerCache, CompilerCache,
TemplateResolver, TemplateResolver,
@ -89,6 +93,10 @@ function _injectorBindings(appComponentType): List<Binding> {
Lexer, Lexer,
ExceptionHandler, ExceptionHandler,
bind(XHR).toValue(new XHRImpl()), bind(XHR).toValue(new XHRImpl()),
ComponentUrlMapper,
UrlResolver,
StyleUrlResolver,
StyleInliner,
]; ];
} }

View File

@ -16,6 +16,8 @@ import {DirectiveMetadata} from './directive_metadata';
import {Template} from '../annotations/template'; import {Template} from '../annotations/template';
import {ShadowDomStrategy} from './shadow_dom_strategy'; import {ShadowDomStrategy} from './shadow_dom_strategy';
import {CompileStep} from './pipeline/compile_step'; import {CompileStep} from './pipeline/compile_step';
import {ComponentUrlMapper} from './component_url_mapper';
import {UrlResolver} from './url_resolver';
/** /**
@ -57,6 +59,9 @@ export class Compiler {
_shadowDomStrategy: ShadowDomStrategy; _shadowDomStrategy: ShadowDomStrategy;
_shadowDomDirectives: List<DirectiveMetadata>; _shadowDomDirectives: List<DirectiveMetadata>;
_templateResolver: TemplateResolver; _templateResolver: TemplateResolver;
_componentUrlMapper: ComponentUrlMapper;
_urlResolver: UrlResolver;
_appUrl: string;
constructor(changeDetection:ChangeDetection, constructor(changeDetection:ChangeDetection,
templateLoader:TemplateLoader, templateLoader:TemplateLoader,
@ -64,7 +69,9 @@ export class Compiler {
parser:Parser, parser:Parser,
cache:CompilerCache, cache:CompilerCache,
shadowDomStrategy: ShadowDomStrategy, shadowDomStrategy: ShadowDomStrategy,
templateResolver: TemplateResolver) { templateResolver: TemplateResolver,
componentUrlMapper: ComponentUrlMapper,
urlResolver: UrlResolver) {
this._changeDetection = changeDetection; this._changeDetection = changeDetection;
this._reader = reader; this._reader = reader;
this._parser = parser; this._parser = parser;
@ -78,6 +85,9 @@ export class Compiler {
ListWrapper.push(this._shadowDomDirectives, reader.read(types[i])); ListWrapper.push(this._shadowDomDirectives, reader.read(types[i]));
} }
this._templateResolver = templateResolver; this._templateResolver = templateResolver;
this._componentUrlMapper = componentUrlMapper;
this._urlResolver = urlResolver;
this._appUrl = urlResolver.resolve(null, './');
} }
createSteps(component:Type, template: Template):List<CompileStep> { createSteps(component:Type, template: Template):List<CompileStep> {
@ -90,8 +100,10 @@ export class Compiler {
var cmpMetadata = this._reader.read(component); var cmpMetadata = this._reader.read(component);
var templateUrl = this._templateLoader.getTemplateUrl(template);
return createDefaultSteps(this._changeDetection, this._parser, cmpMetadata, dirMetadata, return createDefaultSteps(this._changeDetection, this._parser, cmpMetadata, dirMetadata,
this._shadowDomStrategy); this._shadowDomStrategy, templateUrl);
} }
compile(component: Type):Promise<ProtoView> { compile(component: Type):Promise<ProtoView> {
@ -118,6 +130,10 @@ export class Compiler {
var template = this._templateResolver.resolve(component); var template = this._templateResolver.resolve(component);
var componentUrl = this._componentUrlMapper.getUrl(component);
var baseUrl = this._urlResolver.resolve(this._appUrl, componentUrl);
this._templateLoader.setBaseUrl(template, baseUrl);
var tplElement = this._templateLoader.load(template); var tplElement = this._templateLoader.load(template);
if (PromiseWrapper.isPromise(tplElement)) { if (PromiseWrapper.isPromise(tplElement)) {
@ -160,6 +176,12 @@ export class Compiler {
} }
} }
if (protoView.stylePromises.length > 0) {
// The protoView is ready after all asynchronous styles are ready
var syncProtoView = protoView;
protoView = PromiseWrapper.all(syncProtoView.stylePromises).then((_) => syncProtoView);
}
if (nestedPVPromises.length > 0) { if (nestedPVPromises.length > 0) {
// Returns ProtoView Promise when there are any asynchronous nested ProtoViews. // Returns ProtoView Promise when there are any asynchronous nested ProtoViews.
// The promise will resolved after nested ProtoViews are compiled. // The promise will resolved after nested ProtoViews are compiled.
@ -169,7 +191,6 @@ export class Compiler {
); );
} }
// When there is no asynchronous nested ProtoViews, return the ProtoView
return protoView; return protoView;
} }

View File

@ -1,11 +1,11 @@
import {Type, isPresent} from 'angular2/src/facade/lang'; import {Type, isPresent} from 'angular2/src/facade/lang';
import {Map, MapWrapper} from 'angular2/src/facade/lang'; import {Map, MapWrapper} from 'angular2/src/facade/collection';
export class ComponentUrlMapper { export class ComponentUrlMapper {
// Returns the url to the component source file. // Returns the base URL to the component source file.
// The returned url could be: // The returned URL could be:
// - an absolute URL, // - an absolute URL,
// - a URL relative to the application // - a path relative to the application
getUrl(component: Type): string { getUrl(component: Type): string {
return './'; return './';
} }

View File

@ -9,11 +9,10 @@ import {ElementBindingMarker} from './element_binding_marker';
import {ProtoViewBuilder} from './proto_view_builder'; import {ProtoViewBuilder} from './proto_view_builder';
import {ProtoElementInjectorBuilder} from './proto_element_injector_builder'; import {ProtoElementInjectorBuilder} from './proto_element_injector_builder';
import {ElementBinderBuilder} from './element_binder_builder'; import {ElementBinderBuilder} from './element_binder_builder';
import {ShimShadowCss} from './shim_shadow_css'; import {ResolveCss} from './resolve_css';
import {ShimShadowDom} from './shim_shadow_dom'; import {ShimShadowDom} from './shim_shadow_dom';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata'; import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy, EmulatedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {ShadowDomStrategy, EmulatedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {DOM} from 'angular2/src/facade/dom';
/** /**
* Default steps used for compiling a template. * Default steps used for compiling a template.
@ -25,24 +24,20 @@ export function createDefaultSteps(
parser:Parser, parser:Parser,
compiledComponent: DirectiveMetadata, compiledComponent: DirectiveMetadata,
directives: List<DirectiveMetadata>, directives: List<DirectiveMetadata>,
shadowDomStrategy: ShadowDomStrategy) { shadowDomStrategy: ShadowDomStrategy,
templateUrl: string) {
var steps = [new ViewSplitter(parser)]; var steps = [
new ViewSplitter(parser),
if (shadowDomStrategy instanceof EmulatedShadowDomStrategy) { new ResolveCss(compiledComponent, shadowDomStrategy, templateUrl),
var step = new ShimShadowCss(compiledComponent, shadowDomStrategy, DOM.defaultDoc().head);
ListWrapper.push(steps, step);
}
steps = ListWrapper.concat(steps,[
new PropertyBindingParser(parser), new PropertyBindingParser(parser),
new DirectiveParser(directives), new DirectiveParser(directives),
new TextInterpolationParser(parser), new TextInterpolationParser(parser),
new ElementBindingMarker(), new ElementBindingMarker(),
new ProtoViewBuilder(changeDetection, shadowDomStrategy), new ProtoViewBuilder(changeDetection, shadowDomStrategy),
new ProtoElementInjectorBuilder(), new ProtoElementInjectorBuilder(),
new ElementBinderBuilder(parser) new ElementBinderBuilder(parser),
]); ]
if (shadowDomStrategy instanceof EmulatedShadowDomStrategy) { if (shadowDomStrategy instanceof EmulatedShadowDomStrategy) {
var step = new ShimShadowDom(compiledComponent, shadowDomStrategy); var step = new ShimShadowDom(compiledComponent, shadowDomStrategy);

View File

@ -0,0 +1,47 @@
import {CompileStep} from './compile_step';
import {CompileElement} from './compile_element';
import {CompileControl} from './compile_control';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {DOM} from 'angular2/src/facade/dom';
import {Type} from 'angular2/src/facade/lang';
import {PromiseWrapper} from 'angular2/src/facade/async';
import {ListWrapper} from 'angular2/src/facade/collection';
export class ResolveCss extends CompileStep {
_strategy: ShadowDomStrategy;
_component: Type;
_templateUrl: string;
constructor(cmpMetadata: DirectiveMetadata, strategy: ShadowDomStrategy, templateUrl: string) {
super();
this._strategy = strategy;
this._component = cmpMetadata.type;
this._templateUrl = templateUrl;
}
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
// May be remove the styles
if (DOM.tagName(current.element) == 'STYLE') {
current.ignoreBindings = true;
var styleEl = current.element;
var css = DOM.getText(styleEl);
css = this._strategy.transformStyleText(css, this._templateUrl, this._component);
if (PromiseWrapper.isPromise(css)) {
ListWrapper.push(parent.inheritedProtoView.stylePromises, css);
DOM.setText(styleEl, '');
css.then((css) => {
DOM.setText(styleEl, css);
})
} else {
DOM.setText(styleEl, css);
}
this._strategy.handleStyleElement(styleEl);
}
}
}

View File

@ -1,55 +0,0 @@
import {CompileStep} from './compile_step';
import {CompileElement} from './compile_element';
import {CompileControl} from './compile_control';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {DOM, Element, StyleElement} from 'angular2/src/facade/dom';
import {isPresent, isBlank, Type} from 'angular2/src/facade/lang';
export class ShimShadowCss extends CompileStep {
_strategy: ShadowDomStrategy;
_styleHost: Element;
_lastInsertedStyle: Element;
_component: Type;
constructor(cmpMetadata: DirectiveMetadata, strategy: ShadowDomStrategy, styleHost: Element) {
super();
this._strategy = strategy;
this._component = cmpMetadata.type;
this._styleHost = styleHost;
this._lastInsertedStyle = null;
}
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
// May be remove the styles
if (DOM.tagName(current.element) == 'STYLE') {
current.ignoreBindings = true;
if (this._strategy.extractStyles()) {
var styleEl = current.element;
DOM.remove(styleEl);
var css = DOM.getText(styleEl);
var shimComponent = this._strategy.getShimComponent(this._component);
css = shimComponent.shimCssText(css);
DOM.setText(styleEl, css);
this._insertStyle(this._styleHost, styleEl);
}
}
}
_insertStyle(host: Element, style: StyleElement) {
if (isBlank(this._lastInsertedStyle)) {
var firstChild = DOM.firstChild(host);
if (isPresent(firstChild)) {
DOM.insertBefore(firstChild, style);
} else {
DOM.appendChild(host, style);
}
} else {
DOM.insertAfter(this._lastInsertedStyle, style);
}
this._lastInsertedStyle = style;
}
}

View File

@ -2,21 +2,19 @@ import {CompileStep} from './compile_step';
import {CompileElement} from './compile_element'; import {CompileElement} from './compile_element';
import {CompileControl} from './compile_control'; import {CompileControl} from './compile_control';
import {isPresent} from 'angular2/src/facade/lang'; import {isPresent, Type} from 'angular2/src/facade/lang';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata'; import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {ShimComponent} from 'angular2/src/core/compiler/shadow_dom_emulation/shim_component';
export class ShimShadowDom extends CompileStep { export class ShimShadowDom extends CompileStep {
_strategy: ShadowDomStrategy; _strategy: ShadowDomStrategy;
_shimComponent: ShimComponent; _component: Type;
constructor(cmpMetadata: DirectiveMetadata, strategy: ShadowDomStrategy) { constructor(cmpMetadata: DirectiveMetadata, strategy: ShadowDomStrategy) {
super(); super();
this._strategy = strategy; this._strategy = strategy;
this._shimComponent = strategy.getShimComponent(cmpMetadata.type); this._component = cmpMetadata.type;
} }
process(parent:CompileElement, current:CompileElement, control:CompileControl) { process(parent:CompileElement, current:CompileElement, control:CompileControl) {
@ -25,13 +23,12 @@ export class ShimShadowDom extends CompileStep {
} }
// Shim the element as a child of the compiled component // Shim the element as a child of the compiled component
this._shimComponent.shimContentElement(current.element); this._strategy.shimContentElement(this._component, current.element);
// If the current element is also a component, shim it as a host // If the current element is also a component, shim it as a host
var host = current.componentDirective; var host = current.componentDirective;
if (isPresent(host)) { if (isPresent(host)) {
var shimComponent = this._strategy.getShimComponent(host.type); this._strategy.shimHostElement(host.type, current.element);
shimComponent.shimHostElement(current.element);
} }
} }
} }

View File

@ -1,99 +0,0 @@
import {Element, DOM} from 'angular2/src/facade/dom';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {int, isBlank, Type} from 'angular2/src/facade/lang';
import {ShadowCss} from './shadow_css';
/**
* Used to shim component CSS & DOM
*/
export class ShimComponent {
constructor(component: Type) {
}
shimCssText(cssText: string): string {
return null
}
shimContentElement(element: Element) {}
shimHostElement(element: Element) {}
}
/**
* Native components does not need to the shim.
*
* All methods are no-ops.
*/
export class ShimNativeComponent extends ShimComponent {
constructor(component: Type) {
super(component);
};
shimCssText(cssText: string): string {
return cssText;
}
shimContentElement(element: Element) {
}
shimHostElement(element: Element) {
}
}
var _componentCache: Map<Type, int> = MapWrapper.create();
var _componentId: int = 0;
// Reset the component cache - used for tests only
export function resetShimComponentCache() {
MapWrapper.clear(_componentCache);
_componentId = 0;
}
/**
* Emulated components need to be shimmed:
* - An attribute needs to be added to the host,
* - An attribute needs to be added to all nodes in their content,
* - The CSS needs to be scoped.
*/
export class ShimEmulatedComponent extends ShimComponent {
_cmpId: int;
constructor(component: Type) {
super(component);
// Generates a unique ID for components
var componentId = MapWrapper.get(_componentCache, component);
if (isBlank(componentId)) {
componentId = _componentId++;
MapWrapper.set(_componentCache, component, componentId);
}
this._cmpId = componentId;
};
// Scope the CSS
shimCssText(cssText: string): string {
var shadowCss = new ShadowCss();
return shadowCss.shimCssText(cssText, this._getContentAttribute(), this._getHostAttribute());
}
// Add an attribute on a content element
shimContentElement(element: Element) {
DOM.setAttribute(element, this._getContentAttribute(), '');
}
// Add an attribute to the host
shimHostElement(element: Element) {
DOM.setAttribute(element, this._getHostAttribute(), '');
}
// Return the attribute to be added to the component
_getHostAttribute() {
return `_nghost-${this._cmpId}`;
}
// Returns the attribute to be added on every single nodes in the component
_getContentAttribute() {
return `_ngcontent-${this._cmpId}`;
}
}

View File

@ -1,31 +1,44 @@
import {Type, isBlank, isPresent} from 'angular2/src/facade/lang'; import {Type, isBlank, isPresent, int} from 'angular2/src/facade/lang';
import {DOM, Element} from 'angular2/src/facade/dom'; import {DOM, Element, StyleElement} from 'angular2/src/facade/dom';
import {List, ListWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper, MapWrapper, Map} from 'angular2/src/facade/collection';
import {PromiseWrapper} from 'angular2/src/facade/async';
import {View} from './view'; import {View} from './view';
import {Content} from './shadow_dom_emulation/content_tag'; import {Content} from './shadow_dom_emulation/content_tag';
import {LightDom} from './shadow_dom_emulation/light_dom'; import {LightDom} from './shadow_dom_emulation/light_dom';
import {ShimComponent, ShimEmulatedComponent, ShimNativeComponent} from './shadow_dom_emulation/shim_component'; import {ShadowCss} from './shadow_dom_emulation/shadow_css';
import {StyleInliner} from './style_inliner';
import {StyleUrlResolver} from './style_url_resolver';
export class ShadowDomStrategy { export class ShadowDomStrategy {
attachTemplate(el:Element, view:View){} attachTemplate(el:Element, view:View) {}
constructLightDom(lightDomView:View, shadowDomView:View, el:Element){} constructLightDom(lightDomView:View, shadowDomView:View, el:Element) {}
polyfillDirectives():List<Type>{ return null; } polyfillDirectives():List<Type> { return null; }
extractStyles(): boolean { return false; } // TODO(vicb): union types: return either a string or a Promise<string>
getShimComponent(component: Type): ShimComponent { transformStyleText(cssText: string, baseUrl: string, component: Type) {}
return null; handleStyleElement(styleEl: StyleElement) {};
} shimContentElement(component: Type, element: Element) {}
shimHostElement(component: Type, element: Element) {}
} }
export class EmulatedShadowDomStrategy extends ShadowDomStrategy { export class EmulatedShadowDomStrategy extends ShadowDomStrategy {
constructor() { _styleInliner: StyleInliner;
_styleUrlResolver: StyleUrlResolver;
_styleHost: Element;
_lastInsertedStyle: StyleElement;
constructor(styleInliner: StyleInliner, styleUrlResolver: StyleUrlResolver, styleHost: Element) {
super(); super();
this._styleInliner = styleInliner;
this._styleUrlResolver = styleUrlResolver;
this._styleHost = styleHost;
} }
attachTemplate(el:Element, view:View){ attachTemplate(el:Element, view:View){
DOM.clearNodes(el); DOM.clearNodes(el);
moveViewNodesIntoParent(el, view); _moveViewNodesIntoParent(el, view);
} }
constructLightDom(lightDomView:View, shadowDomView:View, el:Element){ constructLightDom(lightDomView:View, shadowDomView:View, el:Element){
@ -36,22 +49,58 @@ export class EmulatedShadowDomStrategy extends ShadowDomStrategy {
return [Content]; return [Content];
} }
extractStyles(): boolean { transformStyleText(cssText: string, baseUrl: string, component: Type) {
return true; cssText = this._styleUrlResolver.resolveUrls(cssText, baseUrl);
var css = this._styleInliner.inlineImports(cssText, baseUrl);
if (PromiseWrapper.isPromise(css)) {
return css.then((css) => _shimCssForComponent(css, component));
} else {
return _shimCssForComponent(css, component);
}
} }
getShimComponent(component: Type): ShimComponent { handleStyleElement(styleEl: StyleElement) {
return new ShimEmulatedComponent(component); DOM.remove(styleEl);
this._insertStyleElement(this._styleHost, styleEl);
};
shimContentElement(component: Type, element: Element) {
var id = _getComponentId(component);
var attrName = _getContentAttribute(id);
DOM.setAttribute(element, attrName, '');
}
shimHostElement(component: Type, element: Element) {
var id = _getComponentId(component);
var attrName = _getHostAttribute(id);
DOM.setAttribute(element, attrName, '');
}
_insertStyleElement(host: Element, style: StyleElement) {
if (isBlank(this._lastInsertedStyle)) {
var firstChild = DOM.firstChild(host);
if (isPresent(firstChild)) {
DOM.insertBefore(firstChild, style);
} else {
DOM.appendChild(host, style);
}
} else {
DOM.insertAfter(this._lastInsertedStyle, style);
}
this._lastInsertedStyle = style;
} }
} }
export class NativeShadowDomStrategy extends ShadowDomStrategy { export class NativeShadowDomStrategy extends ShadowDomStrategy {
constructor() { _styleUrlResolver: StyleUrlResolver;
constructor(styleUrlResolver: StyleUrlResolver) {
super(); super();
this._styleUrlResolver = styleUrlResolver;
} }
attachTemplate(el:Element, view:View){ attachTemplate(el:Element, view:View){
moveViewNodesIntoParent(el.createShadowRoot(), view); _moveViewNodesIntoParent(DOM.createShadowRoot(el), view);
} }
constructLightDom(lightDomView:View, shadowDomView:View, el:Element){ constructLightDom(lightDomView:View, shadowDomView:View, el:Element){
@ -62,17 +111,47 @@ export class NativeShadowDomStrategy extends ShadowDomStrategy {
return []; return [];
} }
extractStyles(): boolean { transformStyleText(cssText: string, baseUrl: string, component: Type) {
return false; return this._styleUrlResolver.resolveUrls(cssText, baseUrl);
}
getShimComponent(component: Type): ShimComponent {
return new ShimNativeComponent(component);
} }
} }
function moveViewNodesIntoParent(parent, view) { function _moveViewNodesIntoParent(parent, view) {
for (var i = 0; i < view.nodes.length; ++i) { for (var i = 0; i < view.nodes.length; ++i) {
DOM.appendChild(parent, view.nodes[i]); DOM.appendChild(parent, view.nodes[i]);
} }
} }
var _componentUIDs: Map<Type, int> = MapWrapper.create();
var _nextComponentUID: int = 0;
function _getComponentId(component: Type) {
var id = MapWrapper.get(_componentUIDs, component);
if (isBlank(id)) {
id = _nextComponentUID++;
MapWrapper.set(_componentUIDs, component, id);
}
return id;
}
// Return the attribute to be added to the component
function _getHostAttribute(id: int) {
return `_nghost-${id}`;
}
// Returns the attribute to be added on every single nodes in the component
function _getContentAttribute(id: int) {
return `_ngcontent-${id}`;
}
function _shimCssForComponent(cssText: string, component: Type): string {
var id = _getComponentId(component);
var shadowCss = new ShadowCss();
return shadowCss.shimCssText(cssText, _getContentAttribute(id), _getHostAttribute(id));
}
// Reset the component cache - used for tests only
export function resetShadowDomCache() {
MapWrapper.clear(_componentUIDs);
_nextComponentUID = 0;
}

View File

@ -1,8 +1,11 @@
import {XHR} from 'angular2/src/core/compiler/xhr/xhr'; import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {ListWrapper} from 'angular2/src/facade/collection'; import {ListWrapper} from 'angular2/src/facade/collection';
import { import {
isBlank, isBlank,
isPresent,
RegExp, RegExp,
RegExpWrapper, RegExpWrapper,
StringWrapper, StringWrapper,
@ -13,20 +16,38 @@ import {
PromiseWrapper, PromiseWrapper,
} from 'angular2/src/facade/async'; } from 'angular2/src/facade/async';
/**
* Inline @import rules in the given CSS.
*
* When an @import rules is inlined, it's url are rewritten.
*/
export class StyleInliner { export class StyleInliner {
_xhr: XHR; _xhr: XHR;
_urlResolver: UrlResolver;
_styleUrlResolver: StyleUrlResolver;
constructor(xhr: XHR) { constructor(xhr: XHR, styleUrlResolver: StyleUrlResolver, urlResolver: UrlResolver) {
this._xhr = xhr; this._xhr = xhr;
this._urlResolver = urlResolver;
this._styleUrlResolver = styleUrlResolver;
} }
// TODO(vicb): handle base url /**
* Inline the @imports rules in the given CSS text.
*
* The baseUrl is required to rewrite URLs in the inlined content.
*
* @param {string} cssText
* @param {string} baseUrl
* @returns {*} a Promise<string> when @import rules are present, a string otherwise
*/
// TODO(vicb): Union types: returns either a Promise<string> or a string // TODO(vicb): Union types: returns either a Promise<string> or a string
inlineImports(cssText: string) { // TODO(vicb): commented out @import rules should not be inlined
return this._inlineImports(cssText, []); inlineImports(cssText: string, baseUrl: string) {
return this._inlineImports(cssText, baseUrl, []);
} }
_inlineImports(cssText: string, inlinedUrls: List<string>) { _inlineImports(cssText: string, baseUrl: string, inlinedUrls: List<string>) {
var partIndex = 0; var partIndex = 0;
var parts = StringWrapper.split(cssText, _importRe); var parts = StringWrapper.split(cssText, _importRe);
@ -38,13 +59,20 @@ export class StyleInliner {
var promises = []; var promises = [];
while (partIndex < parts.length - 1) { while (partIndex < parts.length - 1) {
// prefix is the content before the @import rule
var prefix = parts[partIndex]; var prefix = parts[partIndex];
// rule is the parameter of the @import rule
var rule = parts[partIndex + 1]; var rule = parts[partIndex + 1];
var url = _extractUrl(rule); var url = _extractUrl(rule);
if (isPresent(url)) {
url = this._urlResolver.resolve(baseUrl, url);
}
var mediaQuery = _extractMediaQuery(rule); var mediaQuery = _extractMediaQuery(rule);
var promise; var promise;
if (isBlank(url) || ListWrapper.contains(inlinedUrls, url)) {
if (isBlank(url)) {
promise = PromiseWrapper.resolve(`/* Invalid import rule: "@import ${rule};" */`);
} else if (ListWrapper.contains(inlinedUrls, url)) {
// The current import rule has already been inlined, return the prefix only // The current import rule has already been inlined, return the prefix only
// Importing again might cause a circular dependency // Importing again might cause a circular dependency
promise = PromiseWrapper.resolve(prefix); promise = PromiseWrapper.resolve(prefix);
@ -54,13 +82,15 @@ export class StyleInliner {
this._xhr.get(url), this._xhr.get(url),
(css) => { (css) => {
// resolve nested @import rules // resolve nested @import rules
css = this._inlineImports(css, inlinedUrls); css = this._inlineImports(css, url, inlinedUrls);
if (PromiseWrapper.isPromise(css)) { if (PromiseWrapper.isPromise(css)) {
// wait until nested @import are inlined // wait until nested @import are inlined
return css.then((css) => prefix + _wrapInMediaRule(css, mediaQuery)+ '\n') ; return css.then((css) => {
return prefix + this._transformImportedCss(css, mediaQuery, url) + '\n'
}) ;
} else { } else {
// there are no nested @import, return the css // there are no nested @import, return the css
return prefix + _wrapInMediaRule(css, mediaQuery) + '\n'; return prefix + this._transformImportedCss(css, mediaQuery, url) + '\n';
} }
}, },
(error) => `/* failed to import ${url} */\n` (error) => `/* failed to import ${url} */\n`
@ -70,20 +100,19 @@ export class StyleInliner {
partIndex += 2; partIndex += 2;
} }
return PromiseWrapper.then( return PromiseWrapper.all(promises).then(function (cssParts) {
PromiseWrapper.all(promises), var cssText = cssParts.join('');
function (cssParts) { if (partIndex < parts.length) {
var cssText = cssParts.join(''); // append then content located after the last @import rule
if (partIndex < parts.length) { cssText += parts[partIndex];
// append whatever css located after the last @import rule
cssText += parts[partIndex];
}
return cssText;
},
function(e) {
throw 'error';
} }
); return cssText;
});
}
_transformImportedCss(css: string, mediaQuery: string, url: string): string {
css = this._styleUrlResolver.resolveUrls(css, url);
return _wrapInMediaRule(css, mediaQuery);
} }
} }
@ -106,7 +135,7 @@ function _extractMediaQuery(importRule: string): string {
} }
// Wraps the css in a media rule when the media query is not null // Wraps the css in a media rule when the media query is not null
function _wrapInMediaRule(css: string, query: string) { function _wrapInMediaRule(css: string, query: string): string {
return (isBlank(query)) ? css : `@media ${query} {\n${css}\n}`; return (isBlank(query)) ? css : `@media ${query} {\n${css}\n}`;
} }

View File

@ -4,6 +4,9 @@
import {RegExp, RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang'; import {RegExp, RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang';
import {UrlResolver} from './url_resolver'; import {UrlResolver} from './url_resolver';
/**
* Rewrites URLs by resolving '@import' and 'url()' URLs from the given base URL.
*/
export class StyleUrlResolver { export class StyleUrlResolver {
_resolver: UrlResolver; _resolver: UrlResolver;
@ -31,5 +34,6 @@ export class StyleUrlResolver {
} }
var _cssUrlRe = RegExpWrapper.create('(url\\()([^)]*)(\\))'); var _cssUrlRe = RegExpWrapper.create('(url\\()([^)]*)(\\))');
// TODO(vicb): handle the media query part
var _cssImportRe = RegExpWrapper.create('(@import[\\s]+(?!url\\())([^;]*)(;)'); var _cssImportRe = RegExpWrapper.create('(@import[\\s]+(?!url\\())([^;]*)(;)');
var _quoteRe = RegExpWrapper.create('[\'"]'); var _quoteRe = RegExpWrapper.create('[\'"]');

View File

@ -1,21 +1,29 @@
import {isBlank, isPresent, BaseException, stringify} from 'angular2/src/facade/lang'; import {isBlank, isPresent, BaseException, stringify} from 'angular2/src/facade/lang';
import {DOM, Element} from 'angular2/src/facade/dom'; import {DOM, Element} from 'angular2/src/facade/dom';
import {StringMapWrapper, StringMap} from 'angular2/src/facade/collection'; import {Map, MapWrapper, StringMapWrapper, StringMap} from 'angular2/src/facade/collection';
import {XHR} from './xhr/xhr'; import {XHR} from './xhr/xhr';
import {Template} from 'angular2/src/core/annotations/template'; import {Template} from 'angular2/src/core/annotations/template';
import {UrlResolver} from './url_resolver';
/** /**
* Strategy to load component templates. * Strategy to load component templates.
*/ */
export class TemplateLoader { export class TemplateLoader {
_xhr: XHR; _xhr: XHR;
_cache: StringMap; _htmlCache: StringMap;
_baseUrls: Map<Type, string>;
_urlCache: Map<Type, string>;
_urlResolver: UrlResolver;
constructor(xhr: XHR) { constructor(xhr: XHR, urlResolver: UrlResolver) {
this._xhr = xhr; this._xhr = xhr;
this._cache = StringMapWrapper.create(); this._urlResolver = urlResolver;
this._htmlCache = StringMapWrapper.create();
this._baseUrls = MapWrapper.create();
this._urlCache = MapWrapper.create();
} }
// TODO(vicb): union type: return an Element or a Promise<Element> // TODO(vicb): union type: return an Element or a Promise<Element>
@ -25,20 +33,43 @@ export class TemplateLoader {
} }
if (isPresent(template.url)) { if (isPresent(template.url)) {
var url = template.url; var url = this.getTemplateUrl(template);
var promise = StringMapWrapper.get(this._cache, url); var promise = StringMapWrapper.get(this._htmlCache, url);
if (isBlank(promise)) { if (isBlank(promise)) {
promise = this._xhr.get(url).then(function (html) { promise = this._xhr.get(url).then(function (html) {
var template = DOM.createTemplate(html); var template = DOM.createTemplate(html);
return template; return template;
}); });
StringMapWrapper.set(this._cache, url, promise); StringMapWrapper.set(this._htmlCache, url, promise);
} }
return promise; return promise;
} }
throw new BaseException(`Templates should have either their url or inline property set`); throw new BaseException('Templates should have either their url or inline property set');
}
setBaseUrl(template: Template, baseUrl: string) {
MapWrapper.set(this._baseUrls, template, baseUrl);
MapWrapper.delete(this._urlCache, template);
}
getTemplateUrl(template: Template) {
if (!MapWrapper.contains(this._urlCache, template)) {
var baseUrl = MapWrapper.get(this._baseUrls, template);
if (isBlank(baseUrl)) {
throw new BaseException('The template base URL is not set');
}
var templateUrl;
if (isPresent(template.url)) {
templateUrl = this._urlResolver.resolve(baseUrl, template.url);
} else {
templateUrl = baseUrl;
}
MapWrapper.set(this._urlCache, template, templateUrl);
}
return MapWrapper.get(this._urlCache, template);
} }
} }

View File

@ -1,8 +1,8 @@
import {isPresent, isBlank, RegExpWrapper} from 'angular2/src/facade/lang'; import {isPresent, isBlank, RegExpWrapper, BaseException} from 'angular2/src/facade/lang';
import {DOM, Element} from 'angular2/src/facade/dom'; import {DOM, AnchorElement} from 'angular2/src/facade/dom';
export class UrlResolver { export class UrlResolver {
static a: Element; static a: AnchorElement;
constructor() { constructor() {
if (isBlank(UrlResolver.a)) { if (isBlank(UrlResolver.a)) {

View File

@ -1,4 +1,5 @@
import {DOM, Element, Node, Text, DocumentFragment} from 'angular2/src/facade/dom'; import {DOM, Element, Node, Text, DocumentFragment} from 'angular2/src/facade/dom';
import {Promise} from 'angular2/src/facade/async';
import {ListWrapper, MapWrapper, StringMapWrapper, List} from 'angular2/src/facade/collection'; import {ListWrapper, MapWrapper, StringMapWrapper, List} from 'angular2/src/facade/collection';
import {AST, ContextWithVariableBindings, ChangeDispatcher, ProtoChangeDetector, ChangeDetector, ChangeRecord} import {AST, ContextWithVariableBindings, ChangeDispatcher, ProtoChangeDetector, ChangeDetector, ChangeRecord}
from 'angular2/change_detection'; from 'angular2/change_detection';
@ -273,6 +274,8 @@ export class ProtoView {
isTemplateElement:boolean; isTemplateElement:boolean;
shadowDomStrategy: ShadowDomStrategy; shadowDomStrategy: ShadowDomStrategy;
_viewPool: ViewPool; _viewPool: ViewPool;
stylePromises: List<Promise>;
constructor( constructor(
template:Element, template:Element,
protoChangeDetector:ProtoChangeDetector, protoChangeDetector:ProtoChangeDetector,
@ -290,6 +293,7 @@ export class ProtoView {
this.isTemplateElement = DOM.isTemplateElement(this.element); this.isTemplateElement = DOM.isTemplateElement(this.element);
this.shadowDomStrategy = shadowDomStrategy; this.shadowDomStrategy = shadowDomStrategy;
this._viewPool = new ViewPool(VIEW_POOL_CAPACITY); this._viewPool = new ViewPool(VIEW_POOL_CAPACITY);
this.stylePromises = [];
} }
// TODO(rado): hostElementInjector should be moved to hydrate phase. // TODO(rado): hostElementInjector should be moved to hydrate phase.
@ -539,8 +543,7 @@ export class ProtoView {
new ProtoElementInjector(null, 0, [cmpType], true)); new ProtoElementInjector(null, 0, [cmpType], true));
binder.componentDirective = rootComponentAnnotatedType; binder.componentDirective = rootComponentAnnotatedType;
binder.nestedProtoView = protoView; binder.nestedProtoView = protoView;
var shimComponent = shadowDomStrategy.getShimComponent(cmpType); shadowDomStrategy.shimHostElement(cmpType, insertionElement);
shimComponent.shimHostElement(insertionElement);
return rootProtoView; return rootProtoView;
} }
} }

View File

@ -11,9 +11,11 @@ export 'dart:html' show
Element, Element,
location, location,
Node, Node,
ShadowRoot,
StyleElement, StyleElement,
TemplateElement, TemplateElement,
InputElement, InputElement,
AnchorElement,
Text, Text,
window; window;
@ -127,6 +129,8 @@ class DOM {
el.text = css; el.text = css;
return el; return el;
} }
static ShadowRoot createShadowRoot(Element el) => el.createShadowRoot();
static ShadowRoot getShadowRoot(Element el) => el.shadowRoot;
static clone(Node node) => node.clone(true); static clone(Node node) => node.clone(true);
static bool hasProperty(Element element, String name) => static bool hasProperty(Element element, String name) =>
new JsObject.fromBrowserObject(element).hasProperty(name); new JsObject.fromBrowserObject(element).hasProperty(name);

View File

@ -6,8 +6,10 @@ export var Node = window.Node;
export var NodeList = window.NodeList; export var NodeList = window.NodeList;
export var Text = window.Text; export var Text = window.Text;
export var Element = window.HTMLElement; export var Element = window.HTMLElement;
export var AnchorElement = window.HTMLAnchorElement;
export var TemplateElement = window.HTMLTemplateElement; export var TemplateElement = window.HTMLTemplateElement;
export var StyleElement = window.HTMLStyleElement; export var StyleElement = window.HTMLStyleElement;
export var ShadowRoot = window.ShadowRoot;
export var document = window.document; export var document = window.document;
export var location = window.location; export var location = window.location;
export var gc = window.gc ? () => window.gc() : () => null; export var gc = window.gc ? () => window.gc() : () => null;
@ -144,6 +146,12 @@ export class DOM {
style.innerText = css; style.innerText = css;
return style; return style;
} }
static createShadowRoot(el: Element): ShadowRoot {
return el.createShadowRoot();
}
static getShadowRoot(el: Element): ShadowRoot {
return el.shadowRoot;
}
static clone(node:Node) { static clone(node:Node) {
return node.cloneNode(true); return node.cloneNode(true);
} }

View File

@ -60,7 +60,7 @@ export class XHRMock extends XHR {
if (this._expectations.length > 0) { if (this._expectations.length > 0) {
var expectation = this._expectations[0]; var expectation = this._expectations[0];
if (expectation.url === url) { if (expectation.url == url) {
ListWrapper.remove(this._expectations, expectation); ListWrapper.remove(this._expectations, expectation);
request.complete(expectation.response); request.complete(expectation.response);
return; return;

View File

@ -15,6 +15,9 @@ import {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step'
import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control'; import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver'; import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {ComponentUrlMapper, RuntimeComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection'; import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection';
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
@ -41,7 +44,10 @@ export function main() {
function createCompiler(processClosure) { function createCompiler(processClosure) {
var steps = [new MockStep(processClosure)]; var steps = [new MockStep(processClosure)];
return new TestableCompiler(reader, steps, new FakeTemplateLoader(), tplResolver); var urlResolver = new FakeUrlResolver();
var tplLoader = new FakeTemplateLoader(urlResolver);
return new TestableCompiler(reader, steps,tplLoader, tplResolver,
urlResolver, new ComponentUrlMapper());
} }
it('should run the steps and return the ProtoView of the root element', (done) => { it('should run the steps and return the ProtoView of the root element', (done) => {
@ -66,6 +72,32 @@ export function main() {
}); });
}); });
it('should wait for async styles to be resolved', (done) => {
var styleResolved = false;
var completer = PromiseWrapper.completer();
var compiler = createCompiler( (parent, current, control) => {
var protoView = new ProtoView(current.element, null, null);
ListWrapper.push(protoView.stylePromises, completer.promise.then((_) => {
styleResolved = true;
}));
current.inheritedProtoView = protoView;
});
// It should always return a Promise because the style is async
var pvPromise = compiler.compile(MainComponent);
expect(pvPromise).toBePromise();
expect(styleResolved).toEqual(false);
// The Promise should resolve after the style is ready
completer.resolve(null);
pvPromise.then((protoView) => {
expect(styleResolved).toEqual(true);
done();
});
});
it('should load nested components', (done) => { it('should load nested components', (done) => {
var compiler = createCompiler( (parent, current, control) => { var compiler = createCompiler( (parent, current, control) => {
if (DOM.hasClass(current.element, 'nested')) { if (DOM.hasClass(current.element, 'nested')) {
@ -102,8 +134,8 @@ export function main() {
it('should re-use components being compiled', (done) => { it('should re-use components being compiled', (done) => {
var nestedElBinders = []; var nestedElBinders = [];
var compiler = createCompiler( (parent, current, control) => { var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null);
if (DOM.hasClass(current.element, 'nested')) { if (DOM.hasClass(current.element, 'nested')) {
current.inheritedProtoView = new ProtoView(current.element, null, null);
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null); current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
current.componentDirective = reader.read(NestedComponent); current.componentDirective = reader.read(NestedComponent);
ListWrapper.push(nestedElBinders, current.inheritedElementBinder); ListWrapper.push(nestedElBinders, current.inheritedElementBinder);
@ -134,9 +166,12 @@ export function main() {
describe('(mixed async, sync TemplateLoader)', () => { describe('(mixed async, sync TemplateLoader)', () => {
var reader = new DirectiveMetadataReader(); var reader = new DirectiveMetadataReader();
function createCompiler(processClosure, resolver: TemplateResolver) { function createCompiler(processClosure, templateResolver: TemplateResolver) {
var steps = [new MockStep(processClosure)]; var steps = [new MockStep(processClosure)];
return new TestableCompiler(reader, steps, new FakeTemplateLoader(), resolver); var urlResolver = new FakeUrlResolver();
var tplLoader = new FakeTemplateLoader(urlResolver);
return new TestableCompiler(reader, steps, tplLoader, templateResolver,
urlResolver, new ComponentUrlMapper());
} }
function createNestedComponentSpec(name, resolver: TemplateResolver, error:string = null) { function createNestedComponentSpec(name, resolver: TemplateResolver, error:string = null) {
@ -167,47 +202,72 @@ export function main() {
}); });
} }
var resolver = new FakeTemplateResolver(); var templateResolver = new FakeTemplateResolver();
resolver.setSync(ParentComponent); templateResolver.setSync(ParentComponent);
resolver.setSync(NestedComponent); templateResolver.setSync(NestedComponent);
createNestedComponentSpec('(sync -> sync)', resolver); createNestedComponentSpec('(sync -> sync)', templateResolver);
resolver = new FakeTemplateResolver(); templateResolver = new FakeTemplateResolver();
resolver.setAsync(ParentComponent); templateResolver.setAsync(ParentComponent);
resolver.setSync(NestedComponent); templateResolver.setSync(NestedComponent);
createNestedComponentSpec('(async -> sync)', resolver); createNestedComponentSpec('(async -> sync)', templateResolver);
resolver = new FakeTemplateResolver(); templateResolver = new FakeTemplateResolver();
resolver.setSync(ParentComponent); templateResolver.setSync(ParentComponent);
resolver.setAsync(NestedComponent); templateResolver.setAsync(NestedComponent);
createNestedComponentSpec('(sync -> async)', resolver); createNestedComponentSpec('(sync -> async)', templateResolver);
resolver = new FakeTemplateResolver(); templateResolver = new FakeTemplateResolver();
resolver.setAsync(ParentComponent); templateResolver.setAsync(ParentComponent);
resolver.setAsync(NestedComponent); templateResolver.setAsync(NestedComponent);
createNestedComponentSpec('(async -> async)', resolver); createNestedComponentSpec('(async -> async)', templateResolver);
resolver = new FakeTemplateResolver(); templateResolver = new FakeTemplateResolver();
resolver.setError(ParentComponent); templateResolver.setError(ParentComponent);
resolver.setSync(NestedComponent); templateResolver.setSync(NestedComponent);
createNestedComponentSpec('(error -> sync)', resolver, createNestedComponentSpec('(error -> sync)', templateResolver,
'Failed to load the template for ParentComponent'); 'Failed to load the template for ParentComponent');
// TODO(vicb): Check why errors this fails with Dart // TODO(vicb): Check why errors this fails with Dart
// TODO(vicb): The Promise is rejected with the correct error but an exc is thrown before // TODO(vicb): The Promise is rejected with the correct error but an exc is thrown before
//resolver = new FakeTemplateResolver(); //templateResolver = new FakeTemplateResolver();
//resolver.setSync(ParentComponent); //templateResolver.setSync(ParentComponent);
//resolver.setError(NestedComponent); //templateResolver.setError(NestedComponent);
//createNestedComponentSpec('(sync -> error)', resolver, //createNestedComponentSpec('(sync -> error)', templateResolver,
// 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent'); // 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent');
// //
//resolver = new FakeTemplateResolver(); //templateResolver = new FakeTemplateResolver();
//resolver.setAsync(ParentComponent); //templateResolver.setAsync(ParentComponent);
//resolver.setError(NestedComponent); //templateResolver.setError(NestedComponent);
//createNestedComponentSpec('(async -> error)', resolver, //createNestedComponentSpec('(async -> error)', templateResolver,
// 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent'); // 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent');
}); });
describe('URL resolution', () => {
it('should resolve template URLs by combining application, component and template URLs', (done) => {
var steps = [new MockStep((parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null);
})];
var reader = new DirectiveMetadataReader();
var tplResolver = new FakeTemplateResolver();
var urlResolver = new FakeUrlResolver();
var tplLoader = new FakeTemplateLoader(urlResolver);
var template = new Template({inline: '<div></div>', url: '/tpl.html'});
var cmpUrlMapper = new RuntimeComponentUrlMapper();
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp');
var compiler = new TestableCompiler(reader, steps, tplLoader, tplResolver,
urlResolver, cmpUrlMapper);
tplResolver.forceSync();
tplResolver.setTemplate(MainComponent, template);
compiler.compile(MainComponent).then((protoView) => {
expect(tplLoader.getTemplateUrl(template)).toEqual('http://www.app.com/cmp/tpl.html');
done();
});
})
});
}); });
} }
@ -231,9 +291,17 @@ class TestableCompiler extends Compiler {
steps:List; steps:List;
constructor(reader:DirectiveMetadataReader, steps:List<CompileStep>, loader: TemplateLoader, constructor(reader:DirectiveMetadataReader, steps:List<CompileStep>, loader: TemplateLoader,
resolver: TemplateResolver) { templateResolver: TemplateResolver, urlResolver: UrlResolver, cmpUrlMapper: ComponentUrlMapper) {
super(dynamicChangeDetection, loader, reader, new Parser(new Lexer()), new CompilerCache(), super(dynamicChangeDetection,
new NativeShadowDomStrategy(), resolver); loader,
reader,
new Parser(new Lexer()),
new CompilerCache(),
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
templateResolver,
cmpUrlMapper,
urlResolver);
this.steps = steps; this.steps = steps;
} }
@ -253,9 +321,23 @@ class MockStep extends CompileStep {
} }
} }
class FakeTemplateLoader extends TemplateLoader { class FakeUrlResolver extends UrlResolver {
constructor() { constructor() {
super(null); super();
}
resolve(baseUrl: string, url: string): string {
if (baseUrl === null && url == './') {
return 'http://www.app.com';
};
return baseUrl + url;
}
}
class FakeTemplateLoader extends TemplateLoader {
constructor(urlResolver: UrlResolver) {
super(null, urlResolver);
} }
load(template: Template) { load(template: Template) {
@ -307,14 +389,14 @@ class FakeTemplateResolver extends TemplateResolver {
} }
if (ListWrapper.contains(this._syncCmp, component)) { if (ListWrapper.contains(this._syncCmp, component)) {
return new Template({inline: html}); return template;
} }
if (ListWrapper.contains(this._asyncCmp, component)) { if (ListWrapper.contains(this._asyncCmp, component)) {
return new Template({url: html}); return new Template({url: html});
} }
if (this._forceSync) return new Template({inline: html}); if (this._forceSync) return template;
if (this._forceAsync) return new Template({url: html}); if (this._forceAsync) return new Template({url: html});
throw 'No template'; throw 'No template';

View File

@ -0,0 +1,25 @@
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
import {
ComponentUrlMapper,
RuntimeComponentUrlMapper
} from 'angular2/src/core/compiler/component_url_mapper';
export function main() {
describe('RuntimeComponentUrlMapper', () => {
it('should return the registered URL', () => {
var url = 'http://path/to/component';
var mapper = new RuntimeComponentUrlMapper();
mapper.setComponentUrl(SomeComponent, url);
expect(mapper.getUrl(SomeComponent)).toEqual(url);
});
it('should fallback to ComponentUrlMapper', () => {
var mapper = new ComponentUrlMapper();
var runtimeMapper = new RuntimeComponentUrlMapper();
expect(runtimeMapper.getUrl(SomeComponent)).toEqual(mapper.getUrl(SomeComponent));
});
});
}
class SomeComponent {}

View File

@ -14,6 +14,9 @@ import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_str
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock'; import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config'; import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations'; import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
import {Template} from 'angular2/src/core/annotations/template'; import {Template} from 'angular2/src/core/annotations/template';
@ -28,13 +31,16 @@ export function main() {
var compiler, tplResolver; var compiler, tplResolver;
function createCompiler(tplResolver, changedDetection) { function createCompiler(tplResolver, changedDetection) {
var urlResolver = new UrlResolver();
return new Compiler(changedDetection, return new Compiler(changedDetection,
new TemplateLoader(null), new TemplateLoader(null, null),
new DirectiveMetadataReader(), new DirectiveMetadataReader(),
new Parser(new Lexer()), new Parser(new Lexer()),
new CompilerCache(), new CompilerCache(),
new NativeShadowDomStrategy(), new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
tplResolver tplResolver,
new ComponentUrlMapper(),
urlResolver
); );
} }

View File

@ -72,7 +72,7 @@ export function main() {
current.inheritedProtoView = new ProtoView( current.inheritedProtoView = new ProtoView(
current.element, current.element,
new DynamicProtoChangeDetector(normalizeBlank(registry)), new DynamicProtoChangeDetector(normalizeBlank(registry)),
new NativeShadowDomStrategy()); new NativeShadowDomStrategy(null));
} else if (isPresent(parent)) { } else if (isPresent(parent)) {
current.inheritedProtoView = parent.inheritedProtoView; current.inheritedProtoView = parent.inheritedProtoView;
} }
@ -380,7 +380,7 @@ export function main() {
var results = pipeline.process(el('<div viewroot prop-binding directives></div>')); var results = pipeline.process(el('<div viewroot prop-binding directives></div>'));
var pv = results[0].inheritedProtoView; var pv = results[0].inheritedProtoView;
results[0].inheritedElementBinder.nestedProtoView = new ProtoView( results[0].inheritedElementBinder.nestedProtoView = new ProtoView(
el('<div></div>'), new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy()); el('<div></div>'), new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
instantiateView(pv); instantiateView(pv);
evalContext.prop1 = 'a'; evalContext.prop1 = 'a';
@ -416,7 +416,7 @@ export function main() {
var results = pipeline.process(el('<div viewroot prop-binding directives></div>')); var results = pipeline.process(el('<div viewroot prop-binding directives></div>'));
var pv = results[0].inheritedProtoView; var pv = results[0].inheritedProtoView;
results[0].inheritedElementBinder.nestedProtoView = new ProtoView( results[0].inheritedElementBinder.nestedProtoView = new ProtoView(
el('<div></div>'), new DynamicProtoChangeDetector(registry), new NativeShadowDomStrategy()); el('<div></div>'), new DynamicProtoChangeDetector(registry), new NativeShadowDomStrategy(null));
instantiateView(pv); instantiateView(pv);
evalContext.prop1 = 'a'; evalContext.prop1 = 'a';

View File

@ -21,7 +21,7 @@ export function main() {
current.variableBindings = MapWrapper.createFromStringMap(variableBindings); current.variableBindings = MapWrapper.createFromStringMap(variableBindings);
} }
current.inheritedElementBinder = new ElementBinder(null, null, null); current.inheritedElementBinder = new ElementBinder(null, null, null);
}), new ProtoViewBuilder(dynamicChangeDetection, new NativeShadowDomStrategy())]); }), new ProtoViewBuilder(dynamicChangeDetection, new NativeShadowDomStrategy(null))]);
} }
it('should not create a ProtoView when the isViewRoot flag is not set', () => { it('should not create a ProtoView when the isViewRoot flag is not set', () => {

View File

@ -0,0 +1,137 @@
import {
describe,
beforeEach,
expect,
it,
iit,
ddescribe,
el,
SpyObject,
proxy,
} from 'angular2/test_lib';
import {CompilePipeline} from 'angular2/src/core/compiler/pipeline/compile_pipeline';
import {ResolveCss} from 'angular2/src/core/compiler/pipeline/resolve_css';
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 {Component} from 'angular2/src/core/annotations/annotations';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {ProtoView} from 'angular2/src/core/compiler/view';
import {IMPLEMENTS, Type, stringify} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/facade/dom';
import {PromiseWrapper} from 'angular2/src/facade/async';
export function main() {
describe('ResolveCss', () => {
function createPipeline(strategy:ShadowDomStrategy) {
var annotation = new Component({selector: 'selector'});
var meta = new DirectiveMetadata(SomeComponent, annotation);
var resolveCss = new ResolveCss(meta, strategy, 'http://base');
return new CompilePipeline([
new MockStep((parent, current, control) => {
current.inheritedProtoView = new ProtoView(null, null, null);
}),
resolveCss
]);
}
it('it should set ignoreBindings to true for style elements', () => {
var strategy = new DummyStrategy();
strategy.spy('transformStyleText').andCallFake((a, b, c) => '.css {}');
strategy.spy('handleStyleElement');
var pipeline = createPipeline(strategy);
var results = pipeline.process(el('<div><style></style></div>'));
expect(results[0].ignoreBindings).toBe(false);
expect(results[1].ignoreBindings).toBe(true);
});
it('should delegate the handling of style elements to the strategy', () => {
var strategy = new DummyStrategy();
strategy.spy('transformStyleText').andCallFake((a, b, c) => '.css {}');
strategy.spy('handleStyleElement');
var pipeline = createPipeline(strategy);
var template = el('<div></div>');
var styleEl = el('<style></style>');
DOM.appendChild(template, styleEl);
pipeline.process(template);
expect(strategy.spy('handleStyleElement')).toHaveBeenCalledWith(styleEl);
});
it('should handle css transformed synchronously', () => {
var strategy = new DummyStrategy();
strategy.spy('transformStyleText').andCallFake((css, url, cmp) => {
return `${css}, ${url}, ${stringify(cmp)}`;
});
strategy.spy('handleStyleElement');
var pipeline = createPipeline(strategy);
var template = el('<div></div>');
var styleEl = el('<style>/*css*/</style>');
DOM.appendChild(template, styleEl);
var results = pipeline.process(template);
expect(styleEl).toHaveText('/*css*/, http://base, SomeComponent');
expect(results[0].inheritedProtoView.stylePromises.length).toBe(0);
});
it('should handle css transformed asynchronously', (done) => {
var completer = PromiseWrapper.completer();
var strategy = new DummyStrategy();
var futureCss;
strategy.spy('transformStyleText').andCallFake((css, url, cmp) => {
futureCss = `${css}, ${url}, ${stringify(cmp)}`;
return completer.promise;
});
strategy.spy('handleStyleElement');
var pipeline = createPipeline(strategy);
var template = el('<div></div>');
var styleEl = el('<style>/*css*/</style>');
DOM.appendChild(template, styleEl);
var results = pipeline.process(template);
// The css should be empty before the style promise is resolved
expect(styleEl).toHaveText('');
expect(results[0].inheritedProtoView.stylePromises[0]).toBe(completer.promise);
completer.resolve(futureCss);
// TODO(vicb): refactor once we have better support for async tests
completer.promise.then((_) => {
expect(styleEl).toHaveText('/*css*/, http://base, SomeComponent');
done();
});
});
});
}
@proxy
@IMPLEMENTS(ShadowDomStrategy)
class DummyStrategy extends SpyObject {
noSuchMethod(m) {
return super.noSuchMethod(m)
}
}
class SomeComponent {}
class MockStep extends CompileStep {
processClosure:Function;
constructor(process) {
super();
this.processClosure = process;
}
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
this.processClosure(parent, current, control);
}
}

View File

@ -1,102 +0,0 @@
import {describe, beforeEach, expect, it, iit, ddescribe, el} from 'angular2/test_lib';
import {CompilePipeline} from 'angular2/src/core/compiler/pipeline/compile_pipeline';
import {ShimShadowCss} from 'angular2/src/core/compiler/pipeline/shim_shadow_css';
import {ShimComponent} from 'angular2/src/core/compiler/shadow_dom_emulation/shim_component';
import {Component} from 'angular2/src/core/annotations/annotations';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {Type} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/facade/dom';
export function main() {
describe('ShimShadowCss', () => {
function createPipeline(strategy:ShadowDomStrategy, styleHost) {
var component = new Component({selector: 'selector'});
var meta = new DirectiveMetadata(null, component);
var shimShadowCss = new ShimShadowCss(meta, strategy, styleHost);
return new CompilePipeline([shimShadowCss]);
}
it('it should set ignoreBindings to true for style elements', () => {
var host = el('<div></div>');
var pipeline = createPipeline(new FakeStrategy(false), host);
var results = pipeline.process(el('<div><style></style></div>'));
expect(results[0].ignoreBindings).toBe(false);
expect(results[1].ignoreBindings).toBe(true);
});
it('should not extract the styles when extractStyles() is false', () => {
var host = el('<div></div>');
var pipeline = createPipeline(new FakeStrategy(false), host);
var template = el('<style>.s{}</style>');
pipeline.process(template);
expect(template).toHaveText('.s{}');
});
it('should move the styles to the host when extractStyles() is true', () => {
var host = el('<div></div>');
var pipeline = createPipeline(new FakeStrategy(true), host);
var template = el('<div><style>.s{}</style></div>');
pipeline.process(template);
expect(template).toHaveText('');
expect(host).toHaveText('/* shim */.s{}');
});
it('should preserve original content when moving styles', () => {
var host = el('<div>original content</div>');
var pipeline = createPipeline(new FakeStrategy(true), host);
var template = el('<div><style>.s{}</style></div>');
pipeline.process(template);
expect(template).toHaveText('');
expect(host).toHaveText('/* shim */.s{}original content');
});
it('should preserve attributes on moved style', () => {
var host = el('<div></div>');
var pipeline = createPipeline(new FakeStrategy(true), host);
var template = el('<div><style media="print">.s{}</style></div>');
pipeline.process(template);
var styleEl = DOM.firstChild(host);
expect(DOM.getAttribute(styleEl, 'media')).toEqual('print');
});
it('should move the styles to the host in the original order', () => {
var host = el('<div></div>');
var pipeline = createPipeline(new FakeStrategy(true), host);
var template = el('<div><style>.s1{}</style><style>.s2{}</style></div>');
pipeline.process(template);
expect(host).toHaveText('/* shim */.s1{}/* shim */.s2{}');
});
});
}
class FakeStrategy extends ShadowDomStrategy {
_extractStyles: boolean;
constructor(extractStyles: boolean) {
super();
this._extractStyles = extractStyles;
}
extractStyles(): boolean {
return this._extractStyles;
}
getShimComponent(component: Type): ShimComponent {
return new FakeShimComponent(component);
}
}
class FakeShimComponent extends ShimComponent {
constructor(component: Type) {
super(component);
}
shimCssText(cssText: string): string {
return '/* shim */' + cssText;
}
}

View File

@ -5,20 +5,19 @@ import {ShimShadowDom} from 'angular2/src/core/compiler/pipeline/shim_shadow_dom
import {CompileElement} from 'angular2/src/core/compiler/pipeline/compile_element'; import {CompileElement} from 'angular2/src/core/compiler/pipeline/compile_element';
import {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step'; import {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step';
import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control'; import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control';
import {ShimComponent} from 'angular2/src/core/compiler/shadow_dom_emulation/shim_component';
import {Component} from 'angular2/src/core/annotations/annotations'; import {Component} from 'angular2/src/core/annotations/annotations';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata'; import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {Type, isBlank} from 'angular2/src/facade/lang'; import {Type, isBlank, stringify} from 'angular2/src/facade/lang';
import {DOM, Element} from 'angular2/src/facade/dom'; import {DOM, Element} from 'angular2/src/facade/dom';
export function main() { export function main() {
describe('ShimShadowDom', () => { describe('ShimShadowDom', () => {
function createPipeline(ignoreBindings: boolean) { function createPipeline(ignoreBindings: boolean) {
var component = new Component({selector: 'selector'}); var annotation = new Component({selector: 'selector'});
var meta = new DirectiveMetadata(null, component); var meta = new DirectiveMetadata(SomeComponent, annotation);
var shimShadowDom = new ShimShadowDom(meta, new FakeStrategy()); var shimShadowDom = new ShimShadowDom(meta, new FakeStrategy());
return new CompilePipeline([ return new CompilePipeline([
@ -38,22 +37,22 @@ export function main() {
it('should add the content attribute to content element', () => { it('should add the content attribute to content element', () => {
var pipeline = createPipeline(false); var pipeline = createPipeline(false);
var results = pipeline.process(el('<div></div>')); var results = pipeline.process(el('<div></div>'));
expect(DOM.getAttribute(results[0].element, '_ngcontent')).toEqual('content'); expect(DOM.getAttribute(results[0].element, 'SomeComponent-content')).toEqual('');
expect(isBlank(DOM.getAttribute(results[0].element, '_nghost'))).toBeTruthy(); expect(isBlank(DOM.getAttribute(results[0].element, 'SomeComponent-host'))).toBeTruthy();
}); });
it('should add both the content and host attributes to host element', () => { it('should add both the content and host attributes to host element', () => {
var pipeline = createPipeline(false); var pipeline = createPipeline(false);
var results = pipeline.process(el('<div class="host"></div>')); var results = pipeline.process(el('<div class="host"></div>'));
expect(DOM.getAttribute(results[0].element, '_ngcontent')).toEqual('content'); expect(DOM.getAttribute(results[0].element, 'SomeComponent-content')).toEqual('');
expect(DOM.getAttribute(results[0].element, '_nghost')).toEqual('host'); expect(DOM.getAttribute(results[0].element, 'SomeComponent-host')).toEqual('');
}); });
it('should do nothing when ignoreBindings is true', () => { it('should do nothing when ignoreBindings is true', () => {
var pipeline = createPipeline(true); var pipeline = createPipeline(true);
var results = pipeline.process(el('<div class="host"></div>')); var results = pipeline.process(el('<div class="host"></div>'));
expect(isBlank(DOM.getAttribute(results[0].element, '_ngcontent'))).toBeTruthy(); expect(isBlank(DOM.getAttribute(results[0].element, 'SomeComponent-content'))).toBeTruthy();
expect(isBlank(DOM.getAttribute(results[0].element, '_nghost'))).toBeTruthy(); expect(isBlank(DOM.getAttribute(results[0].element, 'SomeComponent-host'))).toBeTruthy();
}); });
}); });
} }
@ -63,22 +62,14 @@ class FakeStrategy extends ShadowDomStrategy {
super(); super();
} }
getShimComponent(component: Type): ShimComponent { shimContentElement(component: Type, element: Element) {
return new FakeShimComponent(component); var attrName = stringify(component) + '-content';
} DOM.setAttribute(element, attrName, '');
}
class FakeShimComponent extends ShimComponent {
constructor(component: Type) {
super(component);
} }
shimContentElement(element: Element) { shimHostElement(component: Type, element: Element) {
DOM.setAttribute(element, '_ngcontent', 'content'); var attrName = stringify(component) + '-host';
} DOM.setAttribute(element, attrName, '');
shimHostElement(element: Element) {
DOM.setAttribute(element, '_nghost', 'host');
} }
} }

View File

@ -2,6 +2,7 @@ import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular
import {StringMapWrapper, List} from 'angular2/src/facade/collection'; import {StringMapWrapper, List} from 'angular2/src/facade/collection';
import {Type} from 'angular2/src/facade/lang'; import {Type} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/facade/dom';
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection'; import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
@ -14,6 +15,11 @@ import {ShadowDomStrategy,
NativeShadowDomStrategy, NativeShadowDomStrategy,
EmulatedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; EmulatedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock'; import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations'; import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
@ -23,10 +29,13 @@ import {ViewContainer} from 'angular2/src/core/compiler/view_container';
export function main() { export function main() {
describe('integration tests', function() { describe('integration tests', function() {
var urlResolver = new UrlResolver();
var styleUrlResolver = new StyleUrlResolver(urlResolver);
var styleInliner = new StyleInliner(null, styleUrlResolver, urlResolver);
StringMapWrapper.forEach({ StringMapWrapper.forEach({
"native" : new NativeShadowDomStrategy(), "native" : new NativeShadowDomStrategy(styleUrlResolver),
"emulated" : new EmulatedShadowDomStrategy() "emulated" : new EmulatedShadowDomStrategy(styleInliner, styleUrlResolver, DOM.createElement('div'))
}, },
(strategy, name) => { (strategy, name) => {
@ -36,12 +45,14 @@ export function main() {
beforeEach(() => { beforeEach(() => {
tplResolver = new MockTemplateResolver(); tplResolver = new MockTemplateResolver();
compiler = new Compiler(dynamicChangeDetection, compiler = new Compiler(dynamicChangeDetection,
new TemplateLoader(null), new TemplateLoader(null, null),
new DirectiveMetadataReader(), new DirectiveMetadataReader(),
new Parser(new Lexer()), new Parser(new Lexer()),
new CompilerCache(), new CompilerCache(),
strategy, strategy,
tplResolver tplResolver,
new ComponentUrlMapper(),
urlResolver
); );
}); });

View File

@ -1,128 +0,0 @@
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el} from 'angular2/test_lib';
import {
ShimNativeComponent,
ShimEmulatedComponent,
resetShimComponentCache
} from 'angular2/src/core/compiler/shadow_dom_emulation/shim_component';
import {ShadowCss} from 'angular2/src/core/compiler/shadow_dom_emulation/shadow_css';
import {Type} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/facade/dom';
export function main() {
describe('ShimComponent', () => {
describe('ShimNativeComponent', () => {
function createShim(component: Type) {
return new ShimNativeComponent(component);
}
it('should not transform the CSS', () => {
var css = '.foo {color: blue;} :host{color: red;}';
var shim = createShim(SomeComponent);
var shimCss = shim.shimCssText(css);
expect(css).toEqual(shimCss);
});
it('should not transform content elements', () => {
var html = '<p>foo</p>';
var element = el(html);
var shim = createShim(SomeComponent);
shim.shimContentElement(element);
expect(DOM.getOuterHTML(element)).toEqual(html);
});
it('should not transform host elements', () => {
var html = '<p>foo</p>';
var element = el(html);
var shim = createShim(SomeComponent);
shim.shimHostElement(element);
expect(DOM.getOuterHTML(element)).toEqual(html);
});
});
describe('ShimEmulatedComponent', () => {
beforeEach(() => {
resetShimComponentCache();
});
function createShim(component: Type) {
return new ShimEmulatedComponent(component);
}
it('should transform the CSS', () => {
var css = '.foo {color: blue;} :host{color: red;}';
var shim = createShim(SomeComponent);
var shimCss = shim.shimCssText(css);
expect(shimCss).not.toEqual(css);
var shadowCss = new ShadowCss();
expect(shimCss).toEqual(shadowCss.shimCssText(css, '_ngcontent-0', '_nghost-0'));
});
it('should transform content elements', () => {
var html = '<p>foo</p>';
var element = el(html);
var shim = createShim(SomeComponent);
shim.shimContentElement(element);
expect(DOM.getOuterHTML(element)).toEqual('<p _ngcontent-0="">foo</p>');
});
it('should not transform host elements', () => {
var html = '<p>foo</p>';
var element = el(html);
var shim = createShim(SomeComponent);
shim.shimHostElement(element);
expect(DOM.getOuterHTML(element)).toEqual('<p _nghost-0="">foo</p>');
});
it('should generate the same output for the same component', () => {
var html = '<p>foo</p>';
var content1 = el(html);
var host1 = el(html);
var css = '.foo {color: blue;} :host{color: red;}';
var shim1 = createShim(SomeComponent);
shim1.shimContentElement(content1);
shim1.shimHostElement(host1);
var shimCss1 = shim1.shimCssText(css);
var content2 = el(html);
var host2 = el(html);
var shim2 = createShim(SomeComponent);
shim2.shimContentElement(content2);
shim2.shimHostElement(host2);
var shimCss2 = shim2.shimCssText(css);
expect(DOM.getOuterHTML(content1)).toEqual(DOM.getOuterHTML(content2));
expect(DOM.getOuterHTML(host1)).toEqual(DOM.getOuterHTML(host2));
expect(shimCss1).toEqual(shimCss2);
});
it('should generate different outputs for different components', () => {
var html = '<p>foo</p>';
var content1 = el(html);
var host1 = el(html);
var css = '.foo {color: blue;} :host{color: red;}';
var shim1 = createShim(SomeComponent);
shim1.shimContentElement(content1);
shim1.shimHostElement(host1);
var shimCss1 = shim1.shimCssText(css);
var content2 = el(html);
var host2 = el(html);
var shim2 = createShim(SomeComponent2);
shim2.shimContentElement(content2);
shim2.shimHostElement(host2);
var shimCss2 = shim2.shimCssText(css);
expect(DOM.getOuterHTML(content1)).not.toEqual(DOM.getOuterHTML(content2));
expect(DOM.getOuterHTML(host1)).not.toEqual(DOM.getOuterHTML(host2));
expect(shimCss1).not.toEqual(shimCss2);
});
});
});
}
class SomeComponent {}
class SomeComponent2 {}

View File

@ -0,0 +1,169 @@
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el} from 'angular2/test_lib';
import {
NativeShadowDomStrategy,
EmulatedShadowDomStrategy,
resetShadowDomCache,
} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
import {ProtoView} from 'angular2/src/core/compiler/view';
import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/facade/dom';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
import {DynamicProtoChangeDetector} from 'angular2/change_detection';
export function main() {
var strategy;
describe('NativeShadowDomStratgey', () => {
beforeEach(() => {
var urlResolver = new UrlResolver();
var styleUrlResolver = new StyleUrlResolver(urlResolver);
strategy = new NativeShadowDomStrategy(styleUrlResolver);
});
it('should attach the view nodes to the shadow root', () => {
var host = el('<div></div>');
var nodes = el('<div>view</div>');
var pv = new ProtoView(nodes, new DynamicProtoChangeDetector(null), null);
var view = pv.instantiate(null, null);
strategy.attachTemplate(host, view);
var shadowRoot = DOM.getShadowRoot(host);
expect(isPresent(shadowRoot)).toBeTruthy();
expect(shadowRoot).toHaveText('view');
});
it('should rewrite style urls', () => {
var css = '.foo {background-image: url("img.jpg");}';
expect(strategy.transformStyleText(css, 'http://base', null))
.toEqual(".foo {background-image: url('http://base/img.jpg');}");
});
it('should not inline import rules', () => {
var css = '@import "other.css";';
expect(strategy.transformStyleText(css, 'http://base', null))
.toEqual("@import 'http://base/other.css';");
});
});
describe('EmulatedShadowDomStratgey', () => {
var xhr, styleHost;
beforeEach(() => {
var urlResolver = new UrlResolver();
var styleUrlResolver = new StyleUrlResolver(urlResolver);
xhr = new FakeXHR();
var styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
styleHost = el('<div></div>');
strategy = new EmulatedShadowDomStrategy(styleInliner, styleUrlResolver, styleHost);
resetShadowDomCache();
});
it('should attach the view nodes as child of the host element', () => {
var host = el('<div><span>original content</span></div>');
var nodes = el('<div>view</div>');
var pv = new ProtoView(nodes, new DynamicProtoChangeDetector(null), null);
var view = pv.instantiate(null, null);
strategy.attachTemplate(host, view);
var firstChild = DOM.firstChild(host);
expect(DOM.tagName(firstChild)).toEqual('DIV');
expect(firstChild).toHaveText('view');
expect(host).toHaveText('view');
});
it('should rewrite style urls', () => {
var css = '.foo {background-image: url("img.jpg");}';
expect(strategy.transformStyleText(css, 'http://base', SomeComponent))
.toEqual(".foo[_ngcontent-0] {\nbackground-image: url(http://base/img.jpg);\n}");
});
it('should scope style', () => {
var css = '.foo {} :host {}';
expect(strategy.transformStyleText(css, 'http://base', SomeComponent))
.toEqual(".foo[_ngcontent-0] {\n\n}\n\n[_nghost-0] {\n\n}");
});
it('should inline @import rules', (done) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import "one.css";';
var promise = strategy.transformStyleText(css, 'http://base', SomeComponent);
expect(promise).toBePromise();
promise.then((css) => {
expect(css).toEqual('.one[_ngcontent-0] {\n\n}');
done();
});
});
it('should return the same style given the same component', () => {
var css = '.foo {} :host {}';
expect(strategy.transformStyleText(css, 'http://base', SomeComponent))
.toEqual(".foo[_ngcontent-0] {\n\n}\n\n[_nghost-0] {\n\n}");
expect(strategy.transformStyleText(css, 'http://base', SomeComponent))
.toEqual(".foo[_ngcontent-0] {\n\n}\n\n[_nghost-0] {\n\n}");
});
it('should return different styles given different components', () => {
var css = '.foo {} :host {}';
expect(strategy.transformStyleText(css, 'http://base', SomeComponent))
.toEqual(".foo[_ngcontent-0] {\n\n}\n\n[_nghost-0] {\n\n}");
expect(strategy.transformStyleText(css, 'http://base', SomeOtherComponent))
.toEqual(".foo[_ngcontent-1] {\n\n}\n\n[_nghost-1] {\n\n}");
});
it('should move the style element to the style host', () => {
var originalHost = el('<div></div>');
var styleEl = el('<style>/*css*/</style>');
DOM.appendChild(originalHost, styleEl);
expect(originalHost).toHaveText('/*css*/');
strategy.handleStyleElement(styleEl);
expect(originalHost).toHaveText('');
expect(styleHost).toHaveText('/*css*/');
});
it('should add an attribute to the content elements', () => {
var elt = el('<div></div>');
strategy.shimContentElement(SomeComponent, elt);
expect(DOM.getAttribute(elt, '_ngcontent-0')).toEqual('');
});
it('should add an attribute to the host elements', () => {
var elt = el('<div></div>');
strategy.shimHostElement(SomeComponent, elt);
expect(DOM.getAttribute(elt, '_nghost-0')).toEqual('');
});
});
}
class FakeXHR extends XHR {
_responses: Map;
constructor() {
super();
this._responses = MapWrapper.create();
}
get(url: string): Promise<string> {
var response = MapWrapper.get(this._responses, url);
if (isBlank(response)) {
return PromiseWrapper.reject('xhr error');
}
return PromiseWrapper.resolve(response);
}
reply(url: string, response: string) {
MapWrapper.set(this._responses, url, response);
}
}
class SomeComponent {}
class SomeOtherComponent {}

View File

@ -6,24 +6,50 @@ import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {Map, MapWrapper} from 'angular2/src/facade/collection'; import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {XHR} from 'angular2/src/core/compiler/xhr/xhr'; import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
export function main() { export function main() {
describe('StyleInliner', () => { describe('StyleInliner', () => {
var xhr, inliner;
beforeEach(() => {
xhr = new FakeXHR();
var urlResolver = new UrlResolver();
var styleUrlResolver = new StyleUrlResolver(urlResolver);
inliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
});
describe('loading', () => { describe('loading', () => {
it('should return a string when there is no import statement', () => { it('should return a string when there is no import statement', () => {
var css = '.main {}'; var css = '.main {}';
var loader = new StyleInliner(null); var loadedCss = inliner.inlineImports(css, 'http://base');
var loadedCss = loader.inlineImports(css);
expect(loadedCss).not.toBePromise(); expect(loadedCss).not.toBePromise();
expect(loadedCss).toEqual(css); expect(loadedCss).toEqual(css);
}); });
it('should inline @import rules', (done) => { it('should inline @import rules', (done) => {
var xhr = new FakeXHR(); xhr.reply('http://base/one.css', '.one {}');
xhr.reply('one.css', '.one {}'); var css = '@import url("one.css");.main {}';
var css = '@import "one.css";.main {}'; var loadedCss = inliner.inlineImports(css, 'http://base');
var loader = new StyleInliner(xhr); expect(loadedCss).toBePromise();
var loadedCss = loader.inlineImports(css); PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.main {}');
done();
},
function(e) {
throw 'fail;'
}
);
});
// TODO(vicb): fix the StyleInliner
xit('should support url([unquoted url]) in @import rules', (done) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import url(one.css);.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise(); expect(loadedCss).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss,
@ -38,15 +64,13 @@ export function main() {
}); });
it('should handle @import error gracefuly', (done) => { it('should handle @import error gracefuly', (done) => {
var xhr = new FakeXHR();
var css = '@import "one.css";.main {}'; var css = '@import "one.css";.main {}';
var loader = new StyleInliner(xhr); var loadedCss = inliner.inlineImports(css, 'http://base');
var loadedCss = loader.inlineImports(css);
expect(loadedCss).toBePromise(); expect(loadedCss).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss,
function(css) { function(css) {
expect(css).toEqual('/* failed to import one.css */\n.main {}'); expect(css).toEqual('/* failed to import http://base/one.css */\n.main {}');
done(); done();
}, },
function(e) { function(e) {
@ -56,12 +80,10 @@ export function main() {
}); });
it('should inline multiple @import rules', (done) => { it('should inline multiple @import rules', (done) => {
var xhr = new FakeXHR(); xhr.reply('http://base/one.css', '.one {}');
xhr.reply('one.css', '.one {}'); xhr.reply('http://base/two.css', '.two {}');
xhr.reply('two.css', '.two {}');
var css = '@import "one.css";@import "two.css";.main {}'; var css = '@import "one.css";@import "two.css";.main {}';
var loader = new StyleInliner(xhr); var loadedCss = inliner.inlineImports(css, 'http://base');
var loadedCss = loader.inlineImports(css);
expect(loadedCss).toBePromise(); expect(loadedCss).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss,
@ -76,12 +98,10 @@ export function main() {
}); });
it('should inline nested @import rules', (done) => { it('should inline nested @import rules', (done) => {
var xhr = new FakeXHR(); xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('one.css', '@import "two.css";.one {}'); xhr.reply('http://base/two.css', '.two {}');
xhr.reply('two.css', '.two {}');
var css = '@import "one.css";.main {}'; var css = '@import "one.css";.main {}';
var loader = new StyleInliner(xhr); var loadedCss = inliner.inlineImports(css, 'http://base/');
var loadedCss = loader.inlineImports(css);
expect(loadedCss).toBePromise(); expect(loadedCss).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss,
@ -96,12 +116,10 @@ export function main() {
}); });
it('should handle circular dependencies gracefuly', (done) => { it('should handle circular dependencies gracefuly', (done) => {
var xhr = new FakeXHR(); xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('one.css', '@import "two.css";.one {}'); xhr.reply('http://base/two.css', '@import "one.css";.two {}');
xhr.reply('two.css', '@import "one.css";.two {}');
var css = '@import "one.css";.main {}'; var css = '@import "one.css";.main {}';
var loader = new StyleInliner(xhr); var loadedCss = inliner.inlineImports(css, 'http://base/');
var loadedCss = loader.inlineImports(css);
expect(loadedCss).toBePromise(); expect(loadedCss).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss,
@ -115,15 +133,29 @@ export function main() {
); );
}); });
it('should handle invalid @import fracefuly', (done) => {
// Invalid rule: the url is not quoted
var css = '@import one.css;.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('/* Invalid import rule: "@import one.css;" */.main {}');
done();
},
function(e) {
throw 'fail;'
}
);
});
}); });
describe('media query', () => { describe('media query', () => {
it('should wrap inlined content in media query', (done) => { it('should wrap inlined content in media query', (done) => {
var xhr = new FakeXHR(); xhr.reply('http://base/one.css', '.one {}');
xhr.reply('one.css', '.one {}');
var css = '@import "one.css" (min-width: 700px) and (orientation: landscape);'; var css = '@import "one.css" (min-width: 700px) and (orientation: landscape);';
var loader = new StyleInliner(xhr); var loadedCss = inliner.inlineImports(css, 'http://base/');
var loadedCss = loader.inlineImports(css);
expect(loadedCss).toBePromise(); expect(loadedCss).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss,
@ -136,9 +168,31 @@ export function main() {
} }
); );
}); });
}); });
describe('url rewritting', () => {
it('should rewrite url in inlined content', (done) => {
// it should rewrite both '@import' and 'url()'
xhr.reply('http://base/one.css', '@import "./nested/two.css";.one {background-image: url("one.jpg");}');
xhr.reply('http://base/nested/two.css', '.two {background-image: url("../img/two.jpg");}');
var css = '@import "one.css";'
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual(
".two {background-image: url('http://base/img/two.jpg');}\n" +
".one {background-image: url('http://base/one.jpg');}\n"
);
done();
},
function(e) {
throw 'fail;'
}
);
});
});
}); });
} }

View File

@ -12,20 +12,24 @@ export function main() {
@import "2.css"; @import "2.css";
@import url('3.css'); @import url('3.css');
@import url("4.css"); @import url("4.css");
@import url(5.css);
.foo { .foo {
background-image: url("double.jpg"); background-image: url("double.jpg");
background-image: url('simple.jpg'); background-image: url('simple.jpg');
background-image: url(noquote.jpg);
}`; }`;
var expectedCss = ` var expectedCss = `
@import 'base/1.css'; @import 'base/1.css';
@import 'base/2.css'; @import 'base/2.css';
@import url('base/3.css'); @import url('base/3.css');
@import url('base/4.css'); @import url('base/4.css');
@import url('base/5.css');
.foo { .foo {
background-image: url('base/double.jpg'); background-image: url('base/double.jpg');
background-image: url('base/simple.jpg'); background-image: url('base/simple.jpg');
background-image: url('base/noquote.jpg');
}`; }`;
var resolvedCss = styleUrlResolver.resolveUrls(css, 'base'); var resolvedCss = styleUrlResolver.resolveUrls(css, 'base');

View File

@ -1,6 +1,7 @@
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib'; import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {Template} from 'angular2/src/core/annotations/template'; import {Template} from 'angular2/src/core/annotations/template';
@ -14,7 +15,7 @@ export function main() {
beforeEach(() => { beforeEach(() => {
xhr = new XHRMock() xhr = new XHRMock()
loader = new TemplateLoader(xhr); loader = new TemplateLoader(xhr, new FakeUrlResolver());
}); });
it('should load inline templates synchronously', () => { it('should load inline templates synchronously', () => {
@ -23,8 +24,9 @@ export function main() {
}); });
it('should load templates through XHR', (done) => { it('should load templates through XHR', (done) => {
xhr.expect('/foo', 'xhr template'); xhr.expect('base/foo', 'xhr template');
var template = new Template({url: '/foo'}); var template = new Template({url: '/foo'});
loader.setBaseUrl(template, 'base');
loader.load(template).then((el) => { loader.load(template).then((el) => {
expect(el.content).toHaveText('xhr template'); expect(el.content).toHaveText('xhr template');
done(); done();
@ -34,8 +36,9 @@ export function main() {
it('should cache template loaded through XHR', (done) => { it('should cache template loaded through XHR', (done) => {
var firstEl; var firstEl;
xhr.expect('/foo', 'xhr template'); xhr.expect('base/foo', 'xhr template');
var template = new Template({url: '/foo'}); var template = new Template({url: '/foo'});
loader.setBaseUrl(template, 'base');
loader.load(template) loader.load(template)
.then((el) => { .then((el) => {
firstEl = el; firstEl = el;
@ -56,12 +59,13 @@ export function main() {
}); });
it('should return a rejected Promise when xhr loading fails', (done) => { it('should return a rejected Promise when xhr loading fails', (done) => {
xhr.expect('/foo', null); xhr.expect('base/foo', null);
var template = new Template({url: '/foo'}); var template = new Template({url: '/foo'});
loader.setBaseUrl(template, 'base');
PromiseWrapper.then(loader.load(template), PromiseWrapper.then(loader.load(template),
function(_) { throw 'Unexpected response'; }, function(_) { throw 'Unexpected response'; },
function(error) { function(error) {
expect(error).toEqual('Failed to load /foo'); expect(error).toEqual('Failed to load base/foo');
done(); done();
} }
) )
@ -73,3 +77,13 @@ export function main() {
class SomeComponent { class SomeComponent {
} }
class FakeUrlResolver extends UrlResolver {
constructor() {
super();
}
resolve(baseUrl: string, url: string): string {
return baseUrl + url;
}
}

View File

@ -69,7 +69,8 @@ export function main() {
dom = el(`<div><stuff></stuff><div insert-after-me></div><stuff></stuff></div>`); dom = el(`<div><stuff></stuff><div insert-after-me></div><stuff></stuff></div>`);
var insertionElement = dom.childNodes[1]; var insertionElement = dom.childNodes[1];
parentView = createView([dom.childNodes[0]]); parentView = createView([dom.childNodes[0]]);
protoView = new ProtoView(el('<div>hi</div>'), new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy()); protoView = new ProtoView(el('<div>hi</div>'), new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null));
elementInjector = new ElementInjector(null, null, null, null); elementInjector = new ElementInjector(null, null, null, null);
viewContainer = new ViewContainer(parentView, insertionElement, protoView, elementInjector, null); viewContainer = new ViewContainer(parentView, insertionElement, protoView, elementInjector, null);
customViewWithOneNode = createView([el('<div>single</div>')]); customViewWithOneNode = createView([el('<div>single</div>')]);
@ -213,7 +214,7 @@ export function main() {
viewContainer.hydrate(new Injector([]), null); viewContainer.hydrate(new Injector([]), null);
var pv = new ProtoView(el('<div class="ng-binding">{{}}</div>'), var pv = new ProtoView(el('<div class="ng-binding">{{}}</div>'),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy()); new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective])); pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective]));
pv.bindTextNode(0, parser.parseBinding('foo', null)); pv.bindTextNode(0, parser.parseBinding('foo', null));
fancyView = pv.instantiate(null, null); fancyView = pv.instantiate(null, null);

View File

@ -195,7 +195,7 @@ export function main() {
it('should be supported.', () => { it('should be supported.', () => {
var template = el('<div></div>'); var template = el('<div></div>');
var pv = new ProtoView(template, new DynamicProtoChangeDetector(null), var pv = new ProtoView(template, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy()); new NativeShadowDomStrategy(null));
pv.instantiateInPlace = true; pv.instantiateInPlace = true;
var view = pv.instantiate(null, null); var view = pv.instantiate(null, null);
view.hydrate(null, null, null); view.hydrate(null, null, null);
@ -205,7 +205,7 @@ export function main() {
it('should be off by default.', () => { it('should be off by default.', () => {
var template = el('<div></div>') var template = el('<div></div>')
var view = new ProtoView(template, new DynamicProtoChangeDetector(null), var view = new ProtoView(template, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy()) new NativeShadowDomStrategy(null))
.instantiate(null, null); .instantiate(null, null);
view.hydrate(null, null, null); view.hydrate(null, null, null);
expect(view.nodes[0]).not.toBe(template); expect(view.nodes[0]).not.toBe(template);
@ -312,7 +312,7 @@ export function main() {
function createComponentWithSubPV(subProtoView) { function createComponentWithSubPV(subProtoView) {
var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'), var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy()); new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponent], true)); var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponent], true));
binder.componentDirective = someComponentDirective; binder.componentDirective = someComponentDirective;
binder.nestedProtoView = subProtoView; binder.nestedProtoView = subProtoView;
@ -396,7 +396,7 @@ export function main() {
new DynamicProtoChangeDetector(null), null); new DynamicProtoChangeDetector(null), null);
var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'), var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'),
new DynamicProtoChangeDetector(null), new EmulatedShadowDomStrategy()); new DynamicProtoChangeDetector(null), new EmulatedShadowDomStrategy(null, null, null));
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponent], true)); var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponent], true));
binder.componentDirective = new DirectiveMetadataReader().read(SomeComponent); binder.componentDirective = new DirectiveMetadataReader().read(SomeComponent);
binder.nestedProtoView = subpv; binder.nestedProtoView = subpv;
@ -412,7 +412,7 @@ export function main() {
var templateProtoView = new ProtoView( var templateProtoView = new ProtoView(
el('<div id="1"></div>'), new DynamicProtoChangeDetector(null), null); el('<div id="1"></div>'), new DynamicProtoChangeDetector(null), null);
var pv = new ProtoView(el('<someTmpl class="ng-binding"></someTmpl>'), var pv = new ProtoView(el('<someTmpl class="ng-binding"></someTmpl>'),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy()); new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeViewport])); var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeViewport]));
binder.viewportDirective = someViewportDirective; binder.viewportDirective = someViewportDirective;
binder.nestedProtoView = templateProtoView; binder.nestedProtoView = templateProtoView;
@ -606,12 +606,13 @@ export function main() {
beforeEach(() => { beforeEach(() => {
element = DOM.createElement('div'); element = DOM.createElement('div');
pv = new ProtoView(el('<div>hi</div>'), new DynamicProtoChangeDetector(null), pv = new ProtoView(el('<div>hi</div>'), new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy()); new NativeShadowDomStrategy(null));
}); });
it('should create the root component when instantiated', () => { it('should create the root component when instantiated', () => {
var rootProtoView = ProtoView.createRootProtoView(pv, element, var rootProtoView = ProtoView.createRootProtoView(pv, element,
someComponentDirective, new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy()); someComponentDirective, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null));
var view = rootProtoView.instantiate(null, null); var view = rootProtoView.instantiate(null, null);
view.hydrate(new Injector([]), null, null); view.hydrate(new Injector([]), null, null);
expect(view.rootElementInjectors[0].get(SomeComponent)).not.toBe(null); expect(view.rootElementInjectors[0].get(SomeComponent)).not.toBe(null);
@ -619,7 +620,8 @@ export function main() {
it('should inject the protoView into the shadowDom', () => { it('should inject the protoView into the shadowDom', () => {
var rootProtoView = ProtoView.createRootProtoView(pv, element, var rootProtoView = ProtoView.createRootProtoView(pv, element,
someComponentDirective, new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy()); someComponentDirective, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null));
var view = rootProtoView.instantiate(null, null); var view = rootProtoView.instantiate(null, null);
view.hydrate(new Injector([]), null, null); view.hydrate(new Injector([]), null, null);
expect(element.shadowRoot.childNodes[0].childNodes[0].nodeValue).toEqual('hi'); expect(element.shadowRoot.childNodes[0].childNodes[0].nodeValue).toEqual('hi');

View File

@ -10,6 +10,9 @@ import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {Template} from 'angular2/src/core/annotations/template'; import {Template} from 'angular2/src/core/annotations/template';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations'; import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
@ -22,10 +25,18 @@ export function main() {
describe('foreach', () => { describe('foreach', () => {
var view, cd, compiler, component, tplResolver; var view, cd, compiler, component, tplResolver;
beforeEach(() => { beforeEach(() => {
var urlResolver = new UrlResolver();
tplResolver = new MockTemplateResolver(); tplResolver = new MockTemplateResolver();
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null), compiler = new Compiler(
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(), dynamicChangeDetection,
new NativeShadowDomStrategy(), tplResolver); new TemplateLoader(null, null),
new DirectiveMetadataReader(),
new Parser(new Lexer()),
new CompilerCache(),
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
tplResolver,
new ComponentUrlMapper(),
urlResolver);
}); });
function createView(pv) { function createView(pv) {

View File

@ -9,6 +9,9 @@ import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {Component} from 'angular2/src/core/annotations/annotations'; import {Component} from 'angular2/src/core/annotations/annotations';
import {Template} from 'angular2/src/core/annotations/template'; import {Template} from 'angular2/src/core/annotations/template';
@ -22,10 +25,18 @@ export function main() {
var view, cd, compiler, component, tplResolver; var view, cd, compiler, component, tplResolver;
beforeEach(() => { beforeEach(() => {
var urlResolver = new UrlResolver();
tplResolver = new MockTemplateResolver(); tplResolver = new MockTemplateResolver();
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null), compiler = new Compiler(
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(), dynamicChangeDetection,
new NativeShadowDomStrategy(), tplResolver); new TemplateLoader(null, null),
new DirectiveMetadataReader(),
new Parser(new Lexer()),
new CompilerCache(),
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
tplResolver,
new ComponentUrlMapper(),
urlResolver);
}); });
function createView(pv) { function createView(pv) {

View File

@ -2,11 +2,17 @@ import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular
import {DOM} from 'angular2/src/facade/dom'; import {DOM} from 'angular2/src/facade/dom';
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection'; import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {Decorator, Component} from 'angular2/src/core/annotations/annotations'; import {Decorator, Component} from 'angular2/src/core/annotations/annotations';
import {Template} from 'angular2/src/core/annotations/template'; import {Template} from 'angular2/src/core/annotations/template';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {NgElement} from 'angular2/src/core/dom/element'; import {NgElement} from 'angular2/src/core/dom/element';
import {NonBindable} from 'angular2/src/directives/non_bindable'; import {NonBindable} from 'angular2/src/directives/non_bindable';
@ -16,10 +22,18 @@ export function main() {
describe('non-bindable', () => { describe('non-bindable', () => {
var view, cd, compiler, component, tplResolver; var view, cd, compiler, component, tplResolver;
beforeEach(() => { beforeEach(() => {
var urlResolver = new UrlResolver();
tplResolver = new MockTemplateResolver(); tplResolver = new MockTemplateResolver();
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null), compiler = new Compiler(
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(), dynamicChangeDetection,
new NativeShadowDomStrategy(), tplResolver); new TemplateLoader(null, null),
new DirectiveMetadataReader(),
new Parser(new Lexer()),
new CompilerCache(),
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
tplResolver,
new ComponentUrlMapper(),
urlResolver);
}); });
function createView(pv) { function createView(pv) {

View File

@ -2,9 +2,14 @@ import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular
import {DOM} from 'angular2/src/facade/dom'; import {DOM} from 'angular2/src/facade/dom';
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection'; import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {Component} from 'angular2/src/core/annotations/annotations'; import {Component} from 'angular2/src/core/annotations/annotations';
import {Template} from 'angular2/src/core/annotations/template'; import {Template} from 'angular2/src/core/annotations/template';
import {TemplateLoader} from 'angular2/core'; import {TemplateLoader} from 'angular2/core';
@ -15,10 +20,18 @@ export function main() {
describe('switch', () => { describe('switch', () => {
var view, cd, compiler, component, tplResolver; var view, cd, compiler, component, tplResolver;
beforeEach(() => { beforeEach(() => {
var urlResolver = new UrlResolver();
tplResolver = new MockTemplateResolver(); tplResolver = new MockTemplateResolver();
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null), compiler = new Compiler(
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(), dynamicChangeDetection,
new NativeShadowDomStrategy(), tplResolver); new TemplateLoader(null, null),
new DirectiveMetadataReader(),
new Parser(new Lexer()),
new CompilerCache(),
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
tplResolver,
new ComponentUrlMapper(),
urlResolver);
}); });
function createView(pv) { function createView(pv) {

View File

@ -6,6 +6,10 @@ import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock'; import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
@ -22,14 +26,17 @@ export function main() {
function compile(componentType, template, context, callback) { function compile(componentType, template, context, callback) {
var tplResolver = new MockTemplateResolver(); var tplResolver = new MockTemplateResolver();
var urlResolver = new UrlResolver();
var compiler = new Compiler(dynamicChangeDetection, var compiler = new Compiler(dynamicChangeDetection,
new TemplateLoader(null), new TemplateLoader(null, null),
new DirectiveMetadataReader(), new DirectiveMetadataReader(),
new Parser(new Lexer()), new Parser(new Lexer()),
new CompilerCache(), new CompilerCache(),
new NativeShadowDomStrategy(), new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
tplResolver tplResolver,
new ComponentUrlMapper(),
urlResolver
); );
tplResolver.setTemplate(componentType, new Template({ tplResolver.setTemplate(componentType, new Template({

View File

@ -14,6 +14,9 @@ import {Decorator} from 'angular2/src/core/annotations/annotations';
import {Template} from 'angular2/src/core/annotations/template'; import {Template} from 'angular2/src/core/annotations/template';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver'; import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util'; import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util';
@ -83,8 +86,18 @@ export function main() {
var reader = new DirectiveMetadataReader(); var reader = new DirectiveMetadataReader();
var cache = new CompilerCache(); var cache = new CompilerCache();
var templateResolver = new FakeTemplateResolver(); var templateResolver = new FakeTemplateResolver();
var compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null), var urlResolver = new UrlResolver();
reader, new Parser(new Lexer()), cache, new NativeShadowDomStrategy(), templateResolver); var styleUrlResolver = new StyleUrlResolver(urlResolver);
var compiler = new Compiler(
dynamicChangeDetection,
new TemplateLoader(null, urlResolver),
reader,
new Parser(new Lexer()),
cache,
new NativeShadowDomStrategy(styleUrlResolver),
templateResolver,
new ComponentUrlMapper(),
urlResolver);
var templateNoBindings = createTemplateHtml('templateNoBindings', count); var templateNoBindings = createTemplateHtml('templateNoBindings', count);
var templateWithBindings = createTemplateHtml('templateWithBindings', count); var templateWithBindings = createTemplateHtml('templateWithBindings', count);

View File

@ -17,6 +17,10 @@ import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {XHR} from 'angular2/src/core/compiler/xhr/xhr'; import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl'; import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
import {If, Foreach} from 'angular2/directives'; import {If, Foreach} from 'angular2/directives';
import {App, setupReflectorForApp} from './app'; import {App, setupReflectorForApp} from './app';
@ -176,11 +180,12 @@ export function setupReflectorForAngular() {
reflector.registerType(Compiler, { reflector.registerType(Compiler, {
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy, "factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
resolver) => tplResolver, cmpUrlMapper, urlResolver) =>
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy, new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
resolver), tplResolver, cmpUrlMapper, urlResolver),
"parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser], "parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser],
[CompilerCache], [ShadowDomStrategy], [TemplateResolver]], [CompilerCache], [ShadowDomStrategy], [TemplateResolver], [ComponentUrlMapper],
[UrlResolver]],
"annotations": [] "annotations": []
}); });
@ -197,8 +202,8 @@ export function setupReflectorForAngular() {
}); });
reflector.registerType(TemplateLoader, { reflector.registerType(TemplateLoader, {
"factory": (xhr) => new TemplateLoader(xhr), "factory": (xhr, urlResolver) => new TemplateLoader(xhr, urlResolver),
"parameters": [[XHR]], "parameters": [[XHR], [UrlResolver]],
"annotations": [] "annotations": []
}); });
@ -239,9 +244,38 @@ export function setupReflectorForAngular() {
}); });
reflector.registerType(ShadowDomStrategy, { reflector.registerType(ShadowDomStrategy, {
"factory": () => new NativeShadowDomStrategy(), "factory": (strategy) => strategy,
"parameters": [[NativeShadowDomStrategy]],
"annotations": []
});
reflector.registerType(NativeShadowDomStrategy, {
"factory": (styleUrlResolver) => new NativeShadowDomStrategy(styleUrlResolver),
"parameters": [[StyleUrlResolver]],
"annotations": []
});
reflector.registerType(StyleUrlResolver, {
"factory": (urlResolver) => new StyleUrlResolver(urlResolver),
"parameters": [[UrlResolver]],
"annotations": []
});
reflector.registerType(UrlResolver, {
"factory": () => new UrlResolver(),
"parameters": [], "parameters": [],
"annotations": [] "annotations": []
}); });
reflector.registerType(ComponentUrlMapper, {
"factory": () => new ComponentUrlMapper(),
"parameters": [],
"annotations": []
});
reflector.registerType(StyleInliner, {
"factory": () => new StyleInliner(),
"parameters": [],
"annotations": []
});
} }

View File

@ -10,6 +10,10 @@ import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver'; import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
import {DOM, document, window, Element, gc} from 'angular2/src/facade/dom'; import {DOM, document, window, Element, gc} from 'angular2/src/facade/dom';
@ -62,10 +66,13 @@ function setupReflector() {
}); });
reflector.registerType(Compiler, { reflector.registerType(Compiler, {
'factory': (cd, templateLoader, reader, parser, compilerCache, strategy, resolver) => 'factory': (cd, templateLoader, reader, parser, compilerCache, strategy, tplResolver,
new Compiler(cd, templateLoader, reader, parser, compilerCache, strategy, resolver), cmpUrlMapper, urlResolver) =>
new Compiler(cd, templateLoader, reader, parser, compilerCache, strategy, tplResolver,
cmpUrlMapper, urlResolver),
'parameters': [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], 'parameters': [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader],
[Parser], [CompilerCache], [ShadowDomStrategy], [TemplateResolver]], [Parser], [CompilerCache], [ShadowDomStrategy], [TemplateResolver],
[ComponentUrlMapper], [UrlResolver]],
'annotations': [] 'annotations': []
}); });
@ -82,8 +89,8 @@ function setupReflector() {
}); });
reflector.registerType(TemplateLoader, { reflector.registerType(TemplateLoader, {
'factory': (xhr) => new TemplateLoader(xhr), 'factory': (xhr, urlResolver) => new TemplateLoader(xhr, urlResolver),
'parameters': [[XHR]], 'parameters': [[XHR], [UrlResolver]],
'annotations': [] 'annotations': []
}); });
@ -106,9 +113,27 @@ function setupReflector() {
}); });
reflector.registerType(ShadowDomStrategy, { reflector.registerType(ShadowDomStrategy, {
'factory': () => new NativeShadowDomStrategy(), "factory": (strategy) => strategy,
'parameters': [], "parameters": [[NativeShadowDomStrategy]],
'annotations': [] "annotations": []
});
reflector.registerType(NativeShadowDomStrategy, {
"factory": (styleUrlResolver) => new NativeShadowDomStrategy(styleUrlResolver),
"parameters": [[StyleUrlResolver]],
"annotations": []
});
reflector.registerType(StyleUrlResolver, {
"factory": (urlResolver) => new StyleUrlResolver(urlResolver),
"parameters": [[UrlResolver]],
"annotations": []
});
reflector.registerType(UrlResolver, {
"factory": () => new UrlResolver(),
"parameters": [],
"annotations": []
}); });
reflector.registerType(Lexer, { reflector.registerType(Lexer, {
@ -130,6 +155,18 @@ function setupReflector() {
}); });
reflector.registerType(ComponentUrlMapper, {
"factory": () => new ComponentUrlMapper(),
"parameters": [],
"annotations": []
});
reflector.registerType(StyleInliner, {
"factory": () => new StyleInliner(),
"parameters": [],
"annotations": []
});
reflector.registerGetters({ reflector.registerGetters({
'value': (a) => a.value, 'value': (a) => a.value,
'left': (a) => a.left, 'left': (a) => a.left,

View File

@ -12,6 +12,10 @@ import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver'; import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {XHR} from 'angular2/src/core/compiler/xhr/xhr'; import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl'; import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
@ -45,11 +49,12 @@ function setup() {
reflector.registerType(Compiler, { reflector.registerType(Compiler, {
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy, "factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
resolver) => tplResolver, cmpUrlMapper, urlResolver) =>
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy, new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
resolver), tplResolver, cmpUrlMapper, urlResolver),
"parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser], "parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser],
[CompilerCache], [ShadowDomStrategy], [TemplateResolver]], [CompilerCache], [ShadowDomStrategy], [TemplateResolver], [ComponentUrlMapper],
[UrlResolver]],
"annotations": [] "annotations": []
}); });
@ -66,8 +71,8 @@ function setup() {
}); });
reflector.registerType(TemplateLoader, { reflector.registerType(TemplateLoader, {
"factory": (xhr) => new TemplateLoader(xhr), "factory": (xhr, urlResolver) => new TemplateLoader(xhr, urlResolver),
"parameters": [[XHR]], "parameters": [[XHR], [UrlResolver]],
"annotations": [] "annotations": []
}); });
@ -108,7 +113,37 @@ function setup() {
}); });
reflector.registerType(ShadowDomStrategy, { reflector.registerType(ShadowDomStrategy, {
"factory": () => new NativeShadowDomStrategy(), "factory": (strategy) => strategy,
"parameters": [[NativeShadowDomStrategy]],
"annotations": []
});
reflector.registerType(NativeShadowDomStrategy, {
"factory": (styleUrlResolver) => new NativeShadowDomStrategy(styleUrlResolver),
"parameters": [[StyleUrlResolver]],
"annotations": []
});
reflector.registerType(StyleUrlResolver, {
"factory": (urlResolver) => new StyleUrlResolver(urlResolver),
"parameters": [[UrlResolver]],
"annotations": []
});
reflector.registerType(UrlResolver, {
"factory": () => new UrlResolver(),
"parameters": [],
"annotations": []
});
reflector.registerType(ComponentUrlMapper, {
"factory": () => new ComponentUrlMapper(),
"parameters": [],
"annotations": []
});
reflector.registerType(StyleInliner, {
"factory": () => new StyleInliner(),
"parameters": [], "parameters": [],
"annotations": [] "annotations": []
}); });