diff --git a/demo/kitchen-sink/require.js b/demo/kitchen-sink/require.js index d016e1da..39dbad8e 100644 --- a/demo/kitchen-sink/require.js +++ b/demo/kitchen-sink/require.js @@ -1,21 +1,25 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.0.1 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.1 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 regexp: true, nomen: true */ +//Not using strict: uneven strict support in browsers, #392, and causes +//problems with requirejs.exec()/transpiler plugins that may not be strict. +/*jslint regexp: true, nomen: true, sloppy: true */ /*global window, navigator, document, importScripts, jQuery, setTimeout, opera */ var requirejs, require, define; (function (global) { - 'use strict'; - - var version = '2.0.1', + var req, s, head, baseElement, dataMain, src, + interactiveScript, currentlyAddingScript, mainScript, subPath, + version = '2.1.1', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, - cjsRequireRegExp = /require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, + cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, currDirRegExp = /^\.\//, - ostring = Object.prototype.toString, + op = Object.prototype, + ostring = op.toString, + hasOwn = op.hasOwnProperty, ap = Array.prototype, aps = ap.slice, apsp = ap.splice, @@ -33,9 +37,7 @@ var requirejs, require, define; contexts = {}, cfg = {}, globalDefQueue = [], - useInteractive = false, - req, s, head, baseElement, dataMain, src, - interactiveScript, currentlyAddingScript, mainScript, subPath; + useInteractive = false; function isFunction(it) { return ostring.call(it) === '[object Function]'; @@ -53,7 +55,7 @@ var requirejs, require, define; if (ary) { var i; for (i = 0; i < ary.length; i += 1) { - if (func(ary[i], i, ary)) { + if (ary[i] && func(ary[i], i, ary)) { break; } } @@ -68,7 +70,7 @@ var requirejs, require, define; if (ary) { var i; for (i = ary.length - 1; i > -1; i -= 1) { - if (func(ary[i], i, ary)) { + if (ary[i] && func(ary[i], i, ary)) { break; } } @@ -76,7 +78,7 @@ var requirejs, require, define; } function hasProp(obj, prop) { - return obj.hasOwnProperty(prop); + return hasOwn.call(obj, prop); } /** @@ -98,18 +100,23 @@ var requirejs, require, define; /** * 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) { + function mixin(target, source, force, deepStringMixin) { if (source) { eachProp(source, function (value, prop) { if (force || !hasProp(target, prop)) { - target[prop] = value; + if (deepStringMixin && typeof value !== 'string') { + if (!target[prop]) { + target[prop] = {}; + } + mixin(target[prop], value, force, deepStringMixin); + } else { + target[prop] = value; + } } }); } + return target; } //Similar to Function.prototype.bind, but the 'this' object is specified @@ -137,32 +144,6 @@ var requirejs, require, define; return g; } - function makeContextModuleFunc(func, relMap, 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(relMap); - return func.apply(null, args); - }; - } - - function addRequireMethods(req, context, relMap) { - each([ - ['toUrl'], - ['undef'], - ['defined', 'requireDefined'], - ['specified', 'requireSpecified'] - ], function (item) { - req[item[0]] = makeContextModuleFunc(context[item[1] || item[0]], relMap); - }); - } - /** * 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. @@ -204,28 +185,24 @@ var requirejs, require, define; } function newContext(contextName) { - var config = { + var inCheckLoaded, Module, context, handlers, + checkLoadedTimeoutId, + config = { waitSeconds: 7, baseUrl: './', paths: {}, pkgs: {}, - shim: {} + shim: {}, + map: {}, + config: {} }, registry = {}, undefEvents = {}, defQueue = [], defined = {}, - urlMap = {}, urlFetched = {}, requireCounter = 1, - unnormalizedCounter = 1, - //Used to track the order in which modules - //should be executed, by the order they - //load. Important for consistent cycle resolution - //behavior. - waitAry = [], - inCheckLoaded, Module, context, handlers, - checkLoadedTimeoutId; + unnormalizedCounter = 1; /** * Trims the . and .. from an array of path segments. @@ -238,7 +215,7 @@ var requirejs, require, define; */ function trimDots(ary) { var i, part; - for (i = 0; ary[i]; i+= 1) { + for (i = 0; ary[i]; i += 1) { part = ary[i]; if (part === '.') { ary.splice(i, 1); @@ -271,11 +248,12 @@ var requirejs, require, define; * @returns {String} normalized name */ function normalize(name, baseName, applyMap) { - var baseParts = baseName && baseName.split('/'), + var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment, + foundMap, foundI, foundStarMap, starI, + baseParts = baseName && baseName.split('/'), + normalizedBaseParts = baseParts, map = config.map, - starMap = map && map['*'], - pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment, - foundMap; + starMap = map && map['*']; //Adjust any relative paths. if (name && name.charAt(0) === '.') { @@ -286,17 +264,17 @@ var requirejs, require, define; if (config.pkgs[baseName]) { //If the baseName is a package name, then just treat it as one //name to concat the name with. - baseParts = [baseName]; + normalizedBaseParts = baseParts = [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. - baseParts = baseParts.slice(0, baseParts.length - 1); + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); } - name = baseParts.concat(name.split('/')); + name = normalizedBaseParts.concat(name.split('/')); trimDots(name); //Some use of packages may use a . path to reference the @@ -326,28 +304,41 @@ var requirejs, require, define; for (j = baseParts.length; j > 0; j -= 1) { mapValue = map[baseParts.slice(0, j).join('/')]; - //baseName segment has config, find if it has one for + //baseName segment has config, find if it has one for //this name. if (mapValue) { mapValue = mapValue[nameSegment]; if (mapValue) { //Match, update name to the new value. foundMap = mapValue; + foundI = i; break; } } } } - if (!foundMap && starMap && starMap[nameSegment]) { - foundMap = starMap[nameSegment]; - } - if (foundMap) { - nameParts.splice(0, i, foundMap); - name = nameParts.join('/'); break; } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && starMap[nameSegment]) { + foundStarMap = starMap[nameSegment]; + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); } } @@ -358,7 +349,7 @@ var requirejs, require, define; if (isBrowser) { each(scripts(), function (scriptNode) { if (scriptNode.getAttribute('data-requiremodule') === name && - scriptNode.getAttribute('data-requirecontext') === context.contextName) { + scriptNode.getAttribute('data-requirecontext') === context.contextName) { scriptNode.parentNode.removeChild(scriptNode); return true; } @@ -373,12 +364,25 @@ var requirejs, require, define; //Pop off the first array value, since it failed, and //retry pathConfig.shift(); - context.undef(id); + context.require.undef(id); context.require([id]); return true; } } + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + /** * Creates a module mapping that includes plugin prefix, module * name, and path. If parentModuleMap is provided it will @@ -395,13 +399,12 @@ var requirejs, require, define; * @returns {Object} */ function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { - var index = name ? name.indexOf('!') : -1, + var url, pluginModule, suffix, nameParts, prefix = null, parentName = parentModuleMap ? parentModuleMap.name : null, originalName = name, isDefine = true, - normalizedName = '', - url, pluginModule, suffix; + normalizedName = ''; //If no name, then it means it is a require call, generate an //internal name. @@ -410,10 +413,9 @@ var requirejs, require, define; name = '_@r' + (requireCounter += 1); } - if (index !== -1) { - prefix = name.substring(0, index); - name = name.substring(index + 1, name.length); - } + nameParts = splitPrefix(name); + prefix = nameParts[0]; + name = nameParts[1]; if (prefix) { prefix = normalize(prefix, parentName, applyMap); @@ -435,22 +437,15 @@ var requirejs, require, define; //A regular module. normalizedName = normalize(name, parentName, applyMap); - 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); + //Normalized name may be a plugin ID due to map config + //application in normalize. The map config values must + //already be normalized, so do not need to redo that part. + nameParts = splitPrefix(normalizedName); + prefix = nameParts[0]; + normalizedName = nameParts[1]; + isNormalized = true; - //Store the URL mapping for later. - urlMap[normalizedName] = url; - } + url = context.nameToUrl(normalizedName); } } @@ -470,8 +465,8 @@ var requirejs, require, define; originalName: originalName, isDefine: isDefine, id: (prefix ? - prefix + '!' + normalizedName : - normalizedName) + suffix + prefix + '!' + normalizedName : + normalizedName) + suffix }; } @@ -491,7 +486,7 @@ var requirejs, require, define; mod = registry[id]; if (hasProp(defined, id) && - (!mod || mod.defineEmitComplete)) { + (!mod || mod.defineEmitComplete)) { if (name === 'defined') { fn(defined[id]); } @@ -541,163 +536,82 @@ var requirejs, require, define; } } - /** - * 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(mod, enableBuildCallback, altRequire) { - var relMap = mod && mod.map, - modRequire = makeContextModuleFunc(altRequire || context.require, - relMap, - enableBuildCallback); - - addRequireMethods(modRequire, context, relMap); - modRequire.isBrowser = isBrowser; - - return modRequire; - } - handlers = { 'require': function (mod) { - return makeRequire(mod); + if (mod.require) { + return mod.require; + } else { + return (mod.require = context.makeRequire(mod.map)); + } }, 'exports': function (mod) { mod.usingExports = true; if (mod.map.isDefine) { - return (mod.exports = defined[mod.map.id] = {}); + if (mod.exports) { + return mod.exports; + } else { + return (mod.exports = defined[mod.map.id] = {}); + } } }, 'module': function (mod) { - return (mod.module = { - id: mod.map.id, - uri: mod.map.url, - config: function () { - return (config.config && config.config[mod.map.id]) || {}; - }, - exports: defined[mod.map.id] - }); + if (mod.module) { + return mod.module; + } else { + return (mod.module = { + id: mod.map.id, + uri: mod.map.url, + config: function () { + return (config.config && config.config[mod.map.id]) || {}; + }, + exports: defined[mod.map.id] + }); + } } }; - function removeWaiting(id) { + function cleanRegistry(id) { //Clean up machinery used for waiting modules. delete registry[id]; - - each(waitAry, function (mod, i) { - if (mod.map.id === id) { - waitAry.splice(i, 1); - if (!mod.defined) { - context.waitCount -= 1; - } - return true; - } - }); } - function findCycle(mod, traced) { - var id = mod.map.id, - depArray = mod.depMaps, - foundModule; + function breakCycle(mod, traced, processed) { + var id = mod.map.id; - //Do not bother with unitialized modules or not yet enabled - //modules. - if (!mod.inited) { - return; - } + if (mod.error) { + mod.emit('error', mod.error); + } else { + traced[id] = true; + each(mod.depMaps, function (depMap, i) { + var depId = depMap.id, + dep = registry[depId]; - //Found the cycle. - if (traced[id]) { - return mod; - } - - traced[id] = true; - - //Trace through the dependencies. - each(depArray, function (depMap) { - var depId = depMap.id, - depMod = registry[depId]; - - if (!depMod) { - return; - } - - if (!depMod.inited || !depMod.enabled) { - //Dependency is not inited, so this cannot - //be used to determine a cycle. - foundModule = null; - delete traced[id]; - return true; - } - - return (foundModule = findCycle(depMod, traced)); - }); - - return foundModule; - } - - function forceExec(mod, traced, uninited) { - var id = mod.map.id, - depArray = mod.depMaps; - - if (!mod.inited || !mod.map.isDefine) { - return; - } - - if (traced[id]) { - return defined[id]; - } - - traced[id] = mod; - - each(depArray, function(depMap) { - var depId = depMap.id, - depMod = registry[depId], - value; - - if (handlers[depId]) { - return; - } - - if (depMod) { - if (!depMod.inited || !depMod.enabled) { - //Dependency is not inited, - //so this module cannot be - //given a forced value yet. - uninited[id] = true; - return; + //Only force things that have not completed + //being defined, so still in the registry, + //and only if it has not been matched up + //in the module already. + if (dep && !mod.depMatched[i] && !processed[depId]) { + if (traced[depId]) { + mod.defineDep(i, defined[depId]); + mod.check(); //pass false? + } else { + breakCycle(dep, traced, processed); + } } - - //Get the value for the current dependency - value = forceExec(depMod, traced, uninited); - - //Even with forcing it may not be done, - //in particular if the module is waiting - //on a plugin resource. - if (!uninited[depId]) { - mod.defineDepById(depId, value); - } - } - }); - - mod.check(true); - - return defined[id]; - } - - function modCheck(mod) { - mod.check(); + }); + processed[id] = true; + } } function checkLoaded() { - var waitInterval = config.waitSeconds * 1000, + var map, modId, err, usingPathFallback, + 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 = [], + reqCalls = [], stillLoading = false, - needCycleCheck = true, - map, modId, err, usingPathFallback; + needCycleCheck = true; //Do not bother if this call was a result of a cycle break. if (inCheckLoaded) { @@ -716,6 +630,10 @@ var requirejs, require, define; return; } + if (!map.isDefine) { + reqCalls.push(mod); + } + if (!mod.error) { //If the module should be executed, and it has not //been inited and time is up, remember it. @@ -750,31 +668,9 @@ var requirejs, require, define; //Not expired, check for a cycle. if (needCycleCheck) { - - each(waitAry, function (mod) { - if (mod.defined) { - return; - } - - var cycleMod = findCycle(mod, {}), - traced = {}; - - if (cycleMod) { - forceExec(cycleMod, traced, {}); - - //traced modules may have been - //removed from the registry, but - //their listeners still need to - //be called. - eachProp(traced, modCheck); - } + each(reqCalls, function (mod) { + breakCycle(mod, {}, {}); }); - - //Now that dependencies have - //been satisfied, trigger the - //completion check that then - //notifies listeners. - eachProp(registry, modCheck); } //If still waiting on loads, and the waiting load is something @@ -811,7 +707,7 @@ var requirejs, require, define; }; Module.prototype = { - init: function(depMaps, factory, errback, options) { + init: function (depMaps, factory, errback, options) { options = options || {}; //Do not do more inits if already done. Can happen if there @@ -834,33 +730,14 @@ var requirejs, require, define; }); } - each(depMaps, bind(this, function (depMap, i) { - if (typeof depMap === 'string') { - depMap = makeModuleMap(depMap, - (this.map.isDefine ? this.map : this.map.parentMap), - false, - true); - this.depMaps.push(depMap); - } + //Do a copy of the dependency array, so that + //source inputs are not modified. For example + //"shim" deps are passed in here directly, and + //doing a direct modification of the depMaps array + //would affect that config. + this.depMaps = depMaps && depMaps.slice(0); - var handler = handlers[depMap.id]; - - if (handler) { - this.depExports[i] = handler(this); - return; - } - - this.depCount += 1; - - on(depMap, 'defined', bind(this, function (depExports) { - this.defineDep(i, depExports); - this.check(); - })); - - if (errback) { - on(depMap, 'error', errback); - } - })); + this.errback = errback; //Indicate this module has be initialized this.inited = true; @@ -880,20 +757,6 @@ var requirejs, require, define; } }, - defineDepById: function (id, depExports) { - var i; - - //Find the index for this dependency. - each(this.depMaps, function (map, index) { - if (map.id === id) { - i = index; - return true; - } - }); - - return this.defineDep(i, depExports); - }, - defineDep: function (i, depExports) { //Because of cycles, defined callback for a given //export can be called more than once. @@ -916,19 +779,19 @@ var requirejs, require, define; //If the manager is for a plugin managed resource, //ask the plugin to load it now. - if (map.prefix) { - this.callPlugin(); - } else if (this.shim) { - makeRequire(this, true)(this.shim.deps || [], bind(this, function () { - this.load(); + if (this.shim) { + context.makeRequire(this.map, { + enableBuildCallback: true + })(this.shim.deps || [], bind(this, function () { + return map.prefix ? this.callPlugin() : this.load(); })); } else { //Regular dependency. - this.load(); + return map.prefix ? this.callPlugin() : this.load(); } }, - load: function() { + load: function () { var url = this.map.url; //Regular dependency. @@ -940,20 +803,18 @@ var requirejs, require, define; /** * Checks is the module is ready to define itself, and if so, - * define it. If the silent argument is true, then it will just - * define, but not notify listeners, and not ask for a context-wide - * check of all loaded modules. That is useful for cycle breaking. + * define it. */ - check: function (silent) { - if (!this.enabled) { + check: function () { + if (!this.enabled || this.enabling) { return; } - var id = this.map.id, + var err, cjsModule, + id = this.map.id, depExports = this.depExports, exports = this.exports, - factory = this.factory, - err, cjsModule; + factory = this.factory; if (!this.inited) { this.fetch(); @@ -986,9 +847,9 @@ var requirejs, require, define; //favor a non-undefined return value over exports use. cjsModule = this.module; if (cjsModule && - cjsModule.exports !== undefined && - //Make sure it is not already the exports value - cjsModule.exports !== this.exports) { + cjsModule.exports !== undefined && + //Make sure it is not already the exports value + cjsModule.exports !== this.exports) { exports = cjsModule.exports; } else if (exports === undefined && this.usingExports) { //exports already set the defined value. @@ -1022,11 +883,6 @@ var requirejs, require, define; delete registry[id]; this.defined = true; - context.waitCount -= 1; - if (context.waitCount === 0) { - //Clear the wait array used for cycles. - waitAry = []; - } } //Finished the define stage. Allow calling check again @@ -1034,25 +890,33 @@ var requirejs, require, define; //cycle. this.defining = false; - if (!silent) { - if (this.defined && !this.defineEmitted) { - this.defineEmitted = true; - this.emit('defined', this.exports); - this.defineEmitComplete = true; - } + if (this.defined && !this.defineEmitted) { + this.defineEmitted = true; + this.emit('defined', this.exports); + this.defineEmitComplete = true; } + } }, - callPlugin: function() { + callPlugin: function () { var map = this.map, id = map.id, - pluginMap = makeModuleMap(map.prefix, null, false, true); + //Map already normalized the prefix. + pluginMap = makeModuleMap(map.prefix); + + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(pluginMap); on(pluginMap, 'defined', bind(this, function (plugin) { - var name = this.map.name, + var load, normalizedMap, normalizedMod, + name = this.map.name, parentName = this.map.parentMap ? this.map.parentMap.name : null, - load, normalizedMap, normalizedMod; + localRequire = context.makeRequire(map.parentMap, { + enableBuildCallback: true, + skipMap: true + }); //If current map is not normalized, wait for that //normalized name to load instead of continuing. @@ -1064,16 +928,24 @@ var requirejs, require, define; }) || ''; } - normalizedMap = makeModuleMap(map.prefix + '!' + name); + //prefix and name should already be normalized, no need + //for applying map config again either. + normalizedMap = makeModuleMap(map.prefix + '!' + name, + this.map.parentMap); on(normalizedMap, - 'defined', bind(this, function (value) { - this.init([], function () { return value; }, null, { - enabled: true, - ignore: true - }); - })); + 'defined', bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true, + ignore: true + }); + })); + normalizedMod = registry[normalizedMap.id]; if (normalizedMod) { + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(normalizedMap); + if (this.events.error) { normalizedMod.on('error', bind(this, function (err) { this.emit('error', err); @@ -1100,7 +972,7 @@ var requirejs, require, define; //since they will never be resolved otherwise now. eachProp(registry, function (mod) { if (mod.map.id.indexOf(id + '_unnormalized') === 0) { - removeWaiting(mod.map.id); + cleanRegistry(mod.map.id); } }); @@ -1109,9 +981,19 @@ var requirejs, require, define; //Allow plugins to load other code without having to know the //context or how to 'complete' the load. - load.fromText = function (moduleName, text) { + load.fromText = bind(this, function (text, textAlt) { /*jslint evil: true */ - var hasInteractive = useInteractive; + var moduleName = map.name, + moduleMap = makeModuleMap(moduleName), + hasInteractive = useInteractive; + + //As of 2.1.0, support just passing the text, to reinforce + //fromText only being called once per resource. Still + //support old style of passing moduleName but discard + //that moduleName in favor of the internal ref. + if (textAlt) { + text = textAlt; + } //Turn off interactive script matching for IE for any define //calls in the text, then turn it back on at the end. @@ -1119,22 +1001,37 @@ var requirejs, require, define; useInteractive = false; } - req.exec(text); + //Prime the system by creating a module instance for + //it. + getModule(moduleMap); + + try { + req.exec(text); + } catch (e) { + throw new Error('fromText eval for ' + moduleName + + ' failed: ' + e); + } if (hasInteractive) { useInteractive = true; } + //Mark this as a dependency for the plugin + //resource + this.depMaps.push(moduleMap); + //Support anonymous modules. context.completeLoad(moduleName); - }; + + //Bind the value of that module to the value for this + //resource ID. + localRequire([moduleName], load); + }); //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(map.name, makeRequire(map.parentMap, true, function (deps, cb) { - return context.require(deps, cb); - }), load, config); + plugin.load(map.name, localRequire, load, config); })); context.enable(pluginMap, this); @@ -1144,21 +1041,52 @@ var requirejs, require, define; enable: function () { this.enabled = true; - if (!this.waitPushed) { - waitAry.push(this); - context.waitCount += 1; - this.waitPushed = true; - } + //Set flag mentioning that the module is enabling, + //so that immediate calls to the defined callbacks + //for dependencies do not trigger inadvertent load + //with the depCount still being zero. + this.enabling = true; //Enable each dependency - each(this.depMaps, bind(this, function (map) { - var id = map.id, - mod = registry[id]; + each(this.depMaps, bind(this, function (depMap, i) { + var id, mod, handler; + + if (typeof depMap === 'string') { + //Dependency needs to be converted to a depMap + //and wired up to this module. + depMap = makeModuleMap(depMap, + (this.map.isDefine ? this.map : this.map.parentMap), + false, + !this.skipMap); + this.depMaps[i] = depMap; + + handler = handlers[depMap.id]; + + if (handler) { + this.depExports[i] = handler(this); + return; + } + + this.depCount += 1; + + on(depMap, 'defined', bind(this, function (depExports) { + this.defineDep(i, depExports); + this.check(); + })); + + if (this.errback) { + on(depMap, 'error', this.errback); + } + } + + id = depMap.id; + mod = registry[id]; + //Skip special modules like 'require', 'exports', 'module' //Also, don't call enable if it is already enabled, //important in circular dependency cases. if (!handlers[id] && mod && !mod.enabled) { - context.enable(map, this); + context.enable(depMap, this); } })); @@ -1171,10 +1099,12 @@ var requirejs, require, define; } })); + this.enabling = false; + this.check(); }, - on: function(name, cb) { + on: function (name, cb) { var cbs = this.events[name]; if (!cbs) { cbs = this.events[name] = []; @@ -1189,7 +1119,7 @@ var requirejs, require, define; if (name === 'error') { //Now that the error handler was triggered, remove //the listeners, since this broken Module instance - //can stay around for a while in the registry/waitAry. + //can stay around for a while in the registry. delete this.events[name]; } } @@ -1236,17 +1166,35 @@ var requirejs, require, define; }; } - return (context = { + function intakeDefines() { + var args; + + //Any defined modules in the global queue, intake them now. + takeGlobalQueue(); + + //Make sure any remaining defQueue items get properly processed. + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); + } else { + //args are id, deps, factory. Should be normalized by the + //define() function. + callGetModule(args); + } + } + } + + context = { config: config, contextName: contextName, registry: registry, defined: defined, - urlMap: urlMap, urlFetched: urlFetched, - waitCount: 0, defQueue: defQueue, Module: Module, makeModuleMap: makeModuleMap, + nextTick: req.nextTick, /** * Set a configuration for the context. @@ -1262,24 +1210,25 @@ var requirejs, require, define; //Save off the paths and packages since they require special processing, //they are additive. - var paths = config.paths, - pkgs = config.pkgs, + var pkgs = config.pkgs, shim = config.shim, - map = config.map || {}; + objs = { + paths: true, + config: true, + map: true + }; - //Mix in the config values, favoring the new values over - //existing ones in context.config. - mixin(config, cfg, true); - - //Merge paths. - mixin(paths, cfg.paths, true); - config.paths = paths; - - //Merge map - if (cfg.map) { - mixin(map, cfg.map, true); - config.map = map; - } + eachProp(cfg, function (value, prop) { + if (objs[prop]) { + if (prop === 'map') { + mixin(config[prop], value, true, true); + } else { + mixin(config[prop], value, true); + } + } else { + config[prop] = value; + } + }); //Merge shim if (cfg.shim) { @@ -1290,8 +1239,8 @@ var requirejs, require, define; deps: value }; } - if (value.exports && !value.exports.__buildReady) { - value.exports = context.makeShimExports(value.exports); + if (value.exports && !value.exportsFn) { + value.exportsFn = context.makeShimExports(value); } shim[id] = value; }); @@ -1326,6 +1275,18 @@ var requirejs, require, define; config.pkgs = pkgs; } + //If there are any "waiting to execute" modules in the registry, + //update the maps for them, since their info, like URLs to load, + //may have changed. + eachProp(registry, function (mod, id) { + //If module already has init called, since it is too + //late to modify them, and ignore unnormalized ones + //since they are transient. + if (!mod.inited && !mod.map.unnormalized) { + mod.map = makeModuleMap(id); + } + }); + //If a deps array or a config callback is specified, then call //require with those args. This is useful when require is defined as a //config object before require.js is loaded. @@ -1334,122 +1295,144 @@ var requirejs, require, define; } }, - makeShimExports: function (exports) { - var func; - if (typeof exports === 'string') { - func = function () { - return getGlobal(exports); - }; - //Save the exports for use in nodefine checking. - func.exports = exports; - return func; - } else { - return function () { - return exports.apply(global, arguments); - }; + makeShimExports: function (value) { + function fn() { + var ret; + if (value.init) { + ret = value.init.apply(global, arguments); + } + return ret || getGlobal(value.exports); } + return fn; }, - requireDefined: function (id, relMap) { - return hasProp(defined, makeModuleMap(id, relMap, false, true).id); - }, + makeRequire: function (relMap, options) { + options = options || {}; - requireSpecified: function (id, relMap) { - id = makeModuleMap(id, relMap, false, true).id; - return hasProp(defined, id) || hasProp(registry, id); - }, + function localRequire(deps, callback, errback) { + var id, map, requireMod; - require: function (deps, callback, errback, relMap) { - var moduleName, id, map, requireMod, args; - if (typeof deps === 'string') { - if (isFunction(callback)) { - //Invalid call - return onError(makeError('requireargs', 'Invalid require call'), errback); + if (options.enableBuildCallback && callback && isFunction(callback)) { + callback.__requireJsBuild = true; } - //Synchronous access to one module. If require.get is - //available (as in the Node adapter), prefer that. - //In this case deps is the moduleName and callback is - //the relMap - if (req.get) { - return req.get(context, deps, callback); + if (typeof deps === 'string') { + if (isFunction(callback)) { + //Invalid call + return onError(makeError('requireargs', 'Invalid require call'), errback); + } + + //If require|exports|module are requested, get the + //value for them from the special handlers. Caveat: + //this only works while module is being defined. + if (relMap && handlers[deps]) { + return handlers[deps](registry[relMap.id]); + } + + //Synchronous access to one module. If require.get is + //available (as in the Node adapter), prefer that. + if (req.get) { + return req.get(context, deps, relMap); + } + + //Normalize module name, if it contains . or .. + map = makeModuleMap(deps, relMap, false, true); + id = map.id; + + if (!hasProp(defined, id)) { + return onError(makeError('notloaded', 'Module name "' + + id + + '" has not been loaded yet for context: ' + + contextName + + (relMap ? '' : '. Use require([])'))); + } + return defined[id]; } - //Just return the module wanted. In this scenario, the - //second arg (if passed) is just the relMap. - moduleName = deps; - relMap = callback; + //Grab defines waiting in the global queue. + intakeDefines(); - //Normalize module name, if it contains . or .. - map = makeModuleMap(moduleName, relMap, false, true); - id = map.id; + //Mark all the dependencies as needing to be loaded. + context.nextTick(function () { + //Some defines could have been added since the + //require call, collect them. + intakeDefines(); - if (!hasProp(defined, id)) { - return onError(makeError('notloaded', 'Module name "' + - id + - '" has not been loaded yet for context: ' + - contextName)); + requireMod = getModule(makeModuleMap(null, relMap)); + + //Store if map config should be applied to this require + //call for dependencies. + requireMod.skipMap = options.skipMap; + + requireMod.init(deps, callback, errback, { + enabled: true + }); + + checkLoaded(); + }); + + return localRequire; + } + + mixin(localRequire, { + isBrowser: isBrowser, + + /** + * Converts a module name + .extension into an URL path. + * *Requires* the use of a module name. It does not support using + * plain URLs like nameToUrl. + */ + toUrl: function (moduleNamePlusExt) { + var index = moduleNamePlusExt.lastIndexOf('.'), + ext = null; + + if (index !== -1) { + ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); + moduleNamePlusExt = moduleNamePlusExt.substring(0, index); + } + + return context.nameToUrl(normalize(moduleNamePlusExt, + relMap && relMap.id, true), ext); + }, + + defined: function (id) { + return hasProp(defined, makeModuleMap(id, relMap, false, true).id); + }, + + specified: function (id) { + id = makeModuleMap(id, relMap, false, true).id; + return hasProp(defined, id) || hasProp(registry, id); } - return defined[id]; - } - - //Callback require. Normalize args. if callback or errback is - //not a function, it means it is a relMap. Test errback first. - if (errback && !isFunction(errback)) { - relMap = errback; - errback = undefined; - } - if (callback && !isFunction(callback)) { - relMap = callback; - callback = undefined; - } - - //Any defined modules in the global queue, intake them now. - takeGlobalQueue(); - - //Make sure any remaining defQueue items get properly processed. - while (defQueue.length) { - args = defQueue.shift(); - if (args[0] === null) { - return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); - } else { - //args are id, deps, factory. Should be normalized by the - //define() function. - callGetModule(args); - } - } - - //Mark all the dependencies as needing to be loaded. - requireMod = getModule(makeModuleMap(null, relMap)); - - requireMod.init(deps, callback, errback, { - enabled: true }); - checkLoaded(); + //Only allow undef on top level require calls + if (!relMap) { + localRequire.undef = function (id) { + //Bind any waiting define() calls to this context, + //fix for #408 + takeGlobalQueue(); - return context.require; - }, + var map = makeModuleMap(id, relMap, true), + mod = registry[id]; - undef: function (id) { - var map = makeModuleMap(id, null, true), - mod = registry[id]; + delete defined[id]; + delete urlFetched[map.url]; + delete undefEvents[id]; - delete defined[id]; - delete urlMap[id]; - delete urlFetched[map.url]; - delete undefEvents[id]; + if (mod) { + //Hold on to listeners in case the + //module will be attempted to be reloaded + //using a different config. + if (mod.events.defined) { + undefEvents[id] = mod.events; + } - if (mod) { - //Hold on to listeners in case the - //module will be attempted to be reloaded - //using a different config. - if (mod.events.defined) { - undefEvents[id] = mod.events; - } - - removeWaiting(id); + cleanRegistry(id); + } + }; } + + return localRequire; }, /** @@ -1471,9 +1454,9 @@ var requirejs, require, define; * @param {String} moduleName the name of the module to potentially complete. */ completeLoad: function (moduleName) { - var shim = config.shim[moduleName] || {}, - shExports = shim.exports && shim.exports.exports, - found, args, mod; + var found, args, mod, + shim = config.shim[moduleName] || {}, + shExports = shim.exports; takeGlobalQueue(); @@ -1500,9 +1483,7 @@ var requirejs, require, define; //of those calls/init calls changes the registry. mod = registry[moduleName]; - if (!found && - !defined[moduleName] && - mod && !mod.inited) { + if (!found && !defined[moduleName] && mod && !mod.inited) { if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { if (hasPathFallback(moduleName)) { return; @@ -1515,41 +1496,24 @@ var requirejs, require, define; } else { //A script that does not call define(), so just simulate //the call for it. - callGetModule([moduleName, (shim.deps || []), shim.exports]); + callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); } } checkLoaded(); }, - /** - * Converts a module name + .extension into an URL path. - * *Requires* the use of a module name. It does not support using - * plain URLs like nameToUrl. - */ - toUrl: function (moduleNamePlusExt, relModuleMap) { - var index = moduleNamePlusExt.lastIndexOf('.'), - ext = null; - - if (index !== -1) { - ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); - moduleNamePlusExt = moduleNamePlusExt.substring(0, index); - } - - return context.nameToUrl(moduleNamePlusExt, ext, relModuleMap); - }, - /** * Converts a module name to a file path. Supports cases where * moduleName may actually be just an URL. + * Note that it **does not** call normalize on the moduleName, + * it is assumed to have already been normalized. This is an + * internal API, not a public one. Use toUrl for the public API. */ - nameToUrl: function (moduleName, ext, relModuleMap) { + nameToUrl: function (moduleName, ext) { var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url, parentPath; - //Normalize module name if have a base relative module name to work from. - moduleName = normalize(moduleName, relModuleMap && relModuleMap.id, true); - //If a colon is in the URL, it indicates a protocol is used and it is just //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) //or ends with .js, then assume the user meant to use an url and not a module id. @@ -1594,7 +1558,8 @@ var requirejs, require, define; } //Join the path parts together, then figure out if baseUrl is needed. - url = syms.join('/') + (ext || '.js'); + url = syms.join('/'); + url += (ext || (/\?/.test(url) ? '' : '.js')); url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; } @@ -1631,7 +1596,7 @@ var requirejs, require, define; //all old browsers will be supported, but this one was easy enough //to support and still makes sense. if (evt.type === 'load' || - (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { + (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { //Reset interactive script so a script node is not held onto for //to long. interactiveScript = null; @@ -1651,7 +1616,10 @@ var requirejs, require, define; return onError(makeError('scripterror', 'Script error', evt, [data.id])); } } - }); + }; + + context.require = context.makeRequire(); + return context; } /** @@ -1671,8 +1639,8 @@ var requirejs, require, define; req = requirejs = function (deps, callback, errback, optional) { //Find the right context, use default - var contextName = defContextName, - context, config; + var context, config, + contextName = defContextName; // Determine if have config object in the call. if (!isArray(deps) && typeof deps !== 'string') { @@ -1712,6 +1680,16 @@ var requirejs, require, define; return req(config); }; + /** + * Execute something after the current tick + * of the event loop. Override for other envs + * that have a better solution than setTimeout. + * @param {Function} fn function to execute later. + */ + req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) { + setTimeout(fn, 4); + } : function (fn) { fn(); }; + /** * Export require as a global, but only if it does not already exist. */ @@ -1732,9 +1710,21 @@ var requirejs, require, define; //Create default context. req({}); - //Exports some context-sensitive methods on global require, using - //default context if no context specified. - addRequireMethods(req, contexts[defContextName]); + //Exports some context-sensitive methods on global require. + each([ + 'toUrl', + 'undef', + 'defined', + 'specified' + ], function (prop) { + //Reference from contexts instead of early binding to default context, + //so that during builds, the latest instance of the default context + //with its config gets used. + req[prop] = function () { + var ctx = contexts[defContextName]; + return ctx.require[prop].apply(ctx, arguments); + }; + }); if (isBrowser) { head = s.head = document.getElementsByTagName('head')[0]; @@ -1771,10 +1761,11 @@ var requirejs, require, define; if (isBrowser) { //In the browser so use a script tag node = config.xhtml ? - document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : - document.createElement('script'); + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : + document.createElement('script'); node.type = config.scriptType || 'text/javascript'; node.charset = 'utf-8'; + node.async = true; node.setAttribute('data-requirecontext', context.contextName); node.setAttribute('data-requiremodule', moduleName); @@ -1788,15 +1779,15 @@ var requirejs, require, define; //UNFORTUNATELY Opera implements attachEvent but does not follow the script //script execution mode. if (node.attachEvent && - //Check if node.attachEvent is artificially added by custom script or - //natively supported by browser - //read https://github.com/jrburke/requirejs/issues/187 - //if we can NOT find [native code] then it must NOT natively supported. - //in IE8, node.attachEvent does not have toString() - //Note the test for "[native code" with no closing brace, see: - //https://github.com/jrburke/requirejs/issues/273 - !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && - !isOpera) { + //Check if node.attachEvent is artificially added by custom script or + //natively supported by browser + //read https://github.com/jrburke/requirejs/issues/187 + //if we can NOT find [native code] then it must NOT natively supported. + //in IE8, node.attachEvent does not have toString() + //Note the test for "[native code" with no closing brace, see: + //https://github.com/jrburke/requirejs/issues/273 + !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && + !isOpera) { //Probably IE. IE (at least 6-8) do not fire //script onload right after executing the script, so //we cannot tie the anonymous define call to a name. @@ -1877,6 +1868,7 @@ var requirejs, require, define; //baseUrl, if it is not already set. dataMain = script.getAttribute('data-main'); if (dataMain) { + //Set final baseUrl if there is not already an explicit one. if (!cfg.baseUrl) { //Pull off the directory of data-main for use as the //baseUrl. @@ -1884,13 +1876,14 @@ var requirejs, require, define; mainScript = src.pop(); subPath = src.length ? src.join('/') + '/' : './'; - //Set final config. cfg.baseUrl = subPath; - //Strip off any trailing .js since dataMain is now - //like a module name. - dataMain = mainScript.replace(jsSuffixRegExp, ''); + dataMain = mainScript; } + //Strip off any trailing .js since dataMain is now + //like a module name. + dataMain = dataMain.replace(jsSuffixRegExp, ''); + //Put the data-main script in the files to load. cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain]; @@ -1909,7 +1902,7 @@ var requirejs, require, define; define = function (name, deps, callback) { var node, context; - //Allow for anonymous functions + //Allow for anonymous modules if (typeof name !== 'string') { //Adjust args appropriately callback = deps; diff --git a/install.js b/install.js index fcb1fb7d..dca36fff 100644 --- a/install.js +++ b/install.js @@ -42,6 +42,10 @@ function getVersion(path) { return fs.readFileSync(path + "/.git-ref", "utf8"); if (fs.existsSync(path + "/.git/ORIG_HEAD")) return fs.readFileSync(path + "/.git/ORIG_HEAD", "utf8"); + if (fs.existsSync(path + "/.sourcemint/source.json")) { + var json = fs.readFileSync(path + "/.sourcemint/source.json", "utf8"); + return JSON.parse(json).url.split("/").pop(); + } } if (process.argv.indexOf("-c") > 0) try { diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index 1e215071..f2c632df 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -325,7 +325,7 @@ var TextInput = function(parentNode, host) { host.renderer.$keepTextAreaAtCursor = null; // on windows context menu is opened after mouseup - if (useragent.isWin && (useragent.isGecko || useragent.isIE)) + if (useragent.isWin) event.capture(host.container, function(e) { text.style.left = e.clientX - 2 + "px"; text.style.top = e.clientY - 2 + "px"; diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 757db95c..5f14bc14 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -164,8 +164,8 @@ var VirtualRenderer = function(container, theme) { ); this.$loop.schedule(this.CHANGE_FULL); - this.setPadding(4); this.updateCharacterSize(); + this.setPadding(4); }; (function() { @@ -509,13 +509,11 @@ var VirtualRenderer = function(container, theme) { }; this.$updatePrintMargin = function() { - var containerEl; - if (!this.$showPrintMargin && !this.$printMarginEl) return; if (!this.$printMarginEl) { - containerEl = dom.createElement("div"); + var containerEl = dom.createElement("div"); containerEl.className = "ace_layer ace_print-margin-layer"; this.$printMarginEl = dom.createElement("div"); this.$printMarginEl.className = "ace_print-margin"; diff --git a/tool/update_deps.js b/tool/update_deps.js index 91630a50..6d74040c 100644 --- a/tool/update_deps.js +++ b/tool/update_deps.js @@ -19,6 +19,10 @@ var deps = [{ path: "mode/css/csslint.js", url: "https://raw.github.com/stubbornella/csslint/master/release/csslint-node.js", needsFixup: true +}, { + path: "../../demo/kitchen-sink/require.js", + url: "https://raw.github.com/jrburke/requirejs/master/require.js", + needsFixup: false }] var download = function(href, callback) {