| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 /** | |
| 6 * @fileoverview Deferred resource loader for OOBE/Login screens. | |
| 7 */ | |
| 8 | |
| 9 cr.define('cr.ui.login.ResourceLoader', function() { | |
| 10 'use strict'; | |
| 11 | |
| 12 // Deferred assets. | |
| 13 var ASSETS = {}; | |
| 14 | |
| 15 /** | |
| 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. | |
| 20 * | |
| 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. | |
| 28 * | |
| 29 * Example: | |
| 30 * ResourceLoader.registerAssets({ | |
| 31 * id: 'bundle123', | |
| 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'}] | |
| 35 * }); | |
| 36 * | |
| 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. | |
| 41 */ | |
| 42 function registerAssets(desc) { | |
| 43 var html = desc.html || []; | |
| 44 var css = desc.css || []; | |
| 45 var js = desc.js || []; | |
| 46 ASSETS[desc.id] = { | |
| 47 html: html, css: css, js: js, | |
| 48 loaded: false, | |
| 49 count: html.length + css.length + js.length | |
| 50 }; | |
| 51 } | |
| 52 | |
| 53 /** | |
| 54 * Determines whether an asset bundle is defined for a specified id. | |
| 55 * @param {string} id The possible identifier. | |
| 56 */ | |
| 57 function hasDeferredAssets(id) { | |
| 58 return id in ASSETS; | |
| 59 } | |
| 60 | |
| 61 /** | |
| 62 * Determines whether an asset bundle has already been loaded. | |
| 63 * @param {string} id The identifier of the asset bundle. | |
| 64 */ | |
| 65 function alreadyLoadedAssets(id) { | |
| 66 return hasDeferredAssets(id) && ASSETS[id].loaded; | |
| 67 } | |
| 68 | |
| 69 /** | |
| 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. | |
| 73 */ | |
| 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); | |
| 80 } | |
| 81 | |
| 82 /** | |
| 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. | |
| 86 */ | |
| 87 function loadJS(id, url) { | |
| 88 var script = document.createElement('script'); | |
| 89 script.src = url; | |
| 90 script.onload = resourceLoaded.bind(null, id); | |
| 91 document.head.appendChild(script); | |
| 92 } | |
| 93 | |
| 94 /** | |
| 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. | |
| 98 */ | |
| 99 function moveNodes(from, to) { | |
| 100 Array.prototype.forEach.call(from.children, to.appendChild, to); | |
| 101 } | |
| 102 | |
| 103 /** | |
| 104 * Tests whether an XMLHttpRequest has successfully finished loading. | |
| 105 * @param {string} url The requested URL. | |
| 106 * @param {XMLHttpRequest} xhr The XHR object. | |
| 107 */ | |
| 108 function isSuccessful(url, xhr) { | |
| 109 var fileURL = /^file:\/\//; | |
| 110 return xhr.readyState == 4 && | |
| 111 (xhr.status == 200 || fileURL.test(url) && xhr.status == 0); | |
| 112 } | |
| 113 | |
| 114 /* | |
| 115 * Load a chunk of HTML into the current document. | |
| 116 * @param {string} id Identifier of the page's asset bundle. | |
| 117 * @param {Object} html Descriptor of the HTML to fetch. | |
| 118 * @param {string} html.url The URL resolving to some HTML. | |
| 119 * @param {string} html.targetID The element ID to which the retrieved | |
| 120 * HTML nodes should be appended. | |
| 121 */ | |
| 122 function loadHTML(id, html) { | |
| 123 var xhr = new XMLHttpRequest(); | |
| 124 xhr.open('GET', html.url); | |
| 125 xhr.onreadystatechange = function() { | |
| 126 if (isSuccessful(html.url, xhr)) { | |
| 127 moveNodes(this.responseXML.body, $(html.targetID)); | |
| 128 resourceLoaded(id); | |
| 129 } | |
| 130 }; | |
| 131 xhr.responseType = 'document'; | |
| 132 xhr.send(); | |
| 133 } | |
| 134 | |
| 135 /** | |
| 136 * Record that a resource has been loaded for an asset bundle. When | |
| 137 * all the resources have been loaded the callback that was specified | |
| 138 * in the loadAssets call is invoked. | |
| 139 * @param {string} id Identifier of the asset bundle. | |
| 140 */ | |
| 141 function resourceLoaded(id) { | |
| 142 var assets = ASSETS[id]; | |
| 143 assets.count--; | |
| 144 if (assets.count == 0) | |
| 145 finishedLoading(id); | |
| 146 } | |
| 147 | |
| 148 /** | |
| 149 * Finishes loading an asset bundle. | |
| 150 * @param {string} id Identifier of the asset bundle. | |
| 151 */ | |
| 152 function finishedLoading(id) { | |
| 153 var assets = ASSETS[id]; | |
| 154 console.log('Finished loading asset bundle', id); | |
| 155 assets.loaded = true; | |
| 156 window.setTimeout(function() { | |
| 157 assets.callback(); | |
| 158 chrome.send('screenAssetsLoaded', [id]); | |
| 159 }, 0); | |
| 160 } | |
| 161 | |
| 162 /** | |
| 163 * Load an asset bundle, invoking the callback when finished. | |
| 164 * @param {string} id Identifier for the asset bundle to load. | |
| 165 * @param {function()=} callback Function to invoke when done loading. | |
| 166 */ | |
| 167 function loadAssets(id, callback) { | |
| 168 var assets = ASSETS[id]; | |
| 169 assets.callback = callback || function() {}; | |
| 170 console.log('Loading asset bundle', id); | |
| 171 if (alreadyLoadedAssets(id)) | |
| 172 console.warn('asset bundle', id, 'already loaded!'); | |
| 173 if (assets.count == 0) { | |
| 174 finishedLoading(id); | |
| 175 } else { | |
| 176 assets.css.forEach(loadCSS.bind(null, id)); | |
| 177 assets.js.forEach(loadJS.bind(null, id)); | |
| 178 assets.html.forEach(loadHTML.bind(null, id)); | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 return { | |
| 183 alreadyLoadedAssets: alreadyLoadedAssets, | |
| 184 hasDeferredAssets: hasDeferredAssets, | |
| 185 loadAssets: loadAssets, | |
| 186 registerAssets: registerAssets | |
| 187 }; | |
| 188 }); | |
| OLD | NEW |