OSDN Git Service

Version 0.6.107, cleanup X.NodeCSS, fix X.Node.Event for touch, add unescape for...
[pettanr/clientJs.git] / 0.6.x / js / 01_core / 11_XClass.js
1 /**\r
2  * Class を定義し システムの管理下に置く.\r
3  * 全てのクラスと pool が有効の場合インスタンスへの参照が保持される.\r
4  *  1. X.Class.create( opt_settings, opt_name, opt_privateClass, opt_props ) でクラスを登録.\r
5  *  2. コンストラクタ となるメソッドは、opt_props 内の Constructor : function( arg ){ ... }, に書く.\r
6  *  3. 通常通り new で インスタンス生成\r
7  *  4. kill() でオブジェクトをクリーンして削除、pool が有効の場合は pool される.\r
8  *  5. pool が有効の場合、new で pool されたインスタンスが返される.\r
9  *  6. \r
10  * \r
11  */\r
12 \r
13 // ------------------------------------------------------------------------- //\r
14 // ------------ local variables -------------------------------------------- //\r
15 // ------------------------------------------------------------------------- //\r
16 var X_Class_CLASS_LIST         = [],\r
17         X_Class_DEF_LIST           = [],\r
18         X_Class_PRIVATE_CLASS_LIST = [],\r
19         X_Class_PRIVATE_DEF_LIST   = [],\r
20         X_Class_CALLING_SUPER      = [],\r
21         X_Class_CALL_SUPER_STACK   = [],\r
22         X_Class_killPrivateFlag    = false,\r
23         X_Class_traits             = null,\r
24         X_Class_useObjectCreate    = false, // !!Object.create, http://jsperf.com/prototype-vs-object-create-perf\r
25         X_Class_use_proto_         = !!X.emptyFunction.prototype.__proto__,\r
26 \r
27 /** \r
28  * X.Class.create で定義されたクラスのインスタンスが共通で備えるメソッド を格納\r
29  *\r
30  * @class\r
31  */ \r
32 X_Class_CommonProps =\r
33 \r
34 {\r
35         /*\r
36          * インスタンスの破棄。\r
37          */\r
38         kill : function(){\r
39                 var instance = this,\r
40                         klass    = X_Class_getClass( instance ),\r
41                         def      = X_Class_getClassDef( klass ),\r
42                         data, p, i;\r
43                 if( def.isPrivate && !X_Class_killPrivateFlag ){\r
44                         X.Logger.critical( 'PrivateInstance.kill() work in PrivateUser.kill().' );\r
45                         return;\r
46                 };\r
47                 X_Class_killPrivateFlag = false; // onKill 内で PrivateInstance.kill() を防ぐため\r
48                 \r
49                 // onKill() === false の場合、kill のキャンセル\r
50                 // private      は false での キャンセル は無視される\r
51                 \r
52                 if( this.instanceOf( X.EventDispatcher ) ){\r
53                         //console.log( 'this.instanceOf( X.EventDispatcher )! ' + this._dispatching );\r
54                         if( !def.isPrivate ){\r
55                                 if( this._dispatching ){\r
56                                         this.dispatch( X.Event.BEFORE_KILL_INSTANCE );\r
57                                         this._killReserved = true;\r
58                                         this.dispatch( X.Event.KILL_INSTANCE_CANCELED );\r
59                                         return;\r
60                                 } else\r
61                                 if( this.dispatch( X.Event.BEFORE_KILL_INSTANCE ) & X.Callback.PREVENT_DEFAULT ){\r
62                                         this.dispatch( X.Event.KILL_INSTANCE_CANCELED );\r
63                                         return;\r
64                                 };\r
65                         } else {\r
66                                 this.dispatch( X.Event.BEFORE_KILL_INSTANCE );  \r
67                         };\r
68                         this.dispatch( X.Event.KILL_INSTANCE );\r
69                         this._listeners && X_EventDispatcher_systemUnlisten( this ); //.unlisten();\r
70                 } else\r
71                 if( X.Type.isFunction( instance.onKill ) && instance.onKill() === false && !def.isPrivate ){\r
72                         return;\r
73                 };\r
74                 \r
75                 for( p in instance ){\r
76                         if( instance.hasOwnProperty && !instance.hasOwnProperty( p ) ) continue;\r
77                         delete instance[ p ];\r
78                 };\r
79                 if( def.pool ){\r
80                         def.live && def.live.splice( def.live.indexOf( instance ), 1 );\r
81                         def.pool[ def.pool.length ] = instance;\r
82                 };\r
83                 if( def.privateClass ){\r
84                         i = def.userList.indexOf( instance );\r
85                         if( i !== -1 ){\r
86                                 data = X_Class_getPrivate( instance );\r
87                                 X_Class_killPrivateFlag = true;\r
88                                 if( data._dispatching && data.instanceOf( X.EventDispatcher ) ){\r
89                                         data._killReserved = true;\r
90                                 } else {\r
91                                         data.kill();\r
92                                 };\r
93                                 def.dataList.splice( i, 1 );\r
94                                 def.userList.splice( i, 1 );\r
95                         };\r
96                 };\r
97         },\r
98         \r
99         // TODO Super\r
100         // superCall\r
101         \r
102         instanceOf : function( klass ){\r
103                 var Super = this;\r
104                 if( this.constructor === klass ) return true;\r
105                 while( Super = X_Class_getClassDef( Super ).SuperClass ){\r
106                         if( Super === klass ) return true;\r
107                 };\r
108                 return false;\r
109         }\r
110 };\r
111 // ------------------------------------------------------------------------- //\r
112 // --- interface ----------------------------------------------------------- //\r
113 // ------------------------------------------------------------------------- //\r
114 \r
115 /** @namespace */ \r
116 X.Class = {\r
117     /**\r
118      * インスタンスは破棄時(this.kill())に回収され、次回の new MyClass() 時に再利用されます。\r
119      * @memberof X.Class */\r
120         POOL_OBJECT  :  1,\r
121         \r
122         /**\r
123          * 定義するクラスは抽象クラスになります。new AbstractClass() とするとエラーになります。\r
124          * @memberof X.Class */\r
125         ABSTRACT     :  2,\r
126         \r
127         \r
128         /** @memberof X.Class */\r
129         FINAL        :  4,\r
130         /** @memberof X.Class */\r
131         SUPER_ACCESS :  8,\r
132         /** @memberof X.Class */\r
133         PRIVATE_DATA : 16,\r
134         /** @memberof X.Class */\r
135         SINGLETON    : 32, // 未実装\r
136         \r
137         create : function( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
138                 var args        = X_Object_cloneArray( arguments ),\r
139                         displayName = args[ 0 ],\r
140                         classSetting,\r
141                         opt_pool, opt_abstract, opt_final, opt_private,\r
142                         privateDef,\r
143                         props,\r
144                         klass,\r
145                         classDef = {}, hash;\r
146                 if( X.Type.isString( displayName ) === true ){\r
147                         classDef.displayName = displayName;\r
148                         args.shift();\r
149                 };\r
150                 \r
151                 // クラス設定\r
152                 classDef.setting = classSetting = args[ 0 ];\r
153                 if( X.Type.isNumber( classSetting ) ){\r
154                         opt_pool     = !!( classSetting & X.Class.POOL_OBJECT  );\r
155                         opt_abstract = !!( classSetting & X.Class.ABSTRACT     );\r
156                         opt_final    = !!( classSetting & X.Class.FINAL        );\r
157                         opt_private  = !!( classSetting & X.Class.PRIVATE_DATA );\r
158                         if( opt_final && opt_abstract ){\r
159                                 X.Logger.critical( 'final & Abstract!' );\r
160                                 return;\r
161                         };      \r
162                         args.shift();\r
163                 } else {\r
164                         classDef.setting = 0;\r
165                 };\r
166                 \r
167                 // シャドウクラス\r
168                 if( X_Class_PRIVATE_CLASS_LIST.indexOf( args[ 0 ] ) !== -1 ){\r
169                         privateDef = X_Class_getClassDef( args[ 0 ] );\r
170                         if( privateDef.isPrivate !== true ){\r
171                                 X.Logger.critical( 'PrivateClass not found! please, X.Class.create( X.Class.PRIVATE, {...} ).' );\r
172                                 return;\r
173                         } else\r
174                         if( privateDef.Abstract === true ){\r
175                                 X.Logger.critical( 'PrivateClass is Abstract!' );\r
176                                 return;\r
177                         };\r
178                         classDef.privateClass = args.shift();\r
179                 };\r
180                 \r
181                 // インスタンスのメンバー\r
182                 props = args[ 0 ];\r
183                 if( !X.Type.isObject( props ) ){\r
184                         // サブクラスの場合、クラス定義の上書きがなくても作成可能\r
185                         // サブクラスでなくても、クラスメンバ用オブジェクトが無しでも作成可能\r
186                         //if( !X_Class_traits ){\r
187                         //      X.Logger.critical( 'No Class Def!' );\r
188                         //      return;\r
189                         //};\r
190                         props = {};\r
191                 } else\r
192                 if( props.Constructor && X.Type.isFunction( props.Constructor ) ){\r
193                         classDef.Constructor = props.Constructor;\r
194                 };\r
195 \r
196                 klass  = X_Callback_actualClosure( hash = { _ : X_Class_actualConstructor } ); // TODO hash = classDef\r
197                 hash.c = klass;\r
198                 klass.superClassOf = X_Class_superClassOf;\r
199                 klass.subClassOf   = X_Class_subClassOf;\r
200                 \r
201                 if( X_Class_useObjectCreate ){\r
202                         klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonProps, false );\r
203                         klass.prototype.constructor = klass;\r
204                 } else\r
205                 if( X_Class_use_proto_ ){\r
206                         X_Class_override( klass.prototype, props, true );\r
207                         if( X_Class_traits ){\r
208                                 klass.prototype.__proto__ = X_Class_traits;\r
209                         } else {\r
210                                 X_Class_override( klass.prototype, X_Class_CommonProps, false );\r
211                         };\r
212                 } else {\r
213                         klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonProps, false );\r
214                         klass.prototype.constructor = klass;\r
215                 };\r
216                 klass.name = displayName;\r
217                 \r
218                 if( opt_abstract ){\r
219                         classDef.Abstract = true;\r
220                 } else\r
221                 if( opt_pool ){\r
222                         classDef.pool = [];\r
223                         if( opt_private === false ) classDef.live = [];\r
224                 };                      \r
225                 if( opt_final ){\r
226                         classDef.Final = true;\r
227                 } else {\r
228                         klass.inherits = X_Class_inherits;\r
229                 };                      \r
230                 if( opt_private ){\r
231                         if( classDef.privateClass ){\r
232                                 X.Logger.critical( 'Private Data Class has no PrivateClass!' );\r
233                                 return;\r
234                         };\r
235                         classDef.isPrivate = true;\r
236                         X_Class_PRIVATE_CLASS_LIST.push( klass );\r
237                         X_Class_PRIVATE_DEF_LIST.push( classDef );\r
238                 } else {\r
239                         X_Class_CLASS_LIST.push( klass );\r
240                         X_Class_DEF_LIST.push( classDef );                              \r
241                 };\r
242                 return klass;\r
243         },\r
244         \r
245         _newPrivate  : X_Class_newPrivate,\r
246         \r
247         _getPrivate  : X_Class_getPrivate\r
248         \r
249 };\r
250 \r
251 // ------------------------------------------------------------------------- //\r
252 // --- implements ---------------------------------------------------------- //\r
253 // ------------------------------------------------------------------------- //\r
254 function X_Class_getClass( instance ){\r
255         var cList    = X_Class_CLASS_LIST,\r
256                 i        = cList.length,\r
257                 klass;\r
258         for( ; i; ){\r
259                 klass = cList[ --i ];\r
260                 if( instance.constructor === klass ) return klass;\r
261         };\r
262         cList = X_Class_PRIVATE_CLASS_LIST;\r
263         i     = cList.length;\r
264         for( ; i; ){\r
265                 klass = cList[ --i ];\r
266                 if( instance.constructor === klass ) return klass;\r
267         };\r
268         \r
269         if( cList.indexOf( instance ) !== -1 ) return instance;\r
270         if( X_Class_CLASS_LIST.indexOf( instance ) !== -1 ) return instance;\r
271 };\r
272 \r
273 function X_Class_getClassDef( KlassOrInstance ){\r
274         var i = X_Class_CLASS_LIST.indexOf( KlassOrInstance );\r
275         if( i === -1 ) i = X_Class_CLASS_LIST.indexOf( X_Class_getClass( KlassOrInstance ) );\r
276         if( i !== -1 ) return X_Class_DEF_LIST[ i ];\r
277         \r
278         i = X_Class_PRIVATE_CLASS_LIST.indexOf( KlassOrInstance );\r
279         if( i === -1 ) i = X_Class_PRIVATE_CLASS_LIST.indexOf( X_Class_getClass( KlassOrInstance ) );\r
280         if( i !== -1 ) return X_Class_PRIVATE_DEF_LIST[ i ];\r
281         \r
282         if( X_Class_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
283         if( X_Class_PRIVATE_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
284 };\r
285 \r
286 function X_Class_newPrivate( /* instance, args */ ){\r
287         var args         = X_Object_cloneArray( arguments ),\r
288                 user         = args.shift(),\r
289                 def          = X_Class_getClassDef( user ),\r
290                 privateClass = def.privateClass,\r
291                 privateDef   = X_Class_getClassDef( privateClass ),\r
292                 i            = -1;\r
293         if( def.userList ){\r
294                 i = def.userList.indexOf( user );\r
295         } else {\r
296                 def.userList = [];\r
297                 def.dataList = [];\r
298         };\r
299         if( i !== -1 ){\r
300                 X.Logger.critical( 'PrivateData already exist!' );\r
301                 return;\r
302         };\r
303         if( privateDef._tempUser ){\r
304                 X.Logger.critical( 'newPrivate を連続呼び出しされたところ破綻' );\r
305                 return;\r
306         };\r
307         privateDef._tempUser = user;\r
308         return X_Class_actualConstructor( privateClass( X_Closure_COMMAND_BACK ), args );// privateClass.__new( args );\r
309 };\r
310 \r
311 function X_Class_getPrivate( instance ){\r
312         var def = X_Class_getClassDef( instance ),\r
313                 i   = def.userList.indexOf( instance );\r
314         if( i !== -1 ) return def.dataList[ i ];\r
315 };\r
316 \r
317 /* over のプロパティを target にコピーする.ただし target の プロパティが優先, force で解除 */\r
318 function X_Class_override( target, src, force ){\r
319         var p;\r
320         for( p in src ){\r
321                 if( p === 'Super' || p === 'SuperConstructor' || p === '__proto__' || p === 'prototype' || p === 'constructor' ){\r
322                         X.Logger.critical( 'Super & SuperConstructor is reserved!' );\r
323                         return;\r
324                 };\r
325                 if( force || target[ p ] === void 0 ){\r
326                         target[ p ] = src[ p ];\r
327                 };\r
328         };\r
329         return target;\r
330 };\r
331 \r
332 function X_Class_superClassOf( klass ){\r
333         var myDef      = X_Class_getClassDef( this ),\r
334                 targetDef  = X_Class_getClassDef( klass ),\r
335                 SuperClass = klass;\r
336 \r
337         if( !myDef || !targetDef || this === klass ) return false;\r
338         \r
339         while( SuperClass = X_Class_getClassDef( SuperClass ).SuperClass ){\r
340                 if( SuperClass === this ) return true;\r
341         };\r
342         \r
343         return false;\r
344 };\r
345 \r
346 function X_Class_subClassOf( klass ){\r
347         return X_Class_superClassOf.call( klass, this );\r
348 };\r
349         \r
350 /* サブクラスを作るメソッド  \r
351  * var subClass = superClass.inherits( ... ) \r
352  * http://d.hatena.ne.jp/m-hiyama/20051018/1129605002\r
353  */\r
354 function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
355         var args        = X_Object_cloneArray( arguments ),\r
356                 params      = [],\r
357                 Super       = this,\r
358                 superDef    = X_Class_getClassDef( Super ),\r
359                 displayName = args[ 0 ],\r
360                 classSetting,\r
361                 opt_super,\r
362                 klass, def;\r
363         if( superDef.Final ) X.Logger.critical( 'X.Class inherits, Class is final!' );\r
364         \r
365         // サブクラス名\r
366         if( X.Type.isString( displayName ) ){\r
367                 args.shift();\r
368         } else {\r
369                 displayName = 'SubClass of ' + superDef.displayName;\r
370         };\r
371         params.push( displayName );\r
372         \r
373         // サブクラス設定\r
374         classSetting = args[ 0 ];\r
375         if( X.Type.isNumber( classSetting ) ){\r
376                 args.shift();\r
377         } else {\r
378                 // クラス設定がない場合、親からコピーして、Abstract flag は落とす??\r
379                 classSetting = superDef.setting;// &= ~X.Class.ABSTRACT;\r
380         };\r
381         if( superDef.isPrivate ) classSetting = classSetting | X.Class.PRIVATE_DATA;\r
382         opt_super = !!( classSetting & X.Class.SUPER_ACCESS );\r
383         params.push( classSetting );\r
384 \r
385         // サブクラスのシャドウ\r
386         if( args[ 0 ] && X_Class_getClass( args[ 0 ] ) ){\r
387                 params.push( args.shift() );\r
388         } else\r
389         if( superDef.privateClass ){\r
390                 params.push( superDef.privateClass );\r
391         };\r
392         params.push( args[ 0 ] ); /* props サブクラスでは未定義でも可 */\r
393         \r
394         // 継承クラスの作成\r
395         if( X_Class_useObjectCreate ){\r
396                 X_Class_traits = Object.create( Super.prototype );\r
397         } else\r
398         if( X_Class_use_proto_ ){\r
399                 X_Class_traits = Super.prototype;\r
400         } else {\r
401                 //Super.__new = null;\r
402                 X_Class_traits = new Super( X_Closure_COMMAND_DROP );\r
403                 //Super.__new = X_Class_actualConstructor;                      \r
404         };\r
405         klass  = X.Class.create.apply( X.Class, params );\r
406         X_Class_traits = null;\r
407         \r
408         def    = X_Class_getClassDef( klass );\r
409         // 継承用プロパティを控える\r
410         if( opt_super === true ){\r
411                 def.superAccess = true;\r
412                 def.SuperClass  = Super;\r
413                 def.SuperProto  = Super.prototype;\r
414                 def.SuperConstructor = superDef.Constructor || superDef.SuperConstructor;\r
415         } else {\r
416                 def.SuperClass = Super; // instanceOf() で親クラスを調べる!\r
417         };\r
418         \r
419         return klass;\r
420 };\r
421         \r
422 /*\r
423  * new の実体.コンストラクタの機能は instance.Constructor に書く.\r
424  * これにより pool された オブジェクト(破棄されたインスタンス) を再利用できる\r
425  */\r
426 function X_Class_actualConstructor( obj, args ){\r
427         var klass    = obj.c,//this,\r
428                 def      = X_Class_getClassDef( klass ),\r
429                 dataUser = def._tempUser,\r
430                 instance, obj,\r
431                 userDef;\r
432         if( def.Abstract ){\r
433                 X.Logger.critical( 'AbstractClass!' );\r
434                 return;\r
435         };\r
436         if( def.isPrivate && !dataUser ){\r
437                 X.Logger.critical( 'use myClass.newPrivate( instance, ...args )!' );\r
438                 return;\r
439         };\r
440         //klass.__new = null;\r
441         instance = def.pool && def.pool.length > 0 ?\r
442                                         def.pool.pop() :\r
443                                 X_Class_useObjectCreate ?\r
444                                         Object.create( klass.prototype ) :\r
445                                         new klass( X_Closure_COMMAND_DROP );\r
446         //klass.__new = X_Class_actualConstructor;\r
447         \r
448         if( def.isPrivate ){\r
449                 userDef = X_Class_getClassDef( dataUser );\r
450                 userDef.dataList.push( instance );\r
451                 userDef.userList.push( dataUser );\r
452                 instance.User = dataUser;\r
453                 def._tempUser = null;\r
454         } else {\r
455                 def.live && def.live.push( instance );\r
456         };\r
457         if( def.superAccess ){\r
458                 // TODO klass.prototype に移動\r
459                 instance.Super = def.SuperProto;\r
460                 instance.SuperConstructor = X_Class_superConstructor;\r
461         };\r
462         obj = def.Constructor ?\r
463                         def.Constructor.apply( instance, args ) :\r
464                 def.SuperConstructor &&\r
465                         def.SuperConstructor.apply( instance, args );\r
466         if( ( X.Type.isObject( obj ) && obj !== instance ) || X.Type.isFunction( obj ) ){ // Class\r
467                 instance.kill();\r
468                 return obj;\r
469         };\r
470         return instance;\r
471 };\r
472 /*  クラス定義を辿ってスーパークラスのコンストラクタを探す。\r
473  *  呼び出したコンストラクタは配列に控える。\r
474  *  さらに呼ばれた場合、配列を元にさらに奥のコンストラクタを取得\r
475  *  TODO 現在 new しているインスタンスを保持してチェックする\r
476  */\r
477 function X_Class_superConstructor(){\r
478         var sClass = this,\r
479                 i      = X_Class_CALLING_SUPER.indexOf( sClass ),\r
480                 n      = -1,\r
481                 l, sList, def, sConst, ret;\r
482 \r
483         if( i === -1 ){\r
484                 X_Class_CALLING_SUPER[ l = X_Class_CALLING_SUPER.length ] = sClass;\r
485                 X_Class_CALL_SUPER_STACK[ l ] = sList = [];\r
486         } else {\r
487                 sList = X_Class_CALL_SUPER_STACK[ i ];\r
488         };\r
489         \r
490         while( sClass ){\r
491                 def    = X_Class_getClassDef( sClass );\r
492                 sClass = def.SuperClass;\r
493                 sConst = def.SuperConstructor;\r
494                 if( sConst && sList[ ++n ] !== sConst ){\r
495                         sList[ n ] = sConst;\r
496                         ret = sConst.apply( this, arguments );\r
497                         --sList.length;\r
498                         if( !sList.length ){\r
499                                 X_Class_CALLING_SUPER.splice( i, 1 );\r
500                                 X_Class_CALL_SUPER_STACK.splice( i, 1 );\r
501                         };\r
502                         return ret;\r
503                 };\r
504         };\r
505 };\r
506 \r
507 console.log( 'X.Core.Class' );\r