Created
October 15, 2012 08:25
-
-
Save undoZen/3891433 to your computer and use it in GitHub Desktop.
ydiff bug
This file contains 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
<html> | |
<head> | |
<META http-equiv="Content-Type" content="text/html; charset=utf-8"> | |
<LINK href="diff-s.css" rel="stylesheet" type="text/css"> | |
<script type="text/javascript" src="nav-div.js"></script> | |
</head> | |
<body> | |
<div id="left" class="src"> | |
<pre> | |
<a id='leftstart' tid='rightstart'></a> | |
/** | |
* @preserve SeaJS - A Module Loader for the Web | |
* v1.2.1 | seajs.org | MIT Licensed | |
*/ | |
/** | |
* Base namespace for the framework. | |
*/ | |
<a id='1' tid='2' class='m'>this</a>.<a id='3' tid='4' class='m'>seajs</a> <a id='5' tid='6' class='m'>=</a> { <a id='7' tid='8' class='m'>_seajs</a>: <a id='9' tid='10' class='m'>this</a>.<a id='11' tid='12' class='m'>seajs</a> } | |
/** | |
* The version of the framework. It will be replaced with "major.minor.patch" | |
* when building. | |
*/ | |
<span class='d'>seajs.version = '1.2.1'</span> | |
/** | |
* The private utilities. Internal use only. | |
*/ | |
<span class='d'>seajs._util</span> = {} | |
/** | |
* The private configuration data. Internal use only. | |
*/ | |
seajs._config = { | |
/** | |
* Debug mode. It will be turned off automatically when compressing. | |
*/ | |
debug: '%DEBUG%', | |
/** | |
* Modules that are needed to load before all other modules. | |
*/ | |
preload: [] | |
} | |
/** | |
* The minimal language enhancement | |
*/ | |
;(function(util) { | |
var toString = Object.prototype.toString | |
var AP = Array.prototype | |
util.isString = function(val) { | |
return toString.call(val) === '[object String]' | |
} | |
util.isFunction = function(val) { | |
return toString.call(val) === '[object Function]' | |
} | |
util.isRegExp = function(val) { | |
return toString.call(val) === '[object RegExp]' | |
} | |
util.isObject = function(val) { | |
return val === Object(val) | |
} | |
util.isArray = Array.isArray || function(val) { | |
return toString.call(val) === '[object Array]' | |
} | |
util.indexOf = AP.indexOf ? | |
function(arr, item) { | |
return arr.indexOf(item) | |
} : | |
function(arr, item) { | |
for (var i = 0; i < arr.length; i++) { | |
if (arr[i] === item) { | |
return i | |
} | |
} | |
return -1 | |
} | |
var forEach = util.forEach = AP.forEach ? | |
function(arr, fn) { | |
arr.forEach(fn) | |
} : | |
function(arr, fn) { | |
for (var i = 0; i < arr.length; i++) { | |
fn(arr[i], i, arr) | |
} | |
} | |
util.map = AP.map ? | |
function(arr, fn) { | |
return arr.map(fn) | |
} : | |
function(arr, fn) { | |
var ret = [] | |
forEach(arr, function(item, i, arr) { | |
ret.push(fn(item, i, arr)) | |
}) | |
return ret | |
} | |
util.filter = AP.filter ? | |
function(arr, fn) { | |
return arr.filter(fn) | |
} : | |
function(arr, fn) { | |
var ret = [] | |
forEach(arr, function(item, i, arr) { | |
if (fn(item, i, arr)) { | |
ret.push(item) | |
} | |
}) | |
return ret | |
} | |
var keys = util.keys = Object.keys || function(o) { | |
var ret = [] | |
for (var p in o) { | |
if (o.hasOwnProperty(p)) { | |
ret.push(p) | |
} | |
} | |
return ret | |
} | |
util.unique = function(arr) { | |
var o = {} | |
forEach(arr, function(item) { | |
o[item] = 1 | |
}) | |
return keys(o) | |
} | |
util.now = Date.now || function() { | |
return new Date().getTime() | |
} | |
})(seajs._util) | |
/** | |
* The tiny console | |
*/ | |
;(function(util, config) { | |
var AP = Array.prototype | |
/** | |
* The safe wrapper of console.log/error/... | |
*/ | |
util.log = function() { | |
if (typeof console !== 'undefined') { | |
var args = AP.slice.call(arguments) | |
var type = 'log' | |
var last = args[args.length - 1] | |
console[last] && (type = args.pop()) | |
// Only show log info in debug mode | |
if (type === 'log' && !config.debug) return | |
var out = type === 'dir' ? args[0] : AP.join.call(args, ' ') | |
console[type](out) | |
} | |
} | |
})(seajs._util, seajs._config) | |
/** | |
* Path utilities | |
*/ | |
;(function(util, config, global) { | |
var DIRNAME_RE = /.*(?=\/.*$)/ | |
var MULTIPLE_SLASH_RE = /([^:\/])\/\/+/g | |
var FILE_EXT_RE = /\.(?:css|js)$/ | |
var ROOT_RE = /^(.*?\w)(?:\/|$)/ | |
/** | |
* Extracts the directory portion of a path. | |
* dirname('a/b/c.js') ==> 'a/b/' | |
* dirname('d.js') ==> './' | |
* @see http://jsperf.com/regex-vs-split/2 | |
*/ | |
function dirname(path) { | |
var s = path.match(DIRNAME_RE) | |
return (s ? s[0] : '.') + '/' | |
} | |
/** | |
* Canonicalizes a path. | |
* realpath('./a//b/../c') ==> 'a/c' | |
*/ | |
function realpath(path) { | |
MULTIPLE_SLASH_RE.lastIndex = 0 | |
// 'file:///a//b/c' ==> 'file:///a/b/c' | |
// 'http://a//b/c' ==> 'http://a/b/c' | |
if (MULTIPLE_SLASH_RE.test(path)) { | |
path = path.replace(MULTIPLE_SLASH_RE, '$1\/') | |
} | |
// 'a/b/c', just return. | |
if (path.indexOf('.') === -1) { | |
return path | |
} | |
var original = path.split('/') | |
var ret = [], part | |
for (var i = 0; i < original.length; i++) { | |
part = original[i] | |
if (part === '..') { | |
if (ret.length === 0) { | |
throw new Error('The path is invalid: ' + path) | |
} | |
ret.pop() | |
} | |
else if (part !== '.') { | |
ret.push(part) | |
} | |
} | |
return ret.join('/') | |
} | |
/** | |
* Normalizes an uri. | |
*/ | |
function normalize(uri) { | |
uri = realpath(uri) | |
var lastChar = uri.charAt(uri.length - 1) | |
if (lastChar === '/') { | |
return uri | |
} | |
// Adds the default '.js' extension except that the uri ends with #. | |
// ref: http://jsperf.com/get-the-last-character | |
if (lastChar === '#') { | |
uri = uri.slice(0, -1) | |
} | |
else if (uri.indexOf('?') === -1 && !FILE_EXT_RE.test(uri)) { | |
uri += '.js' | |
} | |
// Remove ':80/' for bug in IE | |
if (uri.indexOf(':80/') > 0) { | |
uri = uri.replace(':80/', '/') | |
} | |
return uri | |
} | |
/** | |
* Parses alias in the module id. Only parse the first part. | |
*/ | |
function parseAlias(id) { | |
// #xxx means xxx is already alias-parsed. | |
if (id.charAt(0) === '#') { | |
return id.substring(1) | |
} | |
var alias = config.alias | |
// Only top-level id needs to parse alias. | |
if (alias && isTopLevel(id)) { | |
var parts = id.split('/') | |
var first = parts[0] | |
if (alias.hasOwnProperty(first)) { | |
parts[0] = alias[first] | |
id = parts.join('/') | |
} | |
} | |
return id | |
} | |
var mapCache = {} | |
/** | |
* Converts the uri according to the map rules. | |
*/ | |
function parseMap(uri) { | |
// map: [[match, replace], ...] | |
var map = config.map || [] | |
if (!map.length) return uri | |
var ret = uri | |
// Apply all matched rules in sequence. | |
for (var i = 0; i < map.length; i++) { | |
var rule = map[i] | |
if (util.isArray(rule) && rule.length === 2) { | |
var m = rule[0] | |
if (util.isString(m) && ret.indexOf(m) > -1 || | |
util.isRegExp(m) && m.test(ret)) { | |
ret = ret.replace(m, rule[1]) | |
} | |
} | |
else if (util.isFunction(rule)) { | |
ret = rule(ret) | |
} | |
} | |
if (ret !== uri) { | |
mapCache[ret] = uri | |
} | |
return ret | |
} | |
/** | |
* Gets the original uri. | |
*/ | |
function unParseMap(uri) { | |
return mapCache[uri] || uri | |
} | |
/** | |
* Converts id to uri. | |
*/ | |
function id2Uri(id, refUri) { | |
if (!id) return '' | |
id = parseAlias(id) | |
refUri || (refUri = pageUri) | |
var ret | |
// absolute id | |
if (isAbsolute(id)) { | |
ret = id | |
} | |
// relative id | |
else if (isRelative(id)) { | |
// Converts './a' to 'a', to avoid unnecessary loop in realpath. | |
if (id.indexOf('./') === 0) { | |
id = id.substring(2) | |
} | |
ret = dirname(refUri) + id | |
} | |
// root id | |
else if (isRoot(id)) { | |
ret = refUri.match(ROOT_RE)[1] + id | |
} | |
// top-level id | |
else { | |
ret = config.base + '/' + id | |
} | |
return normalize(ret) | |
} | |
function isAbsolute(id) { | |
return id.indexOf('://') > 0 || id.indexOf('//') === 0 | |
} | |
function isRelative(id) { | |
return id.indexOf('./') === 0 || id.indexOf('../') === 0 | |
} | |
function isRoot(id) { | |
return id.charAt(0) === '/' && id.charAt(1) !== '/' | |
} | |
function isTopLevel(id) { | |
var c = id.charAt(0) | |
return id.indexOf('://') === -1 && c !== '.' && c !== '/' | |
} | |
/** | |
* Normalizes pathname to start with '/' | |
* Ref: https://groups.google.com/forum/#!topic/seajs/9R29Inqk1UU | |
*/ | |
function normalizePathname(pathname) { | |
if (pathname.charAt(0) !== '/') { | |
pathname = '/' + pathname | |
} | |
return pathname | |
} | |
var loc = global['location'] | |
var pageUri = loc.protocol + '//' + loc.host + | |
normalizePathname(loc.pathname) | |
// local file in IE: C:\path\to\xx.js | |
if (pageUri.indexOf('\\') > 0) { | |
pageUri = pageUri.replace(/\\/g, '/') | |
} | |
util.dirname = dirname | |
util.realpath = realpath | |
util.normalize = normalize | |
util.parseAlias = parseAlias | |
util.parseMap = parseMap | |
util.unParseMap = unParseMap | |
util.id2Uri = id2Uri | |
util.isAbsolute = isAbsolute | |
util.isRoot = isRoot | |
util.isTopLevel = isTopLevel | |
util.pageUri = pageUri | |
})(seajs._util, seajs._config, this) | |
/** | |
* Utilities for fetching js and css files | |
*/ | |
;(function(util, config) { | |
var doc = document | |
var head = doc.head || | |
doc.getElementsByTagName('head')[0] || | |
doc.documentElement | |
var baseElement = head.getElementsByTagName('base')[0] | |
var IS_CSS_RE = /\.css(?:\?|$)/i | |
var READY_STATE_RE = /loaded|complete|undefined/ | |
var currentlyAddingScript | |
var interactiveScript | |
util.fetch = function(url, callback, charset) { | |
var isCSS = IS_CSS_RE.test(url) | |
var node = document.createElement(isCSS ? 'link' : 'script') | |
if (charset) { | |
var cs = util.isFunction(charset) ? charset(url) : charset | |
cs && (node.charset = cs) | |
} | |
assetOnload(node, callback || noop) | |
if (isCSS) { | |
node.rel = 'stylesheet' | |
node.href = url | |
} else { | |
node.async = 'async' | |
node.src = url | |
} | |
// For some cache cases in IE 6-9, the script executes IMMEDIATELY after | |
// the end of the insertBefore execution, so use `currentlyAddingScript` | |
// to hold current node, for deriving url in `define`. | |
currentlyAddingScript = node | |
// ref: #185 & http://dev.jquery.com/ticket/2709 | |
baseElement ? | |
head.insertBefore(node, baseElement) : | |
head.appendChild(node) | |
currentlyAddingScript = null | |
} | |
function assetOnload(node, callback) { | |
if (node.nodeName === 'SCRIPT') { | |
scriptOnload(node, callback) | |
} else { | |
styleOnload(node, callback) | |
} | |
} | |
function scriptOnload(node, callback) { | |
node.onload = node.onerror = node.onreadystatechange = function() { | |
if (READY_STATE_RE.test(node.readyState)) { | |
// 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 (node.parentNode && !config.debug) { | |
head.removeChild(node) | |
} | |
// Dereference the node | |
node = undefined | |
callback() | |
} | |
} | |
} | |
function styleOnload(node, callback) { | |
// for Old WebKit and Old Firefox | |
if (isOldWebKit || isOldFirefox) { | |
util.log('Start poll to fetch css') | |
setTimeout(function() { | |
poll(node, callback) | |
}, 1) // Begin after node insertion | |
} | |
else { | |
node.onload = node.onerror = function() { | |
node.onload = node.onerror = null | |
node = undefined | |
callback() | |
} | |
} | |
} | |
function poll(node, callback) { | |
var isLoaded | |
// for WebKit < 536 | |
if (isOldWebKit) { | |
if (node['sheet']) { | |
isLoaded = true | |
} | |
} | |
// for Firefox < 9.0 | |
else if (node['sheet']) { | |
try { | |
if (node['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 in here due to giving time for style rendering. | |
callback() | |
} else { | |
poll(node, callback) | |
} | |
}, 1) | |
} | |
function noop() { | |
} | |
util.getCurrentScript = function() { | |
if (currentlyAddingScript) { | |
return currentlyAddingScript | |
} | |
// For IE6-9 browsers, the script onload event may not fire right | |
// after the 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 = 0; i < scripts.length; i++) { | |
var script = scripts[i] | |
if (script.readyState === 'interactive') { | |
interactiveScript = script | |
return script | |
} | |
} | |
} | |
util.getScriptAbsoluteSrc = function(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) | |
} | |
util.importStyle = function(cssText, id) { | |
// Don't add multi times | |
if (id && doc.getElementById(id)) return | |
var element = doc.createElement('style') | |
id && (element.id = id) | |
// Adds to DOM first to avoid the css hack invalid | |
head.appendChild(element) | |
// IE | |
if (element.styleSheet) { | |
element.styleSheet.cssText = cssText | |
} | |
// W3C | |
else { | |
element.appendChild(doc.createTextNode(cssText)) | |
} | |
} | |
var UA = navigator.userAgent | |
// `onload` event is supported in WebKit since 535.23 | |
// Ref: | |
// - https://bugs.webkit.org/show_activity.cgi?id=38995 | |
var isOldWebKit = Number(UA.replace(/.*AppleWebKit\/(\d+)\..*/, '$1')) < 536 | |
// `onload/onerror` event is supported since Firefox 9.0 | |
// Ref: | |
// - https://bugzilla.mozilla.org/show_bug.cgi?id=185236 | |
// - https://developer.mozilla.org/en/HTML/Element/link#Stylesheet_load_events | |
var isOldFirefox = UA.indexOf('Firefox') > 0 && | |
!('onload' in document.createElement('link')) | |
/** | |
* References: | |
* - http://unixpapa.com/js/dyna.html | |
* - ../test/research/load-js-css/test.html | |
* - ../test/issues/load-css/test.html | |
* - http://www.blaze.io/technical/ies-premature-execution-problem/ | |
*/ | |
})(seajs._util, seajs._config, this) | |
/** | |
* The parser for dependencies | |
*/ | |
;(function(util) { | |
var REQUIRE_RE = /(?:^|[^.$])\brequire\s*\(\s*(["'])([^"'\s\)]+)\1\s*\)/g | |
util.parseDependencies = function(code) { | |
// Parse these `requires`: | |
// var a = require('a'); | |
// someMethod(require('b')); | |
// require('c'); | |
// ... | |
// Doesn't parse: | |
// someInstance.require(...); | |
var ret = [], match | |
code = removeComments(code) | |
REQUIRE_RE.lastIndex = 0 | |
while ((match = REQUIRE_RE.exec(code))) { | |
if (match[2]) { | |
ret.push(match[2]) | |
} | |
} | |
return util.unique(ret) | |
} | |
// See: research/remove-comments-safely | |
function removeComments(code) { | |
return code | |
.replace(/^\s*\/\*[\s\S]*?\*\/\s*$/mg, '') // block comments | |
.replace(/^\s*\/\/.*$/mg, '') // line comments | |
} | |
})(seajs._util) | |
/** | |
* The core of loader | |
*/ | |
;(function(seajs, util, config) { | |
var cachedModules = {} | |
var cachedModifiers = {} | |
var compileStack = [] | |
var STATUS = { | |
'FETCHING': 1, // The module file is fetching now. | |
'FETCHED': 2, // The module file has been fetched. | |
'SAVED': 3, // The module info has been saved. | |
'READY': 4, // All dependencies and self are ready to compile. | |
'COMPILING': 5, // The module is in compiling now. | |
'COMPILED': 6 // The module is compiled and module.exports is available. | |
} | |
function Module(uri, status) { | |
this.uri = uri | |
this.status = status || 0 | |
// this.id is set when saving | |
// this.dependencies is set when saving | |
// this.factory is set when saving | |
// this.exports is set when compiling | |
// this.parent is set when compiling | |
// this.require is set when compiling | |
} | |
Module.prototype._use = function(ids, callback) { | |
util.isString(ids) && (ids = [ids]) | |
var uris = resolve(ids, this.uri) | |
this._load(uris, function() { | |
var args = util.map(uris, function(uri) { | |
return uri ? cachedModules[uri]._compile() : null | |
}) | |
if (callback) { | |
callback.apply(null, args) | |
} | |
}) | |
} | |
Module.prototype._load = function(uris, callback) { | |
var unLoadedUris = util.filter(uris, function(uri) { | |
return uri && (!cachedModules[uri] || | |
cachedModules[uri].status < STATUS.READY) | |
}) | |
var length = unLoadedUris.length | |
if (length === 0) { | |
callback() | |
return | |
} | |
var remain = length | |
for (var i = 0; i < length; i++) { | |
(function(uri) { | |
var module = cachedModules[uri] || | |
(cachedModules[uri] = new Module(uri, STATUS.FETCHING)) | |
module.status >= STATUS.FETCHED ? onFetched() : fetch(uri, onFetched) | |
function onFetched() { | |
// cachedModules[uri] is changed in un-correspondence case | |
module = cachedModules[uri] | |
if (module.status >= STATUS.SAVED) { | |
var deps = getPureDependencies(module) | |
if (deps.length) { | |
Module.prototype._load(deps, function() { | |
cb(module) | |
}) | |
} | |
else { | |
cb(module) | |
} | |
} | |
// Maybe failed to fetch successfully, such as 404 or non-module. | |
// // In these cases, module.status stay at FETCHING or FETCHED. | |
else { | |
util.log('It is not a valid CMD module: ' + uri) | |
cb() | |
} | |
} | |
})(unLoadedUris[i]) | |
} | |
function cb(module) { | |
(module || {}).status < STATUS.READY && (module.status = STATUS.READY) | |
--remain === 0 && callback() | |
} | |
} | |
Module.prototype._compile = function() { | |
var module = this | |
if (module.status === STATUS.COMPILED) { | |
return module.exports | |
} | |
// Just return null when: | |
// 1. the module file is 404. | |
// 2. the module file is not written with valid module format. | |
// 3. other error cases. | |
if (module.status < STATUS.READY && !hasModifiers(module)) { | |
return null | |
} | |
module.status = STATUS.COMPILING | |
function require(id) { | |
var uri = resolve(id, module.uri) | |
var child = cachedModules[uri] | |
// Just return null when uri is invalid. | |
if (!child) { | |
return null | |
} | |
// Avoids circular calls. | |
if (child.status === STATUS.COMPILING) { | |
return child.exports | |
} | |
child.parent = module | |
return child._compile() | |
} | |
require.async = function(ids, callback) { | |
module._use(ids, callback) | |
} | |
require.resolve = function(id) { | |
return resolve(id, module.uri) | |
} | |
require.cache = cachedModules | |
module.require = require | |
module.exports = {} | |
var factory = module.factory | |
if (util.isFunction(factory)) { | |
compileStack.push(module) | |
runInModuleContext(factory, module) | |
compileStack.pop() | |
} | |
else if (factory !== undefined) { | |
module.exports = factory | |
} | |
module.status = STATUS.COMPILED | |
execModifiers(module) | |
return module.exports | |
} | |
Module._define = function(id, deps, factory) { | |
var argsLength = arguments.length | |
// define(factory) | |
if (argsLength === 1) { | |
factory = id | |
id = undefined | |
} | |
// define(id || deps, factory) | |
else if (argsLength === 2) { | |
factory = deps | |
deps = undefined | |
// define(deps, factory) | |
if (util.isArray(id)) { | |
deps = id | |
id = undefined | |
} | |
} | |
// Parses dependencies. | |
if (!util.isArray(deps) && util.isFunction(factory)) { | |
deps = util.parseDependencies(factory.toString()) | |
} | |
var meta = { id: id, dependencies: deps, factory: factory } | |
var derivedUri | |
// Try to derive uri in IE6-9 for anonymous modules. | |
if (document.attachEvent) { | |
// Try to get the current script. | |
var script = util.getCurrentScript() | |
if (script) { | |
derivedUri = util.unParseMap(util.getScriptAbsoluteSrc(script)) | |
} | |
if (!derivedUri) { | |
util.log('Failed to derive URI from interactive script for:', | |
factory.toString(), 'warn') | |
// NOTE: If the id-deriving methods above is failed, then falls back | |
// to use onload event to get the uri. | |
} | |
} | |
// Gets uri directly for specific module. | |
var resolvedUri = id ? resolve(id) : derivedUri | |
if (resolvedUri) { | |
// For IE: | |
// If the first module in a package is not the cachedModules[derivedUri] | |
// self, it should assign to the correct module when found. | |
if (resolvedUri === derivedUri) { | |
var refModule = cachedModules[derivedUri] | |
if (refModule && refModule.realUri && | |
refModule.status === STATUS.SAVED) { | |
cachedModules[derivedUri] = null | |
} | |
} | |
var module = save(resolvedUri, meta) | |
// For IE: | |
// Assigns the first module in package to cachedModules[derivedUrl] | |
if (derivedUri) { | |
// cachedModules[derivedUri] may be undefined in combo case. | |
if ((cachedModules[derivedUri] || {}).status === STATUS.FETCHING) { | |
cachedModules[derivedUri] = module | |
module.realUri = derivedUri | |
} | |
} | |
else { | |
firstModuleInPackage || (firstModuleInPackage = module) | |
} | |
} | |
else { | |
// Saves information for "memoizing" work in the onload event. | |
anonymousModuleMeta = meta | |
} | |
} | |
Module._getCompilingModule = function() { | |
return compileStack[compileStack.length - 1] | |
} | |
Module._find = function(selector) { | |
var matches = [] | |
util.forEach(util.keys(cachedModules), function(uri) { | |
if (util.isString(selector) && uri.indexOf(selector) > -1 || | |
util.isRegExp(selector) && selector.test(uri)) { | |
var module = cachedModules[uri] | |
module.exports && matches.push(module.exports) | |
} | |
}) | |
return matches | |
} | |
Module._modify = function(id, modifier) { | |
var uri = resolve(id) | |
var module = cachedModules[uri] | |
if (module && module.status === STATUS.COMPILED) { | |
runInModuleContext(modifier, module) | |
} | |
else { | |
cachedModifiers[uri] || (cachedModifiers[uri] = []) | |
cachedModifiers[uri].push(modifier) | |
} | |
return seajs | |
} | |
// For plugin developers | |
Module.STATUS = STATUS | |
Module._resolve = util.id2Uri | |
Module._fetch = util.fetch | |
Module.cache = cachedModules | |
// Helpers | |
// ------- | |
var fetchingList = {} | |
var fetchedList = {} | |
var callbackList = {} | |
var anonymousModuleMeta = null | |
var firstModuleInPackage = null | |
var circularCheckStack = [] | |
function resolve(ids, refUri) { | |
if (util.isString(ids)) { | |
return Module._resolve(ids, refUri) | |
} | |
return util.map(ids, function(id) { | |
return resolve(id, refUri) | |
}) | |
} | |
function fetch(uri, callback) { | |
var requestUri = util.parseMap(uri) | |
if (fetchedList[requestUri]) { | |
// See test/issues/debug-using-map | |
cachedModules[uri] = cachedModules[requestUri] | |
callback() | |
return | |
} | |
if (fetchingList[requestUri]) { | |
callbackList[requestUri].push(callback) | |
return | |
} | |
fetchingList[requestUri] = true | |
callbackList[requestUri] = [callback] | |
// Fetches it | |
Module._fetch( | |
requestUri, | |
function() { | |
fetchedList[requestUri] = true | |
// Updates module status | |
var module = cachedModules[uri] | |
if (module.status === STATUS.FETCHING) { | |
module.status = STATUS.FETCHED | |
} | |
// Saves anonymous module meta data | |
if (anonymousModuleMeta) { | |
save(uri, anonymousModuleMeta) | |
anonymousModuleMeta = null | |
} | |
// Assigns the first module in package to cachedModules[uri] | |
// See: test/issues/un-correspondence | |
if (firstModuleInPackage && module.status === STATUS.FETCHED) { | |
cachedModules[uri] = firstModuleInPackage | |
firstModuleInPackage.realUri = uri | |
} | |
firstModuleInPackage = null | |
// Clears | |
if (fetchingList[requestUri]) { | |
delete fetchingList[requestUri] | |
} | |
// Calls callbackList | |
if (callbackList[requestUri]) { | |
util.forEach(callbackList[requestUri], function(fn) { | |
fn() | |
}) | |
delete callbackList[requestUri] | |
} | |
}, | |
config.charset | |
) | |
} | |
function save(uri, meta) { | |
var module = cachedModules[uri] || (cachedModules[uri] = new Module(uri)) | |
// Don't override already saved module | |
if (module.status < STATUS.SAVED) { | |
// Lets anonymous module id equal to its uri | |
module.id = meta.id || uri | |
module.dependencies = resolve( | |
util.filter(meta.dependencies || [], function(dep) { | |
return !!dep | |
}), uri) | |
module.factory = meta.factory | |
// Updates module status | |
module.status = STATUS.SAVED | |
} | |
return module | |
} | |
function runInModuleContext(fn, module) { | |
var ret = fn(module.require, module.exports, module) | |
if (ret !== undefined) { | |
module.exports = ret | |
} | |
} | |
function hasModifiers(module) { | |
return !!cachedModifiers[module.realUri || module.uri] | |
} | |
function execModifiers(module) { | |
var uri = module.realUri || module.uri | |
var modifiers = cachedModifiers[uri] | |
if (modifiers) { | |
util.forEach(modifiers, function(modifier) { | |
runInModuleContext(modifier, module) | |
}) | |
delete cachedModifiers[uri] | |
} | |
} | |
function getPureDependencies(module) { | |
var uri = module.uri | |
return util.filter(module.dependencies, function(dep) { | |
circularCheckStack = [uri] | |
var isCircular = isCircularWaiting(cachedModules[dep], uri) | |
if (isCircular) { | |
circularCheckStack.push(uri) | |
printCircularLog(circularCheckStack) | |
} | |
return !isCircular | |
}) | |
} | |
function isCircularWaiting(module, uri) { | |
if (!module || module.status !== STATUS.SAVED) { | |
return false | |
} | |
circularCheckStack.push(module.uri) | |
var deps = module.dependencies | |
if (deps.length) { | |
if (util.indexOf(deps, uri) > -1) { | |
return true | |
} | |
for (var i = 0; i < deps.length; i++) { | |
if (isCircularWaiting(cachedModules[deps[i]], uri)) { | |
return true | |
} | |
} | |
return false | |
} | |
return false | |
} | |
function printCircularLog(stack, type) { | |
util.log('Found circular dependencies:', stack.join(' --> '), type) | |
} | |
// Public API | |
// ---------- | |
var globalModule = new Module(util.pageUri, STATUS.COMPILED) | |
seajs.use = function(ids, callback) { | |
var preloadMods = config.preload | |
if (preloadMods.length) { | |
// Loads preload modules before all other modules. | |
globalModule._use(preloadMods, function() { | |
config.preload = [] | |
globalModule._use(ids, callback) | |
}) | |
} | |
else { | |
globalModule._use(ids, callback) | |
} | |
return seajs | |
} | |
// For normal users | |
seajs.define = Module._define | |
seajs.cache = Module.cache | |
seajs.find = Module._find | |
seajs.modify = Module._modify | |
// For plugin developers | |
seajs.pluginSDK = { | |
Module: Module, | |
util: util, | |
config: config | |
} | |
})(seajs, seajs._util, seajs._config) | |
/** | |
* The configuration | |
*/ | |
;(function(seajs, util, config) { | |
var noCachePrefix = 'seajs-ts=' | |
var noCacheTimeStamp = noCachePrefix + util.now() | |
// Async inserted script | |
var loaderScript = document.getElementById('seajsnode') | |
// Static script | |
if (!loaderScript) { | |
var scripts = document.getElementsByTagName('script') | |
loaderScript = scripts[scripts.length - 1] | |
} | |
var loaderSrc = util.getScriptAbsoluteSrc(loaderScript) || | |
util.pageUri // When sea.js is inline, set base to pageUri. | |
var base = util.dirname(getLoaderActualSrc(loaderSrc)) | |
util.loaderDir = base | |
// When src is "http://test.com/libs/seajs/1.0.0/sea.js", redirect base | |
// to "http://test.com/libs/" | |
var match = base.match(/^(.+\/)seajs\/[\d\.]+\/$/) | |
if (match) { | |
base = match[1] | |
} | |
config.base = base | |
var dataMain = loaderScript.getAttribute('data-main') | |
if (dataMain) { | |
config.main = dataMain | |
} | |
// The default charset of module file. | |
config.charset = 'utf-8' | |
/** | |
* The function to configure the framework | |
* config({ | |
* 'base': 'path/to/base', | |
* 'alias': { | |
* 'app': 'biz/xx', | |
* 'jquery': 'jquery-1.5.2', | |
* 'cart': 'cart?t=20110419' | |
* }, | |
* 'map': [ | |
* ['test.cdn.cn', 'localhost'] | |
* ], | |
* preload: [], | |
* charset: 'utf-8', | |
* debug: false | |
* }) | |
* | |
*/ | |
seajs.config = function(o) { | |
for (var k in o) { | |
if (!o.hasOwnProperty(k)) continue | |
var previous = config[k] | |
var current = o[k] | |
if (previous && k === 'alias') { | |
for (var p in current) { | |
if (current.hasOwnProperty(p)) { | |
var prevValue = previous[p] | |
var currValue = current[p] | |
// Converts {jquery: '1.7.2'} to {jquery: 'jquery/1.7.2/jquery'} | |
if (/^\d+\.\d+\.\d+$/.test(currValue)) { | |
currValue = p + '/' + currValue + '/' + p | |
} | |
checkAliasConflict(prevValue, currValue, p) | |
previous[p] = currValue | |
} | |
} | |
} | |
else if (previous && (k === 'map' || k === 'preload')) { | |
// for config({ preload: 'some-module' }) | |
if (util.isString(current)) { | |
current = [current] | |
} | |
util.forEach(current, function(item) { | |
if (item) { | |
previous.push(item) | |
} | |
}) | |
} | |
else { | |
config[k] = current | |
} | |
} | |
// Makes sure config.base is an absolute path. | |
var base = config.base | |
if (base && !util.isAbsolute(base)) { | |
config.base = util.id2Uri((util.isRoot(base) ? '' : './') + base + '/') | |
} | |
// Uses map to implement nocache. | |
if (config.debug === 2) { | |
config.debug = 1 | |
seajs.config({ | |
map: [ | |
[/^.*$/, function(url) { | |
if (url.indexOf(noCachePrefix) === -1) { | |
url += (url.indexOf('?') === -1 ? '?' : '&') + noCacheTimeStamp | |
} | |
return url | |
}] | |
] | |
}) | |
} | |
debugSync() | |
return this | |
} | |
function debugSync() { | |
if (config.debug) { | |
// For convenient reference | |
seajs.debug = !!config.debug | |
} | |
} | |
debugSync() | |
function getLoaderActualSrc(src) { | |
if (src.indexOf('??') === -1) { | |
return src | |
} | |
// Such as: http://cdn.com/??seajs/1.2.0/sea.js,jquery/1.7.2/jquery.js | |
// Only support nginx combo style rule. If you use other combo rule, please | |
// explicitly config the base path and the alias for plugins. | |
var parts = src.split('??') | |
var root = parts[0] | |
var paths = util.filter(parts[1].split(','), function(str) { | |
return str.indexOf('sea.js') !== -1 | |
}) | |
return root + paths[0] | |
} | |
function checkAliasConflict(previous, current, key) { | |
if (previous && previous !== current) { | |
util.log('The alias config is conflicted:', | |
'key =', '"' + key + '"', | |
'previous =', '"' + previous + '"', | |
'current =', '"' + current + '"', | |
'warn') | |
} | |
} | |
})(seajs, seajs._util, seajs._config) | |
/** | |
* Prepare for bootstrapping | |
*/ | |
;(function(seajs, util, global) { | |
// The safe and convenient version of console.log | |
seajs.log = util.log | |
// Creates a stylesheet from a text blob of rules. | |
seajs.importStyle = util.importStyle | |
// Sets a alias to `sea.js` directory for loading plugins. | |
seajs.config({ | |
alias: { seajs: util.loaderDir } | |
}) | |
// Uses `seajs-xxx` flag to load plugin-xxx. | |
util.forEach(getStartupPlugins(), function(name) { | |
seajs.use('seajs/plugin-' + name) | |
// Delays `seajs.use` calls to the onload of `mapfile` in debug mode. | |
if (name === 'debug') { | |
seajs._use = seajs.use | |
seajs._useArgs = [] | |
seajs.use = function() { seajs._useArgs.push(arguments); return seajs } | |
} | |
}) | |
// Helpers | |
// ------- | |
function getStartupPlugins() { | |
var ret = [] | |
var str = global.location.search | |
// Converts `seajs-xxx` to `seajs-xxx=1` | |
str = str.replace(/(seajs-\w+)(&|$)/g, '$1=1$2') | |
// Add cookie string | |
str += ' ' + document.cookie | |
// Excludes seajs-xxx=0 | |
str.replace(/seajs-(\w+)=[1-9]/g, function(m, name) { | |
ret.push(name) | |
}) | |
return util.unique(ret) | |
} | |
})(seajs, seajs._util, this) | |
/** | |
* The bootstrap and entrances | |
*/ | |
;(function(seajs, config, global) { | |
var _seajs = seajs._seajs | |
// Avoids conflicting when sea.js is loaded multi times. | |
if (_seajs && !_seajs['args']) { | |
global.seajs = seajs._seajs | |
return | |
} | |
// Assigns to global define. | |
global.define = seajs.define | |
// Loads the data-main module automatically. | |
config.main && seajs.use(config.main) | |
// Parses the pre-call of seajs.config/seajs.use/define. | |
// Ref: test/bootstrap/async-3.html | |
;(function(args) { | |
if (args) { | |
var hash = { | |
0: 'config', | |
1: 'use', | |
2: 'define' | |
} | |
for (var i = 0; i < args.length; i += 2) { | |
seajs[hash[args[i]]].apply(seajs, args[i + 1]) | |
} | |
} | |
})((_seajs || 0)['args']) | |
// Add define.amd property for clear indicator. | |
global.define.cmd = {} | |
// Keeps clean! | |
delete seajs.define | |
delete seajs._util | |
delete seajs._config | |
delete seajs._seajs | |
})(seajs, seajs._config, this) | |
</pre> | |
</div> | |
<div id="right" class="src"> | |
<pre> | |
<a id='rightstart' tid='leftstart'></a> | |
/* SeaJS v1.1.0 | seajs.com | MIT Licensed */ | |
/** | |
* @fileoverview A CommonJS module loader, focused on web. | |
* @author lifesinger@gmail.com (Frank Wang) | |
*/ | |
/** | |
* Base namespace for the framework. | |
*/ | |
<a id='2' tid='1' class='m'>this</a>.<a id='4' tid='3' class='m'>seajs</a> <a id='6' tid='5' class='m'>=</a> { <a id='8' tid='7' class='m'>_seajs</a>: <a id='10' tid='9' class='m'>this</a>.<a id='12' tid='11' class='m'>seajs</a> }; | |
/** | |
* @type {string} The version of the framework. It will be replaced | |
* with "major.minor.patch" when building. | |
*/ | |
<span class='i'>seajs.version = '1.1.0';</span> | |
// Module status: | |
// 1. downloaded - The script file has been downloaded to the browser. | |
// 2. define()d - The define() has been executed. | |
// 3. memoize()d - The module info has been added to memoizedMods. | |
// 4. require()d - The module.exports is available. | |
/** | |
* The private data. Internal use only. | |
*/ | |
<span class='i'>seajs._data</span> = { | |
/** | |
* The configuration data. | |
*/ | |
config: { | |
/** | |
* Debug mode. It will be turned off automatically when compressing. | |
* @const | |
*/ | |
debug: '%DEBUG%', | |
/** | |
* Modules that are needed to load before all other modules. | |
*/ | |
preload: [] | |
}, | |
/** | |
* Modules that have been memoize()d. | |
* { uri: { dependencies: [], factory: fn, exports: {} }, ... } | |
*/ | |
memoizedMods: {}, | |
/** | |
* Modules in current fetching package. | |
*/ | |
packageMods: [] | |
}; | |
/** | |
* The private utils. Internal use only. | |
*/ | |
seajs._util = {}; | |
/** | |
* The inner namespace for methods. Internal use only. | |
*/ | |
seajs._fn = {}; | |
/** | |
* @fileoverview The minimal language enhancement. | |
*/ | |
(function(util) { | |
var toString = Object.prototype.toString; | |
var AP = Array.prototype; | |
util.isString = function(val) { | |
return toString.call(val) === '[object String]'; | |
}; | |
util.isObject = function(val) { | |
return val === Object(val); | |
}; | |
util.isFunction = function(val) { | |
return toString.call(val) === '[object Function]'; | |
}; | |
util.isArray = Array.isArray || function(val) { | |
return toString.call(val) === '[object Array]'; | |
}; | |
util.indexOf = AP.indexOf ? | |
function(arr, item) { | |
return arr.indexOf(item); | |
} : | |
function(arr, item) { | |
for (var i = 0, len = arr.length; i < len; i++) { | |
if (arr[i] === item) { | |
return i; | |
} | |
} | |
return -1; | |
}; | |
var forEach = util.forEach = AP.forEach ? | |
function(arr, fn) { | |
arr.forEach(fn); | |
} : | |
function(arr, fn) { | |
for (var i = 0, len = arr.length; i < len; i++) { | |
fn(arr[i], i, arr); | |
} | |
}; | |
util.map = AP.map ? | |
function(arr, fn) { | |
return arr.map(fn); | |
} : | |
function(arr, fn) { | |
var ret = []; | |
forEach(arr, function(item, i, arr) { | |
ret.push(fn(item, i, arr)); | |
}); | |
return ret; | |
}; | |
util.filter = AP.filter ? | |
function(arr, fn) { | |
return arr.filter(fn); | |
} : | |
function(arr, fn) { | |
var ret = []; | |
forEach(arr, function(item, i, arr) { | |
if (fn(item, i, arr)) { | |
ret.push(item); | |
} | |
}); | |
return ret; | |
}; | |
util.unique = function(arr) { | |
var ret = []; | |
var o = {}; | |
forEach(arr, function(item) { | |
o[item] = 1; | |
}); | |
if (Object.keys) { | |
ret = Object.keys(o); | |
} | |
else { | |
for (var p in o) { | |
if (o.hasOwnProperty(p)) { | |
ret.push(p); | |
} | |
} | |
} | |
return ret; | |
}; | |
util.now = Date.now || function() { | |
return new Date().getTime(); | |
}; | |
})(seajs._util); | |
/** | |
* @fileoverview The error handler. | |
*/ | |
(function(util, data) { | |
util.error = function() { | |
throw join(arguments); | |
}; | |
util.log = function() { | |
if (data.config.debug && typeof console !== 'undefined') { | |
console.log(join(arguments)); | |
} | |
}; | |
function join(args) { | |
return Array.prototype.join.call(args, ' '); | |
} | |
})(seajs._util, seajs._data); | |
/** | |
* @fileoverview Core utilities for the framework. | |
*/ | |
(function(util, data, fn, global) { | |
var config = data.config; | |
/** | |
* Extracts the directory portion of a path. | |
* dirname('a/b/c.js') ==> 'a/b/' | |
* dirname('d.js') ==> './' | |
* @see http://jsperf.com/regex-vs-split/2 | |
*/ | |
function dirname(path) { | |
var s = path.match(/.*(?=\/.*$)/); | |
return (s ? s[0] : '.') + '/'; | |
} | |
/** | |
* Canonicalizes a path. | |
* realpath('./a//b/../c') ==> 'a/c' | |
*/ | |
function realpath(path) { | |
// 'file:///a//b/c' ==> 'file:///a/b/c' | |
// 'http://a//b/c' ==> 'http://a/b/c' | |
path = path.replace(/([^:\/])\/+/g, '$1\/'); | |
// 'a/b/c', just return. | |
if (path.indexOf('.') === -1) { | |
return path; | |
} | |
var old = path.split('/'); | |
var ret = [], part, i = 0, len = old.length; | |
for (; i < len; i++) { | |
part = old[i]; | |
if (part === '..') { | |
if (ret.length === 0) { | |
util.error('Invalid path:', path); | |
} | |
ret.pop(); | |
} | |
else if (part !== '.') { | |
ret.push(part); | |
} | |
} | |
return ret.join('/'); | |
} | |
/** | |
* Normalizes an url. | |
*/ | |
function normalize(url) { | |
url = realpath(url); | |
// Adds the default '.js' extension except that the url ends with #. | |
if (/#$/.test(url)) { | |
url = url.slice(0, -1); | |
} | |
else if (url.indexOf('?') === -1 && !/\.(?:css|js)$/.test(url)) { | |
url += '.js'; | |
} | |
return url; | |
} | |
/** | |
* Parses alias in the module id. Only parse the first part. | |
*/ | |
function parseAlias(id) { | |
// #xxx means xxx is parsed. | |
if (id.charAt(0) === '#') { | |
return id.substring(1); | |
} | |
var alias; | |
// Only top-level id needs to parse alias. | |
if (isTopLevel(id) && (alias = config.alias)) { | |
var parts = id.split('/'); | |
var first = parts[0]; | |
if (alias.hasOwnProperty(first)) { | |
parts[0] = alias[first]; | |
id = parts.join('/'); | |
} | |
} | |
return id; | |
} | |
var mapCache = {}; | |
/** | |
* Maps the module id. | |
* @param {string} url The url string. | |
* @param {Array=} map The optional map array. | |
*/ | |
function parseMap(url, map) { | |
// config.map: [[match, replace], ...] | |
map = map || config['map'] || []; | |
if (!map.length) return url; | |
var ret = url; | |
util.forEach(map, function(rule) { | |
if (rule && rule.length > 1) { | |
ret = ret.replace(rule[0], rule[1]); | |
} | |
}); | |
mapCache[ret] = url; | |
return ret; | |
} | |
/** | |
* Gets the original url. | |
* @param {string} url The url string. | |
*/ | |
function unParseMap(url) { | |
return mapCache[url] || url; | |
} | |
/** | |
* Gets the host portion from url. | |
*/ | |
function getHost(url) { | |
return url.replace(/^(\w+:\/\/[^\/]*)\/?.*$/, '$1'); | |
} | |
/** | |
* Normalizes pathname to start with '/' | |
* Ref: https://groups.google.com/forum/#!topic/seajs/9R29Inqk1UU | |
*/ | |
function normalizePathname(pathname) { | |
if (pathname.charAt(0) !== '/') { | |
pathname = '/' + pathname; | |
} | |
return pathname; | |
} | |
var loc = global['location']; | |
var pageUrl = loc.protocol + '//' + loc.host + | |
normalizePathname(loc.pathname); | |
// local file in IE: C:\path\to\xx.js | |
if (~pageUrl.indexOf('\\')) { | |
pageUrl = pageUrl.replace(/\\/g, '/'); | |
} | |
/** | |
* Converts id to uri. | |
* @param {string} id The module id. | |
* @param {string=} refUrl The referenced uri for relative id. | |
*/ | |
function id2Uri(id, refUrl) { | |
id = parseAlias(id); | |
refUrl = refUrl || pageUrl; | |
var ret; | |
// absolute id | |
if (isAbsolute(id)) { | |
ret = id; | |
} | |
// relative id | |
else if (isRelative(id)) { | |
// Converts './a' to 'a', to avoid unnecessary loop in realpath. | |
id = id.replace(/^\.\//, ''); | |
ret = dirname(refUrl) + id; | |
} | |
// root id | |
else if (isRoot(id)) { | |
ret = getHost(refUrl) + id; | |
} | |
// top-level id | |
else { | |
ret = config.base + '/' + id; | |
} | |
return normalize(ret); | |
} | |
function isAbsolute(id) { | |
return ~id.indexOf('://') || id.indexOf('//') === 0; | |
} | |
function isRelative(id) { | |
return id.indexOf('./') === 0 || id.indexOf('../') === 0; | |
} | |
function isRoot(id) { | |
return id.charAt(0) === '/' && id.charAt(1) !== '/'; | |
} | |
function isTopLevel(id) { | |
var c = id.charAt(0); | |
return id.indexOf('://') === -1 && c !== '.' && c !== '/'; | |
} | |
util.dirname = dirname; | |
util.realpath = realpath; | |
util.normalize = normalize; | |
util.parseAlias = parseAlias; | |
util.parseMap = parseMap; | |
util.unParseMap = unParseMap; | |
util.id2Uri = id2Uri; | |
util.isAbsolute = isAbsolute; | |
util.isTopLevel = isTopLevel; | |
util.pageUrl = pageUrl; | |
})(seajs._util, seajs._data, seajs._fn, this); | |
/** | |
* @fileoverview Utilities for fetching js ans css files. | |
*/ | |
(function(util, data) { | |
var head = document.head || | |
document.getElementsByTagName('head')[0] || | |
document.documentElement; | |
var UA = navigator.userAgent; | |
var isWebKit = ~UA.indexOf('AppleWebKit'); | |
util.getAsset = function(url, callback, charset) { | |
var isCSS = /\.css(?:\?|$)/i.test(url); | |
var node = document.createElement(isCSS ? 'link' : 'script'); | |
if (charset) { | |
node.charset = charset; | |
} | |
assetOnload(node, callback); | |
if (isCSS) { | |
node.rel = 'stylesheet'; | |
node.href = url; | |
head.appendChild(node); // Keep style cascading order | |
} | |
else { | |
node.async = 'async'; | |
node.src = url; | |
//For some cache cases in IE 6-8, the script executes before the end | |
//of the appendChild execution, so to tie an anonymous define | |
//call to the module name (which is stored on the node), hold on | |
//to a reference to this node, but clear after the DOM insertion. | |
currentlyAddingScript = node; | |
head.insertBefore(node, head.firstChild); | |
currentlyAddingScript = null; | |
} | |
}; | |
function assetOnload(node, callback) { | |
if (node.nodeName === 'SCRIPT') { | |
scriptOnload(node, cb); | |
} else { | |
styleOnload(node, cb); | |
} | |
var timer = setTimeout(function() { | |
util.log('Time is out:', node.src); | |
cb(); | |
}, data.config.timeout); | |
function cb() { | |
if (!cb.isCalled) { | |
cb.isCalled = true; | |
clearTimeout(timer); | |
callback(); | |
} | |
} | |
} | |
function scriptOnload(node, callback) { | |
node.onload = node.onerror = node.onreadystatechange = | |
function() { | |
if (/loaded|complete|undefined/.test(node.readyState)) { | |
// Ensure only run once | |
node.onload = node.onerror = node.onreadystatechange = null; | |
// Reduce memory leak | |
if (node.parentNode) { | |
try { | |
if (node.clearAttributes) { | |
node.clearAttributes(); | |
} | |
else { | |
for (var p in node) delete node[p]; | |
} | |
} catch (x) { | |
} | |
// Remove the script | |
head.removeChild(node); | |
} | |
// Dereference the node | |
node = undefined; | |
callback(); | |
} | |
}; | |
// NOTICE: | |
// Nothing will happen in Opera when the file status is 404. In this case, | |
// the callback will be called when time is out. | |
} | |
function styleOnload(node, callback) { | |
// for IE6-9 and Opera | |
if (node.attachEvent) { | |
node.attachEvent('onload', callback); | |
// NOTICE: | |
// 1. "onload" will be fired in IE6-9 when the file is 404, but in | |
// this situation, Opera does nothing, so fallback to timeout. | |
// 2. "onerror" doesn't fire in any browsers! | |
} | |
// Polling for Firefox, Chrome, Safari | |
else { | |
setTimeout(function() { | |
poll(node, callback); | |
}, 0); // Begin after node insertion | |
} | |
} | |
function poll(node, callback) { | |
if (callback.isCalled) { | |
return; | |
} | |
var isLoaded; | |
if (isWebKit) { | |
if (node['sheet']) { | |
isLoaded = true; | |
} | |
} | |
// for Firefox | |
else if (node['sheet']) { | |
try { | |
if (node['sheet'].cssRules) { | |
isLoaded = true; | |
} | |
} catch (ex) { | |
// NS_ERROR_DOM_SECURITY_ERR | |
if (ex.code === 1000) { | |
isLoaded = true; | |
} | |
} | |
} | |
setTimeout(function() { | |
if (isLoaded) { | |
// Place callback in here due to giving time for style rendering. | |
callback(); | |
} else { | |
poll(node, callback); | |
} | |
}, 1); | |
} | |
var currentlyAddingScript; | |
var interactiveScript; | |
util.getCurrentScript = function() { | |
if (currentlyAddingScript) { | |
return currentlyAddingScript; | |
} | |
// For IE6-9 browsers, the script onload event may not fire right | |
// after the 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 = 0; i < scripts.length; i++) { | |
var script = scripts[i]; | |
if (script.readyState === 'interactive') { | |
interactiveScript = script; | |
return script; | |
} | |
} | |
}; | |
util.getScriptAbsoluteSrc = function(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); | |
}; | |
util.isOpera = ~UA.indexOf('Opera'); | |
})(seajs._util, seajs._data); | |
/** | |
* references: | |
* - http://unixpapa.com/js/dyna.html | |
* - ../test/research/load-js-css/test.html | |
* - ../test/issues/load-css/test.html | |
*/ | |
/** | |
* @fileoverview Module Constructor. | |
*/ | |
(function(fn) { | |
/** | |
* Module constructor. | |
* @constructor | |
* @param {string=} id The module id. | |
* @param {Array.<string>|string=} deps The module dependencies. | |
* @param {function()|Object} factory The module factory function. | |
*/ | |
fn.Module = function(id, deps, factory) { | |
this.id = id; | |
this.dependencies = deps || []; | |
this.factory = factory; | |
}; | |
})(seajs._fn); | |
/** | |
* @fileoverview Module authoring format. | |
*/ | |
(function(util, data, fn) { | |
/** | |
* Defines a module. | |
* @param {string=} id The module id. | |
* @param {Array.<string>|string=} deps The module dependencies. | |
* @param {function()|Object} factory The module factory function. | |
*/ | |
function define(id, deps, factory) { | |
var argsLen = arguments.length; | |
// define(factory) | |
if (argsLen === 1) { | |
factory = id; | |
id = undefined; | |
} | |
// define(id || deps, factory) | |
else if (argsLen === 2) { | |
factory = deps; | |
deps = undefined; | |
// define(deps, factory) | |
if (util.isArray(id)) { | |
deps = id; | |
id = undefined; | |
} | |
} | |
// Parse dependencies | |
if (!util.isArray(deps) && util.isFunction(factory)) { | |
deps = parseDependencies(factory.toString()); | |
} | |
// Get url directly for specific modules. | |
if (id) { | |
var url = util.id2Uri(id); | |
} | |
// Try to derive url in IE6-9 for anonymous modules. | |
else if (document.attachEvent && !util.isOpera) { | |
// Try to get the current script | |
var script = util.getCurrentScript(); | |
if (script) { | |
url = util.unParseMap(util.getScriptAbsoluteSrc(script)); | |
} | |
if (!url) { | |
util.log('Failed to derive URL from interactive script for:', | |
factory.toString()); | |
// NOTE: If the id-deriving methods above is failed, then falls back | |
// to use onload event to get the url. | |
} | |
} | |
var mod = new fn.Module(id, deps, factory); | |
if (url) { | |
util.memoize(url, mod); | |
data.packageMods.push(mod); | |
} | |
else { | |
// Saves information for "memoizing" work in the onload event. | |
data.anonymousMod = mod; | |
} | |
} | |
function parseDependencies(code) { | |
// Parse these `requires`: | |
// var a = require('a'); | |
// someMethod(require('b')); | |
// require('c'); | |
// ... | |
// Doesn't parse: | |
// someInstance.require(...); | |
var pattern = /(?:^|[^.])\brequire\s*\(\s*(["'])([^"'\s\)]+)\1\s*\)/g; | |
var ret = [], match; | |
code = removeComments(code); | |
while ((match = pattern.exec(code))) { | |
if (match[2]) { | |
ret.push(match[2]); | |
} | |
} | |
return util.unique(ret); | |
} | |
// http://lifesinger.github.com/lab/2011/remove-comments-safely/ | |
function removeComments(code) { | |
return code | |
.replace(/(?:^|\n|\r)\s*\/\*[\s\S]*?\*\/\s*(?:\r|\n|$)/g, '\n') | |
.replace(/(?:^|\n|\r)\s*\/\/.*(?:\r|\n|$)/g, '\n'); | |
} | |
fn.define = define; | |
})(seajs._util, seajs._data, seajs._fn); | |
/** | |
* @fileoverview The factory for "require". | |
*/ | |
(function(util, data, fn) { | |
var slice = Array.prototype.slice; | |
var RP = Require.prototype; | |
/** | |
* the require constructor function | |
* @param {string} id The module id. | |
*/ | |
function Require(id) { | |
var context = this.context; | |
var uri, mod; | |
// require(mod) ** inner use ONLY. | |
if (util.isObject(id)) { | |
mod = id; | |
uri = mod.id; | |
} | |
// NOTICE: id maybe undefined in 404 etc cases. | |
else if (util.isString(id)) { | |
uri = RP.resolve(id, context); | |
mod = data.memoizedMods[uri]; | |
} | |
// Just return null when: | |
// 1. the module file is 404. | |
// 2. the module file is not written with valid module format. | |
// 3. other error cases. | |
if (!mod) { | |
return null; | |
} | |
// Checks circular dependencies. | |
if (isCircular(context, uri)) { | |
util.log('Found circular dependencies:', uri); | |
return mod.exports; | |
} | |
// Initializes module exports. | |
if (!mod.exports) { | |
initExports(mod, { | |
uri: uri, | |
parent: context | |
}); | |
} | |
return mod.exports; | |
} | |
/** | |
* Use the internal require() machinery to look up the location of a module, | |
* but rather than loading the module, just return the resolved filepath. | |
* | |
* @param {string|Array.<string>} ids The module ids to be resolved. | |
* @param {Object=} context The context of require function. | |
*/ | |
RP.resolve = function(ids, context) { | |
if (util.isString(ids)) { | |
return util.id2Uri(ids, (context || this.context || {}).uri); | |
} | |
return util.map(ids, function(id) { | |
return RP.resolve(id, context); | |
}); | |
}; | |
/** | |
* Loads the specified modules asynchronously and execute the optional | |
* callback when complete. | |
* @param {Array.<string>} ids The specified modules. | |
* @param {function(*)=} callback The optional callback function. | |
*/ | |
RP.async = function(ids, callback) { | |
fn.load(ids, callback, this.context); | |
}; | |
/** | |
* Plugin can override this method to add custom loading. | |
*/ | |
RP.load = function(uri, callback, charset) { | |
util.getAsset(uri, callback, charset); | |
}; | |
/** | |
* The factory of "require" function. | |
* @param {Object} context The data related to "require" instance. | |
*/ | |
function createRequire(context) { | |
// context: { | |
// uri: '', | |
// parent: context | |
// } | |
var that = { context: context || {} }; | |
function require(id) { | |
return Require.call(that, id); | |
} | |
require.constructor = Require; | |
for (var p in RP) { | |
if (RP.hasOwnProperty(p)) { | |
(function(name) { | |
require[name] = function() { | |
return RP[name].apply(that, slice.call(arguments)); | |
}; | |
})(p); | |
} | |
} | |
return require; | |
} | |
function initExports(mod, context) { | |
var ret; | |
var factory = mod.factory; | |
mod.exports = {}; | |
delete mod.factory; | |
delete mod.ready; | |
if (util.isFunction(factory)) { | |
ret = factory(createRequire(context), mod.exports, mod); | |
if (ret !== undefined) { | |
mod.exports = ret; | |
} | |
} | |
else if (factory !== undefined) { | |
mod.exports = factory; | |
} | |
} | |
function isCircular(context, uri) { | |
if (context.uri === uri) { | |
return true; | |
} | |
if (context.parent) { | |
return isCircular(context.parent, uri); | |
} | |
return false; | |
} | |
fn.Require = Require; | |
fn.createRequire = createRequire; | |
})(seajs._util, seajs._data, seajs._fn); | |
/** | |
* @fileoverview Loads a module and gets it ready to be require()d. | |
*/ | |
(function(util, data, fn) { | |
/** | |
* Modules that are being downloaded. | |
* { uri: scriptNode, ... } | |
*/ | |
var fetchingMods = {}; | |
var callbackList = {}; | |
var memoizedMods = data.memoizedMods; | |
var config = data.config; | |
var RP = fn.Require.prototype; | |
/** | |
* Loads preload modules before callback. | |
* @param {function()} callback The callback function. | |
*/ | |
function preload(callback) { | |
var preloadMods = config.preload; | |
var len = preloadMods.length; | |
if (len) { | |
config.preload = preloadMods.slice(len); | |
load(preloadMods, function() { | |
preload(callback); | |
}); | |
} | |
else { | |
callback(); | |
} | |
} | |
/** | |
* Loads modules to the environment. | |
* @param {Array.<string>} ids An array composed of module id. | |
* @param {function(*)=} callback The callback function. | |
* @param {Object=} context The context of current executing environment. | |
*/ | |
function load(ids, callback, context) { | |
preload(function() { | |
if (util.isString(ids)) { | |
ids = [ids]; | |
} | |
var uris = RP.resolve(ids, context); | |
provide(uris, function() { | |
var require = fn.createRequire(context); | |
var args = util.map(uris, function(uri) { | |
return require(data.memoizedMods[uri]); | |
}); | |
if (callback) { | |
callback.apply(null, args); | |
} | |
}); | |
}); | |
} | |
/** | |
* Provides modules to the environment. | |
* @param {Array.<string>} uris An array composed of module uri. | |
* @param {function()=} callback The callback function. | |
*/ | |
function provide(uris, callback) { | |
var unReadyUris = getUnReadyUris(uris); | |
if (unReadyUris.length === 0) { | |
return onProvide(); | |
} | |
for (var i = 0, n = unReadyUris.length, remain = n; i < n; i++) { | |
(function(uri) { | |
if (memoizedMods[uri]) { | |
onLoad(); | |
} else { | |
fetch(uri, onLoad); | |
} | |
function onLoad() { | |
// Preload here to make sure that: | |
// 1. RP.resolve etc. modified by some preload plugins can be used | |
// immediately in the id resolving logic. | |
// Ref: issues/plugin-coffee | |
// 2. The functions provided by the preload modules can be used | |
// immediately in factories of the following modules. | |
preload(function() { | |
var mod = memoizedMods[uri]; | |
if (mod) { | |
var deps = mod.dependencies; | |
if (deps.length) { | |
// Converts deps to absolute id. | |
deps = mod.dependencies = RP.resolve(deps, { | |
uri: mod.id | |
}); | |
} | |
var m = deps.length; | |
if (m) { | |
// if a -> [b -> [c -> [a, e], d]] | |
// when use(['a', 'b']) | |
// should remove a from c.deps | |
deps = removeCyclicWaitingUris(uri, deps); | |
m = deps.length; | |
} | |
if (m) { | |
remain += m; | |
provide(deps, function() { | |
remain -= m; | |
if (remain === 0) onProvide(); | |
}); | |
} | |
} | |
if (--remain === 0) onProvide(); | |
}); | |
} | |
})(unReadyUris[i]); | |
} | |
function onProvide() { | |
setReadyState(unReadyUris); | |
callback(); | |
} | |
} | |
/** | |
* Fetches a module file. | |
* @param {string} uri The module uri. | |
* @param {function()} callback The callback function. | |
*/ | |
function fetch(uri, callback) { | |
if (fetchingMods[uri]) { | |
callbackList[uri].push(callback); | |
return; | |
} | |
callbackList[uri] = [callback]; | |
fetchingMods[uri] = true; | |
RP.load( | |
util.parseMap(uri), | |
function() { | |
// Memoize anonymous module | |
var mod = data.anonymousMod; | |
if (mod) { | |
// Don't override existed module | |
if (!memoizedMods[uri]) { | |
memoize(uri, mod); | |
} | |
data.anonymousMod = null; | |
} | |
// Assign the first module in package to memoizeMos[uri] | |
// See: test/issues/un-correspondence | |
mod = data.packageMods[0]; | |
if (mod && !memoizedMods[uri]) { | |
memoizedMods[uri] = mod; | |
} | |
data.packageMods = []; | |
// Clear | |
if (fetchingMods[uri]) { | |
delete fetchingMods[uri]; | |
} | |
// Call callbackList | |
if (callbackList[uri]) { | |
util.forEach(callbackList[uri], function(fn) { | |
fn(); | |
}); | |
delete callbackList[uri]; | |
} | |
}, | |
data.config.charset | |
); | |
} | |
// Helpers | |
/** | |
* Caches mod info to memoizedMods. | |
*/ | |
function memoize(uri, mod) { | |
mod.id = uri; // change id to the absolute path. | |
memoizedMods[uri] = mod; | |
} | |
/** | |
* Set mod.ready to true when all the requires of the module is loaded. | |
*/ | |
function setReadyState(uris) { | |
util.forEach(uris, function(uri) { | |
if (memoizedMods[uri]) { | |
memoizedMods[uri].ready = true; | |
} | |
}); | |
} | |
/** | |
* Removes the "ready = true" uris from input. | |
*/ | |
function getUnReadyUris(uris) { | |
return util.filter(uris, function(uri) { | |
var mod = memoizedMods[uri]; | |
return !mod || !mod.ready; | |
}); | |
} | |
/** | |
* if a -> [b -> [c -> [a, e], d]] | |
* call removeMemoizedCyclicUris(c, [a, e]) | |
* return [e] | |
*/ | |
function removeCyclicWaitingUris(uri, deps) { | |
return util.filter(deps, function(dep) { | |
return !isCyclicWaiting(memoizedMods[dep], uri); | |
}); | |
} | |
function isCyclicWaiting(mod, uri) { | |
if (!mod || mod.ready) { | |
return false; | |
} | |
var deps = mod.dependencies || []; | |
if (deps.length) { | |
if (~util.indexOf(deps, uri)) { | |
return true; | |
} else { | |
for (var i = 0; i < deps.length; i++) { | |
if (isCyclicWaiting(memoizedMods[deps[i]], uri)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
} | |
return false; | |
} | |
// Public API | |
util.memoize = memoize; | |
fn.load = load; | |
})(seajs._util, seajs._data, seajs._fn); | |
/** | |
* @fileoverview The configuration. | |
*/ | |
(function(host, util, data, fn) { | |
var config = data.config; | |
var noCachePrefix = 'seajs-ts='; | |
var noCacheTimeStamp = noCachePrefix + util.now(); | |
// Async inserted script. | |
var loaderScript = document.getElementById('seajsnode'); | |
// Static script. | |
if (!loaderScript) { | |
var scripts = document.getElementsByTagName('script'); | |
loaderScript = scripts[scripts.length - 1]; | |
} | |
var loaderSrc = util.getScriptAbsoluteSrc(loaderScript) || | |
util.pageUrl; // When sea.js is inline, set base to pageUrl. | |
var base = util.dirname(loaderSrc); | |
util.loaderDir = base; | |
// When src is "http://test.com/libs/seajs/1.0.0/sea.js", redirect base | |
// to "http://test.com/libs/" | |
var match = base.match(/^(.+\/)seajs\/[\d\.]+\/$/); | |
if (match) { | |
base = match[1]; | |
} | |
config.base = base; | |
var mainAttr = loaderScript.getAttribute('data-main'); | |
if (mainAttr) { | |
// data-main="abc" is equivalent to data-main="./abc" | |
if (util.isTopLevel(mainAttr)) { | |
mainAttr = './' + mainAttr; | |
} | |
config.main = mainAttr; | |
} | |
// The max time to load a script file. | |
config.timeout = 20000; | |
/** | |
* The function to configure the framework. | |
* config({ | |
* 'base': 'path/to/base', | |
* 'alias': { | |
* 'app': 'biz/xx', | |
* 'jquery': 'jquery-1.5.2', | |
* 'cart': 'cart?t=20110419' | |
* }, | |
* 'map': [ | |
* ['test.cdn.cn', 'localhost'] | |
* ], | |
* preload: [], | |
* charset: 'utf-8', | |
* timeout: 20000, // 20s | |
* debug: false | |
* }); | |
* | |
* @param {Object} o The config object. | |
*/ | |
fn.config = function(o) { | |
for (var k in o) { | |
var previous = config[k]; | |
var current = o[k]; | |
if (previous && k === 'alias') { | |
for (var p in current) { | |
if (current.hasOwnProperty(p)) { | |
checkAliasConflict(previous[p], current[p]); | |
previous[p] = current[p]; | |
} | |
} | |
} | |
else if (previous && (k === 'map' || k === 'preload')) { | |
// for config({ preload: 'some-module' }) | |
if (!util.isArray(current)) { | |
current = [current]; | |
} | |
util.forEach(current, function(item) { | |
if (item) { // Ignore empty string. | |
previous.push(item); | |
} | |
}); | |
// NOTICE: no need to check conflict for map and preload. | |
} | |
else { | |
config[k] = current; | |
} | |
} | |
// Make sure config.base is absolute path. | |
var base = config.base; | |
if (base && !util.isAbsolute(base)) { | |
config.base = util.id2Uri('./' + base + '#'); | |
} | |
// Use map to implement nocache | |
if (config.debug === 2) { | |
config.debug = 1; | |
fn.config({ | |
map: [ | |
[/.*/, function(url) { | |
if (url.indexOf(noCachePrefix) === -1) { | |
url += (url.indexOf('?') === -1 ? '?' : '&') + noCacheTimeStamp; | |
} | |
return url; | |
}] | |
] | |
}); | |
} | |
// Sync | |
if (config.debug) { | |
host.debug = config.debug; | |
} | |
return this; | |
}; | |
function checkAliasConflict(previous, current) { | |
if (previous && previous !== current) { | |
util.error('Alias is conflicted:', current); | |
} | |
} | |
})(seajs, seajs._util, seajs._data, seajs._fn); | |
/** | |
* @fileoverview Prepare for plugins environment. | |
*/ | |
(function(data, util, fn, global) { | |
var config = data.config; | |
// register plugin names | |
var alias = {}; | |
var loaderDir = util.loaderDir; | |
util.forEach( | |
['base', 'map', 'text', 'json', 'coffee', 'less'], | |
function(name) { | |
name = 'plugin-' + name; | |
alias[name] = loaderDir + name; | |
}); | |
fn.config({ | |
alias: alias | |
}); | |
// handle seajs-debug | |
if (~global.location.search.indexOf('seajs-debug') || | |
~document.cookie.indexOf('seajs=1')) { | |
fn.config({ debug: 2 }); | |
config.preload.push('plugin-map'); | |
} | |
})(seajs._data, seajs._util, seajs._fn, this); | |
/** | |
* @fileoverview The bootstrap and entrances. | |
*/ | |
(function(host, data, fn) { | |
/** | |
* Loads modules to the environment. | |
* @param {Array.<string>} ids An array composed of module id. | |
* @param {function(*)=} callback The callback function. | |
*/ | |
fn.use = function(ids, callback) { | |
fn.load(ids, callback); | |
}; | |
// data-main | |
var mainModuleId = data.config.main; | |
if (mainModuleId) { | |
fn.use([mainModuleId]); | |
} | |
// Parses the pre-call of seajs.config/seajs.use/define. | |
// Ref: test/bootstrap/async-3.html | |
(function(args) { | |
if (args) { | |
var hash = { | |
0: 'config', | |
1: 'use', | |
2: 'define' | |
}; | |
for (var i = 0; i < args.length; i += 2) { | |
fn[hash[args[i]]].apply(host, args[i + 1]); | |
} | |
delete host._seajs; | |
} | |
})((host._seajs || 0)['args']); | |
})(seajs, seajs._data, seajs._fn); | |
/** | |
* @fileoverview The public api of seajs. | |
*/ | |
(function(host, data, fn, global) { | |
// Avoids conflicting when sea.js is loaded multi times. | |
if (host._seajs) { | |
global.seajs = host._seajs; | |
return; | |
} | |
// SeaJS Loader API: | |
host.config = fn.config; | |
host.use = fn.use; | |
// Module Authoring API: | |
var previousDefine = global.define; | |
global.define = fn.define; | |
// For custom loader name. | |
host.noConflict = function(all) { | |
global.seajs = host._seajs; | |
if (all) { | |
global.define = previousDefine; | |
host.define = fn.define; | |
} | |
return host; | |
}; | |
// Keep for plugin developers. | |
host.pluginSDK = { | |
util: host._util, | |
data: host._data | |
}; | |
// For debug mode. | |
var debug = data.config.debug; | |
if (debug) { | |
host.debug = !!debug; | |
} | |
// Keeps clean! | |
delete host._util; | |
delete host._data; | |
delete host._fn; | |
delete host._seajs; | |
})(seajs, seajs._data, seajs._fn, this); | |
</pre> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment