andy-h
2/27/2014 - 6:34 PM

Execute a callback once required scripts have been loaded.

Execute a callback once required scripts have been loaded.

//require(scriptList, onSuccess[, onFailure])
//usage:
//require(["a.js", "b.js"], function (){ /*scripts have loaded; do stuff*/ }, function (){ /*one or more scripts didn't load; handle error*/ });
//
//scriptList can just be a string if there's only one script

var require = (function (){
	
	var head = document.getElementsByTagName("head")[0];
	
	function require(scriptList, onSuccess, onFailure){
		
		"use strict";
		
		var i, len, url, pending = [];
		
		scriptList = [].concat(scriptList);
		len = scriptList.length;
		
		for(i=0; i<len; i++){	//for each required script
			url = getFullUrl(scriptList[i]);
			if(!isLoaded(url)){	//if there is not already a script element with this URL in the document
				appendScript(url, onLoad, onFailure);	//append a script element to <head>
				pending.push(url);
			}
		}
		
		function onLoad(evt){
			if(!this.readyState || this.readyState === "loaded" || this.readyState === "complete"){
				delete this.onreadystatechange;
				delete this.onload;
				pending.splice(pending.indexOf(this.src), 1);
				if(!pending.length){
					onSuccess();
				}
			}
		}
		
	}
	
	function getFullUrl(url){
		var loc, path;
		url = ""+url;
		if(/^https?:\/\//i.test(url)){
			return url;
		}
		
		loc = document.location;
		if(url.slice(0, 2) === "//"){
			return loc.protocol+url;
		}
		else if(url[0] === "/"){
			return loc.protocol+"//"+loc.host+url;
		}
		else{
			path = loc.pathname.replace(/\/[^\/]*$/, "/");
			while(url.slice(0, 3) === "../"){
				path = path.replace(/\/[^\/]*\/$/, "/");
				url = url.slice(3);
			}
			return loc.protocol+"//"+loc.host+path+url;
		}
	}
	
	function isLoaded(url){
		var i, len, scripts = Array.prototype.slice.call(document.getElementsByTagName("script"));
		len = scripts.length;
		for(i=0; i<len; i++){
			//if(getFullUrl(scripts[i].src) === url) return true;
			if(scripts[i].src === url) return true;
		}
		return false;
	}
	
	function appendScript(url, onLoad, onError){
		var script = document.createElement("script");
		script.type = "text/javascript";
		script.src = url;
		script.onreadystatechange = onLoad;
		script.onload = onLoad;
		script.onerror = onError /*|| function (evt){ throw new Error("Required script failed to load: "+url); }*/;
		head.appendChild(script);
	}
	
	return require;
	
})();