OSDN Git Service

Version 0.6.58, X.UI.HBox is working.
[pettanr/clientJs.git] / 0.5.x / javascripts / system.js
1 /*\r
2  * pettanR system.js\r
3  *   version 0.5.48\r
4  *\r
5  * gadgetOS\r
6  *   author:\r
7  *     itozyun\r
8  *   licence:\r
9  *     3-clause BSD\r
10  */\r
11 \r
12 ( function( window, document, undefined ){\r
13         \r
14         var body           = document.getElementsByTagName( 'body' )[ 0 ]; //( document.compatMode || '' ) !== 'CSS1Compat' ? document.body : document.documentElement;// \r
15         var SERVICE_LIST   = [];\r
16         var SUPER_USER_KEY = { getUID: function(){ return 0; }};\r
17         var API_USER_LIST  = [ SUPER_USER_KEY ];\r
18         var numApiUser     = 1;\r
19         \r
20         function EMPTY_FUNCTION(){};\r
21         \r
22         function isApiUser( _user ){\r
23                 return _user === SUPER_USER_KEY ||\r
24                         File.isDriver( _user ) === true ||\r
25                         Application.isApplicationInstance( _user ) === true;\r
26         };\r
27         \r
28         var Const = {\r
29                 FILE: {\r
30                         TYPE: {\r
31                                 UNKNOWN:        0,\r
32                                 FOLDER:         1,\r
33                                 IMAGE:          2,\r
34                                 TEXT:           3,\r
35                                 HTML:           4,\r
36                                 CSV:            5,\r
37                                 JSON:           6,\r
38                                 XML:            7\r
39                         },\r
40                         STATE: {\r
41                                 UNKNOWN:        0,\r
42                                 OK:                     1,\r
43                                 LOADING:        2,\r
44                                 ERROR:          3,\r
45                                 BROKEN:         4\r
46                         },\r
47                         UPDATE_POLICY: {\r
48                                 _____:          parseInt( '00000', 2 ),\r
49                                 ____C:          parseInt( '00001', 2 ), // hasCreateMenu\r
50                                 ___W_:          parseInt( '00010', 2 ), // isWritable\r
51                                 ___WC:          parseInt( '00011', 2 ), // isWritable\r
52                                 __R__:          parseInt( '00100', 2 ), // isRenamable\r
53                                 __R_C:          parseInt( '00101', 2 ), // hasCreateMenu\r
54                                 __RW_:          parseInt( '00110', 2 ), // isWritable\r
55                                 __RWC:          parseInt( '00111', 2 ), // isWritable\r
56                                 _S___:          parseInt( '01000', 2 ), // childrenIsSortable\r
57                                 _S__C:          parseInt( '01001', 2 ),\r
58                                 _S_W_:          parseInt( '01010', 2 ),\r
59                                 _S_WC:          parseInt( '01011', 2 ),\r
60                                 _SR__:          parseInt( '01100', 2 ),\r
61                                 _SR_C:          parseInt( '01101', 2 ),\r
62                                 _SRW_:          parseInt( '01110', 2 ),\r
63                                 _SRWC:          parseInt( '01111', 2 ),\r
64                                 D____:          parseInt( '10000', 2 ),\r
65                                 D___C:          parseInt( '10001', 2 ), // hasCreateMenu\r
66                                 D__W_:          parseInt( '10010', 2 ), // isWritable\r
67                                 D__WC:          parseInt( '10011', 2 ), // isWritable\r
68                                 D_R__:          parseInt( '10100', 2 ), // isRenamable\r
69                                 D_R_C:          parseInt( '10101', 2 ), // hasCreateMenu\r
70                                 D_RW_:          parseInt( '10110', 2 ), // isWritable\r
71                                 D_RWC:          parseInt( '10111', 2 ), // isWritable\r
72                                 DS___:          parseInt( '11000', 2 ), // childrenIsSortable\r
73                                 DS__C:          parseInt( '11001', 2 ),\r
74                                 DS_W_:          parseInt( '11010', 2 ),\r
75                                 DS_WC:          parseInt( '11011', 2 ),\r
76                                 DSR__:          parseInt( '11100', 2 ),\r
77                                 DSR_C:          parseInt( '11101', 2 ),\r
78                                 DSRW_:          parseInt( '11110', 2 ),\r
79                                 DSRWC:          parseInt( '11111', 2 ),\r
80                                 CREATE:         1,\r
81                                 WRAITE:         2,\r
82                                 RENAME:         4,\r
83                                 SORT:           8,\r
84                                 DELETE:         16\r
85                         },\r
86                         EVENT: {\r
87                                 UPDATE_ATTRIVUTE:       'onFileUpdate',\r
88                                 GET_SEQENTIAL_FILES:'gotSeqentilFiles'\r
89                         },\r
90                         DATA_PROPERTY_RESERVED: [\r
91                                 'children', 'driver', 'state', 'type'\r
92                         ]                       \r
93                 },\r
94                 TREE: {\r
95                         EVENT: {\r
96                                 UPDATE:                         'onTreeUpdate'\r
97                         }\r
98                 },\r
99                 KEY: {\r
100                         EVENT: {\r
101                                 KEY_DOWN:                       'keydown',\r
102                                 KEY_UP:                         'keyup',\r
103                                 KEY_CHANGE:                     'keychange',\r
104                                 CURSOL:                         'cursol'\r
105                         }\r
106                 },\r
107                 APP: {\r
108                         TYPE: {\r
109                                 GENERAL : 0,\r
110                                 OVERLAY : 1,\r
111                                 PAGE    : 2\r
112                         }\r
113                 }\r
114         };\r
115 \r
116 /**\r
117  * Class を定義し システムの管理下に置く.\r
118  * 全てのクラスと pool が有効の場合インスタンスへの参照が保持される.\r
119  *  1. Class.create( def, opt_final, opt_pool, opt_abstract ) でクラスを登録.\r
120  *  2. コンストラクタ となるメソッドは、Constructor : function( arg ){ ... }, に書く.\r
121  *  3. 通常通り new で インスタンス生成\r
122  *  4. kill() でオブジェクトをクリーンして削除、pool が有効の場合は pool される.\r
123  *  5. pool が有効の場合、new で pool されたインスタンスが返される.\r
124  *  6. \r
125  * \r
126  */\r
127 var Class = ( function(){\r
128         var CLASS_LIST         = [],\r
129                 DEF_LIST           = [],\r
130                 PRIVATE_CLASS_LIST = [],\r
131                 PRIVATE_DEF_LIST   = [],\r
132                 CONSTRUCTOR        = 'Constructor',\r
133                 GET_INDEX          = Util.getIndex,\r
134                 killPrivateFlag    = false,\r
135                 dataUser           = null,\r
136                 traits             = null,\r
137                 f                  = true,\r
138                 copyArray          = Util.copyArray;\r
139         \r
140         function getClass( instance ){\r
141                 var cList    = CLASS_LIST,\r
142                         i        = cList.length,\r
143                         klass;\r
144                 for( ; i; ){\r
145                         klass = cList[ --i ];\r
146                         if( instance instanceof klass ) return klass;\r
147                 };\r
148                 cList = PRIVATE_CLASS_LIST;\r
149                 i     = cList.length;\r
150                 for( ; i; ){\r
151                         klass = cList[ --i ];\r
152                         if( instance instanceof klass ) return klass;\r
153                 };\r
154                 \r
155                 if( GET_INDEX( cList, instance ) !== -1 ) return instance;\r
156                 if( GET_INDEX( CLASS_LIST, instance ) !== -1 ) return instance;\r
157         };\r
158         \r
159         function getClassDef( KlassOrInstance ){\r
160                 var getIndex = GET_INDEX,\r
161                         i        = getIndex( CLASS_LIST, KlassOrInstance );\r
162                 if( i === -1 ) i = getIndex( CLASS_LIST, getClass( KlassOrInstance ) );\r
163                 if( i !== -1 ) return DEF_LIST[ i ];\r
164                 \r
165                 i = getIndex( PRIVATE_CLASS_LIST, KlassOrInstance );\r
166                 if( i === -1 ) i = getIndex( PRIVATE_CLASS_LIST, getClass( KlassOrInstance ) );\r
167                 if( i !== -1 ) return PRIVATE_DEF_LIST[ i ];\r
168                 \r
169                 if( GET_INDEX( DEF_LIST, KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
170                 if( GET_INDEX( PRIVATE_DEF_LIST, KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
171         };\r
172         \r
173         /* over のプロパティを target にコピーする.ただし target の プロパティが優先, force で解除 */\r
174         function override( target, over, force ){\r
175                 for( var p in over ){\r
176                         if( force === true || typeof target[ p ] === 'undefined' ){\r
177                                 target[ p ] = over[ p ];\r
178                         };\r
179                 };\r
180                 return target;\r
181         };\r
182         \r
183         /* サブクラスを作るメソッド  \r
184          * var subClass = superClass.inherits( ... ) \r
185          * http://d.hatena.ne.jp/m-hiyama/20051018/1129605002\r
186          */\r
187         function inherits( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
188                 var args        = copyArray( arguments ),\r
189                         params      = [],\r
190                         Super       = this,\r
191                         superDef    = getClassDef( Super ),\r
192                         displayName = args[ 0 ],\r
193                         classSetting,\r
194                         opt_super,\r
195                         klass;\r
196                 if( superDef.Final === true ) throw new Error( 'Class is final!' );\r
197                 \r
198                 if( Type.isString( displayName ) === true ){\r
199                         args.shift();\r
200                 } else {\r
201                         displayName = 'SubClass of ' + superDef.displayName;\r
202                 };\r
203                 params.push( displayName );\r
204                 \r
205                 classSetting = args[ 0 ];\r
206                 if( Type.isNumber( classSetting ) === true ){\r
207                         if( superDef.isPrivate === true ) classSetting = classSetting | Class.PRIVATE_DATA;\r
208                         opt_super = !!( classSetting & Class.SUPER_ACCESS );\r
209                         params.push( classSetting );\r
210                         args.shift();\r
211                 };\r
212                 if( getClass( args[ 0 ] ) ){\r
213                         params.push( args.shift() );\r
214                 } else\r
215                 if( superDef.privateClass ){\r
216                         params.push( superDef.privateClass );\r
217                 };\r
218                 params.push( args[ 0 ] ); /* props */\r
219                 f      = false;\r
220                 traits = new Super();\r
221                 f      = true;\r
222                 klass  = Class.create.apply( Class, params );\r
223                 traits = null;\r
224                 if( opt_super === true ) getClassDef( klass ).Super = Super.prototype;\r
225                 return klass;\r
226         };\r
227         \r
228         /* Class.create で作られたクラスのインスタンスが共通で備えるメソッド */\r
229         var CommonProps = {\r
230                 kill : function(){\r
231                         var instance = this,\r
232                                 klass    = getClass( instance ),\r
233                                 def      = getClassDef( klass ),\r
234                                 data, p, i;\r
235                         if( def.isPrivate === true && killPrivateFlag === false ){\r
236                                 throw new Error( 'PrivateInstance.kill() work in PrivateUser.kill().' );\r
237                         };\r
238                         Type.isFunction( instance.onKill ) === true && instance.onKill();\r
239                         for( p in instance ){\r
240                                 if( instance.hasOwnProperty && !instance.hasOwnProperty( p ) ) continue;\r
241                                 delete instance[ p ];\r
242                         };\r
243                         if( def.pool ){\r
244                                 def.live && def.live.splice( GET_INDEX( def.live, instance ), 1 );\r
245                                 def.pool.push( instance );\r
246                         };\r
247                         if( def.privateClass ){\r
248                                 i = GET_INDEX( def.userList, instance );\r
249                                 if( i !== -1 ){\r
250                                         data            = klass.getPrivateData( instance );\r
251                                         killPrivateFlag = true;\r
252                                         data.kill();\r
253                                         killPrivateFlag = false;\r
254                                         def.dataList.splice( i, 1 );\r
255                                         def.userList.splice( i, 1 );\r
256                                 };\r
257                         };\r
258                         // myCallback の削除\r
259                         // myCallback を受け取った API への通知\r
260                 },\r
261                 getMyCallback : function( callback ){\r
262                         var def       = getClassDef( this ),\r
263                                 iList     = def.callbackInstanceList,\r
264                                 rList     = def.callbackRegisterList,\r
265                                 i, cList, myCallback;\r
266                         if( !iList ){\r
267                                 iList = def.callbackInstanceList = [];\r
268                                 rList = def.callbackRegisterList = [];\r
269                         };\r
270                         i = GET_INDEX( iList, this );\r
271                         if( i === -1 ){\r
272                                 cList = [];\r
273                                 iList.push( this );\r
274                                 rList.push( cList );\r
275                         } else {\r
276                                 cList = rList[ i ];\r
277                                 for( i = cList.length; i; ){\r
278                                         if( cList[ --i ].callback === callback ) return cList[ i ];\r
279                                 };\r
280                         };\r
281                         myCallback = new Callback( this, callback );\r
282                         cList.push( myCallback );\r
283                         return myCallback;\r
284                 },\r
285                 releaseMyCallback : function( callback ){\r
286                         var def   = getClassDef( this ),\r
287                                 iList = def.callbackInstanceList,\r
288                                 rList = def.callbackRegisterList,\r
289                                 i, _i, cList;\r
290                         if( !iList ) return;\r
291                         i = GET_INDEX( iList, this );\r
292                         if( i === -1 ) return;\r
293                         cList = rList[ i ];\r
294                         _i    = GET_INDEX( cList, callback );\r
295                         if( _i === -1 ) return;\r
296                         cList.splice( _i, 1 );\r
297                         callback.kill();\r
298                         if( cList.length !== 0 ) return;\r
299                         iList.splice( i, 1 );\r
300                         rList.splice( i, 1 );\r
301                         if( iList.length !== 0 ) return;\r
302                         delete def.callbackInstanceList;\r
303                         delete def.callbackRegisterList;\r
304                 },\r
305                 listenTo : function( eventDispatcher, eventType, callback ){\r
306                         //if( eventDispatcher instanceof EventDsipatcher ){\r
307                                 eventDispatcher.addEventListener( eventType, callback, this );\r
308                         //}\r
309                 },\r
310                 unlistenTo : function( eventDispatcher, eventType, callback ){\r
311                         \r
312                 }\r
313         };\r
314 \r
315         /* privateDataclass をもつクラスに追加されるメソッド */\r
316         function newPrivateData( /* instance, args */ ){\r
317                 var args         = copyArray( arguments ),\r
318                         user         = args.shift(),\r
319                         def          = getClassDef( user ),\r
320                         privateClass = def.privateClass,\r
321                         privateDef   = getClassDef( privateClass ),\r
322                         i            = -1,\r
323                         data;\r
324                 if( def.userList ){\r
325                         i = GET_INDEX( def.userList, user );\r
326                 } else {\r
327                         def.userList = [];\r
328                         def.dataList = [];\r
329                 };\r
330                 if( i !== -1 ){\r
331                         throw new Error( 'PrivateData already exist!' );\r
332                 };\r
333                 dataUser  = user;\r
334                 data      = new privateClass( args );\r
335                 data.User = user;\r
336                 dataUser  = null;       \r
337                 return data;\r
338         };\r
339         function getPrivateData( instance ){\r
340                 var def = getClassDef( instance ),\r
341                         i   = GET_INDEX( def.userList, instance );\r
342                 if( i !== -1 ) return def.dataList[ i ];\r
343         };\r
344         \r
345         /*\r
346          * new の実体.コンストラクタの機能は instance.Constructor に書く.\r
347          * これにより pool された オブジェクト(破棄されたインスタンス) を再利用できる\r
348          */\r
349         /* Constructor Real for GeneralClass */\r
350         function C( args ){\r
351                 var klass = this,\r
352                         def   = getClassDef( klass ),   \r
353                         instance,\r
354                         userDef;\r
355                 if( def.Abstract === true ){\r
356                         throw new Error( 'AbstractClass!' );\r
357                 };\r
358                 if( def.isPrivate === true && dataUser === null ){\r
359                         throw new Error( 'use myClass.newPrivateData( instance, ...args )!' );\r
360                 };\r
361                 f = false;\r
362                 instance = def.pool && def.pool.length > 0 ? def.pool.shift() : instance = new klass();\r
363                 f = true;\r
364                 if( def.Super && !instance.Super ) instance.Super = def.Super;\r
365                 if( def.isPrivate === true ){\r
366                         userDef = getClassDef( dataUser );\r
367                         userDef.dataList.push( instance );\r
368                         userDef.userList.push( dataUser );\r
369                 } else {\r
370                         def.live && def.live.push( instance );\r
371                         args = copyArray( arguments );\r
372                 };\r
373                 def[ CONSTRUCTOR ] && def[ CONSTRUCTOR ].apply( instance, args );\r
374                 return instance;\r
375         };\r
376         \r
377         return {\r
378                 POOL_OBJECT  : 1,\r
379                 ABSTRACT     : 2,\r
380                 FINAL        : 4,\r
381                 SUPER_ACCESS : 8,\r
382                 PRIVATE_DATA : 16,\r
383                 create : function( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
384                         var args        = copyArray( arguments ),\r
385                                 displayName = args[ 0 ],\r
386                                 classSetting,\r
387                                 opt_pool, opt_abstract, opt_final, opt_private,\r
388                                 privateDef,\r
389                                 props,\r
390                                 klass,\r
391                                 classDef = {};\r
392                         if( Type.isString( displayName ) === true ){\r
393                                 classDef.displayName = displayName;\r
394                                 args.shift();\r
395                         };\r
396                         classSetting = args[ 0 ];\r
397                         if( Type.isNumber( classSetting ) === true ){\r
398                                 opt_pool     = !!( classSetting & Class.POOL_OBJECT  );\r
399                                 opt_abstract = !!( classSetting & Class.ABSTRACT     );\r
400                                 opt_final    = !!( classSetting & Class.FINAL        );\r
401                                 opt_private  = !!( classSetting & Class.PRIVATE_DATA );\r
402                                 if( opt_final === true && opt_abstract === true ){\r
403                                         throw new Error( 'final & Abstract!' );\r
404                                 };                              \r
405                                 args.shift();\r
406                         };\r
407                         \r
408                         if( GET_INDEX( PRIVATE_CLASS_LIST, args[ 0 ] ) !== -1 ){\r
409                                 privateDef = getClassDef( args[ 0 ] );\r
410                                 if( privateDef.isPrivate !== true ){\r
411                                         throw new Error( 'PrivateClass not found! please, Class.create( Class.PRIVATE, {...} ).' );\r
412                                 } else\r
413                                 if( privateDef.Abstract === true ){\r
414                                         throw new Error( 'PrivateClass is Abstract!' );\r
415                                 };\r
416                                 classDef.privateClass = args.shift();\r
417                         };\r
418                         props = args[ 0 ];\r
419                         if( props === null || Type.isObject( props ) === false ){\r
420                                 throw new Error( 'No Class Def!' );\r
421                         };\r
422                         \r
423                         if( Type.isFunction( props[ CONSTRUCTOR ] ) === true ){\r
424                                 classDef[ CONSTRUCTOR ] = props[ CONSTRUCTOR ];\r
425                         };\r
426                         \r
427                         klass = function(){ var a = arguments; if( f ) return C.apply( a.callee, a )};\r
428                         klass.prototype = override( override( traits || {}, props, true ), CommonProps, false );\r
429                         \r
430                         if( opt_abstract === true ){\r
431                                 classDef.Abstract = true;\r
432                         } else\r
433                         if( opt_pool === true ){\r
434                                 classDef.pool = [];\r
435                                 if( opt_private === false )classDef.live = [];\r
436                         };                      \r
437                         if( opt_final === true ){\r
438                                 classDef.Final = true;\r
439                         } else {\r
440                                 klass.inherits = inherits;\r
441                         };                      \r
442                         if( opt_private === true ){\r
443                                 if( classDef.privateClass ){\r
444                                         throw new Error( 'Private Data Class has no PrivateClass!' );\r
445                                 };\r
446                                 classDef.isPrivate = true;\r
447                                 PRIVATE_CLASS_LIST.push( klass );\r
448                                 PRIVATE_DEF_LIST.push( classDef );\r
449                         } else {\r
450                                 if( classDef.privateClass ){\r
451                                         klass.newPrivateData = newPrivateData;\r
452                                         klass.getPrivateData = getPrivateData;  \r
453                                 };\r
454                                 CLASS_LIST.push( klass );\r
455                                 DEF_LIST.push( classDef );                              \r
456                         };\r
457                         return klass;\r
458                 },\r
459                 onShutdown : function(){\r
460                         \r
461                 },\r
462                 getClass : function( instance ){\r
463                         return getClass( instance );\r
464                 },\r
465                 getClassDef : function(){\r
466                         \r
467                 }\r
468         };\r
469 })();\r
470 \r
471 /**\r
472  * Callback 時に thisObject や args を指定したい場合に使用. \r
473  */\r
474 var Callback = Class.create(\r
475         Class.POOL_OBJECT | Class.FINAL, {\r
476         Constructor : function( thisObject, callback, opt_args ){\r
477                 if( Type.isFunction( callback ) === false ){\r
478                         throw new Error( 'Not function!' );\r
479                 };\r
480                 this.callback = callback;\r
481                 if( thisObject ) this.thisObject = thisObject;\r
482                 if( Type.isArray( opt_args ) === true ){\r
483                         this.args = opt_args;\r
484                 } else\r
485                 if( opt_args !== undefined ){\r
486                         this.arg = opt_args;\r
487                 };\r
488         },\r
489         fire : function( /* args */ ){\r
490                 var thisObject = this.thisObject || window,\r
491                         args       = Util.copyArray( arguments );\r
492                 if( 0 < args.length ){\r
493                         if( this.args !== undefined ){\r
494                                 args.push.apply( args, this.args );\r
495                         } else\r
496                         if( this.arg !== undefined ){\r
497                                 args.push( this.arg );\r
498                         };\r
499                         this.callback.apply( thisObject, args );\r
500                 } else {\r
501                         if( this.args !== undefined ){\r
502                                 this.callback.apply( thisObject, this.args );\r
503                         } else\r
504                         if( this.arg !== undefined ){\r
505                                 this.callback.call( thisObject, this.arg );\r
506                         } else {\r
507                                 this.callback.call( thisObject );\r
508                         };\r
509                 };\r
510         },\r
511         registerUser : function( user ){\r
512                 if( !this.userList ){\r
513                         this.userList = [ user ];\r
514                 } else {\r
515                         Util.getIndex( this.userList, user ) === -1 && this.userList.push( user );\r
516                 };\r
517         },\r
518         onKill : function(){\r
519                 var instance = this.thisObject;\r
520                 this.userList && Class.getClass( instance ) && instance.releaseMyCalllback( this );\r
521         }\r
522 });\r
523 \r
524 \r
525 /* --------------------------------------------------------------\r
526  * System Timer\r
527  * \r
528  */\r
529 \r
530 var SystemTimer = ( function(){\r
531         var setTimeout    = window.setTimeout;\r
532         var clearTimeout  = window.clearTimeout;\r
533         var INTERVAL_TIME = 16;\r
534         var TICKET_LIST   = [];\r
535         var timerId       = undefined;\r
536         var next          = 0;\r
537         \r
538         function loop(){\r
539                 var i    = 0,\r
540                         list = TICKET_LIST;\r
541             for( i = 0; i < list.length; ){\r
542                 if( list[ i ].fire( next ) !== false ) ++i;\r
543             };\r
544             timerId = undefined;\r
545             update();\r
546         };\r
547         function update(){\r
548                 var list = TICKET_LIST,\r
549                         l    = list.length,\r
550                         n    = 99999999,\r
551                         c;\r
552                 if( l === 0 ){\r
553                         timerId !== undefined && clearTimeout( timerId );\r
554                         timerId = undefined;\r
555                         return;\r
556                 };\r
557             for( ; l; ){\r
558                 c = list[ --l ].count;\r
559                 if( n > c ) n = c;\r
560             };\r
561             if( next > n || timerId === undefined ){\r
562                 timerId !== undefined && clearTimeout( timerId );\r
563                 timerId = setTimeout( loop, INTERVAL_TIME * n );\r
564                 next = n;\r
565             };\r
566         };\r
567         \r
568         var TimerTicket = Class.create(\r
569                 Class.POOL_OBJECT, {\r
570                         Constructor : function( apiuser, callback, time, once, opt_thisObject ){\r
571                                 this.apiuser  = apiuser;\r
572                                 this.callback = callback;\r
573                                 this.time     = time;\r
574                                 this.count    = time;\r
575                                 if( once ) this.once = once;\r
576                                 this.thisObj  = opt_thisObject || apiuser;\r
577                         },\r
578                         fire : function( c ){\r
579                                 this.count -= c;\r
580                                 if( 0 < this.count ) return;\r
581                                 this.callback.call( this.thisObj );\r
582                                 if( this.once === true ){\r
583                                         this.destroy();\r
584                                         TICKET_LIST.splice( Util.getIndex( TICKET_LIST, this ), 1 );\r
585                                         return false;\r
586                                 } else {\r
587                                         this.count = this.time;\r
588                                 };\r
589                         },\r
590                         destroy : function( apiuser, callback ){\r
591                                 if( apiuser  && apiuser  !== this.apiuser )  return false;\r
592                                 if( callback && callback !== this.callback ) return false;\r
593                                 \r
594                                 this.kill();\r
595                                 return true;\r
596                         }\r
597                 }\r
598         );\r
599         \r
600         return {\r
601                 add: function( _apiuser, _handler, _time, _once, opt_thisObject ){\r
602                         if( Type.isNumber( _time ) === false || _time < INTERVAL_TIME ) _time = INTERVAL_TIME;\r
603                         \r
604                     var _ticket = new TimerTicket( _apiuser, _handler, Math.ceil( _time / INTERVAL_TIME ), _once, opt_thisObject );\r
605                     TICKET_LIST.push( _ticket );\r
606                     \r
607                     update();\r
608                 },\r
609                 remove: function( _apiuser, _handler ){\r
610                         var _ticket,\r
611                                 i = 0;\r
612                         while( _ticket = TICKET_LIST[ i ] ){\r
613                                 if( _ticket.destroy( _apiuser, _handler ) === true ){\r
614                                         TICKET_LIST.splice( i, 1 );\r
615                                 } else {\r
616                                         ++i;\r
617                                 };\r
618                         };\r
619                     update();\r
620                 }\r
621         };\r
622 })();\r
623 \r
624 /* --------------------------------------------------------------\r
625  * Async Callback\r
626  * \r
627  */\r
628 var AsyncCall = ( function(){\r
629         var CALLBACK_LIST = [];\r
630         \r
631         var CallbackTicket = Class.create(\r
632                 Class.POOL_OBJECT, {\r
633                 Constructor : function( apiuser, callback, args, thisObject ){\r
634                         this.apiuser  = apiuser;\r
635                         this.callback = callback;\r
636                         this.args     = args;\r
637                         this.thisObj  = thisObject || apiuser;\r
638                 },\r
639                 fire : function(){\r
640                         var f = this.callback,\r
641                                 a = this.args,\r
642                                 t = this.thisObj;\r
643                         this.destroy();\r
644                         if( Type.isArray( a ) === true ){\r
645                                 f.apply( t, a );\r
646                         } else {\r
647                                 f.call( t, a );\r
648                         };\r
649                 },\r
650                 destroy : function( apiuser, callback ){\r
651                         if( apiuser  && apiuser  !== this.apiuser ) return false;\r
652                         if( callback && callback !== this.callback ) return false;\r
653                         \r
654                         this.kill();\r
655                         return true;\r
656                 }\r
657         });\r
658 \r
659         function dispatch(){\r
660                 var _ticket = CALLBACK_LIST.shift();\r
661                 if( _ticket ){\r
662                         _ticket.fire();\r
663                         CALLBACK_LIST.length !== 0 && SystemTimer.add( SUPER_USER_KEY, dispatch, 1, true );\r
664                 };\r
665         };\r
666 \r
667         return {\r
668                 add: function( _apiuser, _callback, _argments, _thisObject ){\r
669                         CALLBACK_LIST.length === 0 && SystemTimer.add( SUPER_USER_KEY, dispatch, 1, true );\r
670                         CALLBACK_LIST.push( new CallbackTicket( _apiuser, _callback, _argments, _thisObject ) );\r
671                 },\r
672                 remove: function( _apiuser, _callback ){\r
673                         var _ticket,\r
674                                 i = 0;\r
675                         while( _ticket = CALLBACK_LIST[ i ] ){\r
676                                 if( _ticket.destroy( _apiuser, _callback ) === true ){\r
677                                         CALLBACK_LIST.splice( i, 1 );\r
678                                 } else {\r
679                                         ++i;\r
680                                 };\r
681                         };\r
682                 }\r
683         };\r
684 })();\r
685 \r
686 /* -----------------------------------------------------------\r
687  * 画像一覧は\r
688  *      お気に入り画像一覧 > tag:ペン次郎 > ペン次郎:笑う\r
689  *  最近アップロードされた画像 > images\r
690  *  最近使われた画像 > images\r
691  *  キャラクター画像庫 > アニマル系 > tag:ペン次郎 > ペン次郎:笑う\r
692  *  風景画像庫 >\r
693  *  効果画像庫 >\r
694  *  アイテム画像庫 >\r
695  *  \r
696  * 画像一覧を読み込むタイミング\r
697  */\r
698 var File = ( function(){\r
699         var DRIVER_LIST             = [];\r
700         \r
701         var FILE_TYPE_IS_FOLDER     = Const.FILE.TYPE.FOLDER,\r
702                 numFileType             = Const.FILE.TYPE.XML,\r
703                 FILEDATA_RESITER        = [],                   // store all of fileData( json object )\r
704                 FILEDATA_ACCESS         = [],                   // file operations for Kernel only ! hide from Out of File\r
705                 FILE_OBJECT_POOL        = [],\r
706                 EVENT_LISTENER_REGISTER = [],\r
707                 TREE_ARRAY              = [],\r
708                 TREE_ACCESS_ARRAY       = [];\r
709         \r
710         var REQUEST_CONTROLER = ( function(){\r
711                 var REQUEST_TICKET_RESISTER = [],\r
712                         currentTicket           = null,\r
713                         currentData             = null,\r
714                         DATA_TYPE_ARRAY         = 'json,xml,html,text'.split( ',' ),\r
715                         DATA_IS_JSON            = 0,\r
716                         DATA_IS_XML             = 1,\r
717                         DATA_IS_HTML            = 2,\r
718                         DATA_IS_TEXT            = 3,\r
719                         numError                = 0;\r
720                 \r
721                 var RequestTicket = Class.create(\r
722                         Class.POOL_OBJECT, {\r
723                         Constructor : function( apiuser, type, data, url, onLoad, onError ){\r
724                                 this.apiuser = apiuser;\r
725                                 this.type    = type;\r
726                                 this.data    = data;\r
727                                 this.url     = url;\r
728                                 this.onLoad  = onLoad;\r
729                                 this.onError = onError;\r
730                                 this.state   = 0;\r
731                         },\r
732                         load : function( data ){\r
733                                 AsyncCall.add( this.apiuser, this.onLoad, [ this.data, data ] );\r
734                         },\r
735                         error : function(){\r
736                                 AsyncCall.add( this.apiuser, this.onError, this.data );\r
737                         }\r
738                 });\r
739                 \r
740                 function request(){\r
741                         if( currentTicket !== null || REQUEST_TICKET_RESISTER.length === 0 ) return;\r
742                         currentTicket = REQUEST_TICKET_RESISTER.shift();\r
743                         $.ajax({\r
744                                 url:            currentTicket.url,\r
745                                 dataType:       DATA_TYPE_ARRAY[ currentTicket.type ],\r
746                                 success:        onSuccess,\r
747                                 error:          onError\r
748                         });\r
749                 };\r
750                 function onSuccess( _data ){\r
751                         currentTicket.load( _data );\r
752                         currentTicket.kill();\r
753                         currentTicket = null;\r
754                         request();\r
755                 };\r
756                 function onError(){\r
757                         ++numError;\r
758                         currentTicket.error();\r
759                         currentTicket.kill(); // retry\r
760                         currentTicket = null;\r
761                         request();\r
762                 };\r
763 \r
764                 return {\r
765                         getNumTask: function(){\r
766                                 return REQUEST_TICKET_RESISTER.length;\r
767                         },\r
768                         getNumError: function(){\r
769                                 return numError;\r
770                         },\r
771                         getJson: function( _apiuser, _data, _url, _onLoad, _onError ){\r
772                                 REQUEST_TICKET_RESISTER.push( new RequestTicket( _apiuser, DATA_IS_JSON, _data, _url, _onLoad, _onError ));\r
773                                 currentTicket === null && request();\r
774                         }\r
775                 };\r
776         })();\r
777 \r
778         var FILE_CONTROLER = {\r
779                 createTree: function( _apiuser, _rootFileData ){\r
780                         var _tree = new TreeClass( _apiuser, _rootFileData );\r
781                         TREE_ARRAY.push( _tree );\r
782                         return _tree;\r
783                 },\r
784                 getFileUID: function( FILEDATAorFILE ){\r
785                         if( FILEDATAorFILE instanceof FileClass ){\r
786                                 return FILEDATAorFILE.getUID();\r
787                         };\r
788                         \r
789                         var uid = Util.getIndex( FILEDATA_RESITER, FILEDATAorFILE );\r
790                         if( uid === -1 ){\r
791                                 uid = FILEDATA_RESITER.length;\r
792                                 FILEDATA_RESITER.push( FILEDATAorFILE );\r
793                         };\r
794                         return uid;\r
795                 },\r
796                 getFileDataAccess: function( UIDorFILEorFILEDATA ){\r
797                         var _uid, _data = FILE_CONTROLER.getFileData( UIDorFILEorFILEDATA ), _access;\r
798 \r
799                         if( _data === null || typeof _data !== 'object' ) return null;\r
800                         for( var i=0, l = FILEDATA_ACCESS.length; i<l; ++i ){\r
801                                 _access = FILEDATA_ACCESS[ i ];\r
802                                 if( _access.DATA === _data ) return _access;\r
803                         };\r
804                         return null;\r
805                 },      \r
806                 getFileData: function( UIDorFILEorFILEDATA ){\r
807                         if( typeof UIDorFILEorFILEDATA === 'number' ){\r
808                                 return FILEDATA_RESITER[ UIDorFILEorFILEDATA ] || null;\r
809                         } else\r
810                         if( UIDorFILEorFILEDATA instanceof FileClass ){\r
811                                 return FILEDATA_RESITER[ UIDorFILEorFILEDATA.getUID() ] || null;\r
812                         } else\r
813                         if( Util.getIndex( FILEDATA_RESITER, UIDorFILEorFILEDATA ) !== -1 ){\r
814                                 return UIDorFILEorFILEDATA;\r
815                         };\r
816                         return null;\r
817                 },\r
818                 getChildren: function( UIDorFILEorFILEDATA ){\r
819                         var _data = FILE_CONTROLER.getFileData( UIDorFILEorFILEDATA );\r
820                         return _data !== null ? _data.children || null : null;\r
821                 },\r
822                 getDriver: function( _file ){\r
823                         var _data = FILE_CONTROLER.getFileData( _file );\r
824                         return _data !== null && _data.driver ? _data.driver : BASE_DRIVER;\r
825                 },\r
826                 getUpdateFlag: function( _file, _bit ){\r
827                         var _driver = FILE_CONTROLER.getDriver( _file ),\r
828                                 _policy;\r
829                         if( typeof _driver.getUpdatePolicy === 'function' ){\r
830                                 _policy = _driver.getUpdatePolicy( _file );\r
831                                 \r
832                         }\r
833                         if( typeof _policy !== 'number' ) {\r
834                                 _policy = BASE_DRIVER.getUpdatePolicy( _file )\r
835                         }\r
836                         return _policy % ( _bit * 2 ) >= _bit;\r
837                 },\r
838                 move: function( _prentUID, _targetfile, _newFolder, _newIndex, _opt_callback ){\r
839                         var _parentData = FILE_CONTROLER.getFileDataAccess( _prentUID ),\r
840                                 _parentType = _parentData.TYPE,\r
841                                 _targetData = FILE_CONTROLER.getFileDataAccess( _targetfile ),\r
842                                 _targetType = _targetData.TYPE;\r
843                 },\r
844                 replace: function( _uid, _file, _newIndex ){\r
845                         \r
846                 },\r
847                 addEventListener: function( FILEorNULL, _eventType, _callback, opt_thisObject ){\r
848                         var _uid = FILEorNULL instanceof FileClass ? FILEorNULL.getUID() : FILEorNULL;\r
849                         EVENT_LISTENER_REGISTER.push( new FileEventTicket( _uid, _eventType, _callback, opt_thisObject ));\r
850                 },\r
851                 removeEventListener: function( FILEorNULL, eventType, callback ){\r
852                         var uid  = FILEorNULL instanceof FileClass ? FILEorNULL.getUID() : FILEorNULL,\r
853                                 list = EVENT_LISTENER_REGISTER,\r
854                                 i    = 0,\r
855                                 ticket;\r
856                         for( ; i < list.length; ){\r
857                                 ticket = list[ i ];\r
858                                 if( ticket.fileUID === uid && ticket.eventType === eventType && ticket.callBack === callback ){\r
859                                         list.splice( i, 1 );\r
860                                         ticket.kill();\r
861                                 } else {\r
862                                         ++i;\r
863                                 };\r
864                         };\r
865                 },\r
866                 getTreeAccess: function(){\r
867                         \r
868                 },\r
869                 fileEventRellay: function( _uid, _event ){\r
870                         var _fileAccess = FILE_CONTROLER.getFileDataAccess( _uid );\r
871                         if( _fileAccess === null ) return;\r
872                         var _treeUID    =  _fileAccess.TREE.getUID(),\r
873                                 _treeAccess = TREE_ACCESS_ARRAY[ _treeUID ],\r
874                                 _data       = _fileAccess.DATA,\r
875                                 _tree;\r
876                         if( !_treeAccess ) return;\r
877                         _treeAccess.dispatchFileEvent( _event );\r
878                         for( var i=0, l = TREE_ARRAY.length; i<l; ++i ){\r
879                                 if( i !== _treeUID ){\r
880                                         _tree = TREE_ARRAY[ i ];\r
881                                         if( FILE_CONTROLER.getFileData( _tree.getCurrentFile() ) === _data ){\r
882                                                 _treeAccess = TREE_ACCESS_ARRAY[ _tree.getUID() ];\r
883                                                 _treeAccess && _treeAccess.dispatchFileEvent( _event );\r
884                                         };\r
885                                 };\r
886                         };\r
887                 }\r
888         };\r
889         \r
890         var TreeClass = function( apiuser, rootFileData ){\r
891                 var PARENT_FILE_RESITER = [],\r
892                         ACCESS = {\r
893                                 apiuser          : apiuser,\r
894                                 dispatchFileEvent: dispatchFileEvent\r
895                         },\r
896                         EVENT_LISTENER_ARRAY = [],\r
897                         instance             = this,\r
898                         rootFile             = new FileClass( instance, null, rootFileData ),\r
899                         currentFile          = rootFile;\r
900                 \r
901                 currentFile.getSeqentialFiles();\r
902                 TREE_ACCESS_ARRAY.push( ACCESS );\r
903                 \r
904                 function dispatchFileEvent( e ){\r
905                         var _eventType  = e.eventType,\r
906                                 _targetFile = e.targetFile,\r
907                                 _uid        = _targetFile.getUID(),\r
908                                 _ticket, _type, _callback;\r
909                         for( var i=0, l = EVENT_LISTENER_REGISTER.length; i<l; ++i ){\r
910                                 _ticket   = EVENT_LISTENER_REGISTER[ i ];\r
911                                 _type     = _ticket.eventType;\r
912                                 _callback = _ticket.callBack;\r
913                                 if( _eventType === _type && _uid === _ticket.fileUID ){\r
914                                         AsyncCall.add( apiuser, _callback, [ _eventType, _targetFile, e.key, e.value ], _ticket.thisObject || _targetFile );\r
915                                 } else\r
916                                 if( _type === Const.TREE.EVENT.UPDATE && _eventType === Const.FILE.EVENT.GET_SEQENTIAL_FILES ){\r
917                                         //_callback( _eventType, _targetFile );\r
918                                         AsyncCall.add( apiuser, _callback, [ _eventType, _targetFile ], _ticket.thisObject || instance );\r
919                                 };\r
920                         };\r
921                 };\r
922                 \r
923                 this.getUID = function(){\r
924                         return Util.getIndex( TREE_ACCESS_ARRAY, ACCESS );\r
925                 };\r
926                 this.getRootFile = function(){\r
927                         return rootFile;\r
928                 };\r
929                 this.getCurrentFile = function(){\r
930                         return currentFile;\r
931                 };\r
932                 this.hierarchy = function(){\r
933                         return PARENT_FILE_RESITER.length;\r
934                 };\r
935                 this.getParentFileAt = function( _index ){\r
936                         var l = PARENT_FILE_RESITER.length;\r
937                         if( typeof _index !== 'number' || _index < 0 || _index >= l ) return null;\r
938                         return PARENT_FILE_RESITER[ l -1 -_index ];\r
939                 };\r
940                 this.down = function( _index ){\r
941                         if( typeof _index !== 'number' || _index < 0 || _index >= currentFile.getChildFileLength()) return;\r
942                         PARENT_FILE_RESITER.unshift( currentFile );\r
943                         currentFile = currentFile.getChildFileAt( _index );\r
944                         currentFile.getSeqentialFiles();\r
945                         return currentFile;\r
946                 };\r
947                 this.up = function( _index ){\r
948                         var l = PARENT_FILE_RESITER.length;\r
949                         if( l === 0 ) return null;\r
950                         \r
951                         if( currentFile ){\r
952                                 var _currentFile = currentFile;\r
953                                 currentFile = null;\r
954                                 _currentFile.destroy();\r
955                         };\r
956                         if( typeof _index === 'number' ){\r
957                                 if( _index >= l ) return null;\r
958                                 currentFile = this.getParentFileAt( _index );\r
959                                 PARENT_FILE_RESITER.splice( 0, l -_index);\r
960                         } else {\r
961                                 currentFile = PARENT_FILE_RESITER.shift();\r
962                         };\r
963                         currentFile.getSeqentialFiles();\r
964                         return currentFile;     \r
965                 };\r
966                 this.addTreeEventListener = function( _eventType, _callback, opt_thisObject ){\r
967                         FILE_CONTROLER.addEventListener( null, _eventType, _callback, opt_thisObject );\r
968                 };\r
969                 this.removeTreeEventListener = function( _eventType, _callback ){\r
970                         FILE_CONTROLER.removeEventListener( null, _eventType, _callback );\r
971                 };\r
972                 this.destroy = function( _apiuser ){\r
973                         if( _apiuser && apiuser !== _apiuser ) return false;\r
974                         // removeEvent\r
975                         var _currentFile = currentFile;\r
976                         currentFile = rootFile = rootFileData = null;\r
977                         // currentFile, rootFile を null にしないと .File.destroy() ができない.\r
978                         _currentFile.destroy();\r
979                         while( PARENT_FILE_RESITER.length > 0 ){\r
980                                 _currentFile = PARENT_FILE_RESITER.shift();\r
981                                 _currentFile.destroy();\r
982                         };\r
983                         \r
984                         AsyncCall.remove( apiuser );\r
985                         instance = apiuser = null;\r
986                         return true;\r
987                 };\r
988         };\r
989         \r
990         var FileEventTicket = Class.create(\r
991                 Class.POOL_OBJECT, {\r
992                 Constructor : function( uid, eventType, callback, opt_thisObject ){\r
993                         this.fileUID    = uid;\r
994                         this.eventType  = eventType;\r
995                         this.callBack   = callback;\r
996                         this.thisObject = opt_thisObject;\r
997                 }       \r
998         });\r
999         \r
1000         var FileEventClass = function( eventType, file, key, value ){\r
1001                 this.eventType        = eventType;\r
1002                 this.targetFile       = file;\r
1003                 this.updatedAttribute = key;\r
1004                 this.updatedValue     = value;\r
1005         };\r
1006 \r
1007 /*\r
1008  * file の data は object で保持している。\r
1009  * File の外からファイルをみるときは、FileClassを通して操作する。\r
1010  * fileの変更、それに付随して追加されたイベントは、TreeClassで管理される。\r
1011  * treeがdestryされると、fileのイベントリスナーも全て削除される。\r
1012  * 他の tree も data の共通する currentFile に対してのみは、file の変更イベントを受け取って流す.\r
1013  * \r
1014  */\r
1015         \r
1016         var FileClass = function( tree, parentData, data ){\r
1017                 var uid = FILE_CONTROLER.getFileUID( data );\r
1018                 \r
1019                 FILEDATA_ACCESS.push( {\r
1020                         TREE:                           tree,\r
1021                         parentData:                     parentData,\r
1022                         DATA:                           data\r
1023                 } );\r
1024                 \r
1025                 tree = parentData = data = null;\r
1026 \r
1027                 this.getUID = function(){\r
1028                         return uid;\r
1029                 };\r
1030         };\r
1031         \r
1032         FileClass.prototype = {\r
1033                 isChildFile: function( _FILEorFILEDATA ){\r
1034                         return this.getChildFileIndex( _FILEorFILEDATA) !== -1;\r
1035                 },\r
1036                 getSeqentialFiles: function(){\r
1037                         var _driver = FILE_CONTROLER.getDriver( this );\r
1038                         if( _driver !== null && typeof _driver.getSeqentialFiles === 'function' ){\r
1039                                 _driver.getSeqentialFiles( this );\r
1040                         }\r
1041                 },\r
1042                 addEventListener: function( _eventType, _callback ){\r
1043                         FILE_CONTROLER.addEventListener( this, _eventType, _callback );\r
1044                 },\r
1045                 removeEventListener: function( _eventType, _callback ){\r
1046                         FILE_CONTROLER.removeEventListener( this, _eventType, _callback );\r
1047                 },\r
1048                 dispatchEvent: function( e ){\r
1049                         e instanceof FileEventClass && FILE_CONTROLER.fileEventRellay( this.getUID(), e );\r
1050                 },\r
1051                 getChildFileLength: function(){\r
1052                         var children = FILE_CONTROLER.getChildren( this );\r
1053                         return Type.isArray( children ) === true ? children.length : -1;\r
1054                 },\r
1055                 getChildFileIndex: function( _FILEorFILEDATA ){\r
1056                         var children = FILE_CONTROLER.getChildren( this );\r
1057                         if( Type.isArray( children ) === false ) return -1;\r
1058                         var l = children.length,\r
1059                                 _fileData = FILE_CONTROLER.getFileData( _FILEorFILEDATA );\r
1060                         if( _fileData === null ) return -1;\r
1061                         for( var i=0; i<l; ++i ){\r
1062                                 if( children[ i ] === _fileData ) return i;\r
1063                         }\r
1064                         return -1;\r
1065                 },\r
1066                 getChildFileAt: function( _index ){\r
1067                         var _access = FILE_CONTROLER.getFileDataAccess( this ),\r
1068                                 _children = FILE_CONTROLER.getChildren( this );\r
1069                         if( typeof _index !== 'number' || _index < 0 || Type.isArray( _children ) === false || _index >= _children.length ) return null;\r
1070                         var _file = new FileClass( _access.TREE, _access.DATA, _children[ _index ]);\r
1071                         // _file.init();\r
1072                         return _file;\r
1073                 },\r
1074                 getName: function(){\r
1075                         var driver = FILE_CONTROLER.getDriver( this );\r
1076                         if( typeof driver.getName === 'function'){\r
1077                                 return driver.getName( this );\r
1078                         }\r
1079                         return BASE_DRIVER.getName( this );\r
1080                 },\r
1081                 getThumbnail: function(){\r
1082                         var driver = FILE_CONTROLER.getDriver( this );\r
1083                         if( typeof driver.getThumbnail === 'function'){\r
1084                                 return driver.getThumbnail( this );\r
1085                         }\r
1086                         return BASE_DRIVER.getThumbnail( this );\r
1087                 },\r
1088                 getType: function(){\r
1089                         var _data = FILE_CONTROLER.getFileData( this );\r
1090                         return typeof _data.type === 'number' ? _data.type : Const.FILE.TYPE.UNKNOWN;\r
1091                 },\r
1092                 getState: function(){\r
1093                         var _data = FILE_CONTROLER.getFileData( this );\r
1094                         return typeof _data.state === 'number' ? _data.state : Const.FILE.STATE.OK;\r
1095                 },\r
1096                 getSummary: function(){\r
1097                         var driver = FILE_CONTROLER.getDriver( this );\r
1098                         if( typeof driver.getSummary === 'function'){\r
1099                                 return driver.getSummary( this );\r
1100                         }\r
1101                         return BASE_DRIVER.getSummary( this );\r
1102                 },\r
1103                 isWritable: function(){\r
1104                         return FILE_CONTROLER.getUpdateFlag( this, Const.FILE.UPDATE_POLICY.WRITE );\r
1105                 },\r
1106                 isSortable: function(){\r
1107                         return FILE_CONTROLER.getUpdateFlag( this, Const.FILE.UPDATE_POLICY.SORT );\r
1108                 },              \r
1109                 isCreatable: function(){\r
1110                         return FILE_CONTROLER.getUpdateFlag( this, Const.FILE.UPDATE_POLICY.CREATE );\r
1111                 },\r
1112                 isRenamable: function(){\r
1113                         return FILE_CONTROLER.getUpdateFlag( this, Const.FILE.UPDATE_POLICY.RENAME );\r
1114                 },\r
1115                 isDeletable: function(){\r
1116                         return FILE_CONTROLER.getUpdateFlag( this, Const.FILE.UPDATE_POLICY.DELETE );\r
1117                 },\r
1118                 read: function(){\r
1119                         // simpleDeepCopy\r
1120                         var driver = FILE_CONTROLER.getDriver( this ),\r
1121                                 data;\r
1122                         if( Type.isFunction( driver.read ) === true ){\r
1123                                  data = driver.read( this );\r
1124                         };\r
1125                         return BASE_DRIVER.read( data || this );\r
1126                 },\r
1127                 write: function( _newData, _onUpdateFunction ){\r
1128                         var driver = FILE_CONTROLER.getDriver( this );\r
1129                         if( typeof driver.write === 'function' ){\r
1130                                 return driver.write( this, _newData, _onUpdateFunction );\r
1131                         };\r
1132                         return BASE_DRIVER.write( this, _newData, _onUpdateFunction );\r
1133                 },\r
1134                 viewerApplicationList: function(){\r
1135                         var driver = FILE_CONTROLER.getDriver( this );\r
1136                         if( typeof driver.viewerApplicationList === 'function' ){\r
1137                                 return driver.viewerApplicationList( this );\r
1138                         };\r
1139                         return BASE_DRIVER.viewerApplicationList( this );\r
1140                 },\r
1141                 editorApplicationList: function(){\r
1142                         var driver = FILE_CONTROLER.getDriver( this );\r
1143                         if( typeof driver.editorApplicationList === 'function' ){\r
1144                                 return driver.editorApplicationList( this );\r
1145                         };\r
1146                         return BASE_DRIVER.viwerApps( this );\r
1147                 },\r
1148                 create: function(){\r
1149                         \r
1150                 },\r
1151                 sort: function(){\r
1152                         \r
1153                 },\r
1154                 onCopy: function(){\r
1155                         \r
1156                 },\r
1157                 onDelete: function(){\r
1158                         \r
1159                 },\r
1160                 move: function( _newFolder, _newIndex, opt_callback ){\r
1161                         var _access = FILE_CONTROLER.getFileDataAccess( this );\r
1162                         _access.TREE.move( _access.parentData, this.getUID(), _newFolder, _newIndex, opt_callback );\r
1163                 },\r
1164                 replace: function( _newIndex, opt_callback ){\r
1165                         var _access = FILE_CONTROLER.getFileDataAccess( this );\r
1166                         _access.TREE.replace( _access.parentData, this.getUID(), _newIndex, opt_callback);\r
1167                 },\r
1168                 /**\r
1169                  * サーチ\r
1170                  * 探しているファイルの属性と値を指定.一致する child の index を配列で返す.\r
1171                  */\r
1172                 search: function( obj, rule ){\r
1173                         var _children = FILE_CONTROLER.getChildren( this ),\r
1174                                 _child,\r
1175                                 ret = [], k, c;\r
1176                         for( var i=0, l=_children.length; i<l; ++i ){\r
1177                                 _child = _children[ i ];\r
1178                                 c = true;\r
1179                                 for( k in obj ){\r
1180                                         if( obj[ k ] !== _child[ k ] ){\r
1181                                                 c = false;\r
1182                                                 break;\r
1183                                         }\r
1184                                 }\r
1185                                 c === true && ret.push( i );\r
1186                         }\r
1187                         return ret;\r
1188                 },\r
1189                 destroy: function(){\r
1190                         var _access = FILE_CONTROLER.getFileDataAccess( this );\r
1191                         var _tree = _access.TREE;\r
1192                         if( _tree.getCurrentFile() === this ) return;\r
1193                         if( _tree.getRootFile() === this ) return;\r
1194                         for( var i=0, l = _tree.hierarchy(); i<l; ++i ){\r
1195                                 if( _tree.getParentFileAt( i ) === this ){\r
1196                                         return;\r
1197                                 }\r
1198                         }\r
1199                         var _index = Util.getIndex( FILEDATA_ACCESS, _access );\r
1200                         if( _index === -1 ) return;\r
1201                         // event の 削除\r
1202                         FILEDATA_ACCESS.splice( _index, 1 );\r
1203                         delete _access.DATA;\r
1204                         delete _access.TREE;\r
1205                         delete _access.parentData;\r
1206                 }\r
1207         };\r
1208 \r
1209         /*\r
1210          * FileDriverBase\r
1211          */\r
1212         var FileDriverBase = function( driverClass ){\r
1213                 this.getUID = function(){\r
1214                         return Util.getIndex( API_USER_LIST, driverClass );\r
1215                 };\r
1216                 this.getSeqentialFiles = function( _file ){\r
1217                 };\r
1218                 this.getName = function( _file ){\r
1219                         var _data = FILE_CONTROLER.getFileData( _file );\r
1220                         return _data.name || 'No Name';\r
1221                 };\r
1222                 this.getThumbnail = function( _file ){\r
1223                         var _data = FILE_CONTROLER.getFileData( _file ),\r
1224                                 _type = _data.type,\r
1225                                 _className = '';\r
1226                         if( _type === Const.FILE.TYPE.FOLDER ){\r
1227                                 _className = 'folder';\r
1228                         } else\r
1229                         if( _type === Const.FILE.TYPE.IMAGE ){\r
1230                                 \r
1231                         } else\r
1232                         if( _type === Const.FILE.TYPE.TEXT ){\r
1233                                 \r
1234                         } else\r
1235                         if( _type === Const.FILE.TYPE.HTML ){\r
1236                                 \r
1237                         } else\r
1238                         if( _type === Const.FILE.TYPE.CSV ){\r
1239                                 \r
1240                         } else\r
1241                         if( _type === Const.FILE.TYPE.JSON ){\r
1242                                 \r
1243                         } else\r
1244                         if( _type === Const.FILE.TYPE.XML ){\r
1245                                 \r
1246                         };\r
1247                         return {\r
1248                                 image:          null,\r
1249                                 className:      ' file-type-' + _className\r
1250                         };\r
1251                 };\r
1252                 this.getSummary = function( _file ){\r
1253                         var _data = FILE_CONTROLER.getFileData( _file ),\r
1254                                 _type = _data.type;\r
1255                         if( _type === Const.FILE.TYPE.FOLDER ){\r
1256                                 return 'folder';\r
1257                         } else\r
1258                         if( _type === Const.FILE.TYPE.IMAGE ){\r
1259                                 return 'image file';\r
1260                         } else\r
1261                         if( _type === Const.FILE.TYPE.TEXT ){\r
1262                                 return 'text file';\r
1263                         } else\r
1264                         if( _type === Const.FILE.TYPE.HTML ){\r
1265                                 return 'html document file';\r
1266                         } else\r
1267                         if( _type === Const.FILE.TYPE.CSV ){\r
1268                                 return 'csv daat file';\r
1269                         } else\r
1270                         if( _type === Const.FILE.TYPE.JSON ){\r
1271                                 return 'json data file';\r
1272                         } else\r
1273                         if( _type === Const.FILE.TYPE.XML ){\r
1274                                 return 'xml data file';\r
1275                         }\r
1276                         return '';\r
1277                 };\r
1278                 this.getUpdatePolicy = function( _file ){\r
1279                         // debug用 全てのメニューを許可\r
1280                         return Const.FILE.UPDATE_POLICY.DSRWC;\r
1281                 };\r
1282                 this.read = function( FILEorDATA ){\r
1283                         var data,\r
1284                                 protects = Const.FILE.DATA_PROPERTY_RESERVED,\r
1285                                 objSrc   = [],\r
1286                                 objCopy  = [],\r
1287                                 getIndex = Util.getIndex;                       \r
1288                         if( FILEorDATA instanceof FileClass ){\r
1289                                 data = FILE_CONTROLER.getFileData( FILEorDATA )\r
1290                         } else {\r
1291                                 data = FILEorDATA;\r
1292                         };\r
1293                         \r
1294                         function clone( src ) {\r
1295                                 var ret, i, key;\r
1296                                 if( Type.isArray( src ) === true ){\r
1297                                         i = getIndex( objSrc, src );\r
1298                                         if( i !== -1 ) return objCopy[ i ];\r
1299                                         ret = [];\r
1300                                         objSrc[ objSrc.length ]   = src;\r
1301                                         objCopy[ objCopy.length ] = ret;\r
1302                                 } else\r
1303                                 if( Type.isObject( src ) === true ){\r
1304                                         i = getIndex( objSrc, src );\r
1305                                         if( i !== -1 ) return objCopy[ i ];\r
1306                                         ret = {};\r
1307                                         objSrc[ objSrc.length ]   = src;\r
1308                                         objCopy[ objCopy.length ] = ret;\r
1309                                 } else\r
1310                                 if( Type.isNumber( src ) === true || Type.isString( src ) === true || Type.isBoolean( src ) === true ){\r
1311                                         return src;\r
1312                                 } else {\r
1313                                         return src;\r
1314                                 };\r
1315                                 for( key in src ){\r
1316                                         if( getIndex( protects, key ) === -1 ){\r
1317                                                 ret[ key ] = clone( src[ key ]);\r
1318                                         };\r
1319                                 };\r
1320                                 return ret;\r
1321                         };                              \r
1322                         return clone( data );\r
1323                 };\r
1324                 this.write = function( _file, _newData, _onUpdateFunction ){\r
1325                         var _data = FILE_CONTROLER.getFileData( _file ),\r
1326                                 _type = _data.type;\r
1327                         return false;\r
1328                 };\r
1329                 this.viewerApplicationList = function(){\r
1330                         return [];\r
1331                 };\r
1332                 this.editorApplicationList = function(){\r
1333                         return [];\r
1334                 };\r
1335                 this.onCreate = function(){\r
1336                         \r
1337                 };\r
1338                 this.onSort = function(){\r
1339                         \r
1340                 };\r
1341                 this.onCopy = function(){\r
1342                         \r
1343                 };\r
1344                 this.onDelete = function(){\r
1345                         \r
1346                 };\r
1347         };\r
1348         \r
1349         var BASE_DRIVER   = new FileDriverBase();\r
1350         \r
1351         var ROOT_FILEDATA = {\r
1352                         name:           'system root',\r
1353                         type:           FILE_TYPE_IS_FOLDER,\r
1354                         children:       []\r
1355                 },\r
1356                 SYSTEM_TREE = FILE_CONTROLER.createTree( SUPER_USER_KEY, ROOT_FILEDATA ),\r
1357                 ROOT_FILE   = SYSTEM_TREE.getRootFile();\r
1358 \r
1359         function createFileTypeID(){\r
1360                 return ++numFileType;\r
1361         };\r
1362         \r
1363         var FileAPIClass = function( driver ){\r
1364                 var constObject;\r
1365                 this.createFolderUnderRoot = function( _fileData ){\r
1366                         if( _fileData !== null && Type.isObject( _fileData ) === true ){\r
1367                                 ROOT_FILEDATA.children.push( _fileData );\r
1368                                 ROOT_FILE.dispatchEvent( new FileEventClass( Const.FILE.EVENT.GET_SEQENTIAL_FILES, ROOT_FILE, 'children', null ));\r
1369                         }\r
1370                 };\r
1371                 this.createFileEvent   = function( _eventType, _file, _key, _value ){\r
1372                         return new FileEventClass( _eventType, _file, _key, _value );\r
1373                 };\r
1374                 this.createFileTypeID  = createFileTypeID;\r
1375                 this.getFileDataAccess = FILE_CONTROLER.getFileDataAccess;\r
1376                 this.getFileData       = FILE_CONTROLER.getFileData;\r
1377                 this.getJson           = function( _data, _url, _onLoad, _onError ){\r
1378                         REQUEST_CONTROLER.getJson( driver, _data, _url, _onLoad, _onError );\r
1379                 };\r
1380                 this.createTree        = function( _rootFile ){\r
1381                         return FILE_CONTROLER.createTree( driver, _rootFile );\r
1382                 };\r
1383                 this.isTreeInstance    = function( _tree ){\r
1384                         return _tree instanceof TreeClass;\r
1385                 };\r
1386                 this.isFileInstance    = function( _file ){\r
1387                         return _file instanceof FileClass;\r
1388                 };\r
1389                 this.isFileEvent       = function( _event ){\r
1390                         return _event instanceof FileEventClass;\r
1391                 };\r
1392                 this.getConst          = function(){\r
1393                         return Const; // constObject = constObject || clone( Const )\r
1394                 };\r
1395         };\r
1396         \r
1397         return {\r
1398                 registerDriver: function( _class ){\r
1399                         _class.prototype = new FileDriverBase( _class );\r
1400                         var _driver = new _class();\r
1401                         \r
1402                         DRIVER_LIST.push( _driver );\r
1403                         API_USER_LIST.push( _class );\r
1404 \r
1405                         return new FileAPIClass( _driver );\r
1406                 },\r
1407                 isDriver: function( _driver ){\r
1408                         return _driver instanceof FileDriverBase;\r
1409                 },\r
1410                 isTreeInstance: function( _tree ){\r
1411                         return _tree instanceof TreeClass;\r
1412                 },\r
1413                 isFileInstance: function( _file ){\r
1414                         return _file instanceof FileClass;\r
1415                 }\r
1416         }\r
1417 })();\r
1418 \r
1419 \r
1420 /* ----------------------------------------------------\r
1421  * ApplicationManager\r
1422  * window resize event, overlayApplication currentAplication に流す\r
1423  */     \r
1424 \r
1425 var APPLICATION_LIST = [];\r
1426 \r
1427 var ApplicationPrivateData = function(){};\r
1428 ApplicationPrivateData.prototype = {\r
1429         appClass      : null,\r
1430         application   : null,\r
1431         displayName   : null,\r
1432         isOverlay     : false,\r
1433         rootElement   : null,\r
1434         bgColor       : '#C1CACF',\r
1435         uiList        : null,\r
1436         formList      : null,\r
1437         finderList    : null,\r
1438         styleCursor   : null,\r
1439         eventRoot     : null,\r
1440         fetchResource : 0,\r
1441         bootParams    : null,\r
1442         phase         : 0,\r
1443         cursor        : '',\r
1444         w             : 0,\r
1445         h             : 0,\r
1446         init          : function( appClass, displayName, isOverlay ){\r
1447                 this.appClass    = appClass;\r
1448                 // this.application = app;\r
1449                 this.displayName = displayName;\r
1450                 this.isOverlay   = isOverlay;\r
1451                 this.rootElement = document.createElement( 'div' );\r
1452                 this.styleCursor = this.rootElement.style;\r
1453                 ApplicationPrivateData.list.push( this );\r
1454         },\r
1455         detect : function(){\r
1456                 if( this.rootElement.firstChild && this.fetchResource === 0 ){\r
1457                         SystemTimer.remove( this.application, this.detect );\r
1458                         this.onOpen();\r
1459                 };\r
1460         },\r
1461         onOpen : function(){\r
1462                 this.rootElement.style.display = '';\r
1463                 \r
1464                 // this.layer !== null && this.layer.onResize( this.w, this.h );\r
1465                 \r
1466                 if( this.application.MIN_WIDTH > this.w || this.application.MIN_HEIGHT > this.h ){\r
1467                         if( Type.isHTMLElement( this.rootElement ) === true ){\r
1468                                 // 小さすぎる!、と表示\r
1469                         };\r
1470                 };\r
1471                 if( this.bootParams.length > 2 ){\r
1472                         this.application.onOpen.apply( this.application, this.bootParams );\r
1473                 } else {\r
1474                         this.application.onOpen( this.w, this.h );\r
1475                 };\r
1476                 this.phase = 4; \r
1477         },\r
1478         fetchResourceComplete : function(){\r
1479                 --this.fetchResource;\r
1480         }\r
1481 };\r
1482 ApplicationPrivateData.list = [];\r
1483 ApplicationPrivateData.get = function( app ){\r
1484         var list = ApplicationPrivateData.list,\r
1485                 i    = list.length;\r
1486         for( ; i; ){\r
1487                 if( app instanceof list[ --i ].appClass ) return list[ i ];\r
1488         };\r
1489         return null;\r
1490 };\r
1491 \r
1492 var AbstractApplication = function( appClass, displayName, isOverlay ){\r
1493         ( new ApplicationPrivateData() ).init( appClass, displayName, isOverlay );\r
1494 };\r
1495 AbstractApplication.prototype = {\r
1496         getUID : function(){\r
1497                 var data = ApplicationPrivateData.get( this );\r
1498                 return Util.getIndex( API_USER_LIST, data.appClass );\r
1499         },\r
1500         init : function(){\r
1501                 var data = ApplicationPrivateData.get( this );\r
1502                 // this.rootElement = data.rootElement;\r
1503                 // data.application = this;\r
1504                 data.phase = 1;\r
1505                 data.appClass === Page.appClass && Page.show();\r
1506                 this.onInit();\r
1507                 data.phase = 2;\r
1508         },\r
1509         open : function( w, h /*, _option */ ){\r
1510                 var data = ApplicationPrivateData.get( this );\r
1511                 data.phase      = 3;\r
1512                 data.bootParams = Util.copyArray( arguments );\r
1513                 data.w          = w;\r
1514                 data.h          = h;\r
1515                 if( data.rootElement.innerHTML && data.rootElement.innerHTML.length > 0 ){\r
1516                         SystemTimer.add( this, data.detect, 16, false, data );\r
1517                 } else {\r
1518                         data.onOpen();\r
1519                 };\r
1520         },\r
1521         resize : function( w, h ){\r
1522                 var data = ApplicationPrivateData.get( this );\r
1523                 if( data.phase !== 4 ) return;\r
1524                 if( this.MIN_WIDTH > w || this.MIN_HEIGHT > h ){\r
1525                         if( Type.isHTMLElement( this.rootElement ) === true ){\r
1526                                 // 小さすぎる!、と表示\r
1527                         };\r
1528                         return;\r
1529                 };\r
1530                 this.onPaneResize( w, h );\r
1531         },\r
1532         close : function(){\r
1533                 var data = ApplicationPrivateData.get( this );\r
1534                 data.phase = 5;\r
1535                 if( this.onClose() === false ){\r
1536                         return false;\r
1537                 };\r
1538                 if( data.uiList ){ \r
1539                         while( data.uiList.length > 0 ) data.uiList.shift().destroy();\r
1540                 };\r
1541                 if( data.finderList ){\r
1542                         while( data.finderList.length > 0 ) data.finderList.shift().destroy();\r
1543                 };              \r
1544                 \r
1545                 data.eventRoot && PointingDeviceEventTree.destroyTree( data.eventRoot );\r
1546                 MouseEvent.remove( this );\r
1547                 KeyEvent.remove( this );\r
1548                 SystemTimer.remove( this );\r
1549                 AsyncCall.remove( this );\r
1550                 StyleSheet.unload( this );\r
1551 \r
1552                 var elm = this.rootElement;\r
1553                 Util.removeAllChildren( elm );\r
1554                 elm.parentNode.removeChild( elm );\r
1555                 \r
1556                 Application.shutdown( this, data.isOverlay );\r
1557                 \r
1558                 data.appClass === Page.appClass && Page.hide();\r
1559 \r
1560                 data.phase = 6;\r
1561                 \r
1562                 var list = ApplicationPrivateData.list;\r
1563                 list.splice( Util.getIndex( list, data ), 1 );\r
1564         },\r
1565         createUIGroup : function( node ){\r
1566                 var data = ApplicationPrivateData.get( this ),\r
1567                         ui = UI.createUIGroup( this, node );\r
1568                 if( data.uiList === null ) data.uiList = [];\r
1569                 data.uiList.push( ui );\r
1570                 return ui;\r
1571         },\r
1572         createUIForm : function( nodeOrElm, opt_elmForm ){\r
1573                 var data = ApplicationPrivateData.get( this ),\r
1574                         form = UIForm.createForm( this, nodeOrElm, opt_elmForm );\r
1575                 if( data.formList === null ) data.formList = [];\r
1576                 data.formList.push( form );\r
1577                 return form;\r
1578         },\r
1579         createFinder : function( _elmTarget, _tree, _onSelect, _viewerOption, _editorOption ){\r
1580                 var data   = ApplicationPrivateData.get( this ),\r
1581                         finder = Finder.create( this, _elmTarget, _tree, _onSelect, _viewerOption, _editorOption );\r
1582                 if( data.finderList === null ) data.finderList = [];\r
1583                 data.finderList.push( finder );\r
1584                 return finder;\r
1585         },\r
1586         createDHTML : function( _elm ){\r
1587                 return DHTML.create( this, _elm );\r
1588         },\r
1589         addEventListener : function( element, eventType, handler, opt_thisObject ){\r
1590                 MouseEvent.add( this, element, eventType, handler, opt_thisObject );\r
1591         },\r
1592         removeEventListener : function( element, eventType, handler ){\r
1593                 MouseEvent.remove( this, element, eventType, handler );\r
1594         },\r
1595         getPointingDeviceEventTreeRoot : function(){\r
1596                 var data = ApplicationPrivateData.get( this );\r
1597                 if( data.phase === 1 ){\r
1598                         data.eventRoot   = PointingDeviceEventTree.create( this );\r
1599                         data.styleCursor = PointingDeviceEventTree._getNodePrivateData( data.eventRoot ).elmMouseCatch.style;\r
1600                 };              \r
1601                 return data.eventRoot;\r
1602         },\r
1603         updateCoursor : function( _cursor ){\r
1604                 var data = ApplicationPrivateData.get( this );\r
1605                 if( data.cursor !== _cursor ){\r
1606                         data.styleCursor.cursor = data.cursor = _cursor;\r
1607                 };\r
1608         },\r
1609         fetchCSS : function( url, opt_onload, opt_onerror ){\r
1610                 var data = ApplicationPrivateData.get( this );\r
1611                 if( data.phase === 1 ){\r
1612                         ++data.fetchResource;\r
1613                         StyleSheet.load( this, url, data.fetchResourceComplete, data.fetchResourceComplete, data );\r
1614                 };\r
1615         },\r
1616         onInit : function(){},\r
1617         onOpen : function(){},\r
1618         onClose : function(){ return true; },\r
1619         onPaneResize : function( w, h ){},\r
1620         addKeyEventListener : function( _eventType, _handler, _keyCode, _shift, _ctrl ){\r
1621                 KeyEvent.add( this, _eventType, _handler, _keyCode, _shift, _ctrl );\r
1622         },\r
1623         removeKeyEventListener : function( _eventType, _handler, _keyCode, _shift, _ctrl ){\r
1624                 KeyEvent.remove( this, _eventType, _handler, _keyCode, _shift, _ctrl );\r
1625         },\r
1626         shiftEnabled : function(){\r
1627                 return KeyEvent.shiftEnabled;\r
1628         },\r
1629         ctrlEnabled : function(){\r
1630                 return KeyEvent.ctrlEnabled;\r
1631         },\r
1632         addTimer : function( handler, time, once ){\r
1633                 SystemTimer.add( this, handler, time, !!once );\r
1634         },\r
1635         removeTimer : function( handler ){\r
1636                 SystemTimer.remove( this, handler );\r
1637         },\r
1638         addAsyncCall : function( _callback, _argments, _thisObject ){\r
1639                 AsyncCall.add( this, _callback, _argments, _thisObject );\r
1640         },\r
1641         removeAsyncCall : function( _callback ){\r
1642                 AsyncCall.remove( this, _callback );\r
1643         },\r
1644         fetchHTMLElement : function( id ){\r
1645                 var elm = document.getElementById( id );\r
1646                 if( elm ){\r
1647                         elm.removeAttribute( 'id' );\r
1648                         elm.parentNode.removeChild( elm );\r
1649                         return elm;\r
1650                 };\r
1651         }\r
1652 };\r
1653 \r
1654 var PointingDeviceEventTree = ( function(){\r
1655         var ROOT_LIST       = [],\r
1656                 currentRootData = null,\r
1657                 targetNodeData  = null,\r
1658                 forceNodeData   = null,\r
1659                 hoverList       = [];\r
1660         \r
1661         function eventRellay( e ){\r
1662                 var data = forceNodeData, // || targetNodeData,\r
1663                         x    = e.clientX,\r
1664                         y    = e.clientY,\r
1665                         type = e.type,\r
1666                         list = hoverList,\r
1667                         i    = 0,\r
1668                         ret, systemOnly = false, addClass, removeClass,\r
1669                         parent;\r
1670                 if( data && data.dispatchEvent( e, type, true ) === true ) return false;\r
1671                 if( currentRootData === null ) return;\r
1672                 targetNodeData = currentRootData;\r
1673                 currentRootData._capcher( x, y );\r
1674                 targetNodeData.apiuser.updateCoursor( targetNodeData._cursor );\r
1675                 data = targetNodeData;\r
1676                 while( data ){\r
1677                         ret = data.dispatchEvent( e, type, true, systemOnly );\r
1678                         if( ret === true || ret === false ) break; // systemOnly = true;\r
1679                         data = data.parentData;\r
1680                 };\r
1681                 \r
1682                 addClass    = Util.addClass;\r
1683                 removeClass = Util.removeClass;\r
1684                 for( ; i < list.length; ){\r
1685                         parent = data = list[ i ];\r
1686                         while( parent.parentData && parent === parent.parentData.hitChild ){\r
1687                                 parent = parent.parentData;\r
1688                         };\r
1689                         if( parent !== currentRootData ){\r
1690                                 data.hover === true && removeClass( data.elm, data.hoverClass );\r
1691                                 delete data.isHover;\r
1692                                 data.events && data.events.mouseout && data.fire( e, 'mouseout', false );\r
1693                                 delete data.hitSelf;\r
1694                                 list.splice( i, 1 );\r
1695                                 continue;\r
1696                         };\r
1697                         if( data.hover === true && data.isHover === false ){\r
1698                                 addClass( data.elm, data.hoverClass );\r
1699                                 data.isHover = true;\r
1700                         };\r
1701                         if( data.hitSelf === false ){\r
1702                                 data.events && data.events.mouseover && data.fire( e, 'mouseover', true );\r
1703                                 data.hitSelf = true;\r
1704                         };\r
1705                         ++i;\r
1706                 };\r
1707                 return false;\r
1708         };      \r
1709         \r
1710         var NodeClass = function( apiuser, rootData, /*parentLayer,*/ parentData, rangeOrElm, through, clip, hover, cursor, scroll, dragdrop ){\r
1711                 ( new NodePrivateData() ).init( apiuser, rootData, /*parentLayer,*/ parentData, this, rangeOrElm, through, clip, hover, cursor, scroll, dragdrop );\r
1712         };\r
1713         NodeClass.prototype = {\r
1714                 createNode : function( rangeOrElmData, through, clip, hover, cursor, scroll, dragdrop ){\r
1715                         var data = NodePrivateData.get( this ),\r
1716                                 elm;\r
1717                         if( Type.isHTMLElement( rangeOrElmData ) === true ){\r
1718                                 elm = rangeOrElmData;\r
1719                         } else\r
1720                         if( Type.isString( rangeOrElmData ) === true ){\r
1721                                 elm = document.getElementById( rangeOrElmData );\r
1722                                 if( !elm ){\r
1723                                         elm = Util.pullHtmlAsTemplete( rangeOrElmData );\r
1724                                 };\r
1725                                 if( !elm || Type.isHTMLElement( elm ) === false || elm.nodeType !== 1 ){\r
1726                                         throw new Error( "invalid HTMLElement." );\r
1727                                 };\r
1728                         } else\r
1729                         if( Type.isObject( rangeOrElmData ) === false || Type.isFinite( rangeOrElmData.x ) === false || Type.isFinite( rangeOrElmData.y ) === false ){\r
1730                                 throw new Error( "No range" );\r
1731                         };\r
1732                         \r
1733                         if( elm && data.elm === null ){\r
1734                                 throw new Error( "MetaLayer don't containe HTMLElement-Layer." );\r
1735                         };\r
1736                         if( data.elm && data.elm.style.hasLayout === false ){\r
1737                                 throw new Error( "[ie] OffsetParent is hasLayout === false." );\r
1738                         };\r
1739                         \r
1740                         var newNode = new NodeClass( data.apiuser, data.rootData, data, elm || rangeOrElmData, through, clip, hover, cursor, scroll, dragdrop ),\r
1741                                 newData = NodePrivateData.get( newNode );\r
1742                         \r
1743                         if( data.childData === null ) data.childData = [];\r
1744                         data.childData.push( newData );\r
1745                         return newNode;\r
1746                 },\r
1747                 createNodeAt : function(){\r
1748                 },\r
1749                 remove : function(){\r
1750                         NodePrivateData.get( this ).remove();\r
1751                 },\r
1752                 nodeIndex : function( v ){\r
1753                         return NodePrivateData.get( this ).nodeIndex( v );\r
1754                 },\r
1755                 numNode : function(){\r
1756                         return NodePrivateData.get( this ).numNode();\r
1757                 },\r
1758                 disabled : function( v ){\r
1759                         return NodePrivateData.get( this ).disabled( v );\r
1760                 },\r
1761                 childrenDisabled : function( v ){\r
1762                         return NodePrivateData.get( this ).disabled( v );\r
1763                 },\r
1764                 mesure : function(){\r
1765                         NodePrivateData.get( this ).mesure();\r
1766                 },\r
1767                 mesureChildren : function(){\r
1768                         NodePrivateData.get( this ).mesureChildren();\r
1769                 },\r
1770                 update : function( x, y, w, h ){\r
1771                         NodePrivateData.get( this ).update( x, y, w, h );\r
1772                 },\r
1773                 setPosition : function( x, y ){\r
1774                         NodePrivateData.get( this ).setPosition( x, y );\r
1775                 },\r
1776                 setSize : function( w, h ){\r
1777                         NodePrivateData.get( this ).setSize( w, h );\r
1778                 },\r
1779                 cursor : function( v ){\r
1780                         return NodePrivateData.get( this ).cursor( v );\r
1781                 },\r
1782                 x : function( x ){\r
1783                         return NodePrivateData.get( this ).positionX( x );\r
1784                 },\r
1785                 y : function( y ){\r
1786                         return NodePrivateData.get( this ).positionY( y );\r
1787                 },\r
1788                 width : function( w ){\r
1789                         return NodePrivateData.get( this ).width( w );\r
1790                 },\r
1791                 height : function( h ){\r
1792                         return NodePrivateData.get( this ).height( h );\r
1793                 },\r
1794                 getAbsolutePositionX : function(){\r
1795                         return NodePrivateData.get( this ).getAbsolutePositionX();\r
1796                 },\r
1797                 getAbsolutePositionY : function(){\r
1798                         return NodePrivateData.get( this ).getAbsolutePositionY();\r
1799                 },\r
1800                 addEventListener : function( type, handler, opt_thisObject ){\r
1801                         NodePrivateData.get( this ).addEventListener( type, handler, opt_thisObject );\r
1802                 },\r
1803                 removeEventListener : function( type, handler ){\r
1804                         NodePrivateData.get( this ).removeEventListener( type, handler );\r
1805                 },\r
1806                 scrollTo : function( x, y ){\r
1807                         NodePrivateData.get( this ).scrollTo( x, y );\r
1808                 },\r
1809                 scrollX : function( v ){\r
1810                         return NodePrivateData.get( this ).scrollX( v );\r
1811                 },\r
1812                 scrollY : function( v ){\r
1813                         return NodePrivateData.get( this ).scrollY( v );\r
1814                 },\r
1815                 invalidateScrollbar : function(){\r
1816                         ScrollBarManager.update( NodePrivateData.get( this ) );\r
1817                 }\r
1818         };\r
1819 \r
1820         /**\r
1821          * clip : true の場合、子ノードの変更によってヒットエリアを変化させない.elm には overflow:hidden としておくのが通常.\r
1822          */\r
1823         var NodePrivateData = function(){};\r
1824         NodePrivateData.prototype = {\r
1825                 elmMouseCatch : null, // rootData only\r
1826                 eventCounter  : null, // rootData only\r
1827                 cursorStyle   : null, // rootData only\r
1828                 node          : null,\r
1829                 apiuser       : null,\r
1830                 rootData      : null,\r
1831                 elm           : null, // resizeTarget\r
1832                 elmScroll     : null,\r
1833                 elmScroller   : null,\r
1834                 elmScrollbar  : null,\r
1835                 x             : 0,\r
1836                 y             : 0,\r
1837                 w             : 0,\r
1838                 h             : 0,\r
1839                 t             : 0, // top\r
1840                 l             : 0, // left\r
1841                 b             : 0, // bottom\r
1842                 r             : 0, // right\r
1843                 absoluteX     : 0,\r
1844                 absoluteY     : 0,\r
1845                 _scrollX      : 0,\r
1846                 _scrollY      : 0,\r
1847                 scrollingX    : 0,\r
1848                 scrollingY    : 0,\r
1849                 _cursor       : '',\r
1850                 // parentLayer   : null,\r
1851                 parentData    : null,\r
1852                 childData     : null,\r
1853                 events        : null,\r
1854                 hitChild      : null,\r
1855                 hitSelf       : false,\r
1856                 _disabled     : false,\r
1857                 _childDisabled: false,\r
1858                 layoutManager : null,\r
1859                 through       : false,\r
1860                 clip          : false,\r
1861                 hover         : false,\r
1862                 hoverClass    : null,\r
1863                 isHover       : false,\r
1864                 scroll        : false,\r
1865                 dragdrop      : false,\r
1866                 tooltip       : null,\r
1867                 init: function( apiuser, rootData, /*parentLayer,*/ parentData, node, rangeOrElm, through, clip, hover, cursor, scroll, dragdrop ){\r
1868                         this.apiuser     = apiuser;\r
1869                         this.rootData    = rootData || this;\r
1870                         // this.parentLayer = parentLayer;\r
1871                         this.parentData  = parentData;\r
1872                         this.node        = node;\r
1873                         this.through     = through;\r
1874                         this.clip        = !!clip;\r
1875                         if( cursor ) this._cursor = cursor;   \r
1876 \r
1877                         if( Type.isHTMLElement( rangeOrElm ) === true ){\r
1878                                 this.elm        = rangeOrElm;\r
1879                                 this.hover      = !!hover;\r
1880                                 this.hoverClass = hover;\r
1881                                 this.scroll     = clip && scroll;                               \r
1882                                 this.mesure();\r
1883                                 this.scroll === true && ScrollBarManager.register( this );\r
1884                         } else {\r
1885                                 this.update( rangeOrElm.x, rangeOrElm.y, rangeOrElm.w, rangeOrElm.h );\r
1886                         };\r
1887                         \r
1888                         NodePrivateData.dataList.push( this );\r
1889                 },\r
1890                 mesure : function(){\r
1891                         var x, y, w, h, parent, _this, _parent;\r
1892                         if( this.elm ){\r
1893                                 w = this.elm.offsetWidth;\r
1894                                 h = this.elm.offsetHeight;\r
1895                                 _this   = Position.cumulativeOffset( this.elm );\r
1896                                 _parent = this.parentData ? Position.cumulativeOffset( this.parentData.elm ) : [ 0, 0 ];\r
1897                                 x  = _this[ 0 ] - _parent[ 0 ];\r
1898                                 y  = _this[ 1 ] - _parent[ 1 ];                         \r
1899                                 if( this.x !== x || this.y !== y || this.w !== w || this.h !== h ){\r
1900                                         this.x = x;\r
1901                                         this.y = y;\r
1902                                         this.w = w;\r
1903                                         this.h = h;\r
1904                                         parent = this.parentData;\r
1905                                         parent && this._updateAbsoluteXY( parent.absoluteX, parent.absoluteY, parent.scrollingX, parent.scrollingY );\r
1906                                         this._updateRectangle();\r
1907                                 };                      \r
1908                         } else {\r
1909                                 this._updateRectangle();\r
1910                         };\r
1911                 },\r
1912                 mesureChildren : function(){\r
1913                         var nodes, i;\r
1914                         if( nodes = this.childData ){\r
1915                                 for( i = nodes.length; i; ){\r
1916                                         nodes[ --i ].mesure();\r
1917                                 };\r
1918                         };\r
1919                 },\r
1920                 update : function( x, y, w, h ){\r
1921                         var updateXY = false,\r
1922                                 _this, _parent,\r
1923                                 parent;\r
1924                         \r
1925                         if( this.elm ){\r
1926                                 // width\r
1927                                 if( Type.isFinite( w ) === true ){\r
1928                                         this.elm.style.width = w + 'px';\r
1929                                 } else\r
1930                                 if( Type.isString( w ) === true ){\r
1931                                         this.elm.style.width = w;\r
1932                                         w = this.elm.offsetWidth;\r
1933                                 };\r
1934                                 //update = this.w !== w;\r
1935         \r
1936                                 // height\r
1937                                 if( Type.isFinite( h ) === true ){\r
1938                                         this.elm.style.height = h + 'px';\r
1939                                 } else\r
1940                                 if( Type.isString( h ) === true ){\r
1941                                         this.elm.style.height = w;\r
1942                                         h = this.elm.offsetHeight;\r
1943                                 };\r
1944                                 //update = update || this.h !== h;\r
1945                                 \r
1946                                 // x\r
1947                                 if( Type.isFinite( x ) === true ){\r
1948                                         this.elm.style.left = x + 'px';\r
1949                                 } else\r
1950                                 if( Type.isString( x ) === true ){\r
1951                                         this.elm.style.left = x;\r
1952                                         updateXY = true;\r
1953                                 } else {\r
1954                                         updateXY = true;\r
1955                                 };\r
1956                                 \r
1957                                 // y\r
1958                                 if( Type.isFinite( y ) === true ){\r
1959                                         this.elm.style.top = y + 'px';\r
1960                                 } else\r
1961                                 if( Type.isString( y ) === true ){\r
1962                                         this.elm.style.top = y;\r
1963                                         updateXY = true;\r
1964                                 } else {\r
1965                                         updateXY = true;\r
1966                                 };\r
1967                                 if( updateXY === true ){\r
1968                                         _this   = Position.cumulativeOffset( this.elm );\r
1969                                         _parent = this.parentData ? Position.cumulativeOffset( this.parentData.elm ) : [ 0, 0 ];\r
1970                                         x       = _this[ 0 ] - _parent[ 0 ];\r
1971                                         y       = _this[ 1 ] - _parent[ 1 ];\r
1972                                 };\r
1973                                 //update = update || this.x !== x;\r
1974                                 //update = update || this.y !== y;\r
1975                                 \r
1976                                 //update === true && this._updateRectangle();\r
1977                                 // return;\r
1978                         };\r
1979                         x = Type.isFinite( x ) === true ? x : this.x;\r
1980                         y = Type.isFinite( y ) === true ? y : this.y;\r
1981                         w = Type.isFinite( w ) === true ? w : this.w;\r
1982                         h = Type.isFinite( h ) === true ? h : this.h;\r
1983                         if( this.x !== x || this.y !== y ){\r
1984                                 this.x = x;\r
1985                                 this.y = y;\r
1986                                 //console.log( 'xy  ' + ( this.elm ? this.elm.id : '' ) + ' x:' + x + ' y:' + y + ' w:' + w + ' h:' + h + ' absX:' + this.parentData.absoluteX )\r
1987                                 parent = this.parentData;\r
1988                                 parent && this._updateAbsoluteXY( parent.absoluteX, parent.absoluteY, parent.scrollingX, parent.scrollingY );\r
1989                                 this.w === w && this.h === h && this._updateRectangle();\r
1990                         };\r
1991                         if( this.w !== w || this.h !== h ){\r
1992                                 this.w = w;\r
1993                                 this.h = h;\r
1994                                 //console.log( 'wh  ' + ( this.elm ? this.elm.id : '' ) + ' x:' + x + ' y:' + y + ' w:' + w + ' h:' + h )\r
1995                                 this._updateRectangle();\r
1996                         };\r
1997                         \r
1998                         ScrollBarManager.update( this );\r
1999                 },\r
2000                 _updateAbsoluteXY : function( x, y, sX, sY ){\r
2001                         var nodes, i;\r
2002                         this.absoluteX = x = this.x + x;\r
2003                         this.absoluteY = y = this.y + y;\r
2004                         if( nodes = this.childData ){\r
2005                                 for( i = nodes.length; i; ){\r
2006                                         nodes[ --i ]._updateAbsoluteXY( x, y, this.scrollingX, this.scrollingY );\r
2007                                 };\r
2008                         };\r
2009                 },\r
2010                 _updateRectangle : function(){\r
2011                         var w = this.w,\r
2012                                 h = this.h,\r
2013                                 x = this.x,\r
2014                                 y = this.y,\r
2015                                 l = x,\r
2016                                 t = y,\r
2017                                 r = x + w,\r
2018                                 b = y + h,\r
2019                                 nodes = this.childData,\r
2020                                 i, node;\r
2021                         // self;\r
2022                         // childnodes\r
2023                         if( this.clip === false && nodes ){\r
2024                                 for( i = nodes.length; i; ){\r
2025                                         node = nodes[ --i ];\r
2026                                         if( node.l + x < l ) l = x + node.l;\r
2027                                         if( node.t + y < t ) t = y + node.t;\r
2028                                         if( r < node.r + x ) r = x + node.r;\r
2029                                         if( b < node.b + y ) b = y + node.b;\r
2030                                 };\r
2031                         };\r
2032                         // update\r
2033                         if( b !== this.b || r !== this.r || t !== this.t || l !== this.l ){\r
2034                                 this.l = l;\r
2035                                 this.t = t;\r
2036                                 this.r = r;\r
2037                                 this.b = b;\r
2038                                 // this.w = r - x;\r
2039                                 // this.h = b - y;\r
2040                                 this.parentData && this.parentData.clip === false && this.parentData._updateRectangle();\r
2041                                 return true;\r
2042                         };\r
2043                 },\r
2044                 setPosition : function( x, y ){\r
2045                         this.update( x, y );\r
2046                 },\r
2047                 setSize : function( w, h ){\r
2048                         this.update( undefined, undefined, w, h );\r
2049                 },\r
2050                 positionX : function( x ){\r
2051                         x !== undefined && this.update( x );\r
2052                         return this.x;\r
2053                 },\r
2054                 positionY : function( y ){\r
2055                         y !== undefined && this.update( undefined, y );\r
2056                         return this.y;\r
2057                 },\r
2058                 width : function( w ){\r
2059                         w !== undefined && this.update( undefined, undefined, w );\r
2060                         return this.w;\r
2061                 },\r
2062                 height : function( h ){\r
2063                         h !== undefined && this.update( undefined, undefined, undefined, h );\r
2064                         return this.h;\r
2065                 },\r
2066                 getAbsolutePositionX : function(){\r
2067                         return this.absoluteX;\r
2068                 },\r
2069                 getAbsolutePositionY : function(){\r
2070                         return this.absoluteY;\r
2071                 },\r
2072                 cursor : function( v ){\r
2073                         if( Type.isString( v ) === true ){\r
2074                                 this._cursor = v;\r
2075                                 this === targetNodeData && this.apiuser.updateCoursor( v );\r
2076                         };\r
2077                         return this._cursor;\r
2078                 },\r
2079                 addEventListener : function( eventType, handler, opt_thisObject ){\r
2080                         var node    = this.node,\r
2081                                 counter = this.rootData.eventCounter,\r
2082                                 list, i;\r
2083                         if( this.events === null ) this.events = {};\r
2084                         list = this.events[ eventType ];\r
2085                         if( !list ){\r
2086                                 list = this.events[ eventType ] = [];\r
2087                         } else {\r
2088                                 for( i = list.length; i; ){\r
2089                                         if( list[ --i ].match( eventType, handler ) === true ){\r
2090                                                 return;\r
2091                                         };\r
2092                                 };                              \r
2093                         };\r
2094                         list.push( new EventTicketClass( this.node, eventType, handler, opt_thisObject ) );\r
2095                         if( eventType !== 'mouseout' && eventType !== 'mouseover' ){\r
2096                                 if( counter[ eventType ] ){\r
2097                                         ++counter[ eventType ];\r
2098                                 } else {\r
2099                                         //console.log( eventType );\r
2100                                         counter[ eventType ] = 1;\r
2101                                         MouseEvent.add( this.apiuser, this.rootData.elmMouseCatch, eventType, eventRellay );\r
2102                                 };                              \r
2103                         };\r
2104                 },\r
2105                 removeEventListener : function( eventType, handler ){\r
2106                         var events  = this.events,\r
2107                                 counter = this.rootData.eventCounter,\r
2108                                 type, list, i = 0;\r
2109                         if( events === null ) return;\r
2110                         console.log( ' *** remove ' + eventType );\r
2111                         for( type in events ){\r
2112                                 list = events[ type ];\r
2113                                 if( eventType && eventType !== type ) continue;\r
2114                                 for( ; i < list.length; ){\r
2115                                         if( list[ i ].destroy( type, handler ) === true ){\r
2116                                                 console.log( ' *** removed! ' + type );\r
2117                                                 list.splice( i, 1 );\r
2118                                         } else {\r
2119                                                 ++i;\r
2120                                         };\r
2121                                 };\r
2122                                 if( list.length === 0 ){\r
2123                                         // delete this[ type ];\r
2124                                         delete events[ type ];\r
2125                                 };\r
2126                                 if( counter[ type ] ){\r
2127                                         --counter[ type ];\r
2128                                         if( counter[ type ] === 0 ){\r
2129                                                 MouseEvent.remove( this.apiuser, this.rootData.elmMouseCatch, type, eventRellay );\r
2130                                                 delete counter[ type ];\r
2131                                         };\r
2132                                 };\r
2133                         };\r
2134                 },\r
2135                 _capcher : function( x, y ){\r
2136                         var t = this, nodes, child, _x, _y, hit, i;\r
2137                         if( t._disabled === true ) return false;\r
2138                         delete t.hitChild;\r
2139                         x -= t.x;\r
2140                         y -= t.y;\r
2141                         if( nodes = t.childData ){\r
2142                                 _x = x - t.scrollingX;\r
2143                                 _y = y - t.scrollingY;\r
2144                                 for( i = nodes.length; i; ){\r
2145                                         child = nodes[ --i ];\r
2146                                         if( child._disabled === false && child.l <= _x && _x < child.r && child.t <= _y && _y < child.b && child._capcher( _x, _y ) === true ){\r
2147                                                 t.hitChild = child;\r
2148                                                 break;\r
2149                                         };\r
2150                                 };\r
2151                         };\r
2152                         if( t.through === true ){\r
2153                                 t.hitChild && t.hitSelf === false && hoverList.push( t );\r
2154                                 return !!t.hitChild;\r
2155                         };\r
2156                         hit = 0 <= x && x < t.w && 0 <= y && y < t.h;\r
2157                         ( t.hitChild || hit ) && t.hitSelf === false && hoverList.push( t );\r
2158                         if( hit === true && t.hitChild === null ) targetNodeData = t;\r
2159                         return hit || !!t.hitChild;\r
2160                 },\r
2161                 fire : function( e, eventType, hit ){\r
2162                         var list = this.events[ eventType ],\r
2163                                 i    = list.length;\r
2164                         e = NodePrivateData.createEvent( e, eventType, this, hit );\r
2165                         for( ; i; ) list[ --i ].fire( e );\r
2166                         // console.log( eventType + ' x:' + x + ' y:' + y );\r
2167                 },\r
2168                 dispatchEvent : function( e, eventType, hit ){\r
2169                         var ret, list, i, p, child;\r
2170                         if( !this.events || !( list = this.events[ eventType ] ) ) return;\r
2171                         \r
2172                         child = !!this.hitChild;\r
2173                         e = NodePrivateData.createEvent( e, eventType, this, hit );\r
2174                         for( i = list.length; i; ){\r
2175                                 ret = list[ --i ].fire( e );\r
2176                                 if( ret === true && child === false ){\r
2177                                         forceNodeData = this;\r
2178                                         return true;\r
2179                                 };\r
2180                                 if( ret === false ) return false;\r
2181                         };\r
2182                         forceNodeData  = null;\r
2183                 },\r
2184                 scrollTo : function( x, y ){\r
2185                         this._scrollX = x;\r
2186                         this._scrollY = y;\r
2187                         ScrollBarManager.update( this );\r
2188                 },\r
2189                 scrollX : function( v ){\r
2190                         if( Type.isFinite( v ) === true ){\r
2191                                 this._scrillX = v;\r
2192                                 ScrollBarManager.update( this );\r
2193                         };\r
2194                         return this.scrollingX; // this._scrollX;\r
2195                 },\r
2196                 scrollY : function( v ){\r
2197                         if( Type.isFinite( v ) === true ){\r
2198                                 this._scrillY = v;\r
2199                                 ScrollBarManager.update( this );\r
2200                         };\r
2201                         return this.scrollingY; // this._scrollY;\r
2202                 },\r
2203                 nodeIndex : function( v ){\r
2204                         var list, i;\r
2205                         if( !this.parentData ) return 0;\r
2206                         \r
2207                         list = this.parentData.childData;\r
2208                         i    = Util.getIndex( list, this );\r
2209                         if( Type.isFinite( v ) === false || i === v && v < 0 && list.length <= v ) return i;\r
2210                         \r
2211                         list.splice( i, 1 );\r
2212                         list.length === v ? list.push( this ) : list.splice( v, 0, this );\r
2213                         this._free();\r
2214                         return v;\r
2215                 },\r
2216                 _free : function(){\r
2217                         if( this.parentData.hitChild === this ){\r
2218                                 this.parentData.hitChild = null;\r
2219                                 this.isHover === true && hoverList.splice( Util.getIndex( hoverList, this ), 1 ) && Util.removeClass( this.elm, this.hoverClass );\r
2220                                 this.isHover = false;\r
2221                                 if( forceNodeData === this ) forceNodeData = null;\r
2222                                 if( targetNodeData  === this ) targetNodeData  = null;\r
2223                         };                      \r
2224                 },\r
2225                 numNode : function(){\r
2226                         return this.childData ? this.childData.length : 0;\r
2227                 },\r
2228                 disabled : function( v ){\r
2229                         if( Type.isBoolean( v ) === true ){\r
2230                                 this._disabled = v;\r
2231                                 if( v === false ){\r
2232                                         this._free();\r
2233                                 };\r
2234                         };\r
2235                         return this._disabled;\r
2236                 },\r
2237                 childrenDisabled : function( v ){\r
2238                         if( Type.isBoolean( v ) === true ){\r
2239                                 this._childDisabled = v;\r
2240                         };\r
2241                         return this._childDisabled;\r
2242                 },\r
2243                 remove : function(){\r
2244                         if( this === this.rootData ) return;\r
2245                         var parent = this.parentData,\r
2246                                 nodes  = parent.childData;\r
2247                         this._destroy();\r
2248                         if( parent.hitChild === this ) delete parent.hitChild;\r
2249                         nodes.splice( Util.getIndex( nodes, this ), 1 );\r
2250                         if( nodes.length === 0 ) delete parent.childData;       \r
2251                         parent.clip === false && parent._updateRectangle();\r
2252                 },\r
2253                 _destroy : function(){\r
2254                         var nodes = this.childData,\r
2255                                 list  = NodePrivateData.dataList,\r
2256                                 node;\r
2257                         this.removeEventListener();\r
2258                         ScrollBarManager.remove( this );\r
2259                         if( nodes ){\r
2260                                 while( node = nodes.shift() ) node._destroy();\r
2261                                 delete this.childData;\r
2262                         };\r
2263                         list.splice( Util.getIndex( list, this ), 1 );\r
2264                 }\r
2265         };\r
2266         NodePrivateData.dataList = [];\r
2267         NodePrivateData.get = function( node ){\r
2268                 // if( node instanceof NodePrivateData ) return node;\r
2269                 // return NodePrivateData.dataList[ layer._getUID() ];\r
2270                 var list = NodePrivateData.dataList;\r
2271                 for( var i = list.length; i; ){\r
2272                         if( list[ --i ].node === node ) return list[ i ];\r
2273                 };\r
2274                 return null;\r
2275         };\r
2276         NodePrivateData.createEvent = function( e, eventType, data, hit ){\r
2277                 var _e = {\r
2278                         layerX      : e.clientX - data.absoluteX,\r
2279                         layerY      : e.clientY - data.absoluteY,\r
2280                         clientX     : e.clientX,\r
2281                         clientY     : e.clientY,\r
2282                         dragOffsetX : e.dragOffsetX,\r
2283                         dragOffsetY : e.dragOffsetY,\r
2284                         dragPhase   : e.dragPhase,                                      \r
2285                         eventType   : eventType,\r
2286                         hit         : hit,\r
2287                         node        : data.node,\r
2288                         wheelDelta  : e.wheelDelta,\r
2289                         target      : forceNodeData ? forceNodeData.node : targetNodeData ? targetNodeData.node : null\r
2290                 };\r
2291                 return _e;\r
2292         };\r
2293         \r
2294         var EventTicketClass = function( node, eventType, handler, opt_thisObject ){\r
2295                 this.node    = node;\r
2296                 this.type    = eventType;\r
2297                 this.handler = handler;\r
2298                 this.thisObj = opt_thisObject || node;\r
2299         };\r
2300         EventTicketClass.prototype = {\r
2301                 match : function( eventType, handler ){\r
2302                         if( handler && this.handler !== handler ) return false;\r
2303                         if( eventType && this.type !== eventType ) return false;\r
2304                         return true;\r
2305                 },\r
2306                 destroy : function( eventType, handler ){\r
2307                         if( this.match( eventType, handler ) === false ) return false;\r
2308                         delete this.node;\r
2309                         delete this.type;\r
2310                         delete this.handler;\r
2311                         delete this.thisObj;\r
2312                         return true;\r
2313                 },\r
2314                 fire : ( function(){\r
2315                         if( Function.prototype.call ){\r
2316                                 return function( e ){\r
2317                                         return this.handler.call( this.thisObj, e );\r
2318                                 };                              \r
2319                         };\r
2320                         return function( e ){\r
2321                                 var ret;\r
2322                                 this.thisObj._currentHandler = this.handler;\r
2323                                 ret = this.thisObj._currentHandler( e );\r
2324                                 delete this.thisObj._currentHandler;\r
2325                                 return ret;                                     \r
2326                         };\r
2327                 })()\r
2328         };\r
2329         \r
2330 /*-------------------------------------\r
2331  *  StayHelper\r
2332  */\r
2333         var StayEventTicketClass = function( node, data, stayhandler, opt_thisObject ){\r
2334                 node.addEventListener( 'mouseover', this.mouseoverHandler, this );\r
2335                 this.node       = node;\r
2336                 this.data       = data;\r
2337                 this.handler    = stayhandler;\r
2338                 this.thisObject = opt_thisObject;\r
2339         };\r
2340         StayEventTicketClass.prototype = Util.extend( new EventTicketClass( null, 'mousestay' ), {\r
2341                 // type : 'mousestay',\r
2342                 e    : null,\r
2343                 mouseoverHandler : function( e ){\r
2344                         this.e = NodePrivateData.createEvent( e, this.type, this.data, true );\r
2345                         this.node.addEventListener( 'mouseout',  this.mousestayHandler, this );\r
2346                         this.node.addEventListener( 'mousemove', this.mousemoveHandler, this );\r
2347                         SystemTimer.add( this.data.apiuser, this.timeoutHandler, null, this );\r
2348                 },\r
2349                 timeoutHandler : function(){\r
2350                         this.mouseoutHandler();\r
2351                         return this.fire( this.e );\r
2352                 },\r
2353                 mousemoveHandler : function( e ){\r
2354                         this.e = NodePrivateData.createEvent( e, this.type, this.data, true );\r
2355                         SystemTimer.remove( this.data.apiuser, this.timeoutHandler );\r
2356                         SystemTimer.add( this.data.apiuser, this.timeoutHandler, null, this );\r
2357                 },\r
2358                 mouseoutHandler : function( e ){\r
2359                         this.node.removeEventListener( 'mouseout', this.mousestayHandler );\r
2360                         this.node.removeEventListener( 'mousemove', this.mousemoveHandler );\r
2361                         SystemTimer.remove( this.data.apiuser, this.timeoutHandler );\r
2362                         delete this.e;\r
2363                 }\r
2364         });\r
2365         \r
2366         var ScrollBarManager = ( function(){\r
2367                 var elmScroller     = document.createElement( 'div' ),\r
2368                         elmBar          = document.createElement( 'div' ),\r
2369                         smoothList      = [],\r
2370                         dragPhase       = 2,\r
2371                         dragOut         = false,\r
2372                         currentNodeData = null,\r
2373                         dragStartY      = 0,\r
2374                         currentEvent;\r
2375                 \r
2376                 function tick(){\r
2377                         var list = smoothList,\r
2378                                 i, data, y;\r
2379                         for( i = 0; i < list.length; ){\r
2380                                 data = list[ i ];\r
2381                                 if( data.scrollingY !== data._scrollY ){\r
2382                                         y = data.scrollingY += data.smoothY;\r
2383                                         if( data.smoothY < 0 ){\r
2384                                                 y = y < data._scrollY ? data._scrollY : y;\r
2385                                         } else {\r
2386                                                 y = data._scrollY < y ? data._scrollY : y;\r
2387                                         };\r
2388                                         data.scrollingY    = y;\r
2389                                         data.elm.scrollTop = -y;\r
2390                                         data.events && data.events.scroll && data.fire( currentEvent, 'scroll', true );\r
2391                                 };\r
2392                                 if( data.scrollingY === data._scrollY ){\r
2393                                         list.splice( i, 1 );\r
2394                                         // data.events && data.events.scroll && data.fire( currentEvent, 'scroll', true );\r
2395                                 } else {\r
2396                                         ++i;\r
2397                                 };\r
2398                         };\r
2399                         list.length === 0 && SystemTimer.remove( SUPER_USER_KEY, tick );\r
2400                         currentEvent.type = 'updateAfterScroll';\r
2401                         AsyncCall.add( data.apiuser, eventRellay, currentEvent ); // スクロール後の更新        \r
2402                 };\r
2403                 \r
2404                 function scrollReady( e ){\r
2405                         var data = this;\r
2406                         \r
2407                         dragOut = false;\r
2408                         if( data === currentNodeData || dragPhase !== 2 ) return; // Drag中の場合は 他にスクロールを作らない\r
2409                         currentNodeData && scrollRelease();\r
2410 \r
2411                         dragPhase = 2;\r
2412                         data.elm.parentNode.appendChild( elmScroller );\r
2413                         elmScroller.appendChild( data.elm );\r
2414                         \r
2415                         elmScroller.style.cssText = 'position:absolute;left:0;top:0;';\r
2416                         elmScroller.appendChild( elmBar );      \r
2417                         \r
2418                         data.elm.scrollTop = -data.scrollingY;\r
2419                         data.rootData.addEventListener( 'mousewheel', onMouseWheelScroll, data );\r
2420                         data.rootData.addEventListener( 'mousedrag',  onMouseDragScroll, data );\r
2421                         data.addEventListener( 'mouseout',   onMouseOut, data );\r
2422                         currentNodeData = data;\r
2423                         ScrollBarManager.update( data );\r
2424                 };\r
2425                 function scrollRelease(){\r
2426                         var data   = currentNodeData;\r
2427                         var parent = elmScroller.parentNode;\r
2428                         parent.appendChild( currentNodeData.elm );\r
2429                         parent.removeChild( elmScroller );\r
2430                         currentNodeData.elm.scrollTop = -data.scrollingY;\r
2431                         \r
2432                         data.rootData.removeEventListener( 'mousewheel', onMouseWheelScroll, data );\r
2433                         data.rootData.removeEventListener( 'mousedrag',  onMouseDragScroll, data );\r
2434                         data.removeEventListener( 'mouseout',   onMouseOut, data );\r
2435                         currentNodeData = null;\r
2436                 };\r
2437                 function onMouseOut( e ){\r
2438                         dragOut = true;\r
2439                         console.log( 'mouseOut ' + dragPhase );\r
2440                         dragPhase === 2 && scrollRelease(); // Dragしてのアウトの場合, scroll をリリースしない\r
2441                 };\r
2442                 function onMouseWheelScroll( e ){\r
2443                         var data = this;\r
2444                         this._scrollY += e.wheelDelta;\r
2445                         ScrollBarManager.update( this );\r
2446                         currentEvent = e;\r
2447                         return true;\r
2448                 };\r
2449                 function onMouseDragScroll( e ){\r
2450                         var data = this;\r
2451                         //e.dragOffsetY;\r
2452                         currentEvent = e;\r
2453                         dragPhase = e.dragPhase;\r
2454                         switch( dragPhase ){\r
2455                                 case 0:\r
2456                                         dragStartY = this.scrollingY;\r
2457                                         data.rootData.removeEventListener( 'mousewheel', onMouseWheelScroll, data );\r
2458                                 case 1:\r
2459                                         this._scrollY = dragStartY + e.dragOffsetY;\r
2460                                         ScrollBarManager.update( this );                                \r
2461                                         return true;\r
2462                                 case 2:\r
2463                                         dragOut === true ? scrollRelease() : data.rootData.addEventListener( 'mousewheel', onMouseWheelScroll, data );\r
2464                                         return false;\r
2465                         };\r
2466                 };\r
2467                 \r
2468                 return {\r
2469                         register : function( data ){\r
2470                                 data.addEventListener( 'mouseover', scrollReady, data );\r
2471                         },\r
2472                         update : function( data ){\r
2473                                 // if( data !== currentNodeData ) return;\r
2474                                 var isCurrent = data === currentNodeData;\r
2475                                 \r
2476                                 var contentH = data._scrollH = data.elm.scrollHeight,\r
2477                                         clipH    = data.h,\r
2478                                         offsetH  = contentH - clipH,\r
2479                                         scrollY  = data._scrollY = 0 < data._scrollY ? 0 : ( data._scrollY < -offsetH ? -offsetH : data._scrollY ),\r
2480                                         barH, barY;\r
2481                                 if( isCurrent === true ){\r
2482                                         elmScroller.style.width  = data.w + 'px';\r
2483                                         elmScroller.style.height = clipH + 'px';                                        \r
2484                                 };\r
2485                                 \r
2486                                 if( offsetH < 1 ){\r
2487                                         data._scrollY = scrollY = 0;\r
2488                                         if( isCurrent === true ) elmBar.style.display = 'none';\r
2489                                 } else\r
2490                                 if( isCurrent === true ){\r
2491                                         barH     = Math.floor( clipH * ( clipH / contentH ) );\r
2492                                         barY     = Math.floor( ( clipH - barH ) * - scrollY / offsetH );\r
2493                                         elmBar.style.cssText = [\r
2494                                                 'position:absolute;',\r
2495                                                 'width:10px;',\r
2496                                                 'background-color:#333;',\r
2497                                                 'right:2px;',\r
2498                                                 'font-size:0;line-height:0;',\r
2499                                                 'height:', barH, 'px;',\r
2500                                                 'top:', data.y + barY, 'px;'\r
2501                                         ].join( '' );                                   \r
2502                                 };\r
2503                                 data.smoothY = ( scrollY - data.scrollingY ) / 10;\r
2504                                 if( data.scrollingY !== scrollY && Util.getIndex( smoothList, data ) === -1 ){\r
2505                                         smoothList.length === 0 && SystemTimer.add( SUPER_USER_KEY, tick, 16 );\r
2506                                         smoothList.push( data );\r
2507                                 };\r
2508                         },\r
2509                         remove : function( data ){\r
2510                                 var list = smoothList,\r
2511                                         i    = Util.getIndex( list, data );\r
2512                                 data === currentNodeData && scrollRelease();\r
2513                                 i !== -1 && list.splice( i, 1 );\r
2514                         }\r
2515                 };\r
2516         })();\r
2517         \r
2518         return {\r
2519                 create : function( apiuser ){\r
2520                         var     elm  = document.createElement( 'div' ),\r
2521                                 root, data;\r
2522                         body.appendChild( elm );\r
2523                         \r
2524                         root = new NodeClass( apiuser, null, null, elm );\r
2525                         data = NodePrivateData.get( root );\r
2526                         \r
2527                         // elm.style.cssText = 'position:absolute;top:0;left:0;height:100%;';\r
2528                         elm.className      = 'mouse-operation-catcher';\r
2529                         elm.unselectable   = 'on';\r
2530                         data.elmMouseCatch = elm;\r
2531                         \r
2532                         data.eventCounter  = {};\r
2533                         ROOT_LIST.push( data );\r
2534                         currentRootData    = data;\r
2535                         targetNodeData     = null;\r
2536                         forceNodeData      = null;\r
2537                         \r
2538                         MouseEvent.add( apiuser, elm, 'mousemove', eventRellay );\r
2539                         return root;\r
2540                 },\r
2541                 onCurrentApplicationChange : function( _application ){\r
2542                         currentRootData    = null;\r
2543                         targetNodeData     = null;\r
2544                         forceNodeData      = null;\r
2545                         for( var i = ROOT_LIST.length; i; ){\r
2546                                 if( ROOT_LIST[ --i ].apiuser === _application ){\r
2547                                         currentRootData = ROOT_LIST[ i ];\r
2548                                         return;\r
2549                                 };\r
2550                         };\r
2551                 },\r
2552                 destroyTree : function( root ){\r
2553                         var data = NodePrivateData.get( root );\r
2554                         MouseEvent.remove( data.apiuser, data.elmMouseCatch, 'mousemove', eventRellay );\r
2555                         body.removeChild( data.elmMouseCatch );\r
2556                         data._destroy();\r
2557                         ROOT_LIST.splice( Util.getIndex( ROOT_LIST, data ), 1 );\r
2558                         if( currentRootData === data ){\r
2559                                 currentRootData    = null;\r
2560                                 targetNodeData     = null;\r
2561                                 forceNodeData      = null;      \r
2562                         };\r
2563                 },\r
2564                 onSystemShutdown : function(){\r
2565                         \r
2566                 },\r
2567                 isNodeInstance : function( node ){\r
2568                         return node instanceof NodeClass;\r
2569                 },\r
2570                 _getNodePrivateData : function( node ){ // system only\r
2571                         return NodePrivateData.get( node );\r
2572                 }\r
2573         };\r
2574 })();\r
2575 \r
2576 var Application = ( function(){\r
2577         \r
2578         var LIVE_APPLICATION_LIST = [];\r
2579         \r
2580         var currentApplication    = null,\r
2581                 coveredApplication    = null,\r
2582                 winW                  = 0,\r
2583                 winH                  = 0;\r
2584         \r
2585         var ApplicationReference = function( appClass, isOverlay, displayName, id, thumbnailUrl, tailColor ){\r
2586                 var self          = this;\r
2587                 var application   = null;\r
2588                 this.id           = id;\r
2589                 this.displayName  = displayName;\r
2590                 this.thumbnailUrl = thumbnailUrl;\r
2591                 this.tailColor    = tailColor;\r
2592                 \r
2593                 function asyncBoot(){\r
2594                         application = Application.boot( appClass, displayName, self.getUID(), isOverlay, Util.copyArray( arguments ) );\r
2595                 };\r
2596                 this.getUID = function(){\r
2597                         return Util.getIndex( API_USER_LIST, appClass );\r
2598                 };\r
2599                 this.getDisplayName = function(){\r
2600                         return this.displayName;\r
2601                 };\r
2602                 this.boot = function( /* _option */ ){\r
2603                         AsyncCall.add( this, asyncBoot, Util.copyArray( arguments ) );\r
2604                 };\r
2605                 this.shutdown = function(){\r
2606                         if( !application ) return false;\r
2607                         \r
2608                         AsyncCall.add( application, ( isOverlay === true ? Overlay.hide : application.close ) );\r
2609                 };\r
2610         };\r
2611         \r
2612         function asyncBootHome(){\r
2613                 currentApplication === null && Home.boot();\r
2614         };\r
2615         function asyncOpen( /* arguments */ ){\r
2616                 var _arg = Util.copyArray( arguments );\r
2617                 _arg.unshift( winW, winH );\r
2618                 currentApplication.open.apply( currentApplication, _arg );\r
2619         };\r
2620         return {\r
2621                 register: function( _class, _overlay, _tail, _displayName, _id, _thumbnailUrl, _tailColor ){\r
2622                         APPLICATION_LIST.push( _class );\r
2623                         API_USER_LIST.push( _class );\r
2624                         var _ref = new ApplicationReference( _class, _overlay, _displayName, _id, _thumbnailUrl, _tailColor );\r
2625                         _tail === true && Home.add( _ref );\r
2626                         return _ref;\r
2627                 },\r
2628                 isApplicationInstance: function( app ){\r
2629                         return ApplicationPrivateData.get( app ) !== null;\r
2630                 },\r
2631                 isApplicationReference: function( _reference ){\r
2632                         return _reference instanceof ApplicationReference;\r
2633                 },\r
2634                 isCurrentAppplication: function( app ){\r
2635                         return app === currentApplication;\r
2636                 },\r
2637                 boot: function( appClass, displayName, uid, isOverlay, arg ){\r
2638                         if( currentApplication ){\r
2639                                 if( currentApplication.getUID() === uid ) return null;\r
2640                                 if( isOverlay === false && currentApplication.close() === false ) return null;\r
2641                         };\r
2642 \r
2643                         appClass.prototype = new AbstractApplication( appClass, displayName, isOverlay );\r
2644                         \r
2645                         var application = new appClass(),\r
2646                                 data = ApplicationPrivateData.get( application );\r
2647                         \r
2648                         application.rootElement = data.rootElement;\r
2649                         data.application = application;\r
2650                         \r
2651                         coveredApplication = isOverlay === true ? currentApplication : null;\r
2652                         \r
2653                         Application.onCurrentApplicationChange( application );\r
2654                         \r
2655                         if( isOverlay === false ){\r
2656                                 body.style.backgroundColor = application.bgColor;\r
2657                                 \r
2658                                 body.appendChild( data.rootElement );\r
2659                                 data.rootElement.style.display = 'none';\r
2660                                 application.init();\r
2661 \r
2662                                 application.addAsyncCall( asyncOpen, arg );\r
2663                         } else {\r
2664                                 Overlay.show( application, arg );\r
2665                         };\r
2666                         \r
2667                         return application;\r
2668                 },\r
2669                 shutdown: function( _application, isOverlay ){\r
2670                         if( isOverlay === false ){\r
2671                                 currentApplication = null;\r
2672                                 AsyncCall.add( SUPER_USER_KEY, asyncBootHome );\r
2673                         } else {\r
2674                                 Application.onCurrentApplicationChange( coveredApplication );\r
2675                                 coveredApplication = null;\r
2676                         };\r
2677                 },\r
2678                 onCurrentApplicationChange: function( _application ){\r
2679                         if( Application.isApplicationInstance( _application ) === false ) return;\r
2680                         if( currentApplication === _application ) return;\r
2681                         currentApplication = _application;\r
2682                         MouseEvent.onCurrentApplicationChange( _application );\r
2683                         PointingDeviceEventTree.onCurrentApplicationChange( _application );\r
2684                         KeyEvent.updateCurrentListener( _application );\r
2685                         // InteractiveLayer.onCurrentApplicationChange( _application );\r
2686                 },\r
2687                 onApplicationShutdown: function( _application ){\r
2688                         LIVE_APPLICATION_LIST.splice( Util.getIndex(  LIVE_APPLICATION_LIST, _application ) );\r
2689                 },\r
2690                 onWindowResize: function( w, h ){\r
2691                         winW = w;\r
2692                         winH = h;\r
2693                         currentApplication && currentApplication.resize( w, h );\r
2694                         Overlay.onWindowResize( w, h );\r
2695                         UI.onWindowResize( w, h );\r
2696                 },\r
2697                 onSystemShutdown: function(){\r
2698                         \r
2699                 }\r
2700         }\r
2701 })();\r
2702 \r
2703 /* --------------------------------------------------------------\r
2704  * Home\r
2705  * \r
2706  */\r
2707         var Home = ( function(){\r
2708                 var APP_REF_LIST    = [];\r
2709                 var ELM_TAIL_ORIGIN = ( function(){\r
2710                         var ret = document.createElement( 'div' ),\r
2711                                 h2  = document.createElement( 'h2' );\r
2712                         ret.className = 'tail-wrapper';\r
2713                         ret.appendChild( h2 );\r
2714                         h2.appendChild( document.createTextNode( 'appName' ) );\r
2715                         return ret;\r
2716                 })();\r
2717                 \r
2718                 var TailClass = function( appRef ){\r
2719                         this.elm = ELM_TAIL_ORIGIN.cloneNode( true );\r
2720                         this.destroy = function(){\r
2721                                 appRef = self = elmName = null;\r
2722                         };                      \r
2723                         \r
2724                         var self    = this,\r
2725                                 elmName = this.elm.getElementsByTagName( 'h2' )[ 0 ].firstChild;\r
2726                         \r
2727                         this.elm.style.backgroundColor = appRef.tailColor;\r
2728                         elmName.data = appRef.displayName;\r
2729                 };\r
2730                 \r
2731                 var ref = Application.register( function(){\r
2732                         var self     = this,\r
2733                                 winW     = 0,\r
2734                                 winH     = 0,\r
2735                                 tailList = [],\r
2736                                 elmContainer, elmHeader;\r
2737                         \r
2738                         function draw(){\r
2739                                 var tail, elm;\r
2740                                 for( var i=0, l=APP_REF_LIST.length; i<l; ++i ){\r
2741                                         tail = new TailClass( APP_REF_LIST[ i ] );\r
2742                                         tailList.push( tail );\r
2743                                         elm  = tail.elm;\r
2744                                         elmContainer.appendChild( elm );\r
2745                                         self.addEventListener( elm, 'click', onTailClick );\r
2746                                 };\r
2747                         };\r
2748                         \r
2749                         function onTailClick( e ){\r
2750                                 var _children = elmContainer.getElementsByTagName( 'div' );\r
2751                                 for( var i=0, l=_children.length; i<l; ++i ){\r
2752                                         if( this === _children[ i ] ){\r
2753                                                 APP_REF_LIST[ i ].boot();\r
2754                                                 break;\r
2755                                         };\r
2756                                 };\r
2757                         };\r
2758                         \r
2759                         this.bgColor     = '#0F6D39';\r
2760                         this.MIN_WIDTH   = 320;\r
2761                         this.MIN_HEIGHT  = 320;\r
2762                         this.onInit = function(){\r
2763                                 self.rootElement.id = 'home-root';\r
2764                                 \r
2765                                 elmContainer        = document.createElement( 'div' );\r
2766                                 self.rootElement.appendChild( elmContainer );\r
2767                                 elmContainer.id     = 'home-tail-container';\r
2768                                 \r
2769                                 elmHeader           = document.createElement( 'div' );\r
2770                                 self.rootElement.appendChild( elmHeader );\r
2771                                 elmHeader.id        = 'home-header';\r
2772                         };\r
2773                         this.onOpen = function( _w, _h ){\r
2774                                 winW = _w;\r
2775                                 winH = _h;\r
2776                                 draw();\r
2777                         };\r
2778                         this.onPaneResize = function( _w, _h ){\r
2779                                 \r
2780                         };\r
2781                         this.onClose = function(){\r
2782                                 self.removeEventListener();\r
2783                                 while( tailList.length > 0 ){\r
2784                                         tailList.shift().destroy();\r
2785                                 }\r
2786                                 self = tailList = elmContainer = null;\r
2787                         };\r
2788                 }, false, false, 'home', 'home', null );\r
2789                 \r
2790                 return {\r
2791                         add: function( _appRef ){\r
2792                                 if( Application.isApplicationReference( _appRef ) === false ) return;\r
2793                                 Util.getIndex( APP_REF_LIST, _appRef ) === -1 && APP_REF_LIST.push( _appRef );\r
2794                         },\r
2795                         boot: function(){\r
2796                                 ref.boot();\r
2797                         }\r
2798                 }\r
2799         })();\r
2800 \r
2801         var Page = ( function(){\r
2802                 var pageNodes = [],\r
2803                         appClass, ref,\r
2804                         ignoreTagList = [ 'script', 'noscript', 'style' ];\r
2805                 \r
2806                 var MemoryClass = function( node ){\r
2807                         this.node = node;\r
2808                 };\r
2809                 MemoryClass.prototype = {\r
2810                         init: function(){\r
2811                                 var node      = this.node,\r
2812                                         _nodeType = node.nodeType;\r
2813                                 if( _nodeType === 1 && Util.getIndex( ignoreTagList, node.tagName.toLowerCase() ) === -1 ){\r
2814                                         this.type    = _nodeType;\r
2815                                         this.display = node.style.display;\r
2816                                 } else\r
2817                                 if( _nodeType === 3 ){\r
2818                                         if( node.data.replace( /\s/g, '' ).length !== 0 ){\r
2819                                                 this.type    = _nodeType;\r
2820                                                 this.before  = pageNodes.length === 0 ? null : pageNodes[ pageNodes.length - 1 ].node;\r
2821                                         } else {\r
2822                                                 body.removeChild( node );\r
2823                                                 return false;\r
2824                                         }\r
2825                                 } else {\r
2826                                         // body.removeChild( node );\r
2827                                         return false;\r
2828                                 };\r
2829                         },\r
2830                         show: function(){\r
2831                                 if( this.type === 1 ){\r
2832                                         if( this.display ){\r
2833                                                 this.node.style.display = this.display;\r
2834                                         } else {\r
2835                                                 this.node.style.display = '';\r
2836                                         }\r
2837                                 } else {\r
2838                                         if( this.before ){\r
2839                                                 body.insertBefore( this.node, this.before );\r
2840                                         } else {\r
2841                                                 body.appendChild( this.node );\r
2842                                         };\r
2843                                 };\r
2844                         },\r
2845                         hide: function(){\r
2846                                 if( !this.node.parentNode ){\r
2847                                         return;\r
2848                                 };\r
2849                                 if( this.type === 1 ){\r
2850                                         this.node.style.display = 'none';\r
2851                                 } else {\r
2852                                         body.removeChild( this.node );\r
2853                                 };\r
2854                         }\r
2855                 };\r
2856                 \r
2857                 return {\r
2858                         onReady: function(){\r
2859                                 var _children = Util.copyArray( body.childNodes ),\r
2860                                         _mem;\r
2861                                 for( var i = 0, l = _children.length; i<l; ++i ){\r
2862                                         _mem = new MemoryClass( _children[ i ] );\r
2863                                         _mem.init() !== false && pageNodes.push( _mem );\r
2864                                 };\r
2865                                 if( pageNodes.length !== 0 ){\r
2866                                         if( Type.isFunction( gOS.PageApplicationClass ) === true ){\r
2867                                                 Page.appClass = gOS.PageApplicationClass;\r
2868                                                 Page.appClass.bgColor    = Page.appClass.bgColor;\r
2869                                                 Page.appClass.MIN_WIDTH  = Page.appClass.MIN_WIDTH  || 240;\r
2870                                                 Page.appClass.MIN_HEIGHT = Page.appClass.MIN_HEIGHT || 240;\r
2871                                         } else {\r
2872                                                 Page.appClass = function(){\r
2873                                                         var self     = this;\r
2874                                                         \r
2875                                                         this.bgColor      = '#ffffff';\r
2876                                                         this.MIN_WIDTH    = 200;\r
2877                                                         this.MIN_HEIGHT   = 200;\r
2878                                                         this.onInit       = function(){};\r
2879                                                         this.onOpen       = function( _w, _h ){\r
2880                                                                 KeyEvent.add( self, Const.KEY.EVENT.KEY_DOWN, ref.shutdown, 27 ); // 27.esc\r
2881                                                         };\r
2882                                                         this.onPaneResize = function( _w, _h ){};\r
2883                                                         this.onClose      = function(){};\r
2884                                                 };\r
2885                                         };\r
2886                                         ref = Application.register( Page.appClass, false, true, document.title, 'page', null, Page.appClass.tailColor || '#999999' );\r
2887                                         if( Type.isFunction( gOS.PageApplicationClass ) === true ){\r
2888                                                 gOS.PageApplicationRef = ref;\r
2889                                         }; \r
2890                                 };\r
2891                                 delete Page.onReady;\r
2892                         },\r
2893                         show: function(){\r
2894                                 for( var i = pageNodes.length; i; ){\r
2895                                         pageNodes[ --i ].show();\r
2896                                 };\r
2897                         },\r
2898                         hide: function(){\r
2899                                 for( var i = pageNodes.length; i; ){\r
2900                                         pageNodes[ --i ].hide();\r
2901                                 };                              \r
2902                         },\r
2903                         boot: function(){\r
2904                                 ref && ref.boot();\r
2905                         },\r
2906                         registered: function(){\r
2907                                 return !!ref;\r
2908                         },\r
2909                         appClass: null\r
2910                 }\r
2911         })();\r
2912 \r
2913 /* --------------------------------------------------------------\r
2914  * Event\r
2915  * \r
2916  *  screenX\r
2917  *  スクリーン座標は、コンピュータのディスプレイの左上を原点とする座標系である。screenX, screenY属性で取得できる。Javascritpでは、同名のプロパティとして実装されている。\r
2918  *  しかし、これは、現実的には、何の役に立たない。ブラウザ自体がディスプレイのどの位置にいるのかがわからないので、画面上の位置を知ったところで、何にもならないからだ。 \r
2919  * \r
2920  *  clientX\r
2921  *  ウインドウ座標とは、現在のブラウザのウインドウの、ドキュメントを表示している部分の左上原点とした座標である。\r
2922  *  問題は、ウインドウは、必ずしもドキュメント全体を表示するとは限らない。スクロールと呼ばれるUIによって、ドキュメントの一部だけを表示しているかもしれない。\r
2923  */\r
2924         var XBrowserEvent = ( function(){\r
2925                 var wrappedHandlerClass,\r
2926                         wrappedEventClass,\r
2927                         tmp;\r
2928                 \r
2929                 if( window.addEventListener ){\r
2930                         wrappedHandlerClass = function( ticket ){\r
2931                                 this.handler = function( e ){\r
2932                                         if( ticket.fire( e ) !== false ) return;\r
2933                                         e.preventDefault();\r
2934                                         e.stopPropagation();\r
2935                                         return false;\r
2936                                 };\r
2937                                 this.destroy = function(){\r
2938                                         ticket = null;\r
2939                                         delete this.handler;\r
2940                                         delete this.destroy;\r
2941                                 };\r
2942                         };\r
2943                 } else {\r
2944                         wrappedEventClass = function( e, element ){\r
2945                                 this._event        = e;\r
2946                                 this.type          = e.type;\r
2947                                 this.target        = e.srcElement;\r
2948                                 this.currentTarget = element;\r
2949                                 this.relatedTarget = e.formElement ? e.formElement : e.toElement;\r
2950                                 this.eventPhase    = e.srcElement === element ? 2: 3;\r
2951                                 \r
2952                                 this.clientX       = e.clientX;\r
2953                                 this.clientY       = e.clientY;\r
2954                                 this.screenX       = e.screenX;\r
2955                                 this.screenY       = e.screenY;\r
2956                                 \r
2957                                 this.keyCode       = e.keyCode;\r
2958                                 this.altKey        = e.altKey;\r
2959                                 this.ctrlKey       = e.ctrlKey;\r
2960                                 this.shiftKey      = e.shiftKey;\r
2961                                 \r
2962                                 this.wheelDelta    = e.wheelDelta;\r
2963                         };\r
2964                         wrappedEventClass.prototype.stopPropagation = function(){\r
2965                                 this._event.cancelBubble = true;\r
2966                         };\r
2967                         wrappedEventClass.prototype.preventDefault  = function(){\r
2968                                 this._event.returnValue = false;\r
2969                         };\r
2970 \r
2971                         if( document.attachEvent ){\r
2972                                 wrappedHandlerClass = function( ticket ){\r
2973                                         this.handler = function(){\r
2974                                                 if( ticket === null ) alert( window.event.type )\r
2975                                                 if( ticket.fire( new wrappedEventClass( window.event, ticket.element ) ) !== false ) return;\r
2976                                                 // e.preventDefault();\r
2977                                                 // e.stopPropagation();\r
2978                                                 window.event.cancelBubble = true;\r
2979                                                 window.event.returnValue  = false;\r
2980                                                 return false;\r
2981                                         };\r
2982                                         this.destroy = function(){\r
2983                                                 ticket = null;\r
2984                                                 delete this.handler;\r
2985                                                 delete this.destroy;\r
2986                                         };\r
2987                                 };\r
2988                         } else {\r
2989                                 tmp = {\r
2990                                         list: [],\r
2991                                         find: function( _ticket ){\r
2992                                                 for( var i=0, l= tmp.list.length, _item; i<l; ++i ){\r
2993                                                         _item = tmp.list[ i ];\r
2994                                                         if( _item.element === _ticket.element && _item.eventType === _ticket.eventType ){\r
2995                                                                 return _item;\r
2996                                                         };\r
2997                                                 };\r
2998                                                 return null;\r
2999                                         }\r
3000                                 };\r
3001                                 tmp.TicketClass = function( _ticket ){\r
3002                                         var self = this;\r
3003                                         this.element   = _ticket.element;\r
3004                                         this.eventType = _ticket.eventType;\r
3005                                         this.tickets   = [ _ticket ];\r
3006                                         this.onDestroy = function(){ self = null; };\r
3007                                         \r
3008                                         this.element[ 'on' + this.eventType ] = function( e ){ return self.fire( e );};\r
3009                                         _ticket = null;\r
3010                                 };\r
3011                                 tmp.TicketClass.prototype = {\r
3012                                         add: function( _ticket ){\r
3013                                                 Util.getIndex( this.tickets, ticket ) === -1 && this.tickets.push( _ticket );\r
3014                                         },\r
3015                                         remove: function( _ticket ){\r
3016                                                 var i = Util.getIndex( this.tickets, _ticket );\r
3017                                                 i !== -1 && this.tickets.splice( i, 1 );\r
3018                                                 this.tickets.length === 0 && this.destroy();\r
3019                                         },\r
3020                                         fire: function( e ){\r
3021                                                 e = e || new wrappedEventClass( window.event, this.element );\r
3022                                                 var i = this.tickets.length,\r
3023                                                         cancel;\r
3024                                                 for( ; i; ){\r
3025                                                         if( this.tickets[ --i ].fire( e ) === false ) cancel = false;\r
3026                                                 };\r
3027                                                 return cancel;\r
3028                                         },\r
3029                                         destroy: function(){\r
3030                                                 this.onDestroy();\r
3031                                                 this.element[ 'on' + this.eventType ] = '';\r
3032                                                 tmp.list.splice( Util.getIndex( tmp.list, this ), 1 );\r
3033                                                 delete this.element;\r
3034                                                 delete this.eventType;\r
3035                                                 delete this.tickets;\r
3036                                                 delete this.onDestroy;\r
3037                                         }\r
3038                                 };\r
3039                         };\r
3040                 };\r
3041 \r
3042                 return {\r
3043                         add: function( _ticket ){\r
3044                                 if( document.addEventListener ){\r
3045                                         XBrowserEvent.add = function( _ticket ){\r
3046                                                 _ticket.wrappedHandler = new wrappedHandlerClass( _ticket );\r
3047                                                 _ticket.element.addEventListener( _ticket.eventType, _ticket.wrappedHandler.handler, false );\r
3048                                         };\r
3049                                 } else\r
3050                                 if( document.attachEvent ){\r
3051                                         XBrowserEvent.add = function( _ticket ){\r
3052                                                 _ticket.wrappedHandler = new wrappedHandlerClass( _ticket );\r
3053                                                 _ticket.element.attachEvent( 'on' + _ticket.eventType, _ticket.wrappedHandler.handler );\r
3054                                         };\r
3055                                 } else {\r
3056                                         XBrowserEvent.add = function( _ticket ){\r
3057                                                 var t = tmp.find( _ticket );\r
3058                                                 if( t !== null ){\r
3059                                                         t.add( _ticket );\r
3060                                                 } else {\r
3061                                                         tmp.list.push( new tmp.TicketClass( _ticket ) );\r
3062                                                 };\r
3063                                         };\r
3064                                 };\r
3065                                 \r
3066                                 XBrowserEvent.add( _ticket );\r
3067                         },\r
3068                         remove: function( _ticket ){\r
3069                                 if( document.removeEventListener ){\r
3070                                         XBrowserEvent.remove = function( _ticket ){\r
3071                                                 _ticket.element.removeEventListener( _ticket.eventType, _ticket.wrappedHandler.handler, false );\r
3072                                                 _ticket.wrappedHandler.destroy();\r
3073                                         };\r
3074                                 } else\r
3075                                 if( document.detachEvent ){\r
3076                                         XBrowserEvent.remove = function( _ticket ){\r
3077                                                 _ticket.element.detachEvent( 'on' + _ticket.eventType, _ticket.wrappedHandler.handler );\r
3078                                                 _ticket.wrappedHandler.destroy();\r
3079                                         };\r
3080                                 } else {\r
3081                                         XBrowserEvent.remove = function( _ticket ){\r
3082                                                 var t = tmp.find( _ticket );\r
3083                                                 if( t !== null ){\r
3084                                                         t.remove( _ticket );\r
3085                                                 };\r
3086                                         };\r
3087                                 };\r
3088                                 \r
3089                                 XBrowserEvent.remove( _ticket );\r
3090                         }\r
3091                 }\r
3092         })();\r
3093 \r
3094 /*\r
3095  * EventTicketClass\r
3096  */\r
3097         var EventTicketClass = function( _element, _eventType, _handler, opt_thisObject ){\r
3098                 this.element        = _element;\r
3099                 this.eventType      = _eventType;\r
3100                 this.handler        = _handler;\r
3101                 this.wrappedHandler = null;\r
3102                 this.thisObject     = opt_thisObject;\r
3103                 XBrowserEvent.add( this );\r
3104         };\r
3105         EventTicketClass.prototype = {\r
3106                 fire : ( function(){\r
3107                         if( Function.prototype.call ){\r
3108                                 return function( e ){\r
3109                                         return this.handler.call( this.thisObject || this.element, e );\r
3110                                 };                              \r
3111                         };\r
3112                         return function( e ){\r
3113                                 var thisObj = this.thisObject || this.element,\r
3114                                         ret;\r
3115                                 thisObj._currentHandler = this.handler;\r
3116                                 ret = thisObj._currentHandler( e );\r
3117                                 delete thisObj._currentHandler;\r
3118                                 return ret;                                     \r
3119                         };\r
3120                 })(),\r
3121                 match: function( _element, _eventType, _handler ){\r
3122                         if( _handler   && _handler   !== this.handler )   return false;\r
3123                         if( _eventType && _eventType !== this.eventType ) return false;\r
3124                         if( _element   && _element   !== this.element )   return false;\r
3125                         \r
3126                         return true;\r
3127                 },\r
3128                 destroy: function( _element, _eventType, _handler ){\r
3129                         if( this.match( _element, _eventType, _handler ) === false ) return false;\r
3130                         \r
3131                         XBrowserEvent.remove( this );\r
3132                         \r
3133                         delete this.element;\r
3134                         delete this.eventType;\r
3135                         delete this.handler;\r
3136                         delete this.wrappedHandler;\r
3137                         delete this.thisObject;\r
3138                         return true;\r
3139                 }\r
3140         };\r
3141 \r
3142 var ReadyEvent = ( function(){\r
3143         var ticketReady,\r
3144                 ticketLoad,\r
3145         timer;\r
3146 \r
3147         function webkitDetect(){\r
3148                 var state = document.readyState;\r
3149                 if( state === 'loaded' || state === 'complete' ){\r
3150                         SystemTimer.remove( SUPER_USER_KEY, webkitDetect );\r
3151                         timer = null;\r
3152                         onReady();\r
3153                 };\r
3154         };\r
3155         function ieDetect(){\r
3156                 if( this.readyState === 'complete' ){ // this.readyState === 'loaded' || \r
3157                         this.onreadystatechange = new Function();\r
3158                         this.onreadystatechange = null;\r
3159                         AsyncCall.remove( SUPER_USER_KEY, ieScroll );\r
3160                         onReady();\r
3161                 };\r
3162         };\r
3163         function ieScroll(){\r
3164                 try {\r
3165                         document.documentElement.doScroll( 'left' );\r
3166                 } catch( e ){\r
3167                         AsyncCall.add( SUPER_USER_KEY, ieScroll );\r
3168                         return;\r
3169                 };\r
3170                 // no errors, fire\r
3171                 document.onreadystatechange = new Function();\r
3172                 document.onreadystatechange = null;\r
3173                 onReady();              \r
3174         };\r
3175                 \r
3176         function onReady(){\r
3177                 ticketReady && ticketReady.destroy();\r
3178                 ticketLoad  && ticketLoad.destroy();\r
3179                 ticketReady = ticketLoad = null;\r
3180                 Page.onReady();\r
3181                 if( Page.registered() === true ){\r
3182                         Page.boot();\r
3183                 } else {\r
3184                         Home.boot();\r
3185                 };\r
3186         };\r
3187         \r
3188         // Apple WebKit (Safari, OmniWeb, ...)\r
3189         if( document.readyState && !!UA.WEBKIT ){\r
3190                 SystemTimer.add( SUPER_USER_KEY, webkitDetect, 50 );\r
3191         /* } else\r
3192                 if( document.readyState && UA.isIE && UA.ieVersion < 9 ){\r
3193                 ieScroll();\r
3194                 document.onreadystatechange = ieDetect; */\r
3195         } else {\r
3196                 ticketReady = new EventTicketClass( document, 'DOMContentLoaded', onReady );\r
3197                 ticketLoad  = new EventTicketClass( window, 'load', onReady );\r
3198         };\r
3199 })();\r
3200 \r
3201 \r
3202 \r
3203 \r
3204 /* =====================================================\r
3205  *  ResizeEvent\r
3206  * \r
3207  */\r
3208 \r
3209 var ResizeEvent = ( function(){\r
3210         var _globalLock = 0;\r
3211         var _resize;\r
3212         var root = window;\r
3213         var w = 0, h = 0;\r
3214         \r
3215         function getInnerSize(){\r
3216                 return {\r
3217                         w : root.innerWidth || root.clientWidth,\r
3218                         h : root.innerHeight || root.clientHeight\r
3219                 };\r
3220         }\r
3221         function unlock(){\r
3222                 _globalLock = 0;\r
3223         }\r
3224         \r
3225         if( document.uniqueID ){\r
3226                 _resize = function(){\r
3227                         root = (document.compatMode || "") !== "CSS1Compat" ? document.body : document.documentElement;\r
3228 \r
3229                         // resize agent\r
3230                         function loop(){\r
3231                                 if( !_globalLock++ ){\r
3232                                         var size = getInnerSize();\r
3233                                         if( w !== size.w || h !== size.h ){// resized\r
3234                                                 w = size.w;\r
3235                                                 h = size.h;\r
3236                                                 // update\r
3237                                                 Application.onWindowResize( w, h );\r
3238                                         }\r
3239                                         window.setTimeout( unlock, 0 );\r
3240                                         // delay unlock\r
3241                                 }\r
3242                                 window.setTimeout( loop, 100 );\r
3243                         }\r
3244                         loop();\r
3245                 };\r
3246         } else {\r
3247                 _resize = function(){\r
3248                         new EventTicketClass( window, 'resize', onResize );\r
3249                         \r
3250                         function onResize(){\r
3251                                 if( !_globalLock++ ) {\r
3252                                         var size = getInnerSize();\r
3253                                         if( w !== size.w || h !== size.h ){// resized\r
3254                                                 w = size.w;\r
3255                                                 h = size.h;\r
3256                                                 // update\r
3257                                                 Application.onWindowResize( w, h );\r
3258                                         }\r
3259                                         window.setTimeout( unlock, 0 );\r
3260                                 }\r
3261                         }\r
3262                         onResize();\r
3263                 };\r
3264         }\r
3265         AsyncCall.add( SUPER_USER_KEY, _resize );\r
3266         \r
3267         return {\r
3268                 getSize: getInnerSize,\r
3269                 onSystemShutdown: function(){\r
3270                         \r
3271                 }\r
3272         }\r
3273 })();\r
3274 \r
3275 \r
3276 /* =====================================================\r
3277  *  MouseEvent\r
3278  * \r
3279  */\r
3280         var MouseEvent = ( function(){\r
3281                 var CLICK_OFFSET   = 2 * 2,\r
3282                         DRAG_OFFSET    = 4 * 4;         \r
3283                 \r
3284                 var EVENT_LIST_MAP = [],\r
3285                         TMP = {},\r
3286                         currentEventList;\r
3287         /*-------------------------------------\r
3288          * ClickHelper\r
3289          * mousedown, mouseup, の移動距離を調べて clickハンドラ を呼ぶ\r
3290          */\r
3291                 var ClickEventTicketClass = function( element, clickhandler, opt_thisObject ){\r
3292                         this.mousedownTicket = new EventTicketClass( element, 'mousedown', this.mousedownHandler, this );\r
3293                         this.element         = element;\r
3294                         this.handler         = clickhandler;\r
3295                         this.thisObject      = opt_thisObject;\r
3296                 };\r
3297                 ClickEventTicketClass.prototype = {\r
3298                         element          : null,\r
3299                         handler          : null,\r
3300                         thisObject       : null,\r
3301                         startX           : 0,\r
3302                         startY           : 0,\r
3303                         mousedownTicket  : null,\r
3304                         mousemoveTicket  : null,\r
3305                         mouseupTicket    : null,\r
3306                         mouseoutTicket   : null,\r
3307                         eventType        : 'click',\r
3308                         fire             : EventTicketClass.prototype.fire,\r
3309                         match            : EventTicketClass.prototype.match,\r
3310                         mousedownHandler : function( e ){\r
3311                                 this.startX = e.clientX;\r
3312                                 this.startY = e.clientY;\r
3313                                 \r
3314                                 this.mousemoveTicket = new EventTicketClass( this.element, 'mousemove', this.mousemoveHandler, this );\r
3315                                 this.mouseupTicket   = new EventTicketClass( this.element, 'mouseup',   this.mouseupHandler,   this );\r
3316                                 this.mouseoutTicket  = new EventTicketClass( this.element, 'mouseout',  this.mouseoutHandler,  this );\r
3317                                 return false;                   \r
3318                         },\r
3319                         mousemoveHandler : function( e ){\r
3320                                 var offsetX = e.clientX - this.startX,\r
3321                                         offsetY = e.clientY - this.startY;                              \r
3322                                 offsetX * offsetX + offsetY * offsetY >= CLICK_OFFSET && this.mouseoutHandler();\r
3323                                 return false;\r
3324                         },\r
3325                         mouseupHandler : function( e ){\r
3326                                 this.mouseoutHandler();\r
3327                                 return this.fire( ClickEventTicketClass.createEvent( e ) );\r
3328                         },\r
3329                         mouseoutHandler : function( e ){\r
3330                                 this.mousemoveTicket && this.mousemoveTicket.destroy();\r
3331                                 this.mouseupTicket   && this.mouseupTicket.destroy();\r
3332                                 this.mouseoutTicket  && this.mouseoutTicket.destroy();\r
3333                                 if( this.mousemoveTicket ) delete this.mousemoveTicket;\r
3334                                 if( this.mouseupTicket  )  delete this.mouseupTicket;\r
3335                                 if( this.mouseoutTicket )  delete this.mouseoutTicket;\r
3336                                 return false;\r
3337                         },\r
3338                         destroy : function( _element, _eventType, _handler ){\r
3339                                 if( this.match( _element, _eventType, _handler ) === false ) return false;\r
3340                                 \r
3341                                 this.mouseoutHandler();\r
3342                                 this.mousedownTicket.destroy();\r
3343 \r
3344                                 delete this.element;\r
3345                                 delete this.handler;\r
3346                                 delete this.thisObject;\r
3347                                 delete this.mousedownTicket;    \r
3348                                 return true;\r
3349                         }\r
3350                 };\r
3351                 if( document.createEvent ){\r
3352                         ClickEventTicketClass.createEvent = function( e ){\r
3353                                 var _e = document.createEvent( 'MouseEvents' );\r
3354                                 _e.initMouseEvent(\r
3355                                         'click' , false, true, e.view, \r
3356                                         e.detail, e.screenX, e.screenY, e.clientX, e.clientY, \r
3357                                         e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, \r
3358                                         e.button, e.relatedTarget\r
3359                                 );\r
3360                                 return _e;\r
3361                         };                                      \r
3362                 } else\r
3363                 if( document.attachEvent ){\r
3364                         ClickEventTicketClass.createEvent = function( e ){\r
3365                                 e.type = 'click';\r
3366                                 return e;\r
3367                         };\r
3368                 } else {\r
3369                         \r
3370                 };\r
3371                 \r
3372         /*-------------------------------------\r
3373          *  WheelHelper\r
3374          */\r
3375                 var WheelEventTicketClass = ( function(){\r
3376                         if( UA.GECKO ){\r
3377                                 return function( element, wheelhandler, opt_thisObject ){\r
3378                                         this.wheelTicket = new EventTicketClass( element, 'DOMMouseScroll', this.onGeckoWheel, this );\r
3379                                         this.element     = element;\r
3380                                         this.handler     = wheelhandler;\r
3381                                         this.thisObject  = opt_thisObject;\r
3382                                 };\r
3383                         } else\r
3384                         if( true || UA.isIE ){\r
3385                                 return function( element, wheelhandler, opt_thisObject ){\r
3386                                         this.wheelTicket = new EventTicketClass( element, this.eventType, wheelhandler );\r
3387                                         this.element     = element;\r
3388                                         this.handler     = wheelhandler;\r
3389                                         this.thisObject  = opt_thisObject;\r
3390                                 };\r
3391                         } else {\r
3392                                 TMP.wheelHandlerList = [];\r
3393                                 TMP.wheelThisObjList = [];\r
3394                                 //TMP.wheelLegacy = undefined;\r
3395                                 TMP.onWheel   = function( e ){\r
3396                                         e = e || window.event;\r
3397                                         var cancel = true,\r
3398                                                 f = TMP.wheelLegacy, i;\r
3399                                         if( f ) cancel = f.call( this, e );\r
3400                                         \r
3401                                         for( i = TMP.wheelHandlerList.length; i; ){\r
3402                                                 if( TMP.wheelHandlerList[ --i ].call( TMP.wheelThisObjList[ i ] || this, e ) === false ) cancel = false;\r
3403                                         };\r
3404                                         return cancel;\r
3405                                 };\r
3406                                 return function( element, wheelhandler, opt_thisObject ){\r
3407                                         this.element     = element;\r
3408                                         this.handler     = wheelhandler;\r
3409                                         this.thisObject  = opt_thisObject;\r
3410                                         \r
3411                                         if( TMP.wheelHandlerList.length === 0 ){\r
3412                                                 //TMP.wheelLegacy     = Type.isFunction( window.onmousewheel ) === true ? window.onmousewheel : undefined;\r
3413                                                 element.onmousewheel = TMP.onWheel;\r
3414                                         };\r
3415                                         TMP.wheelHandlerList.push( wheelhandler );\r
3416                                         TMP.wheelThisObjList.push( opt_thisObject )\r
3417                                 };\r
3418                         };\r
3419                 })();\r
3420                 WheelEventTicketClass.prototype = {\r
3421                         eventType : 'mousewheel',\r
3422                         match     : EventTicketClass.prototype.match,\r
3423                         destroy   : function( _element, _eventType, _handler ){\r
3424                                 if( this.match( _element, _eventType, _handler ) === false ) return false;\r
3425                                 \r
3426                                 this.wheelTicket && this.wheelTicket.destroy();\r
3427                                 \r
3428                                 delete this.wheelTicket;\r
3429                                 delete this.element;\r
3430                                 delete this.handler;\r
3431                                 delete this.thisObject;\r
3432                                 \r
3433                                 this.onDestroy && this.onDestroy();\r
3434                                 return true;\r
3435                         }\r
3436                 };\r
3437                 if( UA.GECKO ){\r
3438                         WheelEventTicketClass.prototype.onGeckoWheel = function( e ){\r
3439                                 var _e = document.createEvent( 'MouseEvents' );\r
3440                                 _e.initMouseEvent(\r
3441                                         'mousewheel' , false, true, e.view, \r
3442                                         e.detail, e.screenX, e.screenY, e.clientX, e.clientY, \r
3443                                         e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, \r
3444                                         e.button, e.relatedTarget\r
3445                                 );\r
3446                                 _e.wheelDelta = e.detail * -40;\r
3447                                 return this.handler.call( this.thisObject || this.element, _e );\r
3448                         };\r
3449                 } else\r
3450                 if( true || UA.isIE ){\r
3451 \r
3452                 } else {\r
3453                         WheelEventTicketClass.prototype.onDestroy = function(){\r
3454                                 TMP.wheelHandlerList.splice( Util.getIndex( TMP.wheelHandlerList, this.handler ), 1 );\r
3455                                 TMP.wheelThisObjList.splice( Util.getIndex( TMP.wheelThisObjList, this.handler ), 1 );\r
3456                                 if( TMP.wheelHandlerList.length === 0 ) this.element.onmousewheel = '';\r
3457                         };                      \r
3458                 };\r
3459                 \r
3460         /*-------------------------------------\r
3461          *  DragHelper\r
3462          */\r
3463                 var DragEventTicketClass = function( element, draghandler, opt_thisObject ){\r
3464                         this.mousedownTicket = new EventTicketClass( element, 'mousedown', this.mousedownHandler, this );\r
3465                         this.element         = element;\r
3466                         this.handler         = draghandler;\r
3467                         this.thisObject      = opt_thisObject;\r
3468                 };\r
3469                 DragEventTicketClass.prototype = {\r
3470                         element         : null,\r
3471                         handler         : null,\r
3472                         thisObject      : null,\r
3473                         startX          : 0,\r
3474                         startY          : 0,\r
3475                         dragging        : false,\r
3476                         mousedownTicket : null,\r
3477                         mousemoveTicket : null,\r
3478                         mouseupTicket   : null,\r
3479                         mouseoutTicket  : null,\r
3480                         eventType       : 'mousedrag',\r
3481                         fire            : EventTicketClass.prototype.fire,\r
3482                         match           : EventTicketClass.prototype.match,\r
3483                         mousedownHandler: function( e ){\r
3484                                 this.startX = e.clientX;\r
3485                                 this.startY = e.clientY;\r
3486                                 \r
3487                                 this.mousemoveTicket = new EventTicketClass( this.element, 'mousemove', this.dragMoveHandler, this );\r
3488                                 this.mouseupTicket   = new EventTicketClass( this.element, 'mouseup',   this.dragEndHandler,  this );\r
3489                                 this.mouseoutTicket  = new EventTicketClass( this.element, 'mouseout',  this.dragEndHandler,  this );                                   \r
3490                         \r
3491                                 return false;\r
3492                         },\r
3493                         dragMoveHandler : function( e ){\r
3494                                 var offsetX = e.clientX - this.startX,\r
3495                                         offsetY = e.clientY - this.startY;\r
3496                                 if( this.dragging === false ){\r
3497                                         if( offsetX * offsetX + offsetY * offsetY < DRAG_OFFSET ) return;\r
3498                                         console.log( 'Drag start' );\r
3499                                         // dragStart\r
3500                                         this.dragging = true;\r
3501                                         return this.fire( DragEventTicketClass.createEvent( e, offsetX, offsetY, 0 ) );\r
3502                                 };\r
3503                                 return this.fire( DragEventTicketClass.createEvent( e, offsetX, offsetY, 1 ) );\r
3504                         },\r
3505                         dragEndHandler  : function( e ){\r
3506                                 if( this.dragging === true ){\r
3507                                         console.log( 'Drag End ' + e.type );\r
3508                                         this.removeEvents();\r
3509                                         // dragEnd\r
3510                                         return this.fire( DragEventTicketClass.createEvent( e, e.clientX - this.startX, e.clientY - this.startY, 2 ) );\r
3511                                 };\r
3512                                 this.removeEvents();\r
3513                                 return false;\r
3514                         },\r
3515                         removeEvents : function(){\r
3516                                 this.dragging = false;\r
3517                                 if( this.mousemoveTicket ){\r
3518                                         this.mousemoveTicket.destroy();\r
3519                                         delete this.mousemoveTicket;\r
3520                                 };\r
3521                                 if( this.mouseupTicket ){\r
3522                                         this.mouseupTicket.destroy();\r
3523                                         delete this.mouseupTicket;\r
3524                                 };\r
3525                                 if( this.mouseoutTicke ){\r
3526                                         this.mouseoutTicket.destroy();\r
3527                                         delete this.mouseoutTicket;\r
3528                                 };                              \r
3529                         },\r
3530                         destroy : function( _element, _eventType, _handler ){\r
3531                                 if( this.match( _element, _eventType, _handler ) === false ) return false;\r
3532                                 \r
3533                                 this.removeEvents();\r
3534                                 this.mousedownTicket.destroy();\r
3535 \r
3536                                 delete this.element;\r
3537                                 delete this.handler;\r
3538                                 delete this.thisObject;\r
3539                                 delete this.mousedownTicket;    \r
3540                                 return true;\r
3541                         }\r
3542                 };\r
3543                 if( document.createEvent ){\r
3544                         DragEventTicketClass.createEvent = function( e, offsetX, offsetY, dragPhase ){\r
3545                                 var _e = document.createEvent( 'MouseEvents' );\r
3546                                 _e.initMouseEvent(\r
3547                                         DragEventTicketClass.prototype.eventType , false, true, e.view, \r
3548                                         e.detail, e.screenX, e.screenY, e.clientX, e.clientY, \r
3549                                         e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, \r
3550                                         e.button, e.relatedTarget\r
3551                                 );\r
3552                                 _e.dragPhase   = dragPhase;\r
3553                                 _e.dragOffsetX = offsetX;\r
3554                                 _e.dragOffsetY = offsetY;\r
3555                                 return _e;\r
3556                         };                                      \r
3557                 } else\r
3558                 if( document.attachEvent ){\r
3559                         DragEventTicketClass.createEvent = function( e, offsetX, offsetY, dragPhase ){\r
3560                                 e.type        = DragEventTicketClass.prototype.eventType;\r
3561                                 e.dragPhase   = dragPhase;\r
3562                                 e.dragOffsetX = offsetX;\r
3563                                 e.dragOffsetY = offsetY;\r
3564                                 return e;\r
3565                         };\r
3566                 } else {\r
3567                         \r
3568                 };\r
3569 \r
3570                 return {\r
3571                         add: function( _apiuser, _element, _eventType, _handler, opt_thisObject ){\r
3572                                 if( isApiUser( _apiuser ) === true &&\r
3573                                         ( Type.isHTMLElement( _element ) === true || _element === window || _element === document ) &&\r
3574                                         Type.isString( _eventType ) === true &&\r
3575                                         Type.isFunction( _handler ) === true\r
3576                                 ){\r
3577                                         var _uid    = _apiuser.getUID(),\r
3578                                                 _events = EVENT_LIST_MAP[ _uid ];\r
3579                                         if( Type.isArray( _events ) === false ){\r
3580                                                 _events = EVENT_LIST_MAP[ _uid ] = [];\r
3581                                         } else {\r
3582                                                 // 2重登録の禁止\r
3583                                                 for( var i=0, l=_events.length; i<l; ++i ){\r
3584                                                         if( _events[ i ].match( _element, _eventType, _handler ) === true ) return;\r
3585                                                 };\r
3586                                         };\r
3587                                         switch( _eventType ){\r
3588                                                 case 'click':\r
3589                                                         _events.push( new ClickEventTicketClass( _element, _handler, opt_thisObject ) );\r
3590                                                         break;\r
3591                                                 case 'mousewheel':\r
3592                                                         _events.push( new WheelEventTicketClass( _element, _handler, opt_thisObject ) );\r
3593                                                         break;\r
3594                                                 case 'mousedrag':\r
3595                                                         _events.push( new DragEventTicketClass( _element, _handler, opt_thisObject ) );\r
3596                                                         break;\r
3597                                                 default:\r
3598                                                         _events.push( new EventTicketClass( _element, _eventType, _handler, opt_thisObject ) );\r
3599                                         };\r
3600                                 };\r
3601                         },\r
3602                         remove: function( apiuser, element, eventType, handler ){\r
3603                                 if( isApiUser( apiuser ) === true ){\r
3604                                         var uid  = apiuser.getUID(),\r
3605                                                 list = EVENT_LIST_MAP[ uid ],\r
3606                                                 i    = 0;\r
3607                                         if( Type.isArray( list ) === false ) return;\r
3608                                         for( ;i < list.length; ){\r
3609                                                 if( list[ i ].destroy( element, eventType, handler ) === true ){\r
3610                                                         list.splice( i, 1 );\r
3611                                                 } else {\r
3612                                                         ++i;\r
3613                                                 };\r
3614                                         };\r
3615                                         if( list.length === 0 ){\r
3616                                                 EVENT_LIST_MAP[ uid ] = null;\r
3617                                         };\r
3618                                 };\r
3619                         },\r
3620                         onCurrentApplicationChange: function(){\r
3621                                 \r
3622                         },\r
3623                         onApplicationShutdown: function(){\r
3624                                 \r
3625                         },\r
3626                         onSystemShutdown: function(){\r
3627                                 \r
3628                         }\r
3629                 }\r
3630         })();\r
3631 \r
3632 /* ----------------------------------------\r
3633  * KEY\r
3634  * \r
3635  *  - EDITABLE_TEXT_CONTROL\r
3636  * \r
3637  *    .SHIFT_DOWN_EVENT:        'shiftDown',\r
3638  *    .SHIFT_UP_EVENT:          'shiftUp',\r
3639  *    .CTRL_DOWN_EVENT:         'ctrlDown',\r
3640  *    .CTRL_UP_EVENT:           'ctrlUp',\r
3641  *    .SPACE_DOWN_EVENT:        'spaceDown',\r
3642  *    .SPACE_UP_EVENT:          'spaceUp',\r
3643  *    .init:                            function,\r
3644  *    .addKeyDownEvent:         function,\r
3645  *    .keyEventDispatcher:      function,\r
3646  * \r
3647  * ショートカットキーの監視とテキスト入力(input, textarea)、チェックボックスを管理する。\r
3648  * キー入力はdocumentで受けて、テキスト編集中(input, textarea)はそちらにキーイベント流す。\r
3649  * \r
3650  */\r
3651 var KeyEvent = ( function(){\r
3652         var EVENT_LIST_MAP = [],\r
3653                 LOCK_UP        = [],\r
3654                 LOCK_DOWN      = [],\r
3655                 application    = null,\r
3656                 currentList    = null;\r
3657 \r
3658         window.focus();\r
3659         \r
3660         var focusTicket    = null,\r
3661                 keydownTicket  = null,\r
3662                 keyupTicket    = null,\r
3663                 keyPress       = null,\r
3664                 keypressTicket = null;\r
3665         \r
3666         function unlock( lock, key ){\r
3667                 lock.splice( Util.getIndex( lock, key ), 1 );\r
3668         };\r
3669         \r
3670         function onKeyChange( e ){\r
3671                 var cancel         = false,\r
3672                         type           = e.type,\r
3673                         key            = e.keyCode, // || e.which,\r
3674                         shift          = Type.isBoolean( e.shiftKey ) === true ? e.shiftKey : ( e.modifiers & Event.SHIFT_MASK ),\r
3675                         ctrl           = Type.isBoolean( e.ctrlKey  ) === true ? e.ctrlKey  : ( e.modifiers & Event.CONTROL_MASK ),\r
3676                         lock           = type === 'keyup' ? LOCK_UP : LOCK_DOWN,\r
3677                         i, t;\r
3678                         \r
3679                 // block chattering\r
3680                 if( Util.getIndex( lock, key ) !== -1 ) return;\r
3681                 lock.push( key );\r
3682                 AsyncCall.add( SUPER_USER_KEY, unlock, [ lock, key ] );\r
3683                 \r
3684                 if( key === 16 || shift === true ){\r
3685                         KeyEvent.shiftEnabled = type !== 'keyup';\r
3686                 };\r
3687                 if( key === 17 || ctrl === true ){\r
3688                         KeyEvent.ctrlEnabled  = type !== 'keyup';\r
3689                 };\r
3690                 for( i = currentList.length; i; ){\r
3691                         t = currentList[ --i ];\r
3692                         if( Type.isFunction( t[ type ] ) === true && t.keyCode === key && ( t.shift === undefined || t.shift === shift ) && ( t.ctrl === undefined || t.ctrl === ctrl )){\r
3693                                 if( t[ type ].call( t.apiuser, e ) === false ){\r
3694                                         cancel = true;\r
3695                                         break;\r
3696                                 };\r
3697                         };\r
3698                 };\r
3699                 if( cancel === true || key === 18 || key === 9 || key === 27 || e.altKey === true ){ // 13.enter 18.esc 9.tab 27.esc   || ( key === 13 && overlayEnabled === false)\r
3700                         return false;\r
3701                 };\r
3702         };\r
3703         \r
3704         if( UA.isIE === true && UA.ieRenderingVersion < 9 ){\r
3705                 keyPress = function( e ){\r
3706                         var key = e.keyCode;\r
3707                         if( key === 13 || key === 27 ){\r
3708                                 e.type = 'keydown';\r
3709                                 return onKeyChange( e );\r
3710                         };\r
3711                 };\r
3712         };\r
3713         \r
3714         var KeyEventTicketClass = function( _apiuser, _type, _onKeydown, _onKeyup, _keyCode, _shift, _ctrl ){\r
3715                 this.apiuser = _apiuser;\r
3716                 this.type    = _type;\r
3717                 this.keydown = _onKeydown;\r
3718                 this.keyup   = _onKeyup;                \r
3719                 this.keyCode = _keyCode;\r
3720                 this.shift   = _shift;\r
3721                 this.ctrl    = _ctrl;\r
3722                 _apiuser = _onKeydown = _onKeyup = null;\r
3723         }\r
3724         KeyEventTicketClass.prototype = {\r
3725                 match: function( _apiuser, _type, _handler, _keyCode, _shift, _ctrl ){\r
3726                         if( _apiuser  && _apiuser  !== this.apiuser ) return false;\r
3727                         if( _type     && _type     !== this.type )    return false;\r
3728                         if( _handler ){\r
3729                                 if( this.type === 'keydown' ){\r
3730                                         if( _handler !== this.keydown ) return false;\r
3731                                 } else {\r
3732                                         if( _handler !== this.keyup )   return false;\r
3733                                 };\r
3734                         };\r
3735                         if( _keyCode  && _keyCode  !== this.keyCode ) return false;\r
3736                         if( _shift    && _shift    !== this.shift )   return false;\r
3737                         if( _ctrl     && _ctrl     !== this.ctrl )    return false;\r
3738                         return true;\r
3739                 },\r
3740                 destroy: function( _apiuser, _type, _handler, _keyCode, _shift, _ctrl ){\r
3741                         if( this.match( _apiuser, _type, _handler, _keyCode, _shift, _ctrl ) === false ) return false;\r
3742                         \r
3743                         delete this.apiuser;\r
3744                         delete this.keydown;\r
3745                         delete this.keyup;\r
3746                         \r
3747                         return true;\r
3748                 }\r
3749         };\r
3750         \r
3751         function registerEvent( _apiuser, _type, _onKeydown, _onKeyup, _keyCode, _shift, _ctrl ){\r
3752                 var _uid  = _apiuser.getUID(),\r
3753                         _list = EVENT_LIST_MAP[ _uid ];\r
3754                 if( Type.isArray( _list ) === false ){\r
3755                         _list = EVENT_LIST_MAP[ _uid ] = [];\r
3756                 }\r
3757                 for( var i=0, l=_list.length; i<l; ++i ){\r
3758                         if( _list[ i ].match( _apiuser, _type, _onKeydown || _onKeyup, _keyCode, _shift, _ctrl ) === true ) return;\r
3759                 }\r
3760                 _list.push( new KeyEventTicketClass( _apiuser, _type, _onKeydown, _onKeyup, _keyCode, _shift, _ctrl ));\r
3761                 \r
3762                 if( _apiuser === application ) KeyEvent.updateCurrentListener( _apiuser );\r
3763         };\r
3764         \r
3765         return {\r
3766                 add: function( _apiuser, _type, _handler, _keyCode, _shift, _ctrl ){\r
3767                         if( _type === 'keydown' ){\r
3768                                 registerEvent( _apiuser, _type, _handler, null, _keyCode, _shift, _ctrl );\r
3769                         } else\r
3770                         if( _type === 'keyup' ){\r
3771                                 registerEvent( _apiuser, _type, null, _handler, _keyCode, _shift, _ctrl );\r
3772                         } else\r
3773                         if( _type === 'keychange' ){\r
3774                                 registerEvent( _apiuser, _type, _handler, _handler, _keyCode, _shift, _ctrl );\r
3775                         } else\r
3776                         if( _type === 'cursol' ){\r
3777                                 \r
3778                         };\r
3779                 },\r
3780                 remove: function( _apiuser, _type, _handler, _keyCode, _shift, _ctrl ){\r
3781                         var _list = EVENT_LIST_MAP[ _apiuser.getUID() ],\r
3782                                 i = 0;\r
3783                         if( Type.isArray( _list ) === true ){\r
3784                                 while( i < _list.length ){\r
3785                                         if( _list[ i ].destroy( _apiuser, _type, _handler, _keyCode, _shift, _ctrl ) === true ){\r
3786                                                 _list.splice( i, 1 );\r
3787                                         } else {\r
3788                                                 ++i;\r
3789                                         }\r
3790                                 }\r
3791                         }\r
3792                         if( _apiuser === application ) KeyEvent.updateCurrentListener( _apiuser );\r
3793                 },\r
3794                 shiftEnabled: false,\r
3795                 ctrlEnabled:  false,\r
3796                 /*\r
3797                  * currentListener\r
3798                  *  currrentApplication ( overlay Application ) or\r
3799                  *  superuser ( UI )\r
3800                  */\r
3801                 updateCurrentListener: function( _apiuser ){\r
3802                         application = _apiuser;\r
3803                         var _uid    = _apiuser.getUID();\r
3804                         currentList = EVENT_LIST_MAP[ _uid ] || ( EVENT_LIST_MAP[ _uid ] = [] );\r
3805                         \r
3806                         var _ticket,\r
3807                                 _down = false,\r
3808                                 _up   = false;\r
3809                         for( var i=currentList.length; _ticket = currentList[ --i ]; ){\r
3810                                 if( _down === false ) _down = !!_ticket.keydown;\r
3811                                 if( _up   === false ) _up   = !!_ticket.keyup;\r
3812                                 if( _down && _up ) break;\r
3813                         }\r
3814                         if( _down === true ){\r
3815                                 keydownTicket = new EventTicketClass( document, 'keydown', onKeyChange );\r
3816                                 keypressTicket = keyPress !== null ? new EventTicketClass( document, 'keypress', keyPress ) : null;\r
3817                         } else {\r
3818                                 keydownTicket && keydownTicket.destroy();\r
3819                                 keypressTicket && keypressTicket.destroy();\r
3820                                 keydownTicket = keypressTicket = null;\r
3821                         }\r
3822                         if( _up === true ){\r
3823                                 keyupTicket   = new EventTicketClass( document, 'keyup', onKeyChange );\r
3824                         } else {\r
3825                                 keyupTicket && keyupTicket.destroy();\r
3826                                 keyupTicket = null;\r
3827                         }\r
3828                         \r
3829                         if( _down === true || _up === true ){\r
3830                                 focusTicket   = new EventTicketClass( document, 'mouseenter', window.focus );\r
3831                         } else {\r
3832                                 focusTicket && focusTicket.destroy();\r
3833                                 focusTicket = null;\r
3834                         }\r
3835                 },\r
3836                 onApplicationShutdown: function( _apiuser ){\r
3837                         KeyEvent.remove( _apiuser );\r
3838                 },\r
3839                 onSystemShutdown: function(){\r
3840                         \r
3841                 }\r
3842         }\r
3843 })();\r
3844 \r
3845 /**\r
3846  * \r
3847  * http://thudjs.tumblr.com/post/637855087/stylesheet-onload-or-lack-thereof\r
3848  */\r
3849 \r
3850 var StyleSheet = ( function(){\r
3851         var head = document.getElementsByTagName( 'head' )[ 0 ];\r
3852         \r
3853         var TICKET_LIST = [];\r
3854         var STATE_LIST  = 'loaded,complete,uninitialized'.split( ',' );\r
3855         \r
3856         var cssRules, sheet;\r
3857         \r
3858         var FetchCssTicketClass = function( _apiuser, _url, _elm, _onload, _onerror, opt_thisObject ){\r
3859                 this.apiusers = [ _apiuser ];\r
3860                 this.url      = _url;\r
3861                 this.elm      = _elm;\r
3862                 this.onload   = [ _onload ];\r
3863                 this.onerror  = [ _onerror ];\r
3864                 this.thisObj  = [ opt_thisObject ];\r
3865                 this.time     = 0;\r
3866         };\r
3867         FetchCssTicketClass.prototype = {\r
3868                 match: function( _apiuser, _url ){\r
3869                         if( _apiuser  && Util.getIndex( this.apiusers, _apiuser ) === -1 ) return false;\r
3870                         if( _url      && _url      !== this.url     ) return false;\r
3871                         return true;\r
3872                 },\r
3873                 destroy: function( _apiuser, _url ){\r
3874                         if( this.match( _apiuser, _url ) === false ) return false;\r
3875                         \r
3876                         var i = Util.getIndex( this.apiusers, _apiuser );\r
3877                         \r
3878                         this.apiusers.splice( i, 1 );\r
3879                         this.onload.splice( i, 1 );\r
3880                         this.onerror.splice( i, 1 );\r
3881                         this.thisObj.splice( i, 1 );\r
3882                         \r
3883                         if( this.apiusers.length !== 0 ) return false;\r
3884                         \r
3885                         head.removeChild( this.elm );\r
3886                         this.elm.onreadystatechange = new Function();\r
3887                         this.elm.onload = null;\r
3888                         \r
3889                         delete this.apiusers;\r
3890                         delete this.url;\r
3891                         delete this.elm;\r
3892                         delete this.onload;\r
3893                         delete this.onerror;\r
3894                         delete this.thisObj;\r
3895                         delete this.time;\r
3896                         \r
3897                         return true;\r
3898                 },\r
3899                 loaded: function(){\r
3900                 for( var i = this.onload.length, f; i; ){\r
3901                         f = this.onload[ --i ];\r
3902                         Type.isFunction( f ) === true && AsyncCall.add( this.apiusers[ i ], f, this.url, this.thisObj[ i ] || this.apiusers[ i ] );\r
3903                         this.onload[ i ] = this.onerror[ i ] = null;\r
3904                 };\r
3905                 },\r
3906                 error: function(){\r
3907                 for( var i = this.onerror.length, f; i; ){\r
3908                         f = this.onerror[ --i ];\r
3909                         Type.isFunction( f ) === true && AsyncCall.add( this.apiusers[ i ], f, this.url, this.thisObj[ i ] || this.apiusers[ i ] );\r
3910                         this.onload[ i ] = this.onerror[ i ] = null;\r
3911                 };\r
3912                 },\r
3913                 check: function(){\r
3914                         var el = this.elm;\r
3915                         try {\r
3916                                 return el[ sheet ] && el[ sheet ][ cssRules ].length > 0;\r
3917                         } catch( e ){\r
3918                                 return false;\r
3919                         };\r
3920                 },\r
3921                 done: false\r
3922         };\r
3923         \r
3924         function getTicket( elm ){\r
3925                 for( var i = TICKET_LIST.length, t; i; ){\r
3926                         t = TICKET_LIST[ --i ];\r
3927                         if( t.elm === elm ) return t;\r
3928                 };\r
3929         };\r
3930         \r
3931         function detect(){\r
3932                 var t = getTicket( this ), rs = this.readyState, c;\r
3933                 if( t && t.done === false && ( !rs || Util.getIndex( STATE_LIST, rs ) !== -1 ) ){\r
3934                         t.done = true;\r
3935                 t.loaded();\r
3936                 this.onreadystatechange = new Function();\r
3937                 this.onload = null;\r
3938                 };\r
3939         };\r
3940         \r
3941         function checkTimer(){\r
3942                 var l = TICKET_LIST.length,\r
3943                         n = 0, t;\r
3944                 for( var i = 0; i < l; ++i ){\r
3945                         t = TICKET_LIST[ i ];\r
3946                         ++t.time;\r
3947                         if( t.check() === true ){\r
3948                                 t.loaded();\r
3949                                 ++n;\r
3950                         } else\r
3951                         if( t.time > 99 ){\r
3952                                 t.error();\r
3953                         } else {\r
3954                                 \r
3955                         };\r
3956                 };\r
3957                 l === n && SystemTimer.remove( SUPER_USER_KEY, checkTimer );\r
3958         };\r
3959         \r
3960         return {\r
3961                 load: function( _apiuser, _url, opt_onload, opt_onerror, opt_thisObject ){\r
3962                         _url = Util.getAbsolutePath( _url );\r
3963                         var t;\r
3964                         for( var i=TICKET_LIST.length; i; ){\r
3965                                 t = TICKET_LIST[ --i ];\r
3966                                 if( t.match( null, _url ) === true ){\r
3967                                         if( t.match( _apiuser, _url ) === false ){\r
3968                                                 t.apiusers.push( _apiuser );\r
3969                                                 t.onload.push( opt_onload );\r
3970                                                 t.onerror.push( opt_onerror );\r
3971                                                 t.thisObj.push( opt_thisObject );\r
3972                                         };\r
3973                                         SystemTimer.add( SUPER_USER_KEY, checkTimer, 333 );\r
3974                                         return;\r
3975                                 };\r
3976                         };\r
3977                         var elm = document.createElement( 'link' );\r
3978                         head.appendChild( elm );\r
3979                         elm.rel  = 'stylesheet';\r
3980                         elm.type = 'text\/css';\r
3981                         elm.onreadystatechange = elm.onload = detect;\r
3982                         elm.href = _url;\r
3983                         \r
3984                         if( !sheet ){ // only assign these once\r
3985                                 cssRules = 'cssRules';\r
3986                                 sheet    = 'sheet';\r
3987                                 if ( !( sheet in elm ) ) { // MSIE uses non-standard property names\r
3988                                         cssRules = 'rules';\r
3989                                         sheet    = 'styleSheet';\r
3990                                 };\r
3991                         };\r
3992                         \r
3993                         TICKET_LIST.push( new FetchCssTicketClass( _apiuser, _url, elm, opt_onload, opt_onerror, opt_thisObject ) );\r
3994                         \r
3995                         SystemTimer.add( SUPER_USER_KEY, checkTimer, 333 );\r
3996                 },\r
3997                 unload: function( _apiuser, _url ){\r
3998                         _url = _url ? Util.getAbsolutePath( _url ) : null;\r
3999             var t;\r
4000                         for( var i = 0; i < TICKET_LIST.length; ){\r
4001                                 t = TICKET_LIST[ i ];\r
4002                                 if( t.destroy( _apiuser, _url ) === true ){\r
4003                                         TICKET_LIST.splice( i, 1 );\r
4004                                 } else {\r
4005                                         ++i;\r
4006                                 }\r
4007                         };\r
4008                         if( TICKET_LIST.length === 0 ){\r
4009                                 SystemTimer.remove( SUPER_USER_KEY, checkTimer );\r
4010                         }\r
4011                 }\r
4012         }\r
4013 })();\r
4014 \r
4015 /*\r
4016  * AssetLoader\r
4017  * fetchCSS\r
4018  * fetchJson\r
4019  * fetchHtml\r
4020  * fetchImage\r
4021  * fetchLocalFile\r
4022  * fetchLocalStorage\r
4023  */\r
4024 \r
4025 var Image = ( function(){\r
4026         var TASK_LIST = [];\r
4027         /* \r
4028          * FetchClass original is\r
4029          * \r
4030          * LICENSE: MIT?\r
4031          *  URL: http://d.hatena.ne.jp/uupaa/20080413/1208067631\r
4032          *  AUTHOR: uupaa.js@gmail.com\r
4033          * \r
4034          */\r
4035         function detect(){\r
4036                 for( var i=0, t; i < TASK_LIST.length; ){\r
4037                         t = TASK_LIST[ i ];\r
4038                         if( t.complete() === true ){\r
4039                                 TASK_LIST.splice( i, 1 );\r
4040                         } else {\r
4041                                 ++i;\r
4042                         };\r
4043                 };\r
4044                 TASK_LIST.length === 0 && SystemTimer.remove( SUPER_USER_KEY, detect );\r
4045         };\r
4046         function getTask( img ){\r
4047                 for( var i = TASK_LIST.length; i; ){\r
4048                         if( TASK_LIST[ --i ].img === img ) return TASK_LIST[ i ];\r
4049                 };\r
4050         };\r
4051         function onError(){\r
4052                 var task = getTask( this );\r
4053                 if( task.finish === true ) return;\r
4054                 task.finish = true;\r
4055                 AsyncCall.add( task.apiuser, task.asyncCallback, null, task );\r
4056         };\r
4057         function onLoad(){\r
4058                 // if( finish === true ) return; // これがあると firefox3.6 で駄目、、、\r
4059                 // if( timer ) return; // これがあると safari3.2 で駄目、、、\r
4060                 var task = getTask( this );\r
4061                 task.finish = true;\r
4062                 TASK_LIST.splice( Util.getIndex( TASK_LIST, task ), 1 );\r
4063                 if( window.opera && !task.img.complete ){\r
4064                         AsyncCall.add( task.apiuser, task.asyncCallback, null, task );\r
4065                         return;\r
4066                 };\r
4067                 task.size = Util.getImageSize( this );\r
4068                 AsyncCall.add( task.apiuser, task.asyncCallback, null, task );\r
4069         };\r
4070 \r
4071 \r
4072         var FetchClass = function( apiuser, abspath, onLoadCallback, onErrorCallback, timeout ){\r
4073                 this.apiuser         = apiuser;\r
4074                 this.abspath         = abspath;\r
4075                 this.onLoadCallback  = onLoadCallback;\r
4076                 this.onErrorCallback = onErrorCallback;\r
4077                 this.timeout         = timeout;\r
4078                 this.tick            = 0;\r
4079         };\r
4080         FetchClass.prototype = {\r
4081                 img: null,\r
4082                 size: null,\r
4083                 tick: 0,\r
4084                 finish: false,\r
4085                 load: function(){\r
4086                         var img     = this.img = document.createElement( 'img' ); //var img = new Image(); ではieでimgのsizeが取れない、、、removeChildも失敗し、imgSizeGetterにimgが残る\r
4087                         img.onabort = img.onerror = onError;\r
4088                         img.onload  = onLoad;\r
4089                         img.src     = this.abspath;\r
4090                 },\r
4091                 complete: function(){\r
4092                         if( this.finish === true ) return true;\r
4093                         if( this.img.complete ){\r
4094                                 this.finish = true;\r
4095                                 if( this.img.width ) return true;\r
4096                                 AsyncCall.add( this.apiuser, this.asyncCallback, null, this );\r
4097                                 return true;\r
4098                         };\r
4099                         if( ( this.tick += 250 ) > this.timeout ){\r
4100                                 this.finish = true;\r
4101                                 AsyncCall.add( this.apiuser, this.asyncCallback, null, this );\r
4102                                 return true;\r
4103                         };\r
4104                 },\r
4105                 asyncCallback: function(){\r
4106                         this.size ? this.onLoadCallback( this.abspath, this.size.width, this.size.height ) : this.onErrorCallback( this.abspath );\r
4107                         this.destroy();\r
4108                 },\r
4109                 destroy: function(){\r
4110                         this.finish  = true;\r
4111                         this.img.src = this.img.onload = this.img.onabort = this.img.onerror = '';\r
4112                         delete this.img;\r
4113                         delete this.size;\r
4114                         delete this.onLoadCallback;\r
4115                         delete this.onErrorCallback;\r
4116                 },\r
4117                 stop: function(){\r
4118                         timer !== null && window.clearTimeout( timer );\r
4119                         destroy();\r
4120                 }\r
4121         };\r
4122         \r
4123         return {\r
4124                 load: function( URLorELM, onLoad, onError, opt_timeout ){\r
4125                         var src, fetch;\r
4126                         if( Type.isString( URLorELM ) === true ){\r
4127                                 src = URLorELM;\r
4128                         } else\r
4129                         if( Type.isHTMLElement( URLorELM ) === true && URLorELM.tagName.toLowerCase() === 'img' ){\r
4130                                 src = URLorELM.src;\r
4131                         } else {\r
4132                                 return;\r
4133                         };\r
4134                         \r
4135                         fetch = new FetchClass(\r
4136                                 Util.getAbsolutePath( src ),\r
4137                                 onLoad, onError,\r
4138                                 Type.isFinite( opt_timeout ) === true ? opt_timeout : undefined\r
4139                         );\r
4140                         TASK_LIST.push( fetch );\r
4141                         \r
4142                         SystemTimer.add( SUPER_USER_KEY, detect, 250 );\r
4143                 },\r
4144                 unload: function(  ){\r
4145                         \r
4146                 }\r
4147         };\r
4148 })();\r
4149 \r
4150 \r
4151 /* ----------------------------------------\r
4152  * \r
4153  */\r
4154 \r
4155 var Overlay = ( function(){\r
4156         var elmContainer, elmShadow, elmCloseButton,\r
4157                 bootParams,\r
4158                 application    = null,\r
4159                 visible        = false,\r
4160                 bodyOverflow   = '',\r
4161                 windowW, windowH;\r
4162 \r
4163         function onCloseClick( e ){\r
4164                 Overlay.hide();\r
4165                 return false;\r
4166         };\r
4167         function asyncInit( /* arguments */ ){\r
4168                 application.init();\r
4169                 //application.rootElement.style.display = 'none';\r
4170                 \r
4171                 elmContainer.style.cssText = "top:" + body.scrollTop + 'px;display:none;';\r
4172                 $( elmContainer ).stop().fadeIn( onFadeInComplete );            \r
4173         };\r
4174         function asyncOpen( /* arguments */ ){\r
4175 \r
4176                 \r
4177                 \r
4178         };\r
4179         function onFadeInComplete(){\r
4180                 KeyEvent.add( application, Const.KEY.EVENT.KEY_DOWN, Overlay.hide, 27 ); // 27.esc\r
4181                 MouseEvent.add( application, elmCloseButton, 'click', onCloseClick );\r
4182                 \r
4183                 var _arg = bootParams; //Util.copyArray( arguments );\r
4184                 _arg.unshift( windowW, windowH );\r
4185                 application.open.apply( application, _arg );            \r
4186         };\r
4187         function onFadeOutComplete(){   \r
4188                 Util.removeAllChildren( elmContainer );\r
4189                 body.removeChild( elmContainer );\r
4190                 elmContainer = elmShadow = elmCloseButton = null;\r
4191         };\r
4192         return {\r
4193                 show: function( _application, _bootParams ){\r
4194                         if( visible === true && application === _application ) return;\r
4195                         if( Application.isApplicationInstance( _application ) === false ) return;\r
4196                         \r
4197                         elmContainer = document.createElement( 'div' );\r
4198                         body.appendChild( elmContainer );\r
4199                         \r
4200                         elmContainer.id = 'overlay-container';\r
4201                         \r
4202                         bodyOverflow        = body.style.overflow;\r
4203                         body.style.overflow = 'hidden';\r
4204                         \r
4205                         elmShadow = document.createElement( 'div' );\r
4206                         elmContainer.appendChild( elmShadow );\r
4207                         elmShadow.id = 'overlay-shadow';\r
4208                         \r
4209                         elmCloseButton  = document.createElement( 'div' );\r
4210                         elmContainer.appendChild( elmCloseButton );\r
4211                         elmCloseButton.id = 'overlay-close-button';\r
4212                         elmCloseButton.appendChild( document.createTextNode( 'x' ) );\r
4213                         \r
4214                         elmContainer.style.display = 'none'; // hide for fadeIn\r
4215                         \r
4216                         visible     = true;\r
4217                         application = _application;\r
4218                         \r
4219                         //asyncInit();\r
4220                         elmContainer.insertBefore( application.rootElement, elmCloseButton );\r
4221                         _application.addAsyncCall( asyncInit );\r
4222                         // _application.addAsyncCall( asyncOpen,  );\r
4223                         \r
4224                         bootParams = _bootParams;                       \r
4225                 },\r
4226                 hide: function(){\r
4227                         if( visible === false ) return;\r
4228                         if( application.close() === false ) return false;\r
4229                         \r
4230                         body.style.overflow = bodyOverflow;\r
4231                         \r
4232                         $( elmContainer ).stop().css( {\r
4233                                 filter:         '',\r
4234                                 opacity:        ''\r
4235                         }).fadeOut( onFadeOutComplete );\r
4236                         visible = false;\r
4237                         \r
4238                         application = null;\r
4239                 },\r
4240                 onWindowResize: function( _windowW, _windowH ){\r
4241                         windowW = _windowW;\r
4242                         windowH = _windowH;                     \r
4243                         \r
4244                         if( application === null ) return;\r
4245                         \r
4246                         elmContainer.style.height = _windowH + 'px';\r
4247                         elmContainer.style.top    = body.scrollTop + 'px';\r
4248 \r
4249                         elmShadow.style.height = _windowH + 'px';\r
4250 \r
4251                         AsyncCall.add( application, application.resize, [ _windowW, _windowH ] );\r
4252                 }\r
4253         }\r
4254 })();\r
4255 \r
4256 /* ----------------------------------------\r
4257  * UI\r
4258  * \r
4259  * keyEventRellay\r
4260  *  form -> overlay -> view\r
4261  * \r
4262  */\r
4263 \r
4264 var UI = ( function(){\r
4265         var UI_LIST     = [],\r
4266                 currentUser = null,\r
4267                 currentList = null,\r
4268                 currentUi   = null,\r
4269                 currentItem = null,\r
4270                 windowW     = 0,\r
4271                 windowH     = 0;\r
4272 \r
4273         var CLASSNAME_COMBOBOX_OPTION = 'combobox-option',\r
4274                 CLASSNAME_COMBOBOX_OPTION_CURRENT = CLASSNAME_COMBOBOX_OPTION + ' combobox-option-current',\r
4275                 ELM_COMBOBOX = ( function(){\r
4276                         var ret       = document.createElement( 'a' ),\r
4277                                 elmToggle = document.createElement( 'span' ),\r
4278                                 elmValue  = document.createElement( 'span' );\r
4279                         ret.href = '#';\r
4280                         ret.appendChild( elmToggle );\r
4281                         ret.appendChild( elmValue );\r
4282                         elmToggle.className = 'combobox-toggle';\r
4283                         elmValue.className  = 'combobox-value';\r
4284                         \r
4285                         elmToggle.appendChild( document.createTextNode( '▼' ));\r
4286                         elmValue.appendChild( document.createTextNode( 'null' ));\r
4287                         return ret;\r
4288                 })();\r
4289         \r
4290         var UIItemPrivateData = function(){};\r
4291         UIItemPrivateData.prototype = {\r
4292                 groupData   : null,\r
4293                 item        : null,\r
4294                 elm         : null,\r
4295                 node        : null,\r
4296                 focus       : false,\r
4297                 visible     : true,\r
4298                 enabled     : true,\r
4299                 value       : null,\r
4300                 onUpdate    : null,\r
4301                 validator   : null,\r
4302                 elmValue    : null,\r
4303                 elmBox      : null,\r
4304                 elmA        : null,\r
4305                 elmToggle   : null,\r
4306                 elmValue    : null,\r
4307                 selectIndex : 0,\r
4308                 optionList  : null,\r
4309                 init    : function( groupData, item, elm, value, onUpdate, validator, focus, visible, enabled ){\r
4310                         this.groupData = groupData;\r
4311                         this.item      = item;\r
4312                         this.elm       = elm;\r
4313                         this.value     = value;\r
4314                         this.onUpdate  = onUpdate;\r
4315                         this.validator = validator;                     \r
4316                         this.focus     = !!focus;\r
4317                         this.visible   = !!visible;\r
4318                         this.enabled   = !!enabled;\r
4319                         UIItemPrivateData.list.push( this );\r
4320                 },\r
4321                 destroy : function(){\r
4322                         var list = UIItemPrivateData.list;\r
4323                         list.splice( Util.getIndex( list, this ), 1 );\r
4324                         \r
4325                         list = this.groupData.itemList;\r
4326                         var i = Util.getIndex( list, this.item );\r
4327                         i !== -1 && list.splice( i, 1 );\r
4328                         \r
4329                         this.node && this.node.remove();\r
4330                 }\r
4331         };\r
4332         UIItemPrivateData.list = [];\r
4333         UIItemPrivateData.get = function( item ){\r
4334                 var list = UIItemPrivateData.list;\r
4335                 for( i = list.length; i; ){\r
4336                         if( list[ --i ].item === item ) return list[ i ];\r
4337                 };\r
4338                 return null;\r
4339         };\r
4340         \r
4341 /* --------------------------------\r
4342  * TextInputManager\r
4343  */\r
4344         var TextInputManager = ( function(){\r
4345                 var elmInput = ( function(){\r
4346                         var ret  = document.createElement( 'input' );\r
4347                         ret.type = 'text';\r
4348                         ret.id   = 'ui-textinput';\r
4349                         return ret;\r
4350                 })();\r
4351                 var currentData;\r
4352                 \r
4353                 function updateWrapperPosition(){\r
4354                         var p = Position.cumulativeOffset( currentData.elmValue ),\r
4355                                 w = currentData.elmValue.offsetWidth - 2,\r
4356                                 _w;             \r
4357                         elmInput.style.cssText = [\r
4358                                 'left:',   p[ 0 ], 'px;',\r
4359                                 'top:',    p[ 1 ], 'px;',//,\r
4360                                 'width:',  w, 'px;'//,\r
4361                                 //'height:', data.elmValue.offsetHeight, 'px;',\r
4362                                 //'position:absolute;'\r
4363                         ].join( '' );\r
4364                         \r
4365                         //_w = elmInput.offsetWidth;\r
4366                         //if( w !== _w ) elmInput.style.width = ( w - ( _w - w ) ) + 'px;';     \r
4367                 };\r
4368                 \r
4369                 return {\r
4370                         show: function( data ){\r
4371                                 // this.groupData.node.addEventListener( 'mouseout' );\r
4372                                 currentData = data;\r
4373 \r
4374                                 body.appendChild( elmInput );\r
4375                                 elmInput.value = data.value;\r
4376                                 updateWrapperPosition();\r
4377                                 \r
4378                                 elmInput.focus();\r
4379                                 elmInput.select();\r
4380                                 \r
4381                                 SystemTimer.add( SUPER_USER_KEY, updateWrapperPosition, 500 );\r
4382                         },\r
4383                         hide : function( data ){\r
4384                                 if( currentData !== data ) return;\r
4385                                 currentData = null;\r
4386                                 body.removeChild( elmInput );\r
4387                                 var ret = elmInput.value;\r
4388                                 elmInput.value = '';\r
4389                                 SystemTimer.remove( SUPER_USER_KEY, updateWrapperPosition );\r
4390                                 return ret;\r
4391                         },\r
4392                         update : function( data ){\r
4393                                 elmInput.value = data.value;\r
4394                         },\r
4395                         onWindowResize: function( _w, _h ){\r
4396                                 AsyncCall.add( currentUser, updateWrapperPosition );\r
4397                         }\r
4398                 };\r
4399         })();\r
4400         \r
4401         var TextInputClass = function( groupData, elmWrapper, elmValue, onUpdate, validater ){\r
4402                 var data = new UIItemPrivateData();\r
4403                 data.init( groupData, this, elmWrapper, elmValue.innerHTML, onUpdate, validater, false, true, true );\r
4404                 Util.addClass( elmValue, 'editable-text' );\r
4405                 data.elmValue = elmValue;\r
4406                 this.value( data.value );\r
4407                 data.node = groupData.node.createNode( elmWrapper, false, true, 'ui-inpittext-hover', 'pointer' );\r
4408                 data.node.addEventListener( 'click', this.focus, this );\r
4409                 //MouseEvent.add( groupData.apiuser, elmWrapper, 'click', instance.focus );\r
4410         };\r
4411         TextInputClass.prototype = {\r
4412                 value : function( value ){\r
4413                         var data = UIItemPrivateData.get( this );\r
4414                         if( Type.isString( value ) === true || Type.isNumber( value ) === true ){\r
4415                                 data.elmValue.innerHTML = data.value = '' + value;\r
4416                                 data.focus === true && TextInputManager.update( data );\r
4417                         };\r
4418                         data.focus === true && this.blur();\r
4419                         return data.value;\r
4420                 },\r
4421                 focus : function( e ){\r
4422                         var data = UIItemPrivateData.get( this );\r
4423                         data.focus = true;\r
4424                         start( data );\r
4425                         TextInputManager.show( data );\r
4426                         return false;\r
4427                 },\r
4428                 blur : function( keep ){\r
4429                         var data = UIItemPrivateData.get( this ),\r
4430                                 newValue;\r
4431                         if( data.focus === false ) return;\r
4432                         newValue = TextInputManager.hide( data );\r
4433                         newValue = keep !== 27 ? ( data.validater ? '' + data.validater( newValue ) : newValue ) : data.value; // 27:ESC\r
4434 \r
4435                         data.elmValue.innerHTML = newValue;\r
4436                         \r
4437                         data.onUpdate && newValue !== data.value && AsyncCall.add( data.groupData.apiuser, data.onUpdate, [ newValue, data.value ], this );\r
4438                         \r
4439                         data.value = newValue;\r
4440                         data.focus = false;\r
4441                         finish( data );\r
4442                 },\r
4443                 enabled : function( v ){\r
4444                         var data = UIItemPrivateData.get( this );\r
4445                         if( Type.isBoolean( v ) === true && data.enabled !== v ){\r
4446                                 Util.toggleClass( data.elm, 'ui-textinput-disabled', !v );\r
4447                                 if( data.focus === true && v === false ) this.blur();\r
4448                                 data.enabled = v;\r
4449                                 data.node.disabled( !( data.visible && v ) );\r
4450                         };\r
4451                         return data.enabled;\r
4452                 },\r
4453                 visible : function( v ){\r
4454                         var data = UIItemPrivateData.get( this );\r
4455                         if( Type.isBoolean( v ) === true && data.visible !== v ){\r
4456                                 data.elm.style.display = v ? '' : 'none';\r
4457                                 if( data.focus === true && v === false ) this.blur();\r
4458                                 data.visible = v;\r
4459                                 data.node.disabled( !( data.enabled && v ) );\r
4460                         };\r
4461                         return data.visible;\r
4462                 },\r
4463                 destroy : function(){\r
4464                         var data = UIItemPrivateData.get( this );\r
4465                         data.focus === true && TextInputManager.hide( data );\r
4466                         data.destroy();\r
4467                 }\r
4468         };\r
4469 \r
4470 /* --------------------------------\r
4471  * TextInputManager\r
4472  */\r
4473         var FileInputManager = ( function(){\r
4474                 var currentData,\r
4475                         elmForm,\r
4476                         elmFileInput,\r
4477                         elmWrap,\r
4478                         evt;\r
4479                 \r
4480                 function updateWrapperPosition(){\r
4481                         var p = Position.cumulativeOffset( currentData.elmValue ),\r
4482                                 w = currentData.elmValue.offsetWidth,\r
4483                                 _w;             \r
4484                         elmWrap.style.cssText = [\r
4485                                 'left:',   p[ 0 ], 'px;',\r
4486                                 'top:',    p[ 1 ], 'px;',//,\r
4487                                 'width:',  w, 'px;'//,\r
4488                                 //'height:', data.elmValue.offsetHeight, 'px;',\r
4489                                 //'position:absolute;'\r
4490                         ].join( '' );\r
4491                         \r
4492                         _w = elmWrap.offsetWidth;\r
4493                         if( w !== _w ) elmWrap.style.width = ( w - ( _w - w ) ) + 'px'; \r
4494                 };\r
4495                 \r
4496                 function change( e ){\r
4497                         var data = currentData,\r
4498                                 file = data.elmFileInputReal.value;\r
4499                         file = file.split( '\\' );\r
4500                         file = file[ file.length - 1 ];\r
4501                         if( data.value !== file ){\r
4502                                 data.onUpdate && AsyncCall.add( data.groupData.apiuser, data.onUpdate, [ file, data.value ], this );\r
4503                                 data.elmValue.innerHTML = data.value = file;\r
4504                         };\r
4505                         currentData.item.blur();\r
4506                 };\r
4507                 function asyncMouseout(){\r
4508                         currentData && currentData.item.blur();\r
4509                 };\r
4510                 function onClick(){\r
4511                         MouseEvent.remove( currentUser, elmFileInput, 'mouseout', asyncMouseout );\r
4512                         MouseEvent.remove( currentUser, elmFileInput, 'click', onClick );       \r
4513                 };\r
4514                 return {\r
4515                         show : function( data ){\r
4516                                 currentData = data;\r
4517                                 \r
4518                                 elmFileInput = data.elmFileInputReal;\r
4519                                 elmWrap      = elmFileInput.parentNode;\r
4520                                 // \r
4521                                 \r
4522                                 updateWrapperPosition();\r
4523                                 elmFileInput.focus();\r
4524                                 //data.node.addEventListener( 'change', change, data );\r
4525                                 evt = new EventTicketClass( elmFileInput, 'change', change );\r
4526                                 MouseEvent.add( currentUser, elmFileInput, 'mouseout', asyncMouseout );\r
4527                                 MouseEvent.add( currentUser, elmFileInput, 'click', onClick );\r
4528                                 // currentData.elmFileInputReal.onchange = change;\r
4529                                 SystemTimer.add( SUPER_USER_KEY, updateWrapperPosition, 500 );\r
4530                         },\r
4531                         hide : function( data ){\r
4532                                 if( currentData !== data ) return;\r
4533                                 // data.node.removeEventListener( 'change', change );\r
4534                                 evt.destroy();\r
4535                                 // MouseEvent.remove( currentUser, elmFileInput, 'mouseout', asyncMouseout );\r
4536                                 onClick();\r
4537                                 //currentData.elmFileInputReal.onchange = null;\r
4538                                 elmWrap.style.display = 'none';\r
4539                                 currentData = elmFileInput = null;\r
4540                                 SystemTimer.remove( SUPER_USER_KEY, updateWrapperPosition );\r
4541                         },\r
4542                         onWindowResize: function( _w, _h ){\r
4543                                 AsyncCall.add( currentUser, updateWrapperPosition );\r
4544                         }\r
4545                 };\r
4546         })();\r
4547         \r
4548         var FileInputClass = function( groupData, elmWrapper, onUpdate, validater, elmFileInputReal, elmValue ){\r
4549                 var data = new UIItemPrivateData();\r
4550                 data.init( groupData, this, elmWrapper, null, onUpdate, null, false, true, true );\r
4551                 data.node = groupData.node.createNode( elmWrapper, false, true, 'ui-fileinput-hover', 'pointer' );\r
4552                 data.elmValue = elmValue;\r
4553                 data.elmFileInputReal = elmFileInputReal;\r
4554                 data.node.addEventListener( 'mouseover', this.focus, this );\r
4555         };\r
4556         FileInputClass.prototype = {\r
4557                 value : function(){\r
4558                         return data.value;\r
4559                 },\r
4560                 focus : function(){\r
4561                         var data = UIItemPrivateData.get( this );\r
4562                         data.focus = true;\r
4563                         Util.addClass( data.elm, 'fileinput-has-focus' );\r
4564                         start( data );\r
4565                         FileInputManager.show( data );\r
4566                 },\r
4567                 blur : function( keyCode ){\r
4568                         var data = UIItemPrivateData.get( this );\r
4569                         Util.removeClass( data.elm, 'fileinput-has-focus' );\r
4570                         data.focus = false;\r
4571                         FileInputManager.hide( data );\r
4572                         finish( data );\r
4573                 },\r
4574                 enabled : function( v ){\r
4575                         var data = UIItemPrivateData.get( this );\r
4576                         if( Type.isBoolean( v ) === true && data.enabled !== v ){\r
4577                                 if( data.focus === true && v === false ) this.blur();\r
4578                                 Util.toggleClass( data.elm, 'fileinput-disabled', !v );\r
4579                                 data.enabled = v;\r
4580                                 data.node.disabled( !( data.visible && v ) );\r
4581                         };\r
4582                         return data.enabled;\r
4583                 },\r
4584                 visible : function( v ){\r
4585                         var data = UIItemPrivateData.get( this );\r
4586                         if( Type.isBoolean( v ) === true && data.visible !== v ){\r
4587                                 if( data.focus === true && v === false ) this.blur();\r
4588                                 data.elm.style.display = v ? '' : 'none';\r
4589                                 data.visible = v;\r
4590                                 data.node.disabled( !( data.enabled && v ) );\r
4591                         };\r
4592                         return data.visible;\r
4593                 },\r
4594                 destroy : function(){\r
4595                         var data = UIItemPrivateData.get( this );\r
4596                         data.focus === true && FileInputManager.hide( data );\r
4597                         data.destroy();\r
4598                 }\r
4599         };\r
4600         \r
4601         var ButtonClass = function( groupData, elmWrapper, onUpdate ){\r
4602                 var data = new UIItemPrivateData();\r
4603                 data.init( groupData, this, elmWrapper, null, onUpdate, null, false, true, true );\r
4604                 data.node = groupData.node.createNode( elmWrapper, false, true, 'ui-button-hover', 'pointer' );\r
4605                 data.node.addEventListener( 'click', onUpdate );\r
4606                 //MouseEvent.add( groupData.apiuser, elmWrapper, 'click', onUpdate );\r
4607         };\r
4608         ButtonClass.prototype = {\r
4609                 focus : function(){\r
4610                         var data = UIItemPrivateData.get( this );\r
4611                         data.focus = true;\r
4612                         Util.addClass( data.elm, 'button-has-focus' );\r
4613                         start( data );\r
4614                 },\r
4615                 blur : function( keyCode ){\r
4616                         var data = UIItemPrivateData.get( this );\r
4617                         keyCode === 13 && data.onUpdate && data.onUpdate();\r
4618                         Util.removeClass( data.elm, 'button-has-focus' );\r
4619                         data.focus = false;\r
4620                         finish( data );\r
4621                 },\r
4622                 enabled : function( v ){\r
4623                         var data = UIItemPrivateData.get( this );\r
4624                         if( Type.isBoolean( v ) === true && data.enabled !== v ){\r
4625                                 Util.toggleClass( data.elm, 'button-disabled', !v );\r
4626                                 data.enabled = v;\r
4627                                 data.node.disabled( !( data.visible && v ) );\r
4628                         };\r
4629                         return data.enabled;\r
4630                 },\r
4631                 visible : function( v ){\r
4632                         var data = UIItemPrivateData.get( this );\r
4633                         if( Type.isBoolean( v ) === true && data.visible !== v ){\r
4634                                 data.elm.style.display = v ? '' : 'none';\r
4635                                 data.visible = v;\r
4636                                 data.node.disabled( !( data.enabled && v ) );\r
4637                         };\r
4638                         return data.visible;\r
4639                 },\r
4640                 destroy : function(){\r
4641                         var data = UIItemPrivateData.get( this );\r
4642                         // MouseEvent.remove( data.groupData.apiuser, data.elm );\r
4643                         data.destroy();\r
4644                 }\r
4645         };\r
4646 \r
4647         var ComboBoxClass = function( groupData, elmWrapper, onUpdate ){\r
4648                 var elmA   = ELM_COMBOBOX.cloneNode( true ),\r
4649                         data   = new UIItemPrivateData();\r
4650                 data.init( groupData, this, elmWrapper, null, onUpdate, null, false, true, true );\r
4651                 \r
4652                 data.elmBox      = Util.getElementsByClassName( elmWrapper, 'combobox' )[ 0 ];\r
4653                 data.elmBox.appendChild( elmA );\r
4654                 data.elmA        = elmA;\r
4655                 data.elmToggle   = Util.getElementsByClassName( elmA, 'combobox-toggle' )[ 0 ];\r
4656                 data.elmValue    = Util.getElementsByClassName( elmA, 'combobox-value' )[ 0 ].firstChild;\r
4657                 data.selectIndex = 0;\r
4658                 data.optionList  = [];\r
4659 \r
4660                 data.node = groupData.node.createNode( elmWrapper, false, true, 'ui-combobox-hover', 'pointer' );\r
4661                 data.node.addEventListener( 'click', this.focus, this );\r
4662         };\r
4663         ComboBoxClass.prototype = {\r
4664                 focus : function( e ){\r
4665                         var data = UIItemPrivateData.get( this );\r
4666                         data.node.removeEventListener( 'click', this.focus );\r
4667                         data.focus = true;\r
4668                         data.elmA.className = 'combobox-has-focus';\r
4669                         start( data );\r
4670                         OptionControl.show( data );\r
4671                         return false;\r
4672                 },\r
4673                 blur : function( keyCode ){\r
4674                         var data = UIItemPrivateData.get( this );\r
4675                         OptionControl.hide( this );\r
4676                         data.focus = false;\r
4677                         data.elmA.className = '';\r
4678                         finish( data );\r
4679                         data.node.addEventListener( 'click', this.focus, this );\r
4680                 },\r
4681                 enabled : function( v ){\r
4682                         var data = UIItemPrivateData.get( this );\r
4683                         if( Type.isBoolean( v ) === true && data.enabled !== v ){\r
4684                                 Util.toggleClass( data.elm, 'ui-combobox-disabled', !v );\r
4685                                 if( data.focus === true && v === false ) this.blur();\r
4686                                 data.enabled = v;\r
4687                                 data.node.disabled( !( data.visible && v ) );\r
4688                         };\r
4689                         return data.enabled;\r
4690                 },\r
4691                 visible : function( v ){\r
4692                         var data = UIItemPrivateData.get( this );\r
4693                         if( Type.isBoolean( v ) === true && data.visible !== v ){\r
4694                                 data.elm.style.display = v ? '' : 'none';\r
4695                                 if( data.focus === true && v === false ) this.blur();\r
4696                                 data.visible = v;\r
4697                                 data.node.disabled( !( data.enabled && v ) );\r
4698                         };\r
4699                         return data.visible;\r
4700                 },\r
4701                 value : function( _value ){\r
4702                         var data = UIItemPrivateData.get( this ),\r
4703                                 i    = 0,\r
4704                                 list = data.optionList,\r
4705                                 l    = list.length,\r
4706                                 _option;\r
4707                         if( Type.isString( _value ) === true && data.value !== _value ){\r
4708                                 for( ; i < l; ++i ){\r
4709                                         _option = list[ i ];\r
4710                                         if( _value === _option.value ){\r
4711                                                 data.value = _value;\r
4712                                                 data.index = i;\r
4713                                                 data.elmValue.data = _option.displayValue;\r
4714                                                 if( data.focus === true ){\r
4715                                                         OptionControl.update( this, _value );\r
4716                                                 };\r
4717                                                 data.onUpdate && AsyncCall.add( data.groupData.apiuser, data.onUpdate, _value, this );\r
4718                                                 break;\r
4719                                         };\r
4720                                 };\r
4721                         };\r
4722                         return data.value;\r
4723                 },\r
4724                 selectIndex : function(){\r
4725                         var data = UIItemPrivateData.get( this );\r
4726                         return data.selectIndex;\r
4727                 },\r
4728                 createOption : function( _displayValue, _value, _isSelected ){\r
4729                         var data   = UIItemPrivateData.get( this ),\r
4730                                 option = null,\r
4731                                 list   = data.optionList,\r
4732                                 i      = list.length,\r
4733                                 _option, i;\r
4734                         _value      = _value || _displayValue;\r
4735                         _isSelected = !!_isSelected;\r
4736                         for( ; i; ){\r
4737                                 _option = list[ --i ];\r
4738                                 if( _value === _option.value ){\r
4739                                         option = _option;\r
4740                                         break;\r
4741                                 };\r
4742                         };\r
4743                         if( _isSelected === true ){\r
4744                                 data.selectIndex   = list.length;\r
4745                                 data.elmValue.data = _displayValue;\r
4746                         };                      \r
4747                         option === null && list.push( new OptionDataClass( _displayValue, _value, _isSelected ) );\r
4748                 },\r
4749                 destroy : function(){\r
4750                         var data   = UIItemPrivateData.get( this );\r
4751                         data.focus === true && OptionControl.hide( this );\r
4752                         // this.blur();\r
4753                         // MouseEvent.remove( data.groupData.apiuser, data.elm );\r
4754                         data.optionList.length = 0;\r
4755                         data.destroy();\r
4756                 }\r
4757         };\r
4758         var OptionDataClass = function( displayValue, value, isCurrent ){\r
4759                 this.displayValue = displayValue;\r
4760                 this.value        = value || displayValue;\r
4761                 this.current      = isCurrent;\r
4762                 displayValue = value = null;\r
4763         };\r
4764 \r
4765         var OptionControl = ( function(){\r
4766                 var ELM_OPTION_WRAPPER = ( function(){\r
4767                                 var ret = document.createElement( 'div' );\r
4768                                 ret.className = 'option-container';\r
4769                                 return ret;\r
4770                         })(),\r
4771                         ELM_OPTION_ORIGIN = ( function(){\r
4772                                 var ret = document.createElement( 'a' );\r
4773                                 ret.appendChild( document.createTextNode( 'option' ) );\r
4774                                 ret.href = '#';\r
4775                                 return ret;\r
4776                         })();\r
4777 \r
4778                 var OptionClass = function( option ){\r
4779                         this.elm     = ELM_OPTION_ORIGIN.cloneNode( true );\r
4780                         this.data    = option;\r
4781                         this.init();\r
4782                 };\r
4783                 OptionClass.prototype = {\r
4784                         init: function(){\r
4785                                 ELM_OPTION_WRAPPER.appendChild( this.elm );\r
4786                                 this.elm.firstChild.data = this.data.displayValue;\r
4787                                 this.current( this.data.current );\r
4788                                 MouseEvent.add( SUPER_USER_KEY, this.elm, 'mousedown', onOptionSelect );// onclick では 選択ボックス 隠すように body に設定した onmouseup が先に動いてしまう!\r
4789                         },\r
4790                         current: function( _current ){\r
4791                                 this.elm.className = _current === true ? CLASSNAME_COMBOBOX_OPTION_CURRENT : CLASSNAME_COMBOBOX_OPTION;\r
4792                                 this.data.current  = _current;\r
4793                                 currentOption      = _current === true ? this : currentOption;\r
4794                         },\r
4795                         destroy: function(){\r
4796                                 MouseEvent.remove( SUPER_USER_KEY, this.elm );\r
4797                                 Util.removeAllChildren( this.elm );\r
4798                                 ELM_OPTION_WRAPPER.removeChild( this.elm );\r
4799                                 delete this.elm;\r
4800                                 delete this.data;\r
4801                         }\r
4802                 };\r
4803                 \r
4804                 function onOptionSelect( e ){\r
4805                         var i = 0,\r
4806                                 l = OPTION_LIST.length,\r
4807                                 _option;\r
4808                         for( ; i < l; ++i ){\r
4809                                 _option = OPTION_LIST[ i ];\r
4810                                 if( this === _option.elm ){\r
4811                                         updateCurrrentOption( _option.data.value, true );\r
4812                                         currentCombobox.blur();\r
4813                                         break;\r
4814                                 };\r
4815                         };\r
4816                         return false;\r
4817                 };\r
4818                 \r
4819                 var OPTION_LIST     = [],\r
4820                         currentCombobox = null,\r
4821                         apiuser,\r
4822                         elm,\r
4823                         currentOption,\r
4824                         currentIndex;\r
4825                 \r
4826                 function updateCurrrentOption( _value, _updateCombobox ){\r
4827                         var _option,\r
4828                                 i = OPTION_LIST.length;\r
4829                         for( ; i; ){\r
4830                                 _option = OPTION_LIST[ --i ];\r
4831                                 if( _value === _option.data.value ){\r
4832                                         currentOption && currentOption.current( false );\r
4833                                         _option.current( true );\r
4834                                         currentOption = _option;\r
4835                                         currentIndex  = i;\r
4836                                         _updateCombobox === true && currentCombobox.value( _value );\r
4837                                         break;\r
4838                                 };\r
4839                         };\r
4840                 };\r
4841                 function bodyMouseupHandler(){\r
4842                         currentCombobox.blur();\r
4843                         OptionControl.hide( currentCombobox );\r
4844                 };\r
4845                 function updateWrapperPosition(){\r
4846                         var position = Util.getAbsolutePosition( elm );\r
4847 \r
4848                         ELM_OPTION_WRAPPER.style.cssText = [\r
4849                                 'width:', elm.offsetWidth - 2, 'px;',\r
4850                                 'left:',  position.x, 'px;',\r
4851                                 'top:',   position.y + elm.offsetHeight, 'px;'\r
4852                         ].join( '' );\r
4853                 };\r
4854                 function change( e ){\r
4855                         var l   = OPTION_LIST.length,\r
4856                                 i   = currentIndex + ( e.keyCode === 40 ? -1 : 1 );\r
4857                         if( currentCombobox === null || l < 2 ) return;\r
4858                         i = i < 0 ?\r
4859                                         l - 1 :\r
4860                                         i < l ? i : 0;\r
4861                         updateCurrrentOption( OPTION_LIST[ i ].data.value, true );\r
4862                         return false;\r
4863                 };\r
4864                 return {\r
4865                         show: function( data ){\r
4866                                 var combobox = data.item,\r
4867                                         list     = data.optionList,\r
4868                                         i        = 0,\r
4869                                         l        = list.length;\r
4870                                 if( currentItem !== combobox || currentCombobox === combobox ) return;\r
4871                                 currentCombobox && currentCombobox.blur();\r
4872                                 \r
4873                                 apiuser         = data.groupData.apiuser;\r
4874                                 currentCombobox = combobox;\r
4875                                 elm             = data.elmBox;\r
4876                                 \r
4877                                 for( ; i < l; ++i ){\r
4878                                         OPTION_LIST.unshift( new OptionClass( list[ i ] ) );\r
4879                                 };\r
4880                                 MouseEvent.add( SUPER_USER_KEY, document, 'mouseup', bodyMouseupHandler );\r
4881                                 KeyEvent.add( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, change, 38 );\r
4882                                 KeyEvent.add( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, change, 40 );\r
4883                                 //KeyEvent.add( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, onEnter, 13 );\r
4884                                 //KeyEvent.updateCurrentListener( SUPER_USER_KEY );\r
4885                                 \r
4886                                 body.appendChild( ELM_OPTION_WRAPPER );\r
4887                                 \r
4888                                 updateCurrrentOption( combobox.value(), false );\r
4889                                 updateWrapperPosition();\r
4890                                 \r
4891                                 SystemTimer.add( SUPER_USER_KEY, updateWrapperPosition, 500 );\r
4892                         },\r
4893                         hide: function( _combobox ){\r
4894                                 if( currentCombobox !== _combobox || currentCombobox === null ) return;\r
4895 \r
4896                                 var _option;\r
4897                                 while( _option = OPTION_LIST.shift() ){\r
4898                                         _option.destroy();\r
4899                                 };\r
4900                                 \r
4901                                 body.removeChild( ELM_OPTION_WRAPPER );\r
4902                                 \r
4903                                 MouseEvent.remove( SUPER_USER_KEY, document, 'mouseup', bodyMouseupHandler );\r
4904                                 KeyEvent.remove( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, change );\r
4905                                 KeyEvent.remove( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, change );\r
4906                                 //KeyEvent.remove( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, onEnter );\r
4907                                 //KeyEvent.updateCurrentListener( apiuser );\r
4908                                 \r
4909                                 SystemTimer.remove( SUPER_USER_KEY, updateWrapperPosition, 500 );\r
4910                                 \r
4911                                 apiuser         = null;\r
4912                                 currentCombobox = null;\r
4913                                 currentOption   = null;\r
4914                                 currentIndex    = 0;                            \r
4915                         },\r
4916                         onEnter: function(){\r
4917                                 currentCombobox.value( currentOption.data.value );\r
4918                                 //currentCombobox.blur();\r
4919                                 //OptionControl.hide( currentCombobox );\r
4920                         },\r
4921                         update: function( data, _value ){\r
4922                                 if( currentCombobox !== data.item || currentItem !== data.item ) return;\r
4923                                 if( currentOption.data.value === _value ) return;\r
4924                                 updateCurrrentOption( _value, true );\r
4925                         },\r
4926                         onWindowResize: function( _w, _h ){\r
4927                                 currentCombobox && AsyncCall.add( apiuser, updateWrapperPosition );\r
4928                         }\r
4929                 };\r
4930         })();\r
4931         \r
4932         var UIGroupPrivateData = function(){};\r
4933         UIGroupPrivateData.prototype = {\r
4934                 apiuser  : null,\r
4935                 node     : null,\r
4936                 uigroup  : null,\r
4937                 itemList : null,\r
4938                 visible  : true,\r
4939                 enabled  : true,\r
4940                 init     : function( apiuser, node, uigroup ){\r
4941                         this.apiuser  = apiuser;\r
4942                         this.node     = node;\r
4943                         this.uigroup  = uigroup;\r
4944                         this.itemList = [];\r
4945                         UIGroupPrivateData.list.push( this );\r
4946                 },\r
4947                 destroy  : function(){\r
4948                         \r
4949                 }\r
4950         };\r
4951         UIGroupPrivateData.list = [];\r
4952         UIGroupPrivateData.get  = function( uigroup ){\r
4953                 var list = UIGroupPrivateData.list,\r
4954                         i    = list.length;\r
4955                 for( ; i; ){\r
4956                         if( list[ --i ].uigroup === uigroup ) return list[ i ];\r
4957                 };\r
4958                 return null;\r
4959         };\r
4960         \r
4961         var UIGroupClass = function( apiuser, node ){\r
4962                 ( new UIGroupPrivateData() ).init( apiuser, node, this );\r
4963         };\r
4964         UIGroupClass.prototype = {\r
4965                 focus : function( _value ){\r
4966                         var data = UIGroupPrivateData.get( this );\r
4967                         /*\r
4968                         if( _value === true ){\r
4969                                 if( currentItem ){\r
4970                                         start( apiuser, self, currentItem );\r
4971                                 } else\r
4972                                 if( itemList.length > 0 ){\r
4973                                         start( apiuser, self, itemList[ 0 ] );\r
4974                                 };\r
4975                         } else\r
4976                         if( _value === false ){\r
4977                                 finish( apiuser, self, currentItem );\r
4978                         } else\r
4979                         */\r
4980                         if( _value && Util.getIndex( data.itemList, _value ) !== -1 ){\r
4981                                 // currentItem = _value;\r
4982                                 currentList = data.itemList;\r
4983                         };\r
4984                         return currentUi === this; \r
4985                 },\r
4986                 blur : function(){\r
4987                         var data = UIGroupPrivateData.get( this );\r
4988                         if( currentList === data.itemList ){\r
4989                                 currentList = null;\r
4990                         };\r
4991                 },\r
4992                 createInputText : function( elmWrapper, onUpdate, validater ){\r
4993                         var data     = UIGroupPrivateData.get( this ),\r
4994                                 elmValue = Util.getElementsByClassName( elmWrapper, 'editable-value' )[ 0 ],\r
4995                                 ret;\r
4996                         if( elmValue ){\r
4997                                 ret = new TextInputClass( data, elmWrapper, elmValue, onUpdate, validater );\r
4998                                 data.itemList.push( ret );\r
4999                                 return ret;\r
5000                         };\r
5001                         alert( 'error createInputText' );\r
5002                 },\r
5003                 createButton : function( elm, onClick ){\r
5004                         var data = UIGroupPrivateData.get( this ),\r
5005                                 ret  = new ButtonClass( data, elm, onClick );\r
5006                         data.itemList.push( ret );\r
5007                         return ret;\r
5008                 },\r
5009                 createFileInput : function( elm, onUpdate, validater, elmFileInputReal ){\r
5010                         var data     = UIGroupPrivateData.get( this ),\r
5011                                 elmValue = Util.getElementsByClassName( elm, 'fileinput-value' )[ 0 ],\r
5012                                 ret;\r
5013                         if( elmValue ){\r
5014                                 ret = new FileInputClass( data, elm, onUpdate, validater, elmFileInputReal, elmValue );\r
5015                                 data.itemList.push( ret );\r
5016                                 return ret;\r
5017                         };\r
5018                         return ret;\r
5019                 },\r
5020                 createCombobox : function( elm, onUpdate, optionList ){\r
5021                         var data = UIGroupPrivateData.get( this ),\r
5022                                 ret  = new ComboBoxClass( data, elm, onUpdate, optionList );\r
5023                         data.itemList.push( ret );\r
5024                         return ret;\r
5025                 },\r
5026                 createCheckBox : function(){\r
5027                         \r
5028                 },\r
5029                 createRadio : function(){\r
5030                         \r
5031                 },\r
5032                 createSlider : function(){\r
5033                         \r
5034                 },\r
5035                 visible : function( v ){\r
5036                         var data = UIGroupPrivateData.get( this );\r
5037                         if( Type.isBoolean( v ) === true && data.visible !== v ){\r
5038                                 for( var i = data.itemList.length; i; ){\r
5039                                         data.itemList[ --i ].visible( v );\r
5040                                 };\r
5041                                 data.visible = v;\r
5042                                 data.node.disabled( !( data.enabled && v ) );\r
5043                         };\r
5044                         return data.visible;\r
5045                 },\r
5046                 enabled : function( v ){\r
5047                         var data = UIGroupPrivateData.get( this );\r
5048                         if( Type.isBoolean( v ) === true && data.enabled !== v ){\r
5049                                 for( var i = data.itemList.length; i; ){\r
5050                                         data.itemList[ --i ].enabled( v );\r
5051                                 };\r
5052                                 data.enabled = v;\r
5053                                 data.node.disabled( !( data.visible && v ) );\r
5054                         };\r
5055                         return data.enabled;\r
5056                 },\r
5057                 destroy : function(){\r
5058                         var data = UIGroupPrivateData.get( this ),\r
5059                                 _item;\r
5060                         if( currentUi === this ){\r
5061                                 currentItem.blur();\r
5062                                 // finish( UIItemPrivateData.get( currentItem ) );\r
5063                         };                      \r
5064                         while( _item = data.itemList.shift() ){\r
5065                                 _item.destroy();\r
5066                         };\r
5067                         data.destroy();\r
5068                 }\r
5069         };\r
5070         \r
5071         function start( data ){\r
5072                 if( currentItem !== data.item ){\r
5073                         currentUi !== data.groupData.uigroup && currentUi && currentUi.blur();\r
5074                         \r
5075                         currentItem !== null && currentItem.blur();\r
5076                         \r
5077                         currentUser = data.groupData.apiuser;\r
5078                         currentUi   = data.groupData.uigroup;\r
5079                         currentItem = data.item;\r
5080                         \r
5081                         currentUi.focus( currentItem );\r
5082                         \r
5083                         // if( currentUser !== _apiuser ) {\r
5084                                 KeyEvent.add( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, onKeyDown, 13 );\r
5085                                 KeyEvent.add( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, onKeyDown, 27 );\r
5086                                 KeyEvent.add( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, onKeyDown,  9 );\r
5087                                 KeyEvent.updateCurrentListener( SUPER_USER_KEY );\r
5088                         // };\r
5089                 };\r
5090         }\r
5091         function finish( data ){\r
5092                 if( currentItem === data.item ){\r
5093                         currentUi.blur();\r
5094                         \r
5095                         currentUser = null;\r
5096                         currentUi   = null;\r
5097                         currentItem = null;\r
5098                         currentList = null;\r
5099                         \r
5100                         KeyEvent.remove( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, onKeyDown, 13 );\r
5101                         KeyEvent.remove( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, onKeyDown, 27 );\r
5102                         KeyEvent.remove( SUPER_USER_KEY, Const.KEY.EVENT.KEY_DOWN, onKeyDown,  9 );\r
5103                         KeyEvent.updateCurrentListener( data.groupData.apiuser );\r
5104                 };\r
5105         };\r
5106 \r
5107         function onKeyDown( e ){\r
5108                 if( currentItem === null ) return true;\r
5109                 var keyCode = e.keyCode,\r
5110                         index   = Util.getIndex( currentList, currentItem );\r
5111                 if( keyCode === 13 || keyCode === 27 || keyCode === 9 || keyCode === 18 || e.altKey === true ){ // 13.return 27.esc 9.tab 18.alt\r
5112                         keyCode === 9  && tabShift( index, e.shiftKey === true ? -1 : 1 );\r
5113                         keyCode === 13 && currentItem instanceof ComboBoxClass && OptionControl.onEnter();\r
5114                         keyCode === 13 && tabShift( index, 1 );                 \r
5115                         currentItem && currentItem.blur( keyCode );\r
5116                         return false;\r
5117                 };\r
5118         };\r
5119 \r
5120         function tabShift( index, way ){\r
5121                 var l = currentList.length,\r
5122                         i = index + way,\r
5123                         item;\r
5124                 if( l < 2 ) return;\r
5125                 while( i !== index ){\r
5126                         i = i < 0 ?\r
5127                                 l - 1 :\r
5128                                 i < l ? i : 0; // 0 < i < l\r
5129                         item = currentList[ i ];\r
5130                         if( item.enabled() === true && item.visible() === true ){\r
5131                                 AsyncCall.add( currentUser, item.focus, null, item );\r
5132                                 return;\r
5133                         };\r
5134                         i += way;\r
5135                 };\r
5136         };\r
5137         \r
5138         return {\r
5139                 createUIGroup: function( apiuser, node ){\r
5140                         var uid  = apiuser.getUID(),\r
5141                                 list = UI_LIST[ uid ],\r
5142                                 ui   = new UIGroupClass( apiuser, node );\r
5143                         if( Type.isArray( list ) === false ){\r
5144                                 list = UI_LIST[ uid ] = [];\r
5145                         };\r
5146                         list.push( ui );\r
5147                         return ui;\r
5148                 },\r
5149                 onWindowResize: function( w, h ){\r
5150                         windowW = w;\r
5151                         windowH = h;\r
5152                         currentItem instanceof ComboBoxClass && OptionControl.onWindowResize( w, h );\r
5153                         currentItem instanceof TextInputClass && TextInputManager.onWindowResize( w, h );\r
5154                         currentItem instanceof FileInputClass && FileInputManager.onWindowResize( w, h );\r
5155                 },\r
5156                 onCurrentApplicationChange: function( _apiuser ){\r
5157                         currentList = UI_LIST[ _apiuser.getUID() ];\r
5158                 },\r
5159                 onApplicationShutdown: function( _apiuser ){\r
5160                         KeyEvent.remove( _apiuser );\r
5161                 },\r
5162                 onSystemShutdown: function(){\r
5163                         \r
5164                 }\r
5165         };\r
5166 })();\r
5167 \r
5168 var UIForm = ( function(){\r
5169         var FORM_LIST           = [];\r
5170         var CLASSNAME_FORM      = 'uiform-invisible';\r
5171         var CLASSNAME_FILE_WRAP = 'ui-fileinput-wrapper';\r
5172         var FormItemData = function(){};\r
5173     var windowW, windowH;\r
5174         FormItemData.prototype = {\r
5175                 formData : null,\r
5176                 uiItem   : null,\r
5177                 init : function( formData, uiItem ){\r
5178                         this.formData = formData;\r
5179                         this.uiItem   = uiItem;\r
5180                 },\r
5181                 onUpdate : function( v ){\r
5182                         // var index = Util.getIndex( this.formData.itemList, this );\r
5183                 }\r
5184         };\r
5185         \r
5186         var FormPrivateData = function(){};\r
5187         FormPrivateData.prototype = {\r
5188                 apiuser  : null,\r
5189                 node     : null,\r
5190                 form     : null,\r
5191                 elmForm  : null,\r
5192                 itemList : null,\r
5193                 visible  : true,\r
5194                 enabled  : true,\r
5195                 init     : function( apiuser, from, node, elm, elmForm ){\r
5196                         this.apiuser      = apiuser;\r
5197                         this.form         = form;\r
5198                         this.ui           = apiuser.createUIGroup( node );\r
5199                         this.node         = node;\r
5200                         this.elm          = elm;\r
5201                         this.elmForm      = elmForm;\r
5202                         this.itemList     = [];\r
5203                         elmForm.className = CLASSNAME_FORM;\r
5204                         FormPrivateData.list.push( this );\r
5205                         \r
5206                         var forms = Util.copyArray( elmForm.getElementsByTagName( '*' ) ),\r
5207                                 l     = forms.length,\r
5208                                 i     = 0,\r
5209                                 items = 'input,select,textarea,button',\r
5210                                 form, data, el, wrap;\r
5211                         for( ; i<l; ++i ){\r
5212                                 form = forms[ i ];\r
5213                                 if( form.nodeType !== 1 ) continue;\r
5214                                 switch( form.tagName.toLowerCase() ){\r
5215                                         case 'input':\r
5216                                                 switch( form.type.toLowerCase() ){\r
5217                                                         case 'text':\r
5218                                                                 break;\r
5219                                                         case 'file':\r
5220                                                                 el = document.createElement( 'div' );\r
5221                                                                 el.className = 'uiform-file-container';\r
5222                                                                 el.appendChild( document.createElement( 'div' ) );\r
5223                                                                 el.appendChild( document.createElement( 'div' ) );\r
5224                                                                 el.firstChild.className = 'uiform-label';\r
5225                                                                 el.lastChild.className  = 'uiform-file fileinput-value';\r
5226                                                                 // opera9 don't work for opera9;\r
5227                                                                 //el = Util.pullHtmlAsTemplete( '<div class="uiform-file-container"><div class="uiform-label"></div><div class="uiform-file fileinput-value"></div></div>' );\r
5228                                                                 elm.appendChild( el );\r
5229                                                                 data = new FormItemData();\r
5230                                                                 wrap = document.createElement( 'div' );\r
5231                                                                 form.parentNode.insertBefore( wrap, form );\r
5232                                                                 wrap.className = CLASSNAME_FILE_WRAP;\r
5233                                                                 wrap.appendChild( form );\r
5234                                                                 data.init( this, this.ui.createFileInput( el, data.onUpdate, null, form ) );\r
5235                                                                 this.itemList.push( data );\r
5236                                                                 break;\r
5237                                                         case 'button':\r
5238                                                                 break;\r
5239                                                         default:\r
5240                                                                 continue;\r
5241                                                 };\r
5242                                                 break;\r
5243                                         case 'select':\r
5244                                                 break;\r
5245                                         case 'button':\r
5246                                                 break;\r
5247                                         case 'textarea':\r
5248                                                 break;\r
5249                                         default:\r
5250                                                 continue;\r
5251                                 };\r
5252                         };\r
5253                 },\r
5254                 destroy  : function(){\r
5255                         \r
5256                 }\r
5257         };\r
5258         FormPrivateData.list = [];\r
5259         FormPrivateData.get  = function( from ){\r
5260                 var list = FormPrivateData.list,\r
5261                         i    = list.length;\r
5262                 for( ; i; ){\r
5263                         if( list[ --i ].form === form ) return list[ i ];\r
5264                 };\r
5265                 return null;\r
5266         };\r
5267         \r
5268         var FormClass = function( apiuser, node, elm, elmForm ){\r
5269                 ( new FormPrivateData() ).init( apiuser, this, node, elm, elmForm );\r
5270         };\r
5271         FormClass.prototype = {\r
5272                 createTextInput : function(){\r
5273                         \r
5274                 },\r
5275                 createMultiLineInput : function(){\r
5276                         \r
5277                 },\r
5278                 createFileInput : function(){\r
5279                         \r
5280                 },\r
5281                 createButton : function(){\r
5282                         \r
5283                 },\r
5284                 createComboBox : function(){\r
5285                         \r
5286                 },\r
5287                 submit : function(){\r
5288                         \r
5289                 }\r
5290         };\r
5291         \r
5292         return {\r
5293                 createForm: function( apiuser, nodeOrElm, opt_elmForm ){\r
5294                         var uid  = apiuser.getUID(),\r
5295                                 list = FORM_LIST[ uid ],\r
5296                                 node, elm, form;\r
5297                         if( PointingDeviceEventTree.isNodeInstance( nodeOrElm ) === true ){\r
5298                                 node = nodeOrElm;\r
5299                                 elm  = PointingDeviceEventTree._getNodePrivateData( nodeOrElm ).elm;\r
5300                         } else {\r
5301                                 // App が eventTree を持っている?\r
5302                                 // App が eventTree を持っていない\r
5303                                 elm  = nodeOrElm;\r
5304                         };  \r
5305                         form = new FormClass( apiuser, node, elm, opt_elmForm );\r
5306                         if( Type.isArray( list ) === false ){\r
5307                                 list = FORM_LIST[ uid ] = [];\r
5308                         };\r
5309                         list.push( form );\r
5310                         return form;\r
5311                 },\r
5312                 onWindowResize: function( w, h ){\r
5313                         windowW = w;\r
5314                         windowH = h;\r
5315                         currentItem instanceof ComboBoxClass && OptionControl.onWindowResize( w, h );\r
5316                         currentItem instanceof TextInputClass && TextInputManager.onWindowResize( w, h );\r
5317                         currentItem instanceof FileInputClass && FileInputManager.onWindowResize( w, h );\r
5318                 },\r
5319                 onCurrentApplicationChange: function( _apiuser ){\r
5320                 },\r
5321                 onApplicationShutdown: function( _apiuser ){\r
5322                 },\r
5323                 onSystemShutdown: function(){\r
5324                         \r
5325                 }\r
5326         };\r
5327 })();\r
5328 \r
5329 var Finder = ( function(){\r
5330         var FINDER_LIST              = [],\r
5331                 ELM_ORIGIN_LOCATION_ITEM = Util.pullHtmlAsTemplete( '<div class="finder-location-item"></div>' ),\r
5332                 HTML_FINDER_ICON = ( function(){\r
5333                         return ( UA.isIE === true && UA.ieVersion < 8 ?\r
5334                         [\r
5335                                 '<div class="finder-icon fnder-icon-ie7">',\r
5336                                         '<div class="finder-icon-handle"></div>',\r
5337                                         '<div class="file-icon"><div></div></div>',\r
5338                                         '<span class="finder-icon-cell finder-icon-ie-filename">',\r
5339                                                 '<span class="finder-icon-vertical-middle-outer">',\r
5340                                                         '<span class="finder-icon-vertical-middle-inner">',\r
5341                                                                 '<span class="finder-icon-filename break-word">file name</span>',\r
5342                                                         '</span>',\r
5343                                                 '</span>',\r
5344                                         '</span>',\r
5345                                         '<span class="finder-icon-cell finder-icon-ie-summary">',\r
5346                                                 '<span class="finder-icon-vertical-middle-outer">',\r
5347                                                         '<span class="finder-icon-vertical-middle-inner">',\r
5348                                                                 '<span class="finder-icon-summary break-word">file descriptiion</span>',\r
5349                                                         '</span>',\r
5350                                                 '</span>',\r
5351                                         '</span>',\r
5352                                         '<div class="finder-icon-down"></div>',\r
5353                                 '</div>'\r
5354                         ] :\r
5355                         [\r
5356                                 '<div class="finder-icon fnder-icon-modern">',\r
5357                                         '<div class="finder-icon-handle"></div>',\r
5358                                         '<div class="file-icon"><div></div></div>',\r
5359                                         '<div class="finder-icon-filename break-word">file name</div>',\r
5360                                         '<div class="finder-icon-summary break-word">file descriptiion</div>',\r
5361                                         '<div class="finder-icon-down">&gt;</div>',\r
5362                                 '</div>'\r
5363                         ] ).join( '' );\r
5364                 })(),\r
5365                 ELM_ORIGIN_FINDER_ICON = Util.pullHtmlAsTemplete( HTML_FINDER_ICON ),\r
5366                 ICON_HEIGHT            = Util.getElementSize( ELM_ORIGIN_FINDER_ICON ).height;\r
5367         \r
5368         // t : 時間\r
5369     // b : 開始の値(開始時の座標やスケールなど)\r
5370     // c : 開始と終了の値の差分\r
5371     // d : Tween(トゥイーン)の合計時間\r
5372 \r
5373         function easeOutQuad( t, b, c, d ){\r
5374                 t /= d;\r
5375                 return -c * t*( t-2 ) + b;\r
5376         };\r
5377         \r
5378 /**\r
5379  * FinderIconClass\r
5380  */\r
5381         var FinderIconClass = function(){};\r
5382         FinderIconClass.prototype = {\r
5383                 finderData       : null,\r
5384                 file             : null,\r
5385                 elm              : null,\r
5386                 node             : null,\r
5387                 _index           : -1,\r
5388                 _style           : -1,\r
5389                 init : function( page, file, w, index, style ){\r
5390                         if( !this.elm ) this.elm  = ELM_ORIGIN_FINDER_ICON.cloneNode( true );\r
5391 \r
5392                         if( this.page !== page ){\r
5393                                 this.page = page;\r
5394                                 page.elm.appendChild( this.elm );\r
5395                                 this.node && this.node.remove();\r
5396                                 this.node = page.node.createNode( this.elm, false, true, 'finder-icon-hover', '' );\r
5397                         };\r
5398                         if( this.file !== file ){\r
5399                                 this.file && this.file.destroy();\r
5400                                 this.file   = file;\r
5401                                 this._index = index;\r
5402                                 this.draw( w );\r
5403                                 return;\r
5404                         };\r
5405                         if( this._index !== index ){\r
5406                                 this._index = index;\r
5407                                 this.resize( w );\r
5408                         };\r
5409                 },\r
5410                 index : function( _index ){     \r
5411                         return this._index;\r
5412                 },\r
5413                 style : function( _style ){\r
5414                         return this._style;\r
5415                 },\r
5416                 draw : function( w ){\r
5417                         var file       = this.file,\r
5418                                 elm        = this.elm,\r
5419                                 thumb      = file.getThumbnail(),\r
5420                                 elmThumb   = Util.getElementsByClassName( elm, 'file-icon' )[ 0 ].firstChild,\r
5421                                 elmName    = Util.getElementsByClassName( elm, 'finder-icon-filename' )[ 0 ],\r
5422                                 elmDesc    = Util.getElementsByClassName( elm, 'finder-icon-summary' )[ 0 ];\r
5423                         if( thumb.image ){\r
5424                                 elmThumb.className = 'has-thumbnail';\r
5425                                 elmThumb.style.backgroundImage = [ 'url(', thumb.image, ')' ].join( '' );\r
5426                         } else {\r
5427                                 elmThumb.className = thumb.className;\r
5428                                 elmThumb.style.backgroundImage = '';\r
5429                         };\r
5430                         \r
5431                         elmName.firstChild.data = file.getName();\r
5432                         elmDesc.firstChild.data = file.getSummary();\r
5433                         \r
5434                         this.resize( w );\r
5435                 },\r
5436                 resize : function( w ){\r
5437                         this.node.update( 0, this._index * ICON_HEIGHT, w );\r
5438                 },\r
5439                 onEditorClick : function( e ){\r
5440                         this.onEditorCallback && this.onEditorCallback( this.file, this.file.editorApplicationList()[ 0 ] );\r
5441                         return false;\r
5442                 },\r
5443                 onViwerClick : function( e ){\r
5444                         this.onViewerCallback && this.onViewerCallback( this.file, this.file.viewerApplicationList()[ 0 ] );\r
5445                         return false;\r
5446                 },\r
5447                 onActionClick : function( e ){\r
5448                         this.onActionCallback && this.onActionCallback( this.file );\r
5449                         return false;\r
5450                 },\r
5451                 destroy : function(){\r
5452                         this.elm && this.elm.parentNode.removeChild( this.elm );\r
5453                         this.file && this.file.destroy();\r
5454                         this.node && this.node.remove();\r
5455                         delete this.page;\r
5456                         delete this.file;\r
5457                         delete this.node;\r
5458                         delete this._index;\r
5459                         delete this._style;\r
5460                         FinderIconClass.pool.push( this );\r
5461                 }       \r
5462         };\r
5463         FinderIconClass.pool = [];\r
5464         FinderIconClass.get = function( page, file, w, index, style ){\r
5465                 var _icon = FinderIconClass.pool.length > 0 ? FinderIconClass.pool.shift() : new FinderIconClass();\r
5466                 _icon.init( page, file, w, index, style );\r
5467                 return _icon;\r
5468         };\r
5469 \r
5470 /**\r
5471  * PathClass\r
5472  */\r
5473         var PathClass = function(){};\r
5474         PathClass.prototype = {\r
5475                 finderData : null,\r
5476                 elm        : null,\r
5477                 node       : null,\r
5478                 file       : null,\r
5479                 _index     : null,\r
5480                 w          : 0,\r
5481                 init : function( finderData, file, index ){\r
5482                         if( !this.elm ) this.elm  = ELM_ORIGIN_LOCATION_ITEM.cloneNode( true );\r
5483                         \r
5484                         if( this.finderData !== finderData ){\r
5485                                 this.finderData = finderData;\r
5486                                 finderData.elmPath.appendChild( this.elm );\r
5487                                 this.node && this.node.remove();\r
5488                                 delete this.node;\r
5489                         };\r
5490                         if( this.file !== file ){\r
5491                                 this.file = file;\r
5492                                 this.draw();\r
5493                         };\r
5494                         this._index = index;\r
5495                         if( !this.node ) this.node = finderData.nodePath.createNode( this.elm, false, true, 'finder-path-hover', 'pointer' );\r
5496                 },\r
5497                 draw  : function(){\r
5498                         this.elm.className = 'file-icon-' + this.file.getType();\r
5499                         this.elm.innerHTML = this.file.getName();                       \r
5500                 },\r
5501                 textWidth : function(){\r
5502                         this.elm.style.width = 'auto';\r
5503                         var ret = this.elm.offsetWidth;\r
5504                         this.elm.style.width = '';\r
5505                         return ret + 15;\r
5506                 },\r
5507                 update : function( x, w ){\r
5508                         this.node.update( x - 15, undefined, w );\r
5509                 },\r
5510                 index : function( _index ){\r
5511                         return this._index;\r
5512                 },\r
5513                 destroy : function(){\r
5514                         this.finderData.elmPath.removeChild( this.elm );\r
5515                         this.node && this.node.remove();\r
5516                         \r
5517                         delete this.finderData;\r
5518                         delete this.elm;\r
5519                         delete this.node;\r
5520                         delete this.file;\r
5521                         delete this._index;\r
5522                         PathClass.pool.push( this );\r
5523                 }\r
5524         };\r
5525         PathClass.pool = [];\r
5526         PathClass.get  = function( finderData, file, index ){\r
5527                 var _bread = PathClass.pool.length > 0 ? PathClass.pool.shift() : new PathClass();\r
5528                 _bread.init( finderData, file, index );\r
5529                 return _bread;\r
5530         };\r
5531         \r
5532         \r
5533         /**\r
5534          * Page\r
5535          */\r
5536         var PageClass = function(){};\r
5537         PageClass.prototype = {\r
5538                 nodeRoot     : null,\r
5539                 elmRoot      : null,\r
5540                 elmScroll    : null,\r
5541                 elm          : null,\r
5542                 node         : null,\r
5543                 folder       : null,\r
5544                 iconList     : null,\r
5545                 sliding      : false,\r
5546                 currentX     : 0,\r
5547                 panTime      : 0,\r
5548                 startX       : 0,\r
5549                 offsetX      : 0,\r
5550                 panTotalTime : 0,\r
5551                 isPanOut     : false,\r
5552                 init : function( nodeRoot, elmRoot, elmScroll ){\r
5553                         this.nodeRoot  = nodeRoot;\r
5554                         this.elmRoot   = elmRoot;\r
5555                         this.elmScroll = elmScroll;\r
5556                         \r
5557                         if( this.elm === null ){\r
5558                                 this.elm = document.createElement( 'div' );\r
5559                         };\r
5560                         elmScroll.appendChild( this.elm );\r
5561                         this.elm.style.cssText = 'position:absolute;top:0;';\r
5562                         // this.elm.style.display = 'none';\r
5563                         this.node = this.nodeRoot.createNode( this.elm, true, false );\r
5564                         if( this.iconList === null ){\r
5565                                 this.iconList = [];\r
5566                         };\r
5567                 },\r
5568                 panInReady : function( way ){\r
5569                         this.elm.style.display = '';\r
5570                         var x = this.sliding === true ? this.currentX : way * this.nodeRoot.width();\r
5571                         this.startX       = this.currentX = x;\r
5572                         this.targetX      = 0;\r
5573                         this.offsetX      = -x;\r
5574                         this.panTime      = 0;\r
5575                         this.panTotalTime = 20;\r
5576                         this.sliding      = true;\r
5577                         this.isPanOut     = false;\r
5578                         // this.elm.style.left = x + 'px';\r
5579                         this.node.x( x );\r
5580                 },\r
5581                 panOutReady : function( way ){\r
5582                         var x = -way * this.nodeRoot.width();\r
5583                         this.startX       = this.currentX || 0;\r
5584                         this.targetX      = x;\r
5585                         this.offsetX      = x - this.startX;\r
5586                         this.panTime      = 0;\r
5587                         this.panTotalTime = 20;\r
5588                         this.sliding      = true;\r
5589                         this.isPanOut     = true;\r
5590                 },\r
5591                 pan : function(){\r
5592                         var page = this,\r
5593                                 x    = page.currentX = easeOutQuad( page.panTime, page.startX, page.offsetX, page.panTotalTime );\r
5594                         // page.elm.style.left = x + 'px';\r
5595                         this.node.x( x );\r
5596                         if( page.panTotalTime < ++page.panTime ){\r
5597                                 delete page.panTime;\r
5598                                 delete page.startX;\r
5599                                 delete page.offsetX;                                    \r
5600                                 delete page.panTotalTime;\r
5601                                 delete page.sliding;\r
5602                                 if( this.isPanOut === true ) this.elm.style.display = 'none';\r
5603                         };\r
5604                 },\r
5605                 draw : function( folder ){\r
5606                         var _w = this.nodeRoot.width();\r
5607                         this.folder = folder;\r
5608                         var data     = this,\r
5609                                 iconList = data.iconList,\r
5610                                 i        = 0,\r
5611                                 j        = 0,\r
5612                                 l        = folder.getChildFileLength(),\r
5613                                 m        = iconList.length,\r
5614                                 scrollY  = -this.nodeRoot.scrollY(),\r
5615                                 rootH    = scrollY + this.nodeRoot.height(),\r
5616                                 icon;\r
5617 \r
5618                         for( ; i < l; ++i ){\r
5619                                 if( ( i + 1 ) * ICON_HEIGHT < scrollY || rootH < i * ICON_HEIGHT ) continue;\r
5620                                 if( j < m ){\r
5621                                         iconList[ j ].init( this, folder.getChildFileAt( i ), _w, i, data.style );\r
5622                                 } else {\r
5623                                         iconList.push( FinderIconClass.get( this, folder.getChildFileAt( i ), _w, i, data.style ) );\r
5624                                 };\r
5625                                 j++;\r
5626                         };\r
5627                         data.elmRoot.className    = folder.getState() === Const.FILE.STATE.LOADING ? 'finder-body loading' : 'finder-body';\r
5628                         // data.elmRoot.style.height = ( data.h - data.headH ) + 'px';\r
5629                         \r
5630                         while( j < iconList.length ) iconList.pop().destroy();\r
5631                         data.elmScroll.style.height = ( l * ICON_HEIGHT ) + 'px';\r
5632                 },\r
5633                 onScroll : function(){\r
5634                         var _w       = this.nodeRoot.width();\r
5635                         \r
5636                         var data     = this,\r
5637                                 iconList = data.iconList,\r
5638                                 folder   = this.folder,\r
5639                                 i        = 0,\r
5640                                 j        = 0,\r
5641                                 l        = folder.getChildFileLength(),\r
5642                                 scrollY  = -this.nodeRoot.scrollY(),\r
5643                                 rootH    = scrollY + this.nodeRoot.height(),\r
5644                                 startIndex = 0 < iconList.length ? iconList[ 0 ]._index : 0,\r
5645                                 icon;\r
5646                         \r
5647                         // console.log( ' > ' + scrollY + ' , ' + rootH )\r
5648                         for( ; i < l; ++i ){\r
5649                                 if( ( i + 1 ) * ICON_HEIGHT < scrollY || rootH < i * ICON_HEIGHT ){\r
5650                                         if( iconList.length <= j ) continue;\r
5651                                         icon = iconList[ j ];\r
5652                                         if( icon._index !== i ) continue;\r
5653                                         icon.destroy();\r
5654                                         iconList.splice( j, 1 );\r
5655                                         continue;\r
5656                                 };\r
5657                                 if( iconList.length <= j || iconList[ j ]._index !== i ){\r
5658                                         if( i < startIndex ){\r
5659                                                 iconList.splice( j, 0, FinderIconClass.get( this, folder.getChildFileAt( i ), _w, i, data.style ) );                    \r
5660                                         } else\r
5661                                         if( startIndex + iconList.length <= i ){\r
5662                                                 iconList.push( FinderIconClass.get( this, folder.getChildFileAt( i ), _w, i, data.style ) );                    \r
5663                                         };                                      \r
5664                                 };\r
5665                                 ++j;\r
5666                         };\r
5667                         \r
5668                         //while( j < iconList.length ) iconList.pop().destroy();\r
5669                 },\r
5670                 resize : function( w ){\r
5671                         var list = this.iconList,\r
5672                                 i    = list.length;\r
5673                         for( ; i; ) list[ --i ].resize( w );\r
5674                 },\r
5675                 destroy : function(){\r
5676                         var icon;\r
5677                         while( icon = this.iconList.shift() ) icon.destroy();\r
5678                         \r
5679                         this.elm.parentNode.removeChild( this.elm );\r
5680                 }\r
5681         };\r
5682         \r
5683         var ApplicationButton = function(){};\r
5684         ApplicationButton.prototype = {\r
5685                 elm     : null,\r
5686                 button  : null,\r
5687                 app     : null,\r
5688                 file    : null,\r
5689                 fileUID : -1,\r
5690                 init    : function( ui, elmParent, app, file ){\r
5691                         if( this.elm === null ){\r
5692                                 this.elm = document.createElement( 'div' );\r
5693                         };\r
5694                         elmParent.appendChild( this.elm );\r
5695                         this.elm.className = 'button';\r
5696                         this.elm.innerHTML = app.getDisplayName();\r
5697                         \r
5698                         var that = this;\r
5699                         this.button = ui.createButton( this.elm, function(){\r
5700                                 that.onClick();\r
5701                                 // that = null;\r
5702                         } );\r
5703                         \r
5704                         this.app     = app;\r
5705                         this.file    = file;\r
5706                         this.fileUID = file.getUID();\r
5707                 },\r
5708                 onClick : function(){\r
5709                         this.app.boot( this.file );\r
5710                         return false;\r
5711                 },\r
5712                 destroy : function(){\r
5713                         var elm = this.elm;\r
5714                         elm.parentNode.removeChild( elm );\r
5715                         \r
5716                         this.button.destroy();\r
5717                         //this.kill()\r
5718                         //this.elm = elm;\r
5719                 }\r
5720         };\r
5721         \r
5722         var DetailPageClass = function(){};\r
5723         DetailPageClass.prototype = Util.extend( new PageClass(), {\r
5724                 appButtons : null,\r
5725                 init : function( finderData ){\r
5726                         this.finderData = finderData;\r
5727                         this.apiuser    = finderData.apiuser;\r
5728                         this.nodeRoot   = finderData.nodeRoot;\r
5729                         this.elmRoot    = finderData.elmRoot;\r
5730                         this.elmScroll  = finderData.elmScroll;\r
5731                         \r
5732                         if( this.elm === null ){\r
5733                                 this.elm = Util.pullHtmlAsTemplete( [\r
5734                                         '<div class="finder-detail">',\r
5735                                                 '<div class="file-icon"><div></div></div>',\r
5736                                                 '<div class="finder-detail-filename break-word">file name</div>',\r
5737                                                 '<div class="finder-detail-summary break-word">file descriptiion</div>',\r
5738                                                 '<div>View this file</div>',\r
5739                                                 '<div class="viewer-apps"></div>',                                              \r
5740                                                 '<div>Edit this file</div>',\r
5741                                                 '<div class="editor-apps"></div>',\r
5742                                         '</div>'\r
5743                                 ].join( '' ) );\r
5744                         };\r
5745                         this.elm.style.display = 'none';\r
5746                         this.elmScroll.appendChild( this.elm );\r
5747                         this.node = this.nodeRoot.createNode( this.elm, true, false );\r
5748                         \r
5749                         this.ui = this.apiuser.createUIGroup( this.node );\r
5750                         this.appButtons = [];\r
5751                 },\r
5752                 draw : function( file ){\r
5753                         var elm        = this.elm,\r
5754                                 thumb      = file.getThumbnail(),\r
5755                                 elmThumb   = Util.getElementsByClassName( elm, 'file-icon' )[ 0 ].firstChild,\r
5756                                 elmName    = Util.getElementsByClassName( elm, 'finder-detail-filename' )[ 0 ],\r
5757                                 elmDesc    = Util.getElementsByClassName( elm, 'finder-detail-summary' )[ 0 ],\r
5758                                 tmpButtons = Util.copyArray( this.appButtons ),\r
5759                                 apps, app, elmContainer, button;\r
5760                         if( thumb.image ){\r
5761                                 elmThumb.className = 'has-thumbnail';\r
5762                                 elmThumb.style.backgroundImage = [ 'url(', thumb.image, ')' ].join( '' );\r
5763                         } else {\r
5764                                 elmThumb.className = thumb.className;\r
5765                                 elmThumb.style.backgroundImage = '';\r
5766                         };\r
5767                         \r
5768                         elmName.firstChild.data = file.getName();\r
5769                         elmDesc.firstChild.data = file.getSummary();\r
5770                         this.node.width( this.nodeRoot.width() );\r
5771                         this.node.height( this.nodeRoot.height() );\r
5772                         \r
5773                         this.appButtons.length = 0;\r
5774                         \r
5775                         apps         = file.viewerApplicationList();\r
5776                         elmContainer = Util.getElementsByClassName( elm, 'viewer-apps' )[ 0 ];\r
5777                         for( i = 0; i < apps.length; ++i ){\r
5778                                 button = 0 < tmpButtons.length ? tmpButtons.shift() : new ApplicationButton();\r
5779                                 button.init( this.ui, elmContainer, apps[ i ], file );\r
5780                                 this.appButtons.push( button );\r
5781                         };\r
5782                         apps         = file.editorApplicationList();\r
5783                         elmContainer = Util.getElementsByClassName( elm, 'editor-apps' )[ 0 ];\r
5784                         for( i = 0; i < apps.length; ++i ){\r
5785                                 button = 0 < tmpButtons.length ? tmpButtons.shift() : new ApplicationButton();\r
5786                                 button.init( this.ui, elmContainer, apps[ i ], file );\r
5787                                 this.appButtons.push( button );\r
5788                         };\r
5789                         \r
5790                         while( button = tmpButtons.shift() ) button.destroy();\r
5791                         \r
5792                         this.resize();\r
5793                 },\r
5794                 pan : function(){\r
5795                         var page = this,\r
5796                                 x    = page.currentX = easeOutQuad( page.panTime, page.startX, page.offsetX, page.panTotalTime );\r
5797                         // page.elm.style.left = x + 'px';\r
5798                         this.node.x( x );\r
5799                         if( page.panTotalTime < ++page.panTime ){\r
5800                                 delete page.panTime;\r
5801                                 delete page.startX;\r
5802                                 delete page.offsetX;                                    \r
5803                                 delete page.panTotalTime;\r
5804                                 delete page.sliding;\r
5805                                 if( this.isPanOut === true ) this.elm.style.display = 'none';\r
5806                         };\r
5807                 },\r
5808                 onScroll : function(){\r
5809                         \r
5810                 },\r
5811                 resize : function(){\r
5812                         this.elmScroll.style.height = this.nodeRoot.height() + 'px';\r
5813                 },\r
5814                 destroy : function(){\r
5815                         var button;\r
5816                         while( button = this.appButtons.shift() ) button.destroy();\r
5817                         this.ui.destroy();\r
5818                         this.node.remove();\r
5819                 }\r
5820         });\r
5821         \r
5822 /**\r
5823  * FinderPrivateData\r
5824  */\r
5825         var FinderPrivateData = Class.create(\r
5826                 Class.PRIVATE_DATA, {\r
5827                 finder       : null,\r
5828                 apiuser      : null,\r
5829                 elmRoot      : null,\r
5830                 nodeRoot     : null,\r
5831                 elmScroll    : null,\r
5832                 elmPath      : null,\r
5833                 nodePath     : null,\r
5834                 tree         : null,\r
5835                 onSelect     : null,\r
5836                 viewerOption : null,\r
5837                 editorOption : null,\r
5838                 pathList     : null,\r
5839                 headH        : 0,\r
5840                 iconW        : 0,\r
5841                 iconH        : 0,\r
5842                 style        : 0,\r
5843                 pageIcons1   : null,\r
5844                 pageIcons2   : null,\r
5845                 panInPage    : null,\r
5846                 panOutPage   : null,\r
5847                 pageDetail   : null,\r
5848                 currentFile  : null,\r
5849                 Constructor : function( finder, apiuser, elm, tree, onSelect, viewerOption, editorOption ){\r
5850                         this.finder       = finder;\r
5851                         this.apiuser      = apiuser;\r
5852                         if( PointingDeviceEventTree.isNodeInstance( elm ) === true ){\r
5853                                 this.nodeRoot = elm;\r
5854                                 this.elmRoot  = PointingDeviceEventTree._getNodePrivateData( elm ).elm;\r
5855                         } else {\r
5856                                 // App が eventTree を持っている?\r
5857                                 // App が eventTree を持っていない\r
5858                                 this.elmRoot  = elm;\r
5859                         };\r
5860                         this.nodeRoot.addEventListener( 'click', this.onIconClick, this );\r
5861                         this.nodeRoot.addEventListener( 'scroll', this.onScroll, this );\r
5862                         \r
5863                         this.elmScroll    = document.createElement( 'div' );\r
5864                         this.elmRoot.appendChild( this.elmScroll );\r
5865                         this.elmScroll.className     = 'finder-elm-scroll';\r
5866                         this.elmScroll.style.cssText = 'width:100%;overflow:hidden;';\r
5867                         \r
5868                         this.tree         = tree;\r
5869                         this.onSelect     = onSelect;\r
5870                         this.viewerOption = viewerOption;\r
5871                         this.editorOption = editorOption;\r
5872                         \r
5873                         var size          = Util.getElementSize( ELM_ORIGIN_FINDER_ICON );\r
5874                         this.iconW        = size.width;\r
5875                         this.iconH        = size.height;\r
5876                         \r
5877                         tree.addTreeEventListener( Const.TREE.EVENT.UPDATE, this.draw, this );\r
5878                         Util.addClass( this.elmRoot, 'finder-body' );\r
5879                         \r
5880                         if( this.panInPage === null ){\r
5881                                 this.pageIcons1 = new PageClass();\r
5882                                 this.pageIcons2 = new PageClass();\r
5883                                 this.pageDetail = new DetailPageClass();\r
5884                         };\r
5885                         this.pageIcons1.init( this.nodeRoot, this.elmRoot, this.elmScroll );\r
5886                         this.pageIcons2.init( this.nodeRoot, this.elmRoot, this.elmScroll );\r
5887                         this.pageDetail.init( this );\r
5888                 },\r
5889                 onIconClick : function( e ){\r
5890                         if( this.panInPage === this.pageDetail ) return;\r
5891                         \r
5892                         var target = e.target,\r
5893                                 list   = this.panInPage.iconList,\r
5894                                 i, icon,\r
5895                                 file;\r
5896                         if( target === this.nodeRoot ) return;\r
5897                         for( i = list.length; i; ){\r
5898                                 icon = list[ --i ];\r
5899                                 if( icon.node === target ){\r
5900                                         i = icon._index;\r
5901                                         file = this.currentFile.getChildFileAt( i );\r
5902                                         if( target.width() - 30 < e.layerX ){\r
5903                                                 this.tree.down( i );\r
5904                                                 this.draw( this.w, this.h, 1, true );\r
5905                                         } else\r
5906                                         if( file.getChildFileLength() !== -1 || file.getType() === Const.FILE.TYPE.FOLDER ){\r
5907                                                 this.tree.down( i );\r
5908                                                 this.draw( this.w, this.h, 1 );\r
5909                                         } else\r
5910                                         if( Type.isFunction( this.onSelect ) === true ){ /* && this.onSelect( file ) === true */\r
5911                                                 this.onSelect( file );\r
5912                                         } else {\r
5913                                                 this.tree.down( i );\r
5914                                                 this.draw( this.w, this.h, 1 );\r
5915                                         };\r
5916                                         file.destroy();\r
5917                                         break;\r
5918                                 };\r
5919                         };\r
5920                 },\r
5921                 onScroll : function( e ){\r
5922                         this.panInPage.onScroll( e );\r
5923                 },\r
5924                 onPathClick : function( e ){\r
5925                         var target = e.target,\r
5926                                 i      = target.nodeIndex();\r
5927                         if( target === this.nodePath || this.nodePath.numNode() - 1 === i ) return;\r
5928                         this.tree.up( i );\r
5929                         this.draw( this.w, this.h, -1 );\r
5930                 },\r
5931                 draw : function( w, h, way, showDetail ){\r
5932                         var data = this, page;\r
5933                         data.w = w = Type.isFinite( w ) === true ? w : data.w;\r
5934                         data.h = h = Type.isFinite( h ) === true ? h : data.h;\r
5935                         \r
5936                         var file     = this.currentFile = this.tree.getCurrentFile(),\r
5937                                 isFolder = showDetail !== true && ( file.getChildFileLength() !== -1 || file.getType() === Const.FILE.TYPE.FOLDER );\r
5938                         \r
5939                         data.elmPath && data.drawPath( w );\r
5940                         page = this.panInPage;\r
5941                         if( Type.isNumber( way ) === true ){\r
5942                                 if( page.sliding === false ){\r
5943                                         if( isFolder === true ){\r
5944                                                 this.panInPage = page === this.pageIcons1 ? this.pageIcons2 : ( page === this.pageIcons2 ? this.pageIcons1 : this.panOutPage );\r
5945                                         } else {\r
5946                                                 this.panInPage = this.pageDetail;\r
5947                                         };\r
5948                                         this.panOutPage = page;\r
5949                                 };\r
5950                                 this.panInPage.panInReady( way );\r
5951                                 //this.panInPage.elm.className = 'panIN';\r
5952                                 this.panOutPage.panOutReady( way );\r
5953                                 //this.panOutPage.elm.className = 'panOut';\r
5954                                 this.nodeRoot.disabled( true );\r
5955                                 SystemTimer.add( this.apiuser, this.tick, 16, false, this );\r
5956                         } else {\r
5957                                 if( isFolder === true ){\r
5958                                         this.panInPage = page === null ? this.pageIcons1 : page;\r
5959                                 } else {\r
5960                                         this.panInPage = this.pageDetail;\r
5961                                 };\r
5962                         };\r
5963                         this.panInPage.draw( file );\r
5964                         \r
5965                         data.nodeRoot.invalidateScrollbar();\r
5966                 },\r
5967                 tick : function(){\r
5968                         if( this.panInPage.sliding === false && this.panOutPage.sliding === false ){\r
5969                                 SystemTimer.remove( this.apiuser, this.tick );\r
5970                                 this.nodeRoot.disabled( false );\r
5971                                 this.nodeRoot.invalidateScrollbar();\r
5972                                 return;\r
5973                         };\r
5974                         this.panInPage.sliding === true && this.panInPage.pan();\r
5975                         this.panOutPage.sliding  === true && this.panOutPage.pan();\r
5976                 },\r
5977                 drawPath : function( w ){\r
5978                         if( !this.elmPath.parentNode ) return;\r
5979                         w = this.nodePath.width();\r
5980                         var data      = this,\r
5981                                 tree      = data.tree,\r
5982                                 pathList  = data.pathList,\r
5983                                 i         = 0,\r
5984                                 l         = tree.hierarchy() + 1,\r
5985                                 m         = pathList.length,\r
5986                                 wList     = [],\r
5987                                 totalW    = 0,\r
5988                                 minW      = FinderPrivateData.MIN_PATH_WIDTH,\r
5989                                 file, path, pathW, offset, remove, pathX = 0, fit = false;\r
5990                         \r
5991                         for( ; i < l; ++i ){\r
5992                                 file = i !== l - 1 ? tree.getParentFileAt( i ) : this.currentFile;\r
5993                                 if( i < m ){\r
5994                                         pathList[ i ].init( this, file, i );\r
5995                                 } else {\r
5996                                         pathList.push( PathClass.get( this, file, i ) );\r
5997                                 };\r
5998                         };\r
5999                         while( l < pathList.length ) pathList.pop().destroy();\r
6000                         \r
6001                         for( i = l; i; ){\r
6002                                 pathW = pathList[ --i ].textWidth();\r
6003                                 wList.push( pathW );\r
6004                                 totalW += pathW;\r
6005                         };\r
6006                         \r
6007                         //if( minW * ( l + 1 ) * 1.2 < w ){\r
6008                                 console.log( totalW + ' , ' + w )\r
6009                                 while( true ){\r
6010                                         if( fit === true ) break;\r
6011                                         for( i = 0; i < l; ++i ){\r
6012                                                 offset = totalW - w;\r
6013                                                 if( offset <= 0 ){\r
6014                                                         fit = true;\r
6015                                                         break;\r
6016                                                 };\r
6017                                                 remove = l - i;\r
6018                                                 remove = offset < remove ? offset : remove;\r
6019                                                 pathW  = wList[ i ];\r
6020                                                 if( pathW - remove < minW ){\r
6021                                                         totalW -= ( pathW - minW );\r
6022                                                         wList[ i ] = minW;\r
6023                                                 } else {\r
6024                                                         wList[ i ] = pathW - remove;\r
6025                                                         totalW -= remove;\r
6026                                                 };\r
6027                                         };\r
6028                                 };\r
6029                                 for( i = 0; i < l; ++i ){\r
6030                                         path  = pathList[ i ];\r
6031                                         pathW = wList[ i ];\r
6032                                         path.update( pathX, pathW );\r
6033                                         pathX += pathW;\r
6034                                 };                      \r
6035                         //} else {\r
6036                                 \r
6037                         //};\r
6038                 },\r
6039                 createPath : function( node ){\r
6040                         if( this.elmPath ) return;\r
6041                         \r
6042                         if( PointingDeviceEventTree.isNodeInstance( node ) === true ){\r
6043                                 this.nodePath = node;\r
6044                                 this.elmPath  = PointingDeviceEventTree._getNodePrivateData( node ).elm;\r
6045                                 \r
6046                                 node.addEventListener( 'click', this.onPathClick, this );\r
6047                                 Util.addClass( this.elmPath, 'finder-path' );\r
6048                                 // this.elmPath  = document.createElement( 'div' );\r
6049                                 // this.elmPath.className = ;\r
6050                                 this.pathList = [];\r
6051                                 // this.headH    = 0;\r
6052                                 AsyncCall.add( this.apiuser, this.draw, null, this );\r
6053                         };\r
6054                 },\r
6055                 onKill : function(){\r
6056                         this.tree.removeTreeEventListener( Const.TREE.EVENT.UPDATE, this.draw );\r
6057 \r
6058                         if( this.pathList ){\r
6059                                 while( this.pathList.length > 0 ) this.pathList.shift().destroy();\r
6060                         };\r
6061                         \r
6062                         this.pageIcons1.destroy();\r
6063                         this.pageIcons2.destroy();\r
6064                         this.pageDetail.destroy();\r
6065                         this.nodeRoot.remove();\r
6066                         \r
6067                         FINDER_LIST.splice( Util.getIndex( FINDER_LIST, this.finder ), 1 );\r
6068                         var data = ApplicationPrivateData.get( this.apiuser ),\r
6069                                 list = data.finderList,\r
6070                                 i    = Util.getIndex( list, this.finder );\r
6071                         i !== -1 && list.splice( i, 1 );\r
6072                 }\r
6073         });\r
6074         FinderPrivateData.MIN_PATH_WIDTH = 25;\r
6075 \r
6076 /**\r
6077  * FinderClass\r
6078  */\r
6079         var Finder = Class.create(\r
6080                 FinderPrivateData, {\r
6081                 Constructor : function( application, elmRoot, tree, onSelect, viewerOption, editorOption ){\r
6082                         Finder.newPrivateData( this, this, application, elmRoot, tree, onSelect, viewerOption, editorOption );\r
6083                 },\r
6084                 MIN_WIDTH  : 200,\r
6085                 MIN_HEIGHT : 200,\r
6086                 resize : function( w, h ){\r
6087                         var data = Finder.getPrivateData( this );\r
6088                         data.panInPage && data.panInPage.resize( w );\r
6089                 },\r
6090                 createPath : function( node ){\r
6091                         return Finder.getPrivateData( this ).createPath( node );\r
6092                 },\r
6093                 destroy : function(){\r
6094                         this.kill();\r
6095                 }\r
6096         });\r
6097 \r
6098         return {\r
6099                 init: function(){\r
6100                         \r
6101                 },\r
6102                 create: function( application, elmTarget, tree, onSelect, viewerOption, editorOption ){\r
6103                         //if( Application.isApplicationInstance( _application ) === false ) return;\r
6104                         \r
6105                         var finder = new Finder( application, elmTarget, tree, onSelect, viewerOption, editorOption );\r
6106                         FINDER_LIST.push( finder );\r
6107                         return finder;\r
6108                 },\r
6109                 registerFinderHead: function(){\r
6110                         \r
6111                 },\r
6112                 registerFinderPane: function( _finderPane ){\r
6113                         \r
6114                 },\r
6115                 isFinderInstance: function( _finder ){\r
6116                         return _finder instanceof Finder;\r
6117                 },\r
6118                 isFinderPaneInstance: function(){\r
6119                         \r
6120                 },\r
6121                 isFinderHeadInstance: function(){\r
6122                 }\r
6123         };\r
6124 })();\r
6125 \r
6126 \r
6127 /*\r
6128  * -- len, %\r
6129  * marginBottom, marginLeft, marginRight, marginTop, margin\r
6130  * padding, paddingBottom, paddingLeft, paddingRight, paddingTop\r
6131  * fontSize, textIndent\r
6132  * height, width\r
6133  * bottom, left, right, top                     (len, %)\r
6134  *\r
6135  * -- len\r
6136  * borderBottomWidth, borderLeftWidth, borderRightWidth, borderTopWidth, borderWidth,\r
6137  * letterSpacing\r
6138  *\r
6139  * -- color\r
6140  * backgroundColor\r
6141  * borderBottomColor, borderLeftColor, borderRightColor, borderTopColor, borderColor\r
6142  * color\r
6143  *\r
6144  * -- special\r
6145  * clip                 rect(0px, 40px, 40px, 0px);\r
6146  * backgroundPosition   (len, %)\r
6147  * opacity\r
6148  * lineHeight           (len, %, num)\r
6149  * zIndex                       ( order )\r
6150  */\r
6151 \r
6152 var DHTML = ( function(){\r
6153         \r
6154         var TICKET_ARRAY = [],\r
6155                 fpms         = 50,\r
6156                 round        = Math.round,\r
6157                 cround       = function( v ){ return round( v * 100 ) / 100 };\r
6158         \r
6159         function startAnimation( _elm, _cssObject, _onComplete, _onEnterFrame, _numFrames ){\r
6160                 var _ticket, i = TICKET_ARRAY.length;\r
6161                 for( ; i; ){\r
6162                         _ticket = TICKET_ARRAY[ --i ];\r
6163                         if( _ticket.elm === _elm ){\r
6164                                 return;\r
6165                         };\r
6166                 };\r
6167                 \r
6168                 var _currentValues     = [],\r
6169                         _offsetValues      = [],\r
6170                         _endValues         = [],\r
6171                         _targetProperties  = [],\r
6172                         _units             = [];\r
6173                 var target, current,\r
6174                         inlineStyle    = CSS.getInlineStyle( _elm ),\r
6175                         currentStyle   = CSS.getWrappedStyle( _elm ),\r
6176                         targetStyle    = CSS.getWrappedStyle( _elm, _cssObject );\r
6177                         targetStyle.pxPerEm = currentStyle.get( 'fontSize' )._toPx();\r
6178                 for( var p in _cssObject ){\r
6179                         p       = Util.camelize( p );\r
6180                         target  = targetStyle.get( p );\r
6181                         current = currentStyle.get( p );\r
6182 \r
6183                         if( target.isValid() === false || current.isValid() === false || current.equal( target ) !== false ){\r
6184                                 target.clear();\r
6185                                 current.clear();\r
6186                                 continue;\r
6187                         };\r
6188                         \r
6189                         current.convert( target );\r
6190                         // alert( current.getValue() + ' , ' + target.getValue() )\r
6191                         _currentValues.push( current.getValue() );\r
6192                         _offsetValues.push( current.getOffset( target ) );\r
6193                         _endValues.push( target.getValue() );\r
6194                         _targetProperties.push( p );\r
6195                         _units.push( target.getUnit() );\r
6196 \r
6197                         // IE has trouble with opacity if it does not have layout\r
6198                         // Force it by setting the zoom level                   \r
6199                         if( p === 'opacity' && SPECIAL.hasLayout ){\r
6200                                 if( SPECIAL.hasLayout( _elm ) === false ) inlineStyle.zoom = 1;\r
6201                                 inlineStyle.filter = current.getValueText();\r
6202                         } else {\r
6203                                 inlineStyle[ p ]   = current.getValueText();\r
6204                         };\r
6205                         \r
6206                         target.clear();\r
6207                         current.clear();\r
6208                 };\r
6209                 \r
6210                 var i, cssTexts = [];\r
6211                 for( i = 0; i < _numFrames; ++i ){\r
6212                         if( i < _numFrames - 1 ){\r
6213                                 tickValue( _currentValues, _offsetValues, _numFrames );\r
6214                                 cssTexts.push( createCssText( _currentValues, _targetProperties, targetStyle, inlineStyle ) );\r
6215                         } else {\r
6216                                 cssTexts.push( createCssText( _endValues, _targetProperties, targetStyle, inlineStyle ) );\r
6217                         };\r
6218                 };\r
6219                 \r
6220                 TICKET_ARRAY.push( new AnimationTaskClass(\r
6221                         _elm, cssTexts,\r
6222                         Type.isFunction( _onComplete ) === true   ? _onComplete   : null,\r
6223                         Type.isFunction( _onEnterFrame ) === true ? _onEnterFrame : null,\r
6224                         _numFrames\r
6225                 ) );\r
6226                 \r
6227                 currentStyle.clear();\r
6228                 targetStyle.clear();            \r
6229                 SystemTimer.add( SUPER_USER_KEY, onEnterFrame, 1000 / fpms );\r
6230         };\r
6231         \r
6232         function tickValue( current, offset, numFrames ){\r
6233                 if( Type.isArray( current ) === true ){\r
6234                         var ret, i = current.length;\r
6235                         for( ; i; ){\r
6236                                 --i;\r
6237                                 ret = tickValue( current[ i ], offset[ i ], numFrames );\r
6238                                 if( Type.isNumber( ret ) === true ) current[ i ] = ret;\r
6239                         };\r
6240                 } else {\r
6241                         return current + offset / numFrames;\r
6242                 };\r
6243         };\r
6244         function createCssText( update, props, style, inline ){\r
6245                 var prop;\r
6246                 for( var i = props.length; i; ){\r
6247                         prop = style.get( props[ --i ] );\r
6248                         prop.setValue( update[ i ] );\r
6249                         inline[ Util.uncamelize( prop.name ) ] = prop.getValueText();\r
6250                         //if( prop.name === 'backgroundColor' ) alert( prop.getValueText() + '|' + update[ i ].join( ',') )\r
6251                         prop.clear();\r
6252                 };\r
6253                 return CSS.toCssText( inline );\r
6254         };\r
6255         \r
6256         function onEnterFrame(){\r
6257                 var _ticket, l,\r
6258                         i = 0;\r
6259                 while( i < TICKET_ARRAY.length ){\r
6260                         _ticket = TICKET_ARRAY[ i ];\r
6261                         l       = _ticket.cssTexts.length;\r
6262                         _ticket.elm.style.cssText = _ticket.cssTexts.shift();\r
6263                         if( l === 1 ){\r
6264                                 _ticket.onComplete && _ticket.onComplete();\r
6265                                 delete _ticket.elm;\r
6266                                 delete _ticket.cssTexts;\r
6267                                 delete _ticket.onComplete;\r
6268                                 delete _ticket.onEnterFrame;\r
6269                                 delete _ticket.numFrame;\r
6270                                 TICKET_ARRAY.splice( i, 1 );\r
6271                         } else {\r
6272                                 _ticket.onEnterFrame && _ticket.onEnterFrame( l / _ticket.numFrame );\r
6273                                 ++i;\r
6274                         };\r
6275                 };\r
6276                 if( TICKET_ARRAY.length === 0 ){\r
6277                         SystemTimer.remove( SUPER_USER_KEY, onEnterFrame );\r
6278                 };\r
6279         };\r
6280         \r
6281         var AnimationTaskClass = function( elm, cssTexts, onEnterFrame, onComplete, numFrame ){\r
6282                 this.elm          = elm;\r
6283                 this.cssTexts     = cssTexts;\r
6284                 this.onEnterFrame = onEnterFrame;\r
6285                 this.onComplete   = onComplete;\r
6286                 this.numFrame     = numFrame;\r
6287         };\r
6288         \r
6289         var VisualEffectClass = function( elm ){\r
6290                 this.elm = elm;\r
6291         };\r
6292         VisualEffectClass.prototype = {\r
6293                 anime : function( _cssObject, _onComplete, _onEnterFrame, _time ){\r
6294                         var _numFrames = Math.floor( _time / fpms );\r
6295                         startAnimation( this.elm, _cssObject, _onComplete, _onEnterFrame, _numFrames );\r
6296                 },\r
6297                 fadeIn : function(){\r
6298                         \r
6299                 },\r
6300                 fadeOut : function(){\r
6301                         \r
6302                 },\r
6303                 update : function( x, y, w, h ){\r
6304                         var _cssText = this.elm.style.cssText;\r
6305                 }\r
6306         };\r
6307         \r
6308         return {\r
6309                 create: function( application, _elm ){\r
6310                         return new VisualEffectClass( _elm );\r
6311                 },\r
6312                 isInstanceOfVisualEffect: function( _instance){\r
6313                         return _instance instanceof VisualEffectClass;\r
6314                 }\r
6315         }\r
6316 })();\r
6317 \r
6318 \r
6319 /* --------------------------------------------\r
6320  * \r
6321  */\r
6322 \r
6323         Application.onCurrentApplicationChange( SUPER_USER_KEY );\r
6324         \r
6325         SERVICE_LIST.push( MouseEvent );\r
6326         \r
6327         new EventTicketClass( window, 'unload', function(){\r
6328                 var _service;\r
6329                 while( SERVICE_LIST.length > 0 ){\r
6330                         _service = SERVICE_LIST.shift();\r
6331                         Type.isFunction( _service.onSystemShutdown ) === true && _service.onSystemShutdown();\r
6332                 }\r
6333         });\r
6334         // beforeunload\r
6335 \r
6336 \r
6337 /* ---------------------------------------------\r
6338  * broadcast to global\r
6339  */\r
6340         window.gOS = {};\r
6341         \r
6342         gOS.registerApplication = Application.register;\r
6343         gOS.registerDriver      = File.registerDriver;\r
6344         \r
6345 })( window, document );\r