11import { Injectable } from 'angular2/di' ;
2- import { isBlank , isPresent , BaseException , stringify } from 'angular2/src/facade/lang' ;
3- import { Map , MapWrapper , ListWrapper } from 'angular2/src/facade/collection' ;
2+ import { isBlank , isPresent , BaseException , stringify , isPromise } from 'angular2/src/facade/lang' ;
3+ import { Map , MapWrapper , ListWrapper , List } from 'angular2/src/facade/collection' ;
44import { PromiseWrapper , Promise } from 'angular2/src/facade/async' ;
55import { DOM } from 'angular2/src/dom/dom_adapter' ;
66
77import { XHR } from 'angular2/src/render/xhr' ;
88
99import { ViewDefinition } from '../../api' ;
10- import { UrlResolver } from 'angular2/src/services/url_resolver' ;
10+
11+ import { StyleInliner } from './style_inliner' ;
12+ import { StyleUrlResolver } from './style_url_resolver' ;
1113
1214/**
1315 * Strategy to load component templates.
@@ -17,37 +19,36 @@ import {UrlResolver} from 'angular2/src/services/url_resolver';
1719export class TemplateLoader {
1820 _cache : Map < string , Promise < string > > = new Map ( ) ;
1921
20- constructor ( private _xhr : XHR , urlResolver : UrlResolver ) { }
22+ constructor ( private _xhr : XHR , private _styleInliner : StyleInliner ,
23+ private _styleUrlResolver : StyleUrlResolver ) { }
2124
2225 load ( view : ViewDefinition ) : Promise < /*element*/ any > {
23- let html ;
24- let fetchedStyles ;
26+ let tplElAndStyles : List < string | Promise < string > > = [ this . _loadHtml ( view ) ] ;
2527
26- // Load the HTML
27- if ( isPresent ( view . template ) ) {
28- html = PromiseWrapper . resolve ( view . template ) ;
29- } else if ( isPresent ( view . templateAbsUrl ) ) {
30- html = this . _loadText ( view . templateAbsUrl ) ;
31- } else {
32- throw new BaseException ( 'View should have either the templateUrl or template property set' ) ;
28+ if ( isPresent ( view . styles ) ) {
29+ view . styles . forEach ( ( cssText : string ) => {
30+ let textOrPromise = this . _resolveAndInlineCssText ( cssText , view . templateAbsUrl ) ;
31+ tplElAndStyles . push ( textOrPromise ) ;
32+ } ) ;
3333 }
3434
35- // Load the styles
36- if ( isPresent ( view . styleAbsUrls ) && view . styleAbsUrls . length > 0 ) {
37- fetchedStyles = ListWrapper . map ( view . styleAbsUrls , url => this . _loadText ( url ) ) ;
38- } else {
39- fetchedStyles = [ ] ;
35+ if ( isPresent ( view . styleAbsUrls ) ) {
36+ view . styleAbsUrls . forEach ( url => {
37+ let promise = this . _loadText ( url ) . then (
38+ cssText => this . _resolveAndInlineCssText ( cssText , view . templateAbsUrl ) ) ;
39+ tplElAndStyles . push ( promise ) ;
40+ } ) ;
4041 }
4142
42- // Inline the styles and return a template element
43- return PromiseWrapper . all ( ListWrapper . concat ( [ html ] , fetchedStyles ) )
43+ // Inline the styles from the @View annotation and return a template element
44+ return PromiseWrapper . all ( tplElAndStyles )
4445 . then ( ( res : List < string > ) => {
45- let html = res [ 0 ] ;
46- let fetchedStyles = ListWrapper . slice ( res , 1 ) ;
46+ let tplEl = res [ 0 ] ;
47+ let cssTexts = ListWrapper . slice ( res , 1 ) ;
4748
48- html = _createStyleTags ( view . styles ) + _createStyleTags ( fetchedStyles ) + html ;
49+ _insertCssTexts ( DOM . content ( tplEl ) , cssTexts ) ;
4950
50- return DOM . createTemplate ( html ) ;
51+ return tplEl ;
5152 } ) ;
5253 }
5354
@@ -67,10 +68,74 @@ export class TemplateLoader {
6768
6869 return response ;
6970 }
71+
72+ // Load the html and inline any style tags
73+ private _loadHtml ( view : ViewDefinition ) : Promise < any /* element */ > {
74+ let html ;
75+
76+ // Load the HTML
77+ if ( isPresent ( view . template ) ) {
78+ html = PromiseWrapper . resolve ( view . template ) ;
79+ } else if ( isPresent ( view . templateAbsUrl ) ) {
80+ html = this . _loadText ( view . templateAbsUrl ) ;
81+ } else {
82+ throw new BaseException ( 'View should have either the templateUrl or template property set' ) ;
83+ }
84+
85+ // Inline the style tags from the html
86+ return html . then ( html => {
87+ var tplEl = DOM . createTemplate ( html ) ;
88+ let styleEls = DOM . querySelectorAll ( DOM . content ( tplEl ) , 'STYLE' ) ;
89+
90+ let promises : List < Promise < string > > = [ ] ;
91+ for ( let i = 0 ; i < styleEls . length ; i ++ ) {
92+ let promise = this . _resolveAndInlineElement ( styleEls [ i ] , view . templateAbsUrl ) ;
93+ if ( isPromise ( promise ) ) {
94+ promises . push ( promise ) ;
95+ }
96+ }
97+
98+ return promises . length > 0 ? PromiseWrapper . all ( promises ) . then ( _ => tplEl ) : tplEl ;
99+ } ) ;
100+ }
101+
102+ /**
103+ * Inlines a style element.
104+ *
105+ * @param styleEl The style element
106+ * @param baseUrl The base url
107+ * @returns {Promise<any> } null when no @import rule exist in the css or a Promise
108+ * @private
109+ */
110+ private _resolveAndInlineElement ( styleEl , baseUrl : string ) : Promise < any > {
111+ let textOrPromise = this . _resolveAndInlineCssText ( DOM . getText ( styleEl ) , baseUrl ) ;
112+
113+ if ( isPromise ( textOrPromise ) ) {
114+ return ( < Promise < string > > textOrPromise ) . then ( css => { DOM . setText ( styleEl , css ) ; } ) ;
115+ } else {
116+ DOM . setText ( styleEl , < string > textOrPromise ) ;
117+ return null ;
118+ }
119+ }
120+
121+ private _resolveAndInlineCssText ( cssText : string , baseUrl : string ) : string | Promise < string > {
122+ cssText = this . _styleUrlResolver . resolveUrls ( cssText , baseUrl ) ;
123+ return this . _styleInliner . inlineImports ( cssText , baseUrl ) ;
124+ }
70125}
71126
72- function _createStyleTags ( styles ?: List < string > ) : string {
73- return isBlank ( styles ) ?
74- '' :
75- ListWrapper . map ( styles , css => `<style type='text/css'>${ css } </style>` ) . join ( '' ) ;
127+ function _insertCssTexts ( element , cssTexts : List < string > ) : void {
128+ if ( cssTexts . length == 0 ) return ;
129+
130+ let insertBefore = DOM . firstChild ( element ) ;
131+
132+ for ( let i = cssTexts . length - 1 ; i >= 0 ; i -- ) {
133+ let styleEl = DOM . createStyleElement ( cssTexts [ i ] ) ;
134+ if ( isPresent ( insertBefore ) ) {
135+ DOM . insertBefore ( insertBefore , styleEl ) ;
136+ } else {
137+ DOM . appendChild ( element , styleEl ) ;
138+ }
139+ insertBefore = styleEl ;
140+ }
76141}
0 commit comments