UNPKG

framework-factory

Version:

A wonderful factory framwork for creating modern object oriented javascript libraries.

1,168 lines (1,049 loc) 87.2 kB
/** vim: et:ts=4:sw=4:sts=4 * @license RequireJS 1.0.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ /*jslint strict: false, plusplus: false, sub: true */ /*global window, navigator, document, importScripts, jQuery, setTimeout, opera */ var requirejs, require, define; (function () { //Change this version number for each release. var version = "1.0.6", commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /require\(\s*["']([^'"\s]+)["']\s*\)/g, currDirRegExp = /^\.\//, jsSuffixRegExp = /\.js$/, ostring = Object.prototype.toString, ap = Array.prototype, aps = ap.slice, apsp = ap.splice, isBrowser = !!(typeof window !== "undefined" && navigator && document), isWebWorker = !isBrowser && typeof importScripts !== "undefined", //PS3 indicates loaded and complete, but need to wait for complete //specifically. Sequence is "loading", "loaded", execution, // then "complete". The UA check is unfortunate, but not sure how //to feature test w/o causing perf issues. readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? /^complete$/ : /^(complete|loaded)$/, defContextName = "_", //Oh the tragedy, detecting opera. See the usage of isOpera for reason. isOpera = typeof opera !== "undefined" && opera.toString() === "[object Opera]", empty = {}, contexts = {}, globalDefQueue = [], interactiveScript = null, checkLoadedDepth = 0, useInteractive = false, reservedDependencies = { require: true, module: true, exports: true }, req, cfg = {}, currentlyAddingScript, s, head, baseElement, scripts, script, src, subPath, mainScript, dataMain, globalI, ctx, jQueryCheck, checkLoadedTimeoutId; function isFunction(it) { return ostring.call(it) === "[object Function]"; } function isArray(it) { return ostring.call(it) === "[object Array]"; } /** * Simple function to mix in properties from source into target, * but only if target does not already have a property of the same name. * This is not robust in IE for transferring methods that match * Object.prototype names, but the uses of mixin here seem unlikely to * trigger a problem related to that. */ function mixin(target, source, force) { for (var prop in source) { if (!(prop in empty) && (!(prop in target) || force)) { target[prop] = source[prop]; } } return req; } /** * Constructs an error with a pointer to an URL with more information. * @param {String} id the error ID that maps to an ID on a web page. * @param {String} message human readable error. * @param {Error} [err] the original error, if there is one. * * @returns {Error} */ function makeError(id, msg, err) { var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); if (err) { e.originalError = err; } return e; } /** * Used to set up package paths from a packagePaths or packages config object. * @param {Object} pkgs the object to store the new package config * @param {Array} currentPackages an array of packages to configure * @param {String} [dir] a prefix dir to use. */ function configurePackageDir(pkgs, currentPackages, dir) { var i, location, pkgObj; for (i = 0; (pkgObj = currentPackages[i]); i++) { pkgObj = typeof pkgObj === "string" ? { name: pkgObj } : pkgObj; location = pkgObj.location; //Add dir to the path, but avoid paths that start with a slash //or have a colon (indicates a protocol) if (dir && (!location || (location.indexOf("/") !== 0 && location.indexOf(":") === -1))) { location = dir + "/" + (location || pkgObj.name); } //Create a brand new object on pkgs, since currentPackages can //be passed in again, and config.pkgs is the internal transformed //state for all package configs. pkgs[pkgObj.name] = { name: pkgObj.name, location: location || pkgObj.name, //Remove leading dot in main, so main paths are normalized, //and remove any trailing .js, since different package //envs have different conventions: some use a module name, //some use a file name. main: (pkgObj.main || "main") .replace(currDirRegExp, '') .replace(jsSuffixRegExp, '') }; } } /** * jQuery 1.4.3-1.5.x use a readyWait/ready() pairing to hold DOM * ready callbacks, but jQuery 1.6 supports a holdReady() API instead. * At some point remove the readyWait/ready() support and just stick * with using holdReady. */ function jQueryHoldReady($, shouldHold) { if ($.holdReady) { $.holdReady(shouldHold); } else if (shouldHold) { $.readyWait += 1; } else { $.ready(true); } } if (typeof define !== "undefined") { //If a define is already in play via another AMD loader, //do not overwrite. return; } if (typeof requirejs !== "undefined") { if (isFunction(requirejs)) { //Do not overwrite and existing requirejs instance. return; } else { cfg = requirejs; requirejs = undefined; } } //Allow for a require config object if (typeof require !== "undefined" && !isFunction(require)) { //assume it is a config object. cfg = require; require = undefined; } /** * Creates a new context for use in require and define calls. * Handle most of the heavy lifting. Do not want to use an object * with prototype here to avoid using "this" in require, in case it * needs to be used in more super secure envs that do not want this. * Also there should not be that many contexts in the page. Usually just * one for the default context, but could be extra for multiversion cases * or if a package needs a special context for a dependency that conflicts * with the standard context. */ function newContext(contextName) { var context, resume, config = { waitSeconds: 7, baseUrl: "./", paths: {}, pkgs: {}, catchError: {} }, defQueue = [], specified = { "require": true, "exports": true, "module": true }, urlMap = {}, defined = {}, loaded = {}, waiting = {}, waitAry = [], urlFetched = {}, managerCounter = 0, managerCallbacks = {}, plugins = {}, //Used to indicate which modules in a build scenario //need to be full executed. needFullExec = {}, fullExec = {}, resumeDepth = 0; /** * Trims the . and .. from an array of path segments. * It will keep a leading path segment if a .. will become * the first path segment, to help with module name lookups, * which act like paths, but can be remapped. But the end result, * all paths that use this function should look normalized. * NOTE: this method MODIFIES the input array. * @param {Array} ary the array of path segments. */ function trimDots(ary) { var i, part; for (i = 0; (part = ary[i]); i++) { if (part === ".") { ary.splice(i, 1); i -= 1; } else if (part === "..") { if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { //End of the line. Keep at least one non-dot //path segment at the front so it can be mapped //correctly to disk. Otherwise, there is likely //no path mapping for a path starting with '..'. //This can still fail, but catches the most reasonable //uses of .. break; } else if (i > 0) { ary.splice(i - 1, 2); i -= 2; } } } } /** * Given a relative module name, like ./something, normalize it to * a real name that can be mapped to a path. * @param {String} name the relative name * @param {String} baseName a real name that the name arg is relative * to. * @returns {String} normalized name */ function normalize(name, baseName) { var pkgName, pkgConfig; //Adjust any relative paths. if (name && name.charAt(0) === ".") { //If have a base name, try to normalize against it, //otherwise, assume it is a top-level require that will //be relative to baseUrl in the end. if (baseName) { if (config.pkgs[baseName]) { //If the baseName is a package name, then just treat it as one //name to concat the name with. baseName = [baseName]; } else { //Convert baseName to array, and lop off the last part, //so that . matches that "directory" and not name of the baseName's //module. For instance, baseName of "one/two/three", maps to //"one/two/three.js", but we want the directory, "one/two" for //this normalization. baseName = baseName.split("/"); baseName = baseName.slice(0, baseName.length - 1); } name = baseName.concat(name.split("/")); trimDots(name); //Some use of packages may use a . path to reference the //"main" module name, so normalize for that. pkgConfig = config.pkgs[(pkgName = name[0])]; name = name.join("/"); if (pkgConfig && name === pkgName + '/' + pkgConfig.main) { name = pkgName; } } else if (name.indexOf("./") === 0) { // No baseName, so this is ID is resolved relative // to baseUrl, pull off the leading dot. name = name.substring(2); } } return name; } /** * Creates a module mapping that includes plugin prefix, module * name, and path. If parentModuleMap is provided it will * also normalize the name via require.normalize() * * @param {String} name the module name * @param {String} [parentModuleMap] parent module map * for the module name, used to resolve relative names. * * @returns {Object} */ function makeModuleMap(name, parentModuleMap) { var index = name ? name.indexOf("!") : -1, prefix = null, parentName = parentModuleMap ? parentModuleMap.name : null, originalName = name, normalizedName, url, pluginModule; if (index !== -1) { prefix = name.substring(0, index); name = name.substring(index + 1, name.length); } if (prefix) { prefix = normalize(prefix, parentName); } //Account for relative paths if there is a base name. if (name) { if (prefix) { pluginModule = defined[prefix]; if (pluginModule && pluginModule.normalize) { //Plugin is loaded, use its normalize method. normalizedName = pluginModule.normalize(name, function (name) { return normalize(name, parentName); }); } else { normalizedName = normalize(name, parentName); } } else { //A regular module. normalizedName = normalize(name, parentName); url = urlMap[normalizedName]; if (!url) { //Calculate url for the module, if it has a name. //Use name here since nameToUrl also calls normalize, //and for relative names that are outside the baseUrl //this causes havoc. Was thinking of just removing //parentModuleMap to avoid extra normalization, but //normalize() still does a dot removal because of //issue #142, so just pass in name here and redo //the normalization. Paths outside baseUrl are just //messy to support. url = context.nameToUrl(name, null, parentModuleMap); //Store the URL mapping for later. urlMap[normalizedName] = url; } } } return { prefix: prefix, name: normalizedName, parentMap: parentModuleMap, url: url, originalName: originalName, fullName: prefix ? prefix + "!" + (normalizedName || '') : normalizedName }; } /** * Determine if priority loading is done. If so clear the priorityWait */ function isPriorityDone() { var priorityDone = true, priorityWait = config.priorityWait, priorityName, i; if (priorityWait) { for (i = 0; (priorityName = priorityWait[i]); i++) { if (!loaded[priorityName]) { priorityDone = false; break; } } if (priorityDone) { delete config.priorityWait; } } return priorityDone; } function makeContextModuleFunc(func, relModuleMap, enableBuildCallback) { return function () { //A version of a require function that passes a moduleName //value for items that may need to //look up paths relative to the moduleName var args = aps.call(arguments, 0), lastArg; if (enableBuildCallback && isFunction((lastArg = args[args.length - 1]))) { lastArg.__requireJsBuild = true; } args.push(relModuleMap); return func.apply(null, args); }; } /** * Helper function that creates a require function object to give to * modules that ask for it as a dependency. It needs to be specific * per module because of the implication of path mappings that may * need to be relative to the module name. */ function makeRequire(relModuleMap, enableBuildCallback, altRequire) { var modRequire = makeContextModuleFunc(altRequire || context.require, relModuleMap, enableBuildCallback); mixin(modRequire, { nameToUrl: makeContextModuleFunc(context.nameToUrl, relModuleMap), toUrl: makeContextModuleFunc(context.toUrl, relModuleMap), defined: makeContextModuleFunc(context.requireDefined, relModuleMap), specified: makeContextModuleFunc(context.requireSpecified, relModuleMap), isBrowser: req.isBrowser }); return modRequire; } /* * Queues a dependency for checking after the loader is out of a * "paused" state, for example while a script file is being loaded * in the browser, where it may have many modules defined in it. */ function queueDependency(manager) { context.paused.push(manager); } function execManager(manager) { var i, ret, err, errFile, errModuleTree, cb = manager.callback, map = manager.map, fullName = map.fullName, args = manager.deps, listeners = manager.listeners, cjsModule; //Call the callback to define the module, if necessary. if (cb && isFunction(cb)) { if (config.catchError.define) { try { ret = req.execCb(fullName, manager.callback, args, defined[fullName]); } catch (e) { err = e; } } else { ret = req.execCb(fullName, manager.callback, args, defined[fullName]); } if (fullName) { //If setting exports via "module" is in play, //favor that over return value and exports. After that, //favor a non-undefined return value over exports use. cjsModule = manager.cjsModule; if (cjsModule && cjsModule.exports !== undefined && //Make sure it is not already the exports value cjsModule.exports !== defined[fullName]) { ret = defined[fullName] = manager.cjsModule.exports; } else if (ret === undefined && manager.usingExports) { //exports already set the defined value. ret = defined[fullName]; } else { //Use the return value from the function. defined[fullName] = ret; //If this module needed full execution in a build //environment, mark that now. if (needFullExec[fullName]) { fullExec[fullName] = true; } } } } else if (fullName) { //May just be an object definition for the module. Only //worry about defining if have a module name. ret = defined[fullName] = cb; //If this module needed full execution in a build //environment, mark that now. if (needFullExec[fullName]) { fullExec[fullName] = true; } } //Clean up waiting. Do this before error calls, and before //calling back listeners, so that bookkeeping is correct //in the event of an error and error is reported in correct order, //since the listeners will likely have errors if the //onError function does not throw. if (waiting[manager.id]) { delete waiting[manager.id]; manager.isDone = true; context.waitCount -= 1; if (context.waitCount === 0) { //Clear the wait array used for cycles. waitAry = []; } } //Do not need to track manager callback now that it is defined. delete managerCallbacks[fullName]; //Allow instrumentation like the optimizer to know the order //of modules executed and their dependencies. if (req.onResourceLoad && !manager.placeholder) { req.onResourceLoad(context, map, manager.depArray); } if (err) { errFile = (fullName ? makeModuleMap(fullName).url : '') || err.fileName || err.sourceURL; errModuleTree = err.moduleTree; err = makeError('defineerror', 'Error evaluating ' + 'module "' + fullName + '" at location "' + errFile + '":\n' + err + '\nfileName:' + errFile + '\nlineNumber: ' + (err.lineNumber || err.line), err); err.moduleName = fullName; err.moduleTree = errModuleTree; return req.onError(err); } //Let listeners know of this manager's value. for (i = 0; (cb = listeners[i]); i++) { cb(ret); } return undefined; } /** * Helper that creates a callack function that is called when a dependency * is ready, and sets the i-th dependency for the manager as the * value passed to the callback generated by this function. */ function makeArgCallback(manager, i) { return function (value) { //Only do the work if it has not been done //already for a dependency. Cycle breaking //logic in forceExec could mean this function //is called more than once for a given dependency. if (!manager.depDone[i]) { manager.depDone[i] = true; manager.deps[i] = value; manager.depCount -= 1; if (!manager.depCount) { //All done, execute! execManager(manager); } } }; } function callPlugin(pluginName, depManager) { var map = depManager.map, fullName = map.fullName, name = map.name, plugin = plugins[pluginName] || (plugins[pluginName] = defined[pluginName]), load; //No need to continue if the manager is already //in the process of loading. if (depManager.loading) { return; } depManager.loading = true; load = function (ret) { depManager.callback = function () { return ret; }; execManager(depManager); loaded[depManager.id] = true; //The loading of this plugin //might have placed other things //in the paused queue. In particular, //a loader plugin that depends on //a different plugin loaded resource. resume(); }; //Allow plugins to load other code without having to know the //context or how to "complete" the load. load.fromText = function (moduleName, text) { /*jslint evil: true */ var hasInteractive = useInteractive; //Indicate a the module is in process of loading. loaded[moduleName] = false; context.scriptCount += 1; //Indicate this is not a "real" module, so do not track it //for builds, it does not map to a real file. context.fake[moduleName] = true; //Turn off interactive script matching for IE for any define //calls in the text, then turn it back on at the end. if (hasInteractive) { useInteractive = false; } req.exec(text); if (hasInteractive) { useInteractive = true; } //Support anonymous modules. context.completeLoad(moduleName); }; //No need to continue if the plugin value has already been //defined by a build. if (fullName in defined) { load(defined[fullName]); } else { //Use parentName here since the plugin's name is not reliable, //could be some weird string with no path that actually wants to //reference the parentName's path. plugin.load(name, makeRequire(map.parentMap, true, function (deps, cb) { var moduleDeps = [], i, dep, depMap; //Convert deps to full names and hold on to them //for reference later, when figuring out if they //are blocked by a circular dependency. for (i = 0; (dep = deps[i]); i++) { depMap = makeModuleMap(dep, map.parentMap); deps[i] = depMap.fullName; if (!depMap.prefix) { moduleDeps.push(deps[i]); } } depManager.moduleDeps = (depManager.moduleDeps || []).concat(moduleDeps); return context.require(deps, cb); }), load, config); } } /** * Adds the manager to the waiting queue. Only fully * resolved items should be in the waiting queue. */ function addWait(manager) { if (!waiting[manager.id]) { waiting[manager.id] = manager; waitAry.push(manager); context.waitCount += 1; } } /** * Function added to every manager object. Created out here * to avoid new function creation for each manager instance. */ function managerAdd(cb) { this.listeners.push(cb); } function getManager(map, shouldQueue) { var fullName = map.fullName, prefix = map.prefix, plugin = prefix ? plugins[prefix] || (plugins[prefix] = defined[prefix]) : null, manager, created, pluginManager, prefixMap; if (fullName) { manager = managerCallbacks[fullName]; } if (!manager) { created = true; manager = { //ID is just the full name, but if it is a plugin resource //for a plugin that has not been loaded, //then add an ID counter to it. id: (prefix && !plugin ? (managerCounter++) + '__p@:' : '') + (fullName || '__r@' + (managerCounter++)), map: map, depCount: 0, depDone: [], depCallbacks: [], deps: [], listeners: [], add: managerAdd }; specified[manager.id] = true; //Only track the manager/reuse it if this is a non-plugin //resource. Also only track plugin resources once //the plugin has been loaded, and so the fullName is the //true normalized value. if (fullName && (!prefix || plugins[prefix])) { managerCallbacks[fullName] = manager; } } //If there is a plugin needed, but it is not loaded, //first load the plugin, then continue on. if (prefix && !plugin) { prefixMap = makeModuleMap(prefix); //Clear out defined and urlFetched if the plugin was previously //loaded/defined, but not as full module (as in a build //situation). However, only do this work if the plugin is in //defined but does not have a module export value. if (prefix in defined && !defined[prefix]) { delete defined[prefix]; delete urlFetched[prefixMap.url]; } pluginManager = getManager(prefixMap, true); pluginManager.add(function (plugin) { //Create a new manager for the normalized //resource ID and have it call this manager when //done. var newMap = makeModuleMap(map.originalName, map.parentMap), normalizedManager = getManager(newMap, true); //Indicate this manager is a placeholder for the real, //normalized thing. Important for when trying to map //modules and dependencies, for instance, in a build. manager.placeholder = true; normalizedManager.add(function (resource) { manager.callback = function () { return resource; }; execManager(manager); }); }); } else if (created && shouldQueue) { //Indicate the resource is not loaded yet if it is to be //queued. loaded[manager.id] = false; queueDependency(manager); addWait(manager); } return manager; } function main(inName, depArray, callback, relModuleMap) { var moduleMap = makeModuleMap(inName, relModuleMap), name = moduleMap.name, fullName = moduleMap.fullName, manager = getManager(moduleMap), id = manager.id, deps = manager.deps, i, depArg, depName, depPrefix, cjsMod; if (fullName) { //If module already defined for context, or already loaded, //then leave. Also leave if jQuery is registering but it does //not match the desired version number in the config. if (fullName in defined || loaded[id] === true || (fullName === "jquery" && config.jQuery && config.jQuery !== callback().fn.jquery)) { return; } //Set specified/loaded here for modules that are also loaded //as part of a layer, where onScriptLoad is not fired //for those cases. Do this after the inline define and //dependency tracing is done. specified[id] = true; loaded[id] = true; //If module is jQuery set up delaying its dom ready listeners. if (fullName === "jquery" && callback) { jQueryCheck(callback()); } } //Attach real depArray and callback to the manager. Do this //only if the module has not been defined already, so do this after //the fullName checks above. IE can call main() more than once //for a module. manager.depArray = depArray; manager.callback = callback; //Add the dependencies to the deps field, and register for callbacks //on the dependencies. for (i = 0; i < depArray.length; i++) { depArg = depArray[i]; //There could be cases like in IE, where a trailing comma will //introduce a null dependency, so only treat a real dependency //value as a dependency. if (depArg) { //Split the dependency name into plugin and name parts depArg = makeModuleMap(depArg, (name ? moduleMap : relModuleMap)); depName = depArg.fullName; depPrefix = depArg.prefix; //Fix the name in depArray to be just the name, since //that is how it will be called back later. depArray[i] = depName; //Fast path CommonJS standard dependencies. if (depName === "require") { deps[i] = makeRequire(moduleMap); } else if (depName === "exports") { //CommonJS module spec 1.1 deps[i] = defined[fullName] = {}; manager.usingExports = true; } else if (depName === "module") { //CommonJS module spec 1.1 manager.cjsModule = cjsMod = deps[i] = { id: name, uri: name ? context.nameToUrl(name, null, relModuleMap) : undefined, exports: defined[fullName] }; } else if (depName in defined && !(depName in waiting) && (!(fullName in needFullExec) || (fullName in needFullExec && fullExec[depName]))) { //Module already defined, and not in a build situation //where the module is a something that needs full //execution and this dependency has not been fully //executed. See r.js's requirePatch.js for more info //on fullExec. deps[i] = defined[depName]; } else { //Mark this dependency as needing full exec if //the current module needs full exec. if (fullName in needFullExec) { needFullExec[depName] = true; //Reset state so fully executed code will get //picked up correctly. delete defined[depName]; urlFetched[depArg.url] = false; } //Either a resource that is not loaded yet, or a plugin //resource for either a plugin that has not //loaded yet. manager.depCount += 1; manager.depCallbacks[i] = makeArgCallback(manager, i); getManager(depArg, true).add(manager.depCallbacks[i]); } } } //Do not bother tracking the manager if it is all done. if (!manager.depCount) { //All done, execute! execManager(manager); } else { addWait(manager); } } /** * Convenience method to call main for a define call that was put on * hold in the defQueue. */ function callDefMain(args) { main.apply(null, args); } /** * jQuery 1.4.3+ supports ways to hold off calling * calling jQuery ready callbacks until all scripts are loaded. Be sure * to track it if the capability exists.. Also, since jQuery 1.4.3 does * not register as a module, need to do some global inference checking. * Even if it does register as a module, not guaranteed to be the precise * name of the global. If a jQuery is tracked for this context, then go * ahead and register it as a module too, if not already in process. */ jQueryCheck = function (jqCandidate) { if (!context.jQuery) { var $ = jqCandidate || (typeof jQuery !== "undefined" ? jQuery : null); if ($) { //If a specific version of jQuery is wanted, make sure to only //use this jQuery if it matches. if (config.jQuery && $.fn.jquery !== config.jQuery) { return; } if ("holdReady" in $ || "readyWait" in $) { context.jQuery = $; //Manually create a "jquery" module entry if not one already //or in process. Note this could trigger an attempt at //a second jQuery registration, but does no harm since //the first one wins, and it is the same value anyway. callDefMain(["jquery", [], function () { return jQuery; }]); //Ask jQuery to hold DOM ready callbacks. if (context.scriptCount) { jQueryHoldReady($, true); context.jQueryIncremented = true; } } } } }; function findCycle(manager, traced) { var fullName = manager.map.fullName, depArray = manager.depArray, fullyLoaded = true, i, depName, depManager, result; if (manager.isDone || !fullName || !loaded[fullName]) { return result; } //Found the cycle. if (traced[fullName]) { return manager; } traced[fullName] = true; //Trace through the dependencies. if (depArray) { for (i = 0; i < depArray.length; i++) { //Some array members may be null, like if a trailing comma //IE, so do the explicit [i] access and check if it has a value. depName = depArray[i]; if (!loaded[depName] && !reservedDependencies[depName]) { fullyLoaded = false; break; } depManager = waiting[depName]; if (depManager && !depManager.isDone && loaded[depName]) { result = findCycle(depManager, traced); if (result) { break; } } } if (!fullyLoaded) { //Discard the cycle that was found, since it cannot //be forced yet. Also clear this module from traced. result = undefined; delete traced[fullName]; } } return result; } function forceExec(manager, traced) { var fullName = manager.map.fullName, depArray = manager.depArray, i, depName, depManager, prefix, prefixManager, value; if (manager.isDone || !fullName || !loaded[fullName]) { return undefined; } if (fullName) { if (traced[fullName]) { return defined[fullName]; } traced[fullName] = true; } //Trace through the dependencies. if (depArray) { for (i = 0; i < depArray.length; i++) { //Some array members may be null, like if a trailing comma //IE, so do the explicit [i] access and check if it has a value. depName = depArray[i]; if (depName) { //First, make sure if it is a plugin resource that the //plugin is not blocked. prefix = makeModuleMap(depName).prefix; if (prefix && (prefixManager = waiting[prefix])) { forceExec(prefixManager, traced); } depManager = waiting[depName]; if (depManager && !depManager.isDone && loaded[depName]) { value = forceExec(depManager, traced); manager.depCallbacks[i](value); } } } } return defined[fullName]; } /** * Checks if all modules for a context are loaded, and if so, evaluates the * new ones in right dependency order. * * @private */ function checkLoaded() { var waitInterval = config.waitSeconds * 1000, //It is possible to disable the wait interval by using waitSeconds of 0. expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), noLoads = "", hasLoadedProp = false, stillLoading = false, cycleDeps = [], i, prop, err, manager, cycleManager, moduleDeps; //If there are items still in the paused queue processing wait. //This is particularly important in the sync case where each paused //item is processed right away but there may be more waiting. if (context.pausedCount > 0) { return undefined; } //Determine if priority loading is done. If so clear the priority. If //not, then do not check if (config.priorityWait) { if (isPriorityDone()) { //Call resume, since it could have //some waiting dependencies to trace. resume(); } else { return undefined; } } //See if anything is still in flight. for (prop in loaded) { if (!(prop in empty)) { hasLoadedProp = true; if (!loaded[prop]) { if (expired) { noLoads += prop + " "; } else { stillLoading = true; if (prop.indexOf('!') === -1) { //No reason to keep looking for unfinished //loading. If the only stillLoading is a //plugin resource though, keep going, //because it may be that a plugin resource //is waiting on a non-plugin cycle. cycleDeps = []; break; } else { moduleDeps = managerCallbacks[prop] && managerCallbacks[prop].moduleDeps; if (moduleDeps) { cycleDeps.push.apply(cycleDeps, moduleDeps); } } } } } } //Check for exit conditions. if (!hasLoadedProp && !context.waitCount) { //If the loaded object had no items, then the rest of //the work below does not need to be done. return undefined; } if (expired && noLoads) { //If wait time expired, throw error of unloaded modules. err = makeError("timeout", "Load timeout for modules: " + noLoads); err.requireType = "timeout"; err.requireModules = noLoads; err.contextName = context.contextName; return req.onError(err); } //If still loading but a plugin is waiting on a regular module cycle //break the cycle. if (stillLoading && cycleDeps.length) { for (i = 0; (manager = waiting[cycleDeps[i]]); i++) { if ((cycleManager = findCycle(manager, {}))) { forceExec(cycleManager, {}); break; } } } //If still waiting on loads, and the waiting load is something //other than a plugin resource, or there are still outstanding //scripts, then just try back later. if (!expired && (stillLoading || context.scriptCount)) { //Something is still waiting to load. Wait for it, but only //if a timeout is not already in effect. if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { checkLoadedTimeoutId = setTimeout(function () { checkLoadedTimeoutId = 0; checkLoaded(); }, 50); } return undefined; } //If still have items in the waiting cue, but all modules have //been loaded, then it means there are some circular dependencies //that need to be broken. //However, as a waiting thing is fired, then it can add items to //the waiting cue, and those items should not be fired yet, so //make sure to redo the checkLoaded call after breaking a single //cycle, if nothing else loaded then this logic will pick it up //again. if (context.waitCount) { //Cycle through the waitAry, and call items in sequence. for (i = 0; (manager = waitAry[i]); i++) { forceExec(manager, {}); } //If anything got placed in the paused queue, run it down. if (context.paused.length) { resume(); } //Only allow this recursion to a certain depth. Only //triggered by errors in calling a module in which its //modules waiting on it cannot finish loading, or some circular //dependencies that then may add more dependencies. //The value of 5 is a bit arbitrary. Hopefully just one extra //pass, or two for the case of circular dependencies generating //more work that gets resolved in the sync node case. if (checkLoadedDepth < 5) { checkLoadedDepth += 1; checkLoaded(); } } checkLoadedDepth = 0; //Check for DOM ready, and nothing is waiting across contexts. req.checkReadyState(); return undefined; } /** * Resumes tracing of dependencies and then checks if everything is loaded. */ resume = function () { var manager, map, url, i, p, args, fullName; //Any defined modules in the global queue, intake them now. context.takeGlobalQueue(); resumeDepth += 1; if (context.scriptCount <= 0) { //Synchronous envs will push the number below zero with the //decrement above, be sure to set it back to zero for good measure. //require() calls that also do not end up loading scripts could //push the number negative too. context.scriptCount = 0; } //Make sure any remaining defQueue items get properly processed. while (defQueue.length) { args = defQueue.shift(); if (args[0] === null) { return req.onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); } else { callDefMain(args); } } //Skip the resume of paused dependencies //if current context is in priority wait. if (!config.priorityWait || isPriorityDone()) { while (context.paused.length) { p = context.paused; context.pausedCount += p.length; //Reset paused list context.paused = []; for (i = 0; (manager = p[i]); i++) { map = manager.map; url = map.url;