Adding float-no-zero branch hosted build
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview An interface for module loading.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.module.AbstractModuleLoader');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An interface that loads JavaScript modules.
|
||||
* @interface
|
||||
*/
|
||||
goog.module.AbstractModuleLoader = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Loads a list of JavaScript modules.
|
||||
*
|
||||
* @param {Array.<string>} ids The module ids in dependency order.
|
||||
* @param {Object} moduleInfoMap A mapping from module id to ModuleInfo object.
|
||||
* @param {function()?=} opt_successFn The callback if module loading is a
|
||||
* success.
|
||||
* @param {function(?number)?=} opt_errorFn The callback if module loading is an
|
||||
* error.
|
||||
* @param {function()?=} opt_timeoutFn The callback if module loading times out.
|
||||
* @param {boolean=} opt_forceReload Whether to bypass cache while loading the
|
||||
* module.
|
||||
*/
|
||||
goog.module.AbstractModuleLoader.prototype.loadModules = function(
|
||||
ids, moduleInfoMap, opt_successFn, opt_errorFn, opt_timeoutFn,
|
||||
opt_forceReload) {};
|
||||
|
||||
|
||||
/**
|
||||
* Pre-fetches a JavaScript module.
|
||||
*
|
||||
* @param {string} id The module id.
|
||||
* @param {!goog.module.ModuleInfo} moduleInfo The module info.
|
||||
*/
|
||||
goog.module.AbstractModuleLoader.prototype.prefetchModule = function(
|
||||
id, moduleInfo) {};
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Defines the base class for a module. This is used to allow the
|
||||
* code to be modularized, giving the benefits of lazy loading and loading on
|
||||
* demand.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.module.BaseModule');
|
||||
|
||||
goog.require('goog.Disposable');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A basic module object that represents a module of Javascript code that can
|
||||
* be dynamically loaded.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.Disposable}
|
||||
*/
|
||||
goog.module.BaseModule = function() {
|
||||
goog.Disposable.call(this);
|
||||
};
|
||||
goog.inherits(goog.module.BaseModule, goog.Disposable);
|
||||
|
||||
|
||||
/**
|
||||
* Performs any load-time initialization that the module requires.
|
||||
* @param {Object} context The module context.
|
||||
*/
|
||||
goog.module.BaseModule.prototype.initialize = function(context) {};
|
||||
@@ -0,0 +1,269 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
*
|
||||
* @fileoverview This class supports the dynamic loading of compiled
|
||||
* javascript modules at runtime, as descibed in the designdoc.
|
||||
*
|
||||
* <http://go/js_modules_design>
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.module.Loader');
|
||||
|
||||
goog.require('goog.Timer');
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.object');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The dynamic loading functionality is defined as a class. The class
|
||||
* will be used as singleton. There is, however, a two step
|
||||
* initialization procedure because parameters need to be passed to
|
||||
* the goog.module.Loader instance.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
goog.module.Loader = function() {
|
||||
/**
|
||||
* Map of module name/array of {symbol name, callback} pairs that are pending
|
||||
* to be loaded.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this.pending_ = {};
|
||||
|
||||
/**
|
||||
* Provides associative access to each module and the symbols of each module
|
||||
* that have aready been loaded (one lookup for the module, another lookup
|
||||
* on the module for the symbol).
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this.modules_ = {};
|
||||
|
||||
/**
|
||||
* Map of module name to module url. Used to avoid fetching the same URL
|
||||
* twice by keeping track of in-flight URLs.
|
||||
* Note: this allows two modules to be bundled into the same file.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this.pendingModuleUrls_ = {};
|
||||
|
||||
/**
|
||||
* The base url to load modules from. This property will be set in init().
|
||||
* @type {?string}
|
||||
* @private
|
||||
*/
|
||||
this.urlBase_ = null;
|
||||
|
||||
/**
|
||||
* Array of modules that have been requested before init() was called.
|
||||
* If require() is called before init() was called, the required
|
||||
* modules can obviously not yet be loaded, because their URL is
|
||||
* unknown. The modules that are requested before init() are
|
||||
* therefore stored in this array, and they are loaded at init()
|
||||
* time.
|
||||
* @type {Array.<string>}
|
||||
* @private
|
||||
*/
|
||||
this.pendingBeforeInit_ = [];
|
||||
};
|
||||
goog.addSingletonGetter(goog.module.Loader);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a full URL to the compiled module code given a base URL and a
|
||||
* module name. By default it's urlBase + '_' + module + '.js'.
|
||||
* @param {string} urlBase URL to the module files.
|
||||
* @param {string} module Module name.
|
||||
* @return {string} The full url to the module binary.
|
||||
* @private
|
||||
*/
|
||||
goog.module.Loader.prototype.getModuleUrl_ = function(urlBase, module) {
|
||||
return urlBase + '_' + module + '.js';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The globally exported name of the load callback. Matches the
|
||||
* definition in the js_modular_binary() BUILD rule.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.module.Loader.LOAD_CALLBACK = '__gjsload__';
|
||||
|
||||
|
||||
/**
|
||||
* Loads the module by evaluating the javascript text in the current
|
||||
* scope. Uncompiled, base identifiers are visible in the global scope;
|
||||
* when compiled they are visible in the closure of the anonymous
|
||||
* namespace. Notice that this cannot be replaced by the global eval,
|
||||
* because the global eval isn't in the scope of the anonymous
|
||||
* namespace function that the jscompiled code lives in.
|
||||
*
|
||||
* @param {string} t_ The javascript text to evaluate. IMPORTANT: The
|
||||
* name of the identifier is chosen so that it isn't compiled and
|
||||
* hence cannot shadow compiled identifiers in the surrounding scope.
|
||||
* @private
|
||||
*/
|
||||
goog.module.Loader.loaderEval_ = function(t_) {
|
||||
eval(t_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the Loader to be fully functional. Also executes load
|
||||
* requests that were received before initialization. Must be called
|
||||
* exactly once, with the URL of the base library. Module URLs are
|
||||
* derived from the URL of the base library by inserting the module
|
||||
* name, preceded by a period, before the .js prefix of the base URL.
|
||||
*
|
||||
* @param {string} baseUrl The URL of the base library.
|
||||
* @param {Function=} opt_urlFunction Function that creates the URL for the
|
||||
* module file. It will be passed the base URL for module files and the
|
||||
* module name and should return the fully-formed URL to the module file to
|
||||
* load.
|
||||
*/
|
||||
goog.module.Loader.prototype.init = function(baseUrl, opt_urlFunction) {
|
||||
// For the use by the module wrappers, loaderEval_ is exported to
|
||||
// the page. Note that, despite the name, this is not part of the
|
||||
// API, so it is here and not in api_app.js. Cf. BUILD. Note this is
|
||||
// done before the first load requests are sent.
|
||||
goog.exportSymbol(goog.module.Loader.LOAD_CALLBACK,
|
||||
goog.module.Loader.loaderEval_);
|
||||
|
||||
this.urlBase_ = baseUrl.replace(/\.js$/, '');
|
||||
if (opt_urlFunction) {
|
||||
this.getModuleUrl_ = opt_urlFunction;
|
||||
}
|
||||
|
||||
goog.array.forEach(this.pendingBeforeInit_, function(module) {
|
||||
this.load_(module);
|
||||
}, this);
|
||||
goog.array.clear(this.pendingBeforeInit_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Requests the loading of a symbol from a module. When the module is
|
||||
* loaded, the requested symbol will be passed as argument to the
|
||||
* function callback.
|
||||
*
|
||||
* @param {string} module The name of the module. Usually, the value
|
||||
* is defined as a constant whose name starts with MOD_.
|
||||
* @param {number|string} symbol The ID of the symbol. Usually, the value is
|
||||
* defined as a constant whose name starts with SYM_.
|
||||
* @param {Function} callback This function will be called with the
|
||||
* resolved symbol as the argument once the module is loaded.
|
||||
*/
|
||||
goog.module.Loader.prototype.require = function(module, symbol, callback) {
|
||||
var pending = this.pending_;
|
||||
var modules = this.modules_;
|
||||
if (modules[module]) {
|
||||
// already loaded
|
||||
callback(modules[module][symbol]);
|
||||
} else if (pending[module]) {
|
||||
// loading is pending from another require of the same module
|
||||
pending[module].push([symbol, callback]);
|
||||
} else {
|
||||
// not loaded, and not requested
|
||||
pending[module] = [[symbol, callback]]; // Yes, really [[ ]].
|
||||
// Defer loading to initialization if Loader is not yet
|
||||
// initialized, otherwise load the module.
|
||||
if (goog.isString(this.urlBase_)) {
|
||||
this.load_(module);
|
||||
} else {
|
||||
this.pendingBeforeInit_.push(module);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Registers a symbol in a loaded module. When called without symbol,
|
||||
* registers the module to be fully loaded and executes all callbacks
|
||||
* from pending require() callbacks for this module.
|
||||
*
|
||||
* @param {string} module The name of the module. Cf. parameter module
|
||||
* of method require().
|
||||
* @param {number|string=} opt_symbol The symbol being defined, or nothing when
|
||||
* all symbols of the module are defined. Cf. parameter symbol of method
|
||||
* require().
|
||||
* @param {Object=} opt_object The object bound to the symbol, or nothing when
|
||||
* all symbols of the module are defined.
|
||||
*/
|
||||
goog.module.Loader.prototype.provide = function(
|
||||
module, opt_symbol, opt_object) {
|
||||
var modules = this.modules_;
|
||||
var pending = this.pending_;
|
||||
if (!modules[module]) {
|
||||
modules[module] = {};
|
||||
}
|
||||
if (opt_object) {
|
||||
// When an object is provided, just register it.
|
||||
modules[module][opt_symbol] = opt_object;
|
||||
} else if (pending[module]) {
|
||||
// When no object is provided, and there are pending require()
|
||||
// callbacks for this module, execute them.
|
||||
for (var i = 0; i < pending[module].length; ++i) {
|
||||
var symbol = pending[module][i][0];
|
||||
var callback = pending[module][i][1];
|
||||
callback(modules[module][symbol]);
|
||||
}
|
||||
delete pending[module];
|
||||
delete this.pendingModuleUrls_[module];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Starts to load a module. Assumes that init() was called.
|
||||
*
|
||||
* @param {string} module The name of the module.
|
||||
* @private
|
||||
*/
|
||||
goog.module.Loader.prototype.load_ = function(module) {
|
||||
// NOTE(user): If the module request happens inside a click handler
|
||||
// (presumably inside any user event handler, but the onload event
|
||||
// handler is fine), IE will load the script but not execute
|
||||
// it. Thus we break out of the current flow of control before we do
|
||||
// the load. For the record, for IE it would have been enough to
|
||||
// just defer the assignment to src. Safari doesn't execute the
|
||||
// script if the assignment to src happens *after* the script
|
||||
// element is inserted into the DOM.
|
||||
goog.Timer.callOnce(function() {
|
||||
// The module might have been registered in the interim (if fetched as part
|
||||
// of another module fetch because they share the same url)
|
||||
if (this.modules_[module]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var url = this.getModuleUrl_(this.urlBase_, module);
|
||||
|
||||
// Check if specified URL is already in flight
|
||||
var urlInFlight = goog.object.containsValue(this.pendingModuleUrls_, url);
|
||||
this.pendingModuleUrls_[module] = url;
|
||||
if (urlInFlight) {
|
||||
return;
|
||||
}
|
||||
|
||||
var s = goog.dom.createDom('script',
|
||||
{'type': 'text/javascript', 'src': url});
|
||||
document.body.appendChild(s);
|
||||
}, 0, this);
|
||||
};
|
||||
@@ -0,0 +1,166 @@
|
||||
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
*
|
||||
* @fileoverview This class supports the dynamic loading of compiled
|
||||
* javascript modules at runtime, as descibed in the designdoc.
|
||||
*
|
||||
* <http://go/js_modules_design>
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.module');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.module.Loader');
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper of goog.module.Loader.require() for use in modules.
|
||||
* See method goog.module.Loader.require() for
|
||||
* explanation of params.
|
||||
*
|
||||
* @param {string} module The name of the module. Usually, the value
|
||||
* is defined as a constant whose name starts with MOD_.
|
||||
* @param {number|string} symbol The ID of the symbol. Usually, the value is
|
||||
* defined as a constant whose name starts with SYM_.
|
||||
* @param {Function} callback This function will be called with the
|
||||
* resolved symbol as the argument once the module is loaded.
|
||||
*/
|
||||
goog.module.require = function(module, symbol, callback) {
|
||||
goog.module.Loader.getInstance().require(module, symbol, callback);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper of goog.module.Loader.provide() for use in modules
|
||||
* See method goog.module.Loader.provide() for explanation of params.
|
||||
*
|
||||
* @param {string} module The name of the module. Cf. parameter module
|
||||
* of method require().
|
||||
* @param {number|string=} opt_symbol The symbol being defined, or nothing
|
||||
* when all symbols of the module are defined. Cf. parameter symbol of
|
||||
* method require().
|
||||
* @param {Object=} opt_object The object bound to the symbol, or nothing when
|
||||
* all symbols of the module are defined.
|
||||
*/
|
||||
goog.module.provide = function(module, opt_symbol, opt_object) {
|
||||
goog.module.Loader.getInstance().provide(
|
||||
module, opt_symbol, opt_object);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper of init() so that we only need to export this single
|
||||
* identifier instead of three. See method goog.module.Loader.init() for
|
||||
* explanation of param.
|
||||
*
|
||||
* @param {string} urlBase The URL of the base library.
|
||||
* @param {Function=} opt_urlFunction Function that creates the URL for the
|
||||
* module file. It will be passed the base URL for module files and the
|
||||
* module name and should return the fully-formed URL to the module file to
|
||||
* load.
|
||||
*/
|
||||
goog.module.initLoader = function(urlBase, opt_urlFunction) {
|
||||
goog.module.Loader.getInstance().init(urlBase, opt_urlFunction);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Produces a function that delegates all its arguments to a
|
||||
* dynamically loaded function. This is used to export dynamically
|
||||
* loaded functions.
|
||||
*
|
||||
* @param {string} module The module to load from.
|
||||
* @param {number|string} symbol The ID of the symbol to load from the module.
|
||||
* This symbol must resolve to a function.
|
||||
* @return {!Function} A function that forwards all its arguments to
|
||||
* the dynamically loaded function specified by module and symbol.
|
||||
*/
|
||||
goog.module.loaderCall = function(module, symbol) {
|
||||
return function() {
|
||||
var args = arguments;
|
||||
goog.module.require(module, symbol, function(f) {
|
||||
f.apply(null, args);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Requires symbols for multiple modules, and invokes a final callback
|
||||
* on the condition that all of them are loaded. I.e. a barrier for
|
||||
* loading of multiple symbols. If no symbols are required, the
|
||||
* final callback is called immediately.
|
||||
*
|
||||
* @param {Array.<Object>} symbolRequests A
|
||||
* list of tuples of module, symbol, callback (analog to the arguments
|
||||
* to require(), above). These will each be require()d
|
||||
* individually. NOTE: This argument will be modified during execution
|
||||
* of the function.
|
||||
* @param {Function} finalCb A function that is called when all
|
||||
* required symbols are loaded.
|
||||
*/
|
||||
goog.module.requireMultipleSymbols = function(symbolRequests, finalCb) {
|
||||
var I = symbolRequests.length;
|
||||
if (I == 0) {
|
||||
finalCb();
|
||||
} else {
|
||||
for (var i = 0; i < I; ++i) {
|
||||
goog.module.requireMultipleSymbolsHelper_(symbolRequests, i, finalCb);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Used by requireMultipleSymbols() to load each required symbol and
|
||||
* keep track how many are loaded, and finally invoke the barrier
|
||||
* callback when they are all done.
|
||||
*
|
||||
* @param {Array.<Object>} symbolRequests Same as in
|
||||
* requireMultipleSymbols().
|
||||
* @param {number} i The single module that is required in this invocation.
|
||||
* @param {Function} finalCb Same as in requireMultipleSymbols().
|
||||
* @private
|
||||
*/
|
||||
goog.module.requireMultipleSymbolsHelper_ = function(symbolRequests, i,
|
||||
finalCb) {
|
||||
var r = symbolRequests[i];
|
||||
var module = r[0];
|
||||
var symbol = r[1];
|
||||
var symbolCb = r[2];
|
||||
goog.module.require(module, symbol, function() {
|
||||
symbolCb.apply(this, arguments);
|
||||
symbolRequests[i] = null;
|
||||
if (goog.array.every(symbolRequests, goog.module.isNull_)) {
|
||||
finalCb();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the given element is null.
|
||||
*
|
||||
* @param {Object} el The element to check if null.
|
||||
* @param {number} i The index of the element.
|
||||
* @param {Array.<Object>} arr The array that contains the element.
|
||||
* @return {boolean} TRUE iff the element is null.
|
||||
* @private
|
||||
*/
|
||||
goog.module.isNull_ = function(el, i, arr) {
|
||||
return el == null;
|
||||
};
|
||||
@@ -0,0 +1,335 @@
|
||||
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Defines the goog.module.ModuleInfo class.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.module.ModuleInfo');
|
||||
|
||||
goog.require('goog.Disposable');
|
||||
goog.require('goog.functions');
|
||||
goog.require('goog.module.BaseModule');
|
||||
goog.require('goog.module.ModuleLoadCallback');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A ModuleInfo object is used by the ModuleManager to hold information about a
|
||||
* module of js code that may or may not yet be loaded into the environment.
|
||||
*
|
||||
* @param {Array.<string>} deps Ids of the modules that must be loaded before
|
||||
* this one. The ids must be in dependency order (i.e. if the ith module
|
||||
* depends on the jth module, then i > j).
|
||||
* @param {string} id The module's ID.
|
||||
* @constructor
|
||||
* @extends {goog.Disposable}
|
||||
*/
|
||||
goog.module.ModuleInfo = function(deps, id) {
|
||||
goog.Disposable.call(this);
|
||||
|
||||
/**
|
||||
* A list of the ids of the modules that must be loaded before this module.
|
||||
* @type {Array.<string>}
|
||||
* @private
|
||||
*/
|
||||
this.deps_ = deps;
|
||||
|
||||
/**
|
||||
* The module's ID.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.id_ = id;
|
||||
|
||||
/**
|
||||
* Callbacks to execute once this module is loaded.
|
||||
* @type {Array.<goog.module.ModuleLoadCallback>}
|
||||
* @private
|
||||
*/
|
||||
this.onloadCallbacks_ = [];
|
||||
|
||||
/**
|
||||
* Callbacks to execute if the module load errors.
|
||||
* @type {Array.<goog.module.ModuleLoadCallback>}
|
||||
* @private
|
||||
*/
|
||||
this.onErrorCallbacks_ = [];
|
||||
|
||||
/**
|
||||
* Early callbacks to execute once this module is loaded. Called after
|
||||
* module initialization but before regular onload callbacks.
|
||||
* @type {Array.<goog.module.ModuleLoadCallback>}
|
||||
* @private
|
||||
*/
|
||||
this.earlyOnloadCallbacks_ = [];
|
||||
};
|
||||
goog.inherits(goog.module.ModuleInfo, goog.Disposable);
|
||||
|
||||
|
||||
/**
|
||||
* The uris that can be used to retrieve this module's code.
|
||||
* @type {Array.<string>?}
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.uris_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* The constructor to use to instantiate the module object after the module
|
||||
* code is loaded. This must be either goog.module.BaseModule or a subclass of
|
||||
* it.
|
||||
* @type {Function}
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.moduleConstructor_ = goog.module.BaseModule;
|
||||
|
||||
|
||||
/**
|
||||
* The module object. This will be null until the module is loaded.
|
||||
* @type {goog.module.BaseModule?}
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.module_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Gets the dependencies of this module.
|
||||
* @return {Array.<string>} The ids of the modules that this module depends on.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.getDependencies = function() {
|
||||
return this.deps_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the ID of this module.
|
||||
* @return {string} The ID.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.getId = function() {
|
||||
return this.id_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the uris of this module.
|
||||
* @param {Array.<string>} uris Uris for this module's code.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.setUris = function(uris) {
|
||||
this.uris_ = uris;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the uris of this module.
|
||||
* @return {Array.<string>?} Uris for this module's code.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.getUris = function() {
|
||||
return this.uris_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the constructor to use to instantiate the module object after the
|
||||
* module code is loaded.
|
||||
* @param {Function} constructor The constructor of a goog.module.BaseModule
|
||||
* subclass.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.setModuleConstructor = function(
|
||||
constructor) {
|
||||
if (this.moduleConstructor_ === goog.module.BaseModule) {
|
||||
this.moduleConstructor_ = constructor;
|
||||
} else {
|
||||
throw Error('Cannot set module constructor more than once.');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Registers a function that should be called after the module is loaded. These
|
||||
* early callbacks are called after {@link Module#initialize} is called but
|
||||
* before the other callbacks are called.
|
||||
* @param {Function} fn A callback function that takes a single argument which
|
||||
* is the module context.
|
||||
* @param {Object=} opt_handler Optional handler under whose scope to execute
|
||||
* the callback.
|
||||
* @return {goog.module.ModuleLoadCallback} Reference to the callback
|
||||
* object.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.registerEarlyCallback = function(
|
||||
fn, opt_handler) {
|
||||
return this.registerCallback_(this.earlyOnloadCallbacks_, fn, opt_handler);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Registers a function that should be called after the module is loaded.
|
||||
* @param {Function} fn A callback function that takes a single argument which
|
||||
* is the module context.
|
||||
* @param {Object=} opt_handler Optional handler under whose scope to execute
|
||||
* the callback.
|
||||
* @return {goog.module.ModuleLoadCallback} Reference to the callback
|
||||
* object.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.registerCallback = function(
|
||||
fn, opt_handler) {
|
||||
return this.registerCallback_(this.onloadCallbacks_, fn, opt_handler);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Registers a function that should be called if the module load fails.
|
||||
* @param {Function} fn A callback function that takes a single argument which
|
||||
* is the failure type.
|
||||
* @param {Object=} opt_handler Optional handler under whose scope to execute
|
||||
* the callback.
|
||||
* @return {goog.module.ModuleLoadCallback} Reference to the callback
|
||||
* object.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.registerErrback = function(
|
||||
fn, opt_handler) {
|
||||
return this.registerCallback_(this.onErrorCallbacks_, fn, opt_handler);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Registers a function that should be called after the module is loaded.
|
||||
* @param {Array.<goog.module.ModuleLoadCallback>} callbacks The array to
|
||||
* add the callback to.
|
||||
* @param {Function} fn A callback function that takes a single argument which
|
||||
* is the module context.
|
||||
* @param {Object=} opt_handler Optional handler under whose scope to execute
|
||||
* the callback.
|
||||
* @return {goog.module.ModuleLoadCallback} Reference to the callback
|
||||
* object.
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.registerCallback_ = function(
|
||||
callbacks, fn, opt_handler) {
|
||||
var callback = new goog.module.ModuleLoadCallback(fn, opt_handler);
|
||||
callbacks.push(callback);
|
||||
return callback;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the module has been loaded.
|
||||
* @return {boolean} Whether the module has been loaded.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.isLoaded = function() {
|
||||
return !!this.module_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the module.
|
||||
* @return {goog.module.BaseModule?} The module if it has been loaded.
|
||||
* Otherwise, null.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.getModule = function() {
|
||||
return this.module_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets this module as loaded.
|
||||
* @param {function() : Object} contextProvider A function that provides the
|
||||
* module context.
|
||||
* @return {boolean} Whether any errors occurred while executing the onload
|
||||
* callbacks.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.onLoad = function(contextProvider) {
|
||||
// Instantiate and initialize the module object.
|
||||
var module = new this.moduleConstructor_;
|
||||
module.initialize(contextProvider());
|
||||
|
||||
// Keep an internal reference to the module.
|
||||
this.module_ = module;
|
||||
|
||||
// Fire any early callbacks that were waiting for the module to be loaded.
|
||||
var errors =
|
||||
!!this.callCallbacks_(this.earlyOnloadCallbacks_, contextProvider());
|
||||
|
||||
// Fire any callbacks that were waiting for the module to be loaded.
|
||||
errors = errors ||
|
||||
!!this.callCallbacks_(this.onloadCallbacks_, contextProvider());
|
||||
|
||||
if (!errors) {
|
||||
// Clear the errbacks.
|
||||
this.onErrorCallbacks_.length = 0;
|
||||
}
|
||||
|
||||
return errors;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls the error callbacks for the module.
|
||||
* @param {goog.module.ModuleManager.FailureType} cause What caused the error.
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.onError = function(cause) {
|
||||
var result = this.callCallbacks_(this.onErrorCallbacks_, cause);
|
||||
if (result) {
|
||||
// Throw an exception asynchronously. Do not let the exception leak
|
||||
// up to the caller, or it will blow up the module loading framework.
|
||||
window.setTimeout(
|
||||
goog.functions.error('Module errback failures: ' + result), 0);
|
||||
}
|
||||
this.earlyOnloadCallbacks_.length = 0;
|
||||
this.onloadCallbacks_.length = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper to call the callbacks after module load.
|
||||
* @param {Array.<goog.module.ModuleLoadCallback>} callbacks The callbacks
|
||||
* to call and then clear.
|
||||
* @param {*} context The module context.
|
||||
* @return {Array.<*>} Any errors encountered while calling the callbacks,
|
||||
* or null if there were no errors.
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleInfo.prototype.callCallbacks_ = function(callbacks, context) {
|
||||
// NOTE(nicksantos):
|
||||
// In practice, there are two error-handling scenarios:
|
||||
// 1) The callback does some mandatory initialization of the module.
|
||||
// 2) The callback is for completion of some optional UI event.
|
||||
// There's no good way to handle both scenarios.
|
||||
//
|
||||
// Our strategy here is to protect module manager from exceptions, so that
|
||||
// the failure of one module doesn't affect the loading of other modules.
|
||||
// Then, we try to report the exception as best we can.
|
||||
|
||||
// Call each callback in the order they were registered
|
||||
var errors = [];
|
||||
for (var i = 0; i < callbacks.length; i++) {
|
||||
try {
|
||||
callbacks[i].execute(context);
|
||||
} catch (e) {
|
||||
errors.push(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the list of callbacks.
|
||||
callbacks.length = 0;
|
||||
return errors.length ? errors : null;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.module.ModuleInfo.prototype.disposeInternal = function() {
|
||||
goog.module.ModuleInfo.superClass_.disposeInternal.call(this);
|
||||
goog.dispose(this.module_);
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview A simple callback mechanism for notification about module
|
||||
* loads. Should be considered package-private to goog.module.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.module.ModuleLoadCallback');
|
||||
|
||||
goog.require('goog.debug.entryPointRegistry');
|
||||
goog.require('goog.debug.errorHandlerWeakDep');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class used to encapsulate the callbacks to be called when a module loads.
|
||||
* @param {Function} fn Callback function.
|
||||
* @param {Object=} opt_handler Optional handler under whose scope to execute
|
||||
* the callback.
|
||||
* @constructor
|
||||
*/
|
||||
goog.module.ModuleLoadCallback = function(fn, opt_handler) {
|
||||
/**
|
||||
* Callback function.
|
||||
* @type {Function}
|
||||
* @private
|
||||
*/
|
||||
this.fn_ = fn;
|
||||
|
||||
/**
|
||||
* Optional handler under whose scope to execute the callback.
|
||||
* @type {Object|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.handler_ = opt_handler;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Completes the operation and calls the callback function if appropriate.
|
||||
* @param {*} context The module context.
|
||||
*/
|
||||
goog.module.ModuleLoadCallback.prototype.execute = function(context) {
|
||||
if (this.fn_) {
|
||||
this.fn_.call(this.handler_ || null, context);
|
||||
this.handler_ = null;
|
||||
this.fn_ = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Abort the callback, but not the actual module load.
|
||||
*/
|
||||
goog.module.ModuleLoadCallback.prototype.abort = function() {
|
||||
this.fn_ = null;
|
||||
this.handler_ = null;
|
||||
};
|
||||
|
||||
|
||||
// Register the browser event handler as an entry point, so that
|
||||
// it can be monitored for exception handling, etc.
|
||||
goog.debug.entryPointRegistry.register(
|
||||
/**
|
||||
* @param {function(!Function): !Function} transformer The transforming
|
||||
* function.
|
||||
*/
|
||||
function(transformer) {
|
||||
goog.module.ModuleLoadCallback.prototype.execute =
|
||||
transformer(goog.module.ModuleLoadCallback.prototype.execute);
|
||||
});
|
||||
@@ -0,0 +1,462 @@
|
||||
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview The module loader for loading modules across the network.
|
||||
*
|
||||
* Browsers do not guarantee that scripts appended to the document
|
||||
* are executed in the order they are added. For production mode, we use
|
||||
* XHRs to load scripts, because they do not have this problem and they
|
||||
* have superior mechanisms for handling failure. However, XHR-evaled
|
||||
* scripts are harder to debug.
|
||||
*
|
||||
* In debugging mode, we use normal script tags. In order to make this work,
|
||||
* we load the scripts in serial: we do not execute script B to the document
|
||||
* until we are certain that script A is finished loading.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.module.ModuleLoader');
|
||||
|
||||
goog.require('goog.Timer');
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('goog.events.EventHandler');
|
||||
goog.require('goog.events.EventTarget');
|
||||
goog.require('goog.log');
|
||||
goog.require('goog.module.AbstractModuleLoader');
|
||||
goog.require('goog.net.BulkLoader');
|
||||
goog.require('goog.net.EventType');
|
||||
goog.require('goog.net.jsloader');
|
||||
goog.require('goog.userAgent.product');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A class that loads Javascript modules.
|
||||
* @constructor
|
||||
* @extends {goog.events.EventTarget}
|
||||
* @implements {goog.module.AbstractModuleLoader}
|
||||
*/
|
||||
goog.module.ModuleLoader = function() {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* Event handler for managing handling events.
|
||||
* @type {goog.events.EventHandler}
|
||||
* @private
|
||||
*/
|
||||
this.eventHandler_ = new goog.events.EventHandler(this);
|
||||
|
||||
/**
|
||||
* A map from module IDs to goog.module.ModuleLoader.LoadStatus.
|
||||
* @type {!Object.<Array.<string>, goog.module.ModuleLoader.LoadStatus>}
|
||||
* @private
|
||||
*/
|
||||
this.loadingModulesStatus_ = {};
|
||||
};
|
||||
goog.inherits(goog.module.ModuleLoader, goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* A logger.
|
||||
* @type {goog.log.Logger}
|
||||
* @protected
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.logger = goog.log.getLogger(
|
||||
'goog.module.ModuleLoader');
|
||||
|
||||
|
||||
/**
|
||||
* Whether debug mode is enabled.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.debugMode_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* Whether source url injection is enabled.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.sourceUrlInjection_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether sourceURL affects stack traces.
|
||||
* Chrome is currently the only browser that does this, but
|
||||
* we believe other browsers are working on this.
|
||||
* @see http://bugzilla.mozilla.org/show_bug.cgi?id=583083
|
||||
*/
|
||||
goog.module.ModuleLoader.supportsSourceUrlStackTraces = function() {
|
||||
return goog.userAgent.product.CHROME;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether sourceURL affects the debugger.
|
||||
*/
|
||||
goog.module.ModuleLoader.supportsSourceUrlDebugger = function() {
|
||||
return goog.userAgent.product.CHROME || goog.userAgent.GECKO;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the debug mode for the loader.
|
||||
* @return {boolean} Whether the debug mode is enabled.
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.getDebugMode = function() {
|
||||
return this.debugMode_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the debug mode for the loader.
|
||||
* @param {boolean} debugMode Whether the debug mode is enabled.
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.setDebugMode = function(debugMode) {
|
||||
this.debugMode_ = debugMode;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* When enabled, we will add a sourceURL comment to the end of all scripts
|
||||
* to mark their origin.
|
||||
*
|
||||
* On WebKit, stack traces will refect the sourceURL comment, so this is
|
||||
* useful for debugging webkit stack traces in production.
|
||||
*
|
||||
* Notice that in debug mode, we will use source url injection + eval rather
|
||||
* then appending script nodes to the DOM, because the scripts will load far
|
||||
* faster. (Appending script nodes is very slow, because we can't parallelize
|
||||
* the downloading and evaling of the script).
|
||||
*
|
||||
* The cost of appending sourceURL information is negligible when compared to
|
||||
* the cost of evaling the script. Almost all clients will want this on.
|
||||
*
|
||||
* TODO(nicksantos): Turn this on by default. We may want to turn this off
|
||||
* for clients that inject their own sourceURL.
|
||||
*
|
||||
* @param {boolean} enabled Whether source url injection is enabled.
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.setSourceUrlInjection = function(enabled) {
|
||||
this.sourceUrlInjection_ = enabled;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether we're using source url injection.
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.usingSourceUrlInjection_ = function() {
|
||||
return this.sourceUrlInjection_ ||
|
||||
(this.getDebugMode() &&
|
||||
goog.module.ModuleLoader.supportsSourceUrlStackTraces());
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.module.ModuleLoader.prototype.loadModules = function(
|
||||
ids, moduleInfoMap, opt_successFn, opt_errorFn, opt_timeoutFn,
|
||||
opt_forceReload) {
|
||||
var loadStatus = this.loadingModulesStatus_[ids] ||
|
||||
new goog.module.ModuleLoader.LoadStatus();
|
||||
loadStatus.loadRequested = true;
|
||||
loadStatus.successFn = opt_successFn || null;
|
||||
loadStatus.errorFn = opt_errorFn || null;
|
||||
|
||||
if (!this.loadingModulesStatus_[ids]) {
|
||||
// Modules were not prefetched.
|
||||
this.loadingModulesStatus_[ids] = loadStatus;
|
||||
this.downloadModules_(ids, moduleInfoMap);
|
||||
// TODO(user): Need to handle timeouts in the module loading code.
|
||||
} else if (goog.isDefAndNotNull(loadStatus.responseTexts)) {
|
||||
// Modules prefetch is complete.
|
||||
this.evaluateCode_(ids);
|
||||
}
|
||||
// Otherwise modules prefetch is in progress, and these modules will be
|
||||
// executed after the prefetch is complete.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate the JS code.
|
||||
* @param {Array.<string>} moduleIds The module ids.
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.evaluateCode_ = function(moduleIds) {
|
||||
this.dispatchEvent(new goog.module.ModuleLoader.Event(
|
||||
goog.module.ModuleLoader.EventType.REQUEST_SUCCESS, moduleIds));
|
||||
|
||||
goog.log.info(this.logger, 'evaluateCode ids:' + moduleIds);
|
||||
var success = true;
|
||||
var loadStatus = this.loadingModulesStatus_[moduleIds];
|
||||
var uris = loadStatus.requestUris;
|
||||
var texts = loadStatus.responseTexts;
|
||||
try {
|
||||
if (this.usingSourceUrlInjection_()) {
|
||||
for (var i = 0; i < uris.length; i++) {
|
||||
var uri = uris[i];
|
||||
goog.globalEval(texts[i] + ' //@ sourceURL=' + uri);
|
||||
}
|
||||
} else {
|
||||
goog.globalEval(texts.join('\n'));
|
||||
}
|
||||
} catch (e) {
|
||||
success = false;
|
||||
// TODO(user): Consider throwing an exception here.
|
||||
goog.log.warning(this.logger, 'Loaded incomplete code for module(s): ' +
|
||||
moduleIds, e);
|
||||
}
|
||||
|
||||
this.dispatchEvent(
|
||||
new goog.module.ModuleLoader.Event(
|
||||
goog.module.ModuleLoader.EventType.EVALUATE_CODE, moduleIds));
|
||||
|
||||
if (!success) {
|
||||
this.handleErrorHelper_(moduleIds, loadStatus.errorFn, null /* status */);
|
||||
} else if (loadStatus.successFn) {
|
||||
loadStatus.successFn();
|
||||
}
|
||||
delete this.loadingModulesStatus_[moduleIds];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles a successful response to a request for prefetch or load one or more
|
||||
* modules.
|
||||
*
|
||||
* @param {goog.net.BulkLoader} bulkLoader The bulk loader.
|
||||
* @param {Array.<string>} moduleIds The ids of the modules requested.
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.handleSuccess_ = function(
|
||||
bulkLoader, moduleIds) {
|
||||
goog.log.info(this.logger, 'Code loaded for module(s): ' + moduleIds);
|
||||
|
||||
var loadStatus = this.loadingModulesStatus_[moduleIds];
|
||||
loadStatus.responseTexts = bulkLoader.getResponseTexts();
|
||||
|
||||
if (loadStatus.loadRequested) {
|
||||
this.evaluateCode_(moduleIds);
|
||||
}
|
||||
|
||||
// NOTE: A bulk loader instance is used for loading a set of module ids.
|
||||
// Once these modules have been loaded successfully or in error the bulk
|
||||
// loader should be disposed as it is not needed anymore. A new bulk loader
|
||||
// is instantiated for any new modules to be loaded. The dispose is called
|
||||
// on a timer so that the bulkloader has a chance to release its
|
||||
// objects.
|
||||
goog.Timer.callOnce(bulkLoader.dispose, 5, bulkLoader);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.module.ModuleLoader.prototype.prefetchModule = function(
|
||||
id, moduleInfo) {
|
||||
// Do not prefetch in debug mode.
|
||||
if (this.getDebugMode()) {
|
||||
return;
|
||||
}
|
||||
var loadStatus = this.loadingModulesStatus_[[id]];
|
||||
if (loadStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
var moduleInfoMap = {};
|
||||
moduleInfoMap[id] = moduleInfo;
|
||||
this.loadingModulesStatus_[[id]] = new goog.module.ModuleLoader.LoadStatus();
|
||||
this.downloadModules_([id], moduleInfoMap);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Downloads a list of JavaScript modules.
|
||||
*
|
||||
* @param {Array.<string>} ids The module ids in dependency order.
|
||||
* @param {Object} moduleInfoMap A mapping from module id to ModuleInfo object.
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.downloadModules_ = function(
|
||||
ids, moduleInfoMap) {
|
||||
var uris = [];
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
goog.array.extend(uris, moduleInfoMap[ids[i]].getUris());
|
||||
}
|
||||
goog.log.info(this.logger, 'downloadModules ids:' + ids + ' uris:' + uris);
|
||||
|
||||
if (this.getDebugMode() &&
|
||||
!this.usingSourceUrlInjection_()) {
|
||||
// In debug mode use <script> tags rather than XHRs to load the files.
|
||||
// This makes it possible to debug and inspect stack traces more easily.
|
||||
// It's also possible to use it to load JavaScript files that are hosted on
|
||||
// another domain.
|
||||
// The scripts need to load serially, so this is much slower than parallel
|
||||
// script loads with source url injection.
|
||||
goog.net.jsloader.loadMany(uris);
|
||||
} else {
|
||||
var loadStatus = this.loadingModulesStatus_[ids];
|
||||
loadStatus.requestUris = uris;
|
||||
|
||||
var bulkLoader = new goog.net.BulkLoader(uris);
|
||||
|
||||
var eventHandler = this.eventHandler_;
|
||||
eventHandler.listen(
|
||||
bulkLoader,
|
||||
goog.net.EventType.SUCCESS,
|
||||
goog.bind(this.handleSuccess_, this, bulkLoader, ids),
|
||||
false,
|
||||
null);
|
||||
eventHandler.listen(
|
||||
bulkLoader,
|
||||
goog.net.EventType.ERROR,
|
||||
goog.bind(this.handleError_, this, bulkLoader, ids),
|
||||
false,
|
||||
null);
|
||||
bulkLoader.load();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles an error during a request for one or more modules.
|
||||
* @param {goog.net.BulkLoader} bulkLoader The bulk loader.
|
||||
* @param {Array.<string>} moduleIds The ids of the modules requested.
|
||||
* @param {number} status The response status.
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.handleError_ = function(
|
||||
bulkLoader, moduleIds, status) {
|
||||
var loadStatus = this.loadingModulesStatus_[moduleIds];
|
||||
// The bulk loader doesn't cancel other requests when a request fails. We will
|
||||
// delete the loadStatus in the first failure, so it will be undefined in
|
||||
// subsequent errors.
|
||||
if (loadStatus) {
|
||||
delete this.loadingModulesStatus_[moduleIds];
|
||||
this.handleErrorHelper_(moduleIds, loadStatus.errorFn, status);
|
||||
}
|
||||
|
||||
// NOTE: A bulk loader instance is used for loading a set of module ids. Once
|
||||
// these modules have been loaded successfully or in error the bulk loader
|
||||
// should be disposed as it is not needed anymore. A new bulk loader is
|
||||
// instantiated for any new modules to be loaded. The dispose is called
|
||||
// on another thread so that the bulkloader has a chance to release its
|
||||
// objects.
|
||||
goog.Timer.callOnce(bulkLoader.dispose, 5, bulkLoader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles an error during a request for one or more modules.
|
||||
* @param {Array.<string>} moduleIds The ids of the modules requested.
|
||||
* @param {?function(?number)} errorFn The function to call on failure.
|
||||
* @param {?number} status The response status.
|
||||
* @private
|
||||
*/
|
||||
goog.module.ModuleLoader.prototype.handleErrorHelper_ = function(
|
||||
moduleIds, errorFn, status) {
|
||||
this.dispatchEvent(
|
||||
new goog.module.ModuleLoader.Event(
|
||||
goog.module.ModuleLoader.EventType.REQUEST_ERROR, moduleIds));
|
||||
|
||||
goog.log.warning(this.logger, 'Request failed for module(s): ' + moduleIds);
|
||||
|
||||
if (errorFn) {
|
||||
errorFn(status);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.module.ModuleLoader.prototype.disposeInternal = function() {
|
||||
goog.module.ModuleLoader.superClass_.disposeInternal.call(this);
|
||||
|
||||
this.eventHandler_.dispose();
|
||||
this.eventHandler_ = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.module.ModuleLoader.EventType = {
|
||||
/** Called after the code for a module is evaluated. */
|
||||
EVALUATE_CODE: goog.events.getUniqueId('evaluateCode'),
|
||||
|
||||
/** Called when the BulkLoader finishes successfully. */
|
||||
REQUEST_SUCCESS: goog.events.getUniqueId('requestSuccess'),
|
||||
|
||||
/** Called when the BulkLoader fails, or code loading fails. */
|
||||
REQUEST_ERROR: goog.events.getUniqueId('requestError')
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.module.ModuleLoader.EventType} type The type.
|
||||
* @param {Array.<string>} moduleIds The ids of the modules being evaluated.
|
||||
* @constructor
|
||||
* @extends {goog.events.Event}
|
||||
*/
|
||||
goog.module.ModuleLoader.Event = function(type, moduleIds) {
|
||||
goog.base(this, type);
|
||||
|
||||
/**
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.moduleIds = moduleIds;
|
||||
};
|
||||
goog.inherits(goog.module.ModuleLoader.Event, goog.events.Event);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A class that keeps the state of the module during the loading process. It is
|
||||
* used to save loading information between modules download and evaluation.
|
||||
* @constructor
|
||||
*/
|
||||
goog.module.ModuleLoader.LoadStatus = function() {
|
||||
/**
|
||||
* The request uris.
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.requestUris = null;
|
||||
|
||||
/**
|
||||
* The response texts.
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.responseTexts = null;
|
||||
|
||||
/**
|
||||
* Whether loadModules was called for the set of modules referred by this
|
||||
* status.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.loadRequested = false;
|
||||
|
||||
/**
|
||||
* Success callback.
|
||||
* @type {?function()}
|
||||
*/
|
||||
this.successFn = null;
|
||||
|
||||
/**
|
||||
* Error callback.
|
||||
* @type {?function(?number)}
|
||||
*/
|
||||
this.errorFn = null;
|
||||
};
|
||||
@@ -0,0 +1,438 @@
|
||||
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Tests for goog.module.ModuleLoader.
|
||||
* @author nicksantos@google.com (Nick Santos)
|
||||
*/
|
||||
|
||||
goog.provide('goog.module.ModuleLoaderTest');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.functions');
|
||||
goog.require('goog.module.ModuleLoader');
|
||||
goog.require('goog.module.ModuleManager');
|
||||
goog.require('goog.module.ModuleManager.CallbackType');
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.testing.AsyncTestCase');
|
||||
goog.require('goog.testing.PropertyReplacer');
|
||||
goog.require('goog.testing.events.EventObserver');
|
||||
goog.require('goog.testing.jsunit');
|
||||
goog.require('goog.testing.recordFunction');
|
||||
goog.require('goog.userAgent.product');
|
||||
|
||||
goog.setTestOnly('goog.module.ModuleLoaderTest');
|
||||
|
||||
|
||||
var modA1Loaded = false;
|
||||
var modA2Loaded = false;
|
||||
var modB1Loaded = false;
|
||||
|
||||
var moduleLoader = null;
|
||||
var moduleManager = null;
|
||||
var stubs = new goog.testing.PropertyReplacer();
|
||||
|
||||
var testCase = goog.testing.AsyncTestCase.createAndInstall(document.title);
|
||||
testCase.stepTimeout = 5 * 1000; // 5 seconds
|
||||
|
||||
var EventType = goog.module.ModuleLoader.EventType;
|
||||
var observer;
|
||||
|
||||
testCase.setUp = function() {
|
||||
modA1Loaded = false;
|
||||
modA2Loaded = false;
|
||||
modB1Loaded = false;
|
||||
|
||||
goog.provide = goog.nullFunction;
|
||||
moduleManager = goog.module.ModuleManager.getInstance();
|
||||
stubs.replace(moduleManager, 'getBackOff_', goog.functions.constant(0));
|
||||
|
||||
moduleLoader = new goog.module.ModuleLoader();
|
||||
observer = new goog.testing.events.EventObserver();
|
||||
|
||||
goog.events.listen(
|
||||
moduleLoader, goog.object.getValues(EventType), observer);
|
||||
|
||||
moduleManager.setLoader(moduleLoader);
|
||||
moduleManager.setAllModuleInfo({
|
||||
'modA': [],
|
||||
'modB': ['modA']
|
||||
});
|
||||
moduleManager.setModuleUris({
|
||||
'modA': ['testdata/modA_1.js', 'testdata/modA_2.js'],
|
||||
'modB': ['testdata/modB_1.js']
|
||||
});
|
||||
|
||||
assertNotLoaded('modA');
|
||||
assertNotLoaded('modB');
|
||||
assertFalse(modA1Loaded);
|
||||
};
|
||||
|
||||
testCase.tearDown = function() {
|
||||
stubs.reset();
|
||||
|
||||
// Ensure that the module manager was created.
|
||||
assertNotNull(goog.module.ModuleManager.getInstance());
|
||||
moduleManager = goog.module.ModuleManager.instance_ = null;
|
||||
|
||||
// tear down the module loaded flag.
|
||||
modA1Loaded = false;
|
||||
|
||||
// Remove all the fake scripts.
|
||||
var scripts = goog.array.clone(
|
||||
document.getElementsByTagName('SCRIPT'));
|
||||
for (var i = 0; i < scripts.length; i++) {
|
||||
if (scripts[i].src.indexOf('testdata') != -1) {
|
||||
goog.dom.removeNode(scripts[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function testLoadModuleA() {
|
||||
testCase.waitForAsync('wait for module A load');
|
||||
moduleManager.execOnLoad('modA', function() {
|
||||
testCase.continueTesting();
|
||||
assertLoaded('modA');
|
||||
assertNotLoaded('modB');
|
||||
assertTrue(modA1Loaded);
|
||||
|
||||
assertEquals('EVALUATE_CODE',
|
||||
0, observer.getEvents(EventType.EVALUATE_CODE).length);
|
||||
assertEquals('REQUEST_SUCCESS',
|
||||
1, observer.getEvents(EventType.REQUEST_SUCCESS).length);
|
||||
assertArrayEquals(
|
||||
['modA'], observer.getEvents(EventType.REQUEST_SUCCESS)[0].moduleIds);
|
||||
assertEquals('REQUEST_ERROR',
|
||||
0, observer.getEvents(EventType.REQUEST_ERROR).length);
|
||||
});
|
||||
}
|
||||
|
||||
function testLoadModuleB() {
|
||||
testCase.waitForAsync('wait for module B load');
|
||||
moduleManager.execOnLoad('modB', function() {
|
||||
testCase.continueTesting();
|
||||
assertLoaded('modA');
|
||||
assertLoaded('modB');
|
||||
assertTrue(modA1Loaded);
|
||||
});
|
||||
}
|
||||
|
||||
function testLoadDebugModuleA() {
|
||||
testCase.waitForAsync('wait for module A load');
|
||||
moduleLoader.setDebugMode(true);
|
||||
moduleManager.execOnLoad('modA', function() {
|
||||
testCase.continueTesting();
|
||||
assertLoaded('modA');
|
||||
assertNotLoaded('modB');
|
||||
assertTrue(modA1Loaded);
|
||||
});
|
||||
}
|
||||
|
||||
function testLoadDebugModuleB() {
|
||||
testCase.waitForAsync('wait for module B load');
|
||||
moduleLoader.setDebugMode(true);
|
||||
moduleManager.execOnLoad('modB', function() {
|
||||
testCase.continueTesting();
|
||||
assertLoaded('modA');
|
||||
assertLoaded('modB');
|
||||
assertTrue(modA1Loaded);
|
||||
});
|
||||
}
|
||||
|
||||
function testLoadDebugModuleAThenB() {
|
||||
// Swap the script tags of module A, to introduce a race condition.
|
||||
// See the comments on this in ModuleLoader's debug loader.
|
||||
moduleManager.setModuleUris({
|
||||
'modA': ['testdata/modA_2.js', 'testdata/modA_1.js'],
|
||||
'modB': ['testdata/modB_1.js']
|
||||
});
|
||||
testCase.waitForAsync('wait for module B load');
|
||||
moduleLoader.setDebugMode(true);
|
||||
moduleManager.execOnLoad('modB', function() {
|
||||
testCase.continueTesting();
|
||||
assertLoaded('modA');
|
||||
assertLoaded('modB');
|
||||
|
||||
var scripts = goog.array.clone(
|
||||
document.getElementsByTagName('SCRIPT'));
|
||||
var seenLastScriptOfModuleA = false;
|
||||
for (var i = 0; i < scripts.length; i++) {
|
||||
var uri = scripts[i].src;
|
||||
if (uri.indexOf('modA_1.js') >= 0) {
|
||||
seenLastScriptOfModuleA = true;
|
||||
} else if (uri.indexOf('modB') >= 0) {
|
||||
assertTrue(seenLastScriptOfModuleA);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testSourceInjection() {
|
||||
moduleLoader.setSourceUrlInjection(true);
|
||||
assertSourceInjection();
|
||||
}
|
||||
|
||||
function testSourceInjectionViaDebugMode() {
|
||||
moduleLoader.setDebugMode(true);
|
||||
assertSourceInjection();
|
||||
}
|
||||
|
||||
function assertSourceInjection() {
|
||||
testCase.waitForAsync('wait for module B load');
|
||||
|
||||
moduleManager.execOnLoad('modB', function() {
|
||||
testCase.continueTesting();
|
||||
|
||||
assertTrue(!!throwErrorInModuleB);
|
||||
|
||||
var ex = assertThrows(function() {
|
||||
throwErrorInModuleB();
|
||||
});
|
||||
|
||||
var stackTrace = ex.stack.toString();
|
||||
var expectedString = 'testdata/modB_1.js';
|
||||
|
||||
if (goog.module.ModuleLoader.supportsSourceUrlStackTraces()) {
|
||||
// Source URL should be added in eval or in jsloader.
|
||||
assertContains(expectedString, stackTrace);
|
||||
} else if (moduleLoader.isDebugMode()) {
|
||||
// Browsers used jsloader, thus URLs are present.
|
||||
assertContains(expectedString, stackTrace);
|
||||
} else {
|
||||
// Browser used eval, does not support source URL.
|
||||
assertNotContains(expectedString, stackTrace);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testModuleLoaderRecursesTooDeep(opt_numModules) {
|
||||
// There was a bug in the module loader where it would retry recursively
|
||||
// whenever there was a synchronous failure in the module load. When you
|
||||
// asked for modB, it would try to load its dependency modA. When modA
|
||||
// failed, it would move onto modB, and then start over, repeating until it
|
||||
// ran out of stack.
|
||||
var numModules = opt_numModules || 1;
|
||||
var uris = {};
|
||||
var deps = {};
|
||||
var mods = [];
|
||||
for (var num = 0; num < numModules; num++) {
|
||||
var modName = 'mod' + num;
|
||||
mods.unshift(modName);
|
||||
uris[modName] = [];
|
||||
deps[modName] = num ? ['mod' + (num - 1)] : [];
|
||||
for (var i = 0; i < 5; i++) {
|
||||
uris[modName].push(
|
||||
'http://www.google.com/crossdomain' + num + 'x' + i + '.js');
|
||||
}
|
||||
}
|
||||
|
||||
moduleManager.setAllModuleInfo(deps);
|
||||
moduleManager.setModuleUris(uris);
|
||||
|
||||
// Make all XHRs throw an error, so that we test the error-handling
|
||||
// functionality.
|
||||
var oldXmlHttp = goog.net.XmlHttp;
|
||||
stubs.set(goog.net, 'XmlHttp', function() {
|
||||
return {
|
||||
open: goog.functions.error('mock error'),
|
||||
abort: goog.nullFunction
|
||||
};
|
||||
});
|
||||
goog.object.extend(goog.net.XmlHttp, oldXmlHttp);
|
||||
|
||||
var errorCount = 0;
|
||||
var errorIds = [];
|
||||
var errorHandler = function(ignored, modId) {
|
||||
errorCount++;
|
||||
errorIds.push(modId);
|
||||
};
|
||||
moduleManager.registerCallback(
|
||||
goog.module.ModuleManager.CallbackType.ERROR,
|
||||
errorHandler);
|
||||
|
||||
moduleManager.execOnLoad(mods[0], function() {
|
||||
fail('modB should not load successfully');
|
||||
});
|
||||
|
||||
assertEquals(mods.length, errorCount);
|
||||
|
||||
goog.array.sort(mods);
|
||||
goog.array.sort(errorIds);
|
||||
assertArrayEquals(mods, errorIds);
|
||||
|
||||
assertArrayEquals([], moduleManager.requestedModuleIdsQueue_);
|
||||
assertArrayEquals([], moduleManager.userInitiatedLoadingModuleIds_);
|
||||
}
|
||||
|
||||
function testModuleLoaderRecursesTooDeep2modules() {
|
||||
testModuleLoaderRecursesTooDeep(2);
|
||||
}
|
||||
|
||||
function testModuleLoaderRecursesTooDeep3modules() {
|
||||
testModuleLoaderRecursesTooDeep(3);
|
||||
}
|
||||
|
||||
function testModuleLoaderRecursesTooDeep4modules() {
|
||||
testModuleLoaderRecursesTooDeep(3);
|
||||
}
|
||||
|
||||
function testErrback() {
|
||||
// Don't run this test on IE, because the way the test runner catches
|
||||
// errors on IE plays badly with the simulated errors in the test.
|
||||
if (goog.userAgent.IE) return;
|
||||
|
||||
// Modules will throw an exception if this boolean is set to true.
|
||||
modA1Loaded = true;
|
||||
|
||||
var errorHandler = function() {
|
||||
testCase.continueTesting();
|
||||
assertNotLoaded('modA');
|
||||
};
|
||||
moduleManager.registerCallback(
|
||||
goog.module.ModuleManager.CallbackType.ERROR,
|
||||
errorHandler);
|
||||
|
||||
moduleManager.execOnLoad('modA', function() {
|
||||
fail('modA should not load successfully');
|
||||
});
|
||||
|
||||
testCase.waitForAsync('wait for the error callback');
|
||||
}
|
||||
|
||||
function testPrefetchThenLoadModuleA() {
|
||||
moduleManager.prefetchModule('modA');
|
||||
stubs.set(goog.net.BulkLoader.prototype, 'load', function() {
|
||||
fail('modA should not be reloaded')
|
||||
});
|
||||
|
||||
testCase.waitForAsync('wait for module A load');
|
||||
moduleManager.execOnLoad('modA', function() {
|
||||
testCase.continueTesting();
|
||||
assertLoaded('modA');
|
||||
assertEquals('REQUEST_SUCCESS',
|
||||
1, observer.getEvents(EventType.REQUEST_SUCCESS).length);
|
||||
assertArrayEquals(
|
||||
['modA'], observer.getEvents(EventType.REQUEST_SUCCESS)[0].moduleIds);
|
||||
assertEquals('REQUEST_ERROR',
|
||||
0, observer.getEvents(EventType.REQUEST_ERROR).length);
|
||||
});
|
||||
}
|
||||
|
||||
function testPrefetchThenLoadModuleB() {
|
||||
moduleManager.prefetchModule('modB');
|
||||
stubs.set(goog.net.BulkLoader.prototype, 'load', function() {
|
||||
fail('modA and modB should not be reloaded')
|
||||
});
|
||||
|
||||
testCase.waitForAsync('wait for module B load');
|
||||
moduleManager.execOnLoad('modB', function() {
|
||||
testCase.continueTesting();
|
||||
assertLoaded('modA');
|
||||
assertLoaded('modB');
|
||||
assertEquals('REQUEST_SUCCESS',
|
||||
2, observer.getEvents(EventType.REQUEST_SUCCESS).length);
|
||||
assertArrayEquals(
|
||||
['modA'], observer.getEvents(EventType.REQUEST_SUCCESS)[0].moduleIds);
|
||||
assertArrayEquals(
|
||||
['modB'], observer.getEvents(EventType.REQUEST_SUCCESS)[1].moduleIds);
|
||||
assertEquals('REQUEST_ERROR',
|
||||
0, observer.getEvents(EventType.REQUEST_ERROR).length);
|
||||
});
|
||||
}
|
||||
|
||||
function testPrefetchModuleAThenLoadModuleB() {
|
||||
moduleManager.prefetchModule('modA');
|
||||
|
||||
testCase.waitForAsync('wait for module A load');
|
||||
moduleManager.execOnLoad('modB', function() {
|
||||
testCase.continueTesting();
|
||||
assertLoaded('modA');
|
||||
assertLoaded('modB');
|
||||
assertEquals('REQUEST_SUCCESS',
|
||||
2, observer.getEvents(EventType.REQUEST_SUCCESS).length);
|
||||
assertArrayEquals(
|
||||
['modA'], observer.getEvents(EventType.REQUEST_SUCCESS)[0].moduleIds);
|
||||
assertArrayEquals(
|
||||
['modB'], observer.getEvents(EventType.REQUEST_SUCCESS)[1].moduleIds);
|
||||
assertEquals('REQUEST_ERROR',
|
||||
0, observer.getEvents(EventType.REQUEST_ERROR).length);
|
||||
});
|
||||
}
|
||||
|
||||
function testLoadModuleBThenPrefetchModuleA() {
|
||||
testCase.waitForAsync('wait for module A load');
|
||||
moduleManager.execOnLoad('modB', function() {
|
||||
testCase.continueTesting();
|
||||
assertLoaded('modA');
|
||||
assertLoaded('modB');
|
||||
assertEquals('REQUEST_SUCCESS',
|
||||
2, observer.getEvents(EventType.REQUEST_SUCCESS).length);
|
||||
assertArrayEquals(
|
||||
['modA'], observer.getEvents(EventType.REQUEST_SUCCESS)[0].moduleIds);
|
||||
assertArrayEquals(
|
||||
['modB'], observer.getEvents(EventType.REQUEST_SUCCESS)[1].moduleIds);
|
||||
assertEquals('REQUEST_ERROR',
|
||||
0, observer.getEvents(EventType.REQUEST_ERROR).length);
|
||||
assertThrows('Module load already requested: modB',
|
||||
function() {
|
||||
moduleManager.prefetchModule('modA')
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testPrefetchModuleWithBatchModeEnabled() {
|
||||
moduleManager.setBatchModeEnabled(true);
|
||||
assertThrows('Modules prefetching is not supported in batch mode',
|
||||
function() {
|
||||
moduleManager.prefetchModule('modA');
|
||||
});
|
||||
}
|
||||
|
||||
function testLoadErrorCallbackExecutedWhenPrefetchFails() {
|
||||
// Make all XHRs throw an error, so that we test the error-handling
|
||||
// functionality.
|
||||
var oldXmlHttp = goog.net.XmlHttp;
|
||||
stubs.set(goog.net, 'XmlHttp', function() {
|
||||
return {
|
||||
open: goog.functions.error('mock error'),
|
||||
abort: goog.nullFunction
|
||||
};
|
||||
});
|
||||
goog.object.extend(goog.net.XmlHttp, oldXmlHttp);
|
||||
|
||||
var errorCount = 0;
|
||||
var errorHandler = function() {
|
||||
errorCount++;
|
||||
};
|
||||
moduleManager.registerCallback(
|
||||
goog.module.ModuleManager.CallbackType.ERROR,
|
||||
errorHandler);
|
||||
|
||||
moduleLoader.prefetchModule('modA', moduleManager.moduleInfoMap_['modA']);
|
||||
moduleLoader.loadModules(['modA'], moduleManager.moduleInfoMap_,
|
||||
function() {
|
||||
fail('modA should not load successfully')
|
||||
}, errorHandler);
|
||||
|
||||
assertEquals(1, errorCount);
|
||||
}
|
||||
|
||||
function assertLoaded(id) {
|
||||
assertTrue(moduleManager.getModuleInfo(id).isLoaded());
|
||||
}
|
||||
|
||||
function assertNotLoaded(id) {
|
||||
assertFalse(moduleManager.getModuleInfo(id).isLoaded());
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// All Rights Reserved
|
||||
|
||||
/**
|
||||
* @fileoverview File #1 of module A.
|
||||
*/
|
||||
|
||||
goog.provide('goog.module.testdata.modA_1');
|
||||
|
||||
if (window.modA1Loaded) throw Error('modA_1 loaded twice');
|
||||
window.modA1Loaded = true;
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// All Rights Reserved
|
||||
|
||||
/**
|
||||
* @fileoverview File #2 of module A.
|
||||
*/
|
||||
|
||||
goog.provide('goog.module.testdata.modA_2');
|
||||
|
||||
goog.require('goog.module.ModuleManager');
|
||||
|
||||
if (window.modA2Loaded) throw Error('modA_2 loaded twice');
|
||||
window.modA2Loaded = true;
|
||||
|
||||
goog.module.ModuleManager.getInstance().setLoaded('modA');
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// All Rights Reserved
|
||||
|
||||
/**
|
||||
* @fileoverview File #1 of module B.
|
||||
*/
|
||||
|
||||
goog.provide('goog.module.testdata.modB_1');
|
||||
|
||||
goog.require('goog.module.ModuleManager');
|
||||
|
||||
function throwErrorInModuleB() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
if (window.modB1Loaded) throw Error('modB_1 loaded twice');
|
||||
window.modB1Loaded = true;
|
||||
|
||||
goog.module.ModuleManager.getInstance().setLoaded('modB');
|
||||
Reference in New Issue
Block a user