• easyloader源码


      1 /**
      2  * easyloader - jQuery EasyUI
      3  * 
      4  * Licensed under the GPL:
      5  *   http://www.gnu.org/licenses/gpl.txt
      6  *
      7  * Copyright 2010 stworthy [ stworthy@gmail.com ] 
      8  * 
      9  */
     10 (function(){
     11     //将所有的插件,和插件资源和依赖文件放进modules对象中。
     12     var modules = {
     13         
     14         draggable:{
     15             js:'jquery.draggable.js'
     16         },
     17         droppable:{
     18             js:'jquery.droppable.js'
     19         },
     20         resizable:{
     21             js:'jquery.resizable.js'
     22         },
     23         linkbutton:{
     24             js:'jquery.linkbutton.js',
     25             css:'linkbutton.css'
     26         },
     27         pagination:{
     28             js:'jquery.pagination.js',
     29             css:'pagination.css',
     30             dependencies:['linkbutton']
     31         },
     32         datagrid:{
     33             js:'jquery.datagrid.js',
     34             css:'datagrid.css',
     35             dependencies:['panel','resizable','linkbutton','pagination']
     36         },
     37         treegrid:{
     38             js:'jquery.treegrid.js',
     39             css:'tree.css',
     40             dependencies:['datagrid']
     41         },
     42         panel: {
     43             js:'jquery.panel.js',
     44             css:'panel.css'
     45         },
     46         window:{
     47             js:'jquery.window.js',
     48             css:'window.css',
     49             dependencies:['resizable','draggable','panel']
     50         },
     51         dialog:{
     52             js:'jquery.dialog.js',
     53             css:'dialog.css',
     54             dependencies:['linkbutton','window']
     55         },
     56         messager:{
     57             js:'jquery.messager.js',
     58             css:'messager.css',
     59             dependencies:['linkbutton','window']
     60         },
     61         layout:{
     62             js:'jquery.layout.js',
     63             css:'layout.css',
     64             dependencies:['resizable','panel']
     65         },
     66         form:{
     67             js:'jquery.form.js'
     68         },
     69         menu:{
     70             js:'jquery.menu.js',
     71             css:'menu.css'
     72         },
     73         tabs:{
     74             js:'jquery.tabs.js',
     75             css:'tabs.css',
     76             dependencies:['panel','linkbutton']
     77         },
     78         splitbutton:{
     79             js:'jquery.splitbutton.js',
     80             css:'splitbutton.css',
     81             dependencies:['linkbutton','menu']
     82         },
     83         menubutton:{
     84             js:'jquery.menubutton.js',
     85             css:'menubutton.css',
     86             dependencies:['linkbutton','menu']
     87         },
     88         accordion:{
     89             js:'jquery.accordion.js',
     90             css:'accordion.css',
     91             dependencies:['panel']
     92         },
     93         calendar:{
     94             js:'jquery.calendar.js',
     95             css:'calendar.css'
     96         },
     97         combo:{
     98             js:'jquery.combo.js',
     99             css:'combo.css',
    100             dependencies:['panel','validatebox']
    101         },
    102         combobox:{
    103             js:'jquery.combobox.js',
    104             css:'combobox.css',
    105             dependencies:['combo']
    106         },
    107         combotree:{
    108             js:'jquery.combotree.js',
    109             dependencies:['combo','tree']
    110         },
    111         combogrid:{
    112             js:'jquery.combogrid.js',
    113             dependencies:['combo','datagrid']
    114         },
    115         validatebox:{
    116             js:'jquery.validatebox.js',
    117             css:'validatebox.css'
    118         },
    119         numberbox:{
    120             js:'jquery.numberbox.js',
    121             dependencies:['validatebox']
    122         },
    123         spinner:{
    124             js:'jquery.spinner.js',
    125             css:'spinner.css',
    126             dependencies:['validatebox']
    127         },
    128         numberspinner:{
    129             js:'jquery.numberspinner.js',
    130             dependencies:['spinner','numberbox']
    131         },
    132         timespinner:{
    133             js:'jquery.timespinner.js',
    134             dependencies:['spinner']
    135         },
    136         tree:{
    137             js:'jquery.tree.js',
    138             css:'tree.css',
    139             dependencies:['draggable','droppable']
    140         },
    141         datebox:{
    142             js:'jquery.datebox.js',
    143             css:'datebox.css',
    144             dependencies:['calendar','validatebox']
    145         },
    146         parser:{
    147             js:'jquery.parser.js'
    148         }
    149     };
    150     //将国际化文件放入一个locales对象中
    151     var locales = {
    152         'af':'easyui-lang-af.js',
    153         'bg':'easyui-lang-bg.js',
    154         'ca':'easyui-lang-ca.js',
    155         'cs':'easyui-lang-cs.js',
    156         'da':'easyui-lang-da.js',
    157         'de':'easyui-lang-de.js',
    158         'en':'easyui-lang-en.js',
    159         'fr':'easyui-lang-fr.js',
    160         'nl':'easyui-lang-nl.js',
    161         'zh_CN':'easyui-lang-zh_CN.js',
    162         'zh_TW':'easyui-lang-zh_TW.js'
    163     };
    164     
    165     //定义一个局部变量,做循环遍历时候,存放状态
    166     var queues = {};
    167     
    168     //加载js方法
    169     function loadJs(url, callback){
    170         //标志变量,js是否加载并执行
    171         var done = false;
    172         var script = document.createElement('script');//创建script dom
    173         script.type = 'text/javascript';
    174         script.language = 'javascript';
    175         script.src = url;
    176         script.onload = script.onreadystatechange = function(){ //onload是firefox 浏览器事件,onreadystatechange,是ie的,为了兼容,两个都写上,这样写会导致内存泄露
    177             //script.readyState只是ie下有这个属性,如果这个值为undefined,说明是在firefox,就直接可以执行下面的代码了。反之为ie,需要对script.readyState
    178             //状态具体值进行判别,loaded和complete状态表示,脚本加载了并执行了。
    179             if (!done && (!script.readyState || script.readyState == 'loaded' || script.readyState == 'complete')){
    180                 done = true;
    181                 
    182                 script.onload = script.onreadystatechange = null;//释放内存,还会泄露。
    183                 if (callback){//加载后执行回调
    184                     callback.call(script);
    185                 }
    186             }
    187         }
    188         //具体加载动作,上面的onload是注册事件,
    189         document.getElementsByTagName("head")[0].appendChild(script);
    190     }
    191     //运行js ,看代码逻辑可知,运行js,只是在js执行后,将这个script删除而已,主要用来加载国际化文件
    192     function runJs(url, callback){
    193         loadJs(url, function(){
    194             document.getElementsByTagName("head")[0].removeChild(this);
    195             if (callback){
    196                 callback();
    197             }
    198         });
    199     }
    200     
    201     //加载css没什么好说的
    202     function loadCss(url, callback){
    203         var link = document.createElement('link');
    204         link.rel = 'stylesheet';
    205         link.type = 'text/css';
    206         link.media = 'screen';
    207         link.href = url;
    208         document.getElementsByTagName('head')[0].appendChild(link);
    209         if (callback){
    210             callback.call(link);
    211         }
    212     }
    213     //加载单一一个plugin,仔细研究module ,可以发现,pingin之间通过dependence,构造成了一颗依赖树,
    214     //这个方法,就是加载具体树中的一个节点
    215     function loadSingle(name, callback){
    216         //把整个plugin的状态设置为loading
    217         queues[name] = 'loading';
    218         
    219         var module = modules[name];
    220         //把js状态设置为loading
    221         var jsStatus = 'loading';
    222         //如果允许css,并且plugin有css,则加载css,否则设置加载过了,其实是不加载
    223         var cssStatus = (easyloader.css && module['css']) ? 'loading' : 'loaded';
    224         //加载css,plugin 的css,如果是全称,就用全称,否则把简写换成全称,所以简写的css文件要放入到themes/type./文件下
    225         if (easyloader.css && module['css']){
    226             if (/^http/i.test(module['css'])){
    227                 var url = module['css'];
    228             } else {
    229                 var url = easyloader.base + 'themes/' + easyloader.theme + '/' + module['css'];
    230             }
    231             loadCss(url, function(){
    232                 cssStatus = 'loaded';
    233                 //js, css加载完,才调用回调
    234                 if (jsStatus == 'loaded' && cssStatus == 'loaded'){
    235                     finish();
    236                 }
    237             });
    238         }
    239         //加载js,全称用全称,简写补全。
    240         if (/^http/i.test(module['js'])){
    241             var url = module['js'];
    242         } else {
    243             var url = easyloader.base + 'plugins/' + module['js'];
    244         }
    245         loadJs(url, function(){
    246             jsStatus = 'loaded';
    247             if (jsStatus == 'loaded' && cssStatus == 'loaded'){
    248                 finish();
    249             }
    250         });
    251         //加载完调用的方法,改plugin状态
    252         function finish(){
    253             queues[name] = 'loaded';
    254             //调用正在加载的方法,其实已经加载完了,
    255             easyloader.onProgress(name);
    256             if (callback){
    257                 callback();
    258             }
    259         }
    260     }
    261     //加载主模块入口,
    262     function loadModule(name, callback){
    263         //定义数组,最后是形成的是依赖插件列表,最独立的插件放在首位,name是末尾
    264         var mm = [];
    265         var doLoad = false;
    266         //name有两种,一种是string ,一种是string array,这样一次可以加载多个plugin,都是调用add方法进行添加
    267         if (typeof name == 'string'){
    268             add(name);
    269         } else {
    270             for(var i=0; i<name.length; i++){
    271                 add(name[i]);
    272             }
    273         }
    274         
    275         function add(name){
    276             //如果modules中没有这个plugin那退出
    277             if (!modules[name]) return;
    278             //如果有,查看它是否依赖其他plugin
    279             var d = modules[name]['dependencies'];
    280             //如果依赖,就加载依赖的plugin.同时在加载依赖的plugin的依赖。注意循环中调用了add,是递归
    281             if (d){
    282                 for(var i=0; i<d.length; i++){
    283                     add(d[i]);
    284                 }
    285             }
    286             mm.push(name);
    287         }
    288         
    289         function finish(){
    290             if (callback){
    291                 callback();
    292             }
    293             //调用onLoad,传递name 为参数
    294             easyloader.onLoad(name);
    295         }
    296         //形成依赖树,不行还没有做实质性工作呢,那就是加载。打起精神来,最核心的代码就是以下的了
    297         //超时用
    298         var time = 0;
    299         //定义一个加载方法,定义后直接调用
    300         function loadMm(){
    301             //如果mm有长度,长度!=0,加载plugin,为0,即加载完毕,开始加载国际化文件。
    302             if (mm.length){
    303                 var m = mm[0];    // the first module
    304                 if (!queues[m]){//状态序列中没有这个plugin的信息,说明没有加载这个plug,调用laodSingle进行加载
    305                     doLoad = true; 
    306                     loadSingle(m, function(){
    307                         mm.shift();//加载完成后,将这个元素从数组去除,在继续加载,直到数组
    308                         loadMm();
    309                     });
    310                 } else if (queues[m] == 'loaded'){//如果这个plugin已经加载,就不用加载,以为mm中可能有重复项
    311                     mm.shift();
    312                     loadMm();
    313                 } else {
    314                     if (time < easyloader.timeout){//超时时候,10秒钟调用一次loadMn().注意arguments.callee代表函数本身
    315                         time += 10;
    316                         setTimeout(arguments.callee, 10); 
    317                     }
    318                 }
    319             } else {
    320                 if (easyloader.locale && doLoad == true && locales[easyloader.locale]){
    321                     var url = easyloader.base + 'locale/' + locales[easyloader.locale];
    322                     runJs(url, function(){
    323                         finish();
    324                     });
    325                 } else {
    326                     finish();
    327                 }
    328             }
    329         }
    330         
    331         loadMm();
    332     }
    333 //    定义一个加载器,注意,是全局变量,没有var,
    334     easyloader = {
    335         modules:modules,
    336         locales:locales,
    337         
    338         base:'.',//该属性是为了加载js,记录文件夹路径的
    339         theme:'default', //默认主题
    340         css:true,  
    341         locale:null,
    342         timeout:2000,//加载超时事件
    343     //easyloader.load(),该模块加载的调用方法,先加载css,然后加载js
    344         load: function(name, callback){
    345             //如果加载是*.css文件,判断是不是以http开头,如果是,直接调用
    346             if (/.css$/i.test(name)){
    347                 if (/^http/i.test(name)){
    348                     loadCss(name, callback);
    349                 } else {
    350                     //不是http的,加上base.文件夹路径
    351                     loadCss(easyloader.base + name, callback);
    352                 }
    353             } 
    354             //加载js文件
    355             else if (/.js$/i.test(name)){
    356                 if (/^http/i.test(name)){
    357                     loadJs(name, callback);
    358                 } else {
    359                     loadJs(easyloader.base + name, callback);
    360                 }
    361             } else {
    362                 //如果直接传递一个插件名,就去modole数组中加载。改方法是重点,也是easyui自带的plugin加载方式
    363                 loadModule(name, callback);
    364             }
    365         },
    366         
    367         onProgress: function(name){},
    368         onLoad: function(name){}
    369     };
    370 //以上一直在定义函数,和变量,此处为真正执行处
    371 //获取页面的所有的script,主要是为了获取我们现在解释的easyloader.js文件路径,来设置base属性
    372     var scripts = document.getElementsByTagName('script');
    373     for(var i=0; i<scripts.length; i++){
    374         var src = scripts[i].src;
    375         if (!src) continue;
    376         var m = src.match(/easyloader.js(W|$)/i);//判断文件是否含有easyloadr.js
    377         if (m){
    378             //如果有,base为easyloadr.js 的相同前缀
    379             easyloader.base = src.substring(0, m.index);
    380         }
    381     }
    382 //定义一个简化调用接口
    383     window.using = easyloader.load;
    384     
    385     if (window.jQuery){
    386         jQuery(function(){
    387             //系统数据加载完后,加载parser.js插件,该插件是渲染界面的
    388             easyloader.load('parser', function(){
    389                 jQuery.parser.parse();//渲染方法
    390             });
    391         });
    392     }
    393     
    394 })();
  • 相关阅读:
    Android之Parcel
    Android常用的IPC通信
    Android之Surface绘制原理
    Android之Surface
    Android之SurfaceFlinger服务
    Android Service(服务)
    Android Service进阶之路
    Android之UI线程启动
    Android之Activity显示原理
    python17-Django进阶
  • 原文地址:https://www.cnblogs.com/dhl-2013/p/4562990.html
Copyright © 2020-2023  润新知