/* * easyloader - jQuery EasyUI * * Licensed under the GPL: * http://www.gnu.org/licenses/gpl.txt * * Copyright 2010 stworthy [ stworthy@gmail.com ] * */ (function ($) { //将所有的插件,和插件资源和依赖文件放进modules对象中。 var modules = {}; //将国际化文件放入一个locales对象中 var locales = { 'af': 'easyui-lang-af.js', 'bg': 'easyui-lang-bg.js', 'ca': 'easyui-lang-ca.js', 'cs': 'easyui-lang-cs.js', 'da': 'easyui-lang-da.js', 'de': 'easyui-lang-de.js', 'en': 'easyui-lang-en.js', 'fr': 'easyui-lang-fr.js', 'nl': 'easyui-lang-nl.js', 'zh_CN': 'easyui-lang-zh_CN.js', 'zh_TW': 'easyui-lang-zh_TW.js' }; //定义一个局部变量,做循环遍历时候,存放状态 var queues = {}; var sysTheme = "default";//系统主题标识 //定义一个加载器,注意,是全局变量 easyloader = { modules: modules, locales: locales, debugMode: false, //true开发模式,false调试模式,实际中生产环境配置false,开启择不缓存文件 minMode: false, //迷你模式下,只加载min的文件 hideFormError: true,//校验默认规则,隐藏模式 base: '.', //该属性是为了加载js,记录文件夹路径的 theme: '', //个性主题标识 css: true, //是否包含css样式控制 pluginsStr: 'plugins', //主插件的地址 dialogCssName: 'dialog_style01', //解决CMS和UCP的组件的冲突问题,其他项目不要使用 dialogToTop:false,//是否弹到顶层,弹到顶层以后,回写需要指定document对象,不支持默认写到当前 dialogAllowToMax: false, //弹出框允许最大化 dialogAllowToMin: false, //弹出框允许最小化 dialogAllowRefresh: false, //弹出框允许刷新 /** * 外部插件开发最简单的配置是单插件模式,插件和配置文件放在js目录下,所有插件放在plugins目录下 * 如果是多个插件必须已数组的形式统一给定 */ sysloading: "
正在加载中,请稍候...
",//全局统一等待样式 extPlugins: (typeof pluginloader == "undefined") ? "" : pluginloader.defPlugins, //外部插件的集合 extPluginsRoot: '', //扩展插件的根目录地址,程序会自动处理,不需要关注 extPluginsFolder: 'js', //外部插件的相对目录,这个目录是一个相对根目录,和lovey目录必须同级 extPluginsName: 'plugins', //用于存放插件的包名 splitStr: '/', //文件路径分隔符 URI: '', //应用部署路径 pluginsJsonDone: false, //主插件是否加载完毕 extPluginJsonDone: {}, //辅助插件是否加载完毕 locale: null, isIframe: false, //是否iframe集成,默认否,by yzhao timeout: 2000, //加载超时事件 //easyloader.load(),该模块加载的调用方法,先加载css,然后加载js load: function (name, callback) { //如果加载是*.css文件,判断是不是以http开头,如果是,直接调用 if (/\.css$/i.test(name)) { if (/^http/i.test(name)) { loadCss(name, callback); } else { //不是http的,加上base.文件夹路径 loadCss(easyloader.base + name, callback); } } //加载js文件 else if (/\.js$/i.test(name) && (typeof name == 'string')) { if (/^http/i.test(name) || /^\//i.test(name)) { loadJs(name, callback); } else { loadJs(easyloader.base + name, callback); } } else { //构造module关系树,name有两种,一种是string ,一种是string array,这样一次可以加载多个plugin,都是调用add方法进行添加 makeModule(name, callback); } }, onProgress: function (name) { }, onLoad: function (name) { } }; //以上一直在定义函数,和变量,此处为真正执行处 //获取页面的所有的script,主要是为了获取我们现在解释的easyloader.js文件路径,来设置base属性 var scripts = document.getElementsByTagName('script'); for (var i = 0; i < scripts.length; i++) { var src = scripts[i].src; if (!src) continue; var m = src.match(/easyloader\.js(\W|$)/i);//判断文件是否含有easyloadr.js if (m) { //如果有,base为easyloadr.js 的相同前缀 easyloader.base = src.substring(0, m.index); //插件配置文件在装配阶段部署路径是获取不到的 easyloader.extPluginsRoot = easyloader.base.split("lovey/js")[0]; } } //定义一个简化调用接口 window.using = easyloader.load; //加载js方法 function loadJs(url, callback) { //标志变量,js是否加载并执行 var done = false; var script = document.createElement('script');//创建script dom script.type = 'text/javascript'; script.language = 'javascript'; script.src = url; script.onload = script.onreadystatechange = function () { //onload是firefox 浏览器事件,onreadystatechange,是ie的,为了兼容,两个都写上,这样写会导致内存泄露 //script.readyState只是ie下有这个属性,如果这个值为undefined,说明是在firefox,就直接可以执行下面的代码了。反之为ie,需要对script.readyState //状态具体值进行判别,loaded和complete状态表示,脚本加载了并执行了。 if (!done && (!script.readyState || script.readyState == 'loaded' || script.readyState == 'complete')) { done = true; script.onload = script.onreadystatechange = null;//释放内存,还会泄露。 if (callback) {//加载后执行回调 callback.call(script); } } }; //具体加载动作,上面的onload是注册事件, document.getElementsByTagName("head")[0].appendChild(script); } //运行js ,看代码逻辑可知,运行js,只是在js执行后,将这个script删除而已,主要用来加载国际化文件 function runJs(url, callback) { loadJs(url, function () { document.getElementsByTagName("head")[0].removeChild(this); if (callback) { callback(); } }); } //加载css没什么好说的 function loadCss(url, callback) { var link = document.createElement('link'); link.rel = 'stylesheet'; link.type = 'text/css'; link.media = 'screen'; link.href = url; document.getElementsByTagName('head')[0].appendChild(link); if (callback) { callback.call(link); } } //加载单一一个plugin,仔细研究module ,可以发现,pingin之间通过dependence,构造成了一颗依赖树, //这个方法,就是加载具体树中的一个节点 function loadSingle(name, callback) { //把整个plugin的状态设置为loading queues[name] = 'loading'; var module = modules[name]; //把js状态设置为loading var jsStatus = 'loading'; //如果允许css,并且plugin有css,则加载css,否则设置加载过了,其实是不加载 var cssStatus = 'loaded'; var themeCcsStatus = 'loaded'; if (module != undefined) { cssStatus = (easyloader.css && module['css']) ? 'loading' : 'loaded'; } var cssUrl = ""; var jsUrl = ""; //加载css,plugin 的css,如果是全称,就用全称,否则把简写换成全称,所以简写的css文件要放入到themes/type./文件下 if (module != undefined) { if (easyloader.css && module['css']) { if (/^http/i.test(module['css'])) { cssUrl = module['css']; } else if (/^\//i.test(module['css'])){ //判断已/开头的表面是全路径 cssUrl = easyloader.URI + module['css']; }else if (module['moduleExt'] != undefined && module['moduleExt'] == true) { //如果是项目自己开发的插件 cssUrl = easyloader.extPluginsRoot + module['extPluginsFolder'] + easyloader.splitStr + module['extPluginsName'] + easyloader.splitStr + name + easyloader.splitStr + sysTheme + easyloader.splitStr + module['css']; //启用min模式,http加载不关注 if (easyloader.minMode) { cssUrl = doUrl(cssUrl, ".css"); } } else { //固定加载default目录下的样式 cssUrl = easyloader.base + easyloader.pluginsStr + easyloader.splitStr + name + easyloader.splitStr + sysTheme + easyloader.splitStr + module['css']; //启用min模式,http加载不关注 if (easyloader.minMode) { cssUrl = doUrl(cssUrl, ".css"); } } if (easyloader.debugMode && cssUrl != "") { cssUrl += "?v=" + new Date().getTime(); } loadCss(cssUrl, function () { cssStatus = 'loaded'; //js, css加载完,才调用回调 if (jsStatus == 'loaded' && cssStatus == 'loaded') { finish(); } }); //必须等待组件的样式加载完成 if (cssStatus == "loaded" && easyloader.theme != "") { themeCcsStatus = 'loaded'; var themeUrl = easyloader.base + "/themes/" + easyloader.theme + easyloader.splitStr + easyloader.theme + ".css"; //启用min模式,http加载不关注 if (easyloader.minMode) { themeUrl = doUrl(themeUrl, ".css"); } loadCss(themeUrl); } } } //加载js,全称用全称,简写补全。已.JS结尾但不是已http开头 if (/\.js$/i.test(name) && !(/^http/i.test(name))) { //已.js结尾,/js打头 jsUrl = easyloader.base + name; if (easyloader.minMode) { jsUrl = doUrl(jsUrl, ".js"); } } else if (/^http/i.test(module['js'])) { // 如果module里面直接加载的是远程js,则直接加载 jsUrl = module['js']; } else if (module['moduleExt'] != undefined && module['moduleExt'] == true) { jsUrl = easyloader.extPluginsRoot + module['extPluginsFolder'] + easyloader.splitStr + module['extPluginsName'] + easyloader.splitStr + name + easyloader.splitStr + module['js']; //启用min模式,http加载不关注 if (easyloader.minMode) { jsUrl = doUrl(jsUrl, ".js"); } } else { if (module['js']) { jsUrl = easyloader.base + easyloader.pluginsStr + easyloader.splitStr + name + easyloader.splitStr + module['js']; //启用min模式,http加载不关注 if (easyloader.minMode) { jsUrl = doUrl(jsUrl, ".js"); } } } if (easyloader.debugMode && jsUrl != "") { jsUrl += "?v=" + new Date().getTime(); } if (jsUrl != "") { loadJs(jsUrl, function () { jsStatus = 'loaded'; if (jsStatus == 'loaded' && cssStatus == 'loaded') { finish(); } }); } else { jsStatus = 'loaded'; if (jsStatus == 'loaded' && cssStatus == 'loaded') { finish(); } } //加载完调用的方法,改plugin状态 function finish() { queues[name] = 'loaded'; //调用正在加载的方法,其实已经加载完了, easyloader.onProgress(name); if (callback) { callback(); } } } //根据传入的地址重新生成url function doUrl(url, type) { if (url == '') { return ""; } var preString = url.split(type)[0]; url = preString + "-min" + type; return url; } //加载主模块入口, function loadModule(name, callback) { //定义数组,最后是形成的是依赖插件列表,最独立的插件放在首位,name是末尾 var mm = []; var doLoad = false; //name有两种,一种是string ,一种是string array,这样一次可以加载多个plugin,都是调用add方法进行添加 if (typeof name == 'string') { add(name); } else { for (var i = 0; i < name.length; i++) { add(name[i]); } } function add(name) { //如果是.js直接放入的队列 if (/\.js$/i.test(name)) { mm.push(name); } else { //如果modules中没有这个plugin那退出,如果是加载直接记在js文件不进行判断 if (!modules[name]) return; //如果有,查看它是否依赖其他plugin var d = modules[name]['dependencies']; //如果依赖,就加载依赖的plugin.同时在加载依赖的plugin的依赖。注意循环中调用了add,是递归 if (d) { for (var i = 0; i < d.length; i++) { add(d[i]); } } //主函数脚本 mm.push(name); } } function finish() { if (callback) { callback(); } //调用onLoad,传递name 为参数 easyloader.onLoad(name); } //形成依赖树,不行还没有做实质性工作呢,那就是加载。打起精神来,最核心的代码就是以下的了 //超时用,后面的依赖前面的,主脚本最后加载 var time = 0; //定义一个加载方法,定义后直接调用 function loadMm() { //如果mm有长度,长度!=0,加载plugin,为0,即加载完毕,开始加载国际化文件。 if (mm.length) { var m = mm[0]; // the first module if (!queues[m]) {//状态序列中没有这个plugin的信息,说明没有加载这个plug,调用laodSingle进行加载 doLoad = true; //加载插件 //console.log(m); loadSingle(m, function () { mm.shift();//加载完成后,将这个元素从数组去除,在继续加载,直到数组 loadMm(); }); } else if (queues[m] == 'loaded') {//如果这个plugin已经加载,就不用加载,以为mm中可能有重复项 mm.shift(); loadMm(); } else { if (time < easyloader.timeout) {//超时时候,10秒钟调用一次loadMn().注意arguments.callee代表函数本身 time += 10; setTimeout(arguments.callee, 10); } } } else { if (easyloader.locale && doLoad == true && locales[easyloader.locale]) { var url = easyloader.base + 'locale/' + locales[easyloader.locale]; runJs(url, function () { finish(); }); } else { finish(); } } } loadMm(); } //模块配置关系装载 function makeModule(name, callback) { if (!easyloader.pluginsJsonDone) { var jsonUrl = easyloader.base + "plugins.json"; //启用压缩模式 if (easyloader.minMode) { jsonUrl = doUrl(jsonUrl, ".json"); } //通过 HTTP GET请求从服务器载入一个JavaScript文件,异步执行 $.ajax({ async: false, url: jsonUrl, success: function (data) { /** * 将module装配完成,在执行回调函数 */ for (var i = 0; i < data.length; ++i) { var tpModuleName = data[i].moduleName; var tpModuleJs = data[i].moduleJs; var tpModuleCss = data[i].moduleCss; var tpModuleDependencies = data[i].moduleDependencies; //如果直接传递一个插件名,就去modole数组中加载。改方法是重点,也是easyui自带的plugin加载方式 if (tpModuleName == undefined) return; easyloader.modules[tpModuleName] = {}; /** * 如果依赖其他module,则最从最低底加载 */ if (tpModuleJs != undefined) { easyloader.modules[tpModuleName] = {js: tpModuleJs}; } //css附加 if (tpModuleCss != undefined) { //直接对象赋值 easyloader.modules[tpModuleName].css = tpModuleCss; } //插件的前缀,插件必须防止在此目录下 by yzhao 主插件地址是固定的,不需要每次多置入 //easyloader.modules[tpModuleName].pluginsStr = easyloader.pluginsStr; //依赖组件定义,不能js和模块名混合写,主JS靠前 if (tpModuleDependencies != undefined) { easyloader.modules[tpModuleName].dependencies = []; if (typeof tpModuleDependencies == 'string') { easyloader.modules[tpModuleName].dependencies.push(tpModuleDependencies); } else { for (var j = 0; j < tpModuleDependencies.length; ++j) { easyloader.modules[tpModuleName].dependencies.push(tpModuleDependencies[j]) } } } } //主插件装配完成标识 easyloader.pluginsJsonDone = true; /** * 主插件和辅助插件装配多必须是同步的,以便保证根据name一定可以找到插件 * 辅助插件加载 */ if (easyloader.extPlugins != '') { if (typeof easyloader.extPlugins == 'string') { loadExtPlugins(easyloader.extPlugins); } else { /** * 如果是数组装配形式,插件的根目录.插件的目录必须是数组,且位置相对 */ if ((typeof easyloader.extPluginsFolder != "string") && (typeof easyloader.extPluginsName != "string")) { for (var k = 0; k < easyloader.extPlugins.length; k++) { loadExtPlugins(easyloader.extPlugins[k], k); } } } } /** * 没有给出模块名不加载模块 */ if (name != undefined) { loadModule(name, callback); } }, dataType: "json"}); } else { loadModule(name, callback); } } //外部插件装配 function loadExtPlugins(pluginName, position) { var jsonModule = easyloader.extPluginJsonDone[pluginName]; if (jsonModule == undefined || !jsonModule['jsDone']) { //插件配置文件在装配阶段部署路径是获取不到的,插件放置在js目录里面名称为xxx_plugins.json var jsonUrl = easyloader.extPluginsRoot; if (position == undefined) { jsonUrl += easyloader.extPluginsFolder + easyloader.splitStr + pluginName + "_plugins.json"; } else { jsonUrl += easyloader.extPluginsFolder[position] + easyloader.splitStr + pluginName + "_plugins.json"; } //启用压缩模式 if (easyloader.minMode) { jsonUrl = doUrl(jsonUrl, ".json"); } //通过 HTTP GET请求从服务器载入一个JavaScript文件,异步执行 $.ajax({ async: false, url: jsonUrl, success: function (data) { /** * 将module装配完成,在执行回调函数 */ if (data != null) { for (var i = 0; i < data.length; ++i) { var tpModuleName = data[i].moduleName; var tpModuleJs = data[i].moduleJs; var tpModuleCss = data[i].moduleCss; var tpModuleDependencies = data[i].moduleDependencies; //如果直接传递一个插件名,就去modole数组中加载。改方法是重点,也是easyui自带的plugin加载方式 if (tpModuleName == undefined || tpModuleJs == undefined) return; /** * 如果依赖其他module,则最从最低底加载 */ easyloader.modules[tpModuleName] = {js: tpModuleJs}; //css附加 if (tpModuleCss != undefined) { //直接对象赋值 easyloader.modules[tpModuleName].css = tpModuleCss; } //插件的包名 by yzhao 改成默认是"plugins" //easyloader.modules[tpModuleName].pluginsStr = easyloader.extPluginsName; easyloader.modules[tpModuleName].extPluginsFolder = position != undefined ? easyloader.extPluginsFolder[position] : easyloader.extPluginsFolder; easyloader.modules[tpModuleName].extPluginsName = position != undefined ? easyloader.extPluginsName[position] : easyloader.extPluginsName; //知道此组件式自定义插件,需要对路径有特殊处理 easyloader.modules[tpModuleName].moduleExt = true; //依赖组件定义,不能js和模块名混合写 if (tpModuleDependencies != undefined) { easyloader.modules[tpModuleName].dependencies = []; if (typeof tpModuleDependencies == 'string') { easyloader.modules[tpModuleName].dependencies.push(tpModuleDependencies); } else { for (var j = 0; j < tpModuleDependencies.length; ++j) { easyloader.modules[tpModuleName].dependencies.push(tpModuleDependencies[j]) } } } } //装配完成标志 easyloader.extPluginJsonDone[pluginName] = {jsDone: true}; } }, dataType: "json"}); } } /*if (window.jQuery) { *//*jQuery(function () { //系统数据加载完后,加载parser.js插件,该插件是渲染界面的 easyloader.load('parser', function () { jQuery.parser.parse();//渲染方法 }); });*//* jQuery(function () { using("base"); }); }*/ /** * 招聘彩蛋 */ /*window.console && console.log("一张网页,要经历怎样的过程,才能抵达用户面前?"); window.console && console.log("一位新人,要经历怎样的成长,才能站在技术之巅?"); window.console && console.log("探寻这里的秘密;"); window.console && console.log("体验这里的挑战;"); window.console && console.log("成为这里的主人;"); window.console && console.log("加入Lovey,加入前端世界,你,可以影响世界。"); window.console && console.log("请将简历发送至 178518@gmail.com (邮件标题请以“姓名-应聘XX职位-来自console”命名)"); window.console && console.log("项目介绍:http://172.16.6.28:7090");*/ })(jQuery);