|
|
/**
|
|
|
* Sea.js 3.0.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: "3.0.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]
|
|
|
|
|
|
if (list) {
|
|
|
// Copy callback lists to prevent modification
|
|
|
list = list.slice()
|
|
|
|
|
|
// Execute event callbacks, use index because it's the faster.
|
|
|
for(var i = 0, len = list.length; i < len; i++) {
|
|
|
list[i](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 MULTI_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, "/")
|
|
|
|
|
|
/*
|
|
|
@author wh1100717
|
|
|
a//b/c ==> a/b/c
|
|
|
a///b/////c ==> a/b/c
|
|
|
DOUBLE_DOT_RE matches a/b/c//../d path correctly only if replace // with / first
|
|
|
*/
|
|
|
path = path.replace(MULTI_SLASH_RE, "$1/")
|
|
|
|
|
|
// a/b/c/../../d ==> a/b/../d ==> a/d
|
|
|
while (path.match(DOUBLE_DOT_RE)) {
|
|
|
path = path.replace(DOUBLE_DOT_RE, "/")
|
|
|
}
|
|
|
|
|
|
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.charCodeAt(last)
|
|
|
|
|
|
// If the uri ends with `#`, just return it without '#'
|
|
|
if (lastC === 35 /* "#" */) {
|
|
|
return path.substring(0, last)
|
|
|
}
|
|
|
|
|
|
return (path.substring(last - 2) === ".js" ||
|
|
|
path.indexOf("?") > 0 ||
|
|
|
lastC === 47 /* "/" */) ? 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.charCodeAt(0)
|
|
|
|
|
|
// Absolute
|
|
|
if (ABSOLUTE_RE.test(id)) {
|
|
|
ret = id
|
|
|
}
|
|
|
// Relative
|
|
|
else if (first === 46 /* "." */) {
|
|
|
ret = (refUri ? dirname(refUri) : data.cwd) + id
|
|
|
}
|
|
|
// Root
|
|
|
else if (first === 47 /* "/" */) {
|
|
|
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 realpath(ret)
|
|
|
}
|
|
|
|
|
|
function id2Uri(id, refUri) {
|
|
|
if (!id) return ""
|
|
|
|
|
|
id = parseAlias(id)
|
|
|
id = parsePaths(id)
|
|
|
id = parseAlias(id)
|
|
|
id = parseVars(id)
|
|
|
id = parseAlias(id)
|
|
|
id = normalize(id)
|
|
|
id = parseAlias(id)
|
|
|
|
|
|
var uri = addBase(id, refUri)
|
|
|
uri = parseAlias(uri)
|
|
|
uri = parseMap(uri)
|
|
|
|
|
|
return uri
|
|
|
}
|
|
|
|
|
|
// For Developers
|
|
|
seajs.resolve = id2Uri;
|
|
|
|
|
|
// Check environment
|
|
|
var isWebWorker = typeof window === 'undefined' && typeof importScripts !== 'undefined' && isFunction(importScripts);
|
|
|
|
|
|
// Ignore about:xxx and blob:xxx
|
|
|
var IGNORE_LOCATION_RE = /^(about|blob):/;
|
|
|
var loaderDir;
|
|
|
// Sea.js's full path
|
|
|
var loaderPath;
|
|
|
// Location is read-only from web worker, should be ok though
|
|
|
var cwd = (!location.href || IGNORE_LOCATION_RE.test(location.href)) ? '' : dirname(location.href);
|
|
|
|
|
|
if (isWebWorker) {
|
|
|
// Web worker doesn't create DOM object when loading scripts
|
|
|
// Get sea.js's path by stack trace.
|
|
|
var stack;
|
|
|
try {
|
|
|
var up = new Error();
|
|
|
throw up;
|
|
|
} catch (e) {
|
|
|
// IE won't set Error.stack until thrown
|
|
|
stack = e.stack.split('\n');
|
|
|
}
|
|
|
// First line is 'Error'
|
|
|
stack.shift();
|
|
|
|
|
|
var m;
|
|
|
// Try match `url:row:col` from stack trace line. Known formats:
|
|
|
// Chrome: ' at http://localhost:8000/script/sea-worker-debug.js:294:25'
|
|
|
// FireFox: '@http://localhost:8000/script/sea-worker-debug.js:1082:1'
|
|
|
// IE11: ' at Anonymous function (http://localhost:8000/script/sea-worker-debug.js:295:5)'
|
|
|
// Don't care about older browsers since web worker is an HTML5 feature
|
|
|
var TRACE_RE = /.*?((?:http|https|file)(?::\/{2}[\w]+)(?:[\/|\.]?)(?:[^\s"]*)).*?/i
|
|
|
// Try match `url` (Note: in IE there will be a tailing ')')
|
|
|
var URL_RE = /(.*?):\d+:\d+\)?$/;
|
|
|
// Find url of from stack trace.
|
|
|
// Cannot simply read the first one because sometimes we will get:
|
|
|
// Error
|
|
|
// at Error (native) <- Here's your problem
|
|
|
// at http://localhost:8000/_site/dist/sea.js:2:4334 <- What we want
|
|
|
// at http://localhost:8000/_site/dist/sea.js:2:8386
|
|
|
// at http://localhost:8000/_site/tests/specs/web-worker/worker.js:3:1
|
|
|
while (stack.length > 0) {
|
|
|
var top = stack.shift();
|
|
|
m = TRACE_RE.exec(top);
|
|
|
if (m != null) {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
var url;
|
|
|
if (m != null) {
|
|
|
// Remove line number and column number
|
|
|
// No need to check, can't be wrong at this point
|
|
|
var url = URL_RE.exec(m[1])[1];
|
|
|
}
|
|
|
// Set
|
|
|
loaderPath = url
|
|
|
// Set loaderDir
|
|
|
loaderDir = dirname(url || cwd);
|
|
|
// This happens with inline worker.
|
|
|
// When entrance script's location.href is a blob url,
|
|
|
// cwd will not be available.
|
|
|
// Fall back to loaderDir.
|
|
|
if (cwd === '') {
|
|
|
cwd = loaderDir;
|
|
|
}
|
|
|
}
|
|
|
else {
|
|
|
var doc = document
|
|
|
var scripts = doc.scripts
|
|
|
|
|
|
// Recommend to add `seajsnode` id for the `sea.js` script element
|
|
|
var loaderScript = doc.getElementById("seajsnode") ||
|
|
|
scripts[scripts.length - 1]
|
|
|
|
|
|
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)
|
|
|
}
|
|
|
loaderPath = getScriptAbsoluteSrc(loaderScript)
|
|
|
// When `sea.js` is inline, set loaderDir to current working directory
|
|
|
loaderDir = dirname(loaderPath || cwd)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* util-request.js - The utilities for requesting script and style files
|
|
|
* ref: tests/research/load-js-css/test.html
|
|
|
*/
|
|
|
if (isWebWorker) {
|
|
|
function requestFromWebWorker(url, callback, charset) {
|
|
|
// Load with importScripts
|
|
|
var error;
|
|
|
try {
|
|
|
importScripts(url);
|
|
|
} catch (e) {
|
|
|
error = e;
|
|
|
}
|
|
|
callback(error);
|
|
|
}
|
|
|
// For Developers
|
|
|
seajs.request = requestFromWebWorker;
|
|
|
}
|
|
|
else {
|
|
|
var doc = document
|
|
|
var head = doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement
|
|
|
var baseElement = head.getElementsByTagName("base")[0]
|
|
|
|
|
|
var currentlyAddingScript
|
|
|
|
|
|
function request(url, callback, charset) {
|
|
|
var node = doc.createElement("script")
|
|
|
|
|
|
if (charset) {
|
|
|
var cs = isFunction(charset) ? charset(url) : charset
|
|
|
if (cs) {
|
|
|
node.charset = cs
|
|
|
}
|
|
|
}
|
|
|
|
|
|
addOnload(node, callback, url)
|
|
|
|
|
|
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, url) {
|
|
|
var supportOnload = "onload" in node
|
|
|
|
|
|
if (supportOnload) {
|
|
|
node.onload = onload
|
|
|
node.onerror = function() {
|
|
|
emit("error", { uri: url, node: node })
|
|
|
onload(true)
|
|
|
}
|
|
|
}
|
|
|
else {
|
|
|
node.onreadystatechange = function() {
|
|
|
if (/loaded|complete/.test(node.readyState)) {
|
|
|
onload()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function onload(error) {
|
|
|
// 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 (!data.debug) {
|
|
|
head.removeChild(node)
|
|
|
}
|
|
|
|
|
|
// Dereference the node
|
|
|
node = null
|
|
|
|
|
|
callback(error)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// For Developers
|
|
|
seajs.request = request
|
|
|
|
|
|
}
|
|
|
var interactiveScript
|
|
|
|
|
|
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
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* util-deps.js - The parser for dependencies
|
|
|
* ref: tests/research/parse-dependencies/test.html
|
|
|
* ref: https://github.com/seajs/searequire
|
|
|
*/
|
|
|
|
|
|
function parseDependencies(s) {
|
|
|
if(s.indexOf('require') == -1) {
|
|
|
return []
|
|
|
}
|
|
|
var index = 0, peek, length = s.length, isReg = 1, modName = 0, parentheseState = 0, parentheseStack = [], res = []
|
|
|
while(index < length) {
|
|
|
readch()
|
|
|
if(isBlank()) {
|
|
|
}
|
|
|
else if(isQuote()) {
|
|
|
dealQuote()
|
|
|
isReg = 1
|
|
|
}
|
|
|
else if(peek == '/') {
|
|
|
readch()
|
|
|
if(peek == '/') {
|
|
|
index = s.indexOf('\n', index)
|
|
|
if(index == -1) {
|
|
|
index = s.length
|
|
|
}
|
|
|
}
|
|
|
else if(peek == '*') {
|
|
|
index = s.indexOf('*/', index)
|
|
|
if(index == -1) {
|
|
|
index = length
|
|
|
}
|
|
|
else {
|
|
|
index += 2
|
|
|
}
|
|
|
}
|
|
|
else if(isReg) {
|
|
|
dealReg()
|
|
|
isReg = 0
|
|
|
}
|
|
|
else {
|
|
|
index--
|
|
|
isReg = 1
|
|
|
}
|
|
|
}
|
|
|
else if(isWord()) {
|
|
|
dealWord()
|
|
|
}
|
|
|
else if(isNumber()) {
|
|
|
dealNumber()
|
|
|
}
|
|
|
else if(peek == '(') {
|
|
|
parentheseStack.push(parentheseState)
|
|
|
isReg = 1
|
|
|
}
|
|
|
else if(peek == ')') {
|
|
|
isReg = parentheseStack.pop()
|
|
|
}
|
|
|
else {
|
|
|
isReg = peek != ']'
|
|
|
modName = 0
|
|
|
}
|
|
|
}
|
|
|
return res
|
|
|
function readch() {
|
|
|
peek = s.charAt(index++)
|
|
|
}
|
|
|
function isBlank() {
|
|
|
return /\s/.test(peek)
|
|
|
}
|
|
|
function isQuote() {
|
|
|
return peek == '"' || peek == "'"
|
|
|
}
|
|
|
function dealQuote() {
|
|
|
var start = index
|
|
|
var c = peek
|
|
|
var end = s.indexOf(c, start)
|
|
|
if(end == -1) {
|
|
|
index = length
|
|
|
}
|
|
|
else if(s.charAt(end - 1) != '\\') {
|
|
|
index = end + 1
|
|
|
}
|
|
|
else {
|
|
|
while(index < length) {
|
|
|
readch()
|
|
|
if(peek == '\\') {
|
|
|
index++
|
|
|
}
|
|
|
else if(peek == c) {
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if(modName) {
|
|
|
res.push(s.slice(start, index - 1))
|
|
|
modName = 0
|
|
|
}
|
|
|
}
|
|
|
function dealReg() {
|
|
|
index--
|
|
|
while(index < length) {
|
|
|
readch()
|
|
|
if(peek == '\\') {
|
|
|
index++
|
|
|
}
|
|
|
else if(peek == '/') {
|
|
|
break
|
|
|
}
|
|
|
else if(peek == '[') {
|
|
|
while(index < length) {
|
|
|
readch()
|
|
|
if(peek == '\\') {
|
|
|
index++
|
|
|
}
|
|
|
else if(peek == ']') {
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
function isWord() {
|
|
|
return /[a-z_$]/i.test(peek)
|
|
|
}
|
|
|
function dealWord() {
|
|
|
var s2 = s.slice(index - 1)
|
|
|
var r = /^[\w$]+/.exec(s2)[0]
|
|
|
parentheseState = {
|
|
|
'if': 1,
|
|
|
'for': 1,
|
|
|
'while': 1,
|
|
|
'with': 1
|
|
|
}[r]
|
|
|
isReg = {
|
|
|
'break': 1,
|
|
|
'case': 1,
|
|
|
'continue': 1,
|
|
|
'debugger': 1,
|
|
|
'delete': 1,
|
|
|
'do': 1,
|
|
|
'else': 1,
|
|
|
'false': 1,
|
|
|
'if': 1,
|
|
|
'in': 1,
|
|
|
'instanceof': 1,
|
|
|
'return': 1,
|
|
|
'typeof': 1,
|
|
|
'void': 1
|
|
|
}[r]
|
|
|
modName = /^require\s*\(\s*(['"]).+?\1\s*\)/.test(s2)
|
|
|
if(modName) {
|
|
|
r = /^require\s*\(\s*['"]/.exec(s2)[0]
|
|
|
index += r.length - 2
|
|
|
}
|
|
|
else {
|
|
|
index += /^[\w$]+(?:\s*\.\s*[\w$]+)*/.exec(s2)[0].length - 1
|
|
|
}
|
|
|
}
|
|
|
function isNumber() {
|
|
|
return /\d/.test(peek)
|
|
|
|| peek == '.' && /\d/.test(s.charAt(index))
|
|
|
}
|
|
|
function dealNumber() {
|
|
|
var s2 = s.slice(index - 1)
|
|
|
var r
|
|
|
if(peek == '.') {
|
|
|
r = /^\.\d+(?:E[+-]?\d*)?\s*/i.exec(s2)[0]
|
|
|
}
|
|
|
else if(/^0x[\da-f]*/i.test(s2)) {
|
|
|
r = /^0x[\da-f]*\s*/i.exec(s2)[0]
|
|
|
}
|
|
|
else {
|
|
|
r = /^\d+\.?\d*(?:E[+-]?\d*)?\s*/i.exec(s2)[0]
|
|
|
}
|
|
|
index += r.length - 1
|
|
|
isReg = 0
|
|
|
}
|
|
|
}
|
|
|
/**
|
|
|
* 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,
|
|
|
// 7 - 404
|
|
|
ERROR: 7
|
|
|
}
|
|
|
|
|
|
|
|
|
function Module(uri, deps) {
|
|
|
this.uri = uri
|
|
|
this.dependencies = deps || []
|
|
|
this.deps = {} // Ref the dependence modules
|
|
|
this.status = 0
|
|
|
|
|
|
this._entry = []
|
|
|
}
|
|
|
|
|
|
// 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
|
|
|
}
|
|
|
|
|
|
Module.prototype.pass = function() {
|
|
|
var mod = this
|
|
|
|
|
|
var len = mod.dependencies.length
|
|
|
|
|
|
for (var i = 0; i < mod._entry.length; i++) {
|
|
|
var entry = mod._entry[i]
|
|
|
var count = 0
|
|
|
for (var j = 0; j < len; j++) {
|
|
|
var m = mod.deps[mod.dependencies[j]]
|
|
|
// If the module is unload and unused in the entry, pass entry to it
|
|
|
if (m.status < STATUS.LOADED && !entry.history.hasOwnProperty(m.uri)) {
|
|
|
entry.history[m.uri] = true
|
|
|
count++
|
|
|
m._entry.push(entry)
|
|
|
if(m.status === STATUS.LOADING) {
|
|
|
m.pass()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// If has passed the entry to it's dependencies, modify the entry's count and del it in the module
|
|
|
if (count > 0) {
|
|
|
entry.remain += count - 1
|
|
|
mod._entry.shift()
|
|
|
i--
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 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)
|
|
|
|
|
|
for (var i = 0, len = uris.length; i < len; i++) {
|
|
|
mod.deps[mod.dependencies[i]] = Module.get(uris[i])
|
|
|
}
|
|
|
|
|
|
// Pass entry to it's dependencies
|
|
|
mod.pass()
|
|
|
|
|
|
// If module has entries not be passed, call onload
|
|
|
if (mod._entry.length) {
|
|
|
mod.onload()
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// Begin parallel loading
|
|
|
var requestCache = {}
|
|
|
var m
|
|
|
|
|
|
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
|
|
|
|
|
|
// When sometimes cached in IE, exec will occur before onload, make sure len is an number
|
|
|
for (var i = 0, len = (mod._entry || []).length; i < len; i++) {
|
|
|
var entry = mod._entry[i]
|
|
|
if (--entry.remain === 0) {
|
|
|
entry.callback()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
delete mod._entry
|
|
|
}
|
|
|
|
|
|
// Call this method when module is 404
|
|
|
Module.prototype.error = function() {
|
|
|
var mod = this
|
|
|
mod.onload()
|
|
|
mod.status = STATUS.ERROR
|
|
|
}
|
|
|
|
|
|
// 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
|
|
|
|
|
|
if (mod._entry && !mod._entry.length) {
|
|
|
delete mod._entry
|
|
|
}
|
|
|
|
|
|
//non-cmd module has no property factory and exports
|
|
|
if (!mod.hasOwnProperty('factory')) {
|
|
|
mod.non = true
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// Create require
|
|
|
var uri = mod.uri
|
|
|
|
|
|
function require(id) {
|
|
|
var m = mod.deps[id] || Module.get(require.resolve(id))
|
|
|
if (m.status == STATUS.ERROR) {
|
|
|
throw new Error('module was broken: ' + m.uri);
|
|
|
}
|
|
|
return m.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 mod.exports
|
|
|
}
|
|
|
|
|
|
// 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.hasOwnProperty(requestUri)) {
|
|
|
mod.load()
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if (fetchingList.hasOwnProperty(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: isFunction(data.charset) ? data.charset(requestUri) || 'utf-8' : data.charset
|
|
|
})
|
|
|
|
|
|
if (!emitData.requested) {
|
|
|
requestCache ?
|
|
|
requestCache[emitData.requestUri] = sendRequest :
|
|
|
sendRequest()
|
|
|
}
|
|
|
|
|
|
function sendRequest() {
|
|
|
seajs.request(emitData.requestUri, emitData.onRequest, emitData.charset)
|
|
|
}
|
|
|
|
|
|
function onRequest(error) {
|
|
|
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())) {
|
|
|
// When 404 occurs, the params error will be true
|
|
|
if(error === true) {
|
|
|
m.error()
|
|
|
}
|
|
|
else {
|
|
|
m.load()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 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 = typeof parseDependencies === "undefined" ? [] : 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 (!isWebWorker && !meta.uri && doc.attachEvent && typeof getCurrentScript !== "undefined") {
|
|
|
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
|
|
|
|
|
|
emit("save", mod)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 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._entry.push(mod)
|
|
|
mod.history = {}
|
|
|
mod.remain = 1
|
|
|
|
|
|
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
|
|
|
delete mod.history
|
|
|
delete mod.remain
|
|
|
delete mod._entry
|
|
|
}
|
|
|
|
|
|
mod.load()
|
|
|
}
|
|
|
|
|
|
|
|
|
// Public API
|
|
|
|
|
|
seajs.use = function(ids, callback) {
|
|
|
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
|
|
|
*/
|
|
|
|
|
|
// The root path to use for id2uri parsing
|
|
|
data.base = loaderDir
|
|
|
|
|
|
// The loader directory
|
|
|
data.dir = loaderDir
|
|
|
|
|
|
// The loader's full path
|
|
|
data.loader = loaderPath
|
|
|
|
|
|
// The current working directory
|
|
|
data.cwd = cwd
|
|
|
|
|
|
// The charset for requesting files
|
|
|
data.charset = "utf-8"
|
|
|
|
|
|
// 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
|
|
|
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);
|
|
|
|
|
|
seajs.config({
|
|
|
base: 'http://localhost:8000',
|
|
|
charset: 'utf-8'
|
|
|
}); |
|
|
\ No newline at end of file |
...
|
...
|
|