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