      1 ﻿
      2 /*
      3
      4 ********	class template		********
      5
      6 用
      7 =function(){}()
      8 似乎亦可，見 SWFObject 2.2
      9 */
     10
     11 var ClassT={};	//	class template set	讓 addCode 也可以讀通
     12
     13
     14
     15 //	===================================================
     16 /*
     17 	** class description: class template (simple version)
     18
     19 _=this
     20
     21 TODO:
     22
     23
     24 HISTORY:
     25 2008/7/21 16:12:32	create
     26 */
     27 var
     28 classT=
     29
     30 (ClassT.classT=function(initF){
     31
     32 var
     33
     34 //	class private	-----------------------------------
     35
     36
     37 //	instance constructor	---------------------------
     38 instanceL=[],
     39 initI=function(a){
     40  var _t=this,_p=pv(_t);
     41  instanceL.push(_t);	//	for destructor
     42  //_p.vars=a
     43
     44  //	initial instance object
     45 },_=function(){initI.apply(this,arguments);initF&&initF.apply(this,arguments);},
     46
     47
     48 //	(instance private handle)	不要 instance private 的把這函數刪掉即可。
     49 _p='_'+(''+Math.random()).replace(/\./,''),
     50 //	get private variables (instance[,destroy]), init private variables (instance[,access function list[, instance destructor]])
     51 pv=function(i,d,k){var V,K=_p('k');return arguments.callee.caller===_p('i')?(V=_p(i[K]=_p()),V.O=i,V.L={}):(K in i)&&(V=_p(i[K]))&&i===V.O?d?(_p(i[K],1),delete i[K]):V.L:{};};
     52
     53 //	class destructor	---------------------------
     54 /*
     55 please call at last (e.g., window.unload)
     56
     57 usage:
     58 classT=classT.destroy();
     59 or if you has something more to do:
     60 classT.destroy()&&classT=null;
     61 */
     62
     63 _.destroy=function(){for(var i=0,l=instanceL.length;i<l;i++)instanceL[i].destroy();_p();};
     64
     65 //	(instance private handle, continue)
     66 eval('_p=(function(){var '+_p+'={a:pv,d:_.destroy,c:0,k:"+pv+'+Math.random()+'",i:initI};return function(i,d){var f=arguments.callee.caller;if(f==='+_p+'.a){if(!d)return i in '+_p+'?'+_p+'[i]:('+_p+'[i='+_p+'.c++]={},i);'+_p+'[i]={};}if(f==='+_p+'.d)'+_p+'={};}})();');
     67 _p.toString=function(){return'';};
     68
     69
     70 //	class public interface	---------------------------
     71
     72 //	func
     73 _.func=function(){
     74  var _t=this;
     75
     76 };
     77
     78 //	class constructor	---------------------------
     79
     80 // do something others
     81
     82
     83 _.prototype={
     84 //	應該盡量把東西放在 class，instance 少一點…？
     85 //	** important ** 這邊不能作 object 之 initialization，否則因為 object 只會 copy reference，因此 new 時東西會一樣。initialization 得在 _() 中作！
     86
     87 //	instance public interface	-------------------
     88
     89 setV:function(a){
     90  var _t=this,_p=pv(_t);
     91  //_p.vars=a
     92 },
     93
     94
     95 //	instance destructor	---------------------------
     96 /*
     97 usage:
     98 instance=instance.destroy();
     99 or if you has something more to do:
    100 instance.destroy()&&instance=null;
    101 */
    102 destroy:function(){pv(this,1);}
    103 };	//	_.prototype=
    104
    105 return _;
    106 })();	//	function(initF){
    107
    108 //	===================================================
    109
    110
    111
    112
    113
    114
    115 //	解析
    116
    117
    118
    119 //	===================================================
    120
    121 /*
    122 	** class description: class template
    123
    124 _=this
    125
    126 TODO:
    127 .constructor 設定
    128 inherits:
    129 	http://www.cnblogs.com/birdshome/archive/2005/01/28/95933.html
    130 	http://www.blogjava.net/zkjbeyond/archive/2006/05/08/45108.html
    131
    132
    133 HISTORY:
    134 2008/7/21 16:12:32	create
    135 7/24 15:14:16	enhanced by set .toString. But.. If we use delete _p.toString, than we still can..
    136 		eval('a = pv',some_instance);
    137 		eval('var s=_p.toString;delete _p.toString;sl("** test1 _p: "+_p);_p.toString=s;sl("** test2 _p: "+_p);',a);
    138 7/26 11:38:6	className
    139
    140 TOTRY:
    141 直接對 eval 下手，使 delete 掉 eval 則 lost data
    142 */
    143 var
    144 classT_debug=
    145
    146 //	若是不須讓 addCode 也可以讀通，不加 ClassT.~ 也沒關係。
    147 (ClassT.classT=function(initF){	//	initF: additional initialization function
    148
    149 var
    150
    151 //	class private	-----------------------------------
    152 className='',//classT
    153
    154 //	variables
    155 vars=7,
    156 //	function
    157 doLog=function(m){
    158  var _t=_;
    159  sl((className?className+': ':'>> ')+m);	//	this+': '
    160 },
    161
    162
    163
    164 //	instance constructor	---------------------------
    165 instanceL=[],	// 實例 list
    166 initI=function(a){
    167  var _t=this,//	這裡面有用的是 this，不是 arguments.callee。
    168 	_p=pv(_t);//pv(_t,[func1,func2,..],_.destroy);	//	init private variables
    169  instanceL.push(_t);	//	for destructor
    170
    171  //	initial instance object
    172  _t.property1=[];
    173
    174  _t.testV=a;
    175  doLog('class create: '+a);
    176
    177  //return this;
    178 },
    179
    180 //	盡量減少 instance 體積…有用嗎？
    181 _=function(){
    182 	initI.apply(this,arguments);
    183 	initF&&initF.apply(this,arguments);
    184 },
    185
    186
    187 //	(instance private handle)	不要 instance private 的把這函數刪掉即可。
    188 /*
    189 更完整的防治：比對 arguments.callee.caller 的程式碼，確定登錄過才給予存取。
    190 …在 eval() 的第二 argument 下無用武之地。
    191 */
    192
    193 _p='_'+(''+Math.random()).replace(/\./,''),
    194
    195 pv=function(i,d,k){	//	get private variables (instance[,destroy]), init private variables (instance[,access function list[, instance destructor]])
    196  var	V,K=_p('k');
    197 /*	V: get variables
    198
    199 V.L	variables {}
    200 V.O	instance
    201
    202 for full version:
    203 V.F	可存取函數的程式碼 list {}
    204 V.D	instance destructor
    205 */
    206
    207 //	simple version
    208  if(0)return arguments.callee.caller===_p('i')?
    209 	(V=_p(i[K]=_p()),V.O=i,V.L={})
    210 	:(K in i)&&(V=_p(i[K]))&&i===V.O?
    211 		d?(_p(i[K],1),delete i[K]):V.L
    212 		:{};	//	竄改就會出 trouble
    213
    214
    215 //	full version
    216  var c=arguments.callee.caller,j=0,l;
    217  doLog('pv: '+(c===_p('i')?'init':d?'destory':'get variables')+' by '+c);
    218  if(c===_p('i')){
    219   V=_p(i[K]=_p());
    220   V.O=i;
    221   if(k)V.D=k;	//	instance destructor
    222   //	登錄可存取函數的程式碼。更狠的：不用 {} 而用 d，確定是 *完全相同* 的 function。
    223   if(d instanceof Array)	//	[]: no access!!
    224    for(k=V.F={},l=d.length;j<l;j++)
    225     k[d[j]]=1;
    226   return V.L={};
    227  }
    228
    229  //	預防竄改，找尋本來應該的 index。
    230  if(!(K in i)||!(V=_p(i[K]))||i!==V.O)
    231   for(k=_p('c');j<k;j++)
    232    if(i===_p(j).O){
    233     doLog('pv: correct index: '+i[K]+' to '+j);
    234     i[K]=j;
    235     break;
    236    }
    237
    238  if((K in i)&&(V=_p(i[K]))&&i===V.O)
    239   if(d){
    240    //	call from instance destructor
    241    if(!V.D||c===V.D)_p(i[K],1),delete i[K];
    242    //else throw new Error(3,'Error calling to destroy.');
    243   }else if(!V.F||V.F[c]){
    244    doLog('pv: get index '+i[K]+'.');
    245    //if(!V.L)throw new Error(1,'Error to get variables! Maybe it was already destroyed?');//private variables
    246    return V.L;
    247   }
    248
    249  return {};	//	throw new Error(1,'Illegal access!');
    250 };	//	of pv=function(
    251
    252
    253 //	(for inherits)
    254 /*
    255 不要 inherit 的把這段刪掉即可。
    256 usage:
    257 //	模擬 inherits
    258 newClass=oldClass.clone();
    259 //	prevent re-use. 防止再造
    260 delete oldClass.clone;
    261 */
    262 (_.clone=arguments.callee).toString=function(){return '[class_template]';};
    263
    264
    265 //	class destructor	---------------------------
    266 /*
    267 please call at last (e.g., window.unload)
    268
    269 usage:
    270 classT=classT.destroy();
    271 or if you has something more to do:
    272 classT.destroy()&&classT=null;
    273 */
    274
    275 _.destroy=function(){
    276  doLog('destroy: Destroy class.');
    277  for(var i=0,l=instanceL.length;i<l;i++)
    278   instanceL[i].destroy();
    279  _p();
    280 };
    281
    282
    283 //	class public interface	---------------------------
    284
    285 //	variables
    286 _.variables={};
    287 //	func
    288 _.func=function(){
    289  var _t=this;
    290
    291 };
    292
    293
    294 //	(instance private handle, continue)
    295 //	.a: accessable caller function, .d: class destructor, c:count, .k: private variables keyword, .i: init function, m: accessable class members
    296 //	destructor: (index,1)	Warning: 某些環境中 Array 可能無法用 delete?
    297 eval('_p=(function(){var '+_p+'={a:pv,d:_.destroy,c:0,k:"+pv+'+Math.random()+'",i:initI,m:{_:{}}}; (function(m,i){for(i=0;i<m.length;i++)if(m[i])'+_p+'.m[m[i]]=1;})(['
    298 	//'func1,func2'	//	在這裡填上需要 call 隱藏數值的 class private function。若無，可考慮合併到 _.destroy 前。
    299 	+']); return function(i,d){var f=arguments.callee.caller;if(f==='+_p+'.a){if(!d)return i in '+_p+'?'+_p+'[i]:('+_p+'[i='+_p+'.c++]={},i);'+_p+'[i]={};}if('+_p+'.m[f])return '+_p+'.m._;if(f==='+_p+'.d)'+_p+'={};}})();');
    300 _p.toString=function(){return '';};
    301
    302
    303 //	class constructor	---------------------------
    304
    305 // do something others
    306
    307
    308 _.prototype={
    309 //	應該盡量把東西放在 class，instance 少一點…？
    310
    311 //	instance public interface	-------------------
    312
    313 //	** important ** 這邊不能作 object 之 initialization，否則因為 object 只會 copy reference，因此 new 時東西會一樣。initialization 得在 _() 中作！
    314 property1:[],
    315
    316 setV:function(m){
    317  var _t=this,_p=pv(_t);
    318  doLog('setV: class vars='+(vars=m)+', this.vars='+(_p.vars=m));
    319 },
    320
    321 getV:function(){
    322  var _t=this,_p=pv(_t);
    323  doLog('getV: class vars='+vars+', this.vars='+_p.vars);
    324 },
    325
    326
    327 //	instance destructor	---------------------------
    328
    329 /*
    330 usage:
    331 instance=instance.destroy();
    332 or if you has something more to do:
    333 instance.destroy()&&instance=null;
    334
    335 TODO: Need *auto* detect if the object is destroyed.
    336 */
    337 destroy:function(){
    338  //	If you need to do something (e.g, destroy sub-sub-objects) before destroy it, you need to call pv(this) first here.
    339  pv(this,1);
    340 }
    341
    342 };	//	_.prototype=
    343
    344 //	class name	---------------------------
    345 if(className){
    346  _.prototype.toString=_.toString=function(){return '[class '+className+']';};//classT
    347  //eval('var className=_',this);	//	行不通
    348 }
    349
    350 return _;
    351 })();	//	(function(){
    352
    353
    354 //	===================================================
    355
    356
    357 /*
    358 //	test suit
    359 sl('<hr/>');
    360 var c1=new classT(123),c2=new classT(456);
    361
    362 c1.setV('Hello');
    363 c2.setV('World');
    364 c1.getV();
    365 c2.getV();
    366
    367 sl(c1.testV+','+c2.testV);
    368
    369 c1.destroy();
    370 c2.destroy();
    371 classT.destroy();
    372 */
    373
    374
    375
    376
    377
    378 /*
    379 繼承
    380 http://www.cnblogs.com/birdshome/archive/2005/01/28/95933.html
    381
    382
    383 引入arguments.length：這代表傳入引數個數（長度），arguments.callee.length：這代表(function)自身定義的引數個數（長度）
    384 function fn(){
    385  var _f=arguments.callee;	//	f: function, flag	引入arguments.callee：這代表(function)自身
    386  //	以 _f.* 替代 fn.*
    387  alert('fn: _f.val='+_f.val);
    388 }
    389 fn.subfn=function(){
    390  var _f=arguments.callee;	//	function, flag
    391  //	當不用 new 時，以 _f.* 替代 fn.subfn.*，this.* 替代 fn.*。但在 (fn.subfn=function(){ .. }) 中間就不能用 this, _f
    392  alert('fn.subfn: this.val='+this.val);	//	*** !!WARNING!! 在 eval() 中 this 可能表示 window，這時就無法用 this 來得到 fn 了。
    393  alert('fn.subfn: _f.val='+_f.val);
    394 };
    395 fn.subfn.val='test value: fn.subfn.val';
    396 fn.val='test value: fn.val';
    397 fn.prototype={
    398 constructor:fn,	//	need to adjust
    399 subfn:function(){
    400  var _f=arguments.callee;	//	function, flag
    401  //	當不用 new 時，以 _f.* 替代 fn.subfn.*，this.* 替代 fn.*
    402  alert('fn.prototype.subfn: this.val='+this.val);
    403  alert('fn.prototype.subfn: _f.val='+_f.val);
    404  alert('fn.prototype.subfn: this.constructor.val='+this.constructor.val);
    405 },
    406 val:'test value: fn.prototype.val'
    407 };	//	fn.prototype={
    408 fn.prototype.subfn.val='test value: fn.prototype.subfn.val';
    409 var inst=new fn;
    410 //inst.constructor.subfn();
    411 inst.subfn();
    412
    413
    414 var obj={
    415  val:34,
    416  fn:function(){
    417   var _f=arguments.callee;	//	function, flag
    418   //	以 _f.* 替代 obj.subfn.*，this.* 替代 obj.*
    419   alert(this.val);
    420  }
    421 };
    422 ww.ee();
    423
    424
    425
    426 to hack @ Firefox 3.0:	https://bugzilla.mozilla.org/show_bug.cgi?id=442333
    427 假設 scope obj.fn 裡有一個 foo 變數，在 Firefox 上可以使用 var a; eval('a = foo', obj.fn) 把 foo 變數抓到 a 裡面，所以你如果有使用這種方法來放與安全性有關的東西，就得重新檢查一次程式碼：Module Pattern Provides No Privacy…at least not in JavaScript(TM)。在一陣討論後，這個功能打算在 Firefox 3.1 拿掉：Remove eval's optional second argument。
    428
    429 */
    430
    431
    432 /*
    433 實作class:
    434 	http://www.remus.dti.ne.jp/~a-satomi/bunsyorou/ArekorePopup.html
    435 	http://www.klstudio.com/post/32.html
    436 function classA(){
    437  //	define property
    438  //	array
    439  this.attrs=['title','href','cite','datetime'];
    440  //	object
    441  this.ns={
    442 	xhtml1:'http://www.w3.org/1999/xhtml',
    443 	xhtml2:'http://www.w3.org/2002/06/xhtml2',
    444  };
    445  return this;
    446 }
    447 classA.prototype={
    448  //	function
    449  launch:function(){},
    450  init:function(){},
    451  //	object
    452  scanNode:{
    453   recursive:function(node){}
    454  },
    455  //	http://dean.edwards.name/weblog/2005/10/add-event/
    456  addEvent:function(obj,type,listener){
    457   if (obj.addEventListener) // Std DOM Events
    458    obj.addEventListener(type, listener, false);
    459   else if (obj.attachEvent) // IE
    460    obj.attachEvent(
    461     'on' + type,
    462     function() { listener( {
    463      type		: window.event.type,
    464      target		: window.event.srcElement,
    465      currentTarget	: obj,
    466      clientX		: window.event.clientX,
    467      clientY		: window.event.clientY,
    468      pageY		: document.body.scrollTop + window.event.clientY,
    469      keyCode		: window.event?window.event.keyCode:e?e.which:0,
    470      shiftKey		: window.event.shiftKey,
    471      stopPropagation	: function() { window.event.cancelBubble=true; }
    472     } ) }
    473    );
    474  }
    475 };
    476 var A=new classA();
    477
    478
    479 */
    480
    481
    482