-
-
Save guybedford/5546050 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
window.Loader = function(parent, options) { | |
this.global = options.global || {}; | |
this.baseURL = options.baseURL || parent.baseUrl; | |
this._parent = parent || null; | |
this._strict = options.strict || false; | |
this.normalize = options.normalize || parent.normalize; | |
this.resolve = options.resolve || parent.resolve; | |
this.fetch = options.fetch || parent.fetch; | |
this.translate = options.translate || parent.translate; | |
this.link = options.link || parent.link; | |
this._modules = {}; | |
} | |
Loader.prototype = { | |
load: function(name, callback, errback) { | |
name = this.normalize(name); | |
if (this._modules[name]) | |
return callback(this._modules[name]); | |
var opt = this.resolve(name); | |
var url = opt.name; | |
var self = this; | |
this.fetch(url, { | |
fulfill: function(source) { | |
source = self.translate(source, opt); | |
if (self._strict) | |
source = "'use strict';\n" + source; | |
var link = self.link(source, opts); | |
// 1. module | |
if (link instanceof Module) { | |
self._modules[name] = link; | |
return callback(link); | |
} | |
var imports, execute; | |
// 2. specified imports and execute | |
if (typeof link == 'object') { | |
imports = link.imports || []; | |
execute = link.execute; | |
} | |
// 3. undefined -> default | |
else | |
imports = self._parseImports(source); | |
// stops an unnecessary load cascade | |
if (errback.called) | |
return; | |
execute = execute || function() { | |
var deps = {}; | |
for (var i = 0; i < arguments.length; i++) | |
deps[imports[i]] = arguments[i]; | |
try { | |
var exports = self.eval(self._parseExports(source, null)); | |
} | |
catch(e) { | |
return errback(e); | |
} | |
callback(self._modules[name] = new Module(exports)); | |
} | |
if (!imports.length) | |
return execute(); | |
var deps = []; | |
var depCnt = 0; | |
for (var i = 0; i < imports.length; i++) (function(i) { | |
self.load(imports[i], function(module) { | |
depCnt++; | |
deps[i] = module; | |
if (depCnt == imports.length) | |
return execute.apply(self, deps); | |
}, function() { | |
errback(); | |
errback.called = true; | |
}); | |
})(i); | |
}, | |
reject: errback; | |
redirect: function() {} | |
}); | |
}, | |
_parseImports: function(source) { | |
// given the source, get the list of import module names to fetch | |
// supports: | |
// import "moduleName" as varName; | |
return []; | |
}, | |
_parseExports: function(source, deps) { | |
// adjusts source code so that exports becomes the output object | |
// also inserts the deps as the import modules | |
// supports: | |
// export someThing | |
return source + '(exports)'; | |
}, | |
eval: function(source) { | |
var __loader = this; | |
// neeeeeed to use esprima about here | |
/* | |
module "moduleName" { | |
__code__ | |
export = __something__; | |
__more code__ | |
} | |
-> | |
(function() { | |
__code__ | |
var __export = __somethng__; | |
__more code__ | |
return __export; | |
})(); | |
__loader.set("moduleName", new Module({ | |
}); | |
*/ | |
/* | |
import | |
*/ | |
// must support imports | |
// no export support though | |
var __global = this.global; | |
eval('(function(window) {' + source + '}).call(__global, __global);'); | |
}, | |
get: function(name) { | |
return this._modules[this.resolve(name, {}).name]; | |
}, | |
set: function(name, module) { | |
if (typeof name != 'string') { | |
for (var p in name) | |
this.set(p, name[p]); | |
return; | |
} | |
this._modules[this.resolve(name, {}).name] = Module(module); | |
} | |
}; | |
window.Module = function(o) { | |
if (o instanceof Module) | |
return o; | |
if (this.constructor != window.Module) | |
return new Module(o); | |
for (var key in o) | |
if (!o.hasOwnProperty || o.hasOwnProperty(key)) | |
Object.defineProperty(this, key, { | |
configurable: false, | |
enumerable: true, | |
get: function() { | |
return this[key]; | |
} | |
}); | |
} | |
var absUrlRegEx = /^\/|([^\:\/]*:)/; | |
var isUrl = function(name) { | |
return name.substr(name.length - 3, 3) == '.js' || name.match(absUrlRegEx); | |
} | |
window.System = new Loader(null, { | |
global: window, | |
baseURL: document.URL.substring(0, document.URL.lastIndexOf('\/') + 1), | |
strict: false, | |
normalize: function(name, parentName) { | |
if (isUrl(name)) | |
return name; | |
if (name.substr(0, 2) == './') { | |
var parentParts = parentName.split('/'); | |
if (!parentParts.length) | |
return name.substr(2); | |
parentParts.pop(); | |
parentParts.push(name.substr(2)); | |
return parentParts.join('/'); | |
} | |
if (name.substr(0, 3) == '../') { | |
var parentParts = parentName.split('/'); | |
if (!parentParts.length) | |
throw "Path below baseUrl"; | |
parentParts.pop(); | |
return this.normalize(name.substr(3), parentParts.join('/')); | |
} | |
return name; | |
}, | |
resolve: function(name) { | |
for (var r in this.resolvers) | |
if (this.resolvers[r].indexOf(name) != -1) | |
return { name: r }; | |
if (isUrl(name)) | |
return { name: name }; | |
return { | |
name: this.baseURL + (this.baseUrl.substr(this.baseUrl.length - 1, 1) != '/' ? '/' : '') + name + '.js'); | |
}; | |
}, | |
fetch: function(url, options) { | |
var xhr = new XMLHttpRequest(); | |
if (!xhr.withCredentials && typeof XDomainRequest != 'undefined') | |
xhr = new XDomainRequest(); | |
xhr.onreadystatechange = function() { | |
if (xhr.readyState === 4) { | |
if (xhr.status === 200) | |
options.fulfill(xhr.responseText); | |
else | |
options.reject(xhr.statusText); | |
} | |
} | |
xhr.open('GET', url, true); | |
xhr.send(null); | |
}, | |
translate: function(source, options) { | |
return source; | |
}, | |
link: function(source, options) {} | |
}); | |
window.System.resolvers = {}; | |
window.System.ondemand = function(resolvers) { | |
this.resolvers = this.resolvers || {}; | |
for (var r in resolvers) { | |
this.resolvers[r] = this.resolvers[r] || []; | |
if (resolvers[r] instanceof Array) | |
this.resolvers[r] = this.resolvers[r].concat(resolvers[r]); | |
else | |
this.resolvers[r].push(resolvers[r]); | |
} | |
} | |
// run the system loader on <script type="text/javascript:es6"></script> and also <script src="" type="tet/javascript:es6"></script> | |
})(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment