@@ -10,82 +10,141 @@ if (!scope) {
10
10
scope = window . HTMLImports = { flags :{ } } ;
11
11
}
12
12
13
+ // imports
14
+
15
+ var xhr = scope . xhr ;
16
+
17
+ // importer
18
+
13
19
var IMPORT_LINK_TYPE = 'import' ;
20
+ var STYLE_LINK_TYPE = 'stylesheet' ;
14
21
15
- // highlander object represents a primary document (the argument to 'parse ')
22
+ // highlander object represents a primary document (the argument to 'load ')
16
23
// at the root of a tree of documents
17
24
25
+ // for any document, importer:
26
+ // - loads any linked documents (with deduping), modifies paths and feeds them back into importer
27
+ // - loads text of external script tags
28
+ // - loads text of external style tags inside of <element>, modifies paths
29
+
30
+ // when importer 'modifies paths' in a document, this includes
31
+ // - href/src/action in node attributes
32
+ // - paths in inline stylesheets
33
+ // - all content inside templates
34
+
35
+ // linked style sheets in an import have their own path fixed up when their containing import modifies paths
36
+ // linked style sheets in an <element> are loaded, and the content gets path fixups
37
+ // inline style sheets get path fixups when their containing import modifies paths
38
+
18
39
var importer = {
19
40
documents : { } ,
20
41
cache : { } ,
21
42
preloadSelectors : [
22
43
'link[rel=' + IMPORT_LINK_TYPE + ']' ,
23
- 'script[src]' ,
24
- 'link[rel=stylesheet]'
44
+ 'element link[rel=' + STYLE_LINK_TYPE + ']' ,
45
+ 'template' ,
46
+ 'script[src]'
25
47
] . join ( ',' ) ,
26
- load : function ( inDocument , inNext ) {
48
+ loader : function ( inNext ) {
27
49
// construct a loader instance
28
50
loader = new Loader ( importer . loaded , inNext ) ;
29
51
// alias the loader cache (for debugging)
30
52
loader . cache = importer . cache ;
53
+ return loader ;
54
+ } ,
55
+ load : function ( inDocument , inNext ) {
56
+ // construct a loader instance
57
+ loader = importer . loader ( inNext ) ;
31
58
// add nodes from document into loader queue
32
59
importer . preload ( inDocument ) ;
33
60
} ,
34
61
preload : function ( inDocument ) {
35
62
// all preloadable nodes in inDocument
36
63
var nodes = inDocument . querySelectorAll ( importer . preloadSelectors ) ;
37
- // only load imports from the main document
64
+ // from the main document, only load imports
38
65
// TODO(sjmiles): do this by altering the selector list instead
66
+ nodes = this . filterMainDocumentNodes ( inDocument , nodes ) ;
67
+ // extra link nodes from templates, filter templates out of the nodes list
68
+ nodes = this . extractTemplateNodes ( nodes ) ;
69
+ // add these nodes to loader's queue
70
+ loader . addNodes ( nodes ) ;
71
+ } ,
72
+ filterMainDocumentNodes : function ( inDocument , nodes ) {
39
73
if ( inDocument === document ) {
40
74
nodes = Array . prototype . filter . call ( nodes , function ( n ) {
41
- return isDocumentLink ( n ) ;
75
+ return ! isScript ( n ) ;
42
76
} ) ;
43
77
}
44
- // add these nodes to loader's queue
45
- loader . addNodes ( nodes ) ;
78
+ return nodes ;
79
+ } ,
80
+ extractTemplateNodes : function ( nodes ) {
81
+ var extra = [ ] ;
82
+ nodes = Array . prototype . filter . call ( nodes , function ( n ) {
83
+ if ( n . localName === 'template' ) {
84
+ if ( n . content ) {
85
+ var l$ = n . content . querySelectorAll ( 'link[rel=' + STYLE_LINK_TYPE +
86
+ ']' ) ;
87
+ if ( l$ . length ) {
88
+ extra = extra . concat ( Array . prototype . slice . call ( l$ , 0 ) ) ;
89
+ }
90
+ }
91
+ return false ;
92
+ }
93
+ return true ;
94
+ } ) ;
95
+ if ( extra . length ) {
96
+ nodes = nodes . concat ( extra ) ;
97
+ }
98
+ return nodes ;
46
99
} ,
47
- loaded : function ( inUrl , inElt , inResource ) {
48
- if ( isDocumentLink ( inElt ) ) {
49
- var document = importer . documents [ inUrl ] ;
100
+ loaded : function ( url , elt , resource ) {
101
+ if ( isDocumentLink ( elt ) ) {
102
+ var document = importer . documents [ url ] ;
50
103
// if we've never seen a document at this url
51
104
if ( ! document ) {
52
105
// generate an HTMLDocument from data
53
- document = makeDocument ( inResource , inUrl ) ;
106
+ document = makeDocument ( resource , url ) ;
54
107
// resolve resource paths relative to host document
55
- path . resolvePathsInHTML ( document ) ;
108
+ path . resolvePathsInHTML ( document . body ) ;
56
109
// cache document
57
- importer . documents [ inUrl ] = document ;
110
+ importer . documents [ url ] = document ;
58
111
// add nodes from this document to the loader queue
59
112
importer . preload ( document ) ;
60
113
}
114
+ // store import record
115
+ elt . import = {
116
+ href : url ,
117
+ ownerNode : elt ,
118
+ content : document
119
+ } ;
61
120
// store document resource
62
- inElt . content = inElt . __resource = document ;
63
- } else {
64
- inElt . __resource = inResource ;
65
- // resolve stylesheet resource paths relative to host document
66
- if ( isStylesheetLink ( inElt ) ) {
67
- path . resolvePathsInStylesheet ( inElt ) ;
68
- }
121
+ elt . content = resource = document ;
122
+ }
123
+ // store generic resource
124
+ // TODO(sorvell): fails for nodes inside <template>.content
125
+ // see https://code.google.com/p/chromium/issues/detail?id=249381.
126
+ elt . __resource = resource ;
127
+ // css path fixups
128
+ if ( isStylesheetLink ( elt ) ) {
129
+ path . resolvePathsInStylesheet ( elt ) ;
69
130
}
70
131
}
71
132
} ;
72
133
73
- function isDocumentLink ( inElt ) {
74
- return isLinkRel ( inElt , IMPORT_LINK_TYPE ) ;
134
+ function isDocumentLink ( elt ) {
135
+ return isLinkRel ( elt , IMPORT_LINK_TYPE ) ;
75
136
}
76
137
77
- function isStylesheetLink ( inElt ) {
78
- return isLinkRel ( inElt , 'stylesheet' ) ;
138
+ function isStylesheetLink ( elt ) {
139
+ return isLinkRel ( elt , STYLE_LINK_TYPE ) ;
79
140
}
80
141
81
- function isLinkRel ( inElt , inRel ) {
82
- return ( inElt . localName === 'link' && inElt . getAttribute ( 'rel' ) === inRel ) ;
142
+ function isLinkRel ( elt , rel ) {
143
+ return elt . localName === 'link' && elt . getAttribute ( 'rel' ) === rel ;
83
144
}
84
145
85
- function inMainDocument ( inElt ) {
86
- return inElt . ownerDocument === document ||
87
- // TODO(sjmiles): ShadowDOMPolyfill intrusion
88
- inElt . ownerDocument . impl === document ;
146
+ function isScript ( elt ) {
147
+ return elt . localName === 'script' ;
89
148
}
90
149
91
150
function makeDocument ( inHTML , inUrl ) {
@@ -99,6 +158,10 @@ function makeDocument(inHTML, inUrl) {
99
158
doc . head . appendChild ( base ) ;
100
159
// install html
101
160
doc . body . innerHTML = inHTML ;
161
+ // TODO(sorvell): MDV Polyfill intrusion: boostrap template polyfill
162
+ if ( window . HTMLTemplateElement && HTMLTemplateElement . bootstrap ) {
163
+ HTMLTemplateElement . bootstrap ( doc ) ;
164
+ }
102
165
return doc ;
103
166
}
104
167
@@ -151,10 +214,11 @@ Loader.prototype = {
151
214
// need fetch (not a dupe)
152
215
return false ;
153
216
} ,
154
- fetch : function ( inUrl , inElt ) {
155
- xhr . load ( inUrl , function ( err , resource ) {
156
- this . receive ( inUrl , inElt , err , resource ) ;
157
- } . bind ( this ) ) ;
217
+ fetch : function ( url , elt ) {
218
+ var receiveXhr = function ( err , resource ) {
219
+ this . receive ( url , elt , err , resource ) ;
220
+ } . bind ( this ) ;
221
+ xhr . load ( url , receiveXhr ) ;
158
222
} ,
159
223
receive : function ( inUrl , inElt , inErr , inResource ) {
160
224
if ( ! inErr ) {
@@ -179,6 +243,10 @@ Loader.prototype = {
179
243
}
180
244
} ;
181
245
246
+ var URL_ATTRS = [ 'href' , 'src' , 'action' ] ;
247
+ var URL_ATTRS_SELECTOR = '[' + URL_ATTRS . join ( '],[' ) + ']' ;
248
+ var URL_TEMPLATE_SEARCH = '{{.*}}' ;
249
+
182
250
var path = {
183
251
nodeUrl : function ( inNode ) {
184
252
return path . resolveUrl ( path . getDocumentUrl ( document ) , path . hrefOrSrc ( inNode ) ) ;
@@ -243,26 +311,18 @@ var path = {
243
311
var r = t . join ( "/" ) ;
244
312
return r ;
245
313
} ,
246
- resolvePathsInHTML : function ( inRoot ) {
247
- var docUrl = path . documentUrlFromNode ( inRoot . body ) ;
248
- // TODO(sorvell): MDV Polyfill Intrusion
249
- if ( window . HTMLTemplateElement && HTMLTemplateElement . bootstrap ) {
250
- HTMLTemplateElement . bootstrap ( inRoot ) ;
251
- }
252
- var node = inRoot . body ;
253
- path . _resolvePathsInHTML ( node , docUrl ) ;
254
- } ,
255
- _resolvePathsInHTML : function ( inRoot , inUrl ) {
256
- path . resolveAttributes ( inRoot , inUrl ) ;
257
- path . resolveStyleElts ( inRoot , inUrl ) ;
258
- // handle templates, if supported
259
- if ( window . templateContent ) {
260
- var templates = inRoot . querySelectorAll ( 'template' ) ;
261
- if ( templates ) {
262
- forEach ( templates , function ( t ) {
263
- path . _resolvePathsInHTML ( templateContent ( t ) , inUrl ) ;
264
- } ) ;
265
- }
314
+ resolvePathsInHTML : function ( root , url ) {
315
+ url = url || path . documentUrlFromNode ( root )
316
+ path . resolveAttributes ( root , url ) ;
317
+ path . resolveStyleElts ( root , url ) ;
318
+ // handle template.content
319
+ var templates = root . querySelectorAll ( 'template' ) ;
320
+ if ( templates ) {
321
+ forEach ( templates , function ( t ) {
322
+ if ( t . content ) {
323
+ path . resolvePathsInHTML ( t . content , url ) ;
324
+ }
325
+ } ) ;
266
326
}
267
327
} ,
268
328
resolvePathsInStylesheet : function ( inSheet ) {
@@ -306,11 +366,7 @@ var path = {
306
366
}
307
367
} ;
308
368
309
- var URL_ATTRS = [ 'href' , 'src' , 'action' ] ;
310
- var URL_ATTRS_SELECTOR = '[' + URL_ATTRS . join ( '],[' ) + ']' ;
311
- var URL_TEMPLATE_SEARCH = '{{.*}}' ;
312
-
313
- var xhr = scope . xhr || {
369
+ xhr = xhr || {
314
370
async : true ,
315
371
ok : function ( inRequest ) {
316
372
return ( inRequest . status >= 200 && inRequest . status < 300 )
@@ -340,30 +396,6 @@ var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
340
396
scope . xhr = xhr ;
341
397
scope . importer = importer ;
342
398
scope . getDocumentUrl = path . getDocumentUrl ;
343
-
344
- // bootstrap
345
-
346
- // IE shim for CustomEvent
347
- if ( typeof window . CustomEvent !== 'function' ) {
348
- window . CustomEvent = function ( inType ) {
349
- var e = document . createEvent ( 'HTMLEvents' ) ;
350
- e . initEvent ( inType , true , true ) ;
351
- return e ;
352
- } ;
353
- }
354
-
355
- document . addEventListener ( 'DOMContentLoaded' , function ( ) {
356
- // preload document resource trees
357
- importer . load ( document , function ( ) {
358
- // TODO(sjmiles): ShadowDOM polyfill pollution
359
- var doc = window . ShadowDOMPolyfill ? ShadowDOMPolyfill . wrap ( document )
360
- : document ;
361
- HTMLImports . readyTime = new Date ( ) . getTime ( ) ;
362
- // send HTMLImportsLoaded when finished
363
- doc . body . dispatchEvent (
364
- new CustomEvent ( 'HTMLImportsLoaded' , { bubbles : true } )
365
- ) ;
366
- } ) ;
367
- } ) ;
399
+ scope . IMPORT_LINK_TYPE = IMPORT_LINK_TYPE ;
368
400
369
401
} ) ( window . HTMLImports ) ;
0 commit comments