Mathias Panzenböck avatar Mathias Panzenböck committed 4ffb516

require.js: better COmmonJS compliance: added module object and require.paths

Comments (0)

Files changed (1)

-const require = (function () {
-	// be careful so that nothing is bound to the closure made by eval:
-	return (function (_eval) {
-		var loading = {};
-		var loaded  = {};
+const require = (function (_eval) {
+	var loading = {};
+	var loaded  = {};
+	var paths   = [];
 	
-		function _require (module, opts) {
-			if (opts === undefined) {
-				opts = {};
+	function normpath (path) {
+		var newpath = [];
+			
+		path = path.split('/');
+		for (i in path) {
+			var part = path[i];
+			if (part == '..') {
+				newpath.splice(newpath.length-1,1);
+			}
+			else if (part && part != '.') {
+				newpath.push(part);
+			}
+		}
+
+		return newpath.join('/');
+	}
+
+	function _require (moduleName, opts) {
+		var location = window.location;
+		var search = false;
+		var pathIndex = 0;
+		var prefix =  location.protocol + '://' + location.host;
+		var id;
+		var reluri;
+		var uri;
+			
+		if (moduleName[0] == '/') {
+			id = '/' + normpath(moduleName);
+			reluri = id + '.js';
+		}
+		else if (moduleName.substring(0,2) == './'
+				|| moduleName.substring(0,3) == '../'
+				|| paths.length == 0) {
+			id = '/' + normpath(location.pathname + '/../' + moduleName);
+			reluri = id + '.js';
+		}
+		else {
+			search = true;
+			id = normpath(moduleName);
+			reluri = '/' + normpath(paths[0] + '/' + id + '.js');
+		}
+			
+		var uri = prefix + reluri;
+
+		if (opts === undefined) {
+			opts = {};
+		}
+	
+		if (opts.async === undefined) {
+			opts.async = false;
+		}
+	
+		var moduleObj = loaded[uri];
+	
+		if (moduleObj === undefined) {
+			moduleObj = loading[uri];
+		}
+	
+		if (moduleObj === undefined) {
+			loading[uri] = moduleObj = {};
+	
+			var module = {id: id, uri: uri};
+			var argnames = ['exports', 'require', 'module'];
+			var args = [moduleObj, _require, module];
+	
+			if (opts.globals) {
+				for (argname in opts.globals) {
+					if (!/^[_a-zA-Z][_a-zA-Z0-9]*$/.test(argname)
+							|| argname == 'exports'
+							|| argname == 'require'
+							|| argname == 'module') {
+						throw new Error('Illegal global name: '+argname);
+					}
+					argnames.push(argname);
+					args.push(opts.globals[argname]);
+				}
 			}
 	
-			if (opts.async === undefined) {
-				opts.async = false;
+			var xhr = new XMLHttpRequest();
+			var err = null;
+	
+			xhr.addEventListener('abort', function () {
+				delete loading[uri];
+				err = new Error(
+					'Error loading module: ' + id +
+					'\nTransfer aborted by user.');
+				if (opts.onError) {
+					opts.onError(err);
+				}
+			}, false);
+	
+			function transferError () {
+				if (search && xhr.status == 404 && (pathIndex+1) < paths.length) {
+					reluri = '/' + normpath(paths[++pathIndex] + '/' + id + '.js');
+					module.uri = prefix + reluri;
+					xhr.open('GET', reluri, opts.async);
+					xhr.send(null);
+					return;
+				}
+
+				delete loading[uri];
+				err = new Error(
+					'Error loading module: ' + id +
+					'\nHTTP Status: ' + xhr.status + ' ' + xhr.statusText);
+				if (opts.onError) {
+					opts.onError(err);
+				}
 			}
 	
-			var moduleObj = loaded[module];
-	
-			if (moduleObj === undefined) {
-				moduleObj = loading[module];
-			}
-	
-			if (moduleObj === undefined) {
-				loading[module] = moduleObj = {};
-	
-				var argnames = ['exports', 'require'];
-				var args = [moduleObj, _require];
-	
-				if (opts.globals) {
-					for (argname in opts.globals) {
-						if (!/^[_a-zA-Z][_a-zA-Z0-9]*$/.test(argname)
-								|| argname == 'exports'
-								|| argname == 'require') {
-							throw new Error('Illegal global name: '+argname);
-						}
-						argnames.push(argname);
-						args.push(opts.globals[argname]);
-					}
+			xhr.addEventListener('error', transferError, false);
+				
+			xhr.addEventListener('load', function () {
+				if (xhr.status != 200 && xhr.status != 304) {
+					transferError();
+					return;
 				}
 	
-				var xhr = new XMLHttpRequest();
-				var err = null;
-	
-				xhr.addEventListener('abort', function () {
-					delete loading[module];
-					err = new Error(
-						'Error loading module: ' + module +
-						'\nTransfer aborted by user.');
+				try {
+					_eval(
+						'(function ('+argnames.join(',')+') { ' +
+						xhr.responseText+' })').apply(null, args);
+							
+					delete loading[uri];
+					loaded[uri] = moduleObj;
+				}
+				catch (e) {
+					delete loading[uri];
+					err = e;
 					if (opts.onError) {
 						opts.onError(err);
 					}
-				}, false);
 	
-				function transferError () {
-					delete loading[module];
-					err = new Error(
-						'Error loading module: ' + module +
-						'\nHTTP Status: ' + xhr.status + ' ' + xhr.statusText);
-					if (opts.onError) {
-						opts.onError(err);
-					}
+					return;
 				}
 	
-				xhr.addEventListener('error', transferError, false);
-				
-				xhr.addEventListener('load', function () {
-					if (xhr.status != 200 && xhr.status != 304) {
-						transferError();
-						return;
-					}
+				if (opts.onLoad) {
+					opts.onLoad(moduleObj);
+				}
+			}, false);
 	
-					try {
-						_eval(
-							'(function ('+argnames.join(',')+') { ' +
-							xhr.responseText+' })').apply(null, args);
-							
-						delete loading[module];
-						loaded[module] = moduleObj;
-					}
-					catch (e) {
-						delete loading[module];
-						err = e;
-						if (opts.onError) {
-							opts.onError(err);
-						}
+			xhr.open('GET', reluri, opts.async);
+			xhr.send(null);
 	
-						return;
-					}
-	
-					if (opts.onLoad) {
-						opts.onLoad(moduleObj);
-					}
-				}, false);
-	
-				xhr.open('GET', module, opts.async);
-				xhr.send(null);
-	
-				if (err != null) {
-					throw err;
-				}
+			if (err != null) {
+				throw err;
 			}
-			else if (opts.onLoad) {
-				opts.onLoad(moduleObj);
-			}
-	
-			return moduleObj;
+		}
+		else if (opts.onLoad) {
+			opts.onLoad(moduleObj);
 		}
 	
-		return _require;
-	})(function (code) { return eval(code); });
-})();
+		return moduleObj;
+	}
+
+	_require.__proto__ = new Function();
+	_require.__proto__.__defineGetter__('paths', function () {
+		return paths;
+	});
+	
+	return _require;
+	// be careful so that nothing is bound to the closure made by eval:
+})(function (code) { return eval(code); });
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.