[
  {
    "path": "README",
    "content": "________       \n___  __ \\_____ \n__  / / /  __ \\\n_  /_/ // /_/ /\n/_____/ \\____/ v 2.0 pre \n\nDo是一个很轻量文件加载和依赖关系管理的库。目前do.min.js（4.6k）。可能灵活的组织开发中的JS/CSS模块文件，定制各种加载策略。\n\n具体使用方法： http://kejun.github.com/Do/\n\n"
  },
  {
    "path": "do.js",
    "content": "/* Do version 2.0 pre\n * creator: kejun (listenpro@gmail.com)\n * 最新更新：2011-7-12\n */\n\n(function(win, doc) {\n\n// 已加载模块\nvar loaded = {},\n\n// 已加载列表\nloadList = {},\n\n// 加载中的模块\nloadingFiles = {},\n\n// 内部配置文件\nconfig = {\n    // 是否自动加载核心库\n    autoLoad: true,\n\n    // 加载延迟\n    timeout: 6000,\n\n    // 核心库\n    coreLib: ['http://t.douban.com/js/jquery.min.js'],\n\n    /* 模块依赖\n     * {\n     *  moduleName: {\n     *      path: 'URL',\n     *      type:'js|css',\n     *      requires:['moduleName1', 'fileURL']\n     *  }\n     * }\n     */\n    mods: {}\n},\n\njsSelf = (function() { \n  var files = doc.getElementsByTagName('script'); \n  return files[files.length - 1];\n})(),\n\n// 全局模块\nglobalList = [],\n\n// 外部参数\nextConfig,\n\n// domready回调堆栈\nreadyList = [],\n\n// DOM Ready\nisReady = false,\n\n// 模块间的公共数据 \npublicData = {},\n\n// 公共数据回调堆栈 \npublicDataStack = {},\n\nisArray = function(e) { \n  return e.constructor === Array; \n},\n\ngetMod = function(e) {\n var mods = config.mods, mod; \n if (typeof e === 'string') {\n   mod = (mods[e])? mods[e] : { path: e };\n } else {\n   mod = e;\n }\n return mod;\n},\n\nload = function(url, type, charset, cb) {\n    var wait, n, t, img, \n\n    done = function() {\n      loaded[url] = 1;\n      cb && cb(url);\n      cb = null;\n      win.clearTimeout(wait);\n    };\n\n    if (!url) {\n        return;\n    }\n\n    if (loaded[url]) {\n        loadingFiles[url] = false;\n        if (cb) {\n            cb(url);\n        }\n        return;\n    }\n\n    if (loadingFiles[url]) {\n        setTimeout(function() {\n            load(url, type, charset, cb);\n        }, 10);\n        return;\n    }\n\n    loadingFiles[url] = true;\n\n    wait = win.setTimeout(function() {\n    /* 目前延时回调处理，超时后如果有延时回调，执行回调，然后继续等\n     * 延时回调的意义是log延时长的URI，这个处理不属于加载器本身的功能移到外部\n     * 没有跳过是为了避免错误。\n     */\n      if (config.timeoutCallback) {\n        try {\n          config.timeoutCallback(url); \n        } catch(ex) {}\n      }\n    }, config.timeout);\n\n    t =  type || url.toLowerCase().split(/\\./).pop().replace(/[\\?#].*/, '');\n\n    if (t === 'js') {\n      n = doc.createElement('script');\n      n.setAttribute('type', 'text/javascript');\n      n.setAttribute('src', url);\n      n.setAttribute('async', true);\n    } else if (t === 'css') {\n      n = doc.createElement('link');\n      n.setAttribute('type', 'text/css');\n      n.setAttribute('rel', 'stylesheet');\n      n.setAttribute('href', url);\n    }\n\n    if (charset) {\n      n.charset = charset;\n    }\n\n    if (t === 'css') {\n      img = new Image();\n      img.onerror = function() {\n        done();\n        img.onerror = null;\n        img = null;\n      }\n      img.src = url;\n    } else {\n      // firefox, safari, chrome, ie9下加载失败触发\n      // 如果文件是404, 会比timeout早触发onerror。目前不处理404，只处理超时\n      n.onerror = function() {\n        done();\n        n.onerror = null;\n      };\n\n      // ie6~8通过创建vbscript可以识别是否加载成功。\n      // 但这样需先测试性加载再加载影响性能。即使没成功加载而触发cb，顶多报错，没必要杜绝这种报错\n\n      // ie6~9下加载成功或失败，firefox, safari, opera下加载成功触发\n      n.onload = n.onreadystatechange = function() {\n        var url;\n        if (!this.readyState ||\n            this.readyState === 'loaded' ||\n            this.readyState === 'complete') {\n          done();\n          n.onload = n.onreadystatechange = null;\n        }\n      };\n    }\n\n    jsSelf.parentNode.insertBefore(n, jsSelf);\n},\n\n  // 加载依赖论文件(顺序)\n  loadDeps = function(deps, cb) {\n    var mods = config.mods, \n    id, m, mod, i = 0, len;\n\n    id = deps.join('');\n    len = deps.length;\n\n    if (loadList[id]) {\n      cb();\n      return;\n    }\n\n    function callback() {\n      if(!--len) {\n        loadList[id] = 1;\n        cb();\n      }\n    }\n\n    for (; m = deps[i++]; ) {\n      mod = getMod(m);\n      if (mod.requires) {\n        loadDeps(mod.requires, (function(mod){\n              return function(){\n              load(mod.path, mod.type, mod.charset, callback);\n              };\n              })(mod));\n      } else {\n        load(mod.path, mod.type, mod.charset, callback);\n      }\n    }\n  },\n\n  /*!\n   * contentloaded.js\n   *\n   * Author: Diego Perini (diego.perini at gmail.com)\n   * Summary: cross-browser wrapper for DOMContentLoaded\n   * Updated: 20101020\n   * License: MIT\n   * Version: 1.2\n   *\n   * URL:\n   * http://javascript.nwbox.com/ContentLoaded/\n   * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE\n   *\n   */\n\n  // @win window reference\n  // @fn function reference\n  contentLoaded = function(fn) {\n    var done = false, top = true, \n    doc = win.document, \n    root = doc.documentElement,\n    add = doc.addEventListener ? 'addEventListener' : 'attachEvent',\n    rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent',\n    pre = doc.addEventListener ? '' : 'on',\n\n    init = function(e) {\n      if (e.type == 'readystatechange' && doc.readyState != 'complete') return;\n      (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);\n      if (!done && (done = true)) fn.call(win, e.type || e);\n    },\n\n    poll = function() {\n      try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }\n      init('poll');\n    };\n\n    if (doc.readyState == 'complete') fn.call(win, 'lazy');\n    else {\n      if (doc.createEventObject && root.doScroll) {\n        try { top = !win.frameElement; } catch(e) { }\n        if (top) {\n          poll();\n        }\n      }\n      doc[add](pre + 'DOMContentLoaded', init, false);\n      doc[add](pre + 'readystatechange', init, false);\n      win[add](pre + 'load', init, false);\n    }\n  },\n\n  fireReadyList = function() {\n    var i = 0, list;\n    if (readyList.length) {\n      for(; list = readyList[i++]; ) {\n        d.apply(this, list);\n      }\n    }\n  },\n\n  d = function() {\n    var args = [].slice.call(arguments), fn, id;\n\n    // 加载核心库\n    if (config.autoLoad &&\n        !loadList[config.coreLib.join('')]) {\n      loadDeps(config.coreLib, function(){\n          d.apply(null, args);\n          });\n      return;\n    }\n\n    // 加载全局库\n    if (globalList.length > 0 &&\n        !loadList[globalList.join('')]) {\n      loadDeps(globalList, function(){\n          d.apply(null, args);\n          });\n      return;\n    }\n\n    if (typeof args[args.length - 1] === 'function' ) {\n      fn = args.pop();\n    }\n\n    id = args.join('');\n\n    if ((args.length === 0 || loadList[id]) && fn) {\n      fn();\n      return;\n    }\n\n    loadDeps(args, function() {\n        loadList[id] = 1;\n        fn && fn();\n        });\n  };\n\nd.add = function(sName, oConfig) {\n  if (!sName || !oConfig || !oConfig.path) {\n    return;\n  }\n  config.mods[sName] = oConfig;\n};\n\nd.delay = function() {\n  var args = [].slice.call(arguments), delay = args.shift();\n  win.setTimeout(function() {\n      d.apply(this, args);\n      }, delay);\n};\n\nd.global = function() {\n  var args = isArray(arguments[0])? arguments[0] : [].slice.call(arguments);\n  globalList = globalList.concat(args);\n};\n\nd.ready = function() {\n  var args = [].slice.call(arguments);\n  if (isReady) {\n    return d.apply(this, args);\n  }\n  readyList.push(args);\n};\n\nd.css = function(s) {\n  var css = doc.getElementById('do-inline-css');\n  if (!css) {\n    css = doc.createElement('style');\n    css.type = 'text/css';\n    css.id = 'do-inline-css';\n    jsSelf.parentNode.insertBefore(css, jsSelf);\n  }\n\n  if (css.styleSheet) {\n    css.styleSheet.cssText = css.styleSheet.cssText + s;\n  } else {\n    css.appendChild(doc.createTextNode(s));\n  }\n};\n\nd.setData = d.setPublicData = function(prop, value) {\n  var cbStack = publicDataStack[prop];\n\n  publicData[prop] = value;\n\n  if (!cbStack) {\n    return;\n  }\n\n  while (cbStack.length > 0) {\n    (cbStack.pop()).call(this, value);\n  }\n};\n\nd.getData = d.getPublicData = function(prop, cb) {\n  if (publicData[prop]) {\n    cb(publicData[prop]);\n    return;\n  } \n\n  if (!publicDataStack[prop]) {\n    publicDataStack[prop] = [];\n  }\n\n  publicDataStack[prop].push(function(value){\n      cb(value);\n      });\n};\n\nd.setConfig = function(n, v) {\n  config[n] = v;\n  return d;\n};\n\nd.getConfig = function(n) {\n  return config[n];\n};\n\nwin.Do = d;\n\ncontentLoaded(function() {\n  isReady = true;\n  fireReadyList();\n});\n\n// 初始外部配置\nextConfig = jsSelf.getAttribute('data-cfg-autoload');\nif (extConfig) {\n  config.autoLoad = (extConfig.toLowerCase() === 'true') ? true : false;\n}\n\nextConfig = jsSelf.getAttribute('data-cfg-corelib');\nif (extConfig) {\n  config.coreLib = extConfig.split(',');\n}\n\n})(window, document);\n"
  },
  {
    "path": "test/a1.js",
    "content": "var a1 = 1;\n"
  },
  {
    "path": "test/a2.js",
    "content": "var a2 = 2;\n"
  },
  {
    "path": "test/a3.js",
    "content": "var a3 = 3;\n"
  },
  {
    "path": "test/a4.js",
    "content": "var a4 = 4;\n"
  },
  {
    "path": "test/a5.js",
    "content": "var a5 = 5;\n"
  },
  {
    "path": "test/core.js",
    "content": "var core_lib_loaded = 1;\n"
  },
  {
    "path": "test/index.html",
    "content": "<!DOCTYPE HTML>\n<html lang=\"zh-CN\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>Do 2.0 单元测试</title>\n<script src=\"http://code.jquery.com/jquery-latest.js\"></script>\n<script type=\"text/javascript\" src=\"http://code.jquery.com/qunit/git/qunit.js\"></script>\n<link rel=\"stylesheet\" href=\"http://code.jquery.com/qunit/git/qunit.css\" type=\"text/css\" media=\"screen\" />\n\n<script type=\"text/javascript\" src=\"../do.js\" data-cfg-corelib=\"core.js\"></script>\n\n<script type=\"text/javascript\">\n$(function() {\n\n    asyncTest('测试核心类库默认被加载', function(){\n      Do(function(){\n        ok(typeof core_lib_loaded !== 'undefined', '核心类库默认加载成功');\n        start();\n      });\n    });\n\n\n    asyncTest('测试加载依赖', function(){\n      Do('a1.js', 'a2.js', function(){\n        ok(typeof a1 !== 'undefined' && typeof a2 !== 'undefined' , 'a1, a2加载成功');\n        start();\n      });\n    });\n\n    asyncTest('测试按模块名加载', function(){\n      Do.add('a1', {path: 'a1.js', type: 'js'});\n      Do('a1', 'a2.js', function(){\n        ok(typeof a1 !== 'undefined' && typeof a2 !== 'undefined' , 'a1, a2加载成功');\n        start();\n      });\n    });\n\n    asyncTest('测试加载项有依赖的情况', function(){\n        Do({path: 'a1.js', requires:['a3.js']}, 'a2.js', function(){\n        ok(a1 + a2 + a3 === 6, 'a1, a2, a3加载成功');\n        start();\n      });\n    });\n\n    asyncTest('测试全局模块默认被加载', function(){\n        Do.global('a4.js');\n        Do('a3.js', function(){\n          ok(typeof a4 !== 'undefined', '全局模块默认被加载');\n          start();\n        });\n    });\n\n    asyncTest('测试注入CSS', function(){\n        Do.css('.test-mod{ background:red; }');\n        var testMod = $('<span class=\"test-mod\"></span>').appendTo('body');\n        setTimeout(function() {\n          ok(/rgb\\(255, 0, 0\\)|red/.test(testMod.css('background-color')), 'CSS注入成功');\n          start();\n        }, 100);\n    });\n\n    asyncTest('测试延时加载', function(){\n        var finish = 0;\n        Do.delay(1000, 'a4.js', function(){\n          finish = 1;\n        });\n        setTimeout(function(){\n          ok(finish === 1, '延时加载执行');\n          start();\n        }, 1500);\n    });\n\n    asyncTest('测试DOMReady后执行', function(){\n        Do.ready('a4.js', function(){\n          ok(true, 'DOMReady后执行');\n          start();\n        });\n    });\n\n    asyncTest('测试更换核心类库', function(){\n        Do.setConfig('coreLib', ['http://yui.yahooapis.com/combo?3.3.0/build/yui/yui-min.js']);\n        Do(function(){\n          ok(typeof YUI !== 'undefined', '核心类库更换');\n          start();\n        });\n    });\n    \n    asyncTest('测试批量添加模块', function(){\n        Do.setConfig('mods', {\n          a1: { path: 'a1.js' },\n          a2: { path: 'a2.js' },\n          a3: { path: 'a3.js' },\n          a4: { path: 'a4.js' },\n          a5: { path: 'a5.js' }\n        });\n        Do('a1', 'a3', 'a5', function(){\n           ok(true, '加载超时回调被触发');\n           start();\n        });\n    });\n\n    asyncTest('测试模块间公共数据通讯', function(){\n        Do(function(){\n          Do.getData('foo', function(e){\n            ok(e === 10, '收到公共数据');\n            start();\n          });\n        });\n        Do.delay(1000, function(){\n          Do.setData('foo', 10);\n        });\n    });\n\n    asyncTest('测试加载超时回调', function(){\n        Do.setConfig('timeout', 100);\n        Do.setConfig('timeoutCallback', function(url) {\n           ok(true, '加载超时回调被触发');\n           Do.setConfig('timeoutCallback', function(){});\n           start();\n        });\n        Do({path: 'http://1.cuzillion.com/bin/resource.cgi?type=js&sleep=2&n=1&t=1310551047&r=' + Math.random(), type: 'js'});\n    });\n\n});\n</script>\n    \n</head>\n<body>\n  <h1 id=\"qunit-header\">Do 2.0 <sup>pre</sup></h1>\n\n  <h2 id=\"qunit-banner\"></h2>\n  <div id=\"qunit-testrunner-toolbar\"></div>\n\n  <h2 id=\"qunit-userAgent\"></h2>\n  <ol id=\"qunit-tests\"></ol>\n\n  <div id=\"qunit-fixture\"></div>\n</body>\n</html>\n"
  }
]