Path: blob/trunk/third_party/closure/goog/module/moduleinfo.js
2868 views
// Copyright 2008 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Defines the goog.module.ModuleInfo class.16*17*/1819goog.provide('goog.module.ModuleInfo');2021goog.require('goog.Disposable');22goog.require('goog.async.throwException');23goog.require('goog.functions');24/** @suppress {extraRequire} */25goog.require('goog.module');26goog.require('goog.module.BaseModule');27goog.require('goog.module.ModuleLoadCallback');2829// TODO(johnlenz): goog.module.ModuleManager.FailureType into its own file.30goog.forwardDeclare('goog.module.ModuleManager.FailureType');31323334/**35* A ModuleInfo object is used by the ModuleManager to hold information about a36* module of js code that may or may not yet be loaded into the environment.37*38* @param {Array<string>} deps Ids of the modules that must be loaded before39* this one. The ids must be in dependency order (i.e. if the ith module40* depends on the jth module, then i > j).41* @param {string} id The module's ID.42* @constructor43* @extends {goog.Disposable}44* @final45*/46goog.module.ModuleInfo = function(deps, id) {47goog.Disposable.call(this);4849/**50* A list of the ids of the modules that must be loaded before this module.51* @type {Array<string>}52* @private53*/54this.deps_ = deps;5556/**57* The module's ID.58* @type {string}59* @private60*/61this.id_ = id;6263/**64* Callbacks to execute once this module is loaded.65* @type {Array<goog.module.ModuleLoadCallback>}66* @private67*/68this.onloadCallbacks_ = [];6970/**71* Callbacks to execute if the module load errors.72* @type {Array<goog.module.ModuleLoadCallback>}73* @private74*/75this.onErrorCallbacks_ = [];7677/**78* Early callbacks to execute once this module is loaded. Called after79* module initialization but before regular onload callbacks.80* @type {Array<goog.module.ModuleLoadCallback>}81* @private82*/83this.earlyOnloadCallbacks_ = [];84};85goog.inherits(goog.module.ModuleInfo, goog.Disposable);868788/**89* The uris that can be used to retrieve this module's code.90* @type {Array<string>?}91* @private92*/93goog.module.ModuleInfo.prototype.uris_ = null;949596/**97* The constructor to use to instantiate the module object after the module98* code is loaded. This must be either goog.module.BaseModule or a subclass of99* it.100* @type {Function}101* @private102*/103goog.module.ModuleInfo.prototype.moduleConstructor_ = goog.module.BaseModule;104105106/**107* The module object. This will be null until the module is loaded.108* @type {goog.module.BaseModule?}109* @private110*/111goog.module.ModuleInfo.prototype.module_ = null;112113114/**115* Gets the dependencies of this module.116* @return {Array<string>} The ids of the modules that this module depends on.117*/118goog.module.ModuleInfo.prototype.getDependencies = function() {119return this.deps_;120};121122123/**124* Gets the ID of this module.125* @return {string} The ID.126*/127goog.module.ModuleInfo.prototype.getId = function() {128return this.id_;129};130131132/**133* Sets the uris of this module.134* @param {Array<string>} uris Uris for this module's code.135*/136goog.module.ModuleInfo.prototype.setUris = function(uris) {137this.uris_ = uris;138};139140141/**142* Gets the uris of this module.143* @return {Array<string>?} Uris for this module's code.144*/145goog.module.ModuleInfo.prototype.getUris = function() {146return this.uris_;147};148149150/**151* Sets the constructor to use to instantiate the module object after the152* module code is loaded.153* @param {Function} constructor The constructor of a goog.module.BaseModule154* subclass.155*/156goog.module.ModuleInfo.prototype.setModuleConstructor = function(constructor) {157if (this.moduleConstructor_ === goog.module.BaseModule) {158this.moduleConstructor_ = constructor;159} else {160throw Error('Cannot set module constructor more than once.');161}162};163164165/**166* Registers a function that should be called after the module is loaded. These167* early callbacks are called after {@link Module#initialize} is called but168* before the other callbacks are called.169* @param {Function} fn A callback function that takes a single argument which170* is the module context.171* @param {Object=} opt_handler Optional handler under whose scope to execute172* the callback.173* @return {!goog.module.ModuleLoadCallback} Reference to the callback174* object.175*/176goog.module.ModuleInfo.prototype.registerEarlyCallback = function(177fn, opt_handler) {178return this.registerCallback_(this.earlyOnloadCallbacks_, fn, opt_handler);179};180181182/**183* Registers a function that should be called after the module is loaded.184* @param {Function} fn A callback function that takes a single argument which185* is the module context.186* @param {Object=} opt_handler Optional handler under whose scope to execute187* the callback.188* @return {!goog.module.ModuleLoadCallback} Reference to the callback189* object.190*/191goog.module.ModuleInfo.prototype.registerCallback = function(fn, opt_handler) {192return this.registerCallback_(this.onloadCallbacks_, fn, opt_handler);193};194195196/**197* Registers a function that should be called if the module load fails.198* @param {Function} fn A callback function that takes a single argument which199* is the failure type.200* @param {Object=} opt_handler Optional handler under whose scope to execute201* the callback.202* @return {!goog.module.ModuleLoadCallback} Reference to the callback203* object.204*/205goog.module.ModuleInfo.prototype.registerErrback = function(fn, opt_handler) {206return this.registerCallback_(this.onErrorCallbacks_, fn, opt_handler);207};208209210/**211* Registers a function that should be called after the module is loaded.212* @param {Array<goog.module.ModuleLoadCallback>} callbacks The array to213* add the callback to.214* @param {Function} fn A callback function that takes a single argument which215* is the module context.216* @param {Object=} opt_handler Optional handler under whose scope to execute217* the callback.218* @return {!goog.module.ModuleLoadCallback} Reference to the callback219* object.220* @private221*/222goog.module.ModuleInfo.prototype.registerCallback_ = function(223callbacks, fn, opt_handler) {224var callback = new goog.module.ModuleLoadCallback(fn, opt_handler);225callbacks.push(callback);226return callback;227};228229230/**231* Determines whether the module has been loaded.232* @return {boolean} Whether the module has been loaded.233*/234goog.module.ModuleInfo.prototype.isLoaded = function() {235return !!this.module_;236};237238239/**240* Gets the module.241* @return {goog.module.BaseModule?} The module if it has been loaded.242* Otherwise, null.243*/244goog.module.ModuleInfo.prototype.getModule = function() {245return this.module_;246};247248249/**250* Sets this module as loaded.251* @param {function() : Object} contextProvider A function that provides the252* module context.253* @return {boolean} Whether any errors occurred while executing the onload254* callbacks.255*/256goog.module.ModuleInfo.prototype.onLoad = function(contextProvider) {257// Instantiate and initialize the module object.258var module = new this.moduleConstructor_;259module.initialize(contextProvider());260261// Keep an internal reference to the module.262this.module_ = module;263264// Fire any early callbacks that were waiting for the module to be loaded.265var errors =266!!this.callCallbacks_(this.earlyOnloadCallbacks_, contextProvider());267268// Fire any callbacks that were waiting for the module to be loaded.269errors =270errors || !!this.callCallbacks_(this.onloadCallbacks_, contextProvider());271272if (!errors) {273// Clear the errbacks.274this.onErrorCallbacks_.length = 0;275}276277return errors;278};279280281/**282* Calls the error callbacks for the module.283* @param {goog.module.ModuleManager.FailureType} cause What caused the error.284*/285goog.module.ModuleInfo.prototype.onError = function(cause) {286var result = this.callCallbacks_(this.onErrorCallbacks_, cause);287if (result) {288// Throw an exception asynchronously. Do not let the exception leak289// up to the caller, or it will blow up the module loading framework.290window.setTimeout(291goog.functions.error('Module errback failures: ' + result), 0);292}293this.earlyOnloadCallbacks_.length = 0;294this.onloadCallbacks_.length = 0;295};296297298/**299* Helper to call the callbacks after module load.300* @param {Array<goog.module.ModuleLoadCallback>} callbacks The callbacks301* to call and then clear.302* @param {*} context The module context.303* @return {Array<*>} Any errors encountered while calling the callbacks,304* or null if there were no errors.305* @private306*/307goog.module.ModuleInfo.prototype.callCallbacks_ = function(callbacks, context) {308// NOTE(nicksantos):309// In practice, there are two error-handling scenarios:310// 1) The callback does some mandatory initialization of the module.311// 2) The callback is for completion of some optional UI event.312// There's no good way to handle both scenarios.313//314// Our strategy here is to protect module manager from exceptions, so that315// the failure of one module doesn't affect the loading of other modules.316// Errors are thrown outside of the current stack frame, so they still317// get reported but don't interrupt execution.318319// Call each callback in the order they were registered320var errors = [];321for (var i = 0; i < callbacks.length; i++) {322try {323callbacks[i].execute(context);324} catch (e) {325goog.async.throwException(e);326errors.push(e);327}328}329330// Clear the list of callbacks.331callbacks.length = 0;332return errors.length ? errors : null;333};334335336/** @override */337goog.module.ModuleInfo.prototype.disposeInternal = function() {338goog.module.ModuleInfo.superClass_.disposeInternal.call(this);339goog.dispose(this.module_);340};341342343