// Copyright 2006 Google Inc. All Rights Reserved. // This startup script should be included in host pages either just after //
or inside the after module tags. // ////////////////////////////////////////////////////////////////////////////// // DynamicResources // function DynamicResources() { this.pendingElemsBySrc_ = {}; this.pendingScriptElems_ = new Array(); } DynamicResources.prototype = {}; // The array is set up such that, pairwise, the entries are (src, readyFnStr). // Called once for each module that is attached to the host page. // It is theoretically possible that addScripts() could be called reentrantly // if the browser event loop is pumped during this function and an iframe loads; // we may want to enhance this method in the future to support that case. DynamicResources.prototype.addScripts = function(scriptArray, insertBeforeElem) { var wasEmpty = (this.pendingScriptElems_.length == 0); var anyAdded = false; for (var i = 0, n = scriptArray.length; i < n; i += 2) { var src = scriptArray[i]; if (this.pendingElemsBySrc_[src]) { // Don't load the same script twice. continue; } // Set up the element but don't add it to the DOM until its turn. anyAdded = true; var e = document.createElement("script"); this.pendingElemsBySrc_[src] = e; var readyFn; eval("readyFn = " + scriptArray[i+1]); e.__readyFn = readyFn; e.type = "text/javascript"; e.src = src; e.__insertBeforeElem = insertBeforeElem; this.pendingScriptElems_ = this.pendingScriptElems_.concat(e); } if (wasEmpty && anyAdded) { // Kickstart. this.injectScript(this.pendingScriptElems_[0]); } } DynamicResources.prototype.injectScript = function(scriptElem) { var parentElem = scriptElem.__insertBeforeElem.parentNode; parentElem.insertBefore(scriptElem, scriptElem.__insertBeforeElem); } DynamicResources.prototype.addStyles = function(styleSrcArray, insertBeforeElem) { var parent = insertBeforeElem.parentNode; for (var i = 0, n = styleSrcArray.length; i < n; ++i) { var src = styleSrcArray[i]; if (this.pendingElemsBySrc_[src]) continue; var e = document.createElement("link"); this.pendingElemsBySrc_[src] = e; e.type = "text/css"; e.rel = "stylesheet"; e.href = src; parent.insertBefore(e, insertBeforeElem); } } DynamicResources.prototype.isReady = function() { var elems = this.pendingScriptElems_; if (elems.length > 0) { var e = elems[0]; if (!e.__readyFn()) { // The pending script isn't ready yet. return false; } // The pending script has now finished loading. Enqueue the next, if any. e.__readyFn = null; elems.shift(); if (elems.length > 0) { // There is another script. this.injectScript(elems[0]); return false; } } // There are no more pending scripts. return true; } ////////////////////////////////////////////////////////////////////////////// // ModuleControlBlock // function ModuleControlBlock(metaElem, rawName) { var parts = ["", rawName]; var i = rawName.lastIndexOf("="); if (i != -1) { parts[0] = rawName.substring(0, i) + '/'; parts[1] = rawName.substring(i+1); } this.metaElem_ = metaElem; this.baseUrl_ = parts[0]; this.name_ = parts[1]; this.compilationLoaded_ = false; this.frameWnd_ = null; } ModuleControlBlock.prototype = {}; /** * Determines whether this module is fully loaded and ready to run. */ ModuleControlBlock.prototype.isReady = function() { return this.compilationLoaded_; }; /** * Called when the compilation for this module is loaded. */ ModuleControlBlock.prototype.compilationLoaded = function(frameWnd) { this.frameWnd_ = frameWnd; this.compilationLoaded_ = true; } /** * Gets the logical module name, not including a base url prefix if one was * specified. */ ModuleControlBlock.prototype.getName = function() { return this.name_; } /** * Gets the base URL of the module, guaranteed to end with a slash. */ ModuleControlBlock.prototype.getBaseURL = function() { return this.baseUrl_; } /** * Gets the window of the module's frame. */ ModuleControlBlock.prototype.getModuleFrameWindow = function() { return this.frameWnd_; } /** * Injects a set of dynamic scripts. * The array is set up such that, pairwise, the entries are (src, readyFnStr). */ ModuleControlBlock.prototype.addScripts = function(scriptSrcArray) { return ModuleControlBlocks.dynamicResources_.addScripts(scriptSrcArray, this.metaElem_); } /** * Injects a set of dynamic styles. */ ModuleControlBlock.prototype.addStyles = function(styleSrcArray) { return ModuleControlBlocks.dynamicResources_.addStyles(styleSrcArray, this.metaElem_); } ////////////////////////////////////////////////////////////////////////////// // ModuleControlBlocks // function ModuleControlBlocks() { this.blocks_ = []; } ModuleControlBlocks.dynamicResources_ = new DynamicResources(); // "static" ModuleControlBlocks.prototype = {}; /** * Adds a module control control block for the named module. * @param metaElem the meta element that caused the module to be added * @param name the name of the module being added, optionally preceded by * an alternate base url of the form "_path_=_module_". */ ModuleControlBlocks.prototype.add = function(metaElem, name) { var mcb = new ModuleControlBlock(metaElem, name); this.blocks_ = this.blocks_.concat(mcb); }; /** * Determines whether all the modules are loaded and ready to run. */ ModuleControlBlocks.prototype.isReady = function() { for (var i = 0, n = this.blocks_.length; i < n; ++i) { var mcb = this.blocks_[i]; if (!mcb.isReady()) { return false; } } // Are there any pending dynamic resources (e.g. styles, scripts)? if (!ModuleControlBlocks.dynamicResources_.isReady()) { // No, we're still waiting on one or more dynamic resources. return false; } return true; } /** * Determines whether there are any module control blocks. */ ModuleControlBlocks.prototype.isEmpty = function() { return this.blocks_.length == 0; } /** * Gets the module control block at the specified index. */ ModuleControlBlocks.prototype.get = function(index) { return this.blocks_[index]; } /** * Injects an iframe for each module. */ ModuleControlBlocks.prototype.injectFrames = function() { for (var i = 0, n = this.blocks_.length; i < n; ++i) { var mcb = this.blocks_[i]; // Insert an iframe for the module var iframe = document.createElement("iframe"); var selectorUrl = mcb.getBaseURL() + mcb.getName() + ".nocache.html"; selectorUrl += "?" + (__gwt_isHosted() ? "h&" : "" ) + i; var unique = new Date().getTime(); selectorUrl += "&" + unique; iframe.style.border = '0px'; iframe.style.width = '0px'; iframe.style.height = '0px'; // Fragile browser-specific ordering issues below /*@cc_on // prevent extra clicky noises on IE iframe.src = selectorUrl; @*/ if (document.body.firstChild) { document.body.insertBefore(iframe, document.body.firstChild); } else { document.body.appendChild(iframe); } /*@cc_on // prevent extra clicky noises on IE return; @*/ if (iframe.contentWindow) { // Older Mozilla has a caching bug for the iframe and won't reload the nocache. iframe.contentWindow.location.replace(selectorUrl); } else { // Older Safari doesn't have a contentWindow. iframe.src = selectorUrl; } } } /** * Runs the entry point for each module. */ ModuleControlBlocks.prototype.run = function() { for (var i = 0, n = this.blocks_.length; i < n; ++i) { var mcb = this.blocks_[i]; var name = mcb.getName(); var frameWnd = mcb.getModuleFrameWindow(); if (__gwt_isHosted()) { if (!window.external.gwtOnLoad(frameWnd, name)) { // Module failed to load. if (__gwt_onLoadError) { __gwt_onLoadError(name); } else { window.alert("Failed to load module '" + name + "'.\nPlease see the log in the development shell for details."); } } } else { // The compilation itself handles calling the error function. frameWnd.gwtOnLoad(__gwt_onLoadError, name); } } } ////////////////////////////////////////////////////////////////////////////// // Globals // var __gwt_retryWaitMillis = 10; var __gwt_isHostPageLoaded = false; var __gwt_metaProps = {}; var __gwt_onPropertyError = null; var __gwt_onLoadError = null; var __gwt_moduleControlBlocks = new ModuleControlBlocks(); ////////////////////////////////////////////////////////////////////////////// // Common // /** * Determines whether or not the page is being loaded in the GWT hosted browser. */ function __gwt_isHosted() { if (window.external && window.external.gwtOnLoad) { // gwt.hybrid makes the hosted browser pretend not to be if (document.location.href.indexOf("gwt.hybrid") == -1) { return true; } } return false; } /** * Tries to get a module control block based on a query string passed in from * the caller. Used by iframes to get references back to their mcbs. * @param queryString the entire query string as returned by location.search, * which notably includes the leading '?' if one is specified * @return the relevant module control block, ornull
if it cannot
* be derived based on queryString
*/
function __gwt_tryGetModuleControlBlock(queryString) {
if (queryString.length > 0) {
// The pattern is ?[h&]