1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * @fileoverview Deferred resource loader for OOBE/Login screens.
9 cr
.define('cr.ui.login.ResourceLoader', function() {
16 * Register assets for deferred loading. When the bundle is loaded
17 * assets will be added to the current page's DOM: <link> and <script>
18 * tags pointing to the CSS and JavaScript will be added to the
19 * <head>, and HTML will be appended to a specified element.
21 * @param {Object} desc Descriptor for the asset bundle
22 * @param {string} desc.id Unique identifier for the asset bundle.
23 * @param {Array=} desc.js URLs containing JavaScript sources.
24 * @param {Array=} desc.css URLs containing CSS rules.
25 * @param {Array<Object>=} desc.html Descriptors for HTML fragments,
26 * each of which has a 'url' property and a 'targetID' property that
27 * specifies the node under which the HTML should be appended.
30 * ResourceLoader.registerAssets({
32 * js: ['//foo.com/src.js', '//bar.com/lib.js'],
33 * css: ['//foo.com/style.css'],
34 * html: [{ url: '//foo.com/tmpls.html' targetID: 'tmpls'}]
37 * Note: to avoid cross-site requests, all HTML assets must be served
38 * from the same host as the rendered page. For example, if the
39 * rendered page is served as chrome://oobe, then all the HTML assets
40 * must be served as chrome://oobe/path/to/something.html.
42 function registerAssets(desc
) {
43 var html
= desc
.html
|| [];
44 var css
= desc
.css
|| [];
45 var js
= desc
.js
|| [];
47 html
: html
, css
: css
, js
: js
,
49 count
: html
.length
+ css
.length
+ js
.length
54 * Determines whether an asset bundle is defined for a specified id.
55 * @param {string} id The possible identifier.
57 function hasDeferredAssets(id
) {
62 * Determines whether an asset bundle has already been loaded.
63 * @param {string} id The identifier of the asset bundle.
65 function alreadyLoadedAssets(id
) {
66 return hasDeferredAssets(id
) && ASSETS
[id
].loaded
;
70 * Load a stylesheet into the current document.
71 * @param {string} id Identifier of the stylesheet's asset bundle.
72 * @param {string} url The URL resolving to a stylesheet.
74 function loadCSS(id
, url
) {
75 var link
= document
.createElement('link');
76 link
.setAttribute('rel', 'stylesheet');
77 link
.setAttribute('href', url
);
78 link
.onload
= resourceLoaded
.bind(null, id
);
79 document
.head
.appendChild(link
);
83 * Load a script into the current document.
84 * @param {string} id Identifier of the script's asset bundle.
85 * @param {string} url The URL resolving to a script.
87 function loadJS(id
, url
) {
88 var script
= document
.createElement('script');
90 script
.onload
= resourceLoaded
.bind(null, id
);
91 document
.head
.appendChild(script
);
95 * Move DOM nodes from one parent element to another.
96 * @param {HTMLElement} from Element whose children should be moved.
97 * @param {HTMLElement} to Element to which nodes should be appended.
99 function moveNodes(from, to
) {
100 Array
.prototype.forEach
.call(from.children
, function(child
) {
101 to
.appendChild(document
.importNode(child
, true));
106 * Tests whether an XMLHttpRequest has successfully finished loading.
107 * @param {string} url The requested URL.
108 * @param {XMLHttpRequest} xhr The XHR object.
110 function isSuccessful(url
, xhr
) {
111 var fileURL
= /^file:\/\//;
112 return xhr
.readyState
== 4 &&
113 (xhr
.status
== 200 || fileURL
.test(url
) && xhr
.status
== 0);
117 * Load a chunk of HTML into the current document.
118 * @param {string} id Identifier of the page's asset bundle.
119 * @param {Object} html Descriptor of the HTML to fetch.
120 * @param {string} html.url The URL resolving to some HTML.
121 * @param {string} html.targetID The element ID to which the retrieved
122 * HTML nodes should be appended.
124 function loadHTML(id
, html
) {
125 var xhr
= new XMLHttpRequest();
126 xhr
.open('GET', html
.url
);
127 xhr
.onreadystatechange = function() {
128 if (isSuccessful(html
.url
, xhr
)) {
129 moveNodes(this.responseXML
.body
, $(html
.targetID
));
133 xhr
.responseType
= 'document';
138 * Record that a resource has been loaded for an asset bundle. When
139 * all the resources have been loaded the callback that was specified
140 * in the loadAssets call is invoked.
141 * @param {string} id Identifier of the asset bundle.
143 function resourceLoaded(id
) {
144 var assets
= ASSETS
[id
];
146 if (assets
.count
== 0)
151 * Finishes loading an asset bundle.
152 * @param {string} id Identifier of the asset bundle.
154 function finishedLoading(id
) {
155 var assets
= ASSETS
[id
];
156 console
.log('Finished loading asset bundle', id
);
157 assets
.loaded
= true;
158 window
.setTimeout(function() {
160 chrome
.send('screenAssetsLoaded', [id
]);
165 * Load an asset bundle, invoking the callback when finished.
166 * @param {string} id Identifier for the asset bundle to load.
167 * @param {function()=} callback Function to invoke when done loading.
169 function loadAssets(id
, callback
) {
170 var assets
= ASSETS
[id
];
171 assets
.callback
= callback
|| function() {};
172 console
.log('Loading asset bundle', id
);
173 if (alreadyLoadedAssets(id
))
174 console
.warn('asset bundle', id
, 'already loaded!');
175 if (assets
.count
== 0) {
178 assets
.css
.forEach(loadCSS
.bind(null, id
));
179 assets
.js
.forEach(loadJS
.bind(null, id
));
180 assets
.html
.forEach(loadHTML
.bind(null, id
));
185 alreadyLoadedAssets
: alreadyLoadedAssets
,
186 hasDeferredAssets
: hasDeferredAssets
,
187 loadAssets
: loadAssets
,
188 registerAssets
: registerAssets