1 2 /* 3 本檔案為自動生成,請勿編輯! 4 This file is auto created from _structure\structure.js, base.js, module.js, initialization.js 5 by tool: build main script. 6 */ 7 8 9 //<![CDATA[ 10 11 12 /** 13 * @name JavaScript framework: CeL base loader 14 * @fileoverview 15 * Colorless echo JavaScript kit/library base loader. 16 * 本檔案包含了呼叫其他 library 需要用到的 function,以及常用 base functions。<br/> 17 * A JavaScript module framework that is simple to use.<br/> 18 * 本計畫希望能建立一個能簡單上手的 JavaScript 模組架構。 19 * <br/> 20 * 2002-, kanashimi <kanasimi@gmail.com>.<br/> 21 * <br/> 22 * This file is in tab wide of 4 chars, documentation with JsDoc Toolkit (<a href="http://code.google.com/p/jsdoc-toolkit/wiki/TagReference">tags</a>).<br/> 23 * <br/> 24 * <br/>Please visit <a href="http://lyrics.meicho.com.tw/program/">Colorless echo program room</a> for more informations. 25 * @since 自 function.js 0.2 改寫 26 * @since JavaScript 1.2 27 * @since 2010/1/9 00:01:52 建立 28 * @author kanasimi@gmail.com 29 * @version $Id: ce.js,v 0.2 2009/11/26 18:37:11 kanashimi Exp $ 30 */ 31 32 33 /* 34 引用:參照 35 function addCode 36 37 CeL.module 38 39 40 駝峰式大小寫命名規則 CamelCase → embedded_underscore/Snake case 41 42 43 單一JS引用: 44 // [function.js]_iF 45 function _iF(){}_iF.p='HKCU\\Software\\Colorless echo\\function.js.path';if(typeof WScript=="object")try{eval(getU((new ActiveXObject("WScript.Shell")).RegRead(_iF.p)));}catch(e){} 46 function getU(p,enc){var o;try{o=new ActiveXObject('Microsoft.XMLHTTP');}catch(e){o=new XMLHttpRequest();}if(o)with(o){open('GET',p,false);if(enc&&o.overrideMimeType)overrideMimeType('text/xml;charset='+enc);send(null);return responseText;}} 47 // [function.js]End 48 49 50 初始化:參照 51 initialization of function.js 52 53 http://www.w3school.com.cn/html5/html5_script.asp 54 <script type="text/javascript" async="true" src="path/to/function.js"></script> 55 <script type="application/javascript;version=1.7" async="true" src="path/to/function.js"></script> 56 57 JSDoc: 58 http://code.google.com/p/jsdoc-toolkit/w/list 59 http://jsdoc.sourceforge.net/ 60 61 Javadoc: 62 http://java.sun.com/j2se/javadoc/writingdoccomments/ 63 64 VSdoc: 65 JScript IntelliSense in Visual Studio 66 http://weblogs.asp.net/bleroy/archive/2007/04/23/the-format-for-javascript-doc-comments.aspx 67 http://blogs.msdn.com/b/webdevtools/archive/2008/11/07/hotfix-to-enable-vsdoc-js-intellisense-doc-files-is-now-available.aspx 68 Create JScript XML Code Comments 69 http://msdn.microsoft.com/zh-tw/library/bb514138.aspx 70 http://blog.miniasp.com/post/2010/04/Visual-Studio-2010-jQuery-Development-Tips.aspx 71 72 */ 73 74 75 76 /* 77 TODO 78 79 本 library 大量使用了 arguments.callee,但這與 ECMAScript design principles 不甚相符,需要避免。 80 http://stackoverflow.com/questions/103598/why-was-the-arguments-callee-caller-property-deprecated-in-javascript 81 http://wiki.ecmascript.org/doku.php?id=es3.1:design_principles 82 83 84 reset environment (__defineSetter__, __defineGetter__, ..) 85 in case of 86 <a href="http://haacked.com/archive/2009/06/25/json-hijacking.aspx" accessdate="2009/12/2 0:7">JSON Hijacking</a>, 87 <a href="http://blog.miniasp.com/post/2009/11/JavaScript-JSON-Hijacking.aspx" accessdate="2009/12/2 0:18">在 Web 2.0 時代必須重視 JavaScript/JSON Hijacking 攻擊</a>, 88 etc. 89 */ 90 91 92 //try{ 93 94 95 96 97 98 99 /* 100 TODO 101 將 module_name 改成 arguments 102 http://threecups.org/?p=129 103 104 listen language change event 105 play board 106 107 use <a href="http://prototyp.ical.ly/index.php/2007/03/01/javascript-design-patterns-1-the-singleton/" accessdate="2010/4/25 0:23" title="prototyp.ical.ly » Javascript Design Patterns - 1. The Singleton">Singleton pattern</a>, 108 Module 模式或單例模式(<a href="http://zh.wikipedia.org/wiki/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F" accessdate="2010/4/25 0:25" title="单例模式">Singleton</a>)<a href="http://www.comsharp.com/GetKnowledge/zh-CN/TeamBlogTimothyPage_K950.aspx" accessdate="2010/4/25 0:24" title="那些相见恨晚的 JavaScript 技巧 - 基于 COMSHARP CMS">為 Douglas Crockford 所推崇</a>,並被大量應用在 Yahoo User Interface Library YUI。 109 110 http://wiki.forum.nokia.com/index.php/JavaScript_Performance_Best_Practices 111 http://ioio.name/core-javascript-pitfalls.html 112 113 CommonJS 114 http://www.heliximitate.cn/studyblog/archives/tag/commonjs 115 116 */ 117 118 119 /* 120 TODO 121 122 123 124 //module 125 126 //typeof CeL_id === 'string' && typeof this[CeL_id] === 'function' && 127 typeof CeL === 'function' && CeL.setup_module({ 128 name:[module_name], 129 require:[function_name,module_name], 130 131 code:function(CeL){ 132 133 var private_value=1; 134 135 function module_function_1(arg) { 136 ; 137 } 138 module_function_1.required=''; 139 140 141 function module_class_1(arg) { 142 ; 143 } 144 145 function get_value(){ 146 return private_value; 147 } 148 149 module_class_1.prototype.print=function(){}; 150 module_class_1.print=function(){}; 151 152 153 return {module_function_1,module_class_1}; 154 155 } 156 157 }); 158 159 2011/7/31 21:18:01 160 161 162 163 164 */ 165 166 //void( 167 //typeof CeL !== 'function' && 168 ( 169 /* 170 * We can redefine native values only for undefined.<br/> 171 * http://weblogs.asp.net/bleroy/archive/2006/08/02/Define-undefined.aspx<br/> 172 * <br/> 173 * Will speed up references to undefined, and allows redefining its name. (from jQuery)<br/> 174 * <br/> 175 * 用在比較或是 return undefined<br/> 176 * 在舊的 browser 中,undefined 可能不存在。 177 */ 178 function (undefined) { 179 180 /* 181 * ECMA-262 5th edition, ECMAScript 5 strict mode 182 * http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/ 183 * http://davidflanagan.com/Talks/es5/slides.html 184 * http://kangax.github.com/es5-compat-table/ 185 */ 186 'use strict'; 187 188 189 //if(typeof global !== 'function') throw new Error('No global object specified!'); 190 191 192 var 193 library_name = 'CeL' 194 195 /** 196 * default debug level 197 * @type {Integer} 198 * @ignore 199 */ 200 , debug = 0 201 202 /** 203 * library version 204 * @type {String} 205 * @ignore 206 */ 207 , version = '2011.08.04' 208 209 //,window 210 211 , old_namespace 212 213 // library base name-space 214 , _ 215 216 //, _base_function_to_extend 217 218 , function_name_pattern 219 ; 220 221 222 // members of library ----------------------------------------------- 223 ; 224 225 226 /** 227 * Global Scope object<br/> 228 * 於 CeL.eval_code 使用 229 * @ignore 230 * @see 231 * <a href="http://stackoverflow.com/questions/3277182/how-to-get-the-global-object-in-javascript" accessdate="2011/8/6 10:7">How to get the Global Object in JavaScript? - Stack Overflow</a> 232 */ 233 var global = Function('return this')(); // isWeb()?window:this; 234 235 old_namespace = global && global[library_name]; 236 237 238 /* 239 var _Global=(function(){return this;})(); 240 _Global.JustANumber=2; // var _GlobalPrototype=_Global.constructor.prototype;_GlobalPrototype.JustANumber=2; 241 if(typeof _Global=='undefined')_Global=this; 242 for(i in _Global)alert(i); 243 */ 244 245 // 若已經定義過,跳過。因為已有對 conflict 的對策,因此跳過。 246 //if(global[library_name] !== undefined) return; 247 248 249 /** 250 * Will speed up references to DOM: window, and allows redefining its name. (from jQuery) 251 * @ignore 252 */ 253 //window = this; 254 255 256 /** 257 * 本 JavaScript framework 的框架基本宣告<br/> 258 * base name-space declaration of JavaScript library framework 259 * @example 260 * // load library 261 * <script type="text/javascript" src="../ce.js"></script> 262 * // 預防 initialization 到一半彈出警告視窗,所以設大一點。 263 * CeL.log.max_length = 20; 264 * // set debug 265 * CeL.set_debug(); 266 * 267 * // 判別是否已經 load 過 268 * if(typeof CeL !== 'function' || CeL.Class !== 'CeL') 269 * ; // CeL has not been loaded 270 * @name CeL 271 * @class Colorless echo JavaScript kit/library: base name-space declaration 272 */ 273 function _() { 274 // function CeL: library root 275 // declaration for debug 276 //this.global = arguments[0] || arguments.callee.ce_doc; 277 return new (this.init.apply(global, arguments)); 278 }; 279 280 281 // name-space 歸屬設定 282 283 /** 284 * Map over main name-space in case of overwrite (from jQuery) 285 * @ignore 286 */ 287 global[library_name] = _; 288 289 CeL 290 . 291 get_old_namespace = function(){ 292 return old_namespace; 293 }; 294 295 CeL 296 . 297 recover_namespace = function(){ 298 if (old_namespace === undefined) 299 delete global[library_name]; 300 else 301 global[library_name] = old_namespace; 302 return _; 303 }; 304 305 if (typeof _.prototype !== 'object') 306 CeL 307 . 308 /** 309 * framework main prototype definition 310 * for JSDT: 有 prototype 才會將之當作 Class 311 */ 312 prototype = { 313 }; 314 315 316 CeL 317 . 318 /** 319 * JavaScript library framework main class name. 320 * @see <a href="http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf">ECMA-262</a>: Object.Class: A string value indicating the kind of this object. 321 * @constant 322 */ 323 Class = library_name; 324 325 326 327 328 CeL 329 . 330 /** 331 * 本 library 專用之 evaluate()。 332 * 333 * 若在 function 中 eval 以獲得 local variable,在舊 browser 中須加 var。 334 * e.g., 'var local_variable=' + .. 335 * 不加 var 在舊 browser 中會變成 global 變數。 336 * @param code script code to evaluate 337 * @returns value that evaluate process returned 338 * @see window.eval === window.parent.eval 339 * http://stackoverflow.com/questions/3277182/how-to-get-the-global-object-in-javascript 340 */ 341 eval_code = function eval_code(code) { 342 /* 343 JSC eval() takes an optional second argument which can be 'unsafe'. 344 Mozilla/SpiderMonkey eval() takes an optional second argument which is the scope object for new symbols. 345 346 use window.execScript(code,"JavaScript") in IE: window.execScript() 將直接使用全局上下文環境,因此,execScript(Str)中的字符串Str可以影響全局變量。——也包括聲明全局變量、函數以及對象構造器。 347 */ 348 //this.debug(global.eval, 2); 349 //this.debug(global && global.eval && global.eval !== arguments.callee); 350 return global && global.eval && global.eval !== eval_code ? global.eval.call(global, code) : eval(code); 351 }; 352 353 354 CeL 355 . 356 /** 357 * evaluate @ Global scope. 358 * By the ECMA-262, new Function() will 'Pass in the Global Environment as the Scope parameter.' 359 * copy from jQuery core.js 360 * @param code script code to evaluate 361 * @returns value that evaluate process returned 362 * @see 363 * <a href="http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context" accessdate="2011/8/6 8:56">Eval JavaScript in a global context | Java.net</a> 364 * use execScript on Internet Explorer 365 */ 366 global_eval = new Function('code', 'return ' 367 + (global.execScript ? 'global.execScript(' 368 : global.eval ? 'global.eval.call(global,' 369 : window && window.eval ? 'window.eval.call(window,' 370 : 'eval.call(null,') 371 + 'code);'); 372 373 374 375 CeL 376 . 377 /** 378 * simple evaluates to get value of specified variable identifier name. 379 * 不使用 eval(). 380 * @param {String} variable_name variable identifier name. e.g., /[a-z\d$_]+(.[a-z\d_]+)+/i 381 * @param {Object|Function} [name_space] initialize name-space. default: global 382 * @returns value of specified variable identifier name 383 * @since 2010/1/1 18:11:40 384 * @note 385 * 'namespace' 是 JScript.NET 的保留字 386 * 387 * 在兩個子層(a.b.c)下,這樣作效率較差 @User agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.29 Safari/533.4: 388 * function(v){try{return(new Function('return('+v+')'))();}catch(e){}} 389 */ 390 get_variable = function(variable_name, name_space) { 391 //this.debug('get value of [' + variable_name + ']'); 392 if (typeof variable_name !== 'string' || !variable_name) 393 return variable_name; 394 395 var i = 0, 396 // TODO: 可處理 e.g., obj1 . obj2 [ ' obj3.4 * \[ ' ] [''] . obj5 [ " obj6 \" \' \] . " ] 397 // or detect obj1 .. obj2 398 s = variable_name.split('.'), 399 l = s.length, 400 v = name_space || 401 //this.env.global 402 global 403 ; 404 //this.debug('global.' + this.Class + ' = ' + this.env.global[this.Class]); 405 406 try { 407 while (i < l) 408 if (v) 409 // this.debug('to [' + s[i] + ']: ' + v[s[i]]), 410 v = v[s[i++]]; 411 else 412 throw 1; 413 } catch (e) { 414 s[i - 1] = '<em>' + s[i - 1] + '</em><span class="debug_weaken">'; 415 //alert(this.log.buffer.length+','+this.log.max_length+'\n'+this.debug); 416 this.debug('Cannot get [<span title="' + variable_name + '">' + s.join('.') + '</span></span>]!', 2, 'get_variable'); 417 return; 418 } 419 420 return v; 421 }; 422 423 424 425 426 CeL 427 . 428 /** 429 * 取得執行 script 之 path, 在 .hta 中取代 WScript.ScriptFullName。 430 * @returns {String} 執行 script 之 path 431 * @returns '' unknown environment 432 */ 433 get_script_full_name = function() { 434 // 在 IE8, IE9 中,get_object_type.call(WScript) 為 '[object Object]' !! 435 return typeof WScript === 'object' && (!this.is_Object(WScript) || String(WScript) === 'Windows Script Host') 436 && WScript.ScriptFullName 437 || typeof location === 'object' && location === window.location && unescape(location.pathname) 438 || ''; 439 }; 440 441 CeL 442 . 443 /** 444 * 取得執行 script 之名稱 445 * @returns {String} 執行 script 之 名稱 446 * @returns '' unknown environment 447 */ 448 get_script_name = function() { 449 var n, i, j; 450 451 // 在 IE8, IE9 中,get_object_type.call(WScript) 為 '[object Object]' !! 452 if (typeof WScript === 'object' 453 && (!this.is_Object(WScript) || String(WScript) === 'Windows Script Host')) { 454 n = WScript.ScriptName; 455 i = n.lastIndexOf('.'); 456 return i == -1 ? n : n.slice(0, i); 457 } 458 459 if (typeof location === 'object' && location === window.location) { 460 n = unescape(location.pathname), j = n.lastIndexOf('.'); 461 if (!(i = n.lastIndexOf('\\') + 1)) 462 // location.pathname 在 .hta 中會回傳 '\' 形式的 path 463 i = n.lastIndexOf('/') + 1; 464 return i < j ? n.slice(i, j) : n.slice(i); 465 } 466 467 return typeof document === 'object' && document === window.document ? document.title : ''; 468 }; 469 470 471 472 473 /* 474 測試各 type: 475 476 undefined: 477 變數值存在且變數 'undefined' 存在時: variable === undefined 478 否則: typeof(variable) === 'undefined' 479 480 number, boolean, string: 481 typeof(variable) === '~' 482 483 ** NaN 484 ** int/float 485 486 object: 487 null 488 489 不同frame中的Array擁有不同的constructor 490 */ 491 /** 492 * A cache to the function we use to get the type of specified value.<br/> 493 * Get the [[Class]] property of this object.<br/> 494 * 不使用 Object.toString() 是怕被 overridden 495 * @type {Function} 496 * @inner 497 */ 498 var get_object_type = Object.prototype.toString; 499 500 CeL 501 . 502 /** 503 * 判斷為何種 type。主要用在 Error, DOMException 等 native object 之判別。 504 * @param value variable or class instance to test 505 * @param {String} [want_type] type to compare: number, string, boolean, undefined, object, function 506 * @param {Boolean} [get_Class] get the class name of a class(function) instance. 507 * @returns {Boolean} The type is matched. 508 * @returns {String} The type of value 509 * @returns {undefined} error occurred 510 * @example 511 * CeL.is_type(value_to_test, 'Array'); 512 * @since 2009/12/14 19:50:14 513 * @see 514 * <a href="http://lifesinger.org/blog/2009/02/javascript-type-check-2/" accessdate="2009/12/6 19:10">JavaScript类型检测小结(下) - 岁月如歌</a><br/> 515 * <a href="http://thinkweb2.com/projects/prototype/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/" accessdate="2009/12/6 19:10">Perfection kills » `instanceof` considered harmful (or how to write a robust `isArray`)</a> 516 */ 517 is_type = function(value, want_type, get_Class) { 518 var type; 519 if (want_type && (type = typeof want_type) !== 'string') 520 want_type = type; 521 522 type = value === null ? String(value) : typeof value; 523 524 if (get_Class) 525 try { 526 if(type === 'function' && value.Class) 527 // get the class name of a class 528 // 若 value 為 function 時,測試其本身之 Class。 529 type = value.Class; 530 else if (type === 'function' || type === 'object') 531 if (('constructor' in value) && (get_Class = value.constructor).Class) 532 // get the class name of a class instance 533 // 若 value 為 function 且無 Class,或為 object 時,測試其 constructor 之 Class。 534 type = get_Class.Class; 535 else if (get_Class = this.get_function_name(get_Class)) 536 // get Class by function name 537 type = get_Class; 538 } catch (e) { 539 this.err(this.Class + '.is_type: Fault to get ths class name of value!'); 540 } 541 542 if (type !== 'object') 543 // type maybe 'unknown' or 'date'! 544 return want_type ? type === want_type.toLowerCase() : type; 545 546 try { 547 get_Class = get_object_type.call(value); 548 } catch (e) { 549 this.err(this.Class + '.is_type: Fault to get object type of value!'); 550 get_Class = ''; 551 } 552 553 if (want_type) 554 return get_Class === (want_type.charAt(0) === '[' ? want_type 555 : '[object ' + want_type + ']'); 556 557 if (want_type = get_Class.match( 558 /^\[object ([^\]]+)\]$/)) 559 return want_type[1]; 560 561 return type; 562 }; 563 564 565 CeL 566 . 567 /** 568 * get a type test function 569 * @param {String} want_type object type to compare 570 * @param {String} [toString_reference] a reference name to Object.prototype.toString 571 * @returns {Function} type test function 572 * @since 2009/12/20 08:38:26 573 * @example 574 * // 大量驗證時,推薦另外在本身 scope 中造出捷徑: 575 * this.OtS = Object.prototype.toString; 576 * var is_Array = CeL.object_tester('Array', 'OtS'); 577 * // test 578 * if(is_Array(value)) 579 * // it's really a native Array 580 * ; 581 */ 582 object_tester = function(want_type, toString_reference) { 583 var t = '[object ' + want_type + ']'; 584 585 /* 586 return new Function('v', 'return "' + t + '"===' 587 + (toString_reference || 588 // 在 Google Chrome 中 'Object.prototype.toString' 可以與其 reference 同速度,但其他的 reference 會快些。 589 'Object.prototype.toString' 590 //'get_object_type' 591 ) 592 + '.call(v);'); 593 */ 594 595 return typeof toString_reference === 'string' 596 && toString_reference ? 597 new Function('v', 'return "' + t 598 + '"===' + toString_reference + '.call(v);') 599 600 // slow@Chrome 601 : function(v) { return t === get_object_type.call(v); }; 602 // faster@Chrome 603 //: new Function('v', 'return "' + t + '"===Object.prototype.toString.call(v);'); 604 605 }; 606 607 CeL 608 . 609 /** 610 * Test if the value is a native Array. 611 * @param v value to test 612 * @returns {Boolean} the value is a native Array. 613 * @since 2009/12/20 08:38:26 614 */ 615 is_Array = 616 // _.object_tester('Array'); 617 function(v) { 618 // instanceof 比 Object.prototype.toString 快 619 return v instanceof Array 620 || get_object_type.call(v) === '[object Array]'; 621 }; 622 623 CeL 624 . 625 /** 626 * Test if the value is a native Object. 627 * TODO: 628 * test null 629 * @param v value to test 630 * @returns {Boolean} the value is a native Object. 631 * @since 2009/12/20 08:38:26 632 */ 633 is_Object = 634 // Object.prototype.toString.call(undefined) === '[object Object]' @ MSIE 6.0 635 get_object_type.call(undefined) === '[object Object]'? 636 function(v) { 637 return typeof v !== 'undefined' 638 && get_object_type.call(v) === '[object Object]'; 639 } 640 : 641 //_.object_tester('Object'); 642 function(v) { 643 // 非如此不得與 jQuery 平起平坐… 644 return get_object_type.call(v) === '[object Object]'; 645 }; 646 647 CeL 648 . 649 /** 650 * Test if the value is a native Function. 651 * @param v value to test 652 * @returns {Boolean} the value is a native Function. 653 * @since 2009/12/20 08:38:26 654 */ 655 is_Function = 656 //_.object_tester('Function'); 657 function(v) { 658 // typeof 比 Object.prototype.toString 快,不過得注意有些 native object 可能 type 是 'function',但不具有 function 特性。 659 return get_object_type.call(v) === '[object Function]'; 660 661 // 須注意,在 firefox 3 中,typeof [object HTMLObjectElement] 之外的 HTMLElement 皆 === 'function', 662 // 因此光用 typeof() === 'function' 而執行下去會得出 [XPCWrappedNative_NoHelper] Component is not available 663 //return typeof v === 'function' || get_object_type.call(v) === '[object Function]'; 664 }; 665 666 667 //----------------------------------------------------------------------------------------------------------------------------------------------------------// 668 669 670 CeL 671 . 672 /** 673 * 取得/設定環境變數 enumeration<br/> 674 * (雖然不喜歡另開 name-space,但以 2009 當下的 JsDoc Toolkit 來說,似乎沒辦法創造 enumeration。) 675 * @class 環境變數 (environment variables) 與程式會用到的 library 相關變數 / configuration。 676 * @param {String} name 環境變數名稱 677 * @param value 環境變數之值 678 * @returns 舊環境變數之值 679 * @memberOf CeL 680 */ 681 env = function env(name, value) { 682 if (!name) 683 //return undefined; 684 return; 685 686 var _s = env, v = _s[name]; 687 688 if (arguments.length > 1) _s[name] = value; 689 //if (typeof value !== 'undefined') _s[name] = value; 690 691 return isNaN(v) ? String(v) : v; 692 }; 693 694 695 CeL 696 . 697 /** 698 * Setup environment variables 699 * @param {String} [OS_type] type of OS 700 * @param {Boolean} [reset] reset the environment variables 701 * @returns {Object} environment variables set 702 */ 703 initial_env = function(OS_type, reset){ 704 if (reset) 705 this.env = {}; 706 707 var OS, env = this.env; 708 709 /** 710 * default extension of script file. 711 * 設定成 '.' 時由 CeL.get_script_base_path 設定 712 * @type String 713 * @see 714 * <a href="http://soswitcher.blogspot.com/2009/05/blogger-host-javascript-file-for-free.html" accessdate="2010/3/11 23:30">Blogger - Host Javascript File for Free - Blogger,Javascript - Blogger Blog by Switcher</a> 715 * @name CeL.env.script_extension 716 */ 717 env.script_extension = typeof WScript === 'undefined' ? '.' : '.js';//'.txt' 718 719 /** 720 * library main file base name 721 * @name CeL.env.main_script_name 722 * @type String 723 */ 724 env.main_script_name = 'ce'; 725 726 /** 727 * library main file name<br/> 728 * full path: {@link CeL.env.registry_path} + {@link CeL.env.main_script} 729 * @example: 730 * CeL.log('full path: ['+CeL.env.registry_path+CeL.env.main_script+']'); 731 * @name CeL.env.main_script 732 * @type String 733 */ 734 env.main_script = env.main_script_name + env.script_extension; 735 736 /** 737 * module 中的這 member 定義了哪些 member 不被 extend 738 * @name CeL.env.not_to_extend_keyword 739 * @type String 740 */ 741 env.not_to_extend_keyword = 'no_extend'; 742 743 /** 744 * 本 library source 檔案使用之 encoding<br/> 745 * 不使用會產生語法錯誤 746 * @name CeL.env.source_encoding 747 * @type String 748 */ 749 env.source_encoding = 'UTF-16'; 750 751 /** 752 * default global object. 753 * 有可能為 undefined! 754 * @name CeL.env.global 755 * @type Object 756 */ 757 env.global = global; 758 759 /** 760 * creator group / 組織名稱 organization name 761 * @name CeL.env.organization 762 * @type String 763 */ 764 env.organization = 'Colorless echo'; 765 766 /** 767 * 在 registry 中存放 library 資料的 base path 768 * @name CeL.env.registry_base 769 * @type String 770 */ 771 env.registry_base = 'HKCU\\Software\\' + env.organization + '\\' + this.Class 772 + '\\'; 773 /** 774 * 在 registry 中存放 library 在 File System 中的 base path 的 key name 775 * @name CeL.env.registry_base 776 * @type String 777 */ 778 env.registry_path_key_name = env.registry_base + 'path'; 779 //if(typeof WScript === 'object') 780 try { 781 //WScript.Echo(env.registry_path_key_name); 782 783 /** 784 * 存放在 registry 中的 path,通常指的是 library 在 File System 中的 base path 785 * @name CeL.env.registry_path 786 * @type String 787 */ 788 env.registry_path = (WScript.CreateObject("WScript.Shell")) 789 .RegRead(env.registry_path_key_name) 790 // 去除 filename 791 //.replace(/[^\\\/]+$/, '') 792 ; 793 //this.debug(env.registry_path); 794 } catch (e) { 795 // this.warn(e.message); 796 } 797 798 799 //條件式編譯(条件コンパイル) for version>=4, 用 /*@ and @*/ to 判別 800 /*@cc_on 801 @if(@_PowerPC||@_mac) 802 OS='Mac'; 803 @else 804 @if(@_win32||@_win64||@_win16) 805 OS='DOS'; 806 @else 807 OS='unix'; // unknown 808 @end 809 @end@*/ 810 811 /** 812 * 本次執行所在 OS 平台 813 * @name CeL.env.OS 814 * @type String 815 */ 816 env.OS = OS = typeof OS_type === 'string' ? OS_type 817 // 假如未設定則取預設值 818 : (OS || 'unix'); 819 820 /** 821 * 文件預設 new line 822 * @name CeL.env.new_line 823 * @type String 824 */ 825 env.new_line= OS == 'unix' ? '\n' : OS == 'Mac' ? '\r' : '\r\n'; // in VB: vbCrLf 826 /** 827 * file system 預設 path separator<br/> 828 * platform-dependent path separator character, 決定目錄(directory)分隔 829 * @name CeL.env.path_separator 830 * @type String 831 */ 832 env.path_separator = OS == 'unix' ? '/' : '\\'; 833 /** 834 * 預設 module name separator 835 * @name CeL.env.module_name_separator 836 * @type String 837 */ 838 env.module_name_separator = '.'; 839 /** 840 * path_separator in 通用(regular)運算式 841 * @name CeL.env.path_separator_RegExp 842 * @type RegExp 843 */ 844 env.path_separator_RegExp = this.to_RegExp_pattern ? this 845 .to_RegExp_pattern(env.path_separator) 846 : (env.path_separator === '\\' ? '\\' : '') + env.path_separator; 847 /** 848 * 預設語系 849 * 0x404:中文-台灣,0x0411:日文-日本 850 * @name CeL.env.locale 851 * @see <a href="http://msdn.microsoft.com/zh-tw/library/system.globalization.cultureinfo(VS.80).aspx">CultureInfo 類別</a> 852 * @type Number 853 */ 854 env.locale = 0x404; 855 856 /** 857 * script name 858 * @name CeL.env.script_name 859 * @type String 860 */ 861 env.script_name = this.get_script_name(); 862 /** 863 * base path of script. 864 * TODO 865 * 以 reg 代替 866 * @name CeL.env.script_base_path 867 * @type String 868 */ 869 env.script_base_path = this.get_script_full_name() 870 // 去除 filename 871 .replace(/[^\\\/]+$/, ''); 872 873 /** 874 * Legal identifier name in RegExp. 875 * 這 pattern 會佔去兩個筆紀錄: first letter, and least. 876 * .replace(/_/ [g],'for first letter') 877 * .replace(/\\d/,'for least') 878 * 這邊列出的只是合法 identifier 的*子集*,且未去除 reserved words! 879 * 請注意實際判別須加入 ^..$ 880 * 881 * 不用 \d 而用 0-9 是因為 \d 還包括了 MATHEMATICAL BOLD DIGIT。 882 * <a href="http://blog.est.im/archives/3229" accessdate="2010/11/16 20:6">基于正则的URL匹配安全性考虑</a> 883 * @name CeL.env.identifier_RegExp 884 * @see 885 * ECMA-262 7.6 Identifier Names and Identifiers 886 * @type RegExp 887 */ 888 env.identifier_RegExp = /([a-zA-Z$_]|\\u[0-9a-fA-F]{4})([a-zA-Z$_0-9]+|\\u[0-9a-fA-F]{4}){0,63}/; 889 890 /** 891 * Legal identifier name in String from env.identifier_RegExp. 892 * @name CeL.env.identifier_String 893 */ 894 env.identifier_String = env.identifier_RegExp.source; 895 896 return env; 897 }; 898 899 900 CeL 901 . 902 // TODO 903 get_identifier_RegExp = function(pattern, flag, add_for_first_letter, add_for_all_letter) { 904 var s = this.env.identifier_String; 905 if (add_for_first_letter) 906 s = s.replace(/_/g, add_for_first_letter); 907 if (add_for_all_letter) 908 s = s.replace(/0-9/g, add_for_all_letter); 909 910 return new RegExp( 911 (get_object_type.call(pattern) === '[object RegExp]' ? pattern.source : pattern) 912 .replace(/$identifier/g, s), flag || ''); 913 }; 914 915 916 //----------------------------------------------------------------------------------------------------------------------------------------------------------// 917 918 919 CeL 920 . 921 /** 922 * Tell if it's now debugging. 923 * @param {Integer} [debug_level] if it's now in this debug level. 924 * @returns {Boolean} It's now in specified debug level. 925 * @returns {Number} It's now in what debug level (Integer). 926 */ 927 is_debug = function(debug_level){ 928 return typeof debug_level === 'undefined' ? debug 929 : debug >= debug_level; 930 }; 931 932 CeL 933 . 934 /** 935 * Set debugging level 936 * @param {Integer} [debug_level] The debugging level to set. 937 * @type Integer 938 * @returns {Number} debugging level now 939 */ 940 set_debug = function (debug_level) { 941 if (!isNaN(debug_level)) 942 debug = debug_level; 943 944 else if (typeof debug_level === 'undefined' && !debug) 945 debug = 1; 946 947 return debug; 948 }; 949 950 951 /* 952 CeL.extend(function f_name(){}, object || string, initial arguments); 953 CeL.extend({name:function(){},.. }, object || string); 954 CeL.extend([function1,function12,..], object || string); 955 956 set .name 957 */ 958 959 960 961 962 963 964 965 CeL 966 . 967 /** 968 * Get the hash key of text. 969 * @param {String} text text to test 970 * @returns {String} hash key 971 */ 972 _get_hash_key = function(text) { 973 //text = String(text); 974 //text = '' + text; 975 var l = text.length, take = 30, from = .3; 976 from = Math.floor(l * from); 977 //this.log(from + '~' + l + ': ' + (l - from < take ? text : text.substr(from, take))); 978 return l - from < take ? text : text.substr(from, take); 979 }; 980 981 982 // for JScript<=5 983 try { 984 function_name_pattern = new RegExp('^function[\\s\\n]+(\\w+)[\\s\\n]*\\('); 985 } catch (e) { 986 function_name_pattern = function emulate_function_name(fs) { 987 fs = String(fs); 988 var l = 'function ', r, s; 989 990 if (fs.indexOf(l) === 0) { 991 l = l.length; 992 s = { 993 ' ' : 1, 994 '\n' : 1, 995 '\r' : 1, 996 '\t' : 1 997 }; 998 while (fs.charAt(l) in s) 999 l++; 1000 r = fs.indexOf('(', l); 1001 while (fs.charAt(--r) in s) 1002 ; 1003 1004 return [ , fs.slice(l, r + 1) ]; 1005 } 1006 }; 1007 if (typeof RegExp != 'object') 1008 eval('RegExp = function(){};'); 1009 } 1010 1011 CeL 1012 . 1013 /** 1014 * 獲得函數名 1015 * @param {Function} fr function reference 1016 * @param {String} ns name-space 1017 * @param {Boolean} force_load force reload this name-space 1018 * @returns 1019 * @see 1020 * 可能的話請改用 {@link CeL.native.parse_function}(F).funcName 1021 * @since 2010/1/7 22:10:27 1022 */ 1023 get_function_name = function(fr, ns, force_load) { 1024 var _s = _.get_function_name, 1025 // 初始化變數 'm' 1026 m = 0, ft, b, load, k, i; 1027 if (!fr) 1028 try{ 1029 fr = _s.caller; 1030 }catch (e) { 1031 // TODO: handle exception 1032 } 1033 1034 // get function text (函數的解譯文字) 1035 // 不用 insteadof 是怕傳入奇怪的東西,例如 {string} script code 1036 m = typeof fr; 1037 if (m === 'function') { 1038 // 勿更改傳入之 argument 1039 /* 1040 if ('toString' in fr) { 1041 m = fr.toString; 1042 delete fr.toString; 1043 } 1044 ft = String(fr); 1045 if (m) 1046 fr.toString = m; 1047 */ 1048 // TODO: cache Function.prototype.toString 1049 ft = Function.prototype.toString.call(fr); 1050 } else if(m === 'string') 1051 // typeof fr === 'string' 1052 ft = fr; 1053 else 1054 return ''; 1055 1056 // 以函數的解譯文字獲得函數名 1057 if (m = function_name_pattern instanceof RegExp ? 1058 // 包含引數: + '(' + (f ? m[2] : '') + ')'; 1059 ((m = ft.match(function_name_pattern)) && m[1] || 0) 1060 : function_name_pattern instanceof Function ? 1061 function_name_pattern(ft) 1062 : 0){ 1063 //this.debug('matched ' + m, 1, this.Class + '.get_function_name'); 1064 return m; 1065 } 1066 // 無法從 function code 本身得到 name 之資訊。 1067 1068 // 查詢是否是已註冊之 function 1069 if (b = _s.b) 1070 load = _s.ns; 1071 else 1072 _s.b = b = {}, _s.ns = load = {}; 1073 1074 if (!ns) 1075 ns = this; 1076 1077 // cache functions 1078 if ((typeof ns === 'function' || this.is_Object(ns)) && ns.Class 1079 && (force_load || !load[ns.Class])) { 1080 for (i in ns) 1081 if (typeof ns[i] === 'function'){ 1082 k = this._get_hash_key(String(ns[i])); 1083 m = ns.Class + this.env.module_name_separator + i; 1084 //this.debug(m + ': ' + k + (', ' + ns[i]).slice(0, 200)); 1085 if(!(m in load)){ 1086 load[m] = 1; 1087 if (!b[k]) 1088 b[k] = []; 1089 b[k].push( [ m, ns[i] ]); 1090 } 1091 } 1092 load[ns.Class] = 1; 1093 } 1094 1095 // 將函數與 cache 比對以獲得函數名 1096 if (m = b[this._get_hash_key(ft)]) 1097 for (i = 0; i < m.length; i++) { 1098 b= m[i][1]; 1099 if (// typeof fr === 'function' && 1100 fr === b) 1101 return m[i][0]; 1102 if (ft === String(b)) 1103 return m[i]; 1104 } 1105 }; 1106 1107 1108 1109 1110 1111 1112 1113 CeL 1114 . 1115 null_function = function() {}; 1116 1117 1118 // Initialization 1119 1120 // temporary decoration in case we call for nothing and raise error 1121 _.debug = _.err = _.warn = _.log = function(m) { 1122 /* 1123 * 請注意: 1124 * _.log.buffer === this.log.buffer !== log.buffer 1125 * 在 WScript 中 需要用 _.log,其他則可用 log。 1126 * 因此應該將所有類似的值指定給雙方,並注意非[常數]的情況。 1127 */ 1128 var _s = this.log; 1129 //_s.function_to_call.apply(null,arguments); 1130 //_s.function_to_call.apply(global, arguments); 1131 1132 _s.buffer.push(m); 1133 1134 if (!_s.max_length) 1135 _s.max_length = 0; 1136 1137 if (debug && _s.buffer.length > _s.max_length) 1138 _s.function_to_call.call(global, _s.buffer.join('\n\n')), 1139 _s.buffer = []; 1140 }; 1141 1142 1143 /* 1144 * test: 1145 * var k=function l(){alert(l.m);};k.m=1;alert(l.m+','+k.m);k(); 1146 * 1147 * JScript 中 1148 * k(); 1149 * 為 undefined, 其他會把 "l." 代換成 "k."? 1150 * 1151 * @inner 1152 */ 1153 //_.debug.buffer = _.err.buffer = _.warn.buffer = 1154 _.log.buffer = []; 1155 1156 1157 //_.debug.max_length = _.err.max_length = _.warn.max_length = 1158 _.log.max_length = 0; 1159 1160 1161 var max_log_length = 1000; 1162 //_.debug.function_to_call = _.err.function_to_call = _.warn.function_to_call = 1163 _.log.function_to_call = 1164 typeof JSalert === 'function' ? JSalert : 1165 typeof WScript === 'object' ? function(m){m=String(m);if(m.length>2*max_log_length)m=m.slice(0,max_log_length)+'\n\n..\n\n'+m.slice(-max_log_length);WScript.Echo(m);} : 1166 typeof alert === 'object' || typeof alert === 'function' ? function(m){m=String(m);if(m.length>2*max_log_length)m=m.slice(0,max_log_length)+'\n\n..\n\n'+m.slice(-max_log_length);alert(m);} : 1167 _.null_function; 1168 1169 1170 _.initial_env(); 1171 1172 1173 /* 1174 var test_obj = _(2, 'test: Initialization'); 1175 1176 test_obj.test_print('OK!'); 1177 */ 1178 ; 1179 1180 1181 } 1182 )( 1183 // In strict mode, this inside globe functions is undefined. 1184 // https://developer.mozilla.org/en/JavaScript/Strict_mode 1185 //this // || typeof window === 'undefined' || window 1186 ) 1187 //) // void( 1188 ; 1189 1190 1191 1192 //==========================================================================================================================================================// 1193 1194 1195 1196 1197 1198 1199 /* 1200 TODO: 1201 1202 瘦身 1203 1204 use -> using because of 'use' is a keyword of JScript. 1205 1206 等呼叫時才 initialization 1207 1208 1209 http://headjs.com/#theory 1210 Head JS :: The only script in your HEAD 1211 1212 1213 do not use eval. 1214 以其他方法取代 eval 的使用。 1215 1216 http://msdn.microsoft.com/en-us/library/2b36h1wa(VS.71).aspx 1217 The arguments object is not available when running in fast mode, the default for JScript .NET. To compile a program from the command line that uses the arguments object, you must turn off the fast option by using /fast-. It is not safe to turn off the fast option in ASP.NET because of threading issues. 1218 1219 1220 Multiversion Support 1221 http://requirejs.org/docs/api.html 1222 1223 */ 1224 1225 1226 typeof CeL === 'function' && 1227 (function (_) { 1228 1229 'use strict'; 1230 1231 1232 //var _// JSDT:_module_ 1233 //= this; 1234 1235 1236 CeL 1237 . 1238 /** 1239 * 延展物件 (learned from jQuery): 1240 * 將 from_name_space 下的 variable_set 延展/覆蓋到 name_space。 1241 * @since 2009/11/25 21:17:44 1242 * @param variable_set variable set 1243 * @param {Object|Function} name_space extend to what name-space 1244 * @param {Object|Function} from_name_space When inputing function names, we need a base name-space to search these functions. 1245 * @returns library names-pace 1246 * @see 1247 * <a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/03/01/jquery-extend.aspx" accessdate="2009/11/17 1:24" title="jQuery.extend的用法 - 黑暗執行緒">jQuery.extend的用法</a>, 1248 * <a href="http://www.cnblogs.com/rubylouvre/archive/2009/11/21/1607072.html" accessdate="2010/1/1 1:40">jQuery源码学习笔记三 - Ruby's Louvre - 博客园</a> 1249 */ 1250 extend = function extend(variable_set, name_space, from_name_space) { 1251 var _s = extend, i, l; 1252 1253 if(typeof name_space === 'undefined' || name_space === null) 1254 // 如果沒有指定擴展的對象,則擴展到 library 自身 1255 name_space = _s.default_target; 1256 1257 if (typeof from_name_space === 'undefined') 1258 from_name_space = _s.default_target; 1259 else if (variable_set === null && _.is_Function(from_name_space)) 1260 variable_set = from_name_space; 1261 1262 if (typeof variable_set === 'function') { 1263 if (_.parse_function) { 1264 } else { 1265 _.warn('Warning: Please include ' + _.Class + '.parse_function() first!'); 1266 } 1267 1268 } else if (typeof variable_set === 'string') { 1269 if (!from_name_space) 1270 from_name_space = _; 1271 1272 if(name_space === from_name_space) 1273 ; 1274 else if(variable_set in from_name_space){ 1275 //_.debug('extend (' + (typeof variable_set) + ') ' + variable_set + '\n=' + from_name_space[variable_set] + '\n\nto:\n' + name_space); 1276 name_space[variable_set] = from_name_space[variable_set]; 1277 }else 1278 try{ 1279 name_space[variable_set] = _.get_variable(variable_set); 1280 //_.debug(variable_set + ' = ' + name_space[variable_set]); 1281 }catch(e){ 1282 _.warn(_.Class + '.extend:\n' + e.message); 1283 } 1284 1285 } else if (_.is_Array(variable_set) 1286 && !_.is_Array(name_space)) { 1287 for (i = 0, l = variable_set.length; i < l; i++) { 1288 _s(variable_set[i], name_space, from_name_space); 1289 } 1290 1291 } else if (_.is_Object(variable_set) 1292 //|| _.is_Function(variable_set) 1293 ) { 1294 for (i in variable_set) { 1295 if (from_name_space) 1296 name_space[i] = from_name_space[variable_set[i] || i]; 1297 else 1298 name_space[i] = variable_set[i]; 1299 } 1300 } 1301 1302 return _; 1303 }; 1304 1305 //_.extend.default_target = _; 1306 1307 1308 CeL 1309 . 1310 /** 1311 * workaround. 1312 * 把 name_space 下的 function_name (name_space[function_name]) 換成 new_function。 1313 * for Lazy Function Definition Pattern. 1314 * 惰性求值(Lazy Evaluation),又稱懶惰求值、懶漢求值 1315 * @example 1316 * library_namespace.replace_function(_, 'to_SI_prefix', to_SI_prefix); 1317 * @param name_space in which name-space 1318 * @param {String} function_name name_space.function_name 1319 * @param {Function} new_function replace to what function 1320 * @returns new_function 1321 * @see 1322 * http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/, 1323 * http://peter.michaux.ca/article/3556 1324 */ 1325 replace_function = function(name_space, function_name, new_function) { 1326 if(!name_space) 1327 return;//name_space = this; 1328 1329 var old_function = name_space[function_name], type = typeof new_function; 1330 1331 // TODO: RegExp 1332 if (type === 'bool' || type === 'string' || type === 'number') 1333 new_function = new Function('return' 1334 // 對 String 只是做簡單處理,勢必得再加強。 1335 + (type === 'string' ? '"' + type.replace(/\\/g, '\\').replace(/"/g, '\"').replace(/\n/g, '\\n') 1336 + '"' : ' '+type)); 1337 1338 name_space[function_name] = new_function; 1339 // search for other extends 1340 if (_[function_name] === old_function) 1341 _[function_name] = new_function; 1342 1343 return new_function.apply(name_space, arguments); 1344 }; 1345 1346 1347 //----------------------------------------------------------------------------------------------------------------------------------------------------------// 1348 1349 /** 1350 * XMLHttpRequest object type cache. 1351 * {Number} 0: no XMLHttpRequest, 1: new XMLHttpRequest_type(), 2: new ActiveXObject('Microsoft.XMLHTTP'). 1352 * @inner 1353 * @ignore 1354 */ 1355 var XMLHttpRequest_type = 0; 1356 try{ 1357 if(new XMLHttpRequest()) 1358 XMLHttpRequest_type = 1; 1359 else 1360 throw 1; 1361 }catch(e){ 1362 try{ 1363 if(new ActiveXObject('Microsoft.XMLHTTP')) 1364 XMLHttpRequest_type = 2; 1365 }catch(e){ 1366 } 1367 } 1368 1369 var is_Opera = typeof navigator === 'object' 1370 && navigator.appName === 'Opera'; 1371 1372 CeL 1373 . 1374 /** 1375 * Get file resource by {@link XMLHttpRequest}<br/> 1376 * 依序載入 resource,用於 include JavaScript 檔之類需求時,取得檔案內容之輕量級函數。<br/> 1377 * 除 Ajax,本函數亦可用在 CScript 執行中。 1378 * @example 1379 * // get contents of [path/to/file]: 1380 * var file_contents = CeL.get_file('path/to/file'); 1381 * @param {String} path URI / full path. <em style="text-decoration:line-through;">不能用相對path!</em> 1382 * @param {String} [encoding] file encoding 1383 * @returns {String} data content of path 1384 * @returns {undefined} when error occurred: no Ajax function, .. 1385 * @throws uncaught exception @ Firefox: 0x80520012 (NS_ERROR_FILE_NOT_FOUND), <a href="http://www.w3.org/TR/2007/WD-XMLHttpRequest-20070227/#exceptions">NETWORK_ERR</a> exception 1386 * @throws 'Access to restricted URI denied' 當 access 到上一層目錄時 @ Firefox 1387 * @see 1388 * <a href=http://blog.joycode.com/saucer/archive/2006/10/03/84572.aspx">Cross Site AJAX</a>, 1389 * <a href="http://domscripting.com/blog/display/91">Cross-domain Ajax</a>, 1390 * <a href="http://forums.mozillazine.org/viewtopic.php?f=25&t=737645" accessdate="2010/1/1 19:37">FF3 issue with iFrames and XSLT standards</a>, 1391 * <a href="http://kb.mozillazine.org/Security.fileuri.strict_origin_policy" accessdate="2010/1/1 19:38">Security.fileuri.strict origin policy - MozillaZine Knowledge Base</a> 1392 * Chrome: <a href="http://code.google.com/p/chromium/issues/detail?id=37586" title="between builds 39339 (good) and 39344 (bad)">NETWORK_ERR: XMLHttpRequest Exception 101</a> 1393 */ 1394 get_file = XMLHttpRequest_type ? function(path, encoding) { 1395 //with(typeof window.XMLHttpRequest=='undefined'?new ActiveXObject('Microsoft.XMLHTTP'):new XMLHttpRequest()){ 1396 1397 //_.debug('XMLHttpRequest type: ' + XMLHttpRequest_type, 1, 'get_file'); 1398 1399 var _s = _.get_file, 1400 data, 1401 type = 'GET', 1402 /** 1403 * XMLHttpRequest object. 1404 * Can't cache this object. 1405 * @inner 1406 * @ignore 1407 */ 1408 o = XMLHttpRequest_type === 1 ? 1409 new XMLHttpRequest() 1410 : new ActiveXObject('Microsoft.XMLHTTP'); 1411 1412 // 4096: URL 長度限制,與瀏覽器有關。 1413 if (typeof path === 'string' && path.length > 4096 1414 && (data = path.match(/^([^?]{6,200})\?(.+)$/))) 1415 path = data[1], data = data[2], type = 'PUT'; 1416 else 1417 data = null; 1418 1419 o.open(type, path, false); 1420 1421 if (encoding && o.overrideMimeType) 1422 /* 1423 * old: o.overrideMimeType('text/xml;charset='+encoding); 1424 * 但這樣會被當作 XML 解析,產生語法錯誤。 1425 */ 1426 o.overrideMimeType('application/json;charset=' + encoding); 1427 1428 try { 1429 // http://www.w3.org/TR/2007/WD-XMLHttpRequest-20070227/#dfn-send 1430 // Invoking send() without the data argument must give the same result as if it was invoked with null as argument. 1431 o.send(data); 1432 delete _s.error; 1433 1434 } catch (e) { 1435 // Chome: XMLHttpRequest cannot load file:///X:/*.js. Cross origin requests are only supported for HTTP. 1436 // Opera 11.50: 不會 throw,但是 .responseText === ''。 1437 // Apple Safari 3.0.3 may throw NETWORK_ERR: XMLHttpRequest Exception 101 1438 _s.error = e; 1439 1440 //_.warn(_.Class + '.get_file: Loading [' + path + '] failed: ' + e); 1441 //_.err(e); 1442 //_.debug('Loading [' + path + '] failed.'); 1443 1444 //e.object = o; // [XPCWrappedNative_NoHelper] Cannot modify properties of a WrappedNative @ firefox 1445 1446 if (typeof location === 'object' 1447 && (o = path.match(/:(\/\/)?([^\/]+)/)) 1448 && o[2] !== location.hostname) { 1449 _.warn('get_file: 所要求檔案之 domain [' + o[2] 1450 + '] 與所處之 domain [' + location.hostname + '] 不同!<br/>\n您可能需要嘗試使用 ' 1451 + _.Class + '.include_resource()!'); 1452 throw new Error('get_file: Different domain!'); 1453 } 1454 1455 o = _.require_netscape_privilege(e, [_s, arguments]); 1456 //_.debug('require_netscape_privilege return [' + typeof (o) + ('] ' + o).slice(0, 200) + ' ' + (e === o ? '=' : '!') + '== ' + 'error (' + e + ')'); 1457 if (e === o) 1458 throw e; 1459 1460 return o; 1461 } 1462 1463 // workaround for Opera: Opera 11.50: 不會 throw,但是 .responseText === ''。 1464 if (o.responseText === '' && is_Opera) 1465 throw new Error('get_file: Nothing get @ Opera'); 1466 1467 // 當在 local 時,成功的話 status === 0。失敗的話,除 IE 外,status 亦總是 0。 1468 // status was introduced in Windows Internet Explorer 7. http://msdn.microsoft.com/en-us/library/ms534650%28VS.85%29.aspx 1469 // 因此,在 local 失敗時,僅 IE 可由 status 探測,其他得由 responseText 判別。 1470 //_.debug('Get [' + path + '], status: [' + o.status + '] ' + o.statusText); 1471 1472 return Math.floor(o.status / 100) > 3 ? [ o.status, o.responseText ] : o.responseText; 1473 } 1474 : function() { 1475 // No XMLHttpRequest object. 1476 1477 throw new Error('get_file: This browser does not support XMLHttpRequest.'); 1478 // firefox: This function must return a result of type any. 1479 //return undefined; 1480 }; 1481 1482 1483 CeL 1484 . 1485 /** 1486 * Ask privilege in mozilla projects: Firefox 2, 3. 1487 * get_file() 遇到需要提高權限時使用。 1488 * enablePrivilege 似乎只能在執行的 function 本身或 caller 呼叫才有效果,跳出函數即無效,不能 cache,因此提供 callback。 1489 * 就算按下「記住此決定」,重開瀏覽器後需要再重新授權。 1490 * @param {String|Error} privilege privilege that asked 或因權限不足導致的 Error 1491 * @param {Function|Array} callback|[callback,arguments] Run this callback if getting the privilege. If it's not a function but a number(經過幾層/loop層數), detect if there's a loop or run the caller. 1492 * @returns OK / the return of callback 1493 * @throws error 1494 * @since 2010/1/2 00:40:42 1495 */ 1496 require_netscape_privilege = function require_netscape_privilege(privilege, callback) { 1497 var _s = require_netscape_privilege, f, i, 1498 /** 1499 * raise error. 1500 * error 有很多種,所以僅以 'object' 判定。 1501 * @inner 1502 * @ignore 1503 */ 1504 re = function(m) { 1505 //_.debug('Error: ' + m); 1506 throw privilege && typeof privilege === 'object' ? 1507 // Error object 1508 privilege : 1509 // new Error (message) 1510 new Error(m); 1511 }; 1512 1513 if (!_s.enabled) 1514 re('Privilege requiring disabled.'); 1515 1516 // test loop 1517 // 得小心使用: 指定錯可能造成 loop! 1518 if (!isNaN(callback) && callback > 0 && callback < 32) { 1519 try{ 1520 // @Firefox 4: TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them 1521 for (f = _s, i = 0; i < callback; i++) 1522 if (f = f.caller) 1523 // TODO: do not use arguments 1524 f = f.arguments.callee; 1525 1526 if (f === _s) 1527 // It's looped 1528 re('Privilege requiring looped.'); 1529 1530 callback = 1; 1531 1532 }catch (e) { 1533 // TODO: handle exception 1534 } 1535 1536 } 1537 1538 f = _s.enablePrivilege; 1539 //_.debug('enablePrivilege: ' + f); 1540 if (!f && !(_s.enablePrivilege = f = 1541 _.get_variable('netscape.security.PrivilegeManager.enablePrivilege'))) 1542 // 更改設定,預防白忙。 1543 _s.enabled = false, 1544 re('No enablePrivilege get.'); 1545 1546 if (_.is_type(privilege, 'DOMException') 1547 && privilege.code === 1012) 1548 // http://jck11.pixnet.net/blog/post/11630232 1549 // Mozilla的安全機制是透過PrivilegeManager來管理,透過PrivilegeManager的enablePrivilege()函式來開啟這項設定。 1550 // 須在open()之前呼叫enablePrivilege()開啟UniversalBrowserRead權限。 1551 1552 // http://code.google.com/p/ubiquity-xforms/wiki/CrossDomainSubmissionDeployment 1553 // Or: In the URL type "about:config", get to "signed.applets.codebase_principal_support" and change its value to true. 1554 1555 // 由任何網站或視窗讀取私密性資料 1556 privilege = 'UniversalBrowserRead'; 1557 1558 else if (!privilege || typeof privilege !== 'string') 1559 re('Unknown privilege.'); 1560 1561 //_.debug('privilege: ' + privilege); 1562 try { 1563 //_.log(_.Class + '.require_netscape_privilege: Asking privilege [' + privilege + ']..'); 1564 f(privilege); 1565 } catch (e) { 1566 if (privilege !== 'UniversalBrowserRead' || !_.is_local()) 1567 _.warn(_.Class + '.require_netscape_privilege: User denied privilege [' + privilege + '].'); 1568 throw e; 1569 } 1570 1571 //_.debug('OK. Get [' + privilege + ']'); 1572 1573 1574 if (callback === 1) { 1575 //_.debug('再執行一次 caller..'); 1576 try{ 1577 callback = _s.caller; 1578 }catch (e) { 1579 // TODO: handle exception 1580 } 1581 return callback.apply(_, callback.arguments); 1582 1583 /* i = callback.apply(_, callback.arguments); 1584 _.debug(('return ' + i).slice(0, 200)); 1585 return i; 1586 */ 1587 } else if (_.is_Function(callback)) 1588 // 已審查過,為 function 1589 return callback(); 1590 else if (_.is_Array(callback)) 1591 return callback[0].apply(_, callback[1]); 1592 }; 1593 1594 CeL 1595 . 1596 /** 1597 * 當需要要求權限時,是否執行。(這樣可能彈出對話框) 1598 * Firefox 5 之後,就算要求了,對 local 也沒用,甚至會 hang 住掛掉,因此取消了。 1599 * @type Boolean 1600 */ 1601 require_netscape_privilege.enabled = false; 1602 1603 1604 //----------------------------------------------------------------------------------------------------------------------------------------------------------// 1605 1606 1607 CeL 1608 . 1609 /** 1610 * 得知 script file 之相對 base path 1611 * @param {String} JSFN script file name 1612 * @returns {String} relative base path 1613 * @example 1614 * <script type="text/javascript" src="../baseFunc.js"></script> 1615 * // 引數為本.js檔名。若是更改.js檔名,亦需要同步更動此值! 1616 * var basePath=get_script_base_path('baseFunc.js'); 1617 * perl: use File::Basename; 1618 */ 1619 get_script_base_path = function(JSFN){ 1620 //alert(JSFN); 1621 if(!JSFN) 1622 return (typeof location === 'object' ? 1623 // location.pathname 1624 location.href 1625 : typeof WScript === 'object' ? WScript.ScriptFullName 1626 // 用在把檔案拉到此檔上時不方便 1627 //: typeof WshShell === 'object' ? WshShell.CurrentDirectory 1628 : '').replace(/[^\/\\]+$/, ''); 1629 1630 // We don't use is_Object or so. 1631 // 通常會傳入的,都是已經驗證過的值,不會出現需要特殊認證的情況。 1632 // 因此精確繁複的驗證只用在可能輸入奇怪引數的情況。 1633 if (typeof document !== 'object') 1634 return ''; 1635 1636 // form dojo: d.config.baseUrl = src.substring(0, m.index); 1637 var i = 0, o = document.getElementsByTagName('script'), l = o.length, j, b, I; 1638 1639 for (; i < l; i++) 1640 try { 1641 // o[i].src 多是 full path, o[i].getAttribute('src') 僅取得其值,因此可能是相對的。 1642 j = o[i].getAttribute ? o[i].getAttribute('src') : o[i].src; 1643 I = j.lastIndexOf(JSFN); 1644 //alert(j + ',' + JSFN + ',' + I); 1645 if (I !== -1){ 1646 // TODO: dirty hack 1647 if (_.env.script_extension === '.') { 1648 b = j.slice(I + JSFN.length); 1649 if (b === 'js' || b === 'txt') 1650 _.env.script_extension += b, 1651 _.env.main_script += b; 1652 else{ 1653 b = ''; 1654 // 遇到奇怪的 extension 1655 continue; 1656 } 1657 } 1658 // TODO: test 是否以 JSFN 作為結尾 1659 b = j.slice(0, I); 1660 } 1661 } catch (e) { 1662 } 1663 1664 //_.log() 1665 1666 // b || './' 1667 return b || ''; 1668 }; 1669 1670 1671 //----------------------------------------------------------------------------------------------------------------------------------------------------------// 1672 1673 1674 CeL 1675 . 1676 /** 1677 * test 是否符合 module pattern. 1678 * TODO: improve 1679 * @param {String} test_string string to test 1680 * @returns {Boolean} 是否符合 module pattern 1681 */ 1682 is_module_pattern = function(test_string){ 1683 var r = _.env.module_identifier_RegExp; 1684 if (!r) { 1685 // initial module_identifier_RegExp 1686 r = _.env.identifier_RegExp.source; 1687 r = _.env.module_identifier_RegExp = new RegExp('^' + r 1688 + '(\\.' + r + ')*$'); 1689 } 1690 1691 return r.test(test_string); 1692 }; 1693 1694 1695 CeL 1696 . 1697 /** 1698 * test function.request 的項目是否為 module. 1699 * TODO 1700 * 現在還有很大問題! 1701 * @param {String} resource_string resource to test 1702 * @returns {Boolean} resource 是否為 module (true: is module, false: is URL?) 1703 */ 1704 request_item_maybe_module = function(resource_string) { 1705 return resource_string.charAt(0) === '.' 1706 || resource_string.charAt(0) === '/' 1707 || resource_string.indexOf(':') !== -1 1708 // || resource_string.indexOf('%')!==-1 1709 || /\.(js|css)$/i.test(resource_string) ? false : 1710 /\.$/.test(resource_string) 1711 || _.is_module_pattern(resource_string); 1712 }; 1713 1714 1715 var library_base_path; 1716 CeL 1717 . 1718 /** 1719 * get the path of specified module. 1720 * @example 1721 * // 存放 data 的 path 1722 * path = library_namespace.get_module_path(this, ''); 1723 * 1724 * @param {String} module_name module name 1725 * @param {String} file_name 取得在同一目錄下檔名為 file_name 之 path。若填入 '' 可取得 parent 目錄。 1726 * @returns {String} module path 1727 */ 1728 get_module_path = function(module_name, file_name){ 1729 module_name = get_module_name(module_name); 1730 var m; 1731 if (!module_name || !(m = _.split_module_name(module_name))) 1732 return module_name; 1733 1734 //_.debug('load [' + module_name + ']', 1, 'get_module_path'); 1735 var module_path = library_base_path 1736 || (library_base_path = 1737 _.env.registry_path 1738 || _.get_script_base_path(_.env.main_script) 1739 || _.get_script_base_path() 1740 ); 1741 //_.debug('library_base_path: ' + library_base_path, 1, 'get_module_path'); 1742 1743 module_path += m.join(/\//.test(module_path)?'/':'\\') + _.env.script_extension; 1744 //_.debug('module_path: ' + module_path, 1, 'get_module_path'); 1745 1746 if (typeof file_name !== 'undefined') 1747 module_path = module_path.replace(/[^\/]+$/, file_name); 1748 else if (_.getFP) 1749 module_path = _.getFP(module_path, 1); 1750 1751 //_.debug(module_name + ': return [' + module_path + ']', 1, 'get_module_path'); 1752 1753 return module_path; 1754 }; 1755 1756 1757 /* 1758 sample to test: 1759 1760 ./a/b 1761 ./a/b/ 1762 ../a/b 1763 ../a/b/ 1764 a/../b ./b 1765 a/./b a/b 1766 /../a/b /a/b 1767 /./a/b /a/b 1768 /a/./b /a/b 1769 /a/../b /b 1770 /a/../../../b /b 1771 /a/b/.. /a 1772 /a/b/../ /a/ 1773 a/b/.. a 1774 a/b/../ a/ 1775 a/.. . 1776 ./a/b/../../../a.b/../c ../c 1777 ../../../a.b/../c ../../../c 1778 1779 */ 1780 1781 // 2009/11/23 22:12:5 1782 if(0) 1783 CeL 1784 . 1785 deprecated_simplify_path = function(path){ 1786 if(typeof path === 'string'){ 1787 // 去除前後空白 1788 path = path.replace(/\s+$|^\s+/,'').replace(/\/\/+/g,'/'); 1789 1790 var p, is_absolute = '/' === path.charAt(0); 1791 1792 while( path !== (p=path.replace(/\/\.(\/|$)/g,function($0,$1){return $1;})) ) 1793 path = p; 1794 _.debug('1. '+p); 1795 1796 while (path !== (p = path.replace( 1797 /\/([^\/]+)\/\.\.(\/|$)/g, function($0, $1, $2) { 1798 alert( [ $0, $1, $2 ].join('\n')); 1799 return $1 === '..' ? $0 : $2; 1800 }))) 1801 path = p; 1802 _.debug('2. '+p); 1803 1804 if(is_absolute) 1805 path = path.replace(/^(\/\.\.)+/g,''); 1806 else 1807 path = path.replace(/^(\.\/)+/g,''); 1808 _.debug('3. '+p); 1809 1810 if(!path) 1811 path = '.'; 1812 } 1813 1814 return path; 1815 }; 1816 1817 CeL 1818 . 1819 /** 1820 * 轉化所有 /., /.., // 1821 * @since 2009/11/23 22:32:52 1822 * @param {String} path 欲轉化之 path 1823 * @returns {String} path 1824 */ 1825 simplify_path = function(path){ 1826 if(typeof path === 'string'){ 1827 var i, j, l, is_absolute, head; 1828 1829 path = path 1830 .replace(/^[\w\d\-]+:\/\//,function($0){head = $0; return '';}) 1831 // 去除前後空白 1832 //.replace(/\s+$|^\s+/g,'') 1833 //.replace(/\/\/+/g,'/') 1834 .split('/'); 1835 1836 i = 0; 1837 l = path.length; 1838 is_absolute = !path[0]; 1839 1840 for(;i<l;i++){ 1841 if(path[i] === '.') 1842 path[i] = ''; 1843 1844 else if(path[i] === '..'){ 1845 j=i; 1846 while(j>0) 1847 if(path[--j] && path[j]!='..'){ 1848 path[i] = path[j] = ''; // 相消 1849 break; 1850 } 1851 } 1852 } 1853 1854 if(!is_absolute && !path[0]) 1855 path[0] = '.'; 1856 1857 path = path.join('/') 1858 .replace(/\/\/+/g,'/') 1859 .replace(is_absolute? /^(\/\.\.)+/g: /^(\.\/)+/g,'') 1860 ; 1861 1862 if(!path) 1863 path = '.'; 1864 1865 if(head) 1866 path = head + path; 1867 } 1868 1869 return path; 1870 }; 1871 1872 1873 1874 /** 1875 * 載入 module 時執行 extend 工作 1876 * @param module 1877 * @param extend_to 1878 * @param {Function} callback 1879 * @returns 1880 * @inner 1881 * @ignore 1882 */ 1883 var extend_module_member = function(module, extend_to, callback) { 1884 var i, l; 1885 1886 //typeof name_space !== 'undefined' && _.debug(name_space); 1887 // 處理 extend to what name-space 1888 if (!extend_to && extend_to !== false 1889 // 若是在 .setup_module 中的話,可以探測得到 name_space?(忘了) 1890 //|| typeof name_space !== 'function' 1891 || !_.is_Object(extend_to)) 1892 // 預設會 extend 到 library 本身下 1893 extend_to = _; 1894 1895 if (extend_to && (i = _.get_module(module))) { 1896 var ns = i, kw = _.env.not_to_extend_keyword, no_extend = {}; 1897 //_.debug('load [' + module + ']:\nextend\n' + ns); 1898 1899 if (kw in ns) { 1900 l = ns[kw]; 1901 if (typeof l === 'string' && l.indexOf(',') > 0) 1902 l = l.split(','); 1903 1904 if (typeof l === 'string') { 1905 no_extend[l] = 1; 1906 } else if (_.is_Array(l)) { 1907 for (i = 0; i < l.length; i++) 1908 // WScript.Echo('no_extend '+l[i]), 1909 no_extend[l[i]] = 1; 1910 } else if (_.is_Object(l)) { 1911 no_extend = l; 1912 } 1913 1914 no_extend[kw] = 1; 1915 } 1916 1917 // '*': 完全不 extend 1918 if (!no_extend['*']) { 1919 no_extend.Class = 1; 1920 // this: 連 module 本身都不 extend 到 library name-space 下 1921 var no_self = 'this' in no_extend; 1922 if(no_self) 1923 delete no_extend['this']; 1924 1925 l = []; 1926 for (i in ns) 1927 if (!(i in no_extend)) 1928 l.push(i); 1929 1930 //_.debug('load [' + module + ']:\nextend\n' + l + '\n\nto:\n' + (extend_to.Class || extend_to)); 1931 _.extend(l, extend_to, ns); 1932 1933 /* 1934 * extend module itself. 1935 * e.g., .net.web -> .web 1936 */ 1937 if (!no_self && (i = _.split_module_name(module)) 1938 && (i = i.pop()) && !(i in _)) 1939 _[i] = ns; 1940 } 1941 1942 } 1943 1944 1945 try { 1946 i = _.is_Function(callback) && callback(undefined, module); 1947 } catch (e) { 1948 } 1949 return i; 1950 }; 1951 1952 1953 1954 1955 CeL 1956 . 1957 /** 1958 * 不使用 eval 的方法,get the module namespace of specific module name. 1959 * @param {String} module_name module name 1960 * @returns null some error occurred 1961 * @returns namespace of specific module name 1962 */ 1963 get_module = function(module_name) { 1964 module_name = _.split_module_name.call(_, module_name); 1965 1966 // TODO: test module_name.length 1967 if(!module_name) 1968 return null; 1969 1970 var i = 0, l = module_name.length, name_space = _; 1971 // 一層一層 call name-space 1972 while (i < l) 1973 try { 1974 name_space = name_space[module_name[i++]]; 1975 } catch (e) { 1976 return null; 1977 } 1978 1979 return name_space; 1980 }; 1981 1982 1983 1984 1985 CeL 1986 . 1987 /** 1988 * 載入 module。 1989 * <p> 1990 * 本函數會預先準備好下層 module 定義時的環境,但請盡量先 call 上層 name-space 1991 * 再定義下層的,否則可能會出現問題,如 memory leak 等。 1992 * </p> 1993 * 1994 * @param {String} 1995 * [module_name] 1996 * <p> 1997 * module name to register: 本 module 之 name(id) 1998 * </p> 1999 * @param {Function} 2000 * code_for_including 2001 * <p> 2002 * 若欲 include 整個 module 時,需囊括之 code。 2003 * </p> 2004 * code_for_including( 2005 * {Function} library_namespace: namespace of library, 2006 * load_arguments: 呼叫時之 argument(s) 2007 * ) 2008 * @returns null 2009 * <p> 2010 * invalid module 2011 * </p> 2012 * @returns {Object} 2013 * <p> 2014 * 下層 module 之 name-space 2015 * </p> 2016 * @returns undefined 2017 * <p> 2018 * something error, e.g., 未成功 load,code_for_including 2019 * return null, .. 2020 * </p> 2021 */ 2022 setup_module = function(module_name, code_for_including, parent_module_name) { 2023 // adapt arguments 2024 var i, l, name_space, allow_inherit, 2025 /** 2026 * translate {String} code_for_including to function 2027 */ 2028 name = function() { 2029 // null module constructor 2030 if (!code_for_including) 2031 code_for_including = function() { 2032 return function() {}; 2033 }; 2034 2035 else if (typeof code_for_including === 'string') 2036 code_for_including = 2037 // (new Function(code_for_including)).bind(CeL) 2038 new Function(code_for_including); 2039 }; 2040 2041 if (typeof module_name === 'string') { 2042 name(); 2043 if (_.is_Function(code_for_including) 2044 || _.is_Object(code_for_including)) 2045 code_for_including.module_name = module_name; 2046 2047 } else { 2048 code_for_including = module_name; 2049 // TODO: 不設定時會從呼叫時之 path (directory + file name) 取得 2050 } 2051 2052 if (_.is_Object(code_for_including)) { 2053 name_space = code_for_including; 2054 code_for_including = name_space.code; 2055 delete name_space.code; 2056 name(); 2057 2058 _.extend(name_space, code_for_including); 2059 2060 } else 2061 name(); 2062 2063 if (!module_name && !(module_name = code_for_including.module_name)) { 2064 _.err('The module name is not specified!'); 2065 _.debug(code_for_including); 2066 return null; 2067 } 2068 2069 // sub module 2070 if (_.is_Object(l = code_for_including.sub_module)) { 2071 name_space = module_name + _.env.module_name_separator; 2072 for (i in l) 2073 _.setup_module(name_space + i, l[i], module_name); 2074 } 2075 2076 //_.debug('prepare to setup module [' + module_name + ']', 1, 'setup_module'); 2077 2078 /** 2079 * 測試 dependency list 是不是皆已 loaded。 2080 * 會合併 parent module 之 request。 2081 * <dl> 2082 * <dt>依 (module name-space).require 設定 dependency list</dt> 2083 * <dd>(module name-space).require_module = module name[]</dd> 2084 * <dd>(module name-space).require_variable = {variable_name: full_name_with_module_name}</dd> 2085 * <dd>(module name-space).require_URL = URL[]</dd> 2086 * </dl> 2087 * TODO: 2088 * 就算輸入 module path 亦可自動判別出為 module 而非普通 resource。 2089 */ 2090 var require = _.parse_require(code_for_including.require, code_for_including.require_separator, parent_module_name && module_require_chain[parent_module_name]), URL_to_load, module_to_load; 2091 if (_.is_Object(require)) { 2092 _.extend( { 2093 require_module : 'module_to_load', 2094 require_variable : 'variable', 2095 require_URL : 'URL_to_load' 2096 }, code_for_including, require); 2097 2098 if (_.is_Array(require.module_to_load) 2099 && require.module_to_load.length) 2100 module_to_load = require.module_to_load; 2101 2102 if (_.is_Array(require.URL_to_load) 2103 && require.URL_to_load.length) 2104 URL_to_load = require.URL_to_load; 2105 } 2106 2107 2108 if (module_to_load || URL_to_load) { 2109 2110 //_.debug('module [' + (typeof module_name === 'string' ? module_name: undefined) + '] need to load:\n' + module_to_load, 1, 'setup_module'); 2111 2112 // check 登錄 2113 if (module_name in module_require_chain) { 2114 // 可能是循環參照(circular dependencies),還是執行 module code_for_including 2115 // 若本身已經在需求名單中則放行,避免相互需要造成堆疊空間不足(Out of stack space)或 Stack overflow。 2116 _.warn('Skip to load dependencies [' + module_to_load + '] of module [' + module_name + '] because the module is already in the require chain.\nmodule 正在需求鏈中。也許是循環參照(circular dependencies)?'); 2117 2118 }else{ 2119 2120 // 登錄: module_name 正在 call。若由其他 module call 的,那就登錄此 parent module。 2121 module_require_chain[parent_module_name || module_name] = require; 2122 2123 // include required modules 2124 if (module_to_load && _.use(module_to_load)) { 2125 // 若有未載入之 dependencies,則不載入 module。 2126 if(!_.is_local() || _.is_debug(2)) 2127 _.warn(_.Class + '.setup_module: Module [' + module_name + '] fault to load dependencies [' + module_to_load + ']. You have to load it later.'); 2128 2129 // throw and wait .include_resource() to call callback(path, module_name) 2130 // 為了預防後面還有 code 而繼續執行下去,所以採用 throw 而非 return。 2131 throw new Error(_.Class + '.setup_module: Module [' + module_name + '] 無法以 Ajax load required module!\nrequired module list: ['+module_to_load+']'); 2132 } 2133 2134 if (URL_to_load) { 2135 // 嘗試直接載入 2136 for (i in URL_to_load) 2137 try { 2138 if (l = _.get_file(i = URL_to_load[i])) 2139 _.eval_code(l); 2140 else 2141 throw 1; 2142 } catch (e) { 2143 _ .err('module [' + (typeof module_name === 'string' ? module_name : undefined) + '] load URL [' + i 2144 + '] error. You have to load it later.'); 2145 // return and wait .include_resource() to call callback(path, module_name) 2146 throw new Error(_.Class + '.setup_module: module [' + module_name + '] 無法以 Ajax load required URL [' + i + ']!'); 2147 } 2148 } 2149 2150 } 2151 2152 } 2153 // else 所有需求皆已在 queue 中,因此最後總**有機會(不包括發生錯誤的情況!)**會被 load,故 skip。 2154 2155 2156 var module_name_list = _.split_module_name(module_name); 2157 if (!module_name_list) { 2158 _.err('Illegal module name: [' + module_name + ']!'); 2159 _.debug(code_for_including); 2160 2161 // 執行完清除載入中之登錄 2162 if(module_name in module_require_chain) 2163 delete module_require_chain[module_name]; 2164 2165 return null; 2166 } 2167 2168 // 若皆載入: 準備執行 module code_for_including 2169 // 一層一層準備好、預定義 name-space 2170 for (i = 0, l = module_name_list.length - 1, name_space = _; i < l; i++) { 2171 if (!name_space[name = module_name_list[i]]) 2172 /** 2173 * <code> 2174 * _.debug('預先定義 module [' + _.to_module_name(module_name.slice(0, i + 1)) + ']'), 2175 * </code> 2176 */ 2177 name_space[name] = new Function( 2178 '// null constructor for module ' + 2179 _.to_module_name(module_name_list.slice(0, i + 1))); 2180 name_space = name_space[name]; 2181 } 2182 // name_space 這時是 module 的 parent module。 2183 2184 if ( 2185 // 尚未被定義或宣告過 2186 !name_space[name = module_name_list[l]] || 2187 // 可能是之前簡單定義過,例如被上面處理過。這時重新定義,並把原先的 member 搬過來。 2188 !name_space[name].Class) { 2189 2190 // 保留原先的 name-space,for 重新定義 2191 l = name_space[name]; 2192 2193 // extend code, 起始 name-space 2194 try { 2195 /** 2196 * 真正執行 module code. 2197 * <code> 2198 * _.debug('including code of [' + _.to_module_name(module_name) + ']..'), 2199 * </code> 2200 * TODO: code_for_including(_, load_arguments) 2201 */ 2202 i = code_for_including.call(code_for_including, _); 2203 i.prototype.constructor = i; 2204 if('allow_inherit' in i){ 2205 allow_inherit = i.allow_inherit; 2206 delete i.allow_inherit; 2207 } 2208 //code_for_including.toString = function() { return '[class_template ' + name + ']'; }; 2209 //i.toString = function() { return '[class ' + name + ']'; }; 2210 } catch (e) { 2211 _.err(_.Class + '.setup_module: load module [' 2212 + _.to_module_name(module_name) + '] error!\n' + e.message); 2213 i = undefined; 2214 } 2215 2216 if (i === undefined) 2217 // error? 2218 return; 2219 2220 name_space = name_space[name] = i; 2221 2222 // 把原先的 member 搬過來 2223 if (l) { 2224 delete l.Class; 2225 // may use: _.extend() 2226 for (i in l) 2227 name_space[i] = l[i]; 2228 } 2229 name_space.Class = _.to_module_name(module_name); 2230 } 2231 2232 /* 2233 l=[]; 2234 for(i in name_space) 2235 l.push(i); 2236 WScript.Echo('Get members:\n'+l.join(', ')); 2237 */ 2238 2239 // 執行完清除載入中之登錄 2240 if(module_name in module_require_chain) 2241 delete module_require_chain[module_name]; 2242 2243 set_loaded(name_space.Class, code_for_including, allow_inherit); 2244 2245 //_.debug('module [' + module_name + '] 設定 OK.', 1, 'setup_module'); 2246 2247 return name_space; 2248 }; 2249 2250 2251 2252 CeL 2253 . 2254 /** 2255 * 是否 cache code。 2256 * 若不是要重構 code 則不需要。 2257 * undefined: 依照預設 2258 * Boolean: 明確設定,但如此即無法繼承。 2259 * @type Boolean, undefined 2260 */ 2261 cache_code = /*_.is_debug() || */ undefined; 2262 2263 /** 2264 * cache 已經 include 之函式或 class。 2265 * loaded_module[module_name] = 2266 * undefined: 尚未載入。 2267 * {Boolean} true 已經載入,但未 cache code。 2268 * {Function} code 已經載入,這是 cache 了的 code。 2269 * @inner 2270 * @ignore 2271 * @type Object 2272 */ 2273 var loaded_module = { 2274 }; 2275 2276 2277 /** 2278 * 紀錄 **正在 load** 之 module 所需之 dependency list。 2279 * module_require_chain[module_name] = [未載入之 dependency list by .parse_require()] requesting now. 2280 * 2281 * ** 這一項僅在 .setup_module() 發現 dependency list 尚未載入完時,預防循環 request 而用。 2282 * @inner 2283 * @ignore 2284 * @type Object 2285 */ 2286 var module_require_chain = { 2287 }; 2288 2289 2290 2291 CeL 2292 . 2293 /** 2294 * 將輸入的 string 分割成各 module 單元。<br/> 2295 * need environment_adapter()<br/> 2296 * ** 並沒有對 module 做完善的審核! 2297 * @param {String} module_name module name 2298 * @returns {Array} module unit array 2299 */ 2300 split_module_name = function(module_name) { 2301 //_.debug('[' + module_name + ']→[' + module_name.replace(/\.\.+|\\\\+|\/\/+/g, '.').split(/\.|\\|\/|::/) + ']'); 2302 if (typeof module_name === 'string') 2303 module_name = module_name 2304 //.replace(/\.\.+|\\\\+|\/\/+/g, '.') 2305 .replace(/[\\\/]/g, '.') 2306 .split(/[.\\\/]|::/); 2307 2308 if (_.is_Array(module_name) && module_name.length) { 2309 // 去除 library name 2310 if (module_name.length > 1 && _.Class === module_name[0]) 2311 module_name.shift(); 2312 return module_name; 2313 } else 2314 return null; 2315 }; 2316 2317 2318 /** 2319 * 取得建構 code 之 module name。不以 library name 起始。 2320 * // get_module_name() 2321 * code_for_including.module_name === 'module_name'; 2322 * // _.to_module_name() 2323 * library_name.module_parent.module_child.Class === 'library_name.module_parent.module_child' === 'library_name.module_name'; 2324 * TODO: 2325 * 有效率的整合 get_module_name() 與 _.to_module_name() 2326 * @param code_for_including 2327 * @returns {String} module name 2328 */ 2329 var get_module_name = function(code_for_including) { 2330 //_.debug('module_name: ' + (_.is_Function(code_for_including) && code_for_including.module_name ? code_for_including.module_name : code_for_including), 1, 'get_module_name'); 2331 //_.debug('Class: ' + (_.is_Function(code_for_including) && code_for_including.Class ? code_for_including.Class : code_for_including), 1, 'get_module_name'); 2332 2333 return _.is_Function(code_for_including) && code_for_including.module_name ? 2334 code_for_including.module_name 2335 : code_for_including; 2336 }; 2337 2338 2339 CeL 2340 . 2341 /** 2342 * 取得 module 之 name。以 library name 起始。 2343 * @returns {String} module name start with library name 2344 */ 2345 to_module_name = function(module, separator) { 2346 if (_.is_Function(module)) 2347 module = module.Class; 2348 else if (module === _.env.main_script_name) 2349 module = _.Class; 2350 2351 if (typeof module === 'string') 2352 module = _.split_module_name(module); 2353 2354 var name = ''; 2355 if (_.is_Array(module)) { 2356 if (typeof separator !== 'string') 2357 separator = _.env.module_name_separator; 2358 if (module[0] !== _.Class) 2359 name = _.Class + separator; 2360 name += module.join(separator); 2361 } 2362 2363 return name; 2364 }; 2365 2366 2367 2368 //TODO 2369 CeL 2370 . 2371 get_require = function(func) { 2372 if (_.is_Function(func) || _.is_Object(func)) 2373 return func.require; 2374 2375 if (_.is_Function(func = loaded_module[_.to_module_name(func)])) 2376 return func.require_module; 2377 }; 2378 2379 //TODO 2380 CeL 2381 . 2382 unload_module = function(module, g){ 2383 /// <returns>error</returns> 2384 if(_.is_debug()) 2385 throw new Error('UNDO'); 2386 2387 }; 2388 2389 2390 CeL 2391 . 2392 /** 2393 * 判斷 module 是否存在, 2394 * TODO 2395 * 以及是否破損。 2396 * @param {String} module_name module name 2397 * @param {Array} module_name module name list 2398 * @returns {Boolean} 所指定 module 是否全部存在以及良好。 2399 */ 2400 is_loaded = function(module_name) { 2401 if (_.is_Array(module_name)) { 2402 for ( var i = 0, l = module_name.length; i < l; i++) 2403 if (!loaded_module[_.to_module_name(module_name[i])]) 2404 return false; 2405 return true; 2406 } 2407 2408 // var _s = arguments.callee; 2409 //_.debug('test ' + _.to_module_name(module_name)); 2410 2411 /* 2412 var code = loaded_module[_.to_module_name(module_name)], sub_module, prefix; 2413 if (_.is_Function(code) && (sub_module = code.sub_module)) { 2414 sub_module = sub_module.split('|'); 2415 prefix = module_name + _.env.module_name_separator; 2416 for ( var i = 0, l = module_name.length; i < l; i++){ 2417 _.debug('check [' + prefix + sub_module[i] + ']', 1, 'is_loaded'); 2418 if (!_.is_loaded(prefix + sub_module[i])) 2419 return false; 2420 } 2421 return true; 2422 } 2423 */ 2424 2425 return !!loaded_module[_.to_module_name(module_name)]; 2426 }; 2427 2428 2429 2430 /** 2431 * 設定登記 module 已載入。 2432 * @inner 2433 * @private 2434 */ 2435 var set_loaded = function(module_name, code_for_including, 2436 cache_code) { 2437 // _.debug(_.to_module_name(module_name)); 2438 loaded_module[_.to_module_name(module_name)] = (_.cache_code === undefined 2439 && cache_code || _.cache_code) 2440 && code_for_including || true; 2441 }; 2442 2443 2444 2445 2446 2447 function get_include_resource(split) { 2448 if (typeof document !== 'object' || !document.getElementsByTagName) 2449 // document!=='object': 誤在非 HTML 環境執行,卻要求 HTML 環境下的 resource? 2450 //if(typeof document==='object')_.warn(_.Class + ".include_resource: Can't load [" + path + "]!"); 2451 return; 2452 2453 var i, nodes = document.getElementsByTagName('script'), h, hn, count = 0, p, l; 2454 if (split) 2455 h = { 2456 script : {}, 2457 css : {} 2458 }, 2459 hn = h.script; 2460 else 2461 hn = h = {}; 2462 2463 l = nodes.length; 2464 for (i = 0; i < l; i++) 2465 if (p = _.simplify_path(nodes[i].src)) 2466 hn[p] = 1, count++; 2467 2468 nodes = document.getElementsByTagName('link'); 2469 if (split) 2470 hn = l.css; 2471 2472 l = nodes.length; 2473 for (i = 0; i < l; i++) 2474 if (p = _.simplify_path(nodes[i].href)) 2475 hn[p] = 1, count++; 2476 2477 return [ h, count ]; 2478 }; 2479 2480 /** 2481 * 已經 include_resource 了哪些 JavaScript 檔(存有其路徑). 2482 * included_path[path] = 2483 * undefined: 尚未載入。 2484 * true 已經載入。 2485 * 2486 * TODO: 2487 * included_path[index] = [time stamp, path], 2488 * @inner 2489 * @ignore 2490 * @type Object 2491 */ 2492 var included_path; 2493 2494 function included_path_init(){ 2495 var s = get_include_resource(); 2496 if(s) 2497 included_path = s[0]; 2498 return included_path || {}; 2499 } 2500 2501 2502 CeL 2503 . 2504 is_included = function(path) { 2505 return !!(included_path || included_path_init())[path]; 2506 }; 2507 2508 var set_included = function(path, timeout_id) { 2509 (included_path || included_path_init())[path] = timeout_id; 2510 }, 2511 2512 get_included = function(path) { 2513 return (included_path || included_path_init())[path]; 2514 }; 2515 2516 2517 2518 CeL 2519 . 2520 /** 2521 * include resource of module. 2522 * @example 2523 * // 外部程式使用時,通常用在 include 相對於 library 本身路徑固定的檔案。 2524 * // 例如 file_name 改成相對於 library 本身來說的路徑。 2525 * CeL.include_module_resource('../../game/game.css'); 2526 * 2527 * library_namespace.include_module_resource('select_input.css', this); 2528 * 2529 * @param {String} file_name 與 module 位於相同目錄下的 resource file name 2530 * @param {String} [module_name] 呼叫的 module name。未提供則設成 library base path,此時 file_name 為相對於 library 本身路徑的檔案。 2531 * @returns 2532 * @since 2010/1/1-2 13:58:09 2533 */ 2534 include_module_resource = function(file_name, module_name) { 2535 //var m = _.split_module_name.call(_, module_name); 2536 //if (m)m[m.length - 1] = file_name; 2537 return _.include_resource.call(_, 2538 _.get_module_path(get_module_name(module_name) || _.Class, file_name)); 2539 }; 2540 2541 2542 2543 //----------------------------------------------------------------------------------------------------------------------------------------------------------// 2544 2545 2546 CeL 2547 . 2548 /** 2549 * Include specified module.<br/> 2550 * 2551 * 會先嘗試以依序載入(asynchronous)的方式取得 module。 2552 * 無法以 Ajax 載入時,若未設定 callback,會回傳錯誤。若設定 callback,會以同步(synchronous)的方式載入 module,於載入完成執行 callback。 2553 * 若因為 browser 安全性設定而無法取得則會回傳 -1,表示將以同步的方式載入 module。因為 module 尚未載入,在此階段尚無法判別此 module 所需之 dependency list。此 list 會被作為引數傳入 callback。 2554 * 2555 * 注意:以下的 code 中,CeL.warn 不一定會被執行(可能會、可能不會),因為執行時 log 可能尚未被 include。<br/> 2556 * 此時應該改用 CeL.set_run('application.log', callback);<br/> 2557 * code in head/script/: 2558 * <code> 2559 * CeL.use('code.log'); 2560 * CeL.warn('WARNING message'); 2561 * </code> 2562 * ** 在指定 callback 時 name_space 無效! 2563 * ** 預設會 extend 到 library 本身之下! 2564 * @param {String} module module name 2565 * @param {Function} [callback] callback function | [callback, 進度改變時之 function (TODO)] 2566 * @param {Object|Boolean} [extend_to] extend to which name-space<br/> 2567 * false: just load, don't extend to library name-space<br/> 2568 * this: extend to global<br/> 2569 * object: extend to specified name-space that you can use [name_space]._func_ to run it<br/> 2570 * (others, including undefined): extend to root of this library. e.g., call CeL._function_name_ and we can get the specified function. 2571 * @returns {Error} 2572 * @returns -1 will execute callback after load, 不代表 load module 了! 2573 * @returns {undefined} no error, OK 2574 * @example 2575 * CeL.use('code.log', function(){..}); 2576 * CeL.use(['code.log', 'code.debug']); 2577 * @note 2578 * 'use' 是 JScript.NET 的保留字. 2579 */ 2580 use = function requires(module, callback, extend_to, force){ 2581 var _s = requires, i, l, module_path; 2582 2583 //_.debug('load [' + module + ']'); 2584 if (!module) 2585 return; 2586 2587 /* 2588 if (arguments.length > 3) { 2589 l = arguments.length; 2590 name_space = arguments[--l]; 2591 callback = arguments[--l]; 2592 --l; 2593 for (i = 0; i < l; i++) 2594 _s.call(_, arguments[i], callback, name_space); 2595 return; 2596 } 2597 */ 2598 2599 if (_.is_Array(module)) { 2600 var error; 2601 for (i = 0, l = module.length; i < l; i++) 2602 if (error = _s.call(_, module[i], 0, extend_to)) 2603 return error; 2604 try { 2605 i = _.is_Function(callback) && callback(undefined, module); 2606 } catch (e) { 2607 } 2608 return i; 2609 } 2610 2611 if (!force && _.is_loaded(module) 2612 || !(module_path = _.get_module_path(module))) { 2613 try { 2614 i = _.is_Function(callback) 2615 && callback(undefined, module); 2616 } catch (e) { 2617 } 2618 return i; 2619 } 2620 2621 //_.debug('load [' + module + ']:\ntry to load [' + module_path + ']'); 2622 2623 // including code 2624 try { 2625 try{ 2626 // _.debug('load ['+module_path+']'); 2627 // _.debug('load ['+module_path+']:\n'+_.get_file(module_path, _.env.source_encoding)); 2628 //WScript.Echo(_.eval); 2629 if (i = _.get_file(module_path, _.env.source_encoding)) 2630 // eval @ global. 這邊可能會出現 security 問題。 2631 // TODO: 以其他方法取代 eval 的使用。 2632 _.eval_code(i); 2633 else 2634 _.warn('Get no result from [' + module_path + ']! Some error occurred?'); 2635 i = 0; 2636 } catch (e) { 2637 i = e; 2638 } 2639 2640 if (!i) 2641 return extend_module_member(module, extend_to, callback); 2642 2643 // 依序載入失敗 2644 if (callback && typeof window !== 'undefined') { 2645 // 不能直接用 .get_file(),得採用其他方法的狀況。但只在有 callback 時才 include,否則當下 block 的都沒執行,可能出亂子。 2646 // ** 較新之 browser 通常需要使用 callback 的方法,不能使用 "CeL.use('module');_do_some_thing_;"!! 2647 // TODO: 在指定 callback 時使 name_space 依然有效。 2648 _.include_resource(module_path, { 2649 module : module, 2650 callback : function(){ 2651 extend_module_member(module, extend_to, callback); 2652 }, 2653 start : new Date(), 2654 timeout : 80, 2655 global : _ 2656 }, 2657 // 正在 call(循環參照?)則強制 include 2658 module in module_require_chain); 2659 // TODO: 一次指定多個 module 時可以知道進度,全部 load 完才 callback()。 2660 // 此時 callback=[callback, 進度改變時之 function] 2661 // return 進度 Object 2662 return -1; 2663 } 2664 throw i; 2665 2666 } catch (e) { 2667 //_.err(e); 2668 2669 // http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html 2670 // http://reference.sitepoint.com/javascript/DOMException 2671 if (_.is_type(e, 'DOMException') && e.code === 1012) { 2672 if(!_.is_local() || _.is_debug(2)) 2673 _.err(_.Class 2674 + '.use:\n' 2675 + e.message + '\n' 2676 + module_path 2677 + '\n\n程式可能呼叫了一個' 2678 + (_.is_local() ? '不存在的,\n或是繞經上層目錄' 2679 : 'cross domain') 2680 + '的檔案?\n\n請嘗試使用相對路徑,\n或加入 callback: ' 2681 + _.Class 2682 + '.use(module, callback function, name_space)'); 2683 } else if (_.is_type(e, 'Error') && (e.number & 0xFFFF) == 5 2684 || _.is_type(e, 'XPCWrappedNative_NoHelper') 2685 && ('' + e.message).indexOf('NS_ERROR_FILE_NOT_FOUND') !== -1) { 2686 _.err(_.Class + '.use: 檔案可能不存在或存取被拒?\n[' + module_path + ']' + 2687 (_.get_error_message 2688 ? ('<br/>' + _.get_error_message(e)) 2689 : '\n' + e.message 2690 ) 2691 ); 2692 } else if(!_.is_local() || _.is_debug(2)) 2693 _.err(_.Class + '.use: Cannot load [<a href="' + module_path + '">' + module + '</a>]!' 2694 + (_.get_error_message 2695 ? ('<br/>' + _.get_error_message(e) + '<br/>') 2696 : '\n[' + (e.constructor) + '] ' + (e.number ? (e.number & 0xFFFF) : e.code) + ': ' + e.message + '\n' 2697 ) 2698 + '抱歉!在載入其他網頁時發生錯誤,有些功能可能失常。\n重新讀取(reload),或是過段時間再嘗試或許可以解決問題。'); 2699 //_.log('Cannot load [' + module + ']!', _.log.ERROR, e); 2700 2701 return e; 2702 } 2703 2704 }; 2705 2706 2707 CeL 2708 . 2709 is_local = function() { 2710 return typeof window !== 'object' 2711 || typeof location !== 'object' 2712 || window.location !== location 2713 || location.protocol === 'file:'; 2714 }; 2715 2716 /* 2717 bad: sometimes doesn't work. e.g. Google Maps API in IE 2718 push inside window.onload: 2719 window.onload=function(){ 2720 include_resource(p); 2721 setTimeout('init();',2000); 2722 }; 2723 2724 way 3: ref. dojo.provide();, dojo.require(); 2725 document.write('<script type="text/javascript" src="'+encodeURI(p)+'"><\/script>'); 2726 2727 TODO: 2728 encode 2729 2730 */ 2731 ; 2732 2733 CeL 2734 . 2735 /** 2736 * Including other JavaScript/CSS files synchronously. 2737 * 2738 * TODO: 2739 * timeout for giving up 2740 * use document.createElementNS() 2741 * http://headjs.com/#theory 2742 * 2743 * @param {String} resource path 2744 * @param {Function|Object} callback 2745 * use_write ? test function{return } : callback function(path) 2746 * / {callback: callback function(path, module), module: module name, global: global object when run callback} 2747 * @param {Boolean} [use_write] use document.write() instead of insert a element to <head> 2748 * @param {Number} [type] 1: is a .css file, others: script 2749 */ 2750 include_resource = function include_resource(path, callback, force, timeout, type, use_write) { 2751 var _s = _.include_resource, s, t, h; 2752 2753 if (_.is_Array(path)) { 2754 for (s = 0, t = path.length; s < t; s++) 2755 _s(path[s], callback, use_write, type); 2756 return; 2757 } 2758 2759 if (_.is_Object(force) && arguments.length === 3) { 2760 timeout = force.timeout; 2761 type = force.type; 2762 use_write = force.use_write; 2763 force = force.force; 2764 } 2765 2766 if(!force && _.is_included(path)){ 2767 // 已經載入完成 2768 _.is_Function(callback) && _s.wait_to_call(callback, path); 2769 return; 2770 } 2771 set_included(path); 2772 2773 //_.debug('Including [' + path + '].', 1, 'include_resource'); 2774 if (typeof type === 'undefined') 2775 type = /\.css$/i.test(path) ? 1 : 0; 2776 2777 t = 'text/' + (type === 1 ? 'css' : 'javascript'); 2778 /*@cc_on 2779 //use_write=1; // old old IE hack 2780 @*/ 2781 if (!use_write) 2782 try { 2783 // Dynamic Loading / lazy loading 2784 // http://code.google.com/apis/ajax/documentation/#Dynamic 2785 // http://en.wikipedia.org/wiki/Futures_and_promises 2786 s = document.createElement(type === 1 ? 'link' : 'script'); 2787 s.type = t; 2788 if (type === 1) 2789 s.href = path, 2790 // s.media = 'all',//'print' 2791 s.rel = 'stylesheet'; 2792 else 2793 // TODO: see jquery-1.4a2.js: globalEval 2794 // if (is_code) s.text = path; 2795 //s.setAttribute('src', path); 2796 s.src = path, 2797 s.async = true; 2798 2799 s.width = s.height = 0; 2800 2801 // http://wiki.forum.nokia.com/index.php/JavaScript_Performance_Best_Practices 2802 // ** onload 在 local 好像無效 2803 var done = false; 2804 s.onload = s.onreadstatechange = function(e) { 2805 var r; 2806 //_.debug('Loading [' + path + '] .. ' + this.readyState); 2807 // navigator.platform === 'PLAYSTATION 3' 時僅用 'complete'? from requireJS 2808 if (!done && (!(r = this.readyState /* 'readyState' in this ? this.readyState : e.type !== 'load' */) || r === 'loaded' || r === 'complete')) { 2809 done = true; 2810 //_.debug('[' + (this.src || s.href) + '] loaded.'); 2811 2812 //this.onload = this.onreadystatechange = null; 2813 try{ 2814 delete this.onload; 2815 }catch (e) { 2816 // error on IE5–7: Error: Object doesn't support this action 2817 this.onload = null; 2818 } 2819 try{ 2820 delete this.onreadystatechange; 2821 }catch (e) { 2822 // error on IE5–7: Error: Object doesn't support this action 2823 this.onreadystatechange = null; 2824 } 2825 2826 // callback 完自動移除 .js。隨即移除會無效。 .css 移除會失效。 2827 setTimeout(function() { 2828 if (type !== 1) 2829 h.removeChild(s); 2830 h = s = null; 2831 }, 1); 2832 2833 // css 無 timeout 功能。 2834 var tid = get_included(path); 2835 if (tid) { 2836 clearTimeout(tid); 2837 set_included(path, 0); 2838 } 2839 2840 if(callback) 2841 _s.wait_to_call(callback, path); 2842 2843 } 2844 }; 2845 2846 // HTML5: document.head === document.getElementsByTagName('head')[0] 2847 h = document.head || document.getElementsByTagName('head')[0] 2848 || (document.body.parentNode || document.body).appendChild(document.createElement('head')); 2849 2850 h.appendChild(s); 2851 //h.parentNode.insertBefore(s, h); 2852 2853 //_.debug('HTML:\n' + document.getElementsByTagName('html')[0].innerHTML); 2854 /* 2855 * from jquery-1.4a2.js: 2856 * Use insertBefore instead of appendChild to circumvent an IE6 bug 2857 * when using globalEval and a base node is found. 2858 * This arises when a base node is used (#2709). 2859 * @see 2860 * http://github.com/jquery/jquery/commit/d44c5025c42645a6e2b6e664b689669c3752b236 2861 * 不過這會有問題: 後加的 CSS file 優先權會比較高。因此,可以的話還是用 appendChild。 2862 */ 2863 //h.insertBefore(s, h.firstChild); 2864 2865 // css 無 timeout 功能。 2866 if (type !== 1) 2867 set_included(path, setTimeout(function() { 2868 _.warn('include_resource: Loading failed (timeout ' + timeout + ' ms): [' + path + ']'); 2869 // 自動移除 .js。 2870 h.removeChild(s); 2871 h = s = null; 2872 2873 if(callback) 2874 _s.wait_to_call(callback, path, true); 2875 }, timeout || (timeout = _.is_local() ? 2000 : 8000))); 2876 2877 return s; 2878 2879 } catch (e) { 2880 } 2881 2882 //_.debug('Writing code for [' + path + '].'); 2883 // 直接寫入,若非正在 load 頁面時使用會出問題! 2884 if (use_write 2885 || typeof use_write === 'undefined' // && TODO: 正在 load 頁面 2886 ) 2887 document.write(type === 1 ? 2888 '<link type="' + t + '" rel="stylesheet" href="' + path + '"><\/link>' 2889 : '<script type="' + t + '" src="' + path 2890 // language="JScript" 2891 + '"><\/script>'); 2892 2893 // 若是到這邊還沒 load,會造成問題。 2894 //set_included(path); 2895 2896 if (callback) 2897 _s.wait_to_call(callback, path); 2898 }; 2899 2900 2901 CeL 2902 . 2903 /** 2904 * 準備 callback 2905 * @inner 2906 * @private 2907 * @ignore 2908 */ 2909 include_resource.wait_to_call = function(callback, path, failed) { 2910 //alert('include_resource.wait_to_call:\n' + _.to_module_name(callback.module)); 2911 2912 if (_.is_Function(callback)) 2913 // 不是 module,僅僅為指定 function 的話,直接等一下再看看。 2914 // TODO: 等太久時 error handle 2915 setTimeout(function() { 2916 callback(path, undefined, failed); 2917 }, 200); 2918 2919 else if (_.is_Object(callback) && callback.global) 2920 // 是 module。 2921 if (callback.global.is_loaded(callback.module) 2922 || (new Date() - callback.start) > callback.timeout) { 2923 // 依 callback 的類型處理 callback 2924 if(_.is_Function(callback.callback)) 2925 // 直接執行 2926 callback.callback(path, callback.module, failed); 2927 2928 else if (typeof callback.callback === 'string') 2929 // load 另一個 module 2930 _.use(callback.callback); 2931 // TODO 2932 // else.. 2933 2934 } else { 2935 /** 2936 * 還沒載入完成,所以再等一下。 the function it self, not 'this'. 2937 * @inner 2938 * @ignore 2939 */ 2940 var _s = _.include_resource.wait_to_call, _t = this, _a = arguments; 2941 setTimeout(function() { 2942 _s.apply(_t, _a); 2943 }, 50); 2944 } 2945 }; 2946 2947 //if (_.is_Function(include_resource)) 2948 // _.extend(null, include_resource, _.include_resource); 2949 2950 2951 2952 /* 2953 2954 CeL.set_run(running sequence: [commands]|[required sequence]) 2955 [commands]/動作串 2956 [], 2957 function_to_run 2958 [optional] {object} function_to_run.config 2959 執行次序: 2960 [optional: run_first, on load required] function_to_run.run_first = function(is prepared?): [bool] time (ms) to re-check 2961 [optional] function_to_run.require = [require sequence] 2962 [optional: prepared, before trigger] function_to_run.before_load = function() 2963 [optional] waiting for function_to_run.trigger = 2964 觸發時機/trigger action time 2965 [string] action name | number = 0 2966 onload: 'load' (default), {number} timeout (ms) 2967 function_to_run.send_argument = (default: auto detect) 2968 function_to_run = function() event handler 2969 TODO: after_load 2970 2971 [required sequence]/前置條件/先備條件/prerequisite/necessary 2972 {string} library module name to import, {string} file path(image/JavaScript files/CSS), {number} timeout (ms) 2973 2974 .charAt(0)==='.' || .charAt(0)==='/' || .indexOf(':')!==-1 2975 //|| .indexOf('%')!==-1 2976 || /\.(js|css)$/i →URL 2977 2978 i=env.identifier_RegExp.source; 2979 env.module_identifier_RegExp=new RegExp('^'+i+'(\\.'+i+')*$'); →module 2980 2981 else→URL 2982 2983 ∴'path1.sub1.sub2'→'./path1.sub1.sub2' 2984 2985 2986 2987 CeL.set_run.error=function(message){ 2988 ; 2989 }; 2990 CeL.set_run.load={resource:status}; 2991 2992 CeL.use('module_name'); 2993 CeL.load('resource path'); 2994 2995 2996 2011/6/22 17:43:50,2011/7/31 00:11:52 2997 2998 2999 3000 3001 3002 3003 3004 .set_run(running sequence) 3005 3006 3007 // 同步 loading set: 可同時 load 的 {String|Function} module/path/function 3008 synchronous_group = { 3009 //check: {Function}, 3010 3011 // .to_run 會先執行,而後 delete 3012 to_run[]: [{Function} function], 3013 // to load 3014 to_load_path{}: [{String} path], 3015 // 有幾個 resources 需要 load 3016 path_count: integer count of to_load_path, 3017 to_load_module{}: [{String} module], 3018 module_count: integer count of to_load_module, 3019 3020 // 可能闕如: 下一組 3021 next_group: next synchronous_group{}, 3022 3023 // 可能闕如: timeout 用 3024 start_time: integer, 3025 // 已設定之 timeout (ms) 3026 timeout: integer, 3027 3028 // 可能闕如: 臨時新增用,是為了預防有 call C,但 dependency 為 A→B→C 的情況。重複使用 queue 但不檢查 require 可能造成 B 與 C 被放在同一 synchronous_group。 3029 require: {} 3030 }; 3031 3032 3033 3034 3035 臨時/後續/後來新增: 3036 3037 原先 [C,E] 3038 發現B→C [B,E]→[C] 3039 發現D→E [B,D]→[E]→[C] 3040 發現A→B [A,D]→[B]→[E]→[C] 3041 3042 2011/8/8 00:07:06 3043 3044 3045 3046 */ 3047 3048 CeL 3049 . 3050 /** 3051 * control/setup source codes to run. 3052 * 基本上使用同步(synchronous)的方式,除非所需資源已經載入,或是有辦法以 {@link XMLHttpRequest} 取得資源。 3053 * 3054 * @example 3055 * sr = CeL.set_run; 3056 * sr('module_name', function(){ 3057 * // ... 3058 * }); 3059 * 3060 * TODO: 3061 * sr('module_name', function(){ 3062 * CeL.import('module_name', {module_function_1:0}); 3063 * 3064 * CeL.module_function_1('11') === module_function_1('11'); 3065 * 3066 * var instance=new CeL.module_name.module_class_1; 3067 * instance.print(112); 3068 * }); 3069 * 3070 * 3071 * @param running sequence: list of 3072 * {Function} function to run/欲執行之 function → change .to_run 3073 * | {Integer} timeout (ms): 僅能保證上次 function 執行至此次 function 一定會等超過這段時間 → change .start_time, .timeout 3074 * | {String} library module name to import → change .to_load_module, .module_count 3075 * | {String} URL/file path (image/JavaScript files/CSS) → change .to_load_path, .path_count 3076 * | {Array} 另一組同時 loading set: [{String|Function|Integer}, ..] → 拆開全部當作同時 loading 3077 * | TODO: {Object} loading with additional config 3078 * 3079 * @since 2011/8/4 22:31:47 3080 */ 3081 set_run = function() { 3082 //_.debug('process ' + arguments.length + ' items.', 2, '.set_run'); 3083 if (arguments.length > 0) 3084 //Array.prototype.slice.call(arguments) 3085 check_run(arguments, 0); 3086 }; 3087 3088 3089 /** 3090 * main process. 3091 * 3092 * @param {Arguments} work_queue 3093 * sequence of set_run.arguments. 不修改 work_queue===set_run.arguments,直接以 work_queue_index 為開始值。 3094 * @param {Integer} work_queue_index 3095 * index of work queue 3096 * @param {Object} 3097 * [synchronous_group] 正在 running 的 set. 3098 * 3099 * @since 2011/8/4 22:31:47 3100 * 2011/8/8 23:27:15, –2011/8/11 18:29:51 rewrite 3101 */ 3102 function check_run(work_queue, work_queue_index, synchronous_group) { 3103 3104 var work_queue_length = work_queue.length, work_set; 3105 // 沒有累積的 synchronous_group 時,才繼續處理指定的工作。否則先處理之。 3106 if (!synchronous_group) { 3107 3108 while (!(work_set = work_queue[work_queue_index++])) { 3109 if (work_queue_index >= work_queue_length) 3110 _.debug('處理完畢: [' + work_queue_length + '] [' + Array.prototype.slice.call(work_queue) + ']', 2, 'check_run'); 3111 return; 3112 } 3113 3114 var to_run = [], to_load_path = {}, path_count = 0, to_load_module = {}, module_count = 0, timeout = 0, 3115 /** 3116 * 增加項目至當前的 synchronous_group. 3117 */ 3118 add_item = function(item) { 3119 // TODO 3120 // {Object} loading with additional config 3121 3122 if (_.is_Array(item)) { 3123 // {Array} 另一組同時 loading set: [{String|Function|Integer}, ..] → 3124 // 拆開全部當作同時 loading 3125 for ( var i in item) 3126 add_item(item[i]); 3127 3128 } else if (_.is_Function(item)) { 3129 // {Function} function to run → to_run 3130 if (!item.require){ 3131 // TODO 3132 // check if the function require something first. 3133 to_run.push(item); 3134 } else 3135 to_run.push(item); 3136 3137 } else if (typeof item === 'string') { 3138 if (_.request_item_maybe_module(item)){ 3139 // TODO: 若是已 cached 則跳過。 3140 //_.debug('treat resource [' + item + '] as module ' + module_count, 2, 'check_run'); 3141 if (!(item in to_load_module) && !_.is_loaded(item)) 3142 to_load_module[item] = 0, module_count++; 3143 } else if (!(item in to_load_path) && !_.is_included(item)) 3144 //_.debug('treat resource [' + item + '] as URL ' + path_count, 2, 'check_run'); 3145 to_load_path[item] = 0, path_count++; 3146 3147 } else if ((item = Math.floor(item)) > timeout) { 3148 // {Integer} timeout 3149 timeout = item; 3150 3151 } else { 3152 // 其他都將被忽略! 3153 _.warn('check_run: Unknown item: [' + item + ']'); 3154 } 3155 }; 3156 3157 // add item to synchronous_group 3158 add_item(work_set); 3159 3160 // 初始化 initialization synchronous_group 3161 synchronous_group = {}; 3162 3163 if (timeout) 3164 // 設定好時間 3165 synchronous_group.start_time = new Date(), 3166 synchronous_group.timeout = timeout; 3167 if (to_run.length) 3168 synchronous_group.to_run = to_run; 3169 if (path_count) 3170 synchronous_group.path_count = path_count, 3171 synchronous_group.to_load_path = to_load_path; 3172 if (module_count) 3173 synchronous_group.module_count = module_count, 3174 synchronous_group.to_load_module = to_load_module; 3175 3176 //_.debug(module_count + '個同步載入 resource 設定完畢。', 2, 'check_run'); 3177 } 3178 3179 3180 //_.debug('開始處理當前的 synchronous_group, work_queue ' + work_queue_index + '/' + work_queue_length, 2, 'check_run'); 3181 3182 var s, index, 3183 3184 /* 3185 3186 臨時/後續/後來新增: 3187 如果 check 發現 _path_ dependencies 尚未 load,則把 dependencies 加入 to_load_path|to_load_module,去除 (to_load_path|to_load_module)[_path_], 3188 新增一 synchronous_group, next_group.(to_load_path|to_load_module) = _path_ 並設置 synchronous_group.require{} = dependencies 3189 3190 原先 [C,E] 3191 發現B→C [B,E]→[C] 3192 發現D→E [B,D]→[E]→[C] 3193 發現A→B [A,D]→[B]→[E]→[C] 3194 3195 */ 3196 /** 3197 * 臨時/後續新增項目至當前的 synchronous_group. 3198 * callback 用. 3199 */ 3200 afterwards_add = function(item, item_is_path) { 3201 3202 var 3203 require = _.is_Function(item) ? 3204 _.parse_require(item.require, item.require_separator) : 3205 /** module */ 3206 module_require_chain[item], 3207 3208 to_load_path = require.URL_to_load, 3209 to_load_module = require.module_to_load; 3210 3211 if (!to_load_path && !to_load_module) 3212 return 1; 3213 3214 3215 var i, changed = false, s, n; 3216 3217 // 把 dependencies: URL 加入 synchronous_group 3218 if (to_load_path) { 3219 // synchronous_group 可能並沒有 .path_count 3220 if (isNaN(synchronous_group.path_count)) 3221 s = synchronous_group.to_load_path = {}, 3222 synchronous_group.path_count = 0; 3223 else 3224 s = synchronous_group.to_load_path; 3225 3226 for (i in to_load_path) 3227 if (i = to_load_path[i]){ 3228 _.debug('URL load dependency: [' + i + ']→[' + item + ']', 2, 'check_run.afterwards_add'); 3229 if(i in s) 3230 // 假如是同一批的 M1, M2 都需要 P0,則跑到 M2 時 P0 不需要設定第二次,但需要把 M2 移到下一批次。 3231 if ((n = synchronous_group.next_group) && !(item in n.to_load_path)) 3232 n.to_load_path[item] = 0, 3233 n.path_count++; 3234 else { 3235 if (_.is_debug() && (!n || _.is_debug(2))) 3236 _.warn('check_run.afterwards_add: 無法把 URL [' + item + '] 移到下一批次: 下一批次' + (n ? '不存在' : '已有此 URL') + '!'); 3237 } 3238 else 3239 // 因為是指向 Object,因此不需要再設定 synchronous_group.to_load_path。為防節外生枝,直接改 .path_count,不 cache。 3240 s[i] = 0, synchronous_group.path_count++, changed = true, load_URL(i); 3241 } 3242 3243 //show_set('after afterwards_add URL dependency changed'); 3244 } 3245 3246 // 把 dependencies: module 加入 synchronous_group 3247 if(to_load_module){ 3248 // synchronous_group 可能並沒有 .module_count 3249 if (isNaN(synchronous_group.module_count)) 3250 s = synchronous_group.to_load_module = {}, 3251 synchronous_group.module_count = 0; 3252 else 3253 // s: 當前欲載入之 module 3254 s = synchronous_group.to_load_module; 3255 3256 for (i in to_load_module) 3257 if (i = to_load_module[i]){ 3258 _.debug('module load dependency: [' + i + ']→[' + item + ']', 2, 'check_run.afterwards_add'); 3259 if (i in s) 3260 // 假如是同一批的 M1, M2 都需要 M0,則跑到 M2 時 M0 不需要設定第二次,但需要把 M2 移到下一批次。 3261 if ((n = synchronous_group.next_group) && !(item in n.to_load_module)) 3262 n.to_load_module[item] = 0, 3263 n.module_count++; 3264 else { 3265 if (_.is_debug() && (!n || _.is_debug(2))) 3266 _.warn('check_run.afterwards_add: 無法把 module [' + item + '] 移到下一批次: 下一批次' + (n ? '已有此 module' : '不存在') + '!'); 3267 } 3268 else 3269 // 因為是指向 Object,因此不需要再設定 synchronous_group.to_load_module。為防節外生枝,直接改 .module_count,不 cache。 3270 s[i] = 0, synchronous_group.module_count++, changed = true, load_module(i); 3271 } 3272 3273 //show_set('after afterwards_add module dependency changed'); 3274 } 3275 3276 if (changed && item) { 3277 //show_set('準備將 [' + item + '] 從 synchronous_group 搬到 next_group'); 3278 3279 if (s = synchronous_group.next_group) 3280 s = { 3281 next_group : s 3282 }; 3283 else { 3284 s = {}; 3285 if ('timeout' in synchronous_group) 3286 _.extend( { 3287 timeout : 0, 3288 start_time : 0 3289 }, s, synchronous_group); 3290 } 3291 synchronous_group.next_group = s; 3292 3293 if (item_is_path) { 3294 (s.to_load_path = {})[item] = 0; 3295 s.path_count = 1; 3296 } else if (typeof item === 'string') { 3297 (s.to_load_module = {})[item] = 0; 3298 s.module_count = 1; 3299 } else if (_.is_Function(item)) { 3300 (s.to_run = []).push(item); 3301 } 3302 //else warn(); 3303 3304 //show_set('已將 [' + item + '] 從 synchronous_group 搬到 next_group'); 3305 } else 3306 return 2; 3307 3308 }, 3309 3310 // debug 用 3311 //TODO: Object.keys(obj) 3312 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys 3313 get_Object_key = function(o) { 3314 if (_.is_Array(o)) 3315 return o; 3316 //if (!_.is_Object(o)) return; 3317 var i, l = []; 3318 for(i in o) 3319 l.push(i); 3320 return l; 3321 }, 3322 3323 // debug 用 3324 show_set = function(from) { 3325 if(_.is_debug(2)){ 3326 var ptr = synchronous_group, s_data = [ '預計先後載入同步載入組: ' + (from || '') ], d; 3327 do { 3328 d = ptr.to_load_module ? get_Object_key(ptr.to_load_module) : 0; 3329 s_data.push( 3330 d? 3331 '[' + (ptr.module_count === d.length ? ptr.module_count : '<em>登記 ' + ptr.module_count + ' != 實際 ' + d.length + '</em>') + '] ' 3332 + d.join(' <span style="color:#f00">|</span> ') 3333 : '<span style="color:#888">(none: 此同步載入組無預計載入之 module)</span>' 3334 ); 3335 } while (ptr = ptr.next_group); 3336 _.debug(s_data.join('<br/>'), 1, 'check_run.show_set'); 3337 } 3338 }, 3339 3340 //check module_require_chain{module_name} 3341 /** 3342 * 載入間執行之 function. 3343 * 有未載入之 dependencies,僅能從 callback 傳入此 module 所需之 dependency list 來處置。 3344 * TODO: 確認若是load錯誤時,會不會跳過 check_loading 不執行。 3345 */ 3346 check_loading, 3347 load_module, load_URL, 3348 move_to_next_group = false; 3349 3350 // synchronous_group.to_run: 若要處理 .to_run 的 require,則 check_loading() 還是需要設定。 3351 if (work_queue_index < work_queue_length || synchronous_group.to_run) 3352 check_loading = function(path, module_name) { 3353 //_.debug((module_name ? 'module [' + module_name + ']/all ' + synchronous_group.module_count : path ? 'path [' + path + ']/all ' + synchronous_group.path_count : '沒有尚未 load 的 resource') + (synchronous_group.timeout ? ', timeout ' + synchronous_group.timeout : ''), 1, 'check_run.check_loading'); 3354 //show_set('check_loading start'); 3355 3356 if(module_name){ 3357 3358 // is module 3359 delete synchronous_group.to_load_module[module_name]; 3360 synchronous_group.module_count--; 3361 3362 if (!_.is_loaded(module_name)) 3363 if (module_require_chain[module_name]) 3364 afterwards_add(module_name); 3365 else 3366 // 若有不存在的 module,因為會以 .include_resource 載入,在 MSIE 中會 throw。 3367 // 可以由判別 browser 改善此體驗。 3368 _.err('check_run.check_loading: Cannot load module [' + module_name + ']!'); 3369 3370 } else if (path) { 3371 3372 // is path, 無法判別是否成功 included。 3373 delete synchronous_group.to_load_path[path]; 3374 synchronous_group.path_count--; 3375 3376 } 3377 3378 // 可能因為循環參照(circular dependencies),這邊的 module 之前已經 load 過,因此需要再作 check。 3379 // .. pass 3380 ; 3381 3382 if (!synchronous_group.module_count 3383 && !synchronous_group.path_count){ 3384 var timeout = synchronous_group.timeout 3385 - (new Date() - synchronous_group.start_time); 3386 synchronous_group = synchronous_group.next_group; 3387 move_to_next_group = true; 3388 3389 //_.debug('Move to next synchronous load group. 本同步載入組已全部載入,' + (synchronous_group ? '進入下一同步載入組。' : work_queue_index < work_queue.length ? '繼續下一組指定的工作 [' + work_queue_index + '/' + work_queue.length + ']。' : '本次指定的 ' + work_queue_index + ' 項工作已全部執行完成。') + (timeout > 4 ? 'timeout ' + timeout + ' 超過 4ms,設定 timeout。' : ''), 1, 'check_run.check_loading'); 3390 if (timeout > 4) 3391 // TODO: setTimeout 可能不存在! 3392 setTimeout(function() { 3393 check_run(work_queue, work_queue_index, 3394 synchronous_group); 3395 }, timeout); 3396 else 3397 check_run(work_queue, work_queue_index, 3398 synchronous_group); 3399 //_.debug('設定完畢', 1, 'check_run.check_loading'); 3400 } 3401 }, 3402 3403 load_module = function(module_name) { 3404 //_.debug('[' + module_name + ']', 1, 'check_run.load_module'); 3405 // .use 會先試試 .get_file() 3406 _.use(module_name, check_loading); 3407 }, 3408 3409 load_URL = function(URL, encoding) { 3410 // 準備載入 resource. ** 在已經 loaded 的情況下有可能直接就執行完 return! 3411 //_.debug('[' + URL + ']', 1, 'check_run.load_URL'); 3412 if (/\.js$/i.test(URL)) 3413 try{ 3414 // 對 .js 先試試 .get_file() 3415 var t = _.get_file(URL, encoding); 3416 //_.debug('Get [' + t + ']', 2, 'check_run.load_URL'); 3417 if (t) 3418 // eval @ global. 這邊可能會出現 security 問題。 3419 // TODO: 以其他方法取代 eval 的使用。 3420 _.eval_code(t); 3421 3422 check_loading(URL); 3423 return; 3424 3425 }catch (e) { 3426 //_.err(e); 3427 } 3428 3429 //_.debug('需要作同步 loading resource [' + URL + ']', 1, 'check_run.load_URL'); 3430 _.include_resource(URL, check_loading); 3431 }; 3432 3433 // 把能處理的 .to_run function 先執行處理,而後早點 delete 以釋放空間。 3434 if(s = synchronous_group.to_run){ 3435 for (index in s) 3436 try { 3437 // 已經過鑑別,這邊的都是 Function 3438 s[index](); 3439 3440 } catch (e) { 3441 _.err('check_run: ' + e.message); 3442 _.debug('<code>' 3443 + ('' + s[index]).replace(/\n/g, '<br />') 3444 + '</code>'); 3445 } 3446 //_.debug('把能處理的 function 先處理完了,刪除synchronous_group.to_run 的資料。', 2); 3447 delete synchronous_group.to_run; 3448 } 3449 3450 3451 if(s = synchronous_group.to_load_module) 3452 for (index in s) 3453 load_module(index); 3454 3455 if(move_to_next_group) 3456 // 在上一個 load_module() 呼叫 check_loading() 時,可能因為 synchronous_group = synchronous_group.next_group 使得 synchronous_group 已轉換到下一 synchronous load group。 3457 return; 3458 3459 if(s = synchronous_group.to_load_path) 3460 for (index in s) 3461 load_URL(index); 3462 3463 3464 if (!move_to_next_group && check_loading && !synchronous_group.module_count 3465 && !synchronous_group.path_count){ 3466 //_.debug('[' + work_queue_index + '/' + work_queue_length + '] 沒有尚未 load 的 resource (例如只輸入 timeout 或每個 resource 皆 loaded),手動執行 check_loading。', 1, 'check_run'); 3467 check_loading(); 3468 } 3469 3470 // 開始蟄伏, waiting for callback 3471 } 3472 3473 3474 3475 //----------------------------------------------------------------------------------------------------------------------------------------------------------// 3476 3477 3478 3479 CeL 3480 . 3481 /** 3482 * module 中模擬 inherit 時使用。 3483 * 3484 * TODO: 3485 * 同步載入功能 3486 * @param {String} parent_module_name 欲繼承的 module_name 3487 * @param initial_arguments 繼承時的 initial arguments 3488 * @returns 3489 * @see 3490 * <a href="http://fillano.blog.ithome.com.tw/post/257/17355" accessdate="2010/1/1 0:6">Fillano's Learning Notes | 物件導向Javascript - 實作繼承的效果</a>, 3491 * <a href="http://www.crockford.com/javascript/inheritance.html" accessdate="2010/1/1 0:6">Classical Inheritance in JavaScript</a> 3492 */ 3493 inherit = function(parent_module_name, initial_arguments) { 3494 if(!_.cache_code && _.cache_code !== undefined) 3495 _.debug('inherit: cache code did not setted but try to inherit module!'); 3496 3497 var code_for_including = loaded_module[_.to_module_name(parent_module_name)]; 3498 try { 3499 if (_.is_Function(code_for_including)) 3500 return code_for_including.call(code_for_including, _, initial_arguments); 3501 3502 _.err('inherit: [' + parent_module_name + '] did not catched!'); 3503 } catch (e) { 3504 _.err('inherit: running of [' + parent_module_name + '] error!'); 3505 return e; 3506 } 3507 }; 3508 3509 3510 3511 3512 CeL 3513 . 3514 /** 3515 * 解析 dependency list 以獲得所需之 module/path/variable name.. 3516 * 3517 * @param {Array|String} 3518 * dependency_list 3519 * <p> 3520 * list of dependency function/module/variable required. module 須以 3521 * CeL.env.module_name_separator ('.') 結尾。若輸入 String,則以 separator 或 '|' 分割。 3522 * </p> 3523 * @returns {Object} result { variable: {variable_name: full_name}, module: 3524 * {module name: loaded or not}, module_to_load: [], URL: {}} 3525 * @returns {Number} error_no 3526 * @since 2011/8/6 22:10:57 3527 */ 3528 parse_require = function(dependency_list, separator, base_require) { 3529 3530 if(!dependency_list) 3531 // is_Object(undefined) === true! 3532 return 0; 3533 3534 if (typeof dependency_list === 'string') 3535 dependency_list = dependency_list.split(separator || '|'); 3536 else if (!_.is_Array(dependency_list) || !_.is_Object(dependency_list)) 3537 return 1; 3538 3539 var i, module, module_name_separator = _.env.module_name_separator, 3540 /** 3541 * variable name under module 3542 */ 3543 var_name, 3544 /** 3545 * 解析出要 extend 到 'this' 下的 variables。 3546 * variable_hash[variable name] = 所在 module name. 3547 */ 3548 //variable_hash = {}, 3549 /** 3550 * 解析出要 extend 到 'this' 下的 variables。 3551 * variable_full_name[variable name] = variable full name. 3552 */ 3553 variable_full_name, 3554 /** 3555 * 解析出的 URL paths. 3556 * URL_hash[URL] = loaded or not; 3557 */ 3558 URL_hash, 3559 /** 3560 * 解析出需要 load 的 URL paths. 3561 */ 3562 URL_to_load, 3563 /** 3564 * dependency_list 中指定的 module。 3565 * module_hash[module name] = loaded or not 3566 */ 3567 module_hash, 3568 /** 3569 * 已 load 的 module。 3570 */ 3571 //module_loaded = [], 3572 /** 3573 * 要 load 的 module。 3574 */ 3575 module_to_load; 3576 3577 if (_.is_Object(base_require)) { 3578 variable_full_name = base_require.variable, 3579 URL_hash = base_require.URL, 3580 URL_to_load = base_require.URL_to_load, 3581 module_hash = base_require.module, 3582 module_to_load = base_require.module_to_load; 3583 3584 //variable_hash = {}; 3585 } else { 3586 variable_full_name = {}, 3587 URL_hash = {}, 3588 URL_to_load = [], 3589 module_hash = {}, 3590 module_to_load = []; 3591 } 3592 3593 // 解析 dependency_list,將所須 functions/modules 置於 variable_hash/module_hash 中。 3594 for (i in dependency_list) 3595 if (_.request_item_maybe_module(i = dependency_list[i]) 3596 && (module = _.split_module_name(i))) { 3597 3598 // 類似 'data.split_String_to_Object' 的形式,為 function。 3599 // 類似 'data.' 的形式,為 module。 3600 if (var_name = module.pop()) 3601 variable_full_name[var_name] = ( 3602 //variable_hash[var_name] = 3603 _.to_module_name(module)) 3604 + module_name_separator + var_name; 3605 //_.debug('load module [' + _.to_module_name(module) + ']' + (var_name ? '.' + var_name : '')); 3606 3607 //_.debug('test module ['+module.join(module_name_separator)+']: '+_.get_variable(module.join(module_name_separator),_)); 3608 3609 // 不用 _.to_module_name,因為會加油添醋。 3610 module = module.join(module_name_separator); 3611 3612 // 確定是否還沒載入,必須 load。還沒載入則放在 module_to_load[] 中。 3613 if (!(module in module_hash)) { 3614 if (!(module_hash[module] = _.is_loaded(module))) 3615 //_.debug('module [' + module + '] need to load first.'), 3616 module_to_load.push(module); 3617 } 3618 3619 } else if (!(i in URL_hash) && !(URL_hash[i] = _.is_included(i))) 3620 URL_to_load.push(i); 3621 3622 3623 return { 3624 //require : dependency_list, 3625 variable : variable_full_name, 3626 3627 module : module_hash, 3628 //module_loaded : module_loaded, 3629 module_to_load : module_to_load, 3630 3631 URL : URL_hash, 3632 URL_to_load : URL_to_load 3633 }; 3634 }; 3635 3636 3637 /* 3638 //這得要直接貼在標的 scope 內才有用。 3639 var no_strict_variable_use = (function() { 3640 var v, i = 0; 3641 try { 3642 // find a undefined var_name 3643 for (;;) 3644 eval(v = 'tmp_' + i++); 3645 } catch (i) { 3646 } 3647 3648 eval('var ' + v + '=1;'); 3649 3650 try { 3651 // OK 表示在 eval 中可以設定 var. 3652 // 若是 'use strict'; 則不可在 eval() 中置 var. 3653 return eval(v); 3654 } catch (i) { 3655 } 3656 })(); 3657 */ 3658 3659 // http://closure-compiler.appspot.com/ 3660 // 這得要直接貼在標的 scope 內才有用。 3661 //var no_strict_variable_use=function(){var a,b=9;try{for(;;)eval(a="t_"+b++)}catch(c){}eval("var "+a+"=1;");try{return eval(a)}catch(d){}}(); 3662 3663 CeL 3664 . 3665 /** 3666 * module 中需要 include function/module/variable 時設定 local variables 使用。<br/> 3667 * 本函數將把所需 function include 至當前 namespace 下。 3668 * 3669 * TODO: 輸入 function name 即可 3670 * 3671 * @example 3672 * 3673 * // requires (inside module) 3674 * // 事先定義 @ 'use strict'; 3675 * var split_String_to_Object; 3676 * // 之所以需要使用 eval 是因為要 extend 至當前 namespace 下。 3677 * // 若無法 load CeL.data,將會 throw 3678 * eval(library_namespace.use_function(this, 'data.split_String_to_Object')); 3679 * // use it 3680 * split_String_to_Object(); 3681 * 3682 * // 不用 eval 的方法 1: function 預設都會 extend 至當前 library_namespace 下。 3683 * library_namespace.use_function(this, 'data.split_String_to_Object'); 3684 * library_namespace.use_function(this, 'data.split_String_to_Object', false); 3685 * // 若無法 load CeL.data,將會 throw 3686 * // use it 3687 * library_namespace.split_String_to_Object(); 3688 * 3689 * // 不用 eval 的方法 2: 設定 extend_to 3690 * var o={}; 3691 * // 若無法 load CeL.data,將會 throw 3692 * library_namespace.use_function(this, 'data.split_String_to_Object', o); 3693 * // use it 3694 * o.split_String_to_Object(); 3695 * 3696 * @param {Function|Object} name_space module name-space 3697 * @param {Array|String} dependency_list list of dependency function/module/variable required. module 須以 '.' 結尾。若輸入 String,則以 ',' 分割。 3698 * @param {Function|Object} [extend_to] 若設定將把 variable extend 至 extend_to 3699 * 3700 * @returns {Number} error code 3701 * 1: can't parse dependency_list 3702 * 3703 * @throws {Error} 有些 module 尚未載入。 3704 * 3705 * @since 2009/12/26 02:36:31 3706 * 2009/12/31 22:21:23 add 類似 'data.' 的形式,為 module。 3707 * 2010/6/14 22:58:18 避免相互 require 3708 */ 3709 use_function = function(name_space, extend_to, optional_use, no_strict) { 3710 3711 var module_name = get_module_name(name_space); 3712 3713 //_.debug('load function [' + dependency_list + ']' + (typeof module_name === 'string' && module_name ? ' from [' + module_name + ']' : '')); 3714 3715 var variable_name, value, eval_code = [], 3716 /** 3717 * 要 extend 到 name_space 下的 variables。 3718 * variable_hash[variable name] = variable full name, 包括所在 module name. 3719 */ 3720 variable_hash = name_space.require_variable; 3721 3722 no_strict = no_strict && !extend_to ? [] : false; 3723 3724 // 設定 required variables 3725 for (variable_name in variable_hash) 3726 if ((value = _.get_variable(variable_hash[variable_name])) !== undefined) { 3727 //_.debug('指定 [' + variable_name + ']: ' + value)); 3728 if (extend_to) 3729 extend_to[variable_name] = value; 3730 else { 3731 no_strict && no_strict.push(variable_name); 3732 3733 eval_code.push('try{' + variable_name + '=' + 3734 // 預防有保留字,所以用 bracket notation。例如 Chrome 中會出現 'Unexpected token native'。 3735 // Dot Notation and Square Bracket Notation in JavaScript http://www.dev-archive.net/articles/js-dot-notation/ 3736 variable_hash[variable_name].replace(/\.([a-z\d_]+)/gi, '["$1"]') + ';}catch(e){}'); 3737 } 3738 3739 } else { 3740 // 可能因為循環參照(circular dependencies),事實上 required 並未 loaded。 3741 if(!(module_name in module_require_chain) || _.is_debug(2)) 3742 _.err(_.Class + '.use_function: load [' + variable_hash[variable_name] + '] @ [' 3743 + _.to_module_name(module_name) + '] error: The module is not included or defined? You have to load they all later.'); 3744 3745 if (extend_to) { 3746 extend_to[variable_name] = function() { 3747 try { 3748 // 稍後求值,僅對 function 有效。 3749 return _.get_variable(variable_hash[variable_name]); 3750 } catch (e) { 3751 } 3752 }; 3753 } else { 3754 no_strict && no_strict.push(variable_name); 3755 3756 // 稍後求值,僅對 function 有效。 3757 eval_code.push(variable_name + '=function(){try{return ' + variable_name + '=' 3758 + variable_hash[variable_name].replace(/\.([a-z\d_]+)/gi, '["$1"]') 3759 + ';}catch(e){}};'); 3760 } 3761 3762 3763 // delete it if doesn't exists 3764 //delete variable_hash[variable_name]; 3765 } 3766 3767 // 應注意 module_name 為保留字之類的情況,會掛在這邊 return 後的 eval。 3768 return extend_to 3769 || (no_strict ? 'var ' + no_strict.join(',') + ';' : '') + eval_code.join(''); 3770 }; 3771 3772 3773 3774 //----------------------------------------------------------------------------------------------------------------------------------------------------------// 3775 3776 3777 /** 3778 * 為一些比較舊的版本或不同瀏覽器而做調適。 3779 * @since 2010/1/14 17:58:31 3780 * @inner 3781 * @private 3782 * @ignore 3783 */ 3784 function environment_adapter() { 3785 /* 3786 * workaround: 3787 * 理論上 '.'.split(/\./).length 應該是 2,但 IE 5–8 中卻為 0! 3788 * 用 .split('.') 倒是 OK. 3789 * TODO: 3790 * 應該增加可以管控與回復的手段,預防有時需要回到原有行為。 3791 * @since 2010/1/1 19:03:40 3792 */ 3793 if ('.'.split(/\./).length === 0) 3794 (function() { 3795 var _String_split = String.prototype.split, 3796 is_Regexp = _.object_tester('RegExp'); 3797 String.prototype.split = function(r) { 3798 return is_Regexp(r) ? 3799 _String_split.call(this.valueOf().replace( 3800 r.global ? r : 3801 // TODO: 少了 multiline 3802 new RegExp(r.source, r.ignoreCase ? 'ig' : 'g'), 3803 '\0'), '\0') : 3804 _String_split.call(this, r); 3805 }; 3806 })(); 3807 } 3808 3809 environment_adapter(); 3810 3811 } 3812 // 不用 apply(),因為比較舊的瀏覽器沒有 apply()。 3813 )(CeL); 3814 3815 3816 3817 3818 //===========================================================================================================================================================// 3819 3820 3821 3822 3823 //args=args.concat(['turnCode.js']); 3824 3825 // 不作 initialization 3826 //CeL.no_initialization = 0; 3827 3828 if (typeof CeL === 'function' && CeL.env.script_name === CeL.env.main_script_name 3829 && !CeL.no_initialization) 3830 try { 3831 (function() { 3832 // WScript.Echo(CeL.env.script_name); 3833 // CeL.debug(CeL.env.script_name); 3834 3835 3836 // 將 path 寫入 registry 3837 CeL.use('application.OS.Windows'); 3838 CeL.use('application.OS.Windows.registry'); 3839 // CeL.debug(CeL.reg); 3840 //WScript.Echo(CeL.reg); 3841 3842 var path_key_name = CeL.env.registry_path_key_name, 3843 // 此時 script 即為 main_script 3844 library_base_path = CeL.env.script_base_path, 3845 path_in_registry = CeL.reg.getValue(path_key_name) || '(null)'; 3846 //WScript.Echo('registry:\n' + path_in_registry + '\npath now:\n' + library_base_path); 3847 if (path_in_registry !== library_base_path) { 3848 WScript.Echo('Change the base path of [' + CeL.Class + '] from:\n' 3849 + path_in_registry + '\n to\n' + library_base_path 3850 + '\n\nkey name:\n' + path_key_name); 3851 CeL.reg.setValue.cid = 1; 3852 CeL.reg.setValue(path_key_name, library_base_path, 0, 0, 1); 3853 CeL.reg.setValue(CeL.env.registry_base + 'main_script', 3854 library_base_path + CeL.env.script_name, 0, 0, 1); 3855 CeL.reg.setValue.cid = 0; 3856 } 3857 3858 3859 // TODO 3860 // 拖曳檔案到本檔案上面時之處置。 3861 if ( 3862 // args instanceof Array 3863 typeof args === 'object') { 3864 // getEnvironment(); 3865 // alert('Get arguments ['+args.length+']\n'+args.join('\n')); 3866 if (args.length) { 3867 var i = 0, p, enc, f, backupDir = dBasePath('kanashimi\\www\\cgi-bin\\program\\log\\'); 3868 if (!fso.FolderExists(backupDir)) 3869 try { 3870 fso.CreateFolder(backupDir); 3871 } catch (e) { 3872 backupDir = dBasePath('kanashimi\\www\\cgi-bin\\game\\log\\'); 3873 } 3874 if (!fso.FolderExists(backupDir)) 3875 try { 3876 fso.CreateFolder(backupDir); 3877 } catch (e) { 3878 if (2 === alert('無法建立備份資料夾[' + backupDir 3879 + ']!\n接下來的操作將不會備份!', 0, 0, 1 + 48)) 3880 WScript.Quit(); 3881 backupDir = ''; 3882 } 3883 // addCode.report=true; // 是否加入報告 3884 for (; i < args.length; i++) 3885 if ((f = dealShortcut(args[i], 1)) 3886 .match(/\.(js|vbs|hta|s?html?|txt|wsf|pac)$/i) 3887 && isFile(f)) { 3888 p = alert( 3889 '是否以預設編碼[' 3890 + ((enc = autodetectEncode(f)) == simpleFileDformat ? '內定語系(' 3891 + simpleFileDformat + ')' 3892 : enc) + ']處理下面檔案?\n' + f, 3893 0, 0, 3 + 32); 3894 if (p === 2) 3895 break; 3896 else if (p === 6) { 3897 if (backupDir) 3898 fso.CopyFile(f, backupDir + getFN(f), true); 3899 addCode(f); 3900 } 3901 } 3902 } else if (1 === alert('We will generate a reduced [' 3903 + CeL.env.script_name + ']\n to [' + CeL.env.script_name 3904 + '.reduced.js].\nBut it takes several time.', 0, 0, 3905 1 + 32)) 3906 reduceScript(0, CeL.env.script_name + '.reduced.js'); 3907 }// else window.onload=init; 3908 3909 // CeL._iF=undefined; 3910 })(); 3911 } catch (e) { 3912 // TODO: handle exception 3913 } 3914 3915 3916 3917 /* 3918 3919 //test WinShell http://msdn.microsoft.com/en-us/library/bb787810(VS.85).aspx 3920 if (0) { 3921 alert(WinShell.Windows().Item(0).FullName); 3922 3923 var i, cmd, t = '', objFolder = WinShell.NameSpace(0xa), objFolderItem = objFolder 3924 .Items().Item(), colVerbs = objFolderItem.Verbs(); // 假如出意外,objFolder==null 3925 for (i = 0; i < colVerbs.Count; i++) { 3926 t += colVerbs.Item(i) + '\n'; 3927 if (('' + colVerbs.Item(i)).indexOf('&R') != -1) 3928 cmd = colVerbs.Item(i); 3929 } 3930 objFolderItem.InvokeVerb('' + cmd); 3931 alert('Commands:\n' + t); 3932 3933 // objShell.NameSpace(FolderFrom).CopyHere(FolderTo,0); // copy folder 3934 // objFolderItem=objShell.NameSpace(FolderFrom).ParseName("clock.avi");objFolderItem.Items().Item().InvokeVerb([動作]); 3935 // objShell.NameSpace(FolderFromPath).Items.Item(mName).InvokeVerb(); 3936 3937 // Sets or gets the date and time that a file was last modified. 3938 // http://msdn.microsoft.com/en-us/library/bb787825(VS.85).aspx 3939 // objFolderItem.ModifyDate = "01/01/1900 6:05:00 PM"; 3940 // objShell.NameSpace("C:\Temp").ParseName("Test.Txt").ModifyDate = 3941 // DateAdd("d", -1, Now()) CDate("19 October 2007") 3942 3943 // Touch displays or sets the created, access, and modified times of one or 3944 // more files. http://www.stevemiller.net/apps/ 3945 } 3946 3947 //測試可寫入的字元:0-128,最好用1-127,因為許多編輯器會將\0轉成' ',\128又不確定 3948 if (0) { 3949 var t = '', f = 'try.js', i = 0; 3950 for (; i < 128; i++) 3951 t += String.fromCharCode(i); 3952 if (simpleWrite(f, t)) 3953 alert('Write error!\n有此local無法相容的字元?'); 3954 else if (simpleRead(f) != t) 3955 alert('內容不同!'); 3956 else if (simpleWrite(f, dQuote(t) + ';')) 3957 alert('Write error 2!\n有此local無法相容的字元?'); 3958 else if (eval(simpleRead(f)) != t) 3959 alert('eval內容不同!'); 3960 else 3961 alert('OK!'); 3962 } 3963 3964 */ 3965 3966 3967 3968 3969 3970 //}catch(e){WScript.Echo('There are some error in function.js!\n'+e.message);throw e;} 3971 3972 3973 3974 //CeL.use('code.log'); 3975 //CeL.warn('test_print: ' + CeL.code.log.Class); 3976 3977 3978 //]]> 3979 3980