feat(View): add support for styleUrls and styles

fixes #2382
This commit is contained in:
Victor Berchet
2015-06-10 14:40:24 +02:00
parent f065a2ecb7
commit ac3e624d0f
12 changed files with 220 additions and 102 deletions

View File

@ -256,19 +256,25 @@ export class RenderViewRef {}
export class ViewDefinition {
componentId: string;
absUrl: string;
templateAbsUrl: string;
template: string;
directives: List<DirectiveMetadata>;
styleAbsUrls: List<string>;
styles: List<string>;
constructor({componentId, absUrl, template, directives}: {
constructor({componentId, templateAbsUrl, template, styleAbsUrls, styles, directives}: {
componentId?: string,
absUrl?: string,
templateAbsUrl?: string,
template?: string,
styleAbsUrls?: List<string>,
styles?: List<string>,
directives?: List<DirectiveMetadata>
}) {
this.componentId = componentId;
this.absUrl = absUrl;
this.templateAbsUrl = templateAbsUrl;
this.template = template;
this.styleAbsUrls = styleAbsUrls;
this.styles = styles;
this.directives = directives;
}
}

View File

@ -43,7 +43,9 @@ export class DomCompiler extends RenderCompiler {
compileHost(directiveMetadata: DirectiveMetadata): Promise<ProtoViewDto> {
var hostViewDef = new ViewDefinition({
componentId: directiveMetadata.id,
absUrl: null, template: null,
templateAbsUrl: null, template: null,
styles: null,
styleAbsUrls: null,
directives: [directiveMetadata]
});
var element = DOM.createElement(directiveMetadata.selector);

View File

@ -1,6 +1,6 @@
import {Injectable} from 'angular2/di';
import {isBlank, isPresent, BaseException, stringify} from 'angular2/src/facade/lang';
import {Map, MapWrapper, StringMapWrapper, StringMap} from 'angular2/src/facade/collection';
import {Map, MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
import {DOM} from 'angular2/src/dom/dom_adapter';
@ -15,35 +15,62 @@ import {UrlResolver} from 'angular2/src/services/url_resolver';
*/
@Injectable()
export class TemplateLoader {
_htmlCache: StringMap<string, /*element*/ any> = StringMapWrapper.create();
_cache: Map<string, Promise<string>> = MapWrapper.create();
constructor(public _xhr: XHR, urlResolver: UrlResolver) {}
constructor(private _xhr: XHR, urlResolver: UrlResolver) {}
load(template: ViewDefinition): Promise</*element*/ any> {
if (isPresent(template.template)) {
return PromiseWrapper.resolve(DOM.createTemplate(template.template));
}
var url = template.absUrl;
if (isPresent(url)) {
var promise = StringMapWrapper.get(this._htmlCache, url);
load(view: ViewDefinition): Promise</*element*/ any> {
let html;
let fetchedStyles;
if (isBlank(promise)) {
// TODO(vicb): change error when TS gets fixed
// https://github.com/angular/angular/issues/2280
// throw new BaseException(`Failed to fetch url "${url}"`);
promise = PromiseWrapper.then(this._xhr.get(url), html => {
var template = DOM.createTemplate(html);
return template;
}, _ => PromiseWrapper.reject(new BaseException(`Failed to fetch url "${url}"`), null));
StringMapWrapper.set(this._htmlCache, url, promise);
}
// We need to clone the result as others might change it
// (e.g. the compiler).
return promise.then((tplElement) => DOM.clone(tplElement));
// Load the HTML
if (isPresent(view.template)) {
html = PromiseWrapper.resolve(view.template);
} else if (isPresent(view.templateAbsUrl)) {
html = this._loadText(view.templateAbsUrl);
} else {
throw new BaseException('View should have either the templateUrl or template property set');
}
throw new BaseException('View should have either the url or template property set');
// Load the styles
if (isPresent(view.styleAbsUrls) && view.styleAbsUrls.length > 0) {
fetchedStyles = ListWrapper.map(view.styleAbsUrls, url => this._loadText(url));
} else {
fetchedStyles = [];
}
// Inline the styles and return a template element
return PromiseWrapper.all(ListWrapper.concat([html], fetchedStyles))
.then((res: List<string>) => {
let html = res[0];
let fetchedStyles = ListWrapper.slice(res, 1);
html = _createStyleTags(view.styles) + _createStyleTags(fetchedStyles) + html;
return DOM.createTemplate(html);
});
}
private _loadText(url: string): Promise<string> {
var response = MapWrapper.get(this._cache, url);
if (isBlank(response)) {
// TODO(vicb): change error when TS gets fixed
// https://github.com/angular/angular/issues/2280
// throw new BaseException(`Failed to fetch url "${url}"`);
response = PromiseWrapper.catchError(
this._xhr.get(url),
_ => PromiseWrapper.reject(new BaseException(`Failed to fetch url "${url}"`), null));
MapWrapper.set(this._cache, url, response);
}
return response;
}
}
function _createStyleTags(styles?: List<string>): string {
return isBlank(styles) ?
'' :
ListWrapper.map(styles, css => `<style type='text/css'>${css}</style>`).join('');
}

View File

@ -29,7 +29,7 @@ export class ShadowDomCompileStep implements CompileStep {
_processStyleElement(current: CompileElement, control: CompileControl) {
var stylePromise = this._shadowDomStrategy.processStyleElement(
this._template.componentId, this._template.absUrl, current.element);
this._template.componentId, this._template.templateAbsUrl, current.element);
if (isPresent(stylePromise) && PromiseWrapper.isPromise(stylePromise)) {
ListWrapper.push(this._subTaskPromises, stylePromise);
}

View File

@ -8,7 +8,7 @@ import {NG_BINDING_CLASS} from '../util';
import {RenderProtoViewRef} from '../../api';
export function resolveInternalDomProtoView(protoViewRef: RenderProtoViewRef) {
export function resolveInternalDomProtoView(protoViewRef: RenderProtoViewRef): DomProtoView {
return (<DomProtoViewRef>protoViewRef)._protoView;
}