OSDN Git Service

Version 0.6.57, fixed NS of X.UI & X.Class for __proto__.
[pettanr/clientJs.git] / 0.6.x / js / core / 04_XClass.js
1 /**\r
2  * Class を定義し システムの管理下に置く.\r
3  * 全てのクラスと pool が有効の場合インスタンスへの参照が保持される.\r
4  *  1. X.Class.create( def, opt_final, opt_pool, opt_abstract ) でクラスを登録.\r
5  *  2. コンストラクタ となるメソッドは、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 X.Class = ( function(){\r
13         var CLASS_LIST         = [],\r
14                 DEF_LIST           = [],\r
15                 PRIVATE_CLASS_LIST = [],\r
16                 PRIVATE_DEF_LIST   = [],\r
17                 CONSTRUCTOR        = 'Constructor',\r
18                 killPrivateFlag    = false,\r
19                 traits             = null,\r
20                 use__proto__       = !!X.emptyFunction.prototype.__proto__;\r
21         \r
22         /* サブクラスを作るメソッド  \r
23          * var subClass = superClass.inherits( ... ) \r
24          * http://d.hatena.ne.jp/m-hiyama/20051018/1129605002\r
25          */\r
26         function inherits( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
27                 var args        = X.copyArray( arguments ),\r
28                         params      = [],\r
29                         Super       = this,\r
30                         superDef    = X.Class._getClassDef( Super ),\r
31                         displayName = args[ 0 ],\r
32                         classSetting,\r
33                         opt_super,\r
34                         klass, def;\r
35                 if( superDef.Final ) X.Notification.critical( 'X.Class inherits, Class is final!' );\r
36                 \r
37                 // サブクラス名\r
38                 if( X.Type.isString( displayName ) ){\r
39                         args.shift();\r
40                 } else {\r
41                         displayName = 'SubClass of ' + superDef.displayName;\r
42                 };\r
43                 params.push( displayName );\r
44                 \r
45                 // サブクラス設定\r
46                 classSetting = args[ 0 ];\r
47                 if( X.Type.isNumber( classSetting ) ){\r
48                         args.shift();\r
49                 } else {\r
50                         classSetting = superDef.setting;\r
51                 };\r
52                 if( superDef.isPrivate ) classSetting = classSetting | X.Class.PRIVATE_DATA;\r
53                 opt_super = !!( classSetting & X.Class.SUPER_ACCESS );\r
54                 params.push( classSetting );\r
55 \r
56                 // サブクラスのシャドウ\r
57                 if( X.Class._getClass( args[ 0 ] ) ){\r
58                         params.push( args.shift() );\r
59                 } else\r
60                 if( superDef.privateClass ){\r
61                         params.push( superDef.privateClass );\r
62                 };\r
63                 params.push( args[ 0 ] ); /* props サブクラスでは未定義でも可 */\r
64                 \r
65                 // 継承クラスの作成\r
66                 if( use__proto__ ){\r
67                         traits = Super.prototype;\r
68                 } else {\r
69                         Super.__new = null;\r
70                         traits = new Super();\r
71                         Super.__new = C;                        \r
72                 };\r
73                 klass  = X.Class.create.apply( X.Class, params );\r
74                 traits = null;\r
75                 \r
76                 // 継承用プロパティを控える\r
77                 if( opt_super === true ){\r
78                         def = X.Class._getClassDef( klass );\r
79                         def.Super = Super;\r
80                         def.SuperProto = Super.prototype;\r
81                         def.SuperConstructor = superDef[ CONSTRUCTOR ] || superDef.SuperConstructor;\r
82                 };\r
83                 \r
84                 return klass;\r
85         };\r
86         \r
87         /* X.Class.create で作られたクラスのインスタンスが共通で備えるメソッド */\r
88         var CommonProps = {\r
89                 kill : function(){\r
90                         var instance = this,\r
91                                 klass    = X.Class._getClass( instance ),\r
92                                 def      = X.Class._getClassDef( klass ),\r
93                                 data, p, i;\r
94                         if( def.isPrivate === true && killPrivateFlag === false ){\r
95                                 X.Notification.critical( 'PrivateInstance.kill() work in PrivateUser.kill().' );\r
96                                 return;\r
97                         };\r
98                         killPrivateFlag = false; // onKill 内で PrivateInstance.kill() を防ぐため\r
99                         // onKill() === false の場合、kill のキャンセル\r
100                         // private      は false での キャンセル は無視される\r
101                         if( X.Type.isFunction( instance.onKill ) && instance.onKill() === false && !def.isPrivate ){\r
102                                 return;\r
103                         };\r
104                         for( p in instance ){\r
105                                 if( instance.hasOwnProperty && !instance.hasOwnProperty( p ) ) continue;\r
106                                 delete instance[ p ];\r
107                         };\r
108                         if( def.pool ){\r
109                                 def.live && def.live.splice( def.live.indexOf( instance ), 1 );\r
110                                 def.pool[ def.pool.length ] = instance;\r
111                         };\r
112                         if( def.privateClass ){\r
113                                 i = def.userList.indexOf( instance );\r
114                                 if( i !== -1 ){\r
115                                         data            = X.Class._getPrivate( instance );\r
116                                         killPrivateFlag = true;\r
117                                         data.kill();\r
118                                         def.dataList.splice( i, 1 );\r
119                                         def.userList.splice( i, 1 );\r
120                                 };\r
121                         };\r
122                 },\r
123                 instanceOf : function( klass ){\r
124                         var Super = this;\r
125                         if( this.constructor === klass ) return true;\r
126                         while( Super = X.Class._getClassDef( Super ).Super ){\r
127                                 if( Super === klass ) return true;\r
128                         };\r
129                         return false;\r
130                 }\r
131         };\r
132         \r
133         /*\r
134          * new の実体.コンストラクタの機能は instance.Constructor に書く.\r
135          * これにより pool された オブジェクト(破棄されたインスタンス) を再利用できる\r
136          */\r
137         /* Constructor Real for GeneralClass */\r
138         function C( args ){\r
139                 var klass    = this,\r
140                         def      = X.Class._getClassDef( klass ),\r
141                         dataUser = def._tempUser,\r
142                         instance,\r
143                         userDef;\r
144                 if( def.Abstract === true ){\r
145                         X.Notification.critical( 'AbstractClass!' );\r
146                         return;\r
147                 };\r
148                 if( def.isPrivate === true && dataUser === null ){\r
149                         X.Notification.critical( 'use myClass.newPrivate( instance, ...args )!' );\r
150                         return;\r
151                 };\r
152                 klass.__new = null;\r
153                 instance = def.pool && def.pool.length > 0 ? def.pool.pop() : new klass();\r
154                 klass.__new = C;\r
155                 if( def.isPrivate === true ){\r
156                         userDef = X.Class._getClassDef( dataUser );\r
157                         userDef.dataList.push( instance );\r
158                         userDef.userList.push( dataUser );\r
159                         instance.User = dataUser;\r
160                         def._tempUser = null;\r
161                 } else {\r
162                         def.live && def.live.push( instance );\r
163                 };\r
164                 if( def.Super ){\r
165                         // klass.prototype に移動\r
166                         instance.Super = def.SuperProto;\r
167                         instance.SuperConstructor = superConstructor;\r
168                 };\r
169                 def[ CONSTRUCTOR ] ?\r
170                         def[ CONSTRUCTOR ].apply( instance, args ) :\r
171                 def.SuperConstructor &&\r
172                         def.SuperConstructor.apply( instance, args );\r
173                 return instance;\r
174         };\r
175         \r
176         function superConstructor(){\r
177                 var s = X.Class._getClassDef( this ).SuperConstructor;\r
178                 s && s.apply( this, arguments );\r
179         };\r
180         \r
181         return {\r
182                 POOL_OBJECT  : 1,\r
183                 ABSTRACT     : 2,\r
184                 FINAL        : 4,\r
185                 SUPER_ACCESS : 8,\r
186                 PRIVATE_DATA : 16,\r
187                 create : function( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
188                         var args        = X.copyArray( arguments ),\r
189                                 displayName = args[ 0 ],\r
190                                 classSetting,\r
191                                 opt_pool, opt_abstract, opt_final, opt_private,\r
192                                 privateDef,\r
193                                 props,\r
194                                 klass,\r
195                                 classDef = {};\r
196                         if( X.Type.isString( displayName ) === true ){\r
197                                 classDef.displayName = displayName;\r
198                                 args.shift();\r
199                         };\r
200                         \r
201                         // クラス設定\r
202                         classDef.setting = classSetting = args[ 0 ];\r
203                         if( X.Type.isNumber( classSetting ) ){\r
204                                 opt_pool     = !!( classSetting & X.Class.POOL_OBJECT  );\r
205                                 opt_abstract = !!( classSetting & X.Class.ABSTRACT     );\r
206                                 opt_final    = !!( classSetting & X.Class.FINAL        );\r
207                                 opt_private  = !!( classSetting & X.Class.PRIVATE_DATA );\r
208                                 if( opt_final && opt_abstract ){\r
209                                         X.Notification.critical( 'final & Abstract!' );\r
210                                         return;\r
211                                 };      \r
212                                 args.shift();\r
213                         } else {\r
214                                 classDef.setting = 0;\r
215                         };\r
216                         \r
217                         // シャドウクラス\r
218                         if( PRIVATE_CLASS_LIST.indexOf( args[ 0 ] ) !== -1 ){\r
219                                 privateDef = X.Class._getClassDef( args[ 0 ] );\r
220                                 if( privateDef.isPrivate !== true ){\r
221                                         X.Notification.critical( 'PrivateClass not found! please, X.Class.create( X.Class.PRIVATE, {...} ).' );\r
222                                         return;\r
223                                 } else\r
224                                 if( privateDef.Abstract === true ){\r
225                                         X.Notification.critical( 'PrivateClass is Abstract!' );\r
226                                         return;\r
227                                 };\r
228                                 classDef.privateClass = args.shift();\r
229                         };\r
230                         \r
231                         // インスタンスのメンバー\r
232                         props = args[ 0 ];\r
233                         if( props === null || !X.Type.isObject( props ) ){\r
234                                 // サブクラスの場合、クラス定義の上書きがなくても作成可能\r
235                                 if( !traits ){\r
236                                         X.Notification.critical( 'No Class Def!' );\r
237                                         return;\r
238                                 };\r
239                                 props = {};\r
240                         } else\r
241                         if( props[ CONSTRUCTOR ] && X.Type.isFunction( props[ CONSTRUCTOR ] ) ){\r
242                                 classDef[ CONSTRUCTOR ] = props[ CONSTRUCTOR ];\r
243                         };\r
244 \r
245                         klass = new Function( 'var a=arguments,f=a.callee;if(f.__new)return f.__new(a)' );\r
246                         klass.__new = C;\r
247                         klass.superClassOf = X.Class._superClassOf;\r
248                         klass.subClassOf   = X.Class._subClassOf;\r
249                         \r
250                         if( use__proto__ ){\r
251                                 X.Class._override( klass.prototype, props, true );\r
252                                 if( traits ){\r
253                                         klass.prototype.__proto__ = traits;\r
254                                 } else {\r
255                                         X.Class._override( klass.prototype, CommonProps, false );\r
256                                 };\r
257                         //if( X.UA.Safari && X.UA.Safari < 3 ){ // TODO Gecko もこちらへ\r
258                         //      X.Class._override( X.Class._override( traits || klass.prototype, props, true ), CommonProps, false );\r
259                         //      if( traits ) klass.prototype.__proto__ = traits;\r
260                         } else {\r
261                                 klass.prototype = X.Class._override( X.Class._override( traits || klass.prototype, props, true ), CommonProps, false );\r
262                                 klass.prototype.constructor = klass;\r
263                         };\r
264                         klass.name = displayName;\r
265                         \r
266                         if( opt_abstract === true ){\r
267                                 classDef.Abstract = true;\r
268                         } else\r
269                         if( opt_pool === true ){\r
270                                 classDef.pool = [];\r
271                                 if( opt_private === false ) classDef.live = [];\r
272                         };                      \r
273                         if( opt_final === true ){\r
274                                 classDef.Final = true;\r
275                         } else {\r
276                                 klass.inherits = inherits;\r
277                         };                      \r
278                         if( opt_private === true ){\r
279                                 if( classDef.privateClass ){\r
280                                         X.Notification.critical( 'Private Data Class has no PrivateClass!' );\r
281                                         return;\r
282                                 };\r
283                                 classDef.isPrivate = true;\r
284                                 PRIVATE_CLASS_LIST.push( klass );\r
285                                 PRIVATE_DEF_LIST.push( classDef );\r
286                         } else {\r
287                                 CLASS_LIST.push( klass );\r
288                                 DEF_LIST.push( classDef );                              \r
289                         };\r
290                         return klass;\r
291                 },\r
292                 sys_shutdown : function(){\r
293                         \r
294                 },\r
295                 _getClass : function( instance ){\r
296                         var cList    = CLASS_LIST,\r
297                                 i        = cList.length,\r
298                                 klass;\r
299                         for( ; i; ){\r
300                                 klass = cList[ --i ];\r
301                                 if( instance.constructor === klass ) return klass;\r
302                         };\r
303                         cList = PRIVATE_CLASS_LIST;\r
304                         i     = cList.length;\r
305                         for( ; i; ){\r
306                                 klass = cList[ --i ];\r
307                                 if( instance.constructor === klass ) return klass;\r
308                         };\r
309                         \r
310                         if( cList.indexOf( instance ) !== -1 ) return instance;\r
311                         if( CLASS_LIST.indexOf( instance ) !== -1 ) return instance;\r
312                 },\r
313                 _getClassDef : function( KlassOrInstance ){\r
314                         var i = CLASS_LIST.indexOf( KlassOrInstance );\r
315                         if( i === -1 ) i = CLASS_LIST.indexOf( X.Class._getClass( KlassOrInstance ) );\r
316                         if( i !== -1 ) return DEF_LIST[ i ];\r
317                         \r
318                         i = PRIVATE_CLASS_LIST.indexOf( KlassOrInstance );\r
319                         if( i === -1 ) i = PRIVATE_CLASS_LIST.indexOf( X.Class._getClass( KlassOrInstance ) );\r
320                         if( i !== -1 ) return PRIVATE_DEF_LIST[ i ];\r
321                         \r
322                         if( DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
323                         if( PRIVATE_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
324                 },\r
325                 _newPrivate : function( /* instance, args */ ){\r
326                         var args         = X.copyArray( arguments ),\r
327                                 user         = args.shift(),\r
328                                 def          = X.Class._getClassDef( user ),\r
329                                 privateClass = def.privateClass,\r
330                                 privateDef   = X.Class._getClassDef( privateClass ),\r
331                                 i            = -1;\r
332                         if( def.userList ){\r
333                                 i = def.userList.indexOf( user );\r
334                         } else {\r
335                                 def.userList = [];\r
336                                 def.dataList = [];\r
337                         };\r
338                         if( i !== -1 ){\r
339                                 X.Notification.critical( 'PrivateData already exist!' );\r
340                                 return;\r
341                         };\r
342                         if( privateDef._tempUser ){\r
343                                 X.Notification.critical( 'newPrivate を連続呼び出しされたところ破綻' );\r
344                                 return;\r
345                         };\r
346                         privateDef._tempUser = user;\r
347                         return privateClass.__new( args );\r
348                 },\r
349                 _getPrivate : function( instance ){\r
350                         var def = X.Class._getClassDef( instance ),\r
351                                 i   = def.userList.indexOf( instance );\r
352                         if( i !== -1 ) return def.dataList[ i ];\r
353                 },\r
354                 /* over のプロパティを target にコピーする.ただし target の プロパティが優先, force で解除 */\r
355                 _override : function ( target, src, force ){\r
356                         var p;\r
357                         for( p in src ){\r
358                                 if( p === 'Super' || p === 'SuperConstructor' || p === '__proto__' || p === 'prototype' || p === 'constructor' ){\r
359                                         X.Notification.critical( 'Super & SuperConstructor is reserved!' );\r
360                                         return;\r
361                                 };\r
362                                 if( force || target[ p ] === void 0 ){\r
363                                         target[ p ] = src[ p ];\r
364                                 };\r
365                         };\r
366                         return target;\r
367                 },\r
368                 _superClassOf : function(){\r
369                         \r
370                 },\r
371                 _subClassOf : function(){\r
372                         \r
373                 }\r
374         };\r
375 })();\r
376 \r
377 console.log( 'X.Core.Class' );\r