| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview Deferred resource loader for OOBE/Login screens. |
| */ |
| |
| cr.define('cr.ui.login.ResourceLoader', function() { |
| 'use strict'; |
| |
| // Deferred assets. |
| var ASSETS = {}; |
| |
| /** |
| * Register assets for deferred loading. When the bundle is loaded |
| * assets will be added to the current page's DOM: <link> and <script> |
| * tags pointing to the CSS and JavaScript will be added to the |
| * <head>, and HTML will be appended to a specified element. |
| * |
| * @param {Object} desc Descriptor for the asset bundle |
| * @param {string} desc.id Unique identifier for the asset bundle. |
| * @param {Array=} desc.js URLs containing JavaScript sources. |
| * @param {Array=} desc.css URLs containing CSS rules. |
| * @param {Array.<Object>=} desc.html Descriptors for HTML fragments, |
| * each of which has a 'url' property and a 'targetID' property that |
| * specifies the node under which the HTML should be appended. |
| * |
| * Example: |
| * ResourceLoader.registerAssets({ |
| * id: 'bundle123', |
| * js: ['//foo.com/src.js', '//bar.com/lib.js'], |
| * css: ['//foo.com/style.css'], |
| * html: [{ url: '//foo.com/tmpls.html' targetID: 'tmpls'}] |
| * }); |
| * |
| * Note: to avoid cross-site requests, all HTML assets must be served |
| * from the same host as the rendered page. For example, if the |
| * rendered page is served as chrome://oobe, then all the HTML assets |
| * must be served as chrome://oobe/path/to/something.html. |
| */ |
| function registerAssets(desc) { |
| var html = desc.html || []; |
| var css = desc.css || []; |
| var js = desc.js || []; |
| ASSETS[desc.id] = { |
| html: html, css: css, js: js, |
| loaded: false, |
| count: html.length + css.length + js.length |
| }; |
| } |
| |
| /** |
| * Determines whether an asset bundle is defined for a specified id. |
| * @param {string} id The possible identifier. |
| */ |
| function hasDeferredAssets(id) { |
| return id in ASSETS; |
| } |
| |
| /** |
| * Determines whether an asset bundle has already been loaded. |
| * @param {string} id The identifier of the asset bundle. |
| */ |
| function alreadyLoadedAssets(id) { |
| return hasDeferredAssets(id) && ASSETS[id].loaded; |
| } |
| |
| /** |
| * Load a stylesheet into the current document. |
| * @param {string} id Identifier of the stylesheet's asset bundle. |
| * @param {string} url The URL resolving to a stylesheet. |
| */ |
| function loadCSS(id, url) { |
| var link = document.createElement('link'); |
| link.setAttribute('rel', 'stylesheet'); |
| link.setAttribute('href', url); |
| link.onload = resourceLoaded.bind(null, id); |
| document.head.appendChild(link); |
| } |
| |
| /** |
| * Load a script into the current document. |
| * @param {string} id Identifier of the script's asset bundle. |
| * @param {string} url The URL resolving to a script. |
| */ |
| function loadJS(id, url) { |
| var script = document.createElement('script'); |
| script.src = url; |
| script.onload = resourceLoaded.bind(null, id); |
| document.head.appendChild(script); |
| } |
| |
| /** |
| * Move DOM nodes from one parent element to another. |
| * @param {HTMLElement} from Element whose children should be moved. |
| * @param {HTMLElement} to Element to which nodes should be appended. |
| */ |
| function moveNodes(from, to) { |
| Array.prototype.forEach.call(from.children, to.appendChild, to); |
| } |
| |
| /** |
| * Tests whether an XMLHttpRequest has successfully finished loading. |
| * @param {string} url The requested URL. |
| * @param {XMLHttpRequest} xhr The XHR object. |
| */ |
| function isSuccessful(url, xhr) { |
| var fileURL = /^file:\/\//; |
| return xhr.readyState == 4 && |
| (xhr.status == 200 || fileURL.test(url) && xhr.status == 0); |
| } |
| |
| /* |
| * Load a chunk of HTML into the current document. |
| * @param {string} id Identifier of the page's asset bundle. |
| * @param {Object} html Descriptor of the HTML to fetch. |
| * @param {string} html.url The URL resolving to some HTML. |
| * @param {string} html.targetID The element ID to which the retrieved |
| * HTML nodes should be appended. |
| */ |
| function loadHTML(id, html) { |
| var xhr = new XMLHttpRequest(); |
| xhr.open('GET', html.url); |
| xhr.onreadystatechange = function() { |
| if (isSuccessful(html.url, xhr)) { |
| moveNodes(this.responseXML.body, $(html.targetID)); |
| resourceLoaded(id); |
| } |
| }; |
| xhr.responseType = 'document'; |
| xhr.send(); |
| } |
| |
| /** |
| * Record that a resource has been loaded for an asset bundle. When |
| * all the resources have been loaded the callback that was specified |
| * in the loadAssets call is invoked. |
| * @param {string} id Identifier of the asset bundle. |
| */ |
| function resourceLoaded(id) { |
| var assets = ASSETS[id]; |
| assets.count--; |
| if (assets.count == 0) |
| finishedLoading(id); |
| } |
| |
| /** |
| * Finishes loading an asset bundle. |
| * @param {string} id Identifier of the asset bundle. |
| */ |
| function finishedLoading(id) { |
| var assets = ASSETS[id]; |
| console.log('Finished loading asset bundle', id); |
| assets.loaded = true; |
| window.setTimeout(assets.callback, 0); |
| } |
| |
| /** |
| * Load an asset bundle, invoking the callback when finished. |
| * @param {string} id Identifier for the asset bundle to load. |
| * @param {function()=} callback Function to invoke when done loading. |
| */ |
| function loadAssets(id, callback) { |
| var assets = ASSETS[id]; |
| assets.callback = callback || function() {}; |
| console.log('Loading asset bundle', id); |
| if (alreadyLoadedAssets(id)) |
| console.warn('asset bundle', id, 'already loaded!'); |
| if (assets.count == 0) { |
| finishedLoading(id); |
| } else { |
| assets.css.forEach(loadCSS.bind(null, id)); |
| assets.js.forEach(loadJS.bind(null, id)); |
| assets.html.forEach(loadHTML.bind(null, id)); |
| } |
| } |
| |
| return { |
| alreadyLoadedAssets: alreadyLoadedAssets, |
| hasDeferredAssets: hasDeferredAssets, |
| loadAssets: loadAssets, |
| registerAssets: registerAssets |
| }; |
| }); |