refactor(template loading): add support for base URLs, css rewriting
fixes #654
This commit is contained in:
parent
26872f60e6
commit
929fc65493
|
@ -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 {HammerGesturesPlugin} from 'angular2/src/core/events/hammer_gestures';
|
||||
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;
|
||||
|
||||
|
@ -78,7 +82,7 @@ function _injectorBindings(appComponentType): List<Binding> {
|
|||
var plugins = [new HammerGesturesPlugin(), new DomEventsPlugin()];
|
||||
return new EventManager(plugins, zone);
|
||||
}, [VmTurnZone]),
|
||||
bind(ShadowDomStrategy).toValue(new NativeShadowDomStrategy()),
|
||||
bind(ShadowDomStrategy).toClass(NativeShadowDomStrategy),
|
||||
Compiler,
|
||||
CompilerCache,
|
||||
TemplateResolver,
|
||||
|
@ -89,6 +93,10 @@ function _injectorBindings(appComponentType): List<Binding> {
|
|||
Lexer,
|
||||
ExceptionHandler,
|
||||
bind(XHR).toValue(new XHRImpl()),
|
||||
ComponentUrlMapper,
|
||||
UrlResolver,
|
||||
StyleUrlResolver,
|
||||
StyleInliner,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ import {DirectiveMetadata} from './directive_metadata';
|
|||
import {Template} from '../annotations/template';
|
||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||
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;
|
||||
_shadowDomDirectives: List<DirectiveMetadata>;
|
||||
_templateResolver: TemplateResolver;
|
||||
_componentUrlMapper: ComponentUrlMapper;
|
||||
_urlResolver: UrlResolver;
|
||||
_appUrl: string;
|
||||
|
||||
constructor(changeDetection:ChangeDetection,
|
||||
templateLoader:TemplateLoader,
|
||||
|
@ -64,7 +69,9 @@ export class Compiler {
|
|||
parser:Parser,
|
||||
cache:CompilerCache,
|
||||
shadowDomStrategy: ShadowDomStrategy,
|
||||
templateResolver: TemplateResolver) {
|
||||
templateResolver: TemplateResolver,
|
||||
componentUrlMapper: ComponentUrlMapper,
|
||||
urlResolver: UrlResolver) {
|
||||
this._changeDetection = changeDetection;
|
||||
this._reader = reader;
|
||||
this._parser = parser;
|
||||
|
@ -78,6 +85,9 @@ export class Compiler {
|
|||
ListWrapper.push(this._shadowDomDirectives, reader.read(types[i]));
|
||||
}
|
||||
this._templateResolver = templateResolver;
|
||||
this._componentUrlMapper = componentUrlMapper;
|
||||
this._urlResolver = urlResolver;
|
||||
this._appUrl = urlResolver.resolve(null, './');
|
||||
}
|
||||
|
||||
createSteps(component:Type, template: Template):List<CompileStep> {
|
||||
|
@ -90,8 +100,10 @@ export class Compiler {
|
|||
|
||||
var cmpMetadata = this._reader.read(component);
|
||||
|
||||
var templateUrl = this._templateLoader.getTemplateUrl(template);
|
||||
|
||||
return createDefaultSteps(this._changeDetection, this._parser, cmpMetadata, dirMetadata,
|
||||
this._shadowDomStrategy);
|
||||
this._shadowDomStrategy, templateUrl);
|
||||
}
|
||||
|
||||
compile(component: Type):Promise<ProtoView> {
|
||||
|
@ -118,6 +130,10 @@ export class Compiler {
|
|||
|
||||
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);
|
||||
|
||||
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) {
|
||||
// Returns ProtoView Promise when there are any asynchronous nested ProtoViews.
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
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 {
|
||||
// Returns the url to the component source file.
|
||||
// The returned url could be:
|
||||
// Returns the base URL to the component source file.
|
||||
// The returned URL could be:
|
||||
// - an absolute URL,
|
||||
// - a URL relative to the application
|
||||
// - a path relative to the application
|
||||
getUrl(component: Type): string {
|
||||
return './';
|
||||
}
|
||||
|
|
|
@ -9,11 +9,10 @@ import {ElementBindingMarker} from './element_binding_marker';
|
|||
import {ProtoViewBuilder} from './proto_view_builder';
|
||||
import {ProtoElementInjectorBuilder} from './proto_element_injector_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 {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
|
||||
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.
|
||||
|
@ -25,24 +24,20 @@ export function createDefaultSteps(
|
|||
parser:Parser,
|
||||
compiledComponent: DirectiveMetadata,
|
||||
directives: List<DirectiveMetadata>,
|
||||
shadowDomStrategy: ShadowDomStrategy) {
|
||||
shadowDomStrategy: ShadowDomStrategy,
|
||||
templateUrl: string) {
|
||||
|
||||
var steps = [new ViewSplitter(parser)];
|
||||
|
||||
if (shadowDomStrategy instanceof EmulatedShadowDomStrategy) {
|
||||
var step = new ShimShadowCss(compiledComponent, shadowDomStrategy, DOM.defaultDoc().head);
|
||||
ListWrapper.push(steps, step);
|
||||
}
|
||||
|
||||
steps = ListWrapper.concat(steps,[
|
||||
var steps = [
|
||||
new ViewSplitter(parser),
|
||||
new ResolveCss(compiledComponent, shadowDomStrategy, templateUrl),
|
||||
new PropertyBindingParser(parser),
|
||||
new DirectiveParser(directives),
|
||||
new TextInterpolationParser(parser),
|
||||
new ElementBindingMarker(),
|
||||
new ProtoViewBuilder(changeDetection, shadowDomStrategy),
|
||||
new ProtoElementInjectorBuilder(),
|
||||
new ElementBinderBuilder(parser)
|
||||
]);
|
||||
new ElementBinderBuilder(parser),
|
||||
]
|
||||
|
||||
if (shadowDomStrategy instanceof EmulatedShadowDomStrategy) {
|
||||
var step = new ShimShadowDom(compiledComponent, shadowDomStrategy);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,21 +2,19 @@ import {CompileStep} from './compile_step';
|
|||
import {CompileElement} from './compile_element';
|
||||
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 {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 {
|
||||
_strategy: ShadowDomStrategy;
|
||||
_shimComponent: ShimComponent;
|
||||
_component: Type;
|
||||
|
||||
constructor(cmpMetadata: DirectiveMetadata, strategy: ShadowDomStrategy) {
|
||||
super();
|
||||
this._strategy = strategy;
|
||||
this._shimComponent = strategy.getShimComponent(cmpMetadata.type);
|
||||
this._component = cmpMetadata.type;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
var host = current.componentDirective;
|
||||
if (isPresent(host)) {
|
||||
var shimComponent = this._strategy.getShimComponent(host.type);
|
||||
shimComponent.shimHostElement(current.element);
|
||||
this._strategy.shimHostElement(host.type, current.element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}`;
|
||||
}
|
||||
}
|
|
@ -1,31 +1,44 @@
|
|||
import {Type, isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||
import {DOM, Element} from 'angular2/src/facade/dom';
|
||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {Type, isBlank, isPresent, int} from 'angular2/src/facade/lang';
|
||||
import {DOM, Element, StyleElement} from 'angular2/src/facade/dom';
|
||||
import {List, ListWrapper, MapWrapper, Map} from 'angular2/src/facade/collection';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/async';
|
||||
|
||||
import {View} from './view';
|
||||
|
||||
import {Content} from './shadow_dom_emulation/content_tag';
|
||||
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 {
|
||||
attachTemplate(el:Element, view:View){}
|
||||
constructLightDom(lightDomView:View, shadowDomView:View, el:Element){}
|
||||
polyfillDirectives():List<Type>{ return null; }
|
||||
extractStyles(): boolean { return false; }
|
||||
getShimComponent(component: Type): ShimComponent {
|
||||
return null;
|
||||
}
|
||||
attachTemplate(el:Element, view:View) {}
|
||||
constructLightDom(lightDomView:View, shadowDomView:View, el:Element) {}
|
||||
polyfillDirectives():List<Type> { return null; }
|
||||
// TODO(vicb): union types: return either a string or a Promise<string>
|
||||
transformStyleText(cssText: string, baseUrl: string, component: Type) {}
|
||||
handleStyleElement(styleEl: StyleElement) {};
|
||||
shimContentElement(component: Type, element: Element) {}
|
||||
shimHostElement(component: Type, element: Element) {}
|
||||
}
|
||||
|
||||
export class EmulatedShadowDomStrategy extends ShadowDomStrategy {
|
||||
constructor() {
|
||||
_styleInliner: StyleInliner;
|
||||
_styleUrlResolver: StyleUrlResolver;
|
||||
_styleHost: Element;
|
||||
_lastInsertedStyle: StyleElement;
|
||||
|
||||
constructor(styleInliner: StyleInliner, styleUrlResolver: StyleUrlResolver, styleHost: Element) {
|
||||
super();
|
||||
this._styleInliner = styleInliner;
|
||||
this._styleUrlResolver = styleUrlResolver;
|
||||
this._styleHost = styleHost;
|
||||
}
|
||||
|
||||
attachTemplate(el:Element, view:View){
|
||||
DOM.clearNodes(el);
|
||||
moveViewNodesIntoParent(el, view);
|
||||
_moveViewNodesIntoParent(el, view);
|
||||
}
|
||||
|
||||
constructLightDom(lightDomView:View, shadowDomView:View, el:Element){
|
||||
|
@ -36,22 +49,58 @@ export class EmulatedShadowDomStrategy extends ShadowDomStrategy {
|
|||
return [Content];
|
||||
}
|
||||
|
||||
extractStyles(): boolean {
|
||||
return true;
|
||||
transformStyleText(cssText: string, baseUrl: string, component: Type) {
|
||||
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 {
|
||||
return new ShimEmulatedComponent(component);
|
||||
handleStyleElement(styleEl: StyleElement) {
|
||||
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 {
|
||||
constructor() {
|
||||
_styleUrlResolver: StyleUrlResolver;
|
||||
|
||||
constructor(styleUrlResolver: StyleUrlResolver) {
|
||||
super();
|
||||
this._styleUrlResolver = styleUrlResolver;
|
||||
}
|
||||
|
||||
attachTemplate(el:Element, view:View){
|
||||
moveViewNodesIntoParent(el.createShadowRoot(), view);
|
||||
_moveViewNodesIntoParent(DOM.createShadowRoot(el), view);
|
||||
}
|
||||
|
||||
constructLightDom(lightDomView:View, shadowDomView:View, el:Element){
|
||||
|
@ -62,17 +111,47 @@ export class NativeShadowDomStrategy extends ShadowDomStrategy {
|
|||
return [];
|
||||
}
|
||||
|
||||
extractStyles(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
getShimComponent(component: Type): ShimComponent {
|
||||
return new ShimNativeComponent(component);
|
||||
transformStyleText(cssText: string, baseUrl: string, component: Type) {
|
||||
return this._styleUrlResolver.resolveUrls(cssText, baseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
function moveViewNodesIntoParent(parent, view) {
|
||||
function _moveViewNodesIntoParent(parent, view) {
|
||||
for (var i = 0; i < view.nodes.length; ++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;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
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 {
|
||||
isBlank,
|
||||
isPresent,
|
||||
RegExp,
|
||||
RegExpWrapper,
|
||||
StringWrapper,
|
||||
|
@ -13,20 +16,38 @@ import {
|
|||
PromiseWrapper,
|
||||
} 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 {
|
||||
_xhr: XHR;
|
||||
_urlResolver: UrlResolver;
|
||||
_styleUrlResolver: StyleUrlResolver;
|
||||
|
||||
constructor(xhr: XHR) {
|
||||
constructor(xhr: XHR, styleUrlResolver: StyleUrlResolver, urlResolver: UrlResolver) {
|
||||
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
|
||||
inlineImports(cssText: string) {
|
||||
return this._inlineImports(cssText, []);
|
||||
// TODO(vicb): commented out @import rules should not be inlined
|
||||
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 parts = StringWrapper.split(cssText, _importRe);
|
||||
|
||||
|
@ -38,13 +59,20 @@ export class StyleInliner {
|
|||
var promises = [];
|
||||
|
||||
while (partIndex < parts.length - 1) {
|
||||
// prefix is the content before the @import rule
|
||||
var prefix = parts[partIndex];
|
||||
// rule is the parameter of the @import rule
|
||||
var rule = parts[partIndex + 1];
|
||||
var url = _extractUrl(rule);
|
||||
if (isPresent(url)) {
|
||||
url = this._urlResolver.resolve(baseUrl, url);
|
||||
}
|
||||
var mediaQuery = _extractMediaQuery(rule);
|
||||
|
||||
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
|
||||
// Importing again might cause a circular dependency
|
||||
promise = PromiseWrapper.resolve(prefix);
|
||||
|
@ -54,13 +82,15 @@ export class StyleInliner {
|
|||
this._xhr.get(url),
|
||||
(css) => {
|
||||
// resolve nested @import rules
|
||||
css = this._inlineImports(css, inlinedUrls);
|
||||
css = this._inlineImports(css, url, inlinedUrls);
|
||||
if (PromiseWrapper.isPromise(css)) {
|
||||
// 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 {
|
||||
// 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`
|
||||
|
@ -70,20 +100,19 @@ export class StyleInliner {
|
|||
partIndex += 2;
|
||||
}
|
||||
|
||||
return PromiseWrapper.then(
|
||||
PromiseWrapper.all(promises),
|
||||
function (cssParts) {
|
||||
var cssText = cssParts.join('');
|
||||
if (partIndex < parts.length) {
|
||||
// append whatever css located after the last @import rule
|
||||
cssText += parts[partIndex];
|
||||
}
|
||||
return cssText;
|
||||
},
|
||||
function(e) {
|
||||
throw 'error';
|
||||
return PromiseWrapper.all(promises).then(function (cssParts) {
|
||||
var cssText = cssParts.join('');
|
||||
if (partIndex < parts.length) {
|
||||
// append then content located after the last @import rule
|
||||
cssText += parts[partIndex];
|
||||
}
|
||||
);
|
||||
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
|
||||
function _wrapInMediaRule(css: string, query: string) {
|
||||
function _wrapInMediaRule(css: string, query: string): string {
|
||||
return (isBlank(query)) ? css : `@media ${query} {\n${css}\n}`;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
import {RegExp, RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang';
|
||||
import {UrlResolver} from './url_resolver';
|
||||
|
||||
/**
|
||||
* Rewrites URLs by resolving '@import' and 'url()' URLs from the given base URL.
|
||||
*/
|
||||
export class StyleUrlResolver {
|
||||
_resolver: UrlResolver;
|
||||
|
||||
|
@ -31,5 +34,6 @@ export class StyleUrlResolver {
|
|||
}
|
||||
|
||||
var _cssUrlRe = RegExpWrapper.create('(url\\()([^)]*)(\\))');
|
||||
// TODO(vicb): handle the media query part
|
||||
var _cssImportRe = RegExpWrapper.create('(@import[\\s]+(?!url\\())([^;]*)(;)');
|
||||
var _quoteRe = RegExpWrapper.create('[\'"]');
|
||||
|
|
|
@ -1,21 +1,29 @@
|
|||
import {isBlank, isPresent, BaseException, stringify} from 'angular2/src/facade/lang';
|
||||
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 {Template} from 'angular2/src/core/annotations/template';
|
||||
|
||||
import {UrlResolver} from './url_resolver';
|
||||
|
||||
/**
|
||||
* Strategy to load component templates.
|
||||
*/
|
||||
export class TemplateLoader {
|
||||
_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._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>
|
||||
|
@ -25,20 +33,43 @@ export class TemplateLoader {
|
|||
}
|
||||
|
||||
if (isPresent(template.url)) {
|
||||
var url = template.url;
|
||||
var promise = StringMapWrapper.get(this._cache, url);
|
||||
var url = this.getTemplateUrl(template);
|
||||
var promise = StringMapWrapper.get(this._htmlCache, url);
|
||||
|
||||
if (isBlank(promise)) {
|
||||
promise = this._xhr.get(url).then(function (html) {
|
||||
var template = DOM.createTemplate(html);
|
||||
return template;
|
||||
});
|
||||
StringMapWrapper.set(this._cache, url, promise);
|
||||
StringMapWrapper.set(this._htmlCache, url, 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {isPresent, isBlank, RegExpWrapper} from 'angular2/src/facade/lang';
|
||||
import {DOM, Element} from 'angular2/src/facade/dom';
|
||||
import {isPresent, isBlank, RegExpWrapper, BaseException} from 'angular2/src/facade/lang';
|
||||
import {DOM, AnchorElement} from 'angular2/src/facade/dom';
|
||||
|
||||
export class UrlResolver {
|
||||
static a: Element;
|
||||
static a: AnchorElement;
|
||||
|
||||
constructor() {
|
||||
if (isBlank(UrlResolver.a)) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
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 {AST, ContextWithVariableBindings, ChangeDispatcher, ProtoChangeDetector, ChangeDetector, ChangeRecord}
|
||||
from 'angular2/change_detection';
|
||||
|
@ -273,6 +274,8 @@ export class ProtoView {
|
|||
isTemplateElement:boolean;
|
||||
shadowDomStrategy: ShadowDomStrategy;
|
||||
_viewPool: ViewPool;
|
||||
stylePromises: List<Promise>;
|
||||
|
||||
constructor(
|
||||
template:Element,
|
||||
protoChangeDetector:ProtoChangeDetector,
|
||||
|
@ -290,6 +293,7 @@ export class ProtoView {
|
|||
this.isTemplateElement = DOM.isTemplateElement(this.element);
|
||||
this.shadowDomStrategy = shadowDomStrategy;
|
||||
this._viewPool = new ViewPool(VIEW_POOL_CAPACITY);
|
||||
this.stylePromises = [];
|
||||
}
|
||||
|
||||
// TODO(rado): hostElementInjector should be moved to hydrate phase.
|
||||
|
@ -539,8 +543,7 @@ export class ProtoView {
|
|||
new ProtoElementInjector(null, 0, [cmpType], true));
|
||||
binder.componentDirective = rootComponentAnnotatedType;
|
||||
binder.nestedProtoView = protoView;
|
||||
var shimComponent = shadowDomStrategy.getShimComponent(cmpType);
|
||||
shimComponent.shimHostElement(insertionElement);
|
||||
shadowDomStrategy.shimHostElement(cmpType, insertionElement);
|
||||
return rootProtoView;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,11 @@ export 'dart:html' show
|
|||
Element,
|
||||
location,
|
||||
Node,
|
||||
ShadowRoot,
|
||||
StyleElement,
|
||||
TemplateElement,
|
||||
InputElement,
|
||||
AnchorElement,
|
||||
Text,
|
||||
window;
|
||||
|
||||
|
@ -127,6 +129,8 @@ class DOM {
|
|||
el.text = css;
|
||||
return el;
|
||||
}
|
||||
static ShadowRoot createShadowRoot(Element el) => el.createShadowRoot();
|
||||
static ShadowRoot getShadowRoot(Element el) => el.shadowRoot;
|
||||
static clone(Node node) => node.clone(true);
|
||||
static bool hasProperty(Element element, String name) =>
|
||||
new JsObject.fromBrowserObject(element).hasProperty(name);
|
||||
|
|
|
@ -6,8 +6,10 @@ export var Node = window.Node;
|
|||
export var NodeList = window.NodeList;
|
||||
export var Text = window.Text;
|
||||
export var Element = window.HTMLElement;
|
||||
export var AnchorElement = window.HTMLAnchorElement;
|
||||
export var TemplateElement = window.HTMLTemplateElement;
|
||||
export var StyleElement = window.HTMLStyleElement;
|
||||
export var ShadowRoot = window.ShadowRoot;
|
||||
export var document = window.document;
|
||||
export var location = window.location;
|
||||
export var gc = window.gc ? () => window.gc() : () => null;
|
||||
|
@ -144,6 +146,12 @@ export class DOM {
|
|||
style.innerText = css;
|
||||
return style;
|
||||
}
|
||||
static createShadowRoot(el: Element): ShadowRoot {
|
||||
return el.createShadowRoot();
|
||||
}
|
||||
static getShadowRoot(el: Element): ShadowRoot {
|
||||
return el.shadowRoot;
|
||||
}
|
||||
static clone(node:Node) {
|
||||
return node.cloneNode(true);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ export class XHRMock extends XHR {
|
|||
|
||||
if (this._expectations.length > 0) {
|
||||
var expectation = this._expectations[0];
|
||||
if (expectation.url === url) {
|
||||
if (expectation.url == url) {
|
||||
ListWrapper.remove(this._expectations, expectation);
|
||||
request.complete(expectation.response);
|
||||
return;
|
||||
|
|
|
@ -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 {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
|
||||
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 {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
|
@ -41,7 +44,10 @@ export function main() {
|
|||
|
||||
function createCompiler(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) => {
|
||||
|
@ -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) => {
|
||||
var compiler = createCompiler( (parent, current, control) => {
|
||||
if (DOM.hasClass(current.element, 'nested')) {
|
||||
|
@ -102,8 +134,8 @@ export function main() {
|
|||
it('should re-use components being compiled', (done) => {
|
||||
var nestedElBinders = [];
|
||||
var compiler = createCompiler( (parent, current, control) => {
|
||||
current.inheritedProtoView = new ProtoView(current.element, null, null);
|
||||
if (DOM.hasClass(current.element, 'nested')) {
|
||||
current.inheritedProtoView = new ProtoView(current.element, null, null);
|
||||
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
|
||||
current.componentDirective = reader.read(NestedComponent);
|
||||
ListWrapper.push(nestedElBinders, current.inheritedElementBinder);
|
||||
|
@ -134,9 +166,12 @@ export function main() {
|
|||
describe('(mixed async, sync TemplateLoader)', () => {
|
||||
var reader = new DirectiveMetadataReader();
|
||||
|
||||
function createCompiler(processClosure, resolver: TemplateResolver) {
|
||||
function createCompiler(processClosure, templateResolver: TemplateResolver) {
|
||||
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) {
|
||||
|
@ -167,47 +202,72 @@ export function main() {
|
|||
});
|
||||
}
|
||||
|
||||
var resolver = new FakeTemplateResolver();
|
||||
resolver.setSync(ParentComponent);
|
||||
resolver.setSync(NestedComponent);
|
||||
createNestedComponentSpec('(sync -> sync)', resolver);
|
||||
var templateResolver = new FakeTemplateResolver();
|
||||
templateResolver.setSync(ParentComponent);
|
||||
templateResolver.setSync(NestedComponent);
|
||||
createNestedComponentSpec('(sync -> sync)', templateResolver);
|
||||
|
||||
resolver = new FakeTemplateResolver();
|
||||
resolver.setAsync(ParentComponent);
|
||||
resolver.setSync(NestedComponent);
|
||||
createNestedComponentSpec('(async -> sync)', resolver);
|
||||
templateResolver = new FakeTemplateResolver();
|
||||
templateResolver.setAsync(ParentComponent);
|
||||
templateResolver.setSync(NestedComponent);
|
||||
createNestedComponentSpec('(async -> sync)', templateResolver);
|
||||
|
||||
resolver = new FakeTemplateResolver();
|
||||
resolver.setSync(ParentComponent);
|
||||
resolver.setAsync(NestedComponent);
|
||||
createNestedComponentSpec('(sync -> async)', resolver);
|
||||
templateResolver = new FakeTemplateResolver();
|
||||
templateResolver.setSync(ParentComponent);
|
||||
templateResolver.setAsync(NestedComponent);
|
||||
createNestedComponentSpec('(sync -> async)', templateResolver);
|
||||
|
||||
resolver = new FakeTemplateResolver();
|
||||
resolver.setAsync(ParentComponent);
|
||||
resolver.setAsync(NestedComponent);
|
||||
createNestedComponentSpec('(async -> async)', resolver);
|
||||
templateResolver = new FakeTemplateResolver();
|
||||
templateResolver.setAsync(ParentComponent);
|
||||
templateResolver.setAsync(NestedComponent);
|
||||
createNestedComponentSpec('(async -> async)', templateResolver);
|
||||
|
||||
resolver = new FakeTemplateResolver();
|
||||
resolver.setError(ParentComponent);
|
||||
resolver.setSync(NestedComponent);
|
||||
createNestedComponentSpec('(error -> sync)', resolver,
|
||||
templateResolver = new FakeTemplateResolver();
|
||||
templateResolver.setError(ParentComponent);
|
||||
templateResolver.setSync(NestedComponent);
|
||||
createNestedComponentSpec('(error -> sync)', templateResolver,
|
||||
'Failed to load the template for ParentComponent');
|
||||
|
||||
// TODO(vicb): Check why errors this fails with Dart
|
||||
// TODO(vicb): The Promise is rejected with the correct error but an exc is thrown before
|
||||
//resolver = new FakeTemplateResolver();
|
||||
//resolver.setSync(ParentComponent);
|
||||
//resolver.setError(NestedComponent);
|
||||
//createNestedComponentSpec('(sync -> error)', resolver,
|
||||
//templateResolver = new FakeTemplateResolver();
|
||||
//templateResolver.setSync(ParentComponent);
|
||||
//templateResolver.setError(NestedComponent);
|
||||
//createNestedComponentSpec('(sync -> error)', templateResolver,
|
||||
// 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent');
|
||||
//
|
||||
//resolver = new FakeTemplateResolver();
|
||||
//resolver.setAsync(ParentComponent);
|
||||
//resolver.setError(NestedComponent);
|
||||
//createNestedComponentSpec('(async -> error)', resolver,
|
||||
//templateResolver = new FakeTemplateResolver();
|
||||
//templateResolver.setAsync(ParentComponent);
|
||||
//templateResolver.setError(NestedComponent);
|
||||
//createNestedComponentSpec('(async -> error)', templateResolver,
|
||||
// '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;
|
||||
|
||||
constructor(reader:DirectiveMetadataReader, steps:List<CompileStep>, loader: TemplateLoader,
|
||||
resolver: TemplateResolver) {
|
||||
super(dynamicChangeDetection, loader, reader, new Parser(new Lexer()), new CompilerCache(),
|
||||
new NativeShadowDomStrategy(), resolver);
|
||||
templateResolver: TemplateResolver, urlResolver: UrlResolver, cmpUrlMapper: ComponentUrlMapper) {
|
||||
super(dynamicChangeDetection,
|
||||
loader,
|
||||
reader,
|
||||
new Parser(new Lexer()),
|
||||
new CompilerCache(),
|
||||
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
|
||||
templateResolver,
|
||||
cmpUrlMapper,
|
||||
urlResolver);
|
||||
|
||||
this.steps = steps;
|
||||
}
|
||||
|
||||
|
@ -253,9 +321,23 @@ class MockStep extends CompileStep {
|
|||
}
|
||||
}
|
||||
|
||||
class FakeTemplateLoader extends TemplateLoader {
|
||||
class FakeUrlResolver extends UrlResolver {
|
||||
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) {
|
||||
|
@ -307,14 +389,14 @@ class FakeTemplateResolver extends TemplateResolver {
|
|||
}
|
||||
|
||||
if (ListWrapper.contains(this._syncCmp, component)) {
|
||||
return new Template({inline: html});
|
||||
return template;
|
||||
}
|
||||
|
||||
if (ListWrapper.contains(this._asyncCmp, component)) {
|
||||
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});
|
||||
|
||||
throw 'No template';
|
||||
|
|
|
@ -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 {}
|
|
@ -14,6 +14,9 @@ import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_str
|
|||
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
|
||||
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
|
||||
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 {Template} from 'angular2/src/core/annotations/template';
|
||||
|
@ -28,13 +31,16 @@ export function main() {
|
|||
var compiler, tplResolver;
|
||||
|
||||
function createCompiler(tplResolver, changedDetection) {
|
||||
var urlResolver = new UrlResolver();
|
||||
return new Compiler(changedDetection,
|
||||
new TemplateLoader(null),
|
||||
new TemplateLoader(null, null),
|
||||
new DirectiveMetadataReader(),
|
||||
new Parser(new Lexer()),
|
||||
new CompilerCache(),
|
||||
new NativeShadowDomStrategy(),
|
||||
tplResolver
|
||||
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
|
||||
tplResolver,
|
||||
new ComponentUrlMapper(),
|
||||
urlResolver
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ export function main() {
|
|||
current.inheritedProtoView = new ProtoView(
|
||||
current.element,
|
||||
new DynamicProtoChangeDetector(normalizeBlank(registry)),
|
||||
new NativeShadowDomStrategy());
|
||||
new NativeShadowDomStrategy(null));
|
||||
} else if (isPresent(parent)) {
|
||||
current.inheritedProtoView = parent.inheritedProtoView;
|
||||
}
|
||||
|
@ -380,7 +380,7 @@ export function main() {
|
|||
var results = pipeline.process(el('<div viewroot prop-binding directives></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
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);
|
||||
evalContext.prop1 = 'a';
|
||||
|
@ -416,7 +416,7 @@ export function main() {
|
|||
var results = pipeline.process(el('<div viewroot prop-binding directives></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
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);
|
||||
evalContext.prop1 = 'a';
|
||||
|
|
|
@ -21,7 +21,7 @@ export function main() {
|
|||
current.variableBindings = MapWrapper.createFromStringMap(variableBindings);
|
||||
}
|
||||
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', () => {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step';
|
||||
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 {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
|
||||
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';
|
||||
|
||||
export function main() {
|
||||
describe('ShimShadowDom', () => {
|
||||
function createPipeline(ignoreBindings: boolean) {
|
||||
var component = new Component({selector: 'selector'});
|
||||
var meta = new DirectiveMetadata(null, component);
|
||||
var annotation = new Component({selector: 'selector'});
|
||||
var meta = new DirectiveMetadata(SomeComponent, annotation);
|
||||
var shimShadowDom = new ShimShadowDom(meta, new FakeStrategy());
|
||||
|
||||
return new CompilePipeline([
|
||||
|
@ -38,22 +37,22 @@ export function main() {
|
|||
it('should add the content attribute to content element', () => {
|
||||
var pipeline = createPipeline(false);
|
||||
var results = pipeline.process(el('<div></div>'));
|
||||
expect(DOM.getAttribute(results[0].element, '_ngcontent')).toEqual('content');
|
||||
expect(isBlank(DOM.getAttribute(results[0].element, '_nghost'))).toBeTruthy();
|
||||
expect(DOM.getAttribute(results[0].element, 'SomeComponent-content')).toEqual('');
|
||||
expect(isBlank(DOM.getAttribute(results[0].element, 'SomeComponent-host'))).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should add both the content and host attributes to host element', () => {
|
||||
var pipeline = createPipeline(false);
|
||||
var results = pipeline.process(el('<div class="host"></div>'));
|
||||
expect(DOM.getAttribute(results[0].element, '_ngcontent')).toEqual('content');
|
||||
expect(DOM.getAttribute(results[0].element, '_nghost')).toEqual('host');
|
||||
expect(DOM.getAttribute(results[0].element, 'SomeComponent-content')).toEqual('');
|
||||
expect(DOM.getAttribute(results[0].element, 'SomeComponent-host')).toEqual('');
|
||||
});
|
||||
|
||||
it('should do nothing when ignoreBindings is true', () => {
|
||||
var pipeline = createPipeline(true);
|
||||
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, '_nghost'))).toBeTruthy();
|
||||
expect(isBlank(DOM.getAttribute(results[0].element, 'SomeComponent-content'))).toBeTruthy();
|
||||
expect(isBlank(DOM.getAttribute(results[0].element, 'SomeComponent-host'))).toBeTruthy();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -63,22 +62,14 @@ class FakeStrategy extends ShadowDomStrategy {
|
|||
super();
|
||||
}
|
||||
|
||||
getShimComponent(component: Type): ShimComponent {
|
||||
return new FakeShimComponent(component);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeShimComponent extends ShimComponent {
|
||||
constructor(component: Type) {
|
||||
super(component);
|
||||
shimContentElement(component: Type, element: Element) {
|
||||
var attrName = stringify(component) + '-content';
|
||||
DOM.setAttribute(element, attrName, '');
|
||||
}
|
||||
|
||||
shimContentElement(element: Element) {
|
||||
DOM.setAttribute(element, '_ngcontent', 'content');
|
||||
}
|
||||
|
||||
shimHostElement(element: Element) {
|
||||
DOM.setAttribute(element, '_nghost', 'host');
|
||||
shimHostElement(component: Type, element: Element) {
|
||||
var attrName = stringify(component) + '-host';
|
||||
DOM.setAttribute(element, attrName, '');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular
|
|||
|
||||
import {StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||
import {Type} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/facade/dom';
|
||||
|
||||
import {Injector} from 'angular2/di';
|
||||
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
|
||||
|
@ -14,6 +15,11 @@ import {ShadowDomStrategy,
|
|||
NativeShadowDomStrategy,
|
||||
EmulatedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
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 {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() {
|
||||
describe('integration tests', function() {
|
||||
var urlResolver = new UrlResolver();
|
||||
var styleUrlResolver = new StyleUrlResolver(urlResolver);
|
||||
var styleInliner = new StyleInliner(null, styleUrlResolver, urlResolver);
|
||||
|
||||
StringMapWrapper.forEach({
|
||||
"native" : new NativeShadowDomStrategy(),
|
||||
"emulated" : new EmulatedShadowDomStrategy()
|
||||
"native" : new NativeShadowDomStrategy(styleUrlResolver),
|
||||
"emulated" : new EmulatedShadowDomStrategy(styleInliner, styleUrlResolver, DOM.createElement('div'))
|
||||
},
|
||||
(strategy, name) => {
|
||||
|
||||
|
@ -36,12 +45,14 @@ export function main() {
|
|||
beforeEach(() => {
|
||||
tplResolver = new MockTemplateResolver();
|
||||
compiler = new Compiler(dynamicChangeDetection,
|
||||
new TemplateLoader(null),
|
||||
new TemplateLoader(null, null),
|
||||
new DirectiveMetadataReader(),
|
||||
new Parser(new Lexer()),
|
||||
new CompilerCache(),
|
||||
strategy,
|
||||
tplResolver
|
||||
tplResolver,
|
||||
new ComponentUrlMapper(),
|
||||
urlResolver
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -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 {}
|
|
@ -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 {}
|
|
@ -6,24 +6,50 @@ import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
|||
import {Map, MapWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
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() {
|
||||
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', () => {
|
||||
it('should return a string when there is no import statement', () => {
|
||||
var css = '.main {}';
|
||||
var loader = new StyleInliner(null);
|
||||
var loadedCss = loader.inlineImports(css);
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base');
|
||||
expect(loadedCss).not.toBePromise();
|
||||
expect(loadedCss).toEqual(css);
|
||||
});
|
||||
|
||||
it('should inline @import rules', (done) => {
|
||||
var xhr = new FakeXHR();
|
||||
xhr.reply('one.css', '.one {}');
|
||||
var css = '@import "one.css";.main {}';
|
||||
var loader = new StyleInliner(xhr);
|
||||
var loadedCss = loader.inlineImports(css);
|
||||
xhr.reply('http://base/one.css', '.one {}');
|
||||
var css = '@import url("one.css");.main {}';
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base');
|
||||
expect(loadedCss).toBePromise();
|
||||
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();
|
||||
PromiseWrapper.then(
|
||||
loadedCss,
|
||||
|
@ -38,15 +64,13 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should handle @import error gracefuly', (done) => {
|
||||
var xhr = new FakeXHR();
|
||||
var css = '@import "one.css";.main {}';
|
||||
var loader = new StyleInliner(xhr);
|
||||
var loadedCss = loader.inlineImports(css);
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(
|
||||
loadedCss,
|
||||
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();
|
||||
},
|
||||
function(e) {
|
||||
|
@ -56,12 +80,10 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should inline multiple @import rules', (done) => {
|
||||
var xhr = new FakeXHR();
|
||||
xhr.reply('one.css', '.one {}');
|
||||
xhr.reply('two.css', '.two {}');
|
||||
xhr.reply('http://base/one.css', '.one {}');
|
||||
xhr.reply('http://base/two.css', '.two {}');
|
||||
var css = '@import "one.css";@import "two.css";.main {}';
|
||||
var loader = new StyleInliner(xhr);
|
||||
var loadedCss = loader.inlineImports(css);
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(
|
||||
loadedCss,
|
||||
|
@ -76,12 +98,10 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should inline nested @import rules', (done) => {
|
||||
var xhr = new FakeXHR();
|
||||
xhr.reply('one.css', '@import "two.css";.one {}');
|
||||
xhr.reply('two.css', '.two {}');
|
||||
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
|
||||
xhr.reply('http://base/two.css', '.two {}');
|
||||
var css = '@import "one.css";.main {}';
|
||||
var loader = new StyleInliner(xhr);
|
||||
var loadedCss = loader.inlineImports(css);
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base/');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(
|
||||
loadedCss,
|
||||
|
@ -96,12 +116,10 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should handle circular dependencies gracefuly', (done) => {
|
||||
var xhr = new FakeXHR();
|
||||
xhr.reply('one.css', '@import "two.css";.one {}');
|
||||
xhr.reply('two.css', '@import "one.css";.two {}');
|
||||
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
|
||||
xhr.reply('http://base/two.css', '@import "one.css";.two {}');
|
||||
var css = '@import "one.css";.main {}';
|
||||
var loader = new StyleInliner(xhr);
|
||||
var loadedCss = loader.inlineImports(css);
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base/');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(
|
||||
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', () => {
|
||||
it('should wrap inlined content in media query', (done) => {
|
||||
var xhr = new FakeXHR();
|
||||
xhr.reply('one.css', '.one {}');
|
||||
xhr.reply('http://base/one.css', '.one {}');
|
||||
var css = '@import "one.css" (min-width: 700px) and (orientation: landscape);';
|
||||
var loader = new StyleInliner(xhr);
|
||||
var loadedCss = loader.inlineImports(css);
|
||||
var loadedCss = inliner.inlineImports(css, 'http://base/');
|
||||
expect(loadedCss).toBePromise();
|
||||
PromiseWrapper.then(
|
||||
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;'
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -12,20 +12,24 @@ export function main() {
|
|||
@import "2.css";
|
||||
@import url('3.css');
|
||||
@import url("4.css");
|
||||
@import url(5.css);
|
||||
|
||||
.foo {
|
||||
background-image: url("double.jpg");
|
||||
background-image: url('simple.jpg');
|
||||
background-image: url(noquote.jpg);
|
||||
}`;
|
||||
var expectedCss = `
|
||||
@import 'base/1.css';
|
||||
@import 'base/2.css';
|
||||
@import url('base/3.css');
|
||||
@import url('base/4.css');
|
||||
@import url('base/5.css');
|
||||
|
||||
.foo {
|
||||
background-image: url('base/double.jpg');
|
||||
background-image: url('base/simple.jpg');
|
||||
background-image: url('base/noquote.jpg');
|
||||
}`;
|
||||
|
||||
var resolvedCss = styleUrlResolver.resolveUrls(css, 'base');
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
|
||||
|
||||
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';
|
||||
|
||||
|
@ -14,7 +15,7 @@ export function main() {
|
|||
|
||||
beforeEach(() => {
|
||||
xhr = new XHRMock()
|
||||
loader = new TemplateLoader(xhr);
|
||||
loader = new TemplateLoader(xhr, new FakeUrlResolver());
|
||||
});
|
||||
|
||||
it('should load inline templates synchronously', () => {
|
||||
|
@ -23,8 +24,9 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should load templates through XHR', (done) => {
|
||||
xhr.expect('/foo', 'xhr template');
|
||||
xhr.expect('base/foo', 'xhr template');
|
||||
var template = new Template({url: '/foo'});
|
||||
loader.setBaseUrl(template, 'base');
|
||||
loader.load(template).then((el) => {
|
||||
expect(el.content).toHaveText('xhr template');
|
||||
done();
|
||||
|
@ -34,8 +36,9 @@ export function main() {
|
|||
|
||||
it('should cache template loaded through XHR', (done) => {
|
||||
var firstEl;
|
||||
xhr.expect('/foo', 'xhr template');
|
||||
xhr.expect('base/foo', 'xhr template');
|
||||
var template = new Template({url: '/foo'});
|
||||
loader.setBaseUrl(template, 'base');
|
||||
loader.load(template)
|
||||
.then((el) => {
|
||||
firstEl = el;
|
||||
|
@ -56,12 +59,13 @@ export function main() {
|
|||
});
|
||||
|
||||
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'});
|
||||
loader.setBaseUrl(template, 'base');
|
||||
PromiseWrapper.then(loader.load(template),
|
||||
function(_) { throw 'Unexpected response'; },
|
||||
function(error) {
|
||||
expect(error).toEqual('Failed to load /foo');
|
||||
expect(error).toEqual('Failed to load base/foo');
|
||||
done();
|
||||
}
|
||||
)
|
||||
|
@ -73,3 +77,13 @@ export function main() {
|
|||
|
||||
class SomeComponent {
|
||||
}
|
||||
|
||||
class FakeUrlResolver extends UrlResolver {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
resolve(baseUrl: string, url: string): string {
|
||||
return baseUrl + url;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,8 @@ export function main() {
|
|||
dom = el(`<div><stuff></stuff><div insert-after-me></div><stuff></stuff></div>`);
|
||||
var insertionElement = dom.childNodes[1];
|
||||
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);
|
||||
viewContainer = new ViewContainer(parentView, insertionElement, protoView, elementInjector, null);
|
||||
customViewWithOneNode = createView([el('<div>single</div>')]);
|
||||
|
@ -213,7 +214,7 @@ export function main() {
|
|||
viewContainer.hydrate(new Injector([]), null);
|
||||
|
||||
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.bindTextNode(0, parser.parseBinding('foo', null));
|
||||
fancyView = pv.instantiate(null, null);
|
||||
|
|
|
@ -195,7 +195,7 @@ export function main() {
|
|||
it('should be supported.', () => {
|
||||
var template = el('<div></div>');
|
||||
var pv = new ProtoView(template, new DynamicProtoChangeDetector(null),
|
||||
new NativeShadowDomStrategy());
|
||||
new NativeShadowDomStrategy(null));
|
||||
pv.instantiateInPlace = true;
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null);
|
||||
|
@ -205,7 +205,7 @@ export function main() {
|
|||
it('should be off by default.', () => {
|
||||
var template = el('<div></div>')
|
||||
var view = new ProtoView(template, new DynamicProtoChangeDetector(null),
|
||||
new NativeShadowDomStrategy())
|
||||
new NativeShadowDomStrategy(null))
|
||||
.instantiate(null, null);
|
||||
view.hydrate(null, null, null);
|
||||
expect(view.nodes[0]).not.toBe(template);
|
||||
|
@ -312,7 +312,7 @@ export function main() {
|
|||
|
||||
function createComponentWithSubPV(subProtoView) {
|
||||
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));
|
||||
binder.componentDirective = someComponentDirective;
|
||||
binder.nestedProtoView = subProtoView;
|
||||
|
@ -396,7 +396,7 @@ export function main() {
|
|||
new DynamicProtoChangeDetector(null), null);
|
||||
|
||||
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));
|
||||
binder.componentDirective = new DirectiveMetadataReader().read(SomeComponent);
|
||||
binder.nestedProtoView = subpv;
|
||||
|
@ -412,7 +412,7 @@ export function main() {
|
|||
var templateProtoView = new ProtoView(
|
||||
el('<div id="1"></div>'), new DynamicProtoChangeDetector(null), null);
|
||||
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]));
|
||||
binder.viewportDirective = someViewportDirective;
|
||||
binder.nestedProtoView = templateProtoView;
|
||||
|
@ -606,12 +606,13 @@ export function main() {
|
|||
beforeEach(() => {
|
||||
element = DOM.createElement('div');
|
||||
pv = new ProtoView(el('<div>hi</div>'), new DynamicProtoChangeDetector(null),
|
||||
new NativeShadowDomStrategy());
|
||||
new NativeShadowDomStrategy(null));
|
||||
});
|
||||
|
||||
it('should create the root component when instantiated', () => {
|
||||
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);
|
||||
view.hydrate(new Injector([]), null, 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', () => {
|
||||
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);
|
||||
view.hydrate(new Injector([]), null, null);
|
||||
expect(element.shadowRoot.childNodes[0].childNodes[0].nodeValue).toEqual('hi');
|
||||
|
|
|
@ -10,6 +10,9 @@ import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
|||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
|
||||
import {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 {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
|
||||
|
@ -22,10 +25,18 @@ export function main() {
|
|||
describe('foreach', () => {
|
||||
var view, cd, compiler, component, tplResolver;
|
||||
beforeEach(() => {
|
||||
var urlResolver = new UrlResolver();
|
||||
tplResolver = new MockTemplateResolver();
|
||||
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
|
||||
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
|
||||
new NativeShadowDomStrategy(), tplResolver);
|
||||
compiler = new Compiler(
|
||||
dynamicChangeDetection,
|
||||
new TemplateLoader(null, null),
|
||||
new DirectiveMetadataReader(),
|
||||
new Parser(new Lexer()),
|
||||
new CompilerCache(),
|
||||
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
|
||||
tplResolver,
|
||||
new ComponentUrlMapper(),
|
||||
urlResolver);
|
||||
});
|
||||
|
||||
function createView(pv) {
|
||||
|
|
|
@ -9,6 +9,9 @@ import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
|||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
|
||||
import {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 {Template} from 'angular2/src/core/annotations/template';
|
||||
|
@ -22,10 +25,18 @@ export function main() {
|
|||
var view, cd, compiler, component, tplResolver;
|
||||
|
||||
beforeEach(() => {
|
||||
var urlResolver = new UrlResolver();
|
||||
tplResolver = new MockTemplateResolver();
|
||||
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
|
||||
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
|
||||
new NativeShadowDomStrategy(), tplResolver);
|
||||
compiler = new Compiler(
|
||||
dynamicChangeDetection,
|
||||
new TemplateLoader(null, null),
|
||||
new DirectiveMetadataReader(),
|
||||
new Parser(new Lexer()),
|
||||
new CompilerCache(),
|
||||
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
|
||||
tplResolver,
|
||||
new ComponentUrlMapper(),
|
||||
urlResolver);
|
||||
});
|
||||
|
||||
function createView(pv) {
|
||||
|
|
|
@ -2,11 +2,17 @@ import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular
|
|||
import {DOM} from 'angular2/src/facade/dom';
|
||||
import {Injector} from 'angular2/di';
|
||||
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
|
||||
|
||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {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 {Template} from 'angular2/src/core/annotations/template';
|
||||
|
||||
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {NonBindable} from 'angular2/src/directives/non_bindable';
|
||||
|
@ -16,10 +22,18 @@ export function main() {
|
|||
describe('non-bindable', () => {
|
||||
var view, cd, compiler, component, tplResolver;
|
||||
beforeEach(() => {
|
||||
var urlResolver = new UrlResolver();
|
||||
tplResolver = new MockTemplateResolver();
|
||||
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
|
||||
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
|
||||
new NativeShadowDomStrategy(), tplResolver);
|
||||
compiler = new Compiler(
|
||||
dynamicChangeDetection,
|
||||
new TemplateLoader(null, null),
|
||||
new DirectiveMetadataReader(),
|
||||
new Parser(new Lexer()),
|
||||
new CompilerCache(),
|
||||
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
|
||||
tplResolver,
|
||||
new ComponentUrlMapper(),
|
||||
urlResolver);
|
||||
});
|
||||
|
||||
function createView(pv) {
|
||||
|
|
|
@ -2,9 +2,14 @@ import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular
|
|||
import {DOM} from 'angular2/src/facade/dom';
|
||||
import {Injector} from 'angular2/di';
|
||||
import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection';
|
||||
|
||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {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 {Template} from 'angular2/src/core/annotations/template';
|
||||
import {TemplateLoader} from 'angular2/core';
|
||||
|
@ -15,10 +20,18 @@ export function main() {
|
|||
describe('switch', () => {
|
||||
var view, cd, compiler, component, tplResolver;
|
||||
beforeEach(() => {
|
||||
var urlResolver = new UrlResolver();
|
||||
tplResolver = new MockTemplateResolver();
|
||||
compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
|
||||
new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache(),
|
||||
new NativeShadowDomStrategy(), tplResolver);
|
||||
compiler = new Compiler(
|
||||
dynamicChangeDetection,
|
||||
new TemplateLoader(null, null),
|
||||
new DirectiveMetadataReader(),
|
||||
new Parser(new Lexer()),
|
||||
new CompilerCache(),
|
||||
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
|
||||
tplResolver,
|
||||
new ComponentUrlMapper(),
|
||||
urlResolver);
|
||||
});
|
||||
|
||||
function createView(pv) {
|
||||
|
|
|
@ -6,6 +6,10 @@ import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
|||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
|
||||
import {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 {Injector} from 'angular2/di';
|
||||
|
@ -22,14 +26,17 @@ export function main() {
|
|||
|
||||
function compile(componentType, template, context, callback) {
|
||||
var tplResolver = new MockTemplateResolver();
|
||||
var urlResolver = new UrlResolver();
|
||||
|
||||
var compiler = new Compiler(dynamicChangeDetection,
|
||||
new TemplateLoader(null),
|
||||
new TemplateLoader(null, null),
|
||||
new DirectiveMetadataReader(),
|
||||
new Parser(new Lexer()),
|
||||
new CompilerCache(),
|
||||
new NativeShadowDomStrategy(),
|
||||
tplResolver
|
||||
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
|
||||
tplResolver,
|
||||
new ComponentUrlMapper(),
|
||||
urlResolver
|
||||
);
|
||||
|
||||
tplResolver.setTemplate(componentType, new Template({
|
||||
|
|
|
@ -14,6 +14,9 @@ import {Decorator} from 'angular2/src/core/annotations/annotations';
|
|||
import {Template} from 'angular2/src/core/annotations/template';
|
||||
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
|
||||
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||
import {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 {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util';
|
||||
|
@ -83,8 +86,18 @@ export function main() {
|
|||
var reader = new DirectiveMetadataReader();
|
||||
var cache = new CompilerCache();
|
||||
var templateResolver = new FakeTemplateResolver();
|
||||
var compiler = new Compiler(dynamicChangeDetection, new TemplateLoader(null),
|
||||
reader, new Parser(new Lexer()), cache, new NativeShadowDomStrategy(), templateResolver);
|
||||
var urlResolver = new UrlResolver();
|
||||
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 templateWithBindings = createTemplateHtml('templateWithBindings', count);
|
||||
|
||||
|
|
|
@ -17,6 +17,10 @@ import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
|||
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
||||
import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
|
||||
import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl';
|
||||
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 {App, setupReflectorForApp} from './app';
|
||||
|
@ -176,11 +180,12 @@ export function setupReflectorForAngular() {
|
|||
|
||||
reflector.registerType(Compiler, {
|
||||
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
|
||||
resolver) =>
|
||||
tplResolver, cmpUrlMapper, urlResolver) =>
|
||||
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
|
||||
resolver),
|
||||
tplResolver, cmpUrlMapper, urlResolver),
|
||||
"parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser],
|
||||
[CompilerCache], [ShadowDomStrategy], [TemplateResolver]],
|
||||
[CompilerCache], [ShadowDomStrategy], [TemplateResolver], [ComponentUrlMapper],
|
||||
[UrlResolver]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
|
@ -197,8 +202,8 @@ export function setupReflectorForAngular() {
|
|||
});
|
||||
|
||||
reflector.registerType(TemplateLoader, {
|
||||
"factory": (xhr) => new TemplateLoader(xhr),
|
||||
"parameters": [[XHR]],
|
||||
"factory": (xhr, urlResolver) => new TemplateLoader(xhr, urlResolver),
|
||||
"parameters": [[XHR], [UrlResolver]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
|
@ -239,9 +244,38 @@ export function setupReflectorForAngular() {
|
|||
});
|
||||
|
||||
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": [],
|
||||
"annotations": []
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@ import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
|
|||
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
||||
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 {DOM, document, window, Element, gc} from 'angular2/src/facade/dom';
|
||||
|
@ -62,10 +66,13 @@ function setupReflector() {
|
|||
});
|
||||
|
||||
reflector.registerType(Compiler, {
|
||||
'factory': (cd, templateLoader, reader, parser, compilerCache, strategy, resolver) =>
|
||||
new Compiler(cd, templateLoader, reader, parser, compilerCache, strategy, resolver),
|
||||
'factory': (cd, templateLoader, reader, parser, compilerCache, strategy, tplResolver,
|
||||
cmpUrlMapper, urlResolver) =>
|
||||
new Compiler(cd, templateLoader, reader, parser, compilerCache, strategy, tplResolver,
|
||||
cmpUrlMapper, urlResolver),
|
||||
'parameters': [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader],
|
||||
[Parser], [CompilerCache], [ShadowDomStrategy], [TemplateResolver]],
|
||||
[Parser], [CompilerCache], [ShadowDomStrategy], [TemplateResolver],
|
||||
[ComponentUrlMapper], [UrlResolver]],
|
||||
'annotations': []
|
||||
});
|
||||
|
||||
|
@ -82,8 +89,8 @@ function setupReflector() {
|
|||
});
|
||||
|
||||
reflector.registerType(TemplateLoader, {
|
||||
'factory': (xhr) => new TemplateLoader(xhr),
|
||||
'parameters': [[XHR]],
|
||||
'factory': (xhr, urlResolver) => new TemplateLoader(xhr, urlResolver),
|
||||
'parameters': [[XHR], [UrlResolver]],
|
||||
'annotations': []
|
||||
});
|
||||
|
||||
|
@ -106,9 +113,27 @@ function setupReflector() {
|
|||
});
|
||||
|
||||
reflector.registerType(ShadowDomStrategy, {
|
||||
'factory': () => new NativeShadowDomStrategy(),
|
||||
'parameters': [],
|
||||
'annotations': []
|
||||
"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(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({
|
||||
'value': (a) => a.value,
|
||||
'left': (a) => a.left,
|
||||
|
|
|
@ -12,6 +12,10 @@ import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
|
|||
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||
import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
|
||||
import {XHRImpl} from 'angular2/src/core/compiler/xhr/xhr_impl';
|
||||
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';
|
||||
|
||||
|
@ -45,11 +49,12 @@ function setup() {
|
|||
|
||||
reflector.registerType(Compiler, {
|
||||
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
|
||||
resolver) =>
|
||||
tplResolver, cmpUrlMapper, urlResolver) =>
|
||||
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
|
||||
resolver),
|
||||
tplResolver, cmpUrlMapper, urlResolver),
|
||||
"parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser],
|
||||
[CompilerCache], [ShadowDomStrategy], [TemplateResolver]],
|
||||
[CompilerCache], [ShadowDomStrategy], [TemplateResolver], [ComponentUrlMapper],
|
||||
[UrlResolver]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
|
@ -66,8 +71,8 @@ function setup() {
|
|||
});
|
||||
|
||||
reflector.registerType(TemplateLoader, {
|
||||
"factory": (xhr) => new TemplateLoader(xhr),
|
||||
"parameters": [[XHR]],
|
||||
"factory": (xhr, urlResolver) => new TemplateLoader(xhr, urlResolver),
|
||||
"parameters": [[XHR], [UrlResolver]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
|
@ -108,7 +113,37 @@ function setup() {
|
|||
});
|
||||
|
||||
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": [],
|
||||
"annotations": []
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue