/** @license MIT License (c) copyright B Cavalier & J Hann */ /** * curl (cujo resource loader) * An AMD-compliant javascript module and resource loader * * curl is part of the cujo.js family of libraries (http://cujojs.com/) * * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @version 0.6.2 */ (function (global) { var version = '0.6.2', userCfg = global['curl'], doc = global.document, head = doc && (doc['head'] || doc.getElementsByTagName('head')[0]), // // constants / flags msgUsingExports = {}, msgFactoryExecuted = {}, interactive = {}, // this is the list of scripts that IE is loading. one of these will // be the "interactive" script. too bad IE doesn't send a readystatechange // event to tell us exactly which one. activeScripts = {}, // these are always handy :) cleanPrototype = {}, toString = cleanPrototype.toString, undef, // script ready states that signify it's loaded readyStates = { 'loaded': 1, 'interactive': interactive, 'complete': 1 }, // local cache of resource definitions (lightweight promises) cache = {}, // preload are files that must be loaded before any others preload = false, // net to catch anonymous define calls' arguments (non-IE browsers) argsNet, // RegExp's used later, "cached" here dontAddExtRx = /\?/, absUrlRx = /^\/|^[^:]+:\/\//, findLeadingDotsRx = /(?:^|\/)(\.)(\.?)\/?/g, removeCommentsRx = /\/\*[\s\S]*?\*\/|(?:[^\\])\/\/.*?[\n\r]/g, findRValueRequiresRx = /require\s*\(\s*["']([^"']+)["']\s*\)|(?:[^\\]?)(["'])/g, cjsGetters, core; function noop () {} function isType (obj, type) { return toString.call(obj).indexOf('[object ' + type) == 0; } function normalizePkgDescriptor (descriptor) { var path, main; path = descriptor.path = removeEndSlash(descriptor['path'] || descriptor['location'] || ''); main = descriptor['main'] || 'main'; descriptor.config = descriptor['config']; // Omly update if first iteration if ( descriptor.main.indexOf('/') == -1 ) { descriptor.main = main.charAt(0) == '.' ? removeEndSlash(reduceLeadingDots(main, path)) : joinPath(path, main); } return descriptor; } function joinPath (path, file) { return removeEndSlash(path) + '/' + file; } function removeEndSlash (path) { return path && path.charAt(path.length - 1) == '/' ? path.substr(0, path.length - 1) : path; } function reduceLeadingDots (childId, baseId) { // this algorithm is similar to dojo's compactPath, which interprets // module ids of "." and ".." as meaning "grab the module whose name is // the same as my folder or parent folder". These special module ids // are not included in the AMD spec. var levels, removeLevels, isRelative; removeLevels = 1; childId = childId.replace(findLeadingDotsRx, function (m, dot, doubleDot) { if (doubleDot) removeLevels++; isRelative = true; return ''; }); // TODO: throw if removeLevels > baseId levels in debug module if (isRelative) { levels = baseId.split('/'); levels.splice(levels.length - removeLevels, removeLevels); // childId || [] is a trick to not concat if no childId return levels.concat(childId || []).join('/'); } else { return childId; } } function pluginParts (id) { var delPos = id.indexOf('!'); return { resourceId: id.substr(delPos + 1), // resourceId can be zero length pluginId: delPos >= 0 && id.substr(0, delPos) }; } function Begetter () {} function beget (parent) { Begetter.prototype = parent; var child = new Begetter(); Begetter.prototype = cleanPrototype; return child; } function Promise () { var self, thens, complete; self = this; thens = []; function then (resolved, rejected, progressed) { // capture calls to callbacks thens.push([resolved, rejected, progressed]); } function notify (which, arg) { // complete all callbacks var aThen, cb, i = 0; while ((aThen = thens[i++])) { cb = aThen[which]; if (cb) cb(arg); } } complete = function promiseComplete (success, arg) { // switch over to sync then() then = success ? function (resolved, rejected) { resolved && resolved(arg); } : function (resolved, rejected) { rejected && rejected(arg); }; // we no longer throw during multiple calls to resolve or reject // since we don't really provide useful information anyways. complete = noop; // complete all callbacks notify(success ? 0 : 1, arg); // no more notifications notify = noop; // release memory thens = undef; }; this.then = function (resolved, rejected, progressed) { then(resolved, rejected, progressed); return self; }; this.resolve = function (val) { self.resolved = val; complete(true, val); }; this.reject = function (ex) { self.rejected = ex; complete(false, ex); }; this.progress = function (msg) { notify(2, msg); } } function isPromise (o) { return o instanceof Promise; } function when (promiseOrValue, callback, errback, progback) { // we can't just sniff for then(). if we do, resources that have a // then() method will make dependencies wait! if (isPromise(promiseOrValue)) { return promiseOrValue.then(callback, errback, progback); } else { return callback(promiseOrValue); } } /** * Returns a function that when executed, executes a lambda function, * but only executes it the number of times stated by howMany. * When done executing, it executes the completed function. Each callback * function receives the same parameters that are supplied to the * returned function each time it executes. In other words, they * are passed through. * @private * @param howMany {Number} must be greater than zero * @param lambda {Function} executed each time * @param completed {Function} only executes once when the counter * reaches zero * @returns {Function} */ function countdown (howMany, lambda, completed) { return function () { var result; if (--howMany >= 0 && lambda) result = lambda.apply(undef, arguments); // we want ==, not <=, since some callers expect call-once functionality if (howMany == 0 && completed) completed(result); return result; } } core = { createContext: function (cfg, baseId, depNames, isPreload) { var def; def = new Promise(); def.ctxId = def.id = baseId || ''; // '' == global def.isPreload = isPreload; def.depNames = depNames; // functions that dependencies will use: function toAbsId (childId) { return reduceLeadingDots(childId, def.ctxId); } function toUrl (n) { // even though internally, we don't seem to need to do // toAbsId, the AMD spec says we need to do this for plugins. // also, thesec states that we should not append an extension // in this function. return core.resolvePathInfo(toAbsId(n), cfg).url; } function localRequire (ids, callback) { var cb, rvid, childDef, earlyExport; // this is public, so send pure function // also fixes issue #41 cb = callback && function () { callback.apply(undef, arguments[0]); }; // RValue require (CommonJS) if (isType(ids, 'String')) { // return resource rvid = toAbsId(ids); childDef = cache[rvid]; earlyExport = isPromise(childDef) && childDef.exports; if (!(rvid in cache)) { // this should only happen when devs attempt their own // manual wrapping of cjs modules or get confused with // the callback syntax: throw new Error('Module not resolved: ' + rvid); } if (cb) { throw new Error('require(id, callback) not allowed'); } return earlyExport || childDef; } else { // use same id so that relative modules are normalized correctly when(core.getDeps(core.createContext(cfg, def.id, ids)), cb); } } def.require = localRequire; localRequire['toUrl'] = toUrl; def.toAbsId = toAbsId; return def; }, createResourceDef: function (cfg, id, isPreload, optCtxId) { var def, origResolve, execute, resolvedValue; def = core.createContext(cfg, id, undef, isPreload); def.ctxId = optCtxId == undef ? id : optCtxId; origResolve = def.resolve; execute = countdown(1, function (deps) { def.deps = deps; try { resolvedValue = core.executeDefFunc(def); } catch (ex) { def.reject(ex); } }); // definition function by overriding promise resolve function def.resolve = function resolve (deps) { execute(deps); // put resolvedValue in cache cache[def.id] = resolvedValue; origResolve(resolvedValue); }; // track exports def.exportsReady = function executeFactory (deps) { // only resolve early if we also use exports (to avoid // circular dependencies). def.exports will have already // been set by the getDeps loop before we get here. if (def.exports) { execute(deps); def.progress(msgFactoryExecuted); } }; return def; }, createPluginDef: function (cfg, id, isPreload, ctxId) { var def; def = core.createContext(cfg, id, undef, isPreload); def.ctxId = ctxId; return def; }, getCjsRequire: function (def) { return def.require; }, getCjsExports: function (def) { return def.exports || (def.exports = {}); }, getCjsModule: function (def) { var module = def.module; if (!module) { module = def.module = { 'id': def.id, 'uri': core.getDefUrl(def), 'exports': core.getCjsExports(def) }; module.exports = module['exports']; // oh closure compiler! } return module; }, getDefUrl: function (def) { // note: don't look up an anon module's id from it's own toUrl cuz // the parent's config was used to find this module // the toUrl fallback is for named modules in built files // which must have absolute ids. return def.url || (def.url = core.checkToAddJsExt(def.require['toUrl'](def.id))); }, extractCfg: function (cfg) { var pluginCfgs; // set defaults and convert from closure-safe names cfg.baseUrl = cfg['baseUrl'] || ''; cfg.pluginPath = 'pluginPath' in cfg ? cfg['pluginPath'] : 'curl/plugin'; // create object to hold path map. // each plugin and package will have its own pathMap, too. cfg.pathMap = {}; pluginCfgs = cfg.plugins = cfg['plugins'] || {}; // temporary arrays of paths. this will be converted to // a regexp for fast path parsing. cfg.pathList = []; // normalizes path/package info and places info on either // the global cfg.pathMap or on a plugin-specific altCfg.pathMap. // also populates a pathList on cfg or plugin configs. function fixAndPushPaths (coll, isPkg) { var id, pluginId, data, parts, pluginCfg, info; for (var name in coll) { data = coll[name]; pluginCfg = cfg; // grab the package id, if specified. default to // property name. parts = pluginParts(removeEndSlash(data['id'] || data['name'] || name)); id = parts.resourceId; pluginId = parts.pluginId; if (pluginId) { // plugin-specific path pluginCfg = pluginCfgs[pluginId]; if (!pluginCfg) { pluginCfg = pluginCfgs[pluginId] = beget(cfg); pluginCfg.pathMap = beget(cfg.pathMap); pluginCfg.pathList = []; } // remove plugin-specific path from coll delete coll[name]; } if (isPkg) { info = normalizePkgDescriptor(data); } else { info = { path: removeEndSlash(data) }; } info.specificity = id.split('/').length; // info.specificity = (id.match(findSlashRx) || []).length; //console.log('[cujo] id|info : ' + id, info); //console.log('[cujo] pluginCfg : ', pluginCfg); if (id) { pluginCfg.pathMap[id] = info; pluginCfg.pathList.push(id); } else { // naked plugin name signifies baseUrl for plugin // resources. baseUrl could be relative to global // baseUrl. pluginCfg.baseUrl = core.resolveUrl(data, cfg); } } } // adds the path matching regexp onto the cfg or plugin cfgs. function convertPathMatcher (cfg) { var pathMap = cfg.pathMap; cfg.pathRx = new RegExp('^(' + cfg.pathList.sort(function (a, b) { return pathMap[a].specificity < pathMap[b].specificity; } ) .join('|') .replace(/\//g, '\\/') + ')(?=\\/|$)' ); delete cfg.pathList; } // fix all paths and packages fixAndPushPaths(cfg['paths'], false); fixAndPushPaths(cfg['packages'], true); // create search regex for each path map for (var p in pluginCfgs) { var pathList = pluginCfgs[p].pathList; if (pathList) { pluginCfgs[p].pathList = pathList.concat(cfg.pathList); convertPathMatcher(pluginCfgs[p]); } } convertPathMatcher(cfg); return cfg; }, checkPreloads: function (cfg) { var preloads; preloads = cfg['preloads']; if (preloads && preloads.length > 0) { // chain from previous preload, if any. // TODO: revisit when doing package-specific configs. when(preload, function () { preload = core.getDeps(core.createContext(cfg, undef, preloads, true)); }); } }, resolvePathInfo: function (id, cfg, forPlugin) { // searches through the configured path mappings and packages var pathMap, pathInfo, path, pkgCfg, found; pathMap = cfg.pathMap; if (forPlugin && cfg.pluginPath && id.indexOf('/') < 0 && !(id in pathMap)) { // prepend plugin folder path, if it's missing and path isn't in pathMap // Note: this munges the concepts of ids and paths for plugins, // but is generally safe since it's only for non-namespaced // plugins (plugins without path or package info). id = joinPath(cfg.pluginPath, id); } if (!absUrlRx.test(id)) { path = id.replace(cfg.pathRx, function (match) { pathInfo = pathMap[match] || {}; found = true; pkgCfg = pathInfo.config; // if pathInfo.main and match == id, this is a main module if (pathInfo.main && match == id) { return pathInfo.main; } // if pathInfo.path return pathInfo.path else { return pathInfo.path || ''; } }); } else { path = id; } return { path: path, config: pkgCfg || userCfg, url: core.resolveUrl(path, cfg) }; }, resolveUrl: function (path, cfg) { var baseUrl = cfg.baseUrl; return baseUrl && !absUrlRx.test(path) ? joinPath(baseUrl, path) : path; }, checkToAddJsExt: function (url) { // don't add extension if a ? is found in the url (query params) // i'd like to move this feature to a moduleLoader return url + /*(dontAddExtRx.test(url) ? '' :*/ '.js';//); }, loadScript: function (def, success, failure) { // script processing rules learned from RequireJS // insert script var el = doc.createElement('script'); // initial script processing function process (ev) { ev = ev || global.event; // detect when it's done loading if (ev.type == 'load' || readyStates[el.readyState]) { delete activeScripts[def.id]; // release event listeners el.onload = el.onreadystatechange = el.onerror = ''; // ie cries if we use undefined success(); } } function fail (e) { // some browsers send an event, others send a string, // but none of them send anything useful, so just say we failed: failure(new Error('Syntax or http error: ' + def.url)); } // set type first since setting other properties could // prevent us from setting this later // actually, we don't even need to set this at all //el.type = 'text/javascript'; // using dom0 event handlers instead of wordy w3c/ms el.onload = el.onreadystatechange = process; el.onerror = fail; // TODO: support other charsets? el.charset = 'utf-8'; el.async = true; el.src = def.url; // loading will start when the script is inserted into the dom. // IE will load the script sync if it's in the cache, so // indicate the current resource definition if this happens. activeScripts[def.id] = el; // use insertBefore to keep IE from throwing Operation Aborted (thx Bryan Forbes!) head.insertBefore(el, head.firstChild); }, extractCjsDeps: function (defFunc) { // Note: ignores require() inside strings and comments var source, ids = [], currQuote; // prefer toSource (FF) since it strips comments source = typeof defFunc == 'string' ? defFunc : defFunc.toSource ? defFunc.toSource() : defFunc.toString(); // remove comments, then look for require() or quotes source.replace(removeCommentsRx, '').replace(findRValueRequiresRx, function (m, id, qq) { // if we encounter a quote if (qq) { currQuote = currQuote == qq ? undef : currQuote; } // if we're not inside a quoted string else if (!currQuote) { ids.push(id); } return m; // uses least RAM/CPU }); return ids; }, fixArgs: function (args) { // resolve args // valid combinations for define: // (string, array, object|function) sax|saf // (array, object|function) ax|af // (string, object|function) sx|sf // (object|function) x|f var id, deps, defFunc, defFuncArity, len, cjs; len = args.length; defFunc = args[len - 1]; defFuncArity = isType(defFunc, 'Function') ? defFunc.length : -1; if (len == 2) { if (isType(args[0], 'Array')) { deps = args[0]; } else { id = args[0]; } } else if (len == 3) { id = args[0]; deps = args[1]; } // Hybrid format: assume that a definition function with zero // dependencies and non-zero arity is a wrapped CommonJS module if (!deps && defFuncArity > 0) { cjs = true; deps = ['require', 'exports', 'module'].slice(0, defFuncArity).concat(core.extractCjsDeps(defFunc)); } return { id: id, deps: deps || [], res: defFuncArity >= 0 ? defFunc : function () { return defFunc; }, cjs: cjs }; }, executeDefFunc: function (def) { var resource, moduleThis; // the force of AMD is strong so anything returned // overrides exports. // node.js assumes `this` === `exports` so we do that // for all cjs-wrapped modules, just in case. // also, use module.exports if that was set // (node.js convention). // note: if .module exists, .exports exists. moduleThis = def.cjs ? def.exports : undef; resource = def.res.apply(moduleThis, def.deps); if (resource === undef && def.exports) { // note: exports will equal module.exports unless // module.exports was reassigned inside module. resource = def.module ? (def.exports = def.module.exports) : def.exports; } return resource; }, defineResource: function (def, args) { // wait for preload before fetching any other modules when(def.isPreload || preload, function () { def.res = args.res; def.cjs = args.cjs; def.depNames = args.deps; core.getDeps(def); }); }, getDeps: function (parentDef) { var i, names, deps, len, dep, completed, name, exportCollector, resolveCollector; deps = []; names = parentDef.depNames; len = names.length; if (names.length == 0) allResolved(); function collect (dep, index, alsoExport) { deps[index] = dep; if (alsoExport) exportCollector(dep, index); } // reducer-collectors exportCollector = countdown(len, collect, allExportsReady); resolveCollector = countdown(len, collect, allResolved); // initiate the resolution of all dependencies // Note: the correct handling of early exports relies on the // fact that the exports pseudo-dependency is always listed // before other module dependencies. for (i = 0; i < len; i++) { name = names[i]; // is this "require", "exports", or "module"? if (name in cjsGetters) { // a side-effect of cjsGetters is that the cjs // property is also set on the def. resolveCollector(cjsGetters[name](parentDef), i, true); // if we are using the `module` or `exports` cjs variables, // signal any waiters/parents that we can export // early (see progress callback in getDep below). // note: this may fire for `require` as well, if it // is listed after `module` or `exports` in teh deps list, // but that is okay since all waiters will only record // it once. if (parentDef.exports) { parentDef.progress(msgUsingExports); } } // check for blanks. fixes #32. // this helps support yepnope.js, has.js, and the has! plugin else if (!name) { resolveCollector(undef, i, true); } // normal module or plugin resource else { getDep(name, i); } } return parentDef; function getDep (name, index) { var resolveOnce, exportOnce, childDef, earlyExport; resolveOnce = countdown(1, function (dep) { exportOnce(dep); resolveCollector(dep, index); }); exportOnce = countdown(1, function (dep) { exportCollector(dep, index); }); // get child def / dep childDef = core.fetchDep(name, parentDef); // check if childDef can export. if it can, then // we missed the notification and it will never fire in the // when() below. earlyExport = isPromise(childDef) && childDef.exports; if (earlyExport) { exportOnce(earlyExport); } when(childDef, resolveOnce, parentDef.reject, parentDef.exports && function (msg) { // messages are only sent from childDefs that support // exports, and we only notify parents that understand // exports too. if (childDef.exports) { if (msg == msgUsingExports) { // if we're using exports cjs variable on both sides exportOnce(childDef.exports); } else if (msg == msgFactoryExecuted) { resolveOnce(childDef.exports); } } } ); } function allResolved () { parentDef.resolve(deps); } function allExportsReady () { parentDef.exportsReady && parentDef.exportsReady(deps); } }, fetchResDef: function (def) { // ensure url is computed core.getDefUrl(def); core.loadScript(def, function () { var args = argsNet; argsNet = undef; // reset it before we get deps // if our resource was not explicitly defined with an id (anonymous) // Note: if it did have an id, it will be resolved in the define() if (def.useNet !== false) { // if !args, nothing was added to the argsNet if (!args || args.ex) { def.reject(new Error(((args && args.ex) || 'define() missing or duplicated: url').replace('url', def.url))); } else { core.defineResource(def, args); } } }, def.reject ); return def; }, fetchDep: function (depName, parentDef) { var toAbsId, isPreload, parts, mainId, loaderId, pluginId, resId, pathInfo, def, tempDef, resCfg; toAbsId = parentDef.toAbsId; isPreload = parentDef.isPreload; // check for plugin loaderId parts = pluginParts(depName); // resId is not normalized since the plugin may need to do it resId = parts.resourceId; // get id of first resource to load (which could be a plugin) mainId = toAbsId(parts.pluginId || resId); pathInfo = core.resolvePathInfo(mainId, userCfg, !!parts.pluginId); // get custom module loader from package config if not a plugin // TODO: figure out how to make module loaders work with plugins if (parts.pluginId) { loaderId = mainId; } else { loaderId = pathInfo.config['moduleLoader']; if (loaderId) { // since we're not using toAbsId, transformers must be absolute resId = mainId; mainId = loaderId; pathInfo = core.resolvePathInfo(loaderId, userCfg); } } // find resource definition. ALWAYS check via (id in cache) b/c // falsey values could be in there. def = cache[mainId]; if (!(mainId in cache)) { def = cache[mainId] = core.createResourceDef(pathInfo.config, mainId, isPreload, !!parts.pluginId ? pathInfo.path : undef); def.url = core.checkToAddJsExt(pathInfo.url); core.fetchResDef(def); } // plugin or transformer if (mainId == loaderId) { // we need to use depName until plugin tells us normalized id. // if the plugin changes the id, we need to consolidate // def promises below. Note: exports objects will be different // between pre-normalized and post-normalized defs! does this matter? // don't put this resource def in the cache because if the // resId doesn't change, the check if this is a new // normalizedDef (below) will think it's already being loaded. tempDef = /*cache[depName] =*/ new Promise(); // note: this means moduleLoaders can store config info in the // plugins config, too. resCfg = userCfg.plugins[loaderId] || userCfg; // wait for plugin resource def when(def, function(plugin) { var normalizedDef, fullId, dynamic; dynamic = plugin['dynamic']; // check if plugin supports the normalize method if ('normalize' in plugin) { // dojo/has may return falsey values (0, actually) resId = plugin['normalize'](resId, toAbsId, resCfg) || ''; } else { resId = toAbsId(resId); } // use the full id (loaderId + id) to id plugin resources // so multiple plugins may each process the same resource // resId could be blank if the plugin doesn't require any (e.g. "domReady!") fullId = loaderId + '!' + resId; normalizedDef = cache[fullId]; // if this is our first time fetching this (normalized) def if (!(fullId in cache)) { // because we're using resId, plugins, such as wire!, // can use paths relative to the resource normalizedDef = core.createPluginDef(resCfg, fullId, isPreload, resId); // don't cache non-determinate "dynamic" resources (or non-existent resources) if (!dynamic) { cache[fullId] = normalizedDef; } // curl's plugins prefer to receive a deferred, // but to be compatible with AMD spec, we have to // piggy-back on the callback function parameter: var loaded = function (res) { normalizedDef.resolve(res); if (!dynamic) cache[fullId] = res; }; loaded['resolve'] = loaded; loaded['reject'] = normalizedDef.reject; // load the resource! plugin.load(resId, normalizedDef.require, loaded, resCfg); } // chain defs (resolve when plugin.load executes) if (tempDef != normalizedDef) { when(normalizedDef, tempDef.resolve, tempDef.reject, tempDef.progress); } }, tempDef.reject); } // return tempDef if this is a plugin-based resource return tempDef || def; }, getCurrentDefName: function () { // IE marks the currently executing thread as "interactive" // Note: Opera lies about which scripts are "interactive", so we // just have to test for it. Opera provides a true browser test, not // a UA sniff, thankfully. // learned this trick from James Burke's RequireJS var def; if (!isType(global.opera, 'Opera')) { for (var d in activeScripts) { if (readyStates[activeScripts[d].readyState] == interactive) { def = d; break; } } } return def; } }; // hook-up cjs free variable getters cjsGetters = {'require': core.getCjsRequire, 'exports': core.getCjsExports, 'module': core.getCjsModule}; function _curl (/* various */) { var args = [].slice.call(arguments); // extract config, if it's specified if (isType(args[0], 'Object')) { userCfg = core.extractCfg(args.shift()); core.checkPreloads(userCfg); } // thanks to Joop Ringelberg for helping troubleshoot the API function CurlApi (ids, callback, waitFor) { var then, ctx; ctx = core.createContext(userCfg, undef, [].concat(ids)); this['then'] = then = function (resolved, rejected) { when(ctx, // return the dependencies as arguments, not an array function (deps) { if (resolved) resolved.apply(undef, deps); }, // just throw if the dev didn't specify an error handler function (ex) { if (rejected) rejected(ex); else throw ex; } ); return this; }; this['next'] = function (ids, cb) { // chain api return new CurlApi(ids, cb, ctx); }; if (callback) then(callback); when(waitFor, function () { core.getDeps(ctx); }); } return new CurlApi(args[0], args[1]); } function _define (args) { var id = args.id; if (id == undef) { if (argsNet !== undef) { argsNet = {ex: 'Multiple anonymous defines in url'}; } else if (!(id = core.getCurrentDefName())/* intentional assignment */) { // anonymous define(), defer processing until after script loads argsNet = args; } } if (id != undef) { // named define(), it is in the cache if we are loading a dependency // (could also be a secondary define() appearing in a built file, etc.) var def = cache[id]; if (!(id in cache)) { // id is an absolute id in this case, so we can get the config. // there's no way to allow a named define to fetch dependencies // in the preload phase since we can't cascade the parent def. var cfg = core.resolvePathInfo(id, userCfg).config; def = cache[id] = core.createResourceDef(cfg, id); } // check if this resource has already been resolved (can happen if // a module was defined inside a built file and outside of it and // dev didn't coordinate it explicitly) if (isPromise(def)) { def.useNet = false; core.defineResource(def, args); } } } /***** grab any global configuration info *****/ // if userCfg is a function, assume curl() exists already if (isType(userCfg, 'Function')) return; userCfg = core.extractCfg(userCfg || {}); core.checkPreloads(userCfg); /***** define public API *****/ var apiName, apiContext, define; // allow curl to be renamed and added to a specified context apiName = userCfg['apiName'] || 'curl'; apiContext = userCfg['apiContext'] || global; apiContext[apiName] = _curl; // allow curl to be a dependency cache['curl'] = _curl; // wrap inner _define so it can be replaced without losing define.amd define = global['define'] = function () { var args = core.fixArgs(arguments); _define(args); }; _curl['version'] = version; // indicate our capabilities: define['amd'] = { 'plugins': true, 'jQuery': true, 'curl': version }; // expose curl core for special plugins and modules // Note: core overrides will only work in either of two scenarios: // 1. the files are running un-compressed (Google Closure or Uglify) // 2. the overriding module was compressed with curl.js // Compiling curl and the overriding module separately won't work. cache['curl/_privileged'] = { 'core': core, 'cache': cache, 'cfg': userCfg, '_define': _define, '_curl': _curl, 'Promise': Promise }; }(this));