947 lines
20 KiB
JavaScript
947 lines
20 KiB
JavaScript
/**
|
|
* Sea.js 2.2.0 | seajs.org/LICENSE.md
|
|
*/
|
|
(function (global, undefined) {
|
|
|
|
// Avoid conflicting when `sea.js` is loaded multiple times
|
|
if (global.seajs) {
|
|
return
|
|
}
|
|
|
|
var seajs = global.seajs = {
|
|
// The current version of Sea.js being used
|
|
version: "2.2.0"
|
|
}
|
|
|
|
var data = seajs.data = {}
|
|
|
|
|
|
/**
|
|
* util-lang.js - The minimal language enhancement
|
|
*/
|
|
|
|
function isType(type) {
|
|
return function (obj) {
|
|
return {}.toString.call(obj) == "[object " + type + "]"
|
|
}
|
|
}
|
|
|
|
var isObject = isType("Object")
|
|
var isString = isType("String")
|
|
var isArray = Array.isArray || isType("Array")
|
|
var isFunction = isType("Function")
|
|
|
|
var _cid = 0
|
|
function cid() {
|
|
return _cid++
|
|
}
|
|
|
|
|
|
/**
|
|
* util-events.js - The minimal events support
|
|
*/
|
|
|
|
var events = data.events = {}
|
|
|
|
// Bind event
|
|
seajs.on = function (name, callback) {
|
|
var list = events[name] || (events[name] = [])
|
|
list.push(callback)
|
|
return seajs
|
|
}
|
|
|
|
// Remove event. If `callback` is undefined, remove all callbacks for the
|
|
// event. If `event` and `callback` are both undefined, remove all callbacks
|
|
// for all events
|
|
seajs.off = function (name, callback) {
|
|
// Remove *all* events
|
|
if (!(name || callback)) {
|
|
events = data.events = {}
|
|
return seajs
|
|
}
|
|
|
|
var list = events[name]
|
|
if (list) {
|
|
if (callback) {
|
|
for (var i = list.length - 1; i >= 0; i--) {
|
|
if (list[i] === callback) {
|
|
list.splice(i, 1)
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
delete events[name]
|
|
}
|
|
}
|
|
|
|
return seajs
|
|
}
|
|
|
|
// Emit event, firing all bound callbacks. Callbacks receive the same
|
|
// arguments as `emit` does, apart from the event name
|
|
var emit = seajs.emit = function (name, data) {
|
|
var list = events[name], fn
|
|
|
|
if (list) {
|
|
// Copy callback lists to prevent modification
|
|
list = list.slice()
|
|
|
|
// Execute event callbacks
|
|
while ((fn = list.shift())) {
|
|
fn(data)
|
|
}
|
|
}
|
|
|
|
return seajs
|
|
}
|
|
|
|
|
|
/**
|
|
* util-path.js - The utilities for operating path such as id, uri
|
|
*/
|
|
|
|
var DIRNAME_RE = /[^?#]*\//;
|
|
|
|
var DOT_RE = /\/\.\//g;
|
|
var DOUBLE_DOT_RE = /\/[^/]+\/\.\.\//;
|
|
var DOUBLE_SLASH_RE = /([^:/])\/\//g;
|
|
|
|
// Extract the directory portion of a path
|
|
// dirname("a/b/c.js?t=123#xx/zz") ==> "a/b/"
|
|
// ref: http://jsperf.com/regex-vs-split/2
|
|
function dirname(path) {
|
|
return path.match(DIRNAME_RE)[0];
|
|
}
|
|
|
|
// Canonicalize a path
|
|
// realpath("http://test.com/a//./b/../c") ==> "http://test.com/a/c"
|
|
function realpath(path) {
|
|
// /a/b/./c/./d ==> /a/b/c/d
|
|
path = path.replace(DOT_RE, "/");
|
|
|
|
// a/b/c/../../d ==> a/b/../d ==> a/d
|
|
while (path.match(DOUBLE_DOT_RE)) {
|
|
path = path.replace(DOUBLE_DOT_RE, "/");
|
|
}
|
|
|
|
// a//b/c ==> a/b/c
|
|
path = path.replace(DOUBLE_SLASH_RE, "$1/");
|
|
|
|
return path;
|
|
}
|
|
|
|
// Normalize an id
|
|
// normalize("path/to/a") ==> "path/to/a.js"
|
|
// NOTICE: substring is faster than negative slice and RegExp
|
|
function normalize(path) {
|
|
var last = path.length - 1;
|
|
var lastC = path.charAt(last);
|
|
|
|
// If the uri ends with `#`, just return it without '#'
|
|
if (lastC === "#") {
|
|
return path.substring(0, last);
|
|
}
|
|
|
|
return (path.substring(last - 2) === ".js" ||
|
|
path.indexOf("?") > 0 ||
|
|
path.substring(last - 3) === ".css" ||
|
|
lastC === "/") ? path : path + ".js";
|
|
}
|
|
|
|
|
|
var PATHS_RE = /^([^/:]+)(\/.+)$/;
|
|
var VARS_RE = /{([^{]+)}/g;
|
|
|
|
function parseAlias(id) {
|
|
var alias = data.alias;
|
|
return alias && isString(alias[id]) ? alias[id] : id;
|
|
}
|
|
|
|
function parsePaths(id) {
|
|
var paths = data.paths;
|
|
var m;
|
|
|
|
if (paths && (m = id.match(PATHS_RE)) && isString(paths[m[1]])) {
|
|
id = paths[m[1]] + m[2];
|
|
}
|
|
|
|
return id;
|
|
}
|
|
|
|
function parseVars(id) {
|
|
var vars = data.vars;
|
|
|
|
if (vars && id.indexOf("{") > -1) {
|
|
id = id.replace(VARS_RE, function (m, key) {
|
|
return isString(vars[key]) ? vars[key] : m;
|
|
});
|
|
}
|
|
|
|
return id;
|
|
}
|
|
|
|
function parseMap(uri) {
|
|
var map = data.map;
|
|
var ret = uri;
|
|
|
|
if (map) {
|
|
for (var i = 0, len = map.length; i < len; i++) {
|
|
var rule = map[i];
|
|
|
|
ret = isFunction(rule) ?
|
|
(rule(uri) || uri) :
|
|
uri.replace(rule[0], rule[1]);
|
|
|
|
// Only apply the first matched rule
|
|
if (ret !== uri) break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
var ABSOLUTE_RE = /^\/\/.|:\//;
|
|
var ROOT_DIR_RE = /^.*?\/\/.*?\//;
|
|
|
|
function addBase(id, refUri) {
|
|
var ret
|
|
var first = id.charAt(0)
|
|
|
|
// Absolute
|
|
if (ABSOLUTE_RE.test(id)) {
|
|
ret = id
|
|
}
|
|
// Relative
|
|
else if (first === ".") {
|
|
ret = realpath((refUri ? dirname(refUri) : data.cwd) + id)
|
|
}
|
|
// Root
|
|
else if (first === "/") {
|
|
var m = data.cwd.match(ROOT_DIR_RE)
|
|
ret = m ? m[0] + id.substring(1) : id
|
|
}
|
|
// Top-level
|
|
else {
|
|
ret = data.base + id
|
|
}
|
|
|
|
// Add default protocol when uri begins with "//"
|
|
if (ret.indexOf("//") === 0) {
|
|
ret = location.protocol + ret
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
function id2Uri(id, refUri) {
|
|
if (!id) return ""
|
|
|
|
id = parseAlias(id)
|
|
id = parsePaths(id)
|
|
id = parseVars(id)
|
|
id = normalize(id)
|
|
|
|
var uri = addBase(id, refUri)
|
|
uri = parseMap(uri)
|
|
|
|
return uri
|
|
}
|
|
|
|
|
|
var doc = document
|
|
var cwd = dirname(doc.URL)
|
|
var scripts = doc.scripts
|
|
|
|
// Recommend to add `seajsnode` id for the `sea.js` script element
|
|
var loaderScript = doc.getElementById("seajsnode") ||
|
|
scripts[scripts.length - 1]
|
|
|
|
// When `sea.js` is inline, set loaderDir to current working directory
|
|
var loaderDir = dirname(getScriptAbsoluteSrc(loaderScript) || cwd)
|
|
|
|
function getScriptAbsoluteSrc(node) {
|
|
return node.hasAttribute ? // non-IE6/7
|
|
node.src :
|
|
// see http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx
|
|
node.getAttribute("src", 4)
|
|
}
|
|
|
|
|
|
// For Developers
|
|
seajs.resolve = id2Uri
|
|
|
|
|
|
/**
|
|
* util-request.js - The utilities for requesting script and style files
|
|
* ref: tests/research/load-js-css/test.html
|
|
*/
|
|
|
|
var head = doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement
|
|
var baseElement = head.getElementsByTagName("base")[0]
|
|
|
|
var IS_CSS_RE = /\.css(?:\?|$)/i
|
|
var currentlyAddingScript
|
|
var interactiveScript
|
|
|
|
// `onload` event is not supported in WebKit < 535.23 and Firefox < 9.0
|
|
// ref:
|
|
// - https://bugs.webkit.org/show_activity.cgi?id=38995
|
|
// - https://bugzilla.mozilla.org/show_bug.cgi?id=185236
|
|
// - https://developer.mozilla.org/en/HTML/Element/link#Stylesheet_load_events
|
|
var isOldWebKit = +navigator.userAgent
|
|
.replace(/.*AppleWebKit\/(\d+)\..*/, "$1") < 536
|
|
|
|
|
|
function request(url, callback, charset) {
|
|
var isCSS = IS_CSS_RE.test(url)
|
|
var node = doc.createElement(isCSS ? "link" : "script")
|
|
|
|
if (charset) {
|
|
var cs = isFunction(charset) ? charset(url) : charset
|
|
if (cs) {
|
|
node.charset = cs
|
|
}
|
|
}
|
|
|
|
addOnload(node, callback, isCSS, url)
|
|
|
|
if (isCSS) {
|
|
node.rel = "stylesheet"
|
|
node.href = url
|
|
}
|
|
else {
|
|
node.async = true
|
|
node.src = url
|
|
}
|
|
|
|
// For some cache cases in IE 6-8, the script executes IMMEDIATELY after
|
|
// the end of the insert execution, so use `currentlyAddingScript` to
|
|
// hold current node, for deriving url in `define` call
|
|
currentlyAddingScript = node
|
|
|
|
// ref: #185 & http://dev.jquery.com/ticket/2709
|
|
baseElement ?
|
|
head.insertBefore(node, baseElement) :
|
|
head.appendChild(node)
|
|
|
|
currentlyAddingScript = null
|
|
}
|
|
|
|
function addOnload(node, callback, isCSS, url) {
|
|
var supportOnload = "onload" in node
|
|
|
|
// for Old WebKit and Old Firefox
|
|
if (isCSS && (isOldWebKit || !supportOnload)) {
|
|
setTimeout(function () {
|
|
pollCss(node, callback)
|
|
}, 1) // Begin after node insertion
|
|
return
|
|
}
|
|
|
|
if (supportOnload) {
|
|
node.onload = onload
|
|
node.onerror = function () {
|
|
emit("error", { uri: url, node: node })
|
|
onload()
|
|
}
|
|
}
|
|
else {
|
|
node.onreadystatechange = function () {
|
|
if (/loaded|complete/.test(node.readyState)) {
|
|
onload()
|
|
}
|
|
}
|
|
}
|
|
|
|
function onload() {
|
|
// Ensure only run once and handle memory leak in IE
|
|
node.onload = node.onerror = node.onreadystatechange = null
|
|
|
|
// Remove the script to reduce memory leak
|
|
if (!isCSS && !data.debug) {
|
|
head.removeChild(node)
|
|
}
|
|
|
|
// Dereference the node
|
|
node = null
|
|
|
|
callback()
|
|
}
|
|
}
|
|
|
|
function pollCss(node, callback) {
|
|
var sheet = node.sheet
|
|
var isLoaded
|
|
|
|
// for WebKit < 536
|
|
if (isOldWebKit) {
|
|
if (sheet) {
|
|
isLoaded = true
|
|
}
|
|
}
|
|
// for Firefox < 9.0
|
|
else if (sheet) {
|
|
try {
|
|
if (sheet.cssRules) {
|
|
isLoaded = true
|
|
}
|
|
} catch (ex) {
|
|
// The value of `ex.name` is changed from "NS_ERROR_DOM_SECURITY_ERR"
|
|
// to "SecurityError" since Firefox 13.0. But Firefox is less than 9.0
|
|
// in here, So it is ok to just rely on "NS_ERROR_DOM_SECURITY_ERR"
|
|
if (ex.name === "NS_ERROR_DOM_SECURITY_ERR") {
|
|
isLoaded = true
|
|
}
|
|
}
|
|
}
|
|
|
|
setTimeout(function () {
|
|
if (isLoaded) {
|
|
// Place callback here to give time for style rendering
|
|
callback()
|
|
}
|
|
else {
|
|
pollCss(node, callback)
|
|
}
|
|
}, 20)
|
|
}
|
|
|
|
function getCurrentScript() {
|
|
if (currentlyAddingScript) {
|
|
return currentlyAddingScript
|
|
}
|
|
|
|
// For IE6-9 browsers, the script onload event may not fire right
|
|
// after the script is evaluated. Kris Zyp found that it
|
|
// could query the script nodes and the one that is in "interactive"
|
|
// mode indicates the current script
|
|
// ref: http://goo.gl/JHfFW
|
|
if (interactiveScript && interactiveScript.readyState === "interactive") {
|
|
return interactiveScript
|
|
}
|
|
|
|
var scripts = head.getElementsByTagName("script")
|
|
|
|
for (var i = scripts.length - 1; i >= 0; i--) {
|
|
var script = scripts[i]
|
|
if (script.readyState === "interactive") {
|
|
interactiveScript = script
|
|
return interactiveScript
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// For Developers
|
|
seajs.request = request
|
|
|
|
|
|
/**
|
|
* util-deps.js - The parser for dependencies
|
|
* ref: tests/research/parse-dependencies/test.html
|
|
*/
|
|
|
|
var REQUIRE_RE = /"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\/\*[\S\s]*?\*\/|\/(?:\\\/|[^\/\r\n])+\/(?=[^\/])|\/\/.*|\.\s*require|(?:^|[^$])\brequire\s*\(\s*(["'])(.+?)\1\s*\)/g;
|
|
var SLASH_RE = /\\\\/g;
|
|
|
|
function parseDependencies(code) {
|
|
var ret = [];
|
|
|
|
code.replace(SLASH_RE, "")
|
|
.replace(REQUIRE_RE, function(m, m1, m2) {
|
|
if (m2) {
|
|
ret.push(m2);
|
|
}
|
|
});
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* module.js - The core of module loader
|
|
*/
|
|
|
|
var cachedMods = seajs.cache = {}
|
|
var anonymousMeta
|
|
|
|
var fetchingList = {}
|
|
var fetchedList = {}
|
|
var callbackList = {}
|
|
|
|
var STATUS = Module.STATUS = {
|
|
// 1 - The `module.uri` is being fetched
|
|
FETCHING: 1,
|
|
// 2 - The meta data has been saved to cachedMods
|
|
SAVED: 2,
|
|
// 3 - The `module.dependencies` are being loaded
|
|
LOADING: 3,
|
|
// 4 - The module are ready to execute
|
|
LOADED: 4,
|
|
// 5 - The module is being executed
|
|
EXECUTING: 5,
|
|
// 6 - The `module.exports` is available
|
|
EXECUTED: 6
|
|
}
|
|
|
|
|
|
function Module(uri, deps) {
|
|
this.uri = uri
|
|
this.dependencies = deps || []
|
|
this.exports = null
|
|
this.status = 0
|
|
|
|
// Who depends on me
|
|
this._waitings = {}
|
|
|
|
// The number of unloaded dependencies
|
|
this._remain = 0
|
|
}
|
|
|
|
// Resolve module.dependencies
|
|
Module.prototype.resolve = function () {
|
|
var mod = this
|
|
var ids = mod.dependencies
|
|
var uris = []
|
|
|
|
for (var i = 0, len = ids.length; i < len; i++) {
|
|
uris[i] = Module.resolve(ids[i], mod.uri)
|
|
}
|
|
return uris
|
|
}
|
|
|
|
// Load module.dependencies and fire onload when all done
|
|
Module.prototype.load = function () {
|
|
var mod = this
|
|
|
|
// If the module is being loaded, just wait it onload call
|
|
if (mod.status >= STATUS.LOADING) {
|
|
return
|
|
}
|
|
|
|
mod.status = STATUS.LOADING
|
|
|
|
// Emit `load` event for plugins such as combo plugin
|
|
var uris = mod.resolve()
|
|
emit("load", uris)
|
|
|
|
var len = mod._remain = uris.length
|
|
var m
|
|
|
|
// Initialize modules and register waitings
|
|
for (var i = 0; i < len; i++) {
|
|
m = Module.get(uris[i])
|
|
|
|
if (m.status < STATUS.LOADED) {
|
|
// Maybe duplicate: When module has dupliate dependency, it should be it's count, not 1
|
|
m._waitings[mod.uri] = (m._waitings[mod.uri] || 0) + 1
|
|
}
|
|
else {
|
|
mod._remain--
|
|
}
|
|
}
|
|
|
|
if (mod._remain === 0) {
|
|
mod.onload()
|
|
return
|
|
}
|
|
|
|
// Begin parallel loading
|
|
var requestCache = {}
|
|
|
|
for (i = 0; i < len; i++) {
|
|
m = cachedMods[uris[i]]
|
|
|
|
if (m.status < STATUS.FETCHING) {
|
|
m.fetch(requestCache)
|
|
}
|
|
else if (m.status === STATUS.SAVED) {
|
|
m.load()
|
|
}
|
|
}
|
|
|
|
// Send all requests at last to avoid cache bug in IE6-9. Issues#808
|
|
for (var requestUri in requestCache) {
|
|
if (requestCache.hasOwnProperty(requestUri)) {
|
|
requestCache[requestUri]()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Call this method when module is loaded
|
|
Module.prototype.onload = function () {
|
|
var mod = this
|
|
mod.status = STATUS.LOADED
|
|
|
|
if (mod.callback) {
|
|
mod.callback()
|
|
}
|
|
|
|
// Notify waiting modules to fire onload
|
|
var waitings = mod._waitings
|
|
var uri, m
|
|
|
|
for (uri in waitings) {
|
|
if (waitings.hasOwnProperty(uri)) {
|
|
m = cachedMods[uri]
|
|
m._remain -= waitings[uri]
|
|
if (m._remain === 0) {
|
|
m.onload()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reduce memory taken
|
|
delete mod._waitings
|
|
delete mod._remain
|
|
}
|
|
|
|
// Fetch a module
|
|
Module.prototype.fetch = function (requestCache) {
|
|
var mod = this
|
|
var uri = mod.uri
|
|
|
|
mod.status = STATUS.FETCHING
|
|
|
|
// Emit `fetch` event for plugins such as combo plugin
|
|
var emitData = { uri: uri }
|
|
emit("fetch", emitData)
|
|
var requestUri = emitData.requestUri || uri
|
|
|
|
// Empty uri or a non-CMD module
|
|
if (!requestUri || fetchedList[requestUri]) {
|
|
mod.load()
|
|
return
|
|
}
|
|
|
|
if (fetchingList[requestUri]) {
|
|
callbackList[requestUri].push(mod)
|
|
return
|
|
}
|
|
|
|
fetchingList[requestUri] = true
|
|
callbackList[requestUri] = [mod]
|
|
|
|
// Emit `request` event for plugins such as text plugin
|
|
emit("request", emitData = {
|
|
uri: uri,
|
|
requestUri: requestUri,
|
|
onRequest: onRequest,
|
|
charset: data.charset
|
|
})
|
|
|
|
if (!emitData.requested) {
|
|
requestCache ?
|
|
requestCache[emitData.requestUri] = sendRequest :
|
|
sendRequest()
|
|
}
|
|
|
|
function sendRequest() {
|
|
seajs.request(emitData.requestUri, emitData.onRequest, emitData.charset)
|
|
}
|
|
|
|
function onRequest() {
|
|
delete fetchingList[requestUri]
|
|
fetchedList[requestUri] = true
|
|
|
|
// Save meta data of anonymous module
|
|
if (anonymousMeta) {
|
|
Module.save(uri, anonymousMeta)
|
|
anonymousMeta = null
|
|
}
|
|
|
|
// Call callbacks
|
|
var m, mods = callbackList[requestUri]
|
|
delete callbackList[requestUri]
|
|
while ((m = mods.shift())) m.load()
|
|
}
|
|
}
|
|
|
|
// Execute a module
|
|
Module.prototype.exec = function () {
|
|
var mod = this
|
|
|
|
// When module is executed, DO NOT execute it again. When module
|
|
// is being executed, just return `module.exports` too, for avoiding
|
|
// circularly calling
|
|
if (mod.status >= STATUS.EXECUTING) {
|
|
return mod.exports
|
|
}
|
|
|
|
mod.status = STATUS.EXECUTING
|
|
|
|
// Create require
|
|
var uri = mod.uri
|
|
|
|
function require(id) {
|
|
return Module.get(require.resolve(id)).exec()
|
|
}
|
|
|
|
require.resolve = function (id) {
|
|
return Module.resolve(id, uri)
|
|
}
|
|
|
|
require.async = function (ids, callback) {
|
|
Module.use(ids, callback, uri + "_async_" + cid())
|
|
return require
|
|
}
|
|
|
|
// Exec factory
|
|
var factory = mod.factory
|
|
|
|
var exports = isFunction(factory) ?
|
|
factory(require, mod.exports = {}, mod) :
|
|
factory
|
|
|
|
if (exports === undefined) {
|
|
exports = mod.exports
|
|
}
|
|
|
|
// Reduce memory leak
|
|
delete mod.factory
|
|
|
|
mod.exports = exports
|
|
mod.status = STATUS.EXECUTED
|
|
|
|
// Emit `exec` event
|
|
emit("exec", mod)
|
|
|
|
return exports
|
|
}
|
|
|
|
// Resolve id to uri
|
|
Module.resolve = function (id, refUri) {
|
|
// Emit `resolve` event for plugins such as text plugin
|
|
var emitData = { id: id, refUri: refUri }
|
|
emit("resolve", emitData)
|
|
|
|
return emitData.uri || seajs.resolve(emitData.id, refUri)
|
|
}
|
|
|
|
// Define a module
|
|
Module.define = function (id, deps, factory) {
|
|
var argsLen = arguments.length
|
|
|
|
// define(factory)
|
|
if (argsLen === 1) {
|
|
factory = id
|
|
id = undefined
|
|
}
|
|
else if (argsLen === 2) {
|
|
factory = deps
|
|
|
|
// define(deps, factory)
|
|
if (isArray(id)) {
|
|
deps = id
|
|
id = undefined
|
|
}
|
|
// define(id, factory)
|
|
else {
|
|
deps = undefined
|
|
}
|
|
}
|
|
|
|
// Parse dependencies according to the module factory code
|
|
if (!isArray(deps) && isFunction(factory)) {
|
|
deps = parseDependencies(factory.toString())
|
|
}
|
|
|
|
var meta = {
|
|
id: id,
|
|
uri: Module.resolve(id),
|
|
deps: deps,
|
|
factory: factory
|
|
}
|
|
|
|
// Try to derive uri in IE6-9 for anonymous modules
|
|
if (!meta.uri && doc.attachEvent) {
|
|
var script = getCurrentScript()
|
|
|
|
if (script) {
|
|
meta.uri = script.src
|
|
}
|
|
|
|
// NOTE: If the id-deriving methods above is failed, then falls back
|
|
// to use onload event to get the uri
|
|
}
|
|
|
|
// Emit `define` event, used in nocache plugin, seajs node version etc
|
|
emit("define", meta)
|
|
|
|
meta.uri ? Module.save(meta.uri, meta) :
|
|
// Save information for "saving" work in the script onload event
|
|
anonymousMeta = meta
|
|
}
|
|
|
|
// Save meta data to cachedMods
|
|
Module.save = function (uri, meta) {
|
|
var mod = Module.get(uri)
|
|
|
|
// Do NOT override already saved modules
|
|
if (mod.status < STATUS.SAVED) {
|
|
mod.id = meta.id || uri
|
|
mod.dependencies = meta.deps || []
|
|
mod.factory = meta.factory
|
|
mod.status = STATUS.SAVED
|
|
}
|
|
}
|
|
|
|
// Get an existed module or create a new one
|
|
Module.get = function (uri, deps) {
|
|
return cachedMods[uri] || (cachedMods[uri] = new Module(uri, deps))
|
|
}
|
|
|
|
// Use function is equal to load a anonymous module
|
|
Module.use = function (ids, callback, uri) {
|
|
var mod = Module.get(uri, isArray(ids) ? ids : [ids])
|
|
|
|
mod.callback = function () {
|
|
var exports = []
|
|
var uris = mod.resolve()
|
|
|
|
for (var i = 0, len = uris.length; i < len; i++) {
|
|
exports[i] = cachedMods[uris[i]].exec()
|
|
}
|
|
|
|
if (callback) {
|
|
callback.apply(global, exports)
|
|
}
|
|
|
|
delete mod.callback
|
|
}
|
|
|
|
mod.load()
|
|
}
|
|
|
|
// Load preload modules before all other modules
|
|
Module.preload = function (callback) {
|
|
var preloadMods = data.preload
|
|
var len = preloadMods.length
|
|
|
|
if (len) {
|
|
Module.use(preloadMods, function () {
|
|
// Remove the loaded preload modules
|
|
preloadMods.splice(0, len)
|
|
|
|
// Allow preload modules to add new preload modules
|
|
Module.preload(callback)
|
|
}, data.cwd + "_preload_" + cid())
|
|
}
|
|
else {
|
|
callback()
|
|
}
|
|
}
|
|
|
|
|
|
// Public API
|
|
|
|
seajs.use = function (ids, callback) {
|
|
Module.preload(function () {
|
|
Module.use(ids, callback, data.cwd + "_use_" + cid())
|
|
})
|
|
return seajs
|
|
}
|
|
|
|
Module.define.cmd = {}
|
|
global.define = Module.define
|
|
|
|
|
|
// For Developers
|
|
|
|
seajs.Module = Module
|
|
data.fetchedList = fetchedList
|
|
data.cid = cid
|
|
|
|
seajs.require = function (id) {
|
|
var mod = Module.get(Module.resolve(id))
|
|
if (mod.status < STATUS.EXECUTING) {
|
|
mod.onload()
|
|
mod.exec()
|
|
}
|
|
return mod.exports
|
|
}
|
|
|
|
|
|
/**
|
|
* config.js - The configuration for the loader
|
|
*/
|
|
|
|
var BASE_RE = /^(.+?\/)(\?\?)?(seajs\/)+/;
|
|
|
|
// The root path to use for id2uri parsing
|
|
// If loaderUri is `http://test.com/libs/seajs/[??][seajs/1.2.3/]sea.js`, the
|
|
// baseUri should be `http://test.com/libs/`
|
|
data.base = (loaderDir.match(BASE_RE) || ["", loaderDir])[1]
|
|
|
|
// The loader directory
|
|
data.dir = loaderDir
|
|
|
|
// The current working directory
|
|
data.cwd = cwd
|
|
|
|
// The charset for requesting files
|
|
data.charset = "utf-8"
|
|
|
|
// Modules that are needed to load before all other modules
|
|
data.preload = (function () {
|
|
var plugins = []
|
|
|
|
// Convert `seajs-xxx` to `seajs-xxx=1`
|
|
// NOTE: use `seajs-xxx=1` flag in uri or cookie to preload `seajs-xxx`
|
|
var str = location.search.replace(/(seajs-\w+)(&|$)/g, "$1=1$2");
|
|
|
|
// Add cookie string
|
|
str += " " + doc.cookie
|
|
|
|
// Exclude seajs-xxx=0
|
|
str.replace(/(seajs-\w+)=1/g, function (m, name) {
|
|
plugins.push(name)
|
|
})
|
|
|
|
return plugins
|
|
})()
|
|
|
|
// data.alias - An object containing shorthands of module id
|
|
// data.paths - An object containing path shorthands in module id
|
|
// data.vars - The {xxx} variables in module id
|
|
// data.map - An array containing rules to map module uri
|
|
// data.debug - Debug mode. The default value is false
|
|
|
|
seajs.config = function (configData) {
|
|
|
|
for (var key in configData) {
|
|
var curr = configData[key]
|
|
var prev = data[key]
|
|
|
|
// Merge object config such as alias, vars
|
|
if (prev && isObject(prev)) {
|
|
for (var k in curr) {
|
|
prev[k] = curr[k]
|
|
}
|
|
}
|
|
else {
|
|
// Concat array config such as map, preload
|
|
if (isArray(prev)) {
|
|
curr = prev.concat(curr)
|
|
}
|
|
// Make sure that `data.base` is an absolute path
|
|
else if (key === "base") {
|
|
// Make sure end with "/"
|
|
if (curr.slice(-1) !== "/") {
|
|
curr += "/"
|
|
}
|
|
curr = addBase(curr)
|
|
}
|
|
|
|
// Set config
|
|
data[key] = curr
|
|
}
|
|
}
|
|
|
|
emit("config", configData)
|
|
return seajs
|
|
}
|
|
|
|
})(this);
|