OSDN Git Service

Version 0.6.58, X.UI.HBox is working.
[pettanr/clientJs.git] / 0.5.x / javascripts / peta-apps.js
1 /*
2  * pettanR peta.apps.js
3  *   version 0.5.49
4  *   
5  * author:
6  *   itozyun
7  * licence:
8  *   3-clause BSD
9  */
10
11 ( function( pettanr, gOS, window, document, undefined ){
12 /*
13  * PettanR service driver.
14  */
15         var MyAuthorID = 'current_author' in window ? current_author.id : ( pettanr.CONST.SERVER_SUPPORT === false ? 1 : -1 ),
16                 MyArtistID = 'current_artist' in window ? current_artist.id : ( pettanr.CONST.SERVER_SUPPORT === false ? 1 : -1 ),
17                 Driver     = null,
18                 FileAPI    = gOS.registerDriver( function(){
19                         var self = Driver = this,
20                                 unregisteredFileDataJsonList = [];
21                         
22                         function onLoadJson( file, json ){
23                                 var access = FileAPI.getFileDataAccess( file ),
24                                         data   = access !== null ? access.DATA : null,
25                                         i, l, args;
26                                 if( data === null ){
27                                         onErrorJson( file );
28                                         return;
29                                 };
30                                 data.state = Const.FILE.STATE.OK;
31                                 if( Type.isArray( json ) === true ){
32                                         for( i = 0, l = json.length; i < l; ++i ){
33                                                 registerFileData( json[ i ], data );
34                                         };
35                                 } else
36                                 if( Type.isNumber( json.id ) === true ){
37                                         registerFileData( json, data );
38                                 };
39                                 while( 0 < unregisteredFileDataJsonList.length ){
40                                         args = unregisteredFileDataJsonList.shift();
41                                         registerFileData( args[ 0 ], args[ 1 ] );
42                                         //alert( unregisteredFileDataJsonList.length )
43                                 };
44                                 file.dispatchEvent( FileAPI.createFileEvent( Const.FILE.EVENT.GET_SEQENTIAL_FILES, file, 'children', null ) );
45                         };
46                         function onErrorJson( file ){ 
47                                 var data = FileAPI.getFileData( file );
48                                 if( data !== null){
49                                         data.state = Const.FILE.STATE.ERROR;
50                                 };
51                                 file.dispatchEvent( FileAPI.createFileEvent( Const.FILE.EVENT.GET_SEQENTIAL_FILES, file, 'children', null ) );
52                         };
53                         function registerFileData( json, parent ){
54                                 var data;
55                                 switch( parent ){
56                                         // Comic
57                                         case FILE_DATA_COMICS_ROOT    :
58                                         case FILE_DATA_MY_COMICS_ROOT :
59                                         case COMIC_ARRAY              :
60                                                 json.type = FILE_TYPE.COMIC;
61                                                 data = createFileData( json, COMIC_ARRAY, 'title' );
62                                                 if( data.json !== null ) data.json = true;
63                                                 if( data.author ){
64                                                         addChildData( data.author, data );
65                                                         data.author.id === MyAuthorID && addChildData( FILE_DATA_MY_COMICS_ROOT, data );
66                                                 };
67                                                 parent === FILE_DATA_COMICS_ROOT && addChildData( FILE_DATA_LATEST_COMICS, data );
68                                                 break;
69                                         
70                                         case STORY_ARRAY :
71                                                 json.type = FILE_TYPE.STORY;
72                                                 data = createFileData( json, STORY_ARRAY, 'x,y,z,t' );
73                                                 addChildData( FILE_DATA_STORY_ROOT, data );
74                                                 break;
75                                         
76                                         // Lisence
77                                         case FILE_DATA_LISENCE :
78                                         case LICENSE_ARRAY :
79                                                 json.type = FILE_TYPE.LICENSE;
80                                                 data = createFileData( json, LICENSE_ARRAY, 'name,caption,url,system_picture_id,settings,credit_pictures' );
81                                                 addChildData( FILE_DATA_LISENCE, data );
82                                                 break;
83                                         // License Group
84                                         case FILE_DATA_LISENCE_GROUP :
85                                         case LICENSE_GROUP_ARRAY     :
86                                                 json.type = FILE_TYPE.LICENSE_GROUP;
87                                                 data = createFileData( json, LICENSE_GROUP_ARRAY, 'name,caption,url,classname' );
88                                                 addChildData( FILE_DATA_LISENCE_GROUP, data );
89                                                 break;
90                                         
91                                         // Speech Balloon Templete
92                                         case FILE_DATA_BALLOON_ROOT :
93                                         case BALLOON_TEMPLETE_ARRAY :
94                                                 json.type = FILE_TYPE.BALLOON_TEMPLETE;
95                                                 // register pettanr.balloon
96                                                 pettanr.newBalloon.register( json.settings );
97                                                 data = createFileData( json, BALLOON_TEMPLETE_ARRAY, 'name,caption,classname,settings' );
98                                                 addChildData( FILE_DATA_BALLOON_ROOT, data );
99                                                 break;
100                                         
101                                         // Author
102                                         case FILE_DATA_AUTHOR_ROOT :
103                                         case AUTHOR_ARRAY          :
104                                                 json.type = FILE_TYPE.AUTHOR;
105                                                 data = createFileData( json, AUTHOR_ARRAY, 'name,email,homepage_url' );
106                                                 addChildData( FILE_DATA_AUTHOR_ROOT, data );
107                                                 break;
108                                         
109                                         // Artist
110                                         case FILE_DATA_ARTIST_ROOT :
111                                         case ARTIST_ARRAY          :
112                                                 json.type = FILE_TYPE.ARTIST;
113                                                 data = createFileData( json, ARTIST_ARRAY, 'name,email,homepage_url' );
114                                                 addChildData( FILE_DATA_ARTIST_ROOT, data );
115                                                 break;
116
117                                         case PICTURE_ARRAY :
118                                                 json.type = FILE_TYPE.PICTURE;
119                                                 data = createFileData( json, PICTURE_ARRAY, 'ext,revision,credit,settings' );
120                                                 break;
121                                 
122                                         // Resource Picture
123                                         case FILE_DATA_RESOURCE_PICTURES_ROOT    :
124                                         case FILE_DATA_MY_RESOURCE_PICTURES_ROOT :
125                                         case RESOURCE_PICTURE_ARRAY              :
126                                                 json.type = FILE_TYPE.RESOURCE_PICTURE;
127                                                 data = createFileData( json, RESOURCE_PICTURE_ARRAY, 'ext' );
128                                                 if( data.artist ){
129                                                         addChildData( data.artist, data );
130                                                         data.artist.id === MyArtistID && addChildData( FILE_DATA_MY_RESOURCE_PICTURES_ROOT, data );
131                                                 };
132                                                 break;
133
134                                         // Original Picture
135                                         case FILE_DATA_MY_ORIGINAL_PICTURES_ROOT :
136                                         case ORIGINAL_PICTURE_ARRAY              :
137                                                 json.type = FILE_TYPE.ORIGINAL_PICTURE;
138                                                 data = createFileData( json, ORIGINAL_PICTURE_ARRAY, 'ext,filesize,width,height,md5' );
139                                                 if( data.artist ){
140                                                         // addChildData( data.artist, data );
141                                                         data.artist.id === MyArtistID && addChildData( FILE_DATA_MY_ORIGINAL_PICTURES_ROOT, data );
142                                                 };
143                                                 break;
144                                         // Panel
145                                         case FILE_DATA_PANELS_ROOT    :
146                                         case FILE_DATA_MY_PANELS_ROOT :
147                                         case PANEL_ARRAY              :
148                                                         json.type = FILE_TYPE.PANEL;
149                                                         data = createFileData( json, PANEL_ARRAY, 'border,publish,width,height' );
150                                                         addChildData( FILE_DATA_LATEST_PANELS, data );
151                                                         data.author.id === MyAuthorID && addChildData( FILE_DATA_MY_PANELS_ROOT, data );                                                
152                                                 break;
153                                                 
154                                         // Panel Element
155                                         case PANEL_ELEMENT_ARRAY :
156                                                 json.type = FILE_TYPE.PANEL_ELEMENT;
157                                                 data = createFileData( json, PANEL_ELEMENT_ARRAY, 'caption,url,width,height,x,y,z,t' ); // 画像の分
158                                                 // 噴出しの分
159                                                 // 景色の分
160                                                 break;
161                                                 
162                                         default :
163                                                 if( parent.type === FILE_TYPE.COMIC ){
164                                                         //alert( 'comicstory' )
165                                                         data = registerFileData( json, STORY_ARRAY );
166                                                         //addChildData( parent, data );
167                                                         break;
168                                                 };
169                                                 throw new Error( 'build file error!' ); 
170                                 };
171                                 return data;
172                         };
173                         /*
174                          * 1. すでに一度以上ファイルを取得している場合、そのオブジェクトを取得.または、新規に作成.
175                          * 2. オブジェクトに値をコピー・上書き
176                          * 3. 
177                          */
178                         function createFileData( json, array, copyProps ){
179                                 copyProps = copyProps + ',id,type';
180                                 
181                                 var getIndex  = Util.getIndex,
182                                         id        = json.id,
183                                         data      = getResource( array, id ),
184                                         p, i, l,
185                                         histories, history,
186                                         stories, story,
187                                         elements;
188                                 
189                                 // Copy Props
190                                 copyProps = copyProps.split( ',' );
191                                 for( p in json ){
192                                         if( getIndex( copyProps, p ) !== -1 ) data[ p ] = json[ p ];
193                                 };
194                                 
195                                 // Common
196                                 data.driver = Driver;                           
197                                 if( Type.isString( json.created_at ) === true ) data.created_at = Math.floor( new Date( json.created_at ).getTime() / 1000 );
198                                 if( Type.isString( json.updated_at ) === true ) data.updated_at = Math.floor( new Date( json.updated_at ).getTime() / 1000 );
199                                 
200                                 // 実素材履歴
201                                 histories = json.pictures;
202                                 if( Type.isArray( histories ) === true ){
203                                         for( i = 0, l = histories.length; i < l; ++i ){
204                                                 history = getResource( PICTURE_ARRAY, histories[ i ] );
205                                                 addChildData( data, history );
206                                         };
207                                         data.picture = history;
208                                 };                              
209                                 
210                                 // ストーリー
211                                 stories = json.stories;
212                                 if( Type.isArray( stories ) === true ){
213                                         for( i = 0, l = stories.length; i < l; ++i ){
214                                                 story = getResource( STORY_ARRAY, stories[ i ] );
215                                                 /*
216                                                  * 間違い! t 順に格納
217                                                  */
218                                                 addChildData( data, story );
219                                         };
220                                 };
221
222                                 // パネル要素
223                                 elements = json.elements;
224                                 if( Type.isArray( elements ) === true ){
225                                         for( i = 0, l = elements.length; i<l; ++i ){
226                                                 /*
227                                                  * 間違い! t 順に格納
228                                                  */
229                                                 addChildData( data, getResource( PANEL_ELEMENT_ARRAY, elements[ i ] ) );
230                                         };
231                                 };
232                                 
233                                 // Artist
234                                 if( json.artist || json.artist_id ){
235                                         data.artist = getResource( ARTIST_ARRAY, json.artist || json.artist_id );
236                                 };
237                                         
238                                 // Author
239                                 if( json.author || json.author_id ){
240                                         data.author = getResource( AUTHOR_ARRAY, json.author || json.author_id );
241                                 };
242
243                                 // Comic
244                                 if( json.comic || json.comic_id ){
245                                         data.comic = getResource( COMIC_ARRAY, json.comic || json.comic_id );
246                                 };
247
248                                 // Panel
249                                 if( json.panel || json.panel_id ){
250                                         data.panel = getResource( PANEL_ARRAY, json.panel || json.panel_id );
251                                 };
252
253                                 // 実素材
254                                 if( json.picture || json.picture_id ){
255                                         data.picture = getResource( PICTURE_ARRAY, json.picture || json.picture_id );
256                                 };
257
258                                 // License
259                                 if( json.license || json.license_id ){
260                                         data.license = getResource( LICENSE_ARRAY, json.license || json.license_id );
261                                 };
262
263                                 // License Group
264                                 if( json.license_group || json.license_group_id ){
265                                         data.license_group = getResource( LICENSE_GROUP_ARRAY, json.license_group || json.license_group_id );
266                                 };
267                                 
268                                 // 原画
269                                 if( json.original_picture || json.original_picture_id ){
270                                         data.original_picture = getResource( ORIGINAL_PICTURE_ARRAY, json.original_picture || {
271                                                 id        : json.original_picture_id,
272                                                 ext       : json.ext,
273                                                 filesize  : json.filesize,
274                                                 width     : json.width,
275                                                 height    : json.height,
276                                                 md5       : json.md5,
277                                                 artist    : json.artist,
278                                                 artist_id : json.artist_id
279                                         } );                                            
280                                 };
281                                 
282                                 return data;
283                         };
284                         function addChildData( parent, child ){
285                                 if( Type.isArray( parent.children ) === false ){
286                                         parent.children = [ child ];
287                                         return;
288                                 };
289                                 Util.getIndex( parent.children, child ) === -1 && parent.children.push( child );
290                         };
291                         function getResource( list, IDorOBJECT ){
292                                 var data, id, obj;
293                                 if( Type.isNumber( IDorOBJECT ) === true ){
294                                         id = IDorOBJECT;
295                                 } else
296                                 if( IDorOBJECT && Type.isNumber( IDorOBJECT.id ) === true ){
297                                         obj = IDorOBJECT;
298                                         id  = obj.id;
299                                         unregisteredFileDataJsonList.push( [ obj, list ] );
300                                 } else {
301                                         alert( 'getResource error' + IDorOBJECT.toString() );
302                                         return undefined;
303                                 };
304                                 data = list[ id ];
305                                 if( !data ) data = list[ id ] = { id : id };
306                                 return data;
307                         };
308                         
309                         this.getSeqentialFiles = function( file ){
310                                 var data = FileAPI.getFileData( file ),
311                                         json = data.json || null;
312                                 if( data.type === FILE_TYPE.COMIC && json === true ){
313                                         if( pettanr.CONST.SERVER_SUPPORT === false ){
314                                                 json = [ 'json\/comics_', data.id, '.json' ].join( '' );
315                                         } else {
316                                                 json = [ pettanr.CONST.PETTANR_ROOT_PATH, 'stories\/', data.id, '\/comic.json' ].join( '' );
317                                         };
318                                         data.json = null;
319                                 };
320                                 if( typeof json === 'string' ){
321                                         FileAPI.getJson( file, json, onLoadJson, onErrorJson );
322                                         data.state = Const.FILE.STATE.LOADING;
323                                         if( data.json !== null ) delete data.json;
324                                         return;
325                                 };
326                         };
327                         this.getName = function( file ){
328                                 var data = FileAPI.getFileData( file ),
329                                         type = data !== null ? data.type : null;
330                                 switch( type ){
331                                         case FILE_TYPE.BALLOON :
332                                                 break;
333                                         case FILE_TYPE.PANEL_ELEMENT :
334                                                 return 'パネル要素';
335                                         case FILE_TYPE.RESOURCE_PICTURE :
336                                                 return [ '素材 ' + data.id, '.', data.ext ].join( '' );
337                                         case FILE_TYPE.PICTURE  :
338                                                 return [ '実素材 ' + data.id, '.', data.ext ].join( '' );
339                                         case FILE_TYPE.ORIGINAL_PICTURE :
340                                                 return [ '原画 ', data.id, '.', data.ext ].join( '' );
341                                         case FILE_TYPE.COMIC :
342                                                 return data.title;
343                                         case FILE_TYPE.STORY :
344                                                 return [ 'story id:', data.id, ' ', data.comic ? data.comic.title : 'no comic', ':', data.t ].join( '' );
345                                         case FILE_TYPE.PANEL :
346                                                 return [ 'panel id:', data.id ].join( '' );
347                                         case FILE_TYPE.AUTHOR :
348                                                 return [ data.name, '先生' ].join( '' );
349                                         case FILE_TYPE.ARTIST :
350                                                 return [ data.name, '画伯' ].join( '' );
351                                         case FILE_TYPE.BALLOON_TEMPLETE :
352                                                 return [ data.id, data.caption ].join( ':' );
353                                         case FILE_TYPE.FOLDER :
354                                 };
355                                 return data.name;
356                         };
357                         this.getThumbnail = function( file ){
358                                 var data = FileAPI.getFileData( file ),
359                                         type = data !== null ? data.type : null;
360                                 if( data === FILE_DATA_COMICS_ROOT ) return { className: 'file-type-cabinet' };
361                                 switch( type ){
362                                         
363                                         case FILE_TYPE.PANEL_ELEMENT :
364                                                 return { className: 'file-type-charactor' };
365                                         case FILE_TYPE.RESOURCE_PICTURE :
366                                                 return { image: [ pettanr.CONST.THUMBNAIL_PATH, data.id, '.', data.ext ].join( '' )};
367                                         case FILE_TYPE.PICTURE  :
368                                                 //data = data.original_picture;
369                                                 return { image: [ pettanr.CONST.THUMBNAIL_PATH, data.id, '.', data.ext ].join( '' )};
370                                         case FILE_TYPE.ORIGINAL_PICTURE :
371                                                 return { className: 'file-type-charactor' };                    
372                                                 // return { image: [ pettanr.CONST.THUMBNAIL_PATH, data.id, '.', data.ext ].join( '' )};
373                                         case FILE_TYPE.BALLOON :
374                                                 break;
375                                         case FILE_TYPE.COMIC :
376                                                 return { className: 'file-type-comic' };
377                                         case FILE_TYPE.STORY :
378                                                 data = data.panel;
379                                         case FILE_TYPE.PANEL :
380                                                 return { className: 'file-type-panel' };
381                                         case FILE_TYPE.AUTHOR :
382                                                 return { className: 'file-type-author' };
383                                         case FILE_TYPE.ARTIST :
384                                                 return { className: 'file-type-artist' };
385                                         case FILE_TYPE.BALLOON_TEMPLETE :
386                                                 return { className: 'file-type-balloon' };
387                                         case FILE_TYPE.FOLDER :
388                                                 return { className: 'file-type-folder' };
389                                 };
390                                 return { className: 'file-type-broken' };
391                         };
392                         this.getSummary = function( file ){
393                                 var data = FileAPI.getFileData( file ),
394                                         type = data !== null ? data.type : null;
395                                 if( data === FILE_DATA_COMICS_ROOT ) return 'cabinet file';
396                                 switch( type ){
397                                         case FILE_TYPE.BALLOON :
398                                                 break;
399                                         case FILE_TYPE.PANEL_ELEMENT :
400                                                 return 'caption:' + data.caption + ' url:' + data.url + ' ' + data.width + 'x' + data.height + ' x:' + data.x + ' y:' + data.y + ' z:' + data.z + ' t:' + data.t;
401                                         case FILE_TYPE.RESOURCE_PICTURE :
402                                                 data = data.picture;
403                                         case FILE_TYPE.PICTURE :
404                                                 return '実素材情報 revision:' + data.revision + ' ' + data.credit + ' ' + data.settings;
405                                         case FILE_TYPE.ORIGINAL_PICTURE :
406                                                 return [ '原画情報 ', data.width, 'x', data.height, ', filesize:', data.filesize, ' md5', data.md5 ].join( '' );
407                                         case FILE_TYPE.COMIC :
408                                                 return 'comic id:' + data.id;
409                                         case FILE_TYPE.STORY :
410                                                 data = data.panel;
411                                         case FILE_TYPE.PANEL :
412                                                 return [ 'panel id:', data.id, ', width:', data.width, ', height:', data.height, ', 枠線:', data.border, ', 公開:', data.publish ].join( '' );
413                                         case FILE_TYPE.AUTHOR :
414                                                 return 'author id:' + data.id;
415                                         case FILE_TYPE.ARTIST :
416                                                 return [ 'artist id:', data.id, ' Email:', data.email || 'empty' , ', HP:', data.homepage_url || 'empty' ].join( '' );
417                                         case FILE_TYPE.BALLOON_TEMPLETE :
418                                                 return data.name + ', ' + data.settings;
419                                         case FILE_TYPE.FOLDER :
420                                                 return 'pettanR folder';
421                                 };
422                                 return 'pettanR unknown file';
423                         };
424                         this.read = function( file ){
425                                 var data = FileAPI.getFileData( file ),
426                                         type = data !== null ? data.type : null,
427                                         ret, i, elm;
428                                 switch( type ){
429                                         case FILE_TYPE.COMIC :
430                                                 ret = Util.copy( data );
431                                                 ret.panels = ret.children;
432                                                 if( Type.isArray( ret.panels ) === true ){
433                                                         for( i = ret.panels.length; i; ){
434                                                                 elm = ret.panels[ --i ];
435                                                                 elm.elements = elm.children;
436                                                         };
437                                                 };
438                                                 return ret;
439                                         case FILE_TYPE.STORY :
440                                                 ret = Util.copy( data );
441                                                 ret.panel.elements = ret.panel.children;
442                                                 return ret;
443                                         case FILE_TYPE.PANEL :
444                                                 ret = Util.copy( data );
445                                                 ret.elements = ret.children;
446                                                 return ret;
447                                         case FILE_TYPE.PANEL_ELEMENT :
448                                         case FILE_TYPE.BALLOON :
449                                         case FILE_TYPE.ORIGINAL_PICTURE :
450                                 };
451                         };
452                         this.write = function( file, newData, onUpdate ){
453                                 var data = FileAPI.getFileData( file ),
454                                         type = data !== null ? data.type : null;
455                                 switch( type ){
456                                         case FILE_TYPE.COMIC :
457                                         case FILE_TYPE.PANEL :
458                                         case FILE_TYPE.PANEL_ELEMENT :
459                                         case FILE_TYPE.BALLOON :
460                                         case FILE_TYPE.ORIGINAL_PICTURE :
461                                 };
462                         };
463                         this.viewerApplicationList = function( file ){
464                                 var data = FileAPI.getFileData( file ),
465                                         type = data !== null ? data.type : null;
466                                 if( data === FILE_DATA_MY_ORIGINAL_PICTURES_ROOT ) return [ PremiumSatge ];
467                                 switch( type ){
468                                         case FILE_TYPE.COMIC :
469                                         case FILE_TYPE.PANEL :
470                                         case FILE_TYPE.STORY :
471                                                 return [ Reader ];
472                                         case FILE_TYPE.PANEL_ELEMENT :
473                                         case FILE_TYPE.BALLOON :
474                                         case FILE_TYPE.ORIGINAL_PICTURE :
475                                                 break;
476                                         case FILE_TYPE.ARTIST :
477                                                 return [ PremiumSatge ];
478                                         default :                                               
479                                 };
480                                 return [];
481                         };
482                         this.editorApplicationList = function( file ){
483                                 var data = FileAPI.getFileData( file ),
484                                         type = data !== null ? data.type : null;
485                                 switch( type ){
486                                         case FILE_TYPE.COMIC :
487                                                 return [ Editor, ComicConsole ];
488                                         case FILE_TYPE.PANEL :
489                                                 return [ Editor ];
490                                         case FILE_TYPE.PANEL_ELEMENT :
491                                         case FILE_TYPE.BALLOON :
492                                         case FILE_TYPE.ORIGINAL_PICTURE :
493                                         case FILE_TYPE.ARTIST :
494                                         default :                                               
495                                 };
496                                 return [];
497                         }
498                 }),
499                 Const = FileAPI.getConst(),
500                 FILE_TYPE = Util.extend(
501                         Const.FILE.TYPE,
502                         {
503                                 COMIC            : FileAPI.createFileTypeID(),
504                                 STORY            : FileAPI.createFileTypeID(),
505                                 PANEL            : FileAPI.createFileTypeID(),
506                                 PANEL_ELEMENT    : FileAPI.createFileTypeID(),
507                                 BALLOON          : FileAPI.createFileTypeID(),
508                                 BALLOON_TEMPLETE : FileAPI.createFileTypeID(),  
509                                 ORIGINAL_PICTURE : FileAPI.createFileTypeID(),
510                                 RESOURCE_PICTURE : FileAPI.createFileTypeID(),
511                                 PICTURE          : FileAPI.createFileTypeID(),
512                                 AUTHOR           : FileAPI.createFileTypeID(),
513                                 ARTIST           : FileAPI.createFileTypeID(),
514                                 LICENSE          : FileAPI.createFileTypeID(),
515                                 LICENSE_GROUP    : FileAPI.createFileTypeID(),
516                         }
517                 ),
518                 AUTHOR_ARRAY  = [],
519                 ARTIST_ARRAY  = [],
520                 COMIC_ARRAY   = [],
521                 STORY_ARRAY   = [],
522                 PANEL_ARRAY   = [],
523                 LICENSE_ARRAY = [],
524                 PICTURE_ARRAY = [],
525                 LICENSE_GROUP_ARRAY    = [],
526                 PANEL_ELEMENT_ARRAY    = [],
527                 ORIGINAL_PICTURE_ARRAY = [],
528                 RESOURCE_PICTURE_ARRAY = [],
529                 BALLOON_TEMPLETE_ARRAY = [],
530                 BASIC_LICENSES = 'cc_by,cc_nc,cc_nd,cc_sa,keep_aspect_ratio,no_convert,no_flip,no_resize'.split( ','),
531                 FILE_DATA_SERVICE_ROOT = {
532                         name:           'PettanR root',
533                         type:           FILE_TYPE.FOLDER,
534                         children:       []
535                 },
536                 FILE_DATA_COMICS_ROOT = {
537                         name:           'Comics',
538                         type:           FILE_TYPE.FOLDER,
539                         children:       [],
540                         driver:         Driver,
541                         json:           pettanr.CONST.URL_COMICS_JSON
542                 },
543                 FILE_DATA_PANELS_ROOT = {
544                         name:           'Panels',
545                         type:           FILE_TYPE.FOLDER,
546                         children:       [],
547                         driver:         Driver,
548                         json:           pettanr.CONST.URL_PANELS_JSON
549                 },
550                 FILE_DATA_RESOURCE_PICTURES_ROOT = {
551                         name:           '素材',
552                         type:           FILE_TYPE.FOLDER,
553                         children:       [],
554                         driver:         Driver,
555                         json:           pettanr.CONST.URL_RESOURCE_PICTURES_JSON
556                 },
557                 FILE_DATA_ORIGINAL_PICTURES_ROOT = {
558                         name:           '原画',
559                         type:           FILE_TYPE.FOLDER,
560                         children:       [],
561                         driver:         Driver
562                 },
563                 FILE_DATA_MY_COMICS_ROOT = {
564                         name:           'My Comics',
565                         type:           FILE_TYPE.FOLDER,
566                         children:       [],
567                         driver:         Driver,
568                         id:                     MyAuthorID,
569                         json:       pettanr.CONST.URL_MY_COMICS_JSON
570                 },
571                 FILE_DATA_LATEST_COMICS = {
572                         name:           'Latest Comics',
573                         type:           FILE_TYPE.FOLDER,
574                         children:       []
575                 },
576                 FILE_DATA_STORY_ROOT = {
577                         name:           'Stories',
578                         type:           FILE_TYPE.FOLDER,
579                         children:       [],
580                         driver:         Driver
581                 },
582                 FILE_DATA_LATEST_PANELS = {
583                         name:           'Latest Panels',
584                         type:           FILE_TYPE.FOLDER,
585                         children:       []
586                 },
587                 FILE_DATA_MY_PANELS_ROOT = {
588                         name:           'My Panels',
589                         type:           FILE_TYPE.FOLDER,
590                         children:       [],
591                         driver:         Driver,
592                         json:           pettanr.CONST.URL_MY_PANELS_JSON
593                 },
594                 FILE_DATA_MY_RESOURCE_PICTURES_ROOT = {
595                         name:           'My 素材画像',
596                         type:           FILE_TYPE.FOLDER,
597                         children:       [],
598                         driver:         Driver,
599                         // json:                pettanr.CONST.URL_RESOURCE_PICTURES_JSON,
600                         id:                     MyArtistID
601                 },
602                 FILE_DATA_MY_ORIGINAL_PICTURES_ROOT = {
603                         name:           'My 原画',
604                         type:           FILE_TYPE.FOLDER,
605                         children:       [],
606                         driver:         Driver,
607                         json:           pettanr.CONST.URL_MY_ORIGINAL_PICTURES_JSON,
608                         id:                     MyArtistID
609                 },
610                 FILE_DATA_AUTHOR_ROOT = {
611                         name:           'Authors',
612                         type:           FILE_TYPE.FOLDER,
613                         children:       []
614                 },
615                 FILE_DATA_ARTIST_ROOT = {
616                         name:           'Artists',
617                         type:           FILE_TYPE.FOLDER,
618                         children:       []
619                 },
620                 FILE_DATA_LISENCE_ROOT = {
621                         name:           'Lisence Root',
622                         type:           FILE_TYPE.FOLDER,
623                         children:       []
624                 },
625                 FILE_DATA_LISENCE = {
626                         name:           'Lisence',
627                         type:           FILE_TYPE.FOLDER,
628                         children:       []
629                 },
630                 FILE_DATA_LISENCE_GROUP = {
631                         name:           'Lisence Group',
632                         type:           FILE_TYPE.FOLDER,
633                         children:       []
634                 },
635                 FILE_DATA_BALLOON_ROOT = {
636                         name:           'Balloon Templetes',
637                         type:           FILE_TYPE.FOLDER,
638                         children:       [],
639                         driver:         Driver,
640                         json:           pettanr.CONST.SPEECH_BALOON_TEMPLETE
641                 };
642         FILE_DATA_SERVICE_ROOT.children.push( FILE_DATA_COMICS_ROOT, FILE_DATA_RESOURCE_PICTURES_ROOT, FILE_DATA_ORIGINAL_PICTURES_ROOT, FILE_DATA_LISENCE_ROOT, FILE_DATA_BALLOON_ROOT );
643         FILE_DATA_COMICS_ROOT.children.push( FILE_DATA_MY_COMICS_ROOT, FILE_DATA_LATEST_COMICS, FILE_DATA_AUTHOR_ROOT, FILE_DATA_STORY_ROOT, FILE_DATA_PANELS_ROOT );
644         FILE_DATA_PANELS_ROOT.children.push( FILE_DATA_LATEST_PANELS, FILE_DATA_MY_PANELS_ROOT );
645         FILE_DATA_RESOURCE_PICTURES_ROOT.children.push( FILE_DATA_MY_RESOURCE_PICTURES_ROOT, FILE_DATA_ARTIST_ROOT );
646         FILE_DATA_LISENCE_ROOT.children.push( FILE_DATA_LISENCE_GROUP, FILE_DATA_LISENCE );
647         FILE_DATA_ORIGINAL_PICTURES_ROOT.children.push( FILE_DATA_MY_ORIGINAL_PICTURES_ROOT );
648         
649         FileAPI.createFolderUnderRoot( FILE_DATA_SERVICE_ROOT );
650
651         Driver.isPettanrFileInstance = function( file ){
652                 if( FileAPI.isFileInstance( file ) === true ){
653                         var _data = FileAPI.getFileData( file.getUID() );// file でなく  file.getUID()
654                         return _data !== null && _data.driver === Driver;
655                 };
656                 return false;
657         };
658
659 var Cabinet = gOS.registerApplication( function(){
660         var self         = this,
661                 finder       = null,
662                 tree         = null,
663                 nodeClose    = null,
664                 nodePath     = null,
665                 nodeBody     = null,
666                 headerH      = 0,
667                 eventRoot    = null;
668
669         this.bgColor     = '#FFFFFF';
670         this.MIN_WIDTH   = 500;
671         this.MIN_HEIGHT  = 300;
672         this.onInit = function(){
673                 self.rootElement.id = 'cabinet-root';
674                 self.rootElement.innerHTML = [
675                         '<div id="cabinet-header">',
676                                 '<div class="header-title">Cabinet</div>',
677                                 '<div id="cabinet-close-button">x</div>',
678                                 '<div id="cabinet-path" class="finder-path"></div>',
679                         '</div>',
680                         '<div id="cabinet-container" class="finder-container"></div>'
681                 ].join( '' );
682                 
683                 self.fetchCSS( pettanr.CONST.URL_PETA_APPS_CSS );
684                 
685                 tree      = FileAPI.createTree( FILE_DATA_SERVICE_ROOT );
686                 eventRoot = self.getPointingDeviceEventTreeRoot();
687                 
688                 delete self.onInit;
689         };
690         this.onOpen = function( _w, _h ){
691                 headerH = Util.getElementSize( document.getElementById( 'cabinet-header' ) ).height;
692                 
693                 nodeClose = eventRoot.createNode( document.getElementById( 'cabinet-close-button' ), false, false, 'close-button-hover', 'pointer' );
694                 nodeClose.addEventListener( 'click', Cabinet.shutdown );
695                 nodePath  = eventRoot.createNode( document.getElementById( 'cabinet-path' ), false, false );
696                 nodeBody  = eventRoot.createNode( document.getElementById( 'cabinet-container' ), false, true, null, '', true );
697                 
698                 finder = self.createFinder( nodeBody, tree );
699                 finder.createPath( nodePath );
700                 self.onPaneResize( _w, _h );
701         };
702         this.onClose = function(){
703                 finder.destroy();
704                 tree.destroy();
705                 finder = tree = null;
706         };
707         this.onPaneResize = function( w, h ){
708                 nodePath.width( w );
709                 nodeBody.update( 0, headerH, w, h - headerH );
710                 finder.resize( w, h - headerH );
711         };
712 }, false, true, 'Cabinet', 'cabinet', null, '#1C1C1C' );
713
714 var Gallery = gOS.registerApplication( function(){
715         var self         = this,
716                 finder       = null,
717                 tree         = null,
718                 nodeClose    = null,
719                 nodePath     = null,
720                 nodeBody     = null,
721                 headerH      = 0,
722                 eventRoot    = null;
723
724         this.bgColor     = '#FFFFFF';
725         this.MIN_WIDTH   = 500;
726         this.MIN_HEIGHT  = 300;
727         this.onInit = function(){
728                 self.rootElement.id        = 'gallery-root';
729                 self.rootElement.innerHTML = [
730                         '<div id="gallery-header">',
731                                 '<div class="header-title">Gallery</div>',
732                                 '<div id="gallery-close-button">x</div>',
733                                 '<div id="gallery-path" class="finder-path"></div>',
734                         '</div>',
735                         '<div id="gallery-container" class="finder-container"></div>'
736                 ].join( '' );
737                 
738                 self.fetchCSS( pettanr.CONST.URL_PETA_APPS_CSS );
739                 
740                 tree = FileAPI.createTree( FILE_DATA_RESOURCE_PICTURES_ROOT );
741                 var     _root  = tree.getRootFile(),
742                         _myPic = _root.getChildFileAt( 0 ),
743                         _pic   = _root.getChildFileAt( 1 );
744                 _myPic.getSeqentialFiles();
745                 _pic.getSeqentialFiles();
746                 _myPic.destroy();
747                 _pic.destroy();
748                 
749                 eventRoot = self.getPointingDeviceEventTreeRoot();
750         };
751         this.onOpen = function( w, h ){
752                 headerH = Util.getElementSize( document.getElementById( 'gallery-header' ) ).height;
753                 
754                 nodeClose = eventRoot.createNode( document.getElementById( 'gallery-close-button' ), false, false, 'close-button-hover', 'pointer' );
755                 nodeClose.addEventListener( 'click', Gallery.shutdown );
756                 nodePath = eventRoot.createNode( document.getElementById( 'gallery-path' ), false, false );
757                 nodeBody = eventRoot.createNode( document.getElementById( 'gallery-container' ), false, true, null, '', true );
758                 
759                 finder = self.createFinder( nodeBody, tree );
760                 finder.createPath( nodePath );
761                 self.onPaneResize( w, h );
762         };
763         this.onClose = function(){
764                 // finder.destroy();
765                 // tree.destroy();
766                 finder = tree = null;
767         };
768         this.onPaneResize = function( w, h ){
769                 nodePath.width( w );
770                 nodeBody.update( 0, headerH, w, h - headerH );
771                 finder.resize( w, h - headerH );
772         };
773 }, false, true, 'Gallery', 'gallery', null, '#01A31C' );
774
775 var Backyard = gOS.registerApplication( function(){
776         var self         = this;
777         
778         this.bgColor     = '#FFFFFF';
779         this.MIN_WIDTH   = 500;
780         this.MIN_HEIGHT  = 300;
781         this.onInit = function(){
782         };
783         this.onOpen = function( _w, _h, _option ){
784         }
785         this.onClose = function(){
786         }
787         this.onPaneResize = function( _w, _h){
788         }
789 }, false, false, 'Settings', 'settings', null, '#DDDDDD' );
790
791 if( pettanr.DEBUG === true){
792         var Debug = gOS.registerApplication( function(){
793                 var self = this,
794                         elmDl,
795                         data = ( function(){
796                                 var data = {
797                                         pettanR:       pettanr.version,
798                                         ua:            navigator.userAgent,
799                                         platform:      navigator.platform,
800                                         appVersion:    navigator.appVersion,
801                                         appCodeName:   navigator.appCodeName,
802                                         appName:       navigator.appName,
803                                         language:      navigator.browserLanguage || navigator.language,
804                                         ActiveX:       UA.ACTIVEX,
805                                         RenderingMode: UA.isStanderdMode === true ? 'Standerd' : 'Quirks'
806                                 };
807                                 if( UA.IE ){
808                                         data.version = UA.IE;
809                                         if( UA.ieVersion >= 8 ) data.RenderingVersion = UA.ieRenderingVersion;
810                                         data.browserType = UA.STANDALONE === true ? 'Standalone' : 'bundle';
811                                         if( UA.ieVersion < 9 ) {
812                                                 data.vml = UA.VML;
813                                         } else {
814                                                 data.svg = UA.SVG;
815                                         }
816                                 };
817                                 return data;
818                         })();
819
820                 this.bgColor     = '#FFFFFF';
821                 this.MIN_WIDTH   = 500;
822                 this.MIN_HEIGHT  = 300;
823                 this.onInit = function(){
824                         self.rootElement.id = 'debug-root';
825                         self.rootElement.innerHTML = '<dl id="useragent" class="dl-table clearfix"></dl>';
826                 };
827                 this.onOpen = function( _w, _h, _option ){
828                         elmDl = document.getElementById( 'useragent' );
829                         var elmDt, elmDd;
830                         for( var key in data ){
831                                 elmDt = document.createElement( 'dt' );
832                                 elmDt.innerHTML = key;
833                                 elmDd = document.createElement( 'dd' );
834                                 elmDd.innerHTML = '' + data[ key];
835                                 if( !data[ key ] ) elmDd.style.color = 'red';
836                                 elmDl.appendChild( elmDt );
837                                 elmDl.appendChild( elmDd );
838                         }
839                 }
840                 this.onClose = function(){
841                         
842                 }
843                 this.onPaneResize = function( _w, _h ){
844                         
845                 }
846         }, false, true, 'Debug', 'debug', null, '#01A31C' );
847 }
848
849 /* ----------------------------------------
850  * Image Group Exproler
851  *  - overlay
852  */
853 var PremiumSatge = gOS.registerApplication( function(){
854         var BASE_PATH      = pettanr.CONST.RESOURCE_PICTURE_PATH,
855                 THUMB_PATH     = pettanr.CONST.THUMBNAIL_PATH,
856                 LIMIT_FILESIZE = 1024 * 100,
857                 ICON_ARRAY     = [];
858                 
859         var self             = this,
860                 tree, rootFile,
861                 winW, winH, wrapX,
862                 elmContainer, elmIconOrigin, elmName, elmButton,
863                 containerW, containerH, 
864                 itemW, itemH, buttonW,
865                 onUpdate        = null,
866                 onUpdateData    = null,
867                 onUpdateContext = null,
868                 artistID        = -1;
869
870         var ImageGroupIconClass = function( index, data ){
871                 var elmIconWrap     = elmIconOrigin.cloneNode( true ),
872                         elmIconTitle    = Util.getElementsByClassName( elmIconWrap, 'image-group-item-title' )[ 0 ],
873                         originalPicture = data.original_picture || data,
874                         SRC             = [ BASE_PATH, data.id, '.', data.ext ].join( ''),
875                         LOW_SRC         = originalPicture.filesize && originalPicture.filesize > LIMIT_FILESIZE ? [ THUMB_PATH, data.id, '.', data.ext ].join( '' ) : null,
876                         reversibleImage = null,
877                         timer           = null,
878                         onEnterFlag     = false,
879                         instance        = this;
880                 elmContainer.appendChild( elmIconWrap );
881                 elmIconWrap.style.left = ( index * itemW ) + 'px';
882                 elmIconTitle.appendChild( document.createTextNode( originalPicture.filesize + 'bytes' ) );
883                 
884                 function onImageLoad( url, _imgW, _imgH ){
885                         data.width  = _imgW = _imgW || originalPicture.width  || 64;
886                         data.height = _imgH = _imgH || originalPicture.height || 64;
887                         elmIconTitle.firstChild.data = _imgW + 'x' + _imgH;
888                         var zoom = 128 /( _imgW > _imgH ? _imgW : _imgH ),
889                                 MATH_FLOOR = Math.floor,
890                                 h = MATH_FLOOR( _imgH * zoom ),
891                                 w = MATH_FLOOR( _imgW * zoom );
892                         reversibleImage.elm.style.cssText = [
893                                 'width:',  w, 'px;',
894                                 'height:', h, 'px;',
895                                 'margin:', MATH_FLOOR( itemH / 2 - h / 2 ), 'px ', MATH_FLOOR( itemW / 2 - w / 2 ), 'px 0'
896                         ].join('');
897                         reversibleImage.resize( w, h );
898                         self.addEventListener( elmIconWrap, 'click', onClick );
899                 };
900                 
901                 function onClick(){
902                         onUpdateData = data;
903                         PremiumSatge.shutdown();
904                 };
905                 
906                 function asyncDraw(){
907                         reversibleImage = pettanr.image.createReversibleImage( LOW_SRC || SRC, itemW, itemH, onImageLoad );
908                         elmIconWrap.appendChild( reversibleImage.elm );
909                         onEnterFlag = true;
910                         timer = null;
911                 };
912                 
913                 this.onEnter = function( delay ){
914                         self.addTimer( asyncDraw, delay, true );
915                         delete instance.onEnter;
916                 };
917                 this.destroy = function(){
918                         delete instance.destroy;
919                         // timer && window.clearTimeout( timer );
920                         self.removeTimer( asyncDraw );
921                         self.removeEventListener( elmIconWrap );
922                         reversibleImage !== null && reversibleImage.destroy();
923                         // Util.removeAllChildren( elmIconWrap );
924                         // elmContainer.removeChild( elmIconWrap );
925                         reversibleImage = elmIconWrap = elmIconTitle = data = timer = null;
926                 };
927         };
928         
929         function onEnterShowImage(){
930                 var l = ICON_ARRAY.length,
931                         _start = -wrapX /itemW -1,
932                         _end = _start + winW /itemW +1,
933                         _icon;
934                 for( var i=0, c = 0; i<l; ++i){
935                         _icon = ICON_ARRAY[ i ];
936                         if( _start < i && i < _end && _icon.onEnter ){
937                                 _icon.onEnter( c * 100 );
938                                 c++;
939                         }
940                 }
941                 //onEnterInterval !== null && window.clearTimeout( onEnterInterval );
942                 //onEnterInterval = null;
943                 self.removeTimer( onEnterShowImage );
944         };
945         function clickClose(){
946                 PremiumSatge.shutdown();
947         };
948         function onMouseWheel( e ){
949                 if( winW < containerW ){
950                         wrapX += e.wheelDelta / 2;
951                         wrapX = wrapX > 0 ? 0 : wrapX < winW -containerW ? winW -containerW : wrapX;
952                         elmContainer.style.left = wrapX + 'px';
953                         
954                         self.removeTimer( onEnterShowImage );
955                         self.addTimer( onEnterShowImage, 500 );
956                 };
957                 return false;                   
958         };
959         
960         function drawIcons(){
961                 while( ICON_ARRAY.length > 0 ){
962                         ICON_ARRAY.shift().destroy();
963                 };
964                 var _index = rootFile.search( {
965                                 id   : artistID,
966                                 type : FILE_TYPE.ARTIST
967                         })[ 0 ],
968                         _artistFile = rootFile.getChildFileAt( _index ),
969                         file;
970                 if( _artistFile !== null ){
971                         for( var i=0, l=_artistFile.getChildFileLength(); i<l; ++i ){
972                                 file = _artistFile.getChildFileAt( i );
973                                 ICON_ARRAY.push( new ImageGroupIconClass( i, FileAPI.getFileData( file ) ));
974                                 file.destroy();
975                         };
976                         elmName.firstChild.data = _artistFile.getName();
977                         _artistFile.destroy();
978                 };
979         };
980         
981         function onFadeout(){
982                 while( ICON_ARRAY.length > 0 ){
983                         ICON_ARRAY.shift().destroy();
984                 };
985                 onUpdate !== null && onUpdateData !== null && onUpdate.call( onUpdateContext, onUpdateData );
986                 onUpdate = onUpdateData = onUpdateContext = null;
987                 PremiumSatge.shutdown();
988         };
989         
990         
991         this.MIN_WIDTH   = 320;
992         this.MIN_HEIGHT  = 320;
993         this.onInit = function(){
994                 self.rootElement.id = 'image-group-wrapper';
995
996                 self.rootElement.innerHTML = [
997                         '<div id="image-group-icon-container"></div>',
998                         '<div id="image-group-name">NO DATA...</div>',
999                         '<div id="image-group-button" class="button">close</div>'
1000                 ].join( '' );
1001                 
1002                 self.fetchCSS( pettanr.CONST.URL_PETA_APPS_CSS );
1003                 
1004                 tree      = FileAPI.createTree( FILE_DATA_ARTIST_ROOT );
1005                 rootFile  = tree.getRootFile();
1006         };
1007         this.onOpen = function( _windowW, _windowH, _ARTISTIDorFILE, _onUpdate, opt_thisObj ){
1008                 elmContainer  = document.getElementById( 'image-group-icon-container' );
1009                 containerH    = Util.getElementSize( elmContainer ).height;
1010                 
1011                 elmIconOrigin = ( function(){
1012                         var ret  = document.createElement( 'div' ),
1013                                 data = document.createElement( 'div' );
1014                         ret.appendChild( data );
1015                         ret.className  = 'image-group-item';
1016                         data.className = 'image-group-item-title';
1017                         return ret;
1018                 })();
1019
1020                 var size      = Util.getElementSize( elmIconOrigin );
1021                 itemW         = size.width;
1022                 itemH         = size.height;
1023
1024                 elmName       = document.getElementById( 'image-group-name' );
1025                 elmButton     = document.getElementById( 'image-group-button' );
1026                 
1027                 buttonW       = Util.getElementSize( elmButton ).width;
1028                 
1029                 self.addEventListener( elmContainer, 'mousewheel', onMouseWheel );
1030                 self.addEventListener( elmButton, 'click', clickClose );
1031                 tree.addTreeEventListener( Const.TREE.EVENT.UPDATE, drawIcons );
1032                 
1033                 var data = FileAPI.getFileData( _ARTISTIDorFILE );
1034                 if( !data ){
1035                         artistID = MyArtistID || -1;
1036                 } else
1037                 if( data.type === FILE_TYPE.ARTIST || FILE_DATA_MY_ORIGINAL_PICTURES_ROOT === data ){
1038                         artistID = data.id || -1;
1039                 } else
1040                 if( Type.isNumber( _ARTISTIDorFILE ) === true ){
1041                         artistID = _ARTISTIDorFILE;
1042                 };
1043                 
1044                 onUpdate = _onUpdate || null;
1045                 onUpdateContext = opt_thisObj || null;
1046                 onUpdateData = null;
1047                 
1048                 drawIcons();
1049                 
1050                 wrapX = 0;
1051                 containerW = ICON_ARRAY.length * itemW;
1052                 
1053                 winW = _windowW;
1054                 winH = _windowH;
1055                 var w = winW > containerW ? winW : containerW,
1056                         h = _windowH > containerH ? containerH : _windowH,
1057                         MATH_FLOOR = Math.floor;
1058
1059                 $( elmContainer ).css( {
1060                         width:          w,
1061                         height:         0,
1062                         left:           0,
1063                         top:            MATH_FLOOR( _windowH /2 )
1064                 }).stop().animate( {
1065                         height:         h,
1066                         top:            MATH_FLOOR( _windowH /2 - h /2 )
1067                 }, onEnterShowImage );
1068                 
1069                 elmButton.style.cssText = [
1070                         'left:', MATH_FLOOR( _windowW /2 - buttonW /2 ), 'px;',
1071                         'top:',  MATH_FLOOR( _windowH /2 + containerH /2 +10 ), 'px'
1072                 ].join('');
1073         }
1074         this.onPaneResize = function( _windowW, _windowH ){
1075                 var w = _windowW > containerW ? _windowW : containerW,
1076                         h = _windowH > containerH ? containerH : _windowH,
1077                         MATH_FLOOR = Math.floor,
1078                         offsetW = MATH_FLOOR( _windowW /2 -winW /2 );
1079                         
1080                 winW = _windowW;
1081                 winH = _windowH;
1082                 if( offsetW <= 0 ){ // smaller
1083                         $( elmContainer ).stop().css( {
1084                                 left:                           offsetW,
1085                                 width:                          w
1086                         }).animate( {
1087                                 left:                           0,
1088                                 top:                            MATH_FLOOR( _windowH /2 -h /2 )
1089                         });                                     
1090                 } else {
1091                         $( elmContainer ).stop().css( { // bigger
1092                                 left:                           0,
1093                                 width:                          w,
1094                                 borderLeftWidth:        offsetW
1095                         }).animate( {
1096                                 top:                            MATH_FLOOR( _windowH /2 -h /2 ),
1097                                 borderLeftWidth:        0
1098                         });
1099                 }
1100                 elmButton.style.cssText = [
1101                         'left:', MATH_FLOOR( _windowW /2 -buttonW /2 ), 'px;',
1102                         'top:',  MATH_FLOOR( _windowH /2 +containerH /2 + 10 ), 'px'
1103                 ].join('');
1104                 onEnterShowImage();
1105         }
1106         this.onClose = function(){
1107                 if( tree === null ) return true;
1108                 $( elmContainer ).stop().animate( {
1109                                 height: 0,
1110                                 top:    Math.floor( winH / 2 )
1111                         }, onFadeout );
1112                 // onEnterInterval !== null && window.clearTimeout( onEnterInterval );
1113                 // onEnterInterval = null;
1114                 self.removeTimer();
1115                 
1116                 tree.removeTreeEventListener( Const.TREE.EVENT.UPDATE, drawIcons );
1117                 tree.destroy();
1118                 tree = rootFile = null;
1119                 
1120                 return false;
1121         }
1122 }, true, true, 'Premium Stage', 'premiumStage', null, '#C3325F' );
1123
1124
1125 /* ----------------------------------------
1126  * Text Editor
1127  *  - overlay
1128  */
1129 var TextEditor = gOS.registerApplication( function(){
1130         var elmTextarea, elmButton,
1131                 textElement, onUpdate,
1132                 ID = 'textEditor',
1133                 panelX, panelY,
1134                 self = this;
1135         
1136         function clickOK(){
1137                 textElement && textElement.text( elmTextarea.value );
1138                 self.addAsyncCall( asyncCallback );
1139         };
1140         
1141         function asyncCallback(){
1142                 onUpdate && onUpdate( textElement );
1143                 onUpdate = textElement = null;
1144                 TextEditor.shutdown();
1145         };
1146         
1147
1148         function textareaFitHeight(){
1149                 var rows = 0;
1150                 while( elmTextarea.offsetHeight < textElement.h ){
1151                         rows++;
1152                         elmTextarea.rows = rows;
1153                 };
1154                 if( rows > 1 ) elmTextarea.rows = --rows;
1155         };
1156         
1157         /* grobal method */
1158         
1159         this.MIN_WIDTH   = 320;
1160         this.MIN_HEIGHT  = 320;
1161         this.onInit = function(){
1162                 self.rootElement.id        = 'speach-editor-wrapper';
1163                 self.rootElement.innerHTML = '<textarea id="speach-editor"></textarea><div id="speach-edit-complete-button" class="button">OK</div>';
1164         };
1165         this.onOpen = function( _w, _h, _panelX, _panelY, _textElement, _onUpdate ){
1166                 elmTextarea = document.getElementById( 'speach-editor' );
1167                 elmButton   = document.getElementById( 'speach-edit-complete-button' );
1168                 
1169                 self.addKeyEventListener( 'keydown', new Function( 'return false' ), 69, false, true );
1170                 self.addEventListener( elmButton, 'click', clickOK );
1171                 
1172                 panelX = _panelX;
1173                 panelY = _panelY;
1174                 textElement = _textElement;
1175                 onUpdate = _onUpdate || null;
1176                 
1177                 self.onPaneResize( _w, _h );
1178                 elmTextarea.value = _textElement.content;
1179                 elmTextarea.focus();
1180                 
1181                 /*
1182                  * ie6,7は、textarea { width:100%}でも高さが変わらない。rowsを設定。
1183                  */
1184                 UA.isIE === true && UA.ieVersion <= 7 && self.addAsyncCall( textareaFitHeight );
1185         };
1186         this.onPaneResize = function( _w, _h ){
1187                 self.rootElement.style.cssText = [
1188                         'left:', textElement.x + panelX, 'px;',
1189                         'top:',  textElement.y + panelY, 'px;',
1190                         'width:', textElement.w, 'px;',
1191                         'height:', textElement.h, 'px;'
1192                 ].join( '' );
1193         };
1194         this.onClose = function(){
1195                 self.removeKeyEventListener();
1196                 self.removeEventListener( elmButton );
1197                 
1198                 elmTextarea = elmButton = onUpdate = textElement = self = null;
1199         };
1200 }, true, false, 'Tetxt Editor', 'texteditor', null, '#DDDDDD' );
1201
1202
1203 var Reader = gOS.registerApplication( function(){
1204         var windowW, windowH,
1205                 headerH,
1206                 consoleH,
1207                 panelMargin,
1208                 elmContainer, elmTitle, elmAuthor, elmBackButton, elmNextButton,
1209                 bindWorker    = null,
1210                 currentFile   = null,
1211                 comicData     = null,
1212                 currentPanel  = null,
1213                 currentIndex  = 0,
1214                 numPanel      = 0,
1215                 self          = this;
1216
1217         function onBackClick(){
1218                 currentIndex -= ( currentIndex > 0 ? 1 : 0 );
1219                 slide();
1220                 return false;
1221         }
1222         function onNextClick(){
1223                 currentIndex += ( currentIndex < numPanel - 1 ? 1 : 0 );
1224                 slide();
1225                 return false;
1226         }
1227         function slide(){
1228                 var elm    = elmContainer.childNodes[ currentIndex ],
1229                         h      = windowH - headerH - consoleH,
1230                         top    = headerH;
1231                 if( elm ){
1232                         top =  headerH - elm.offsetTop + Math.floor( ( h - elm.offsetHeight ) / 2 );
1233                 }
1234                 
1235                 $( elmContainer ).stop().animate( {
1236                         top:    top
1237                 });
1238         }
1239         function getCurrentTopPosition(){
1240
1241         }
1242         function draw(){
1243                 var fileData, title, author, story;
1244                 
1245                 if( Driver.isPettanrFileInstance( currentFile ) === true ){
1246                         switch( currentFile.getType() ){
1247                                 case FILE_TYPE.COMIC :
1248                                         fileData    = currentFile.read();
1249                                         title       = fileData.title;
1250                                         author      = fileData.author.name;
1251                                         comicData   = fileData;
1252                                         numPanel    = currentFile.getChildFileLength();
1253                                         break;
1254                                 case FILE_TYPE.STORY :
1255                                         story       = currentFile.read();
1256                                         fileData    = story.panel;
1257                                         title       = story.comic.title;
1258                                         author      = fileData.author.name;
1259                                         comicData   = fileData;
1260                                         numPanel    = 1;
1261                                         break;
1262                                 case FILE_TYPE.PANEL :
1263                                         fileData    = currentFile.read();
1264                                         title       = 'No comic';
1265                                         author      = fileData.author.name;
1266                                         comicData   = fileData;
1267                                         numPanel    = 1;
1268                                         break;                  
1269                         };
1270                 } else {
1271                         
1272                 };
1273                 if( comicData !== null ){
1274                         elmTitle.data  = title;
1275                         elmAuthor.data = author;
1276                         // bindWorker.json( comicData );
1277                         bindWorker.file( currentFile );
1278                         self.addAsyncCall( asyncResize );
1279                 };
1280         }
1281         function asyncResize(){
1282                 self.onPaneResize( windowW, windowH );
1283         };
1284         
1285         /* grobal method */
1286         
1287         this.MIN_WIDTH   = 320;
1288         this.MIN_HEIGHT  = 320;
1289         this.onInit = function(){
1290                 self.rootElement.id = 'comic-reader-wrapper';
1291                 self.rootElement.innerHTML = [
1292                         '<div id="comic-reader-panel-container"></div>',
1293                         '<div class="comic-reader-shadow" style="top:0;height:40px;"></div>',
1294                         '<div id="comic-reader-header">',
1295                                 '<div id="comic-reader-header-content">',
1296                                         '<span id="comic-reader-title">NO DATA...</span>',
1297                                         '<span id="comic-reader-author">NO DATA...</span>',
1298                                 '</div>',
1299                         '</div>',
1300                         '<div class="comic-reader-shadow" style="bottom:0;height:100px;"></div>',
1301                         '<div id="comic-reader-console">',
1302                                 '<div id="comic-reader-button-centering">',
1303                                         '<a href="#" id="comic-reader-back-button">▲</da>',
1304                                         '<a href="#" id="comic-reader-forward-button">▼</a>',
1305                                 '</div>',
1306                         '</div>'
1307                 ].join( '' );
1308                 
1309                 self.fetchCSS( pettanr.CONST.URL_PETA_APPS_CSS );
1310                 
1311         };
1312         this.onOpen = function( _w, _h, file ){
1313                 headerH       = Util.getElementSize( document.getElementById( 'comic-reader-header' ) ).height;
1314                 consoleH      = Util.getElementSize( document.getElementById( 'comic-reader-console' ) ).height;
1315                 elmContainer  = document.getElementById( 'comic-reader-panel-container' );
1316                 elmTitle      = document.getElementById( 'comic-reader-title' ).firstChild;
1317                 elmAuthor     = document.getElementById( 'comic-reader-author' ).firstChild;
1318                 elmBackButton = document.getElementById( 'comic-reader-back-button' );
1319                 elmNextButton = document.getElementById( 'comic-reader-forward-button' );
1320
1321                 bindWorker = pettanr.bind.createBindWorker( elmContainer, null, false, false );
1322                 
1323                 self.addEventListener( elmBackButton, 'click', onBackClick );
1324                 self.addEventListener( elmNextButton, 'click', onNextClick );
1325                 
1326                 numPanel = currentIndex = 0;
1327                 
1328                 elmContainer.style.cssText = 'left:' + ( _w / 2 )  + 'px;' + 'top:' + _h + 'px;';
1329                 
1330                 windowW = _w;
1331                 windowH = _h;
1332                 if( FileAPI.isFileInstance( file ) === true ){
1333                         currentFile = file;
1334                         file.addEventListener( Const.FILE.EVENT.GET_SEQENTIAL_FILES, draw );
1335                         file.getSeqentialFiles();
1336                         draw();
1337                 };
1338         };
1339         this.onPaneResize = function( _windowW, _windowH ){
1340                 windowW = _windowW;
1341                 windowH = _windowH;
1342                 var panelH = elmContainer.offsetHeight,
1343                         panelW = elmContainer.offsetWidth,
1344                         h      = _windowH - headerH - consoleH;
1345                 $( elmContainer ).stop().animate(
1346                         {
1347                                 left:   Math.floor( ( _windowW - panelW ) / 2 ),
1348                                 top:    headerH + ( panelH < h ? Math.floor( ( h - panelH ) / 2 ) : 0 )
1349                         }
1350                 );
1351         };
1352         this.onClose = function(){
1353                 self.removeEventListener( elmBackButton );
1354                 self.removeEventListener( elmNextButton );
1355                 
1356                 bindWorker.destroy();
1357                 bindWorker = null;
1358                 
1359                 currentFile && currentFile.removeEventListener( Const.FILE.EVENT.GET_SEQENTIAL_FILES, draw );
1360                 currentFile = comicData = currentPanel = null;
1361                 
1362                 elmContainer = elmTitle = elmAuthor = elmBackButton = elmNextButton = null;
1363         };
1364 }, true, true, 'Comic Reader', 'comicreader', null, '#01A31C' );
1365
1366
1367 var Editor = gOS.registerApplication( function(){
1368
1369         var PANEL_ELEMENT_TYPE_IMAGE = 0,
1370                 PANEL_ELEMENT_TYPE_TEXT  = 1,
1371                 MODULE_ARRAY             = [],
1372                 PANEL_ELEMENT_ARRAY      = [],
1373                 MIN_PANEL_HEIGHT         = 20,
1374                 MIN_ELEMENT_SIZE         = 19,
1375                 MOUSE_HIT_AREA           = 10,
1376                 windowW, windowH,
1377                 app                      = this,
1378                 eventRoot                = null,
1379                 option,
1380                 comicID                  = -1,
1381                 panelID                  = -1,
1382                 panelTimming             = -1,
1383                 phase                    = -1;
1384
1385         var kill = function(){
1386                 var o = this, v;
1387                 for( var p in o ){
1388                         if( o.hasOwnProperty && !o.hasOwnProperty( p ) ) continue;
1389                         v = o[ p ];
1390                         delete o[ p ];
1391                 };
1392         };
1393 /* ----------------------------------------
1394  * MENU BAR
1395  *  - mouseEventListener
1396  *  - controler
1397  * 
1398  * div
1399  *   div.title
1400  *   ul
1401  *     li
1402  *        a
1403  *          span
1404  *          kbd shortcut
1405  */
1406         var MENU_BAR_CONTROL = ( function(){
1407                 var ELM_ITEM_CLASSNAME = 'menubar-item',
1408                         currentMenu        = null,
1409                         elmBar, elmBox,
1410                         nodeBar, nodeBox, layerBox,
1411                         barH, menuW;
1412         /** -----------------------------------------
1413          *  PrivateOptionDataClass
1414          */
1415                 var PrivateOptionDataClass = function( menuData, option, title, shortcut, callback, visible, separateAfter, thisObject ){
1416                         this.menuData      = menuData;
1417                         this.option        = option;
1418                         this.title         = title;
1419                         this.shortcut      = shortcut || '';
1420                         this.callback      = callback;
1421                         this.thisObject    = thisObject;
1422                         this.visible       = visible;
1423                         this.separateAfter = separateAfter;
1424                 };
1425                 PrivateOptionDataClass.prototype = {
1426                         menuData      : null,
1427                         option        : null,
1428                         elm           : null,
1429                         node          : null,
1430                         visible       : undefined,
1431                         border        : false,
1432                         title         : null,
1433                         shortcut      : null,
1434                         callback      : null,
1435                         thisObject    : null,
1436                         separateAfter : false,
1437                         show : function( elm ){
1438                                 if( this.elm === elm ) return;
1439                                 if( !elm ){
1440                                         elm = document.createElement( 'div' );
1441                                         elmBox.appendChild( elm );
1442                                         elm.appendChild( document.createElement( 'span' ) );
1443                                         elm.appendChild( document.createElement( 'kbd' ) );
1444                                 };
1445                                 this.elm      = elm;
1446                                 this.option.title( this.title );
1447                                 this.option.visible( !!this.visible );
1448                                 elm.lastChild.innerHTML = this.shortcut;
1449                                 elm.style.borderStyle = this.border === true ? 'solid' : 'none';
1450                                 
1451                                 this.node     = nodeBox.createNode( elm, false, true, 'menubar-option-hover', 'pointer' );
1452                                 this.node.disabled( !this.visible );
1453                         },
1454                         hide : function(){
1455                                 this.node.remove();
1456                                 delete this.elm;
1457                                 delete this.node;
1458                         },
1459                         fire : function(){
1460                                 this.callback.call( this.thisObject || this.option, Util.getIndex( this.menuData.optionDataList, this ) );
1461                         },
1462                         remove : function(){
1463                                 var list = PrivateOptionDataClass.list;
1464                                 list.splice( Util.getIndex( list, this ), 1 );
1465                         }
1466                 };
1467                 PrivateOptionDataClass.list = [];
1468                 PrivateOptionDataClass.get = function( OptionOrElm ){
1469                         var list = PrivateOptionDataClass.list,
1470                                 i    = list.length,
1471                                 data;
1472                         for( ; i; ){
1473                                 data = list[ --i ];
1474                                 if( data.option === OptionOrElm || data.elm === OptionOrElm ) return data;
1475                         };
1476                         return null;
1477                 };
1478
1479         /** -----------------------------------------
1480          *  OptionClass
1481          */     
1482                 var OptionClass = function( menuData, title, shortcut, callback, visible, separateAfter, thisObject ){
1483                         PrivateOptionDataClass.list.push( new PrivateOptionDataClass( menuData, this, title, shortcut, callback, visible, separateAfter, thisObject ) );
1484                 };
1485                 OptionClass.prototype = {
1486                         title: function( v ){
1487                                 var data = PrivateOptionDataClass.get( this );
1488                                 if( Type.isString( v ) === true ){
1489                                         data.title = v;
1490                                         if( data.elm ) data.elm.firstChild.innerHTML = v;
1491                                 };
1492                                 return data.title;
1493                         },
1494                         visible : function( v ){
1495                                 var data = PrivateOptionDataClass.get( this );
1496                                 if( Type.isBoolean( v ) === true ){
1497                                         data.visible = v;
1498                                         data.elm && Util.toggleClass( data.elm, 'menubar-option-disabled', !v );
1499                                 };
1500                                 return data.visible;
1501                         }
1502                 };
1503         /** -----------------------------------------
1504          *  AsyncOptionClass
1505          */
1506                 var AsyncOptionClass = function( menuData, callback, visible, separateAfter, thisObject ){
1507                         var data  = new PrivateOptionDataClass( menuData, this, null, null, callback, visible, separateAfter, thisObject );
1508                         data.show = AsyncOptionClass.show;
1509                         data.hide = AsyncOptionClass.hide;                      
1510                         PrivateOptionDataClass.list.push( data );
1511                 };
1512                 AsyncOptionClass.prototype = {
1513                         title    : function(){},
1514                         visible  : OptionClass.prototype.visible
1515                 };
1516                 AsyncOptionClass.show = function( elm ){
1517                         if( this.elm === elm ) return;
1518                         if( !elm ){
1519                                 elm = document.createElement( 'div' );
1520                                 elmBox.appendChild( elm );
1521                                 elm.appendChild( document.createElement( 'span' ) );
1522                                 elm.appendChild( document.createElement( 'kbd' ) );             
1523                         };
1524                         this.elm         = elm;
1525                         elm.className    = 'loading';
1526                         elm.style.height = '90px';
1527                         elm.firstChild.innerHTML = this.elm.lastChild.innerHTML = '';
1528                         elm.style.borderStyle    = this.border === true ? 'solid' : 'none';
1529                         
1530                         this.callback();                        
1531                 };
1532                 AsyncOptionClass.hide = function(){
1533                         this.elm.className    = '';
1534                         this.elm.style.height = '';
1535                         delete this.elm;
1536                 };
1537                 
1538         /** -----------------------------------------
1539          *  MenuPrivateDataClass
1540          */
1541                 var MenuPrivateDataClass = function( menu, title ){
1542                         this.menu           = menu;
1543                         this.elm            = document.createElement( 'div' );
1544                         this.optionDataList = [];
1545                         
1546                         elmBar.appendChild( this.elm );
1547                         this.elm.className  = ELM_ITEM_CLASSNAME;
1548                         this.elm.innerHTML  = title;
1549                 };
1550                 MenuPrivateDataClass.prototype = {
1551                         menu           : null,
1552                         elm            : null,
1553                         node           : null,
1554                         visible        : false,
1555                         currentOption  : -1,
1556                         index          : -1,
1557                         optionDataList : null,
1558                         open : function(){
1559                                 this.elm.style.left = ( menuW * Util.getIndex( MenuPrivateDataClass.list, this ) ) + 'px';
1560                                 this.node           = nodeBar.createNode( this.elm, false, false, ELM_ITEM_CLASSNAME + '-hover', 'pointer' );
1561                                 // this.node.addEventListener( 'click', this.onClick, this );
1562                                 this.node.addEventListener( 'click', this.onClick, this );                      
1563                         },                      
1564                         close : function(){
1565                                 var o;
1566                                 while( o = this.optionDataList.shift() ) o.remove();
1567                                 this._kill = kill;
1568                                 this._kill();
1569                         },
1570                         onClick : function( e ){
1571                                 if( currentMenu !== this.menu ){
1572                                         currentMenu && currentMenu.hide();
1573                                         currentMenu = this.menu;
1574                                         this.menu.show();
1575                                 };
1576                         },
1577                         onOptionClick : function( e ){
1578                                 var target = e.target,
1579                                         i      = target.nodeIndex(),
1580                                         option = this.optionDataList[ i ];
1581                                 if( target === nodeBox ) return true;
1582                                 option.fire();
1583                         }
1584                 };
1585                 MenuPrivateDataClass.list = [];
1586                 MenuPrivateDataClass.get  = function( menu ){
1587                         var list = MenuPrivateDataClass.list,
1588                                 i    = list.length;
1589                         for( ; i; ){
1590                                 if( list[ --i ].menu === menu ) return list[ i ];
1591                         };
1592                         return null;
1593                 };
1594         
1595         /** -----------------------------------------
1596          *  MenuClass
1597          */
1598                 var MenuClass = function( title ){
1599                         MenuPrivateDataClass.list.push( new MenuPrivateDataClass( this, title ) );
1600                 };
1601                 MenuClass.prototype = {
1602                         show: function(){
1603                                 var data = MenuPrivateDataClass.get( this );
1604                                 if( data.visible === true ) return;
1605                                 
1606                                 data.elm.className = ELM_ITEM_CLASSNAME + '-focus';
1607                                 
1608                                 if( !elmBox ){
1609                                         elmBox   = document.createElement( 'div' );
1610                                         elmBar.appendChild( elmBox );
1611                                         elmBox.className = 'menubar-option-box';
1612                                         nodeBox  = nodeBar.createNode( elmBox, false, false, 'menubar-option-box-hover' );
1613                                 };
1614                                 nodeBox.disabled( false );
1615                                 elmBar.parentNode.insertBefore( elmBox, elmBar.nextSibling ); // ie6 では elmBar の 子にすると 選択肢が表示されない
1616                                 
1617                                 nodeBox.setPosition( data.node.x(), barH );
1618                                 
1619                                 var i,
1620                                         children = elmBox.childNodes,
1621                                         list     = data.optionDataList
1622                                         l        = list.length;
1623                                 while( l < children.length ){
1624                                         elmBox.removeChild( elmBox.firstChild );
1625                                 };
1626                                 for( i = 0; i < l; ++i ){
1627                                         list[ i ].show( children[ i ] );
1628                                 };
1629                                 nodeBox.mesure();
1630
1631                                 nodeBar.addEventListener( 'mouseout', this.hide, this );
1632                                 nodeBox.addEventListener( 'click', data.onOptionClick, data );
1633                                 data.visible = true;                                                            
1634                         },
1635                         hide: function(){
1636                                 data = MenuPrivateDataClass.get( this );
1637                                 if( data.visible === false ) return;
1638                                 
1639                                 data.elm.className = ELM_ITEM_CLASSNAME;
1640                                 for( var i = data.optionDataList.length; i; ){
1641                                         data.optionDataList[ --i ].hide();
1642                                 };
1643                                 elmBar.parentNode.removeChild( elmBox );
1644                                 nodeBox.disabled( true );
1645
1646                                 nodeBar.removeEventListener( 'mouseout', this.hide );
1647                                 nodeBox.removeEventListener( 'click', data.onOptionClick );
1648                                 data.visible = false;
1649                                 currentMenu  = null;
1650                         },
1651                         createOption: function( title, shortcut, callback, visible, separateBefore, separateAfter, thisObject ){
1652                                 var data       = MenuPrivateDataClass.get( this ),
1653                                         before     = data.optionDataList[ data.optionDataList.length - 1 ],
1654                                         ret        = new OptionClass( data, title, shortcut, callback, visible, separateAfter, thisObject ),
1655                                         dataOption = PrivateOptionDataClass.get( ret );
1656                                 if( before ) before.border = separateBefore === true || before.separateAfter === true;
1657                                 data.optionDataList.push( dataOption );
1658                                 if( data.visible === true ){
1659                                         dataOption.show();
1660                                         nodeBox.mesure();
1661                                 };
1662                                 return ret;
1663                         },
1664                         createAsyncOption: function( onOpen, visible, separateBefore, separateAfter, thisObject ){
1665                                 var data       = MenuPrivateDataClass.get( this ),
1666                                         before     = data.optionDataList[ data.optionDataList.length -1 ],
1667                                         ret        = new AsyncOptionClass( data, onOpen, visible, separateAfter, thisObject ),
1668                                         dataOption = PrivateOptionDataClass.get( ret );
1669                                 if( before ) before.border = separateBefore === true || before.separateAfter === true;
1670                                 data.optionDataList.push( dataOption );
1671                                 data.visible === true && dataOption.show();
1672                                 return ret;
1673                         },
1674                         remove : function( option ){
1675                                 var data       = MenuPrivateDataClass.get( this ),
1676                                         optionData = PrivateOptionDataClass.get( option ),
1677                                         i          = Util.getIndex( data.optionDataList, optionData );
1678                                 if( i === -1 ) return;
1679                                 
1680                                 data.optionDataList.splice( i, 1 );
1681                                 
1682                                 data.visible === true && elmBox.removeChild( optionData.elm ) && optionData.hide();
1683                                 optionData.remove();
1684                                 
1685                                 !( option instanceof AsyncOptionClass ) && data.optionDataList.length === 0 && this.hide();
1686                         }
1687                 };
1688                 
1689                 return {
1690                         id : 'MENU_BAR_CONTROL',
1691                         h  : 0,
1692                         init : function(){
1693                                 elmBar   = document.getElementById( 'menu-bar' );
1694                                 nodeBar  = eventRoot.createNode( elmBar, false, false, 'menu-bar-hover' );
1695                                 
1696                                 MENU_BAR_CONTROL.QUIT   = MENU_BAR_CONTROL.createItem( 'Quit' );
1697                                 MENU_BAR_CONTROL.EDIT   = MENU_BAR_CONTROL.createItem( 'Edit' );
1698                                 MENU_BAR_CONTROL.WINDOW = MENU_BAR_CONTROL.createItem( 'Window' );
1699                                 MENU_BAR_CONTROL.HELP   = MENU_BAR_CONTROL.createItem( 'Help' );
1700                                 
1701                                 var size = Util.getElementSize( MenuPrivateDataClass.list[ 0 ].elm );
1702                                 menuW    = size.width;
1703                                 barH     = MENU_BAR_CONTROL.h = size.height;
1704                                 
1705                                 elmBar.style.top = ( - barH ) + 'px';
1706                                 $( elmBar ).animate( { top: 0 } );                              
1707                                 
1708                                 delete MENU_BAR_CONTROL.init;
1709                         },
1710                         open : function(){
1711                                 for( var i = MenuPrivateDataClass.list.length; i; ) MenuPrivateDataClass.list[ --i ].open();
1712                                 delete MENU_BAR_CONTROL.open;
1713                         },
1714                         close : function(){
1715                                 var data;
1716                                 while( data = MenuPrivateDataClass.list.shift() ) data.close();
1717                                 nodeBox.remove();
1718                                 MenuPrivateDataClass.list = elmBar = layerBox = elmBox = null;
1719                                 MENU_BAR_CONTROL.kill = kill;
1720                                 MENU_BAR_CONTROL.kill();
1721                         },
1722                         createItem : function( title ){
1723                                 return new MenuClass( title );
1724                         },
1725                         busy : function( _busy ){
1726                                 return false;
1727                         },
1728                         onWindowResize: function( _windowW, _windowH ){
1729                                 
1730                         },
1731                         QUIT:   null,
1732                         EDIT:   null,
1733                         WINDOW: null,
1734                         HELP:   null
1735                 };
1736         })();
1737
1738
1739 /* ----------------------------------------
1740  * HISTORY_CONTROL
1741  *  - controler
1742  */
1743         var HISTORY_CONTROL = ( function() {
1744                 var     stackBack    = [],
1745                         stackForward = [],
1746                         menubarBack,
1747                         menubarForward;
1748
1749                 function back(){
1750                         /*
1751                          * currentを控えてstackForward.push(current)
1752                          * stackBack.pop()を実行してcurrentに
1753                          */
1754                         if( stackBack.length === 0 ) return;
1755
1756                         var s = stackBack.pop();
1757                         s.callback.apply( s.thisObj || {}, s.argBack );
1758                         menubarBack.visible( stackBack.length !== 0 );
1759                         SAVE_CONTROL.panelUpdated( stackBack.length !== 0 );
1760                         
1761                         stackForward.push( s );
1762                         menubarForward.visible( true );
1763                 };
1764                 function forward(){
1765                         if( stackForward.length === 0 ) return;
1766                         
1767                         var s = stackForward.pop();
1768                         s.callback.apply( s.thisObj || {}, s.argForword );
1769                         menubarForward.visible( stackForward.length !== 0 );
1770                         
1771                         stackBack.push( s );
1772                         menubarBack.visible( true );
1773                         SAVE_CONTROL.panelUpdated( true );
1774                 };
1775                 var RecordClass = function( callback, argBack, argForword, destroy, opt_thisObject ){
1776                         this.callback   = callback;
1777                         this.argBack    = argBack;
1778                         this.argForword = argForword;
1779                         this.destroy    = !!destroy;
1780                         this.thisObj    = opt_thisObject;
1781                 };
1782                 RecordClass.prototype.kill = function( _callDestroy ){
1783                         var     _argBack    = this.argBack,
1784                                 _argForword = this.argForword,
1785                                 v;
1786                         this._kill = kill;
1787                         this._kill();
1788                         
1789                         if( _callDestroy !== true ) return;
1790                         
1791                         if( Type.isArray( _argBack ) === true ){ // isArray
1792                                 while( v = _argBack.shift() ){
1793                                         _callDestroy === true && Type.isFunction( v.destroy ) === true && v.destroy();
1794                                 };
1795                         };
1796                         if( Type.isArray( _argForword ) === true ){
1797                                 while( v = _argForword.shift() ){
1798                                         _callDestroy === true && Type.isFunction( v.destroy ) === true && v.destroy();
1799                                 };
1800                         };
1801                 };
1802                 return {
1803                         init: function(){
1804                                 app.addKeyEventListener( 'keydown', back,    90, false, true ); // ctrl + Z
1805                                 app.addKeyEventListener( 'keydown', forward, 90, true,  true ); // ctrl + shift + Z
1806                                 app.addKeyEventListener( 'keydown', forward, 89, false, true ); // ctrl + Y
1807                                 
1808                                 delete HISTORY_CONTROL.init;
1809                         },
1810                         open: function(){
1811                                 menubarBack    = MENU_BAR_CONTROL.EDIT.createOption( 'back',    'ctrl + z', back, false );
1812                                 menubarForward = MENU_BAR_CONTROL.EDIT.createOption( 'forward', 'ctrl + y', forward, false, false, true );                              
1813                                 
1814                                 delete HISTORY_CONTROL.open;
1815                         },
1816                         close: function(){
1817                                 var s;
1818                         while( s = stackBack.shift() )    s.kill( true );
1819                         while( s = stackForward.shift() ) s.kill( true );
1820                         menubarBack = menubarForward = stackBack = stackForward = null;
1821                         },
1822                     saveState: function( _function, _argBack, _argForword, _onRecordDestroy, opt_thisObject ){
1823                         stackBack.push( new RecordClass( _function, _argBack, _argForword, _onRecordDestroy, opt_thisObject ));
1824                         menubarBack.visible( true );
1825                                 SAVE_CONTROL.panelUpdated( true );
1826                                 
1827                                 var s;
1828                         while( s = stackForward.shift() ) s.kill( s.destroy );
1829                                 menubarForward.visible( false );
1830                     }           
1831                 };
1832         })();
1833
1834 /* ----------------------------------------
1835  * SAVE_CONTROL
1836  *  - controler
1837  */
1838         var SAVE_CONTROL = ( function(){
1839                 var save, saveQuit, eXport, quit,
1840                         updated  = false;
1841                 
1842                 function quit(){
1843                         Editor.shutdown();
1844                 };
1845                 function onSave(){
1846                         PanelConsole.boot( Model.createPanel( {
1847                                 comicID           : comicID,
1848                                 panelID           : panelID,
1849                                 panelTimming      : panelTimming,
1850                                 panelW            : PANEL_CONTROL.w,
1851                                 panelH            : PANEL_CONTROL.h,
1852                                 borderSize        : 2,
1853                                 panelElementArray : PANEL_ELEMENT_ARRAY,
1854                                 publish           : true
1855                         } ) );
1856                 };
1857                 function onSaveQuit(){
1858                         // Editor.shutdown();
1859                         onSave();
1860                 };
1861                 function onExport(){
1862                         OutputConsole.boot(
1863                                 comicID, panelID, panelTimming,
1864                                 PANEL_CONTROL.w, PANEL_CONTROL.h,
1865                                 2, // border, BackgroundImage
1866                                 PANEL_ELEMENT_ARRAY
1867                         );
1868                 };
1869                 return {
1870                         init: function(){
1871                                 delete SAVE_CONTROL.init;
1872                         },
1873                         open: function(){
1874                                 save     = MENU_BAR_CONTROL.QUIT.createOption( 'save', 'ctrl + S', onSave, false );
1875                                 saveQuit = MENU_BAR_CONTROL.QUIT.createOption( 'save & quit', null, onSaveQuit, false, false, true );
1876                                 eXport   = MENU_BAR_CONTROL.QUIT.createOption( 'export', null, onExport, true, false, true );
1877                                 quit     = MENU_BAR_CONTROL.QUIT.createOption( 'quit', null, quit, true, true );                                
1878                                 
1879                                 delete SAVE_CONTROL.open;
1880                         },
1881                         close: function(){
1882                                 save = saveQuit = eXport = quit = null;
1883                                 SAVE_CONTROL.kill = kill;
1884                                 SAVE_CONTROL.kill();
1885                         },
1886                         quit: quit,
1887                         panelUpdated: function( _updated ){
1888                                 if( Type.isBoolean( _updated ) === true ){
1889                                         save.visible( _updated );
1890                                         saveQuit.visible( _updated );
1891                                         updated = _updated;
1892                                 }
1893                                 return updated;
1894                         },
1895                         save: function(){
1896                                 
1897                         }
1898                 };
1899         })();
1900
1901 /* ----------------------------------------
1902  * WINDOWS_CONTROL
1903  *  - contloler
1904  *  - mouseEventListener
1905  */     
1906         var WINDOWS_CONTROL = ( function(){
1907         /*
1908          *  表示上手前にあるwindowは、WINDOW_DATA_LISTの先頭にあり、htmlでは後ろにある。
1909          */
1910                 var DEFAULT_MIN_WINDOW_WIDTH  = 200,
1911                         DEFAULT_MIN_WINDOW_HEIGHT = 200,
1912                         WINDOW_DATA_LIST          = [],
1913                         WINDOW_BODY_BODER_SIZE    = 1,
1914                         currentWindowData,
1915                         elmRoot,
1916                         nodeContainer,
1917                         elmWindowOrigin,
1918                         closeButtonWidth;
1919         /**
1920          * WindowPrivateData
1921          */
1922                 var WindowPrivateData = function(){};
1923                 WindowPrivateData.prototype = {
1924                         window        : null,
1925                         menubarOption : null,
1926                         elm           : null,
1927                         elmHead       : null,
1928                         elmBody       : null,
1929                         nodeWindow    : null,
1930                         nodeHead      : null,
1931                         nodeBody      : null,
1932                         nodeFoot      : null,
1933                         nodeResize    : null,
1934                         visible       : false,
1935                         isDragging    : false,
1936                         isResizing    : false,
1937                         title         : null,
1938                         x             : 0,
1939                         y             : 0,
1940                         w             : 0,
1941                         h             : 0,
1942                         minWindowW    : 200,
1943                         minWindowH    : 200,
1944                         startX        : 0,
1945                         startY        : 0,
1946                         startW        : 0,
1947                         startH        : 0,
1948                         offsetX       : 0,
1949                         offsetY       : 0,
1950                         headerH       : 0,
1951                         bodyH         : 0,
1952                         footerH       : 0,
1953                         init : function( win, bodyTempleteID, title, x, y, w, h, visible, closeEnabled, resizeEnabled, minWindowW, minWindowH ){
1954                                 this.window         = win;
1955                                 this.bodyTempleteID = bodyTempleteID;
1956                                 this.title          = title;
1957                                 this.x              = x;
1958                                 this.y              = y;
1959                                 this.w              = w;
1960                                 this.h              = h;
1961                                 this.visible        = visible;
1962                                 this.closeEnabled   = closeEnabled;
1963                                 this.resizeEnabled  = resizeEnabled;
1964                                 this.minWindowW     = minWindowW;
1965                                 this.minWindowH     = minWindowH;
1966                                 
1967                                 WINDOW_DATA_LIST.push( this );
1968                         },
1969                         create : function(){
1970                                 var win = this.window;
1971                                 this.elm = win.elm = elmWindowOrigin.cloneNode( true );
1972                                 this.menubarOption = MENU_BAR_CONTROL.WINDOW.createOption( 
1973                                         ( this.visible !== true ? 'show ' : 'hide ' ) + this.title,
1974                                         null, this.onMenubarClick,
1975                                         true, false, false,
1976                                         this
1977                                 );
1978                                 if( win.onInit ){
1979                                         win.onInit();
1980                                         delete win.onInit;
1981                                 };
1982                         },
1983                         onMenubarClick : function(){
1984                                 this.window[ this.visible === true ? 'close' : 'open' ]();
1985                         },
1986                         update : function( x, y, w, h ){
1987                                 var win = this.window, bodyH;
1988                                         
1989                                 x = x !== undefined ? x : this.x;
1990                                 y = y !== undefined ? y : this.y;
1991                                 y = y > MENU_BAR_CONTROL.h ? y : MENU_BAR_CONTROL.h;
1992                                 w = w !== undefined ? w : this.w;
1993                                 h = h !== undefined ? h : this.h;
1994                                 
1995                                 this.nodeWindow.update( x, y, w, h );
1996                                 this.nodeHead && this.nodeHead.update( 0, 0, w, this.headerH );
1997                                 console.log( '************ hewader' + this.headerH )
1998                                 this.nodeBody.update( 0, this.headerH, w, this.bodyH = h - this.headerH - this.footerH );
1999                                 ( this.w !== w || this.h !== h ) && win.onResize && win.onResize( w, this.bodyH );
2000
2001                                 this.x = x;
2002                                 this.y = y;
2003                                 this.w = w;
2004                                 this.h = h;
2005                         },
2006                         firstOpen : function(){
2007                                 var win       = this.window,
2008                                         elmHead   = this.elmHead = Util.getElementsByClassName( this.elm, 'window-header' )[ 0 ],
2009                                         elmBody   = this.elmBody = Util.getElementsByClassName( this.elm, 'window-body' )[ 0 ],
2010                                         elmClose  = Util.getElementsByClassName( this.elm, 'window-close-button' )[ 0 ],
2011                                         elmFoot   = Util.getElementsByClassName( this.elm, 'window-footer' )[ 0 ],
2012                                         elmResize = Util.getElementsByClassName( this.elm, 'window-resize-button' )[ 0 ],
2013                                         replaceID = this.bodyTempleteID;
2014                                 
2015                                 this.nodeWindow = nodeContainer.createNode( this.elm, false, true, 'window-wrapper-hover' );
2016                                 this.nodeWindow.addEventListener( 'mousemove', this.mousemove, this );
2017                                 this.nodeWindow.addEventListener( 'mousedown', this.mousedown, this );
2018                                 this.nodeWindow.addEventListener( 'mouseup',   this.mouseup,   this );
2019                                 this.nodeWindow.addEventListener( 'mouseout',  this.mouseup,   this );
2020                                 
2021                                 // this.nodeHead   = this.nodeWindow.createNode( elmHead );
2022                                 win.title( this.title );
2023
2024                                 this.nodeBody   = this.nodeWindow.createNode( elmBody, false, true, null, '', true );
2025                                 replaceID && elmBody.appendChild( document.getElementById( replaceID ) );
2026                                 
2027                                 if( this.closeEnabled === true ){
2028                                         // this.nodeClose = this.nodeHead.createNode( elmClose );
2029                                         // this.nodeClose.addEventListener( 'mousedown', win.close, data );
2030                                 } else {
2031                                         elmClose.parentNode.removeChild( elmClose );
2032                                 };
2033                                 
2034                                 if( this.resizeEnabled === true ){
2035                                         // this.nodeFoot = this.nodeWindow.createNode( elmFoot );
2036                                         this.footerH  = Util.getElementSize( elmFoot ).height; // this.nodeFoot.height();
2037                                         
2038                                         // this.nodeResize = this.nodeFoot.createNode( elmResize );
2039                                         // this.nodeResize.addEventListener( 'mousedrag', this.resizeDrag, data );
2040                                 } else {
2041                                         elmFoot.parentNode.removeChild( elmFoot );
2042                                 };
2043                                 
2044                                 this.update( this.x, this.y, this.w, this.h );
2045                                 if( win.onFirstOpen ){
2046                                         win.onFirstOpen( this.w, this.bodyH, this.nodeBody );
2047                                         delete win.onFirtOpen;
2048                                 };
2049                                 
2050                                 this.firstOpen = null;
2051                         },
2052                         onFadeIn : function(){
2053                                 var data = WindowPrivateData.get( this ),
2054                                         win  = data.window;
2055                                 data.firstOpen && data.firstOpen();
2056                                 win.onOpen && win.onOpen( data.w, data.bodyH );
2057                                 data.nodeWindow.disabled( false );
2058                                 data.goFront();
2059                         },
2060                         onFadeOut : function(){
2061                                 var data = WindowPrivateData.get( this ),
2062                                         win  = data.window;
2063                                 elmRoot.removeChild( data.elm );
2064                                 win.onClose && app.addAsyncCall( win.onClose, null, win );
2065                         },
2066                         mousedown : function( e ){
2067                                 currentWindowData !== this && this.goFront();
2068                                 
2069                                 var x   = e.layerX,
2070                                         y   = e.layerY;
2071                                 if( this.resizeEnabled === true && this.w - 20 <= x && x < this.w && this.headerH + this.bodyH < y && y <= this.h ){
2072                                         this.isResizing = true;
2073                                         //this.startX     = this.x;
2074                                         //this.startY     = this.y;
2075                                         this.startW     = this.w;
2076                                         this.startH     = this.h;
2077                                         this.offsetX    = x;
2078                                         this.offsetY    = y;
2079                                         // app.updateCoursor( 'nw-resize' );
2080                                         this.nodeWindow.cursor( 'nw-resize' );
2081                                         return true;
2082                                 };
2083                                 
2084                                 // if( x < 0 || y < 0 || this.w < x || this.headerH < y ) return false;
2085                                 if( this.closeEnabled === true && this.w - closeButtonWidth < x && y < this.headerH ){
2086                                         this.window.close();
2087                                         return;
2088                                 };
2089                                 
2090                                 if( y < this.headerH ){
2091                                         this.isDragging = true;
2092                                         this.startX     = this.x;
2093                                         this.startY     = this.y;
2094                                         this.startW     = this.w;
2095                                         this.startH     = this.h;
2096                                         this.offsetX    = x;
2097                                         this.offsetY    = y;
2098                                         
2099                                         // app.updateCoursor( 'move' );
2100                                         this.nodeWindow.cursor( 'move' );
2101                                         return true;                                    
2102                                 }
2103                         },
2104                         mouseup : function( e ){
2105                                 if( this.isResizing === true || this.isDragging === true ){
2106                                         this.isDragging = this.isResizing = false;
2107                                         this.update();
2108                                 };
2109                                 this.nodeWindow.cursor( '' );
2110                         },
2111                         mousemove : function( e ){
2112                                 currentWindowData !== this && this.goFront();
2113                                 
2114                                 var x   = e.layerX,
2115                                         y   = e.layerY,
2116                                         w, h;
2117                                 if( this.isResizing === true ){
2118                                         w = this.startW + x - this.offsetX;
2119                                         h = this.startH + y - this.offsetY;
2120                                         this.w = w = w < this.minWindowW ? this.minWindowW : w;
2121                                         this.h = h = h < this.minWindowH ? this.minWindowH : h;
2122                                         this.elm.style.width  = w + 'px';
2123                                         this.elm.style.height = h + 'px';
2124                                         return true;                            
2125                                 } else
2126                                 if( this.isDragging === true ){
2127                                         this.x = x = this.startX + x - this.offsetX;
2128                                         this.y = y = this.startY + y - this.offsetY;
2129                                         this.elm.style.left = x + 'px';
2130                                         this.elm.style.top  = y + 'px';
2131                                         return true;
2132                                 };
2133                                 // if( e.hit === false || ( this.headerH < layerY && layerY < this.headerH + this.bodyH ) ) return false;
2134                                 this.nodeWindow.cursor( ( /*0 < layerX && layerX < this.w && 0 <= layerY &&*/ y <= this.headerH ) ? 'pointer' : '' );
2135                         },
2136                         goFront : function(){
2137                                 currentWindowData = this;
2138                                 var i = nodeContainer.numNode() - 1;
2139                                 // console.log( this.nodeWindow.nodeIndex() + ' , ' + this.nodeWindow.numNode() )
2140                                 if( this.nodeWindow.nodeIndex() !== i ){
2141                                         this.nodeWindow.nodeIndex( i );
2142                                         elmRoot.appendChild( this.elm );
2143                                 };
2144                         },
2145                         busy : function(){
2146                                 return this.isDragging === true || this.isResizing === true;
2147                         },
2148                         destroy : function(){
2149                                 
2150                         }
2151                 };
2152                 WindowPrivateData.get = function( windowOrElement ){
2153                         if( windowOrElement instanceof WindowPrivateData ) return windowOrElement;
2154                         var list = WINDOW_DATA_LIST,
2155                                 i    = list.length,
2156                                 data;
2157                         for( ; i; ){
2158                                 data = list[ --i ];
2159                                 if( data.window === windowOrElement || data.elm === windowOrElement ) return data;
2160                         };
2161                         return null;
2162                 };
2163                 
2164         /**
2165          * WindowClass
2166          */
2167                 var WindowClass = function( bodyTempleteID, title, x, y, w, h, visible, closeEnabled, resizeEnabled, minWindowW, minWindowH ){
2168                         ( new WindowPrivateData() ).init( this, bodyTempleteID, title, x, y, w, h, visible, closeEnabled, resizeEnabled, minWindowW, minWindowH );
2169                 };
2170                 WindowClass.prototype = {
2171                         elm        : null,
2172                         open : function(){
2173                                 var data = WindowPrivateData.get( this );
2174                                 if( data.visible === true ) return;
2175                                 
2176                                 data.visible = true;
2177                                 openWindow( data );
2178                                 data.menubarOption.title( 'hide ' + data.title );
2179                                 
2180                                 // WINDOW_DATA_LIST.splice( Util.getIndex( WINDOW_DATA_LIST, data ), 1 );
2181                                 // WINDOW_DATA_LIST.unshift( data );
2182                                 currentWindowData  = null;
2183                         },
2184                         close : function(){
2185                                 var data = WindowPrivateData.get( this );
2186                                 if( data.visible === false ) return;
2187                                 
2188                                 data.visible = false;
2189                                 $( data.elm ).fadeOut( data.onFadeOut );
2190                                 data.menubarOption.title( 'show ' + data.title );
2191                                 data.nodeWindow.disabled( true );
2192                         },
2193                         title : function( _title ){
2194                                 if( Type.isString( _title ) === true ){
2195                                         var data = WindowPrivateData.get( this );
2196                                         data.elmHead.firstChild.innerHTML = data.title = _title;
2197                                         // data.nodeHead.mesure();
2198                                         //data.headerH = data.nodeHead.height();
2199                                         data.headerH = Util.getElementSize( data.elmHead ).height;
2200                                 };
2201                                 return data.title;
2202                         },
2203                         createHeaderItem : function(){
2204                                 var data = WindowPrivateData.get( this ),
2205                                         elm  = document.createElement( 'div' ),
2206                                         node;
2207                                 if( !data.nodeHead ) data.nodeHead = data.nodeWindow.createNode( data.elmHead, true, false );
2208                                 data.elmHead.appendChild( elm );
2209                                 elm.className = 'header-item finder-path';
2210                                 node = data.nodeHead.createNode( elm, false, true, 'header-item-hover', '' )
2211                                 // data.nodeHead.mesure();
2212                                 // data.headerH = data.nodeHead.height();
2213                                 
2214                                 data.headerH = Util.getElementSize( data.elmHead ).height;
2215                                 data.update();
2216                                 
2217                                 return node;
2218                         }
2219                 };
2220                 
2221                 function openWindow( data ){
2222                         if( data.visible !== true ) return;
2223                         elmRoot.appendChild( data.elm );// appendした後に fadeIn() しないと ie で filterが適用されない.
2224                         $( data.elm ).fadeIn( data.onFadeIn );
2225                         return;
2226                 };
2227                 
2228                 return {
2229                         id   : 'WINDOWS_CONTROL',
2230                         init : function(){
2231                                 elmRoot          = document.getElementById( 'window-container' );
2232                                 nodeContainer    = eventRoot.createNode( elmRoot, true, false );
2233                                 elmWindowOrigin  = app.fetchHTMLElement( 'windowTemplete' );
2234                                 closeButtonWidth = Util.getElementSize( Util.getElementsByClassName( elmWindowOrigin, 'window-close-button' )[ 0 ] ).width;
2235                                 
2236                                 delete WINDOWS_CONTROL.init;
2237                         },
2238                         open : function(){
2239                                 for( var i = WINDOW_DATA_LIST.length, data; i; ){
2240                                         data = WINDOW_DATA_LIST[ --i ];
2241                                         data.create();
2242                                         openWindow( data );
2243                                 };
2244                                 delete WINDOWS_CONTROL.open;
2245                         },
2246                         close : function(){
2247                         },
2248                         onWindowResize : function( _windowW, _windowH ){
2249                                 /*
2250                                  * 画面外に出るwindowの移動
2251                                  */
2252                         },
2253                         createWindow : function( EXTENDS, bodyTempleteID, title, x, y, w, h, opt_visible, opt_closeEnabled, opt_resizeEnabled, opt_minWindowW, opt_minWindowH ){
2254                                 opt_visible       = opt_visible !== false;
2255                                 opt_closeEnabled  = opt_closeEnabled === true;
2256                                 opt_resizeEnabled = opt_resizeEnabled === true;
2257                                 opt_minWindowW    = opt_minWindowW || ( w < DEFAULT_MIN_WINDOW_WIDTH ) ? w : DEFAULT_MIN_WINDOW_WIDTH;
2258                                 opt_minWindowH    = opt_minWindowH || ( h < DEFAULT_MIN_WINDOW_HEIGHT ) ? h : DEFAULT_MIN_WINDOW_HEIGHT;
2259                                 
2260                                 var win = new WindowClass( bodyTempleteID, title, x, y, w, h, opt_visible, opt_closeEnabled, opt_resizeEnabled, opt_minWindowW, opt_minWindowH ),
2261                                         data;
2262                                 for( var key in EXTENDS ){
2263                                         win[ key ] = EXTENDS[ key ];
2264                                 };
2265                                 if( Type.isUndefined( WINDOWS_CONTROL.init ) === true ){
2266                                         data = WindowPrivateData.get( win );
2267                                         data.create();
2268                                         openWindow( data );
2269                                 };
2270                                 return win;
2271                         }
2272                 };
2273         })();
2274
2275 /* ----------------------------------------
2276  * TOOL_BOX_WINDOW
2277  * - window
2278  */
2279         var TOOL_BOX_WINDOW = ( function(){
2280                         
2281                 app.addKeyEventListener( 'keydown', addImage,   73, false, true );
2282                 app.addKeyEventListener( 'keydown', addText,    84, false, true );
2283                 app.addKeyEventListener( 'keydown', switchGrid, 71, false, true );
2284
2285                 function addImage(){
2286                         // IMAGE_EXPLORER_WINDOW.open();
2287                         app.addAsyncCall( IMAGE_EXPLORER_WINDOW.open, null, IMAGE_EXPLORER_WINDOW );
2288                         //TOOL_BOX_WINDOW.bodyBackOrForward( true );
2289                 };
2290                 function addText(){
2291                         app.addAsyncCall( PANEL_ELEMENT_CONTROL.createTextElement );
2292                 };
2293                 function switchGrid(){
2294                         app.addAsyncCall( GRID_CONTROL.update, null, GRID_CONTROL );
2295                 };
2296                 function popupHelp(){
2297                         //.bodyBackOrForward( true );
2298                         app.addAsyncCall( HELP_DOCUMENTS_WINDOW.open, null, HELP_DOCUMENTS_WINDOW );
2299                 };
2300                 function editBG( e ){
2301                         //TOOL_BOX_WINDOW.bodyBackOrForward( true );
2302                         app.addAsyncCall( INFOMATION_WINDOW.open, null, INFOMATION_WINDOW );
2303                 };
2304                 
2305                 return WINDOWS_CONTROL.createWindow(
2306                         {
2307                                 onInit: function(){
2308                                         MENU_BAR_CONTROL.EDIT.createOption( 'Add Image', 'ctrl + I', addImage, true, true, false );
2309                                         MENU_BAR_CONTROL.EDIT.createOption( 'Add Text',  'ctrl + T', addText, true, false, true );
2310                                         MENU_BAR_CONTROL.EDIT.createOption( 'show Grid', 'ctrl + G', switchGrid, true, true, true );
2311                                 },
2312                                 onFirstOpen: function( x, y, nodeBody ){
2313                                         nodeBody.createNode( document.getElementById( 'toolbox-add-image-button'  ), false, true, 'button-hover', 'pointer' ).addEventListener( 'click', addImage );
2314                                         nodeBody.createNode( document.getElementById( 'toolbox-add-text-button'   ), false, true, 'button-hover', 'pointer' ).addEventListener( 'click', addText );
2315                                         nodeBody.createNode( document.getElementById( 'toolbox-edit-bg-button'    ), false, true, 'button-hover', 'pointer' ).addEventListener( 'click', editBG );
2316                                         nodeBody.createNode( document.getElementById( 'toolbox-switch-grid'       ), false, true, 'button-hover', 'pointer' ).addEventListener( 'click', switchGrid );
2317                                         nodeBody.createNode( document.getElementById( 'toolbox-popup-help-button' ), false, true, 'button-hover', 'pointer' ).addEventListener( 'click', popupHelp );
2318                                         // nodeBody.createNode( document.getElementById( 'toolbox-add-text-button'   ), false, true, 'button-hover', 'pointer' ).addEventListener( 'click', addText );
2319                                 }
2320                         },
2321                         'toolbox-window', 'Tool box', 0, 215, 110, 290, true
2322                 );
2323         })();
2324         
2325         
2326 /* ----------------------------------------
2327  * IMAGE_EXPROLER
2328  *  - window
2329  */
2330         var IMAGE_EXPLORER_WINDOW = ( function(){
2331                 var tree, finder;
2332                 
2333                 function onFileSelect( file ){
2334                         // 他の image ファイルも許可する?
2335                         if( Driver.isPettanrFileInstance( file ) === true ){
2336                                 if( file.getType() === FILE_TYPE.RESOURCE_PICTURE ){
2337                                         PANEL_ELEMENT_CONTROL.onImageSelect( FileAPI.getFileData( file ) );
2338                                 };
2339                         };
2340                 };
2341                 
2342                 return WINDOWS_CONTROL.createWindow(
2343                         {
2344                                 onInit: function(){},
2345                                 onFirstOpen: function( _w, _h, nodeBody ){
2346                                         tree = FileAPI.createTree( FILE_DATA_RESOURCE_PICTURES_ROOT );
2347                                         var     _root  = tree.getRootFile(),
2348                                                 _myPic = _root.getChildFileAt( 0 ),
2349                                                 _pic   = _root.getChildFileAt( 1 );
2350                                         _myPic.getSeqentialFiles();
2351                                         _pic.getSeqentialFiles();
2352                                         _myPic.destroy();
2353                                         _pic.destroy(); 
2354                         
2355                                         finder = app.createFinder(
2356                                                 nodeBody,
2357                                                 tree,
2358                                                 onFileSelect
2359                                         );
2360                                         finder.createPath( IMAGE_EXPLORER_WINDOW.createHeaderItem() );
2361                                 },
2362                                 onOpen: function( _w, _h ){
2363                                         finder.resize( _w, _h );
2364                                 },
2365                                 onResize: function( _w, _h ){
2366                                         finder.resize( _w, _h );
2367                                 }
2368                         },
2369                         null, 'Album', 0, 215, 600, 350, false, true, true, 300, 300
2370                 );
2371         })();
2372         
2373         
2374 /* ----------------------------------------
2375  * INFOMATION_WINDOW
2376  *  - window
2377  */                     
2378         var INFOMATION_WINDOW = ( function(){
2379                 var backgroundInfomationElm;
2380
2381                 return WINDOWS_CONTROL.createWindow(
2382                         {
2383                                 onFirstOpen: function( _w, _h ){
2384                                         backgroundInfomationElm = $( '#panel-background-information');
2385                                 },
2386                                 onResize: function(  _w, _h ){
2387                                 },
2388                                 update: function( currentElement ){
2389
2390                                 }
2391                         },
2392                         'infomation-window', 'Infomation', 0, 30, 200, 180, true
2393                 );
2394         })();
2395
2396 /* ----------------------------------------
2397  * HELP_WINDOW
2398  *  - window
2399  */
2400         var HELP_DOCUMENTS_WINDOW = ( function(){
2401                 var visible          = true,
2402                         jqAjaxContents,
2403                         jqNaviItems,
2404                         jqPages,
2405                         currentPageIndex = 0,
2406                         numPage          = 0,
2407                         asyncOption      = null;
2408
2409                 function onAjaxStart( _pageIndex ){
2410                         delete asyncOption.callback;
2411                         
2412                         currentPageIndex = _pageIndex || currentPageIndex;
2413                         if( onHelpLoad !== null ){
2414                                 $.ajax({
2415                                         url:            'help/jp.xml',
2416                                         dataType:       'xml',
2417                                         success:        onHelpLoad
2418                                 });
2419                                 onHelpLoad = null;
2420                         }
2421                         onAjaxStart = null;
2422                 };
2423                 var onHelpLoad = function( _xml ){
2424                         var jqXML          = $( _xml ),
2425                                 helpTitle      = jqXML.find( 'pages' ).eq( 0 ).attr( 'title' ),
2426                                 elmRoot        = document.createElement( 'div' ),
2427                                 elmNavi        = document.createElement( 'div' ),
2428                                 elmItemOrigin  = document.createElement( 'a' ),
2429                                 elmPages       = document.createElement( 'div' ),
2430                                 elmPageOrigin  = document.createElement( 'div' ),
2431                                 elmTitleOrigin = document.createElement( 'h2' ),
2432                                 elmPage;
2433                         elmRoot.className       = 'multi-page-container clearfix';
2434                         elmNavi.className       = 'sidenavi';
2435                         elmItemOrigin.className = 'sidenavi-item';
2436                         elmItemOrigin.href      = '#';
2437                         elmPages.className      = 'page-contents';
2438                         elmPageOrigin.className = 'page-content main';
2439                         elmPageOrigin.appendChild( elmTitleOrigin);
2440                         
2441                         MENU_BAR_CONTROL.HELP.remove( asyncOption );
2442                         asyncOption = null;                     
2443                         
2444                         jqXML.find( 'page' ).each( function(){
2445                                 var xmlPage = $( this ),
2446                                         title = xmlPage.attr( 'title' ),
2447                                         content = xmlPage.text();
2448                                 
2449                                 elmItemOrigin.innerHTML = title;
2450                                 elmNavi.appendChild( elmItemOrigin.cloneNode( true ) );
2451                                 
2452                                 elmTitleOrigin.innerHTML = title;
2453                                 
2454                                 elmPage = elmPageOrigin.cloneNode( true );
2455                                 elmPage.innerHTML = content;
2456                                 
2457                                 Util.cleanElement( elmPage);
2458                                 
2459                                 if( elmPage.childNodes.length > 0 ){
2460                                         elmPage.insertBefore( elmTitleOrigin.cloneNode( true ), elmPage.childNodes[0]);
2461                                 } else {
2462                                         elmPage.appendChild( elmTitleOrigin.cloneNode( true ));
2463                                 }
2464                                 elmPages.appendChild( elmPage );
2465                                 
2466                                 MENU_BAR_CONTROL.HELP.createOption( title, null, onSelectionClick, true );
2467                                 ++numPage;
2468                         });
2469                         elmRoot.appendChild( elmNavi );
2470                         elmRoot.appendChild( elmPages );
2471                         jqAjaxContents.removeClass( 'loading' ).append( elmRoot );
2472                         
2473                         jqNaviItems = jqAjaxContents.find( 'a.' + elmItemOrigin.className ).click( onNaviClick );
2474                         jqPages     = jqAjaxContents.find( '.page-content' );
2475                         jqPages.find( 'a' ).click( onInnerLinkClick );
2476                         
2477                         app.addAsyncCall( jumpPage );
2478                 };
2479                 function onSelectionClick( _pageIndex ){
2480                         HELP_DOCUMENTS_WINDOW.open();
2481                         jumpPage( _pageIndex );
2482                 };
2483                 function jumpPage( _index ){
2484                         if( Type.isNumber( _index ) === true && 0 <= _index && _index < numPage && currentPageIndex !== _index ){
2485                                 currentPageIndex = _index;
2486                         };
2487                         jqNaviItems.removeClass( 'current' ).eq( currentPageIndex ).addClass( 'current' );
2488                         jqPages.hide().eq( currentPageIndex ).show();
2489                 };
2490                 function onNaviClick( e ){
2491                         // this は <a>
2492                         jumpPage( Util.getChildIndex( this.parentNode, this ) );
2493                         return false;
2494                 };
2495                 function onInnerLinkClick( e ){
2496                         var jump = ( this.href || '' ).split( '#jump' ),
2497                                 n = jump[ 1 ];
2498                         if( !n ) return;
2499                         jumpPage( '' + parseFloat( n ) === n ? parseFloat( n ) : -1 );
2500                         return false;                           
2501                 };
2502                 return WINDOWS_CONTROL.createWindow(
2503                         {
2504                                 onInit: function(){
2505                                         asyncOption    = MENU_BAR_CONTROL.HELP.createAsyncOption( onAjaxStart );
2506                                         jqAjaxContents = $( HELP_DOCUMENTS_WINDOW.elm ).find( '.window-body' ).addClass( 'loading' ).css( { overflow: 'auto' } );
2507                                 },
2508                                 onFirstOpen: function( _w, _h ){
2509                                         jqAjaxContents.css( { height: _h } );
2510                                         onAjaxStart !== null && onAjaxStart();
2511                                 },
2512                                 onResize: function( _w, _h ){
2513                                         jqAjaxContents && jqAjaxContents.css( { height: _h } );
2514                                 }
2515                         },
2516                         null, 'Help', 0, 215, 400, 350, false, true, true, 300, 300
2517                 );
2518         })();
2519
2520 /* ----------------------------------------
2521  * GRID_CONTROL
2522  *  - control
2523  *  - panelResizeListener
2524  */
2525         var GRID_CONTROL = ( function(){
2526                 var elmGrid,
2527                         urlBG   = "url('images/grid.gif')",
2528                         visible = false;
2529
2530                 return {
2531                         init: function(){
2532                                 elmGrid = document.getElementById( 'grid' );
2533                                 delete GRID_CONTROL.init;
2534                         },
2535                         open: function(){
2536                                 delete GRID_CONTROL.open;
2537                         },
2538                         close: function(){
2539                                 
2540                         },
2541                         onPanelResize: function( _panelX, _panelY ){
2542                                 elmGrid.style.backgroundPosition = [ _panelX % 10, 'px ', _panelY % 10, 'px' ].join( '' );
2543                                 elmGrid.style.height = windowH +'px';
2544                         },
2545                         enabled: function(){
2546                                 return visible;
2547                         },
2548                         update: function(){
2549                                 $( elmGrid ).stop().css( {
2550                                         opacity:        '',
2551                                         fliter:         ''
2552                                 })[ visible === true ? 'fadeOut' : 'fadeIn' ]();
2553                                 
2554                                 visible = !visible;
2555                                 
2556                                 if( visible === true && urlBG !== null ){
2557                                         elmGrid.style.backgroundImage = urlBG;
2558                                         urlBG = null;
2559                                 }
2560                                 return visible;
2561                         }
2562                 }
2563         })();
2564                 
2565 /* ----------------------------------------
2566  * WHITE_GLASS_CONTROL
2567  *  - panelResizeListener
2568  */
2569         var WHITE_GLASS_CONTROL = ( function(){
2570                 var styleTop, styleLeft, styleRight, styleBottom;
2571
2572                 return {
2573                         init: function(){
2574                                 styleTop    = document.getElementById( 'whiteGlass-top' ).style;
2575                                 styleLeft   = document.getElementById( 'whiteGlass-left' ).style;
2576                                 styleRight  = document.getElementById( 'whiteGlass-right' ).style;
2577                                 styleBottom = document.getElementById( 'whiteGlass-bottom' ).style;
2578                                 delete WHITE_GLASS_CONTROL.init;
2579                         },
2580                         onPanelResize: function( _panelX, _panelY, _panelW, _panelH ){
2581                                 var     _w             = _panelW,
2582                                         _h             = _panelH,
2583                                         marginTop      = _panelY,
2584                                         marginBottom   = windowH -_h -marginTop,
2585                                         marginX        = _panelX,
2586                                         rightWidth     = windowW -_w -marginX;
2587                                 
2588                                 styleTop.height    = ( marginTop < 0 ? 0 : marginTop ) + 'px';
2589                                 
2590                                 styleLeft.top      = marginTop + 'px';
2591                                 styleLeft.width    = ( marginX < 0 ? 0 : marginX ) + 'px';
2592                                 styleLeft.height   = ( _h + marginBottom ) + 'px';
2593                                 
2594                                 styleRight.top     = marginTop + 'px';
2595                                 styleRight.left    = _w +marginX + 'px';
2596                                 styleRight.width   = ( rightWidth < 0 ? 0 : rightWidth ) + 'px';
2597                                 styleRight.height  = ( _h + marginBottom ) + 'px';
2598                                 
2599                                 styleBottom.top    = ( _h +marginTop ) + 'px';
2600                                 styleBottom.left   = marginX + 'px';
2601                                 styleBottom.width  = _w + 'px';
2602                                 styleBottom.height = ( marginBottom < 0 ? 0 : marginBottom ) + 'px';
2603                         }
2604                 };
2605         })();
2606
2607
2608 /* --------------------------------------------------------------------------------------------
2609  * PanelResizerClass
2610  *  - mouseEventListener
2611  */
2612         var PanelResizerClass = function( id, isTop ){
2613                 this.id    = id;
2614                 this.isTop = isTop;
2615         };
2616         PanelResizerClass.BORDER_SIZE = 2;
2617         PanelResizerClass.HEIGHT      = 30;
2618         PanelResizerClass.prototype = {
2619                 id             : null,
2620                 node           : null,
2621                 style          : null,
2622                 isTop          : false,
2623                 x              : - PanelResizerClass.BORDER_SIZE / 2,
2624                 y              : 0,
2625                 w              : 0,
2626                 h              : PanelResizerClass.HEIGHT,
2627                 panelX         : 0,
2628                 panelY         : 0,
2629                 panelW         : 0,
2630                 panelH         : 0,
2631                 offsetY        : 0,
2632                 startY         : 0,
2633                 startH         : 0,
2634                 isDragging     : false,
2635                 init : function(){
2636                         this.node  = PANEL_CONTROL.node.createNode( document.getElementById( this.id ), false, false, 'panel-resizer-hover', 'pointer' );
2637                         this.node.addEventListener( 'mousedown', this.mousedown, this );
2638                         this.style = document.getElementById( this.id ).style;
2639                         this.y     = this.isTop === true ? ( -5 - PanelResizerClass.HEIGHT - PanelResizerClass.BORDER_SIZE ) : 0;
2640                 },      
2641                 mousedown : function( e ){
2642                         
2643                         var x = e.layerX, // - this.panelX,
2644                                 y = e.layerY; // - this.panelY;
2645                         this.offsetY    = y;
2646                         this.startY     = this.panelY;
2647                         this.startH     = this.panelH;
2648                         this.isDragging = true;
2649                         // app.updateCoursor( 'n-resize' );
2650                         this.node.addEventListener( 'mousemove', this.mousemove, this );
2651                         this.node.addEventListener( 'mouseup',   this.mouseup,   this );
2652                         this.node.cursor( 'n-resize' );
2653                         return true;
2654                 },
2655                 mousemove : function( e ){
2656                         var move = e.layerY - this.offsetY,
2657                                 h;
2658
2659                         if( this.isTop === true ){
2660                                 if( this.panelH - move < MIN_PANEL_HEIGHT ){
2661                                         move = this.panelH - MIN_PANEL_HEIGHT;
2662                                 };
2663                                 PANEL_CONTROL.resizeElement( true, this.panelX, this.panelY + move, this.panelW, this.panelH - move );
2664                         } else {
2665                                 h = this.startH + move;
2666                                 if( 0 < h && h < windowH - this.panelY - PanelResizerClass.HEIGHT - 5 - PanelResizerClass.BORDER_SIZE ){
2667                                         PANEL_CONTROL.resizeElement( false, this.panelX, this.panelY, this.panelW, h < MIN_PANEL_HEIGHT ? MIN_PANEL_HEIGHT : h );
2668                                 };
2669                         };
2670                         return true;
2671                 },
2672                 mouseup : function( e ){
2673                         if( this.isDragging !== true ) return;
2674                         ( this.startY !== this.panelY || this.startH !== this.panelH ) &&
2675                                 HISTORY_CONTROL.saveState(
2676                                         this.restoreState,
2677                                         [ undefined, this.startY, undefined, this.startH ],
2678                                         [ undefined, this.panelY, undefined, this.panelH ],
2679                                         null, this
2680                                 );
2681                         this.isDragging = false;
2682                         var move = e.layerY - this.offsetY,
2683                                 h;
2684
2685                         if( this.isTop === true ){
2686                                 if( this.panelH - move < MIN_PANEL_HEIGHT ){
2687                                         move = this.panelH - MIN_PANEL_HEIGHT;
2688                                 };
2689                                 PANEL_CONTROL.resize( true, this.panelX, this.panelY + move, this.panelW, this.panelH - move );
2690                         } else {
2691                                 h = this.startH + move;
2692                                 if( 0 < h && h < windowH - this.panelY - PanelResizerClass.HEIGHT - 5 - PanelResizerClass.BORDER_SIZE ){
2693                                         PANEL_CONTROL.resize( false, this.panelX, this.panelY, this.panelW, h < MIN_PANEL_HEIGHT ? MIN_PANEL_HEIGHT : h );
2694                                 };
2695                         };
2696                         // app.updateCoursor( '' );
2697                         this.node.removeEventListener( 'mousemove', this.mousemove );
2698                         this.node.removeEventListener( 'mouseup',   this.mouseup );
2699                         this.node.cursor( 'pointer' );
2700                 },
2701                 restoreState : function( x, y, w, h ){
2702                         PANEL_CONTROL.resize( this.isTop, x || this.panelX, y || this.panelY, w || this.panelW, h || this.panelH );
2703                 },
2704                 busy : function(){
2705                         return this.isDragging;
2706                 },
2707                 onPanelResize : function( x, y, w, h ){
2708                         this.panelX = x;
2709                         this.panelY = y;
2710                         if( this.panelW !== w ){
2711                                 this.style.width = ( w + 2 ) + 'px';
2712                                 this.panelW      = w;
2713                         };
2714                         this.panelH = h;
2715                         this.y = this.isTop === true ? this.y : ( this.panelH + 5 + PanelResizerClass.BORDER_SIZE );
2716                         this.w = this.panelW + 2;
2717                         this.node.update( undefined, undefined, this.w );
2718                 }       
2719         };
2720
2721 /* ----------------------------------------
2722  * PANEL_CONTROL
2723  *  - controler
2724  *  - mouseEventListener
2725  * 
2726  * panel-border の表示と onPanelResize の通知.
2727  * panel drag.
2728  * 
2729  */
2730         var PANEL_CONTROL = ( function(){
2731                 var elmPanel, stylePanel,
2732                         nodePanel            = null,
2733                         DEFAULT_PANEL_WIDTH  = 400,
2734                         DEFAULT_PANEL_HEIGHT = 300,
2735                         borderSize           = 2,
2736                         offsetX, offsetY, startX, startY,
2737                         isDragging           = false,
2738                         isDraggable          = false,
2739                         resizerTop           = new PanelResizerClass( 'panel-resizer-top',    true ),
2740                         resizerBottom        = new PanelResizerClass( 'panel-resizer-bottom', false );
2741                 
2742                 app.addKeyEventListener( 'keychange', onSpaceUpdate, 32, false, false );
2743                 
2744                 function onSpaceUpdate( e ){
2745                         if( e.type === 'keyup' ){
2746                                 app.isCurrentInteractiveEventListener( null ) === true && app.updateCoursor( '' );
2747                                 isDraggable = false;
2748                         } else {
2749                                 app.isCurrentInteractiveEventListener( null ) === true && app.updateCoursor( 'move' );
2750                                 isDraggable = true;
2751                         };
2752                         return false;
2753                 };
2754                 
2755                 return {
2756                         id   : 'PANEL_CONTROL',
2757                         x    : 0,
2758                         y    : 0,
2759                         w    : 0,
2760                         h    : 0,
2761                         elm  : null,
2762                         node : null,
2763                         init : function(){
2764                                 elmPanel      = this.elm  = document.getElementById( 'panel-tools-container' );
2765                                 nodePanel     = this.node = eventRoot.createNode( elmPanel, true, false );
2766                                 
2767                                 resizerTop.init();
2768                                 resizerBottom.init();
2769                                 
2770                                 stylePanel = elmPanel.style;
2771                                 delete PANEL_CONTROL.init;
2772                         },
2773                         open: function( _panelW, _panelH, _borderSize ){
2774                                 PANEL_CONTROL.w = Type.isFinite( _panelW ) === true ? _panelW : DEFAULT_PANEL_WIDTH;
2775                                 PANEL_CONTROL.h = Type.isFinite( _panelH ) === true ? _panelH : DEFAULT_PANEL_HEIGHT;
2776                                 borderSize      = Type.isFinite( _borderSize ) === true ? _borderSize : borderSize;
2777                                 
2778                                 delete PANEL_CONTROL.open;
2779                         },
2780                         close: function(){
2781                                 
2782                         },
2783                         resize: function( isResizerTopAction, x, y, w, h ){
2784                                 PANEL_CONTROL.x = x = x !== undefined ? x : PANEL_CONTROL.x;
2785                                 PANEL_CONTROL.y = y = y !== undefined ? y : PANEL_CONTROL.y;
2786                                 PANEL_CONTROL.w = w = w !== undefined ? w : PANEL_CONTROL.w;
2787                                 PANEL_CONTROL.h = h = h !== undefined ? h : PANEL_CONTROL.h;
2788                                 
2789                                 nodePanel.update( x - borderSize, y - borderSize, w, h );
2790
2791                                 
2792                                 resizerTop.onPanelResize( x, y, w, h );
2793                                 resizerBottom.onPanelResize( x, y, w, h );
2794                                 GRID_CONTROL.onPanelResize( x, y );
2795                                 WHITE_GLASS_CONTROL.onPanelResize( x, y, w, h );
2796                                 PANEL_ELEMENT_CONTROL.onPanelResize( x, y, w, h, isResizerTopAction === true );
2797                         },
2798                         resizeElement : function( isResizerTopAction, x, y, w, h ){
2799                                 stylePanel.cssText = [ 'left:',  ( x - borderSize ), 'px;',
2800                                                                          'top:',    ( y - borderSize ), 'px;',
2801                                                                          'width:',  w, 'px;',
2802                                                                          'height:', h, 'px' ].join( '' );
2803                                 // PANEL_RESIZER_TOP.onPanelResize( x, y, w, h );
2804                                 // PANEL_RESIZER_BOTTOM.onPanelResize( x, y, w, h );
2805                                 GRID_CONTROL.onPanelResize( x, y );
2806                                 WHITE_GLASS_CONTROL.onPanelResize( x, y, w, h );
2807                                 PANEL_ELEMENT_CONTROL.onPanelResize( x, y, w, h, isResizerTopAction );                  
2808                         },
2809                         onWindowResize: function( _windowW, _windowH ){
2810                                 PANEL_CONTROL.x = Math.floor( ( _windowW - PANEL_CONTROL.w ) / 2 );
2811                                 PANEL_CONTROL.y = Math.floor( ( _windowH - PANEL_CONTROL.h ) / 2 );
2812                                 PANEL_CONTROL.resize();
2813                         },
2814                         mousemove: function( _mouseX, _mouseY ){
2815                                 if( isDraggable === true && isDragging === true ){
2816                                         PANEL_CONTROL.resize( false, startX + _mouseX - offsetX, startY + _mouseY - offsetY );
2817                                 };
2818                         },
2819                         mouseup: function( _mouseX, _mouseY ){
2820                                 if( isDraggable === true ){
2821                                         isDragging = false;
2822                                         app.updateCoursor( '' );
2823                                 };
2824                         },
2825                         mousedown: function( _mouseX, _mouseY ){
2826                                 if( isDraggable === true ){
2827                                         offsetX    = _mouseX;
2828                                         offsetY    = _mouseY;
2829                                         startX     = PANEL_CONTROL.x;
2830                                         startY     = PANEL_CONTROL.y;
2831                                         isDragging = true;
2832                                         app.updateCoursor( 'move' );
2833                                         return true;
2834                                 };
2835                         },
2836                         busy: function(){
2837                                 return isDragging === true;
2838                         }                               
2839                 };
2840         })();
2841
2842 /* --------------------------------------------------------------------------------------------
2843  * TailOperator
2844  *  - panelElementOperator
2845  */
2846         var TailOperator = ( function(){
2847                 var     styleMover,
2848                         SIZE,
2849                         SIN          = Math.sin,
2850                         COS          = Math.cos,
2851                         ATAN         = Math.atan,
2852                         FLOOR        = Math.floor,
2853                         DEG_TO_RAD   = Math.PI / 180,
2854                         RAD_TO_DEG   = 1 / DEG_TO_RAD,
2855                         currentText  = null,
2856                         tailX, tailY,
2857                         w, h,
2858                         balloonW, balloonH, balloonA, radA,
2859                         visible = false,
2860                         startA;
2861                 
2862                 return {
2863                         init: function(){
2864                                 var elm    = document.getElementById( 'balloon-tail-mover' );
2865                                 SIZE       = Util.getElementSize( elm ).width;
2866                                 styleMover = elm.style;
2867                                 delete TailOperator.init;
2868                         },
2869                         update: function ( _w, _h, _a ){
2870                                 balloonW = _w !== undefined ? _w : balloonW;
2871                                 balloonH = _h !== undefined ? _h : balloonH;
2872                                 balloonA = _a !== undefined ? _a : balloonA;
2873                                 radA = ( balloonA - 90 ) * DEG_TO_RAD;
2874                                 tailX = FLOOR( ( ( COS( radA ) / 2 + 0.5 ) * ( balloonW + SIZE )) - SIZE / 2 );
2875                                 tailY = FLOOR( ( ( SIN( radA ) / 2 + 0.5 ) * ( balloonH + SIZE )) - SIZE / 2 );
2876                                 styleMover.left = tailX + 'px';
2877                                 styleMover.top  = tailY + 'px';
2878                         },
2879                         show: function( _currentText ){
2880                                 /**
2881                                  * visibilityのほうがいい, display:none だと ie で描画が狂う
2882                                  */
2883                                 styleMover.visibility = '';
2884                                 currentText = _currentText;
2885                                 TailOperator.update( _currentText.w, _currentText.h, _currentText.a );
2886                         },
2887                         hide: function(){
2888                                 styleMover.visibility = 'hidden';
2889                                 currentText = null;
2890                         },                      
2891                         hitTest: function( _mouseX, _mouseY ){
2892                                 var _x  = tailX -SIZE / 2,
2893                                         _y  = tailY -SIZE / 2,
2894                                         ret = _x <= _mouseX && _y <= _mouseY && _x + SIZE >= _mouseX && _y + SIZE >= _mouseY;
2895                                 ret === true && app.updateCoursor( 'move' );
2896                                 return ret;
2897                         },
2898                         onStart: function( _mouseX, _mouseY ){
2899                                 if( currentText.type !== PANEL_ELEMENT_TYPE_TEXT ) return false;
2900                                 if( TailOperator.hitTest( _mouseX, _mouseY ) === true ){
2901                                         w = currentText.w;
2902                                         h = currentText.h;
2903                                         startA = currentText.a;
2904                                         return true;
2905                                 };
2906                                 return false;
2907                         },
2908                         onDrag: function( _mouseX, _mouseY ){
2909                                 _mouseX = _mouseX - w / 2;
2910                                 _mouseY = _mouseY - h / 2; //Balloonの中心を0,0とする座標系に変換
2911                                 TailOperator.update( w, h,
2912                                         _mouseX !== 0 ?
2913                                                 ATAN( _mouseY / _mouseX ) * RAD_TO_DEG + ( _mouseX > 0 ? 90 : 270 ) :
2914                                                 _mouseY > 0 ? 180 : 0
2915                                 );
2916                                 currentText && currentText.angle( FLOOR( balloonA + 0.5 ) );
2917                                 CONSOLE_CONTROLER.update( currentText );
2918                         },
2919                         onFinish: function(){
2920                                 startA !== currentText.a && PanelElementOperatorManager.saveStatus( undefined, undefined, w, h, startA );
2921                                 startA !== currentText.a && PanelElementOperatorManager.resize( undefined, undefined, w, h, currentText.a );
2922                         },
2923                         onCancel: function(){
2924                                 currentText.angle( startA );
2925                                 PanelElementOperatorManager.resize( undefined, undefined, w, h, startA );
2926                         }
2927                 }
2928         })();
2929
2930 /* --------------------------------------------------------------------------------------------
2931  * ResizeOperator
2932  *  - panelElementOperator
2933  */
2934         var ResizeOperator = ( function(){
2935                 var     HIT_AREA        = MOUSE_HIT_AREA,
2936                         POSITION_ARRAY  = [],
2937                         FLOOR           = Math.floor,
2938                         CURSOR_AND_FLIP = [
2939                                 { cursor:       'n-resize',             v: 3 },
2940                                 { cursor:       'e-resize',             h: 2 },
2941                                 { cursor:       'e-resize',             h: 1 },
2942                                 { cursor:       'n-resize',             v: 0 },
2943                                 { cursor:       'nw-resize',    h: 5, v: 6, vh: 7 },
2944                                 { cursor:       'ne-resize',    h: 4, v: 7, vh: 6 },
2945                                 { cursor:       'ne-resize',    h: 7, v: 4, vh: 5 },
2946                                 { cursor:       'nw-resize',    h: 6, v: 5, vh: 4 }
2947                         ],
2948                         styleInner,
2949                         elmInner,
2950                         styleResizerTop,
2951                         styleResizerLeft,
2952                         styleResizerRight,
2953                         styleResizerBottom,
2954                         x, y, w, h,
2955                         currentIndex = -1,
2956                         currentElement,
2957                         isSpeach = false;
2958                 
2959                 var RESIZE_WORK_ARRAY = [
2960                                 { x:    0, w:    0, y:  1, h:   -1}, //top
2961                                 { x:    1, w:   -1, y:  0, h:    0}, //left
2962                                 { x:    0, w:    1, y:  0, h:    0}, //right
2963                                 { x:    0, w:    0, y:  0, h:    1}, //bottom
2964                                 { x:    1, w:   -1, y:  1, h:   -1}, //top-left
2965                                 { x:    0, w:    1, y:  1, h:   -1}, //top-right
2966                                 { x:    1, w:   -1, y:  0, h:    1}, //bottom-left
2967                                 { x:    0, w:    1, y:  0, h:    1}  //bottom-right
2968                         ],
2969                         startX, startY, startW, startH,
2970             flipV, flipH, startFilpV, startFilpH, startAspect,
2971                         baseX, baseY, baseW, baseH,
2972                         currentX, currentY, currentW, currentH,
2973                         offsetX, offsetY,
2974                         error = 0;
2975                 
2976                 function update( _x, _y, _w, _h ){
2977                         var __w, __h;
2978                         _x = _x !== undefined ? _x : currentX;
2979                         _y = _y !== undefined ? _y : currentY;
2980                         _w = _w !== undefined ? _w : currentW;
2981                         _h = _h !== undefined ? _h : currentH;
2982                         
2983                         if( isSpeach === false && currentIndex > 3 && app.shiftEnabled() === true ){
2984                                 if( startAspect >= 1 ){
2985                                         __w = _w;
2986                                         _w  = FLOOR( startAspect * _h );
2987                                         _x  = _x + ( currentIndex % 2 === 0 ? __w - _w : 0 );
2988                                 } else {
2989                                         __h = _h;
2990                                         _h  = FLOOR( _w / startAspect );
2991                                         _y  = _y + ( currentIndex <= 5 ? __h - _h : 0 );
2992                                 };
2993                         };
2994                         ResizeOperator.update( x = _x, y = _y, w = _w, h = _h );
2995                         currentElement.resize( _x, _y, _w, _h );
2996                         isSpeach === true && TailOperator.update( _w, _h );
2997                         CONSOLE_CONTROLER.show( currentElement, _w, _h );
2998                         // CONSOLE_CONTROLER.update( currentElement );
2999                 };
3000                 
3001                 function flip( _flipH, _flipV ){
3002                         var p = CURSOR_AND_FLIP[ currentIndex ];
3003                         currentIndex = _flipH === true || _flipV === true ? p[
3004                                         _flipH === true && _flipV === true ? 'vh' : ( _flipH === true ? 'h' : 'v' )
3005                                 ] : currentIndex;
3006                         app.updateCoursor( CURSOR_AND_FLIP[ currentIndex ].cursor );
3007                         elmInner.className = 'current-resizer-is-' + currentIndex;
3008                         currentElement.flip( _flipH, _flipV );
3009                 };
3010                 return {
3011                         init: function(){
3012                                 elmInner           = document.getElementById( 'comic-element-resizer-container-inner' );
3013                                 styleInner         = elmInner.style;
3014                                 
3015                                 styleResizerTop    = document.getElementById( 'comic-element-resizer-top' ).style;
3016                                 styleResizerLeft   = document.getElementById( 'comic-element-resizer-left' ).style;
3017                                 styleResizerRight  = document.getElementById( 'comic-element-resizer-right' ).style;
3018                                 styleResizerBottom = document.getElementById( 'comic-element-resizer-bottom' ).style;
3019                                 
3020                                 delete ResizeOperator.init;
3021                         },
3022                         update: function( _x, _y, _w, _h ){
3023                                 x = _x = _x !== undefined ? _x : x;
3024                                 y = _y = _y !== undefined ? _y : y;
3025                                 w = _w = _w !== undefined ? _w : w;
3026                                 h = _h = _h !== undefined ? _h : h;
3027                                 
3028                                 PanelElementOperatorManager.resizeElement( _x, _y, _w, _h );
3029                                 
3030                                 styleInner.width  = _w + 'px';
3031                                 styleInner.height = _h + 'px';
3032                                 
3033                                 styleResizerTop.left = styleResizerBottom.left = FLOOR( _w / 2 - 5 ) + 'px';
3034                                 styleResizerLeft.top = styleResizerRight.top   = FLOOR( _h / 2 - 5 ) + 'px';
3035         
3036                                 POSITION_ARRAY.length = 0;
3037                                 POSITION_ARRAY.push(
3038                                         {x:     5,                              y:      -HIT_AREA,              w:      _w - 5,                 h:      HIT_AREA * 2 }, // top
3039                                         {x: -HIT_AREA,          y:      5,                              w:      HIT_AREA * 2,   h:      _h - 5 },   // left
3040                                         {x: _w - 5,                     y:      HIT_AREA + 5,   w:      HIT_AREA * 2,   h:      _h - 5 },   // right
3041                                         {x:     5,                              y:      _h - 5,                 w:      _w - 5,                 h:      HIT_AREA * 2 }, // bottom
3042                                         {x:     -HIT_AREA,              y:      -HIT_AREA,              w:      HIT_AREA + 5,   h:      HIT_AREA + 5}, // top left
3043                                         {x: _w - 5,                     y:      -HIT_AREA,              w:      HIT_AREA + 5,   h:      HIT_AREA + 5}, // top right
3044                                         {x:     -HIT_AREA,              y:      _h - 5,                 w:      HIT_AREA + 5,   h:      HIT_AREA + 5}, // bottom left
3045                                         {x:     _w - 5,                 y:      _h - 5,                 w:      HIT_AREA + 5,   h:      HIT_AREA + 5}  // bottom right
3046                                 );
3047                         },
3048                         index: function( _mouseX, _mouseY ){
3049                                 var     p, i;
3050                                 for( i = 4; i < 8; ++i ){
3051                                         p = POSITION_ARRAY[ i ];
3052                                         if( p.x <= _mouseX && p.y <= _mouseY && p.x + p.w >= _mouseX && p.y + p.h >= _mouseY ){
3053                                                 app.updateCoursor( CURSOR_AND_FLIP[ i ].cursor );
3054                                                 elmInner.className  = 'current-resizer-is-' + i;
3055                                                 return currentIndex = i;
3056                                         };
3057                                 };
3058                                 for( i = 0; i < 4; ++i ){
3059                                         p = POSITION_ARRAY[ i ];
3060                                         if( p.x <= _mouseX && _mouseX <= p.x + p.w && p.y <= _mouseY && _mouseY <= p.y + p.h ){
3061                                                 app.updateCoursor( CURSOR_AND_FLIP[ i ].cursor );
3062                                                 elmInner.className  = 'current-resizer-is-' + i;
3063                                                 return currentIndex = i;
3064                                         };
3065                                 };
3066                                 app.updateCoursor( '' );
3067                                 elmInner.className = '';
3068                                 return -1;
3069                         },
3070                         show: function( _currentElement ){
3071                                 currentElement = _currentElement;
3072                                 isSpeach = _currentElement.type === PANEL_ELEMENT_TYPE_TEXT;
3073                                 ResizeOperator.update( _currentElement.x, _currentElement.y, _currentElement.w, _currentElement.h );
3074                         },
3075                         hide: function(){
3076                                 currentElement = null;
3077                         },
3078                         onStart: function( _mouseX, _mouseY ){
3079                                 isSpeach = currentElement.type === PANEL_ELEMENT_TYPE_TEXT;
3080                                 if( currentElement.keepSize === true ) return false;
3081                                 currentIndex = this.index( _mouseX, _mouseY );
3082                                 if( currentIndex === -1 ) return false;
3083                                 offsetX = _mouseX;
3084                                 offsetY = _mouseY;
3085                                 startX = baseX = currentElement.x;
3086                                 startY = baseY = currentElement.y;
3087                                 startW = baseW = currentElement.w;
3088                                 startH = baseH = currentElement.h;
3089                                 startFilpV = currentElement.flipV;
3090                                 startFilpH = currentElement.flipH;
3091                                 startAspect = startW / startH;
3092                                 return true;
3093                         },
3094                         onDrag: function( _mouseX, _mouseY ){
3095                                 var com      = RESIZE_WORK_ARRAY[ currentIndex ],
3096                                         moveX    = _mouseX - offsetX,
3097                                         moveY    = _mouseY - offsetY,
3098                                         _updated = moveX !== 0 || moveY !== 0,
3099                                         _x, _y, _w, _h,
3100                                         _thisError = 0;
3101                                         
3102                                 var _memoryX = 0,
3103                                         _memoryY = 0;
3104                                 /*
3105                                  * Opera 11+ often forget values, why ??
3106                                  */
3107                                 while( _x === undefined || _y === undefined || _w === undefined || _h === undefined ){
3108                                         _x = _x !== undefined ? _x : baseX + moveX * com.x;
3109                                         _y = _y !== undefined ? _y : baseY + moveY * com.y;
3110                                         _w = _w !== undefined ? _w : baseW + moveX * com.w;
3111                                         _h = _h !== undefined ? _h : baseH + moveY * com.h;
3112                                         error += _thisError === 0 ? 0 : 1;
3113                                         ++_thisError;
3114                                         if( _thisError > 9999 ){
3115                                                 ++error
3116                                                 //alert( 'opera error' +error);
3117                                                 this.onCancel();
3118                                                 return;
3119                                         };
3120                                 };
3121                                 
3122                                 if( _w >= MIN_ELEMENT_SIZE && _h >= MIN_ELEMENT_SIZE ){
3123                                         
3124                                 } else 
3125                                 if( _w >= -MIN_ELEMENT_SIZE && _h >= -MIN_ELEMENT_SIZE ){
3126                                         //return;
3127                                         if( _w < MIN_ELEMENT_SIZE){
3128                                                 //_x += Math.abs( MIN_ELEMENT_SIZE -_w);
3129                                                 _x = currentX;
3130                                                 _w = MIN_ELEMENT_SIZE;
3131                                         }
3132                                         if( _h < MIN_ELEMENT_SIZE){
3133                                                 //_y += Math.abs( MIN_ELEMENT_SIZE -_h);
3134                                                 _y = currentY;
3135                                                 _h = MIN_ELEMENT_SIZE;
3136                                         }
3137                                 } else 
3138                                 if( currentElement.type === PANEL_ELEMENT_TYPE_TEXT ){
3139                                         return;
3140                                 } else 
3141                                 if( _w < -MIN_ELEMENT_SIZE || _h < -MIN_ELEMENT_SIZE ){
3142
3143                                         if( _w < -MIN_ELEMENT_SIZE && _h > MIN_ELEMENT_SIZE ){
3144                                         // flipH
3145                                                 _memoryX = _x;
3146                                                 baseX    = _x = _x +_w;
3147                                                 baseY    = _y;
3148                                                 baseW    = _w = _memoryX -_x;
3149                                                 baseH    = _h;
3150                                                 flip( true, false );
3151                                                 flipV    = currentElement.flipV;
3152                                         } else 
3153                                         if( _w > MIN_ELEMENT_SIZE && _h < -MIN_ELEMENT_SIZE ){
3154                                         // flipV
3155                                                 _memoryY = _y;
3156                                                 baseX    = _x;
3157                                                 baseY    = _y = _y +_h;
3158                                                 baseW    = _w;
3159                                                 baseH    = _h = _memoryY -_y;
3160                                                 flip( false, true);
3161                                                 flipH    = currentElement.flipH;
3162                                         } else {
3163                                         // flipVH
3164                                                 _memoryX = _x;
3165                                                 _memoryY = _y;
3166                                                 baseX    = _x = _x + _w;
3167                                                 baseY    = _y = _y + _h;
3168                                                 baseW    = _w = _memoryX - _x;
3169                                                 baseH    = _h = _memoryY - _y;
3170                                                 flip( true, true );
3171                                                 flipV    = currentElement.flipV;
3172                                                 flipH    = currentElement.flipH;
3173                                         };
3174                                         _updated = true;
3175                                         offsetX  = _mouseX;
3176                                         offsetY  = _mouseY;     
3177                                 };
3178                                 currentX = _x;
3179                                 currentY = _y;
3180                                 currentW = _w;
3181                                 currentH = _h;
3182                                 _updated === true && update( _x, _y, _w, _h );
3183                                 /*
3184                                 log.html( [
3185                                                 'currentIndex:', currentIndex, 
3186                                                 'baseW', baseW, 'baseH', baseH,'<br>',
3187                                                 'mouse', _mouseX, _mouseY,'<br>',
3188                                                 'move', moveX, moveY,'<br>',
3189                                                 'xy', _x, _y, 'wh',_w, _h,'<br>',
3190                                                 'com.w', com.w, 'com.h', com.h,'<br>',
3191                                                 'current',currentW, currentH,'<br>',
3192                                                 'result', y, h,
3193                                                 'err', error
3194                                 ].join( ' , ')); */
3195                         },
3196                         onFinish: function(){
3197                                 app.updateCoursor( '' );
3198                                 if( w === startW && h === startH && x === startX && y === startY ) return;
3199                                 PanelElementOperatorManager.resize( x, y, w, h );
3200                                 currentElement.resize( x, y, w, h );
3201                                 PanelElementOperatorManager.saveStatus( startX, startY, startW, startH, undefined, startFilpV, startFilpH );
3202                         },
3203                         onCancel: function(){
3204                                 app.updateCoursor( '' );
3205                                 PanelElementOperatorManager.resize( startX, startY, startW, startH );
3206                                 currentElement.type === PANEL_ELEMENT_TYPE_IMAGE ?
3207                                         currentElement.animate( startX, startY, startW, startH, startFilpV, startFilpH ) :
3208                                         currentElement.animate( startX, startY, startW, startH, angle );
3209                         },
3210                         onShiftUpdate: update,
3211                         onCtrlUpdate: update
3212                 }
3213         })();
3214
3215 /* --------------------------------------------------------------------------------------------
3216  * PositionOperator
3217  *  - panelElementOperator
3218  */
3219         var PositionOperator = ( function(){
3220                 var HIT_AREA = MOUSE_HIT_AREA,
3221                         currentElement,
3222                         startX, startY,
3223                         x, y,
3224                         offsetX, offsetY,
3225                         isCopy = false;
3226                 function update( _x, _y ){
3227                         x = _x !== undefined ? _x : x;
3228                         y = _y !== undefined ? _y : y;
3229                         // ResizeOperator.update( x, y );
3230                         
3231                         PanelElementOperatorManager.resizeElement( x, y );
3232                         
3233                         currentElement.resize( x, y );
3234                         // CONSOLE_CONTROLER.update( currentElement );
3235                 };
3236                 return {
3237                         init: function(){
3238                                 delete PositionOperator.init;
3239                         },
3240                         show : function( _currentElement ){
3241                                 currentElement = _currentElement;
3242                         },
3243                         hide : function(){
3244                                 currentElement = null;
3245                         },
3246                         onStart: function( _mouseX, _mouseY ){
3247                                 offsetX = _mouseX;
3248                                 offsetY = _mouseY;
3249                                 startX  = x = currentElement.x;
3250                                 startY  = y = currentElement.y;
3251                                 app.updateCoursor( 'move' );
3252                         },
3253                         onDrag: function( _mouseX, _mouseY ){
3254                                 var moveX = _mouseX - offsetX,
3255                                         moveY = _mouseY - offsetY,
3256                                         _x    = startX + moveX,
3257                                         _y    = startY + moveY;
3258                                 if( GRID_CONTROL.enabled() === true ){
3259                                         _x = Math.floor( _x / 10 ) * 10;
3260                                         _y = Math.floor( _y / 10 ) * 10;
3261                                 };
3262                                 update( _x, _y );
3263                         },
3264                         onFinish: function(){
3265                                 app.updateCoursor( '' );
3266                                 if( x === startX && y === startY ) return;
3267                                 PanelElementOperatorManager.resize( x, y );
3268                                 currentElement.resize( x, y );
3269                                 PanelElementOperatorManager.saveStatus( startX, startY );
3270                         },
3271                         onCancel: function(){
3272                                 app.updateCoursor( '' );
3273                                 PanelElementOperatorManager.resize( startX, startY );
3274                                 currentElement.animate( startX, startY );
3275                         },
3276                         onShiftUpdate: update,
3277                         onCtrlUpdate: update
3278                 };
3279         })();
3280
3281
3282 /* --------------------------------------------------------------------------------------------
3283  * PanelElementOperatorManager
3284  */
3285         var PanelElementOperatorManager = ( function(){
3286                 var     HIT_AREA        = MOUSE_HIT_AREA,
3287                         isSpeach        = false,
3288                         currentOperator = null,
3289                         currentElement  = null,
3290                         node            = null,
3291                         styleContainer  = null,
3292                         currentX, currentY, currentW, currentH, angle, flipV, flipH;
3293                 
3294                 function mousedown( e ){
3295                         var x = e.layerX - HIT_AREA / 2 - 5,
3296                                 y = e.layerY - HIT_AREA / 2 - 5;
3297                         if( isSpeach === true && TailOperator.onStart( x, y ) === true ){
3298                                 currentOperator = TailOperator;
3299                         } else
3300                         if( ResizeOperator.onStart( x, y ) === true ){
3301                                 currentOperator = ResizeOperator;
3302                         } else {
3303                                 PositionOperator.onStart( x, y );
3304                                 currentOperator = PositionOperator;
3305                         };
3306                         // return true;
3307                 };
3308                 function mousemove( e ){
3309                         var x = e.layerX - HIT_AREA / 2 - 5,
3310                                 y = e.layerY - HIT_AREA / 2 - 5;
3311                         if( currentOperator !== null ){
3312                                 currentOperator.onDrag( x, y );
3313                                 return true;
3314                         } else
3315                         if( currentElement !== null ){
3316                                 ( isSpeach === false || TailOperator.hitTest( x, y ) === false ) && ResizeOperator.index( x, y );
3317                         };
3318                 };
3319                 function mouseup( e ){
3320                         currentOperator !== null && currentOperator.onFinish();
3321                         currentOperator = null;
3322                 };
3323                 
3324                 return {
3325                         elm  : null,
3326                         node : null,
3327                         init : function(){
3328                                 TailOperator.init();
3329                                 ResizeOperator.init();
3330                                 PositionOperator.init();
3331                                 CONSOLE_CONTROLER.init();
3332                                 
3333                                 app.addKeyEventListener( 'keychange', function( e ){
3334                                         currentOperator !== null && currentOperator.onShiftUpdate && currentOperator.onShiftUpdate();
3335                                         return false;
3336                                 }, 16 );
3337                                 app.addKeyEventListener( 'keychange', function( e ){
3338                                         currentOperator !== null && currentOperator.onCtrlUpdate && currentOperator.onCtrlUpdate();
3339                                         return false;
3340                                 }, 17 );
3341                                 app.addKeyEventListener( 'keydown', function( e ){
3342                                         currentOperator !== null && currentOperator.onCancel && currentOperator.onCancel();
3343                                         currentOperator = null;
3344                                         return false;
3345                                 }, 27, false, false );
3346                                 
3347                                 delete PanelElementOperatorManager.init;
3348                         },
3349                         open: function(){
3350                                 var elm = document.getElementById( 'comic-element-resizer-container' );
3351                                 PanelElementOperatorManager.elm  = elm;
3352                                 PanelElementOperatorManager.node = eventRoot.createNode( elm, false, false );
3353                                 PanelElementOperatorManager.node.addEventListener( 'mouseout', PanelElementOperatorManager.hide, PanelElementOperatorManager );
3354                                 styleContainer = elm.style;
3355                                 PanelElementOperatorManager.node.disabled( true );
3356                                 PanelElementOperatorManager.node.addEventListener( 'mousemove', mousemove );
3357                                 PanelElementOperatorManager.node.addEventListener( 'mousedown', mousedown );
3358                                 PanelElementOperatorManager.node.addEventListener( 'mouseup', mouseup );
3359                                 
3360                                 CONSOLE_CONTROLER.open();
3361                                 PanelElementOperatorManager.hide();
3362                                 
3363                                 delete PanelElementOperatorManager.open;
3364                         },
3365                         close: function(){
3366                                 
3367                         },
3368                         show : function( _currentElement ){
3369                                 if( currentElement === null ){
3370                                         styleContainer.display = '';
3371                                         PanelElementOperatorManager.node.disabled( false );
3372                                 };
3373                                 if( currentElement !== _currentElement ){
3374                                         currentElement = _currentElement;
3375                                         
3376                                         ResizeOperator.show( _currentElement );
3377                                         PositionOperator.show( _currentElement );
3378                                         
3379                                         isSpeach = ( _currentElement.type === PANEL_ELEMENT_TYPE_TEXT );
3380                                         isSpeach === true ? TailOperator.show( _currentElement ) : TailOperator.hide();
3381                                         
3382                                         flipV = _currentElement.flipV;
3383                                         flipH = _currentElement.flipH;
3384                                         
3385                                         PanelElementOperatorManager.resize(
3386                                                 _currentElement.x, _currentElement.y, _currentElement.w, _currentElement.h,
3387                                                 isSpeach === true ? _currentElement.a : 0
3388                                         );
3389                                 };
3390                         },
3391                         hide: function(){
3392                                 if( currentElement !== null ){
3393                                         styleContainer.display = 'none';
3394                                         PanelElementOperatorManager.node.disabled( true );
3395                                 };
3396                                 currentElement = null;
3397                                 app.updateCoursor( '' );
3398                                 TailOperator.hide();
3399                                 ResizeOperator.hide();
3400                                 PositionOperator.hide();
3401                                 CONSOLE_CONTROLER.hide();
3402                         },
3403                         resizeElement : function( _x, _y, _w, _h, _angle ){
3404                                 _x = _x !== undefined ? _x : currentX;
3405                                 _y = _y !== undefined ? _y : currentY;
3406                                 _w = _w !== undefined ? _w : currentW;
3407                                 _h = _h !== undefined ? _h : currentH;
3408                                 
3409                                 var style    = PanelElementOperatorManager.elm.style;
3410                                 style.left   = ( PANEL_CONTROL.x + _x - HIT_AREA / 2 - 5 ) + 'px';
3411                                 style.top    = ( PANEL_CONTROL.y + _y - HIT_AREA / 2 - 5 ) + 'px';
3412                                 style.width  = ( _w + HIT_AREA + 5 ) + 'px';
3413                                 style.heught = ( _h + HIT_AREA + 5 ) + 'px';
3414                                 
3415                                 // ResizeOperator.update( _x, _y, _w, _h );
3416                                 isSpeach === true && TailOperator.update( _w, _h, angle );
3417                                 CONSOLE_CONTROLER.show( currentElement, _w, _h );
3418                         },
3419                         resize: function( _x, _y, _w, _h, _angle ){
3420                                 currentX = _x = _x !== undefined ? _x : currentX;
3421                                 currentY = _y = _y !== undefined ? _y : currentY;
3422                                 currentW = _w = _w !== undefined ? _w : currentW;
3423                                 currentH = _h = _h !== undefined ? _h : currentH;
3424                                 angle = _angle = _angle !== undefined ? _angle : angle;
3425
3426                                 // ResizeOperator.update( _x, _y, _w, _h );
3427                                 isSpeach === true && TailOperator.update( _w, _h, angle );
3428                                 CONSOLE_CONTROLER.show( currentElement, _w, _h );
3429                                 //CONSOLE_CONTROLER.update( currentElement );
3430                                 PanelElementOperatorManager.node.update( PANEL_CONTROL.x + _x - HIT_AREA / 2 - 5, PANEL_CONTROL.y + _y - HIT_AREA / 2 - 5, _w + HIT_AREA + 5, _h + HIT_AREA + 5 );
3431                         },
3432                         /* history */
3433                         restoreState: function( _currentElement, _x, _y, _w, _h, _a, _flipV, _flipH ){
3434                                 if( arguments.length !== 8 ) return;
3435                                 if( !_currentElement && !currentOperator ) return;
3436                                 _currentElement.type === PANEL_ELEMENT_TYPE_IMAGE ?
3437                                         _currentElement.animate( _x, _y, _w, _h, _flipV, _flipH ) :
3438                                         _currentElement.animate( _x, _y, _w, _h, _a );
3439                                 currentOperator !== null && currentOperator.onCancel && currentOperator.onCancel();
3440                                 currentOperator = null;
3441                                 currentElement === _currentElement ? PanelElementOperatorManager.resize( _x, _y, _w, _h, _a ) : PanelElementOperatorManager.show( _currentElement );
3442                         },
3443                         saveStatus: function( startX, startY, startW, startH, startA, startFilpV, startFilpH ){
3444                                 startX = startX !== undefined ? startX : currentX;
3445                                 startY = startY !== undefined ? startY : currentY;
3446                                 startW = startW !== undefined ? startW : currentW;
3447                                 startH = startH !== undefined ? startH : currentH;
3448                                 startA = startA !== undefined ? startA : angle;
3449                                 startFilpV = startFilpV !== undefined ? startFilpV : flipV;
3450                                 startFilpH = startFilpH !== undefined ? startFilpH : flipH;
3451                                 currentElement && HISTORY_CONTROL.saveState( PanelElementOperatorManager.restoreState,
3452                                         [ currentElement, startX, startY, startW, startH, startA, startFilpV, startFilpH ],
3453                                         [ currentElement, currentX, currentY, currentW, currentH, angle, flipV, flipH ]
3454                                 );
3455                         }
3456                 };
3457         })();
3458         /*
3459          *  // PanelElementOperatorManager
3460          */
3461
3462 /* --------------------------------------------------------------------------------------------
3463  * CONSOLE_CONTROLER
3464  */
3465         var CONSOLE_CONTROLER = ( function(){
3466                 var LAYER_BACK_BUTTON, LAYER_FORWARD_BUTTON, DELETE_BUTTON, EDIT_BUTTON, CHANGE_BUTTON,
3467                         PUSH_OUT_RATIO  = 0.5,
3468                         tailSize        = 10,
3469                         elmRoot, elmContainer, elmPushout, elmTail,
3470                         pushoutW        = 0,
3471                         pushoutH        = 0,
3472                         pushout         = false,
3473                         currentType     = -1,
3474             currentElement  = null,
3475                         visible         = false,
3476                         node            = null,
3477                         ui, inputX, inputY, inputZ, inputA, inputW, inputH, inputPercentW, inputPercentH, inputAspectRatio,
3478                         buttonBack, buttonForward, buttonDel, buttonEdit, butonChange;
3479                         
3480                 function layerBack(){
3481                         if( currentElement === null ) return;
3482                         if( PANEL_ELEMENT_CONTROL.replace( currentElement, false ) === false ) return;
3483                         CONSOLE_CONTROLER.update( currentElement );
3484                         HISTORY_CONTROL.saveState( PANEL_ELEMENT_CONTROL.replace, [ currentElement, true ], [ currentElement, false ] );
3485                         var _z = currentElement.z;
3486                         LAYER_BACK_BUTTON.visible( _z > 0 );
3487                         LAYER_FORWARD_BUTTON.visible( _z < PANEL_ELEMENT_ARRAY.length - 1 );
3488                 };
3489                 function layerForward(){
3490                         if( currentElement === null ) return;
3491                         if( PANEL_ELEMENT_CONTROL.replace( currentElement, true ) === false ) return;
3492                         CONSOLE_CONTROLER.update( currentElement );
3493                         HISTORY_CONTROL.saveState( PANEL_ELEMENT_CONTROL.replace, [ currentElement, false ], [ currentElement, true ] );
3494                         var _z = currentElement.z;
3495                         LAYER_BACK_BUTTON.visible( _z > 0 );
3496                         LAYER_FORWARD_BUTTON.visible( _z < PANEL_ELEMENT_ARRAY.length - 1 );
3497                 };
3498                 function del(){
3499                         if( currentElement === null ) return;
3500                         HISTORY_CONTROL.saveState( PANEL_ELEMENT_CONTROL.restore, [ true, currentElement ], [ false, currentElement ], false ); // true
3501                         PANEL_ELEMENT_CONTROL.remove( currentElement );
3502                         PanelElementOperatorManager.hide();
3503                 };
3504                 function edit(){
3505                         if( currentElement === null || currentElement.type !== PANEL_ELEMENT_TYPE_TEXT ) return;
3506                         TextEditor.boot( PANEL_CONTROL.x, PANEL_CONTROL.y, currentElement );
3507                 };
3508                 function change(){
3509                         if( currentElement === null ) return;
3510                         PremiumSatge.boot( currentElement.artistID, currentElement.realPicture, currentElement );
3511                 };
3512
3513                 return {
3514                         x: 0,
3515                         y: 0,
3516                         w: 0,
3517                         h: 0,
3518                         init: function(){
3519                                 app.addKeyEventListener( 'keydown', layerBack, 66, false, true );
3520                                 app.addKeyEventListener( 'keydown', layerForward, 70, false, true );
3521                                 app.addKeyEventListener( 'keydown', del, 68, false, true );
3522                                 app.addKeyEventListener( 'keydown', edit, 69, false, true );
3523                                 app.addKeyEventListener( 'keydown', change, 85, false, true );
3524                                 
3525                                 elmContainer = document.getElementById( 'comic-element-consol-container' );
3526                                 elmRoot      = elmContainer.parentNode;
3527                                 elmPushout   = document.getElementById( 'comic-element-consol-pushout-wrapper' );
3528                                 elmTail      = document.getElementById( 'comic-element-consol-pushout-tail' );
3529                                 delete CONSOLE_CONTROLER.init;
3530                         },
3531                         open: function(){
3532                                 LAYER_BACK_BUTTON    = MENU_BAR_CONTROL.EDIT.createOption( 'layer back', 'ctrl + B', layerBack, false, true, false );
3533                                 LAYER_FORWARD_BUTTON = MENU_BAR_CONTROL.EDIT.createOption( 'layer forward', 'ctrl + F', layerForward, false, false, false );
3534                                 DELETE_BUTTON        = MENU_BAR_CONTROL.EDIT.createOption( 'delete', 'ctrl + D', del, false, true, true );
3535                                 EDIT_BUTTON          = MENU_BAR_CONTROL.EDIT.createOption( 'Edit Text', 'ctrl + E', edit, false, true, false );
3536                                 CHANGE_BUTTON        = MENU_BAR_CONTROL.EDIT.createOption( 'change', 'ctrl + U', change, false, false, true );
3537                                 // inputAspectRatio = $( '#comic-element-keep-aspect' );
3538                                 
3539                                 delete CONSOLE_CONTROLER.open;
3540                         },
3541                         onMouseover : function( e ){
3542                                 node.mesureChildren();
3543                                 //node.mesure();
3544                         },
3545                         show: function( _currentElement, w, h ){
3546                                 if( node === null ){
3547                                         node = CONSOLE_CONTROLER.node = PanelElementOperatorManager.node.createNode( elmContainer, false, false, 'comic-element-consol-container-hover' );
3548                                         node.addEventListener( 'mouseover', CONSOLE_CONTROLER.onMouseover, CONSOLE_CONTROLER );
3549                                         ui            = app.createUIGroup( node );
3550                                         inputX        = ui.createInputText( document.getElementById( 'comic-element-x' ), null );
3551                                         inputY        = ui.createInputText( document.getElementById( 'comic-element-y' ), null );
3552                                         inputZ        = ui.createInputText( document.getElementById( 'comic-element-z' ), null );
3553                                         inputA        = ui.createInputText( document.getElementById( 'comic-element-a' ), null );
3554                                         inputW        = ui.createInputText( document.getElementById( 'comic-element-w' ), null );
3555                                         inputH        = ui.createInputText( document.getElementById( 'comic-element-h' ), null );
3556                                         inputPercentW = ui.createInputText( document.getElementById( 'comic-element-w-percent' ), null );
3557                                         inputPercentH = ui.createInputText( document.getElementById( 'comic-element-h-percent' ), null );
3558                                         butonChange   = ui.createButton( document.getElementById( 'change-image-button' ), change ),
3559                                         buttonBack    = ui.createButton( document.getElementById( 'layer-back-button' ), layerBack ),
3560                                         buttonDel     = ui.createButton( document.getElementById( 'delete-button' ), del ),
3561                                         buttonForward = ui.createButton( document.getElementById( 'layer-forward-button' ), layerForward ),
3562                                         buttonEdit    = ui.createButton( document.getElementById( 'edit-text-button' ), edit );
3563                                 };
3564                                 
3565                                 currentElement = _currentElement;
3566                                 
3567                                 var type = currentElement.type,
3568                                         z    = currentElement.z;
3569                                 
3570                                 LAYER_BACK_BUTTON.visible( z > 0 );
3571                                 buttonBack.enabled( z > 0 );
3572                                 LAYER_FORWARD_BUTTON.visible( z < PANEL_ELEMENT_ARRAY.length - 1 );
3573                                 buttonForward.enabled( z < PANEL_ELEMENT_ARRAY.length - 1 )
3574                                 DELETE_BUTTON.visible( true );
3575                                 EDIT_BUTTON.visible( type === PANEL_ELEMENT_TYPE_TEXT );
3576                                 CHANGE_BUTTON.visible( false );
3577                                 
3578                                 //CONSOLE_CONTROLER.x = Math.floor( ( _w - CONSOLE_CONTROLER.w ) / 2 );
3579                                 CONSOLE_CONTROLER.w = w;
3580                                 CONSOLE_CONTROLER.h = elmContainer.offsetHeight;
3581                                 CONSOLE_CONTROLER.y = h - CONSOLE_CONTROLER.h;
3582                                 
3583                                 if( h * PUSH_OUT_RATIO < CONSOLE_CONTROLER.h ){
3584                                         if( pushout === false ){
3585                                                 pushout = true;
3586                                                 elmPushout.lastChild.appendChild( elmContainer );
3587                                                 elmPushout.style.display = 'block';
3588                                                 pushoutW = elmPushout.offsetWidth;
3589                                                 pushoutH = elmPushout.offsetHeight;
3590                                                 elmTail.style.top = ( pushoutH / 2 - tailSize / 2 ) + 'px';
3591                                         };
3592                                         elmPushout.style.left = ( -pushoutW ) + 'px';
3593                                         elmPushout.style.top  = ( h / 2 - pushoutH / 2 ) + 'px';
3594                                         elmPushout.className  = 'satellite-left';
3595                                 } else
3596                                 if( pushout === true ){
3597                                         pushout = false;
3598                                         elmRoot.insertBefore( elmContainer, elmRoot.firstChild );
3599                                         elmPushout.style.cssText = '';
3600                                 };
3601                                 
3602                                 CONSOLE_CONTROLER.update( currentElement );
3603                                 ui.visible( true );
3604                                 node.mesure();
3605                         },
3606                         update : function( _currentElement ){
3607                                 if( _currentElement === null ){
3608                                         visible = false;
3609                                         return;
3610                                 };
3611                                 currentElement = _currentElement;
3612                                 var type = currentElement.type,
3613                                         x    = currentElement.x,
3614                                         y    = currentElement.y,
3615                                         z    = currentElement.z,
3616                                         a    = type === PANEL_ELEMENT_TYPE_TEXT ? Math.floor( currentElement.a ) : 0,
3617                                         w    = currentElement.w,
3618                                         h    = currentElement.h,
3619                                         actualW    = type === PANEL_ELEMENT_TYPE_IMAGE ? currentElement.actualW : 1,
3620                                         actualH    = type === PANEL_ELEMENT_TYPE_IMAGE ? currentElement.actualH : 1,
3621                                         wPercent   = type === PANEL_ELEMENT_TYPE_IMAGE ? Math.floor( w / actualW * 100 ) : 0,
3622                                         hPercent   = type === PANEL_ELEMENT_TYPE_IMAGE ? Math.floor( h / actualH * 100 ) : 0,
3623                                         keepAspect = currentElement.keepAspect;
3624                                         
3625                                 if( currentType !== type ){
3626                                         if( type === PANEL_ELEMENT_TYPE_TEXT ){
3627                                                 inputA.visible( true );
3628                                                 inputPercentW.visible( false );
3629                                                 inputPercentH.visible( false );
3630                                                 buttonEdit.enabled( true );
3631                                                 //inputAspectRatio.hide();
3632                                         } else {
3633                                                 inputA.visible( false );
3634                                                 inputPercentW.visible( true );
3635                                                 inputPercentH.visible( true );
3636                                                 buttonEdit.enabled( false );
3637                                                 //inputAspectRatio.show();
3638                                         };
3639                                         currentType = type;
3640                                 };
3641
3642                                 inputX.value( x );
3643                                 inputY.value( y );
3644                                 inputZ.value( z );
3645                                 type === 1 && inputA.value( a );
3646                                 inputW.value( w );
3647                                 inputH.value( h );
3648                                 type === 0 && inputPercentW.value( wPercent );
3649                                 type === 0 && inputPercentH.value( hPercent );
3650                         },
3651                         hide: function(){
3652                                 // if( visible === true ) styleConsoleWrapper.display = 'none';
3653                                 ui && ui.visible( false );
3654                                 visible = false;
3655                                 currentElement = null;
3656                                 LAYER_BACK_BUTTON.visible( false );
3657                                 LAYER_FORWARD_BUTTON.visible( false );
3658                                 DELETE_BUTTON.visible( false );
3659                                 EDIT_BUTTON.visible( false );
3660                                 CHANGE_BUTTON.visible( false );
3661                         }
3662                 };
3663         })();
3664
3665
3666
3667         var AbstractPanelElement = function( COMIC_ELM_TYPE ){
3668                 this.type = COMIC_ELM_TYPE;
3669         };
3670         AbstractPanelElement.prototype = {
3671                 $       : null,
3672                 data    : null,
3673                 node    : null,
3674                 x       : 0,
3675                 y       : 0,
3676                 w       : 0,
3677                 h       : 0,
3678                 z       : 0,
3679                 timing  : 0,
3680                 actualW : 0,
3681                 actualH : 0,
3682                 flipV   : 0,
3683                 flipH   : 0,
3684                 shift : function( shiftX, shiftY ){
3685                         this.resize( this.x + shiftX, this.y + shiftY );
3686                 },
3687                 mouseover : function( e ){
3688                         PanelElementOperatorManager.show( this );
3689                 }
3690         };
3691
3692 /* --------------------------------------------------------------------------------------------
3693  * ImageElementClass
3694  */
3695         var     jqImageElementOrigin;
3696         var ImageElementClass = function( data ){
3697                 jqImageElementOrigin = jqImageElementOrigin || $( app.fetchHTMLElement( 'imgElementTemplete' ) );
3698                 
3699                 this.$        = jqImageElementOrigin.clone( true );
3700                 this.data     = data;
3701                 this.z        = data.z;
3702                 this.timing   = data.t || PANEL_ELEMENT_ARRAY.length;
3703                 this.keepSize = false;
3704                 this.flipV    = data.height < 0 ? -1 : 1;
3705                 this.flipH    = data.width  < 0 ? -1 : 1;
3706                 this.rPicture = data.picture;
3707                 
3708                 var self = this;
3709                 function animeComplete(){
3710                         self.node.mesure();
3711                         self._flipReversibleImage();
3712                 };
3713                 this.animeComplete = animeComplete;
3714         };
3715         ImageElementClass.prototype = Util.extend(
3716                 new AbstractPanelElement( PANEL_ELEMENT_TYPE_IMAGE ),
3717                 {
3718                         reversibleImage : null,
3719                         init : function(){
3720                                 this._updateResourcePicture( this.rPicture );
3721                                 this.node = PANEL_ELEMENT_CONTROL.node.createNode( this.$.get( 0 ), false, true );
3722                                 this.node.addEventListener( 'mouseover', this.mouseover, this );                                
3723                                 this.resize( this.data.x, this.data.y, Math.abs( this.data.width ), Math.abs( this.data.height ) );
3724                                 this.init = null;
3725                         },
3726                         flip : function( updateH, updateV ){
3727                                 if( updateH !== true && updateV !== true ) return;
3728                                 this.flipH = updateH === true ? -this.flipH : this.flipH;
3729                                 this.flipV = updateV === true ? -this.flipV : this.flipV;
3730                                 this.reversibleImage.resize( this.flipH * this.w, this.flipV * this.h );
3731                         },
3732                         realPicture : function( _rPicture ){
3733                                 if( _rPicture && _rPicture !== this.rPicture ){
3734                                         HISTORY_CONTROL.saveState( this._updateResourcePicture, this.rPicture, _rPicture, this );
3735                                         this._updateResourcePicture( _rPicture );
3736                                 };
3737                                 return this.rPicture;
3738                         },
3739                         resize : function( x, y, w, h, animate ){
3740                                 this.x = x = Type.isFinite( x ) === true ? x : this.x;
3741                                 this.y = y = Type.isFinite( y ) === true ? y : this.y;
3742                                 this.w = w = Type.isFinite( w ) === true ? w : this.w;
3743                                 this.h = h = Type.isFinite( h ) === true ? h : this.h;
3744                                 if( animate === true ){
3745                                         this.$.animate( { 
3746                                                 left:   x,
3747                                                 top:    y,
3748                                                 width:  w,
3749                                                 height: h
3750                                         }, 250 , this.animeComplete );                                  
3751                                 } else {
3752                                         this.node.update( x, y, w, h );
3753                                         this._flipReversibleImage();
3754                                 };
3755                         },
3756                         animate : function ( x, y, w, h, flipH, flipV ){
3757                                 this.flipH = flipH !== undefined ? flipH : this.flipH;
3758                                 this.flipV = flipV !== undefined ? flipV : this.flipV;
3759                                 this.resize( x, y, w, h, true );
3760                         },
3761                         destroy : function(){
3762                                 this.reversibleImage.destroy();
3763                                 this.$.stop().remove();
3764                                 this.node.remove();
3765                                 
3766                                 this.destroy = null;
3767                         },
3768                         _updateResourcePicture : function( _rPicture ){
3769                                 this.rPicture = _rPicture;
3770                                 this.oPicture = this.rPicture.original_picture;
3771                                 this.artistID = this.oPicture.artist.id || -1;
3772
3773                                 this.actualW = this.oPicture.width;
3774                                 this.actualH = this.oPicture.height;
3775                                 
3776                                 var _reversibleImage = pettanr.image.createReversibleImage( 
3777                                                 [ pettanr.CONST.PICTURE_PATH, this.rPicture.id, '.', this.rPicture.ext ].join( '' ),
3778                                                 this.flipH * this.w, this.flipV * this.h
3779                                         );
3780                                 if( this.reversibleImage !== null ){
3781                                         this.$.children( this.reversibleImage.elm ).replaceWith( _reversibleImage.elm );
3782                                         this.reversibleImage.destroy();
3783                                 } else {
3784                                         this.$.append( _reversibleImage.elm );
3785                                 };
3786                                 this.reversibleImage = _reversibleImage;
3787                         },
3788                         _flipReversibleImage : function(){
3789                                 this.reversibleImage && this.reversibleImage.resize( this.flipH * this.w, this.flipV * this.h );
3790                         }
3791                 }
3792         );
3793
3794         
3795 /*
3796  * / ImageElementClass
3797  * --------------------------------------------------------------------------------------------
3798  */
3799
3800
3801 /* --------------------------------------------------------------------------------------------
3802  * TextElementClass
3803  * 
3804  * type
3805  * 0.none
3806  * 1.speach balloon
3807  * 2.think
3808  * 3.bom
3809  * 4.black-box( dq style)
3810  * 5.blue-box( ff style)
3811  * 
3812  */
3813         var jqTextElementOrigin;
3814         var TextElementClass = function( data ){
3815                 jqTextElementOrigin = jqTextElementOrigin || ( function(){
3816                         var _OLD_IE = $( app.fetchHTMLElement( 'textElementTempleteForOldIE' ) ),
3817                                 _MODERN = $( app.fetchHTMLElement( 'textElementTemplete' ) );
3818                         return UA.isIE === true && UA.ieRenderingVersion < 8 ? _OLD_IE : _MODERN;
3819                 })();
3820                 
3821                 this.$       = jqTextElementOrigin.clone( true );
3822                 this.data    = data;
3823                 this.elmText = this.$.find( 'td,.speach-inner' ).get( 0 );
3824                 this.type    = data.balloon_template_id;
3825                 this.content = ( function(){
3826                         var _speachs = data.speeches_attributes;
3827                         for( var k in _speachs ){
3828                                 return _speachs[ k ].content || '';
3829                         }
3830                         return '';
3831                 })();
3832                 this.balloon = pettanr.balloon.createBalloon( data.width, data.height, data.tail, this.type );
3833                 this.z       = data.z;
3834                 this.timing  = data.t || PANEL_ELEMENT_ARRAY.length;
3835                 
3836                 this.$.find( 'img' ).eq( 0 ).replaceWith( this.balloon.elm );
3837                 
3838                 var self = this;
3839                 function animeComplete(){
3840                         self.node.mesure();
3841                         self._resizeBalloon();
3842                 };
3843                 this.animeComplete = animeComplete; 
3844         };
3845         TextElementClass.prototype = Util.extend(
3846                 new AbstractPanelElement( PANEL_ELEMENT_TYPE_TEXT ),
3847                 {
3848                         init : function(){
3849                                 this._updateText();
3850                                 this.node = PANEL_ELEMENT_CONTROL.node.createNode( this.$.get( 0 ), false, true );
3851                                 this.node.addEventListener( 'mouseover', this.mouseover, this );                                
3852                                 this.resize( this.data.x, this.data.y, this.data.width, this.data.height, this.data.tail );
3853                                 this.init = null;
3854                         },
3855                         _updateType : function( _type ){
3856                                 if( this.type !== _type ){
3857                                         this.type = _type || this.type;
3858                                         this.balloon.type( this.type );
3859                                 };
3860                         },
3861                         _updateAngle : function( _a ){
3862                                 if( _a !== undefined && a !== _a ){
3863                                         this.a = _a !== undefined ? _a : this.a;
3864                                         this.balloon.angle( this.a );
3865                                 };
3866                         },
3867                         /* history */
3868                         _updateText : function( _text ){
3869                                 this.content = _text || this.content || '';
3870                                 this.elmText.firstChild.data = this.content;
3871                         },
3872                         _resizeBalloon : function(){
3873                                 this.balloon && this.balloon.resize( this.a, this.w, this.h );
3874                         },
3875                         angle : function( _a ){
3876                                 _a !== undefined && this.resize( this.x, this.y, this.w, this.h, _a );
3877                                 return this.a;
3878                         },
3879                         text : function( _text ){
3880                                 if( _text && this.content !== _text ){
3881                                         HISTORY_CONTROL.saveState( this._updateText, this.content || '', _text, this );
3882                                         this._updateText( _text );
3883                                 };
3884                                 return this.content;
3885                         },
3886                         resize : function( x, y, w, h, a, animate ){
3887                                 this.x = x = x !== undefined ? x : this.x;
3888                                 this.y = y = y !== undefined ? y : this.y;
3889                                 this.w = w = w !== undefined ? w : this.w;
3890                                 this.h = h = h !== undefined ? h : this.h;
3891                                 this.a = a !== undefined ? a : this.a;
3892                                 
3893                                 if( animate === true ){
3894                                         this.$.animate( { 
3895                                                 left:   x,
3896                                                 top:    y,
3897                                                 width:  w,
3898                                                 height: h
3899                                         }, 250 , this.animeComplete );                                  
3900                                 } else {
3901                                         this.node.update( x, y, w, h );
3902                                         this._resizeBalloon();
3903                                 };
3904                         },
3905                         animate : function ( _x, _y, _w, _h, _a ){
3906                                 this.resize( _x, _y, _w, _h, _a, true );
3907                         },
3908                         destroy : function(){
3909                                 this.$.stop().remove();
3910                                 this.balloon.destroy();
3911                                 this.node.remove();
3912                                 
3913                                 this.destroy = null;
3914                         }
3915                 }
3916         );
3917
3918 /* --------------------------------------------------------------------------------------------
3919  * PANEL_ELEMENT_CONTROL
3920  *  - mouseEventListener
3921  */
3922         var PANEL_ELEMENT_CONTROL = ( function(){
3923                 var     elmContainer   = null,
3924                         currentElement = null,
3925                         node           = null,
3926                         panelX, panelY, panelW, panelH,
3927                         startX, startY;
3928         /*
3929          * append, remove, replace
3930          * 
3931          * panelElement には、z-position と dom-index がある。
3932          *   z-position は 表示上の位置。大きいほど前に表示される( z-index)
3933          *   dom-index は 意味上の順番。htmlタグの登場順で、検索結果や音声読み上げブラウザで正しく意味が取れる順番。
3934          * 
3935          * editerでは、実際には z-index は使わず、htmlの順序で前後を表現する。
3936          * dom-index は、数値のみ保持して、投稿時にpanelElementを適宜に並び替える。
3937          * 
3938          * append panelElement
3939          * 1. 新しい panelElement の z-position を得る
3940          * 2. z の同じ panelElementを見つけ、その前に加える。または一番先頭へ。(PANEL_ELEMENT_ARRAY)
3941          *    zが大きいほど、PANEL_ELEMENT_ARRAYの先頭へ。
3942          * 3. dom位置は、PANEL_ELEMENT_ARRAY とは反対に、前のものほど後ろへ。
3943          * 
3944          * 
3945          * remove panelElement
3946          * 1. remove
3947          * 2. renumber z
3948          */
3949                 function onFadeOut(){
3950                         this.parentNode.removeChild( this );
3951                 };
3952                 /*
3953                  * PANEL_ELEMENT_ARRAY の順番を基準に、zの再計算
3954                  * jqElmの並び替え。
3955                  */
3956                 function renumber(){
3957                         var _panelElement, jqElm, jqAfter,
3958                                 i = PANEL_ELEMENT_ARRAY.length;
3959                         for( ; i; ){
3960                                 _panelElement = PANEL_ELEMENT_ARRAY[ --i ];
3961                                 jqElm = _panelElement.$;
3962                                 !jqAfter && elmContainer.appendChild( jqElm.get( 0 ) );
3963                                 jqAfter  && jqAfter.before( jqElm );
3964                                 if( phase === 1 ){
3965                                         _panelElement.z = i;
3966                                         _panelElement.node.nodeIndex( i );
3967                                 };
3968                                 jqAfter = jqElm;
3969                         };
3970                 };
3971                 function onTextInput( _panelElement ){
3972                         PANEL_ELEMENT_CONTROL.add( _panelElement );
3973                         _panelElement.animate( undefined, undefined, _panelElement.w, _panelElement.h );
3974                         HISTORY_CONTROL.saveState( PANEL_ELEMENT_CONTROL.restore, [ false, _panelElement ], [ true, _panelElement ], true, PANEL_ELEMENT_CONTROL );
3975                 };
3976                 
3977                 return {
3978                         id : 'PANEL_ELEMENT_CONTROL',
3979                         node : null,
3980                         init : function(){
3981                                 elmContainer = document.getElementById( 'comic-element-container' );
3982                                 node         = PANEL_ELEMENT_CONTROL.node = eventRoot.createNode( elmContainer, true, false );
3983                                 node.nodeIndex( 0 );
3984                                 delete PANEL_ELEMENT_CONTROL.init;
3985                         },
3986                         open : function(){
3987                                 delete PANEL_ELEMENT_CONTROL.open;
3988                         },
3989                         close : function(){
3990                                 var panelElm;
3991                                 while( panelElm = PANEL_ELEMENT_ARRAY.shift() ){
3992                                         panelElm.destroy && panelElm.destroy();
3993                                 };
3994                         },
3995                         add : function( _panelElement ){
3996                                 var z = Type.isFinite( _panelElement.z ) === true ? _panelElement.z : -1,
3997                                         i = PANEL_ELEMENT_ARRAY.length,
3998                                         _jqElm = _panelElement.$.stop().css( {
3999                                                 filter:         '',
4000                                                 opacity:        ''
4001                                         }),
4002                                         j;
4003                                 if( z < 0 ){
4004                                         PANEL_ELEMENT_ARRAY.push( _panelElement );
4005                                 } else {
4006                                         for( ; i; ){
4007                                                 if( PANEL_ELEMENT_ARRAY[ --i ].z < z ){
4008                                                         j = i;
4009                                                         break;
4010                                                 };
4011                                         };
4012                                         if( j !== i ){
4013                                                 PANEL_ELEMENT_ARRAY.unshift( _panelElement );
4014                                         } else {
4015                                                 PANEL_ELEMENT_ARRAY.splice( i + 1, 0, _panelElement );
4016                                         };
4017                                 };
4018                                 renumber();
4019                                 _jqElm.fadeIn();
4020                                 _panelElement.node.disabled( false );   
4021                         },
4022                         remove : function( _panelElement ){
4023                                 for( var i = PANEL_ELEMENT_ARRAY.length; i; ){
4024                                         if( PANEL_ELEMENT_ARRAY[ --i ] === _panelElement ){
4025                                                 console.log( PANEL_ELEMENT_ARRAY.length );
4026                                                 PANEL_ELEMENT_ARRAY.splice( i, 1 );
4027                                                 _panelElement.node.disabled( true );
4028                                                 _panelElement.node.nodeIndex( PANEL_ELEMENT_ARRAY.length );
4029                                                 renumber();
4030                                                 _panelElement.$.stop().css( {
4031                                                         filter:         '',
4032                                                         opacity:        ''
4033                                                 }).fadeOut( onFadeOut );
4034                                                 if( currentElement === _panelElement ) currentElement = null;
4035                                                 return;
4036                                         };
4037                                 };
4038                         },
4039                         /* history */
4040                         restore : function( isAppend, panelElement ){
4041                                 PANEL_ELEMENT_CONTROL[ isAppend === true ? 'add' : 'remove' ]( panelElement );
4042                         },
4043                         replace: function( _panelElement, goForward ){
4044                                 // PANEL_ELEMENT_ARRAYの再構築
4045                                 var l = PANEL_ELEMENT_ARRAY.length,
4046                                         i,
4047                                         j = l;
4048                                 for( ; j; ){
4049                                         if( PANEL_ELEMENT_ARRAY[ --j ] === _panelElement ){
4050                                                 i = j;
4051                                                 break;
4052                                         };
4053                                 };
4054                                 if( i !== j ) return false;
4055                                 if( goForward === true ){
4056                                         if( i === 0 ) return false;
4057                                         PANEL_ELEMENT_ARRAY.splice( i, 1 );
4058                                         PANEL_ELEMENT_ARRAY.splice( i + 1, 0, _panelElement );
4059                                 } else {
4060                                         if( i === l - 1 ) return false;
4061                                         PANEL_ELEMENT_ARRAY.splice( i, 1 );
4062                                         PANEL_ELEMENT_ARRAY.splice( i - 1, 0, _panelElement );
4063                                 };
4064                                 renumber( true );
4065                                 return true;
4066                         },
4067                         onPanelResize : function ( _panelX, _panelY, _panelW, _panelH, isResizerTopAction ){
4068                         /*
4069                          * リサイズが、ResizerTopによって行われた場合、panelElementのyを動かして見かけ上動かないようにする。
4070                          */                                     
4071                                 if( isResizerTopAction === true ){
4072                                         var     _shiftX = _panelW - panelW,
4073                                                 _shiftY = _panelH - panelH;
4074                                         for( var i = PANEL_ELEMENT_ARRAY.length; i; ){
4075                                                 PANEL_ELEMENT_ARRAY[ --i ].shift( _shiftX, _shiftY );
4076                                         };
4077                                 };
4078                                 node.update( panelX = _panelX, panelY = _panelY, panelW = _panelW, panelH = _panelH );
4079                         },
4080                         createImageElement: function( data ){
4081                                 if( Type.isObject( data ) === false ){
4082                                         PremiumSatge.boot( 1, PANEL_ELEMENT_CONTROL.onImageSelect );
4083                                 } else {
4084                                         PANEL_ELEMENT_CONTROL.onImageSelect( data, true );
4085                                 };
4086                         },
4087                         onImageSelect: function( data, isPanelPictureData ){
4088                                 var _panelElement;
4089                                 if( isPanelPictureData !== true ){
4090                                         _panelElement = new ImageElementClass( {
4091                                                 picture : data.picture,
4092                                                 x       : Math.floor( panelW / 2 - data.width / 2 ),
4093                                                 y       : Math.floor( panelH / 2 - data.height / 2 ),
4094                                                 z       : -1,
4095                                                 t       : 0,
4096                                                 width   : 1,
4097                                                 height  : 1
4098                                         });
4099                                         _panelElement.init();
4100                                         PANEL_ELEMENT_CONTROL.add( _panelElement );
4101                                         _panelElement.animate( undefined, undefined, Math.abs( data.picture.original_picture.width ), Math.abs( data.picture.original_picture.height ) );
4102                                 } else {
4103                                         _panelElement = new ImageElementClass( data );
4104                                         _panelElement.init();
4105                                         PANEL_ELEMENT_CONTROL.add( _panelElement );
4106                                 };
4107                                 HISTORY_CONTROL.saveState( PANEL_ELEMENT_CONTROL.restore, [ false, _panelElement ], [ true, _panelElement ], true );
4108                         },
4109                         createTextElement: function( data ){
4110                                 var _panelElement;
4111                                 if( Type.isObject( data ) === false ){
4112                                         data = {
4113                                                 balloon_template_id:1,
4114                                                 size:               1,
4115                                                 tail:               90,
4116                                                 x:                                      Math.floor( panelW / 2 - 100 + Math.random() * 10 ),
4117                                                 y:                  Math.floor( panelH / 2 - 100 + Math.random() * 10 ),
4118                                                 z:                  -1,
4119                                                 t:                  0,
4120                                                 width:              200,
4121                                                 height:             200,
4122                                                 speeches_attributes: {
4123                                                         text1: {
4124                                                                 content:    'Hello'
4125                                                         }
4126                                                 }
4127                                         };
4128                                         _panelElement = new TextElementClass( data );
4129                                         _panelElement.init();
4130                                         TextEditor.boot( PANEL_CONTROL.x, PANEL_CONTROL.y, _panelElement, onTextInput );
4131                                 } else {
4132                                         _panelElement = new TextElementClass( data );
4133                                         _panelElement.init();
4134                                         onTextInput( _panelElement );
4135                                 };
4136                         }
4137                 };
4138         })();
4139
4140         /*
4141          * end of PANEL_ELEMENT_CONTROL
4142          */
4143
4144         function centering(){
4145                 app.onPaneResize( windowW, windowH );
4146         };
4147
4148         /* grobal method */
4149         
4150         this.MIN_WIDTH   = 320;
4151         this.MIN_HEIGHT  = 320;
4152         this.onInit = function(){
4153                 app.rootElement.id = 'editor';
4154                 app.rootElement.innerHTML = [
4155                         '<div id="grid" style="display:none;"></div>',
4156                         '<div id="comic-element-container"></div>',
4157                         '<div id="whiteGlass-container">',
4158                                 '<div id="whiteGlass-top"></div>',
4159                                 '<div id="whiteGlass-left"></div>',
4160                                 '<div id="whiteGlass-right"></div>',
4161                                 '<div id="whiteGlass-bottom"></div>',
4162                         '</div>',
4163                         '<div id="panel-tools-container">',
4164                                 '<div id="panel-resizer-top">▲</div>',
4165                                 '<div id="panel-resizer-bottom">▼</div>',
4166                         '</div>',
4167                         '<div id="window-container"></div>',
4168                         '<div id="comic-element-resizer-container">',
4169                                 '<div id="comic-element-resizer-container-inner">',
4170                                         '<div id="comic-element-consol-wrapper">',
4171                                                 '<div id="comic-element-consol-container" class="clearfix">',
4172                                                         '<div class="comic-element-consol-item">',
4173                                                                 '<div id="comic-element-x">',
4174                                                                         '<span class="comic-element-attribute-label">x:</span>',
4175                                                                         '<span id="comic-element-x-value" class="comic-element-attribute-value editable-value">0</span>',
4176                                                                 '</div>',
4177                                                                 '<div id="comic-element-y">',
4178                                                                         '<span class="comic-element-attribute-label">y:</span>',
4179                                                                         '<span id="comic-element-y-value" class="comic-element-attribute-value editable-value">0</span>',
4180                                                                 '</div>',
4181                                                         '</div>',
4182                                                         '<div class="comic-element-consol-item">',                                              
4183                                                                 '<div id="comic-element-z">',
4184                                                                         '<span class="comic-element-attribute-label">z:</span>',
4185                                                                         '<span id="comic-element-z-value" class="comic-element-attribute-value editable-value">0</span>',
4186                                                                 '</div>',
4187                                                                 '<div id="comic-element-a">',
4188                                                                         '<span id="comic-element-a-value" class="comic-element-attribute-value editable-value">0</span>',
4189                                                                         '<span class="comic-element-attribute-label">°</span>',
4190                                                                 '</div>',
4191                                                         '</div>',
4192                                                         '<div class="comic-element-consol-item">',
4193                                                                 '<div id="comic-element-w">',
4194                                                                         '<span class="comic-element-attribute-label">w:</span>',
4195                                                                         '<span id="comic-element-w-value" class="comic-element-attribute-value editable-value">0</span>',
4196                                                                 '</div>',
4197                                                                 '<div id="comic-element-h">',
4198                                                                         '<span class="comic-element-attribute-label">h:</span>',
4199                                                                         '<span id="comic-element-h-value" class="comic-element-attribute-value editable-value">0</span>',
4200                                                                 '</div>',
4201                                                         '</div>',
4202                                                         '<div class="comic-element-consol-item">',
4203                                                                 '<!-- <div id="comic-element-keep-aspect"></div> -->',
4204                                                                 '<div id="comic-element-w-percent">',
4205                                                                         '<span id="comic-element-w-percent-value" class="comic-element-attribute-value editable-value">0</span>',
4206                                                                         '<span class="comic-element-attribute-label">%</span>',
4207                                                                 '</div>',
4208                                                                 '<div class="comic-element-consol-item" id="comic-element-h-percent">',
4209                                                                         '<span id="comic-element-h-percent-value" class="comic-element-attribute-value editable-value">0</span>',
4210                                                                         '<span class="comic-element-attribute-label">%</span>',
4211                                                                 '</div>',
4212                                                         '</div>',
4213                                         '<div class="comic-element-consol-item-small">',
4214                                                                 '<div class="button" id="change-image-button">change</div>',
4215                                                         '</div>',
4216                                                         '<div class="comic-element-consol-item-small">',
4217                                                                 '<div class="button" id="layer-back-button">back</div>',
4218                                                         '</div>',
4219                                                         '<div class="comic-element-consol-item-small">',
4220                                                                 '<div class="button" id="delete-button">delete</div>',
4221                                                         '</div>',
4222                                                         '<div class="comic-element-consol-item-small">',
4223                                                                 '<div class="button" id="layer-forward-button">forward</div>',
4224                                                         '</div>',
4225                                                         '<div class="comic-element-consol-item-small">',
4226                                                                 '<div class="button" id="edit-text-button">edit</div>',
4227                                                         '</div>',
4228                                                         '<!-- <div class="comic-element-consol-item-small">',
4229                                                                 '<div class="button" id="hide-text-tail-button">tail</div>',
4230                                                         '</div> -->',
4231                                                 '</div>',
4232                                         '</div>',                               
4233                                         '<div class="comic-element-resizer" id="comic-element-resizer-top"></div>',
4234                                         '<div class="comic-element-resizer" id="comic-element-resizer-left"></div>',
4235                                         '<div class="comic-element-resizer" id="comic-element-resizer-right"></div>',
4236                                         '<div class="comic-element-resizer" id="comic-element-resizer-bottom"></div>',
4237                                         '<div class="comic-element-resizer" id="comic-element-resizer-top-left"></div>',
4238                                         '<div class="comic-element-resizer" id="comic-element-resizer-top-right"></div>',
4239                                         '<div class="comic-element-resizer" id="comic-element-resizer-bottom-left"></div>',
4240                                         '<div class="comic-element-resizer" id="comic-element-resizer-bottom-right"></div>',
4241                                         '<div id="comic-element-consol-pushout-wrapper">',
4242                                                 '<div id="comic-element-consol-pushout-tail"></div>',
4243                                                 '<div id="comic-element-consol-pushout-inner"></div>',
4244                                         '</div>',
4245                                         '<div id="balloon-tail-mover"></div>',
4246                                 '</div>',       
4247                         '</div>',
4248                         '<div id="menu-bar"></div>',
4249                         
4250                         '<div id="templete-container" style="display: none;">',
4251                                 '<div id="imgElementTemplete" class="comic-element-wrapper image-element"></div>',
4252                                 
4253                                 '<div id="textElementTemplete" class="comic-element-wrapper text-element">',
4254                                         '<img>',
4255                                         '<div class="speach">',
4256                                                 '<div class="speach-inner">&nbsp;</div>',
4257                                         '</div>',
4258                                 '</div>',
4259                                 
4260                                 '<div id="textElementTempleteForOldIE" class="comic-element-wrapper text-element">',
4261                                         '<img>',
4262                                         '<div class="speach">',
4263                                                 '<table><tr><td>&nbsp;</td></tr></table>',
4264                                         '</div>',
4265                                 '</div>',
4266                                 
4267                                 '<div id="imageGroupItemTemplete" class="image-group-item">',
4268                                         '<div class="image-group-item-title">img-title</div>',
4269                                 '</div>',
4270                                 
4271                                 '<div id="windowTemplete" class="window-wrapper">',
4272                                         '<div class="window-header">',
4273                                                 '<div class="window-header-title">window title</div>',
4274                                                 '<div class="window-close-button">x</div>',
4275                                         '</div>',
4276                                         '<div class="window-body"></div>',
4277                                         '<div class="window-footer">',
4278                                                 '<div class="window-resize-button"></div>',
4279                                         '</div>',
4280                                 '</div>',
4281                                 
4282                                 '<div id="infomation-window">',
4283                                         '<div id="panel-background-information">',
4284                                                 '<div id="bg-pattern"></div>',
4285                                                 '<div id="select-bg-pattern-button">pattern</div>',
4286                                                 '<div id="reset-bg-pattern-button">x</div>',
4287                                                 '<div id="bg-color"></div>',
4288                                                 '<div id="select-bg-color-button">color</div>',
4289                                                 '<div id="reset-bg-color-button">x</div>',
4290                                                 '<!-- <div id="bg-pattern-x"></div>',
4291                                                 '<div id="bg-pattern-y"></div>',
4292                                                 '<div id="bg-pattern-repeat-x"></div>',
4293                                                 '<div id="bg-pattern-repeat-y"></div> -->',
4294                                         '</div>',
4295                                 '</div>',
4296                                 
4297                                 '<div id="toolbox-window">',
4298                                         '<div id="toolbox-add-image-button" class="button">add image</div>',
4299                                         '<div id="toolbox-add-text-button" class="button">add text</div>',
4300                                         '<div id="toolbox-edit-bg-button" class="button">edit bg</div>',
4301                                         '<div id="toolbox-switch-grid" class="button">grid</div>',
4302                                         '<div id="toolbox-popup-help-button" class="button">?</div>',
4303                                         '<div id="toolbox-post-button" class="button">post</div>',
4304                                 '</div>',
4305                                                         
4306                         '</div>'
4307                 ].join( '' );
4308                 
4309                 app.fetchCSS( pettanr.CONST.URL_PETA_APPS_CSS );
4310                 eventRoot = app.getPointingDeviceEventTreeRoot();
4311                 
4312                 delete app.onInit;
4313         };
4314         this.onOpen = function( _w, _h, file ){
4315                 // 表示奥の物から順に init() していく
4316                 PANEL_ELEMENT_CONTROL.init();
4317                 PANEL_CONTROL.init();
4318                 // PANEL_RESIZER_BOTTOM.init();
4319                 // PANEL_RESIZER_TOP.init();
4320                 WINDOWS_CONTROL.init();
4321                 MENU_BAR_CONTROL.init();
4322                 
4323                 // レイヤーにあまり関係ないモジュール  
4324                 HISTORY_CONTROL.init();
4325                 SAVE_CONTROL.init();
4326                 GRID_CONTROL.init();
4327                 WHITE_GLASS_CONTROL.init();
4328                 PanelElementOperatorManager.init();
4329                 
4330                 comicID      = -1;
4331                 panelID      = -1;
4332                 panelTimming = -1;
4333                 phase        = 0;
4334                 
4335                 var panelW, panelH,
4336                         borderSize,
4337                         fileData, panelElements, panelElm;
4338
4339                 if( FileAPI.isFileInstance( file ) === true ){
4340                         if( Driver.isPettanrFileInstance( file ) === true ){
4341                                 if( file.getType() === FILE_TYPE.COMIC ){
4342                                         fileData = file.read();
4343                                         panelW   = fileData.width;
4344                                         panelH   = fileData.height;
4345                                         comicID  = fileData.id || -1;
4346                                 } else
4347                                 if( file.getType() === FILE_TYPE.PANEL ){
4348                                         fileData      = file.read();
4349                                         panelW        = fileData.width;
4350                                         panelH        = fileData.height;
4351                                         borderSize    = fileData.border;
4352                                         panelElements = fileData.elements;
4353                                         comicID       = fileData.comic ? fileData.comic.id || -1 : -1;
4354                                         panelID       = fileData.id || -1;
4355                                         panelTimming  = fileData.t  || -1;
4356                                 };
4357                         } else {
4358                         };
4359                 } else {
4360                 };
4361                 
4362                 // open() は各モジュールの init() 後に実施可能になる. 
4363                 HISTORY_CONTROL.open();
4364                 SAVE_CONTROL.open();
4365                 WINDOWS_CONTROL.open();
4366                 
4367                 GRID_CONTROL.open();
4368                 PANEL_CONTROL.open( panelW, panelH, borderSize );
4369                 PanelElementOperatorManager.open();
4370                 PANEL_ELEMENT_CONTROL.open();
4371                 
4372                 // last
4373                 MENU_BAR_CONTROL.open();
4374                 
4375                 windowW = _w;
4376                 windowH = _h;
4377                 app.onPaneResize( _w, _h );
4378                 
4379
4380                 if( Type.isArray( panelElements ) === true ){
4381                         for( var i=0; i<panelElements.length; ++i ){
4382                                 panelElm = panelElements[ i ];
4383                                 if( panelElm.picture ){
4384                                         PANEL_ELEMENT_CONTROL.createImageElement( panelElm );
4385                                 } else
4386                                 if( panelElm.balloon_template_id ){
4387                                         PANEL_ELEMENT_CONTROL.createTextElement( panelElm );
4388                                 };
4389                         };
4390                 };
4391                 
4392         /*
4393          * centering
4394          */
4395                 app.addKeyEventListener( 'keydown', centering, 96, false, true );       // ctrl + 0
4396                 app.addKeyEventListener( 'krydown', centering, 48, false, true );       // ctrl + 0
4397                 MENU_BAR_CONTROL.EDIT.createOption( 'centering', 'ctrl + 0', centering, true, true, true);
4398                 
4399                 phase   = 1;
4400
4401                 delete app.onOpen;
4402         };
4403         this.onClose = function(){
4404                 phase   = 2;
4405                 HISTORY_CONTROL.close();
4406                 
4407                 WINDOWS_CONTROL.close();
4408                 
4409                 GRID_CONTROL.close();
4410                 PANEL_CONTROL.close();
4411                 
4412                 PanelElementOperatorManager.close();
4413                 PANEL_ELEMENT_CONTROL.close();
4414                 
4415                 // last
4416                 MENU_BAR_CONTROL.close();
4417                 
4418                 phase = -1;
4419         };
4420         this.onPaneResize = function( _windowW, _windowH ){
4421                 windowW = _windowW || windowW;
4422                 windowH = _windowH || windowH;
4423
4424                 app.rootElement.style.height = _windowH + 'px';
4425                 
4426                 WINDOWS_CONTROL.onWindowResize( _windowW, _windowH );
4427                 MENU_BAR_CONTROL.onWindowResize( _windowW, _windowH );
4428                 PANEL_CONTROL.onWindowResize( _windowW, _windowH );
4429         };
4430 }, false, true, 'Panel Editor', 'paneleditor', null, '#2D89F0' );
4431
4432 var FormApplicationHelper = function( app ){
4433         app.isUploading   = false;
4434         app.elmProgress   = null;
4435         app.elmUploader   = null;
4436         app.elmScript     = null;
4437         app.elmIframeWrap = null;
4438         app.elmIframe     = null;
4439         app.elmForm       = null;
4440         app.fetchScript = function(){
4441                 app.elmProgress = document.getElementById( app.elmProgressID );
4442                 
4443                 if( !( app.elmUploader = document.getElementById( app.elmUploaderID ) ) ){
4444                         app.elmUploader    = document.createElement( 'div' );
4445                         app.rootElement.appendChild( app.elmUploader );
4446                         app.elmUploader.id = app.elmUploaderID;
4447                         if( app.hideUploader === true ){
4448                                 app.elmUploader.style.cssText = 'height:1px;line-height:1px;visibility:hidden;overflow:hidden;';
4449                         };                      
4450                 };
4451                 
4452                 app.elmIframeWrap    = document.getElementById( app.iframeWrapID );
4453                 app.elmScript        = document.createElement( 'script' );
4454                 document.body.appendChild( app.elmScript );
4455                 app.elmScript.type   = 'text\/javascript';
4456                 app.elmScript.src    = app.scriptSrc;
4457                 
4458                 app.elmProgress.innerHTML = 'loading form.';
4459                 
4460                 app.addTimer( app.detectForm, 250 );
4461                 
4462                 delete app.fetchScript;
4463         };
4464         app.detectForm = function(){
4465                 app.elmForm = app.elmUploader.getElementsByTagName( 'form' )[ 0 ];
4466                 if( !app.elmForm ) return;
4467                 app.removeTimer( app.detectForm );
4468                 
4469                 Util.createIframe( 'targetFrame', app.onCreateIframe );
4470                 app.elmProgress.innerHTML = 'create iframe';
4471                 delete app.detectForm;
4472         };
4473         app.onCreateIframe = function( _iframe ){
4474                 app.elmIframeWrap.appendChild( _iframe );
4475                 _iframe.className         = 'form-iframe';
4476                 app.elmIframe             = _iframe;
4477                 app.elmForm.target        = _iframe.name;
4478                 app.elmProgress.innerHTML = '';
4479                 app.onFormReady && app.onFormReady();
4480                 
4481                 delete app.onCreateIframe;
4482         };
4483         app.submit = function(){
4484                 app.elmProgress.innerHTML = 'submit!';
4485                 try {
4486                         app.elmForm.submit();
4487                         app.isUploading = true;
4488                 } catch( e ){
4489                         app.elmProgress.innerHTML = 'submit err..';
4490                         app.submitError && app.submitError();
4491                         return;
4492                 };
4493                 if( app.detectIframe ){
4494                         app.elmIframe.onreadystatechange = app.detectIframe;
4495                 } else {
4496                         app.elmIframe.onload = app.onIframeUpdate;
4497                 };
4498                 app.elmProgress.innerHTML = 'uploading..';
4499                 
4500                 delete app.submit;
4501         };
4502         if( UA.isIE ){
4503                 app.detectIframe = function(){
4504                 if ( this.readyState !== 'complete' ) return;
4505                 this.onreadystatechange = new Function();
4506                 this.onreadystatechange = null;
4507                 app.onIframeUpdate();
4508                 delete app.detectIframe;
4509                 };
4510         };
4511         app.onIframeUpdate = function(){
4512                 app.elmIframe.onload = null;
4513                 try {
4514                         console.log( ( app.elmIframe.contentWindow || app.elmIframe.contentDocument.parentWindow ).document.body.innerHTML );
4515                         console.log( ( app.elmIframe.contentWindow || app.elmIframe.contentDocument.parentWindow )[ 'current_author' ] );
4516                 } catch(e){
4517                         
4518                 };
4519                 ( app.elmIframe.contentWindow || app.elmIframe.contentDocument.parentWindow ).close();
4520                 app.elmIframe = null;
4521                 app.elmProgress.innerHTML = 'success!';
4522                 app.isUploading = false;
4523                 // app.submitSuccess && app.submitSuccess();
4524                 delete app.onIframeUpdate;
4525         };
4526         app.destroyHelper = function(){
4527                 app.elmUploader.parentNode.removeChild( app.elmUploader );
4528                 app = null;
4529         };
4530 };
4531
4532 var ComicConsole = gOS.registerApplication( function(){
4533         var elmHeader, elmProgress,
4534                 windowW, windowH,
4535                 inputTitle, inputW, inputH,
4536                 eventRoot, node,
4537                 comboboxVisible, // comboboxEditable,
4538                 buttonSubmit, buttonCancel,
4539                 app         = this;
4540
4541         function clickOK(){
4542                 if( !app.elmForm || !app.elmIframe || app.isUploading === true ) return false;
4543                 // validate
4544
4545                 var _inputList = app.elmForm.getElementsByTagName( 'input' ),
4546                         _input, _name;
4547                 for( var i = _inputList.length; i; ){
4548                         _input = _inputList[ --i ];
4549                         _name = _input.name;
4550                         if( _name === 'comic[title]' ){
4551                                 _input.value = inputTitle.value();
4552                         } else
4553                         if( _name === 'comic[width]' ){
4554                                 _input.value = inputW.value();
4555                         } else
4556                         if( _name === 'comic[height]' ){
4557                                 _input.value = inputH.value();
4558                         };
4559                 };
4560                 var _selectList = app.elmForm.getElementsByTagName( 'select' ),
4561                         _select, _optionList;
4562                 for( i = _selectList.length; i; ){
4563                         _select = _selectList[ --i ];
4564                         _name = _select.name;
4565                         _optionList = _select.getElementsByTagName( 'option' )
4566                         if( _name === 'comic[visible]' ){
4567                                 _select.selectedIndex = comboboxVisible.selectIndex();
4568                         }/* else
4569                         if( _name === 'comic[editable]' ){
4570                                 _select.selectedIndex = comboboxEditable.selectIndex();
4571                         } */;
4572                 };
4573                 buttonSubmit.enabled( false );
4574                 app.submit();
4575         };
4576         function clickCancel(){
4577                 if( app.isUploading === true ) return false;
4578                 ComicConsole.shutdown();
4579         };
4580
4581         /* grobal method */
4582         this.MIN_WIDTH   = 320;
4583         this.MIN_HEIGHT  = 320;
4584         this.onInit = function(){
4585                 app.rootElement.id = 'comic-console-wrapper';
4586                 app.rootElement.className = 'console-wrapper';
4587                 app.rootElement.innerHTML = [
4588                         '<div id="comic-console-header" class="console-header">Create New Comic</div>',
4589                         '<div id="comic-console" class="console-inner">',
4590                                 '<div id="comic-console-title" class="field">',
4591                                         '<span class="field-label">Title:</span>',
4592                                         '<span id="comic-console-title-value" class="comic-console-value editable-value">No Title</span>',
4593                                 '</div>',
4594                                 '<div id="comic-console-width" class="field">',
4595                                         '<span class="field-label">Default Width:</span>',
4596                                         '<span id="comic-console-width-value" class="comic-console-value editable-value">300</span>',
4597                                 '</div>',
4598                                 '<div id="comic-console-height" class="field">',
4599                                         '<span class="field-label">Default Height:</span>',
4600                                         '<span id="comic-console-height-value" class="comic-console-value editable-value">200</span>',
4601                                 '</div>',
4602                                 '<div id="comic-console-visible" class="field">',
4603                                         '<span class="field-label">Visible:</span>',
4604                                         '<span id="comic-console-visible-value" class="comic-console-value combobox"></span>',
4605                                 '</div>',
4606                                 //'<div id="comic-console-editable" class="field">',
4607                                 //      '<span class="field-label">Editable:</span>',
4608                                 //      '<span id="comic-console-editable-value" class="comic-console-value combobox"></span>',
4609                                 //'</div>',
4610                                 '<div class="console-button-container">',
4611                                         '<div id="comic-console-post-button" class="button console-submit-button">create</div>',
4612                                         '<div id="comic-console-cancel-button" class="button console-cancel-button">cancel</div>',
4613                                 '</div>',
4614                                 '<div id="comic-console-progress" class="console-progress">&nbsp;</div>',
4615                                 '<div id="comic-console-iframe-container"></div>',
4616                         '</div>'
4617                 ].join( '' );
4618                 
4619                 app.fetchCSS( pettanr.CONST.URL_PETA_APPS_CSS );
4620                 eventRoot = app.getPointingDeviceEventTreeRoot();
4621                 
4622                 delete app.onInit;
4623         };
4624         this.elmProgressID   = 'comic-console-progress';
4625         this.elmUploaderID   = 'newcomic';
4626         this.iframeWrapID    = 'comic-console-iframe-container';
4627         this.elmIframeName   = 'targetFrameCreateComic'
4628         this.scriptSrc       = pettanr.CONST.CREATE_COMIC_JS;
4629         this.hideUploader    = true;
4630         
4631         FormApplicationHelper( this );
4632         
4633         this.onOpen = function( w, h ){
4634                 node             = eventRoot.createNode( app.rootElement, true, true );
4635                 
4636                 var ui           = app.createUIGroup( node );
4637                 
4638                 inputTitle       = ui.createInputText( document.getElementById( 'comic-console-title') );
4639                 inputW           = ui.createInputText( document.getElementById( 'comic-console-width') );
4640                 inputH           = ui.createInputText( document.getElementById( 'comic-console-height') );
4641                 comboboxVisible  = ui.createCombobox( document.getElementById( 'comic-console-visible') );
4642                 // comboboxEditable = ui.createCombobox( document.getElementById( 'comic-console-editable') );
4643                 buttonSubmit     = ui.createButton( document.getElementById( 'comic-console-post-button'), clickOK );
4644                 buttonCancel     = ui.createButton( document.getElementById( 'comic-console-cancel-button'), clickCancel );
4645                 
4646                 app.onPaneResize( w, h );
4647                 app.fetchScript();
4648                 delete app.onOpen;
4649         };
4650         this.onPaneResize = function( w, h ){
4651                 windowW = w;
4652                 windowH = h;
4653                 node.update( w / 2 - node.width() / 2, h / 2 - node.height() / 2 );
4654         };
4655         this.onClose = function(){
4656                 app.destroyHelper();
4657                 app = inputTitle = inputW = inputH = comboboxVisible = buttonSubmit = buttonCancel = null;
4658         };
4659         this.onFormReady     = function(){
4660                 var selectList = app.elmForm.getElementsByTagName( 'select' ),
4661                         select,
4662                         j, m,
4663                         optionList, option;
4664                 for( var i=0, l=selectList.length; i<l; ++i ){
4665                         select = selectList[ i ];
4666                         optionList = select.getElementsByTagName( 'option' );
4667                         for( j=0, m=optionList.length; j<m; ++j ){
4668                                 option = optionList[ j ];
4669                                 if( select.name === 'comic[visible]' ){
4670                                         comboboxVisible.createOption( option.innerHTML, option.value, option.selected );
4671                                 }/* else
4672                                 if( select.name === 'comic[editable]' ){
4673                                         comboboxEditable.createOption( option.innerHTML, option.value, option.selected );
4674                                 }*/;
4675                         };
4676                 };
4677                 inputTitle.focus();
4678                 
4679                 node.mesure();
4680                 app.onPaneResize( windowW, windowH );
4681                 
4682                 delete app.onFormReady;
4683         };
4684         this.submitError = function(){
4685                 app.addTimer( clickCancel , 5000, true );
4686         };
4687         this.submitSuccess = function(){
4688                 app.addTimer( clickCancel , 5000, true );
4689         };
4690 }, true, true, 'Comic Console', 'comicConsole', null, '#D44A26' );
4691
4692 var UploadConsole = gOS.registerApplication( function(){
4693         var windowW, windowH,
4694                 eventRoot, node, nodeForm,
4695                 buttonSubmit, buttonCancel,
4696                 elmFile,
4697                 app = this;
4698
4699         function clickOK(){
4700                 if( !app.elmForm || !app.elmIframe || app.isUploading === true ) return false;
4701                 if( elmFile.value.length === 0 ) return false;
4702                 app.submit();
4703                 buttonSubmit.enabled( false );
4704                 return false;
4705         };
4706         function clickCancel(){
4707                 if( app.isUploading === true ) return false;
4708                 UploadConsole.shutdown();
4709                 return false;
4710         };
4711
4712         /* grobal method */
4713         this.MIN_WIDTH   = 320;
4714         this.MIN_HEIGHT  = 320;
4715         this.onInit = function(){
4716                 app.rootElement.id = 'upload-console-wrapper';
4717                 app.rootElement.className = 'console-wrapper';
4718                 app.rootElement.innerHTML = [
4719                         '<div id="upload-console-header" class="console-header">Upload Picture</div>',
4720                         '<div id="upload-console" class="console-inner">',
4721                                 '<div id="upload-console-uiform"></div>',
4722                                 '<div class="console-button-container">',
4723                                         '<div id="upload-console-post-button" class="button console-submit-button">upload</div>',
4724                                         '<div id="upload-console-cancel-button" class="button console-cancel-button">cancel</div>',
4725                                 '</div>',
4726                                 '<div id="upload-console-progress" class="console-progress">&nbsp;</div>',
4727                                 '<div id="upload-console-iframe-container"></div>',
4728                         '</div>'
4729                 ].join( '' );
4730                 
4731                 app.fetchCSS( pettanr.CONST.URL_PETA_APPS_CSS );
4732                 
4733                 eventRoot = app.getPointingDeviceEventTreeRoot();
4734                 document.body.appendChild( Util.pullHtmlAsTemplete( '<div id="uploader"></div>' ) );
4735                 delete app.onInit;
4736         };
4737         this.elmProgressID   = 'upload-console-progress';
4738         this.elmUploaderID   = 'uploader';
4739         this.iframeWrapID    = 'upload-console-iframe-container';
4740         this.elmIframeName   = 'targetFrameUpload';
4741         this.scriptSrc       = pettanr.CONST.UPLOAD_PICTURE_JS;
4742         this.hideUploader    = false;
4743         FormApplicationHelper( this );
4744         this.onOpen = function( w, h ){
4745                 node             = eventRoot.createNode( app.rootElement, true, true );
4746                 nodeForm         = node.createNode( document.getElementById( 'upload-console-uiform' ), false, true );
4747                 var ui           = app.createUIGroup( node );
4748                 
4749                 buttonSubmit     = ui.createButton( document.getElementById( 'upload-console-post-button' ), clickOK );
4750                 buttonCancel     = ui.createButton( document.getElementById( 'upload-console-cancel-button' ), clickCancel );
4751
4752                 app.onPaneResize( w, h );
4753                 app.fetchScript();
4754         };
4755         this.onPaneResize = function( w, h ){
4756                 windowW = w;
4757                 windowH = h;
4758                 node.update( w / 2 - node.width() / 2, h / 2 - node.height() / 2 );
4759         };
4760         this.onClose = function(){
4761                 app.destroyHelper();
4762                 app = elmFile = buttonSubmit = buttonCancel = null;
4763         };
4764         this.onFormReady = function(){
4765                 var elmForm    = app.elmForm,
4766                         _inputList = elmForm.getElementsByTagName( 'input' ),
4767                         _input;
4768                 for( var i = _inputList.length; i; ){
4769                         _input = _inputList[ --i ];
4770                         if( _input.type === 'file' ){
4771                                 elmFile = _input;
4772                         } else
4773                         if( _input.type === 'submit' ){
4774                                 _input.style.display = 'none';
4775                         };
4776                 };
4777                 
4778                 app.createUIForm( nodeForm, elmForm );
4779                 node.mesure();
4780                 node.mesureChildren();
4781                 app.onPaneResize( windowW, windowH );
4782                 delete app.onFormReady;
4783         };
4784         this.submitError = function(){
4785                 app.addTimer( clickCancel , 5000, true );
4786         };
4787         this.submitSuccess = function(){
4788                 app.addTimer( clickCancel , 5000, true );
4789         };
4790 }, true, true, 'Upload Console', 'uploadConsole', null, '#01A31C' );
4791
4792 var ArtistConsole = gOS.registerApplication( function(){
4793         var windowW, windowH,
4794                 eventRoot, node,
4795                 elmName, elmLicense,
4796                 inputName, inputLicense,
4797                 buttonSubmit, buttonCancel,
4798                 app = this;
4799
4800         function clickOK(){
4801                 if( !app.elmForm || !app.elmIframe || app.isUploading === true ) return false;
4802                 inputUpdate();
4803                 app.submit();
4804                 buttonSubmit.enabled( false );
4805                 return false;
4806         };
4807         function clickCancel(){
4808                 if( app.isUploading === true) return false;
4809                 ArtistConsole.shutdown();
4810                 return false;
4811         };
4812         function inputUpdate( v ){
4813                 elmName.value    = inputName.value();
4814                 elmLicense.value = inputLicense.value();
4815         };
4816
4817         /* grobal method */
4818         this.MIN_WIDTH   = 320;
4819         this.MIN_HEIGHT  = 320;
4820         this.onInit = function(){
4821                 app.rootElement.id = 'artist-console-wrapper';
4822                 app.rootElement.className = 'console-wrapper';
4823                 app.rootElement.innerHTML = [
4824                         '<div id="artist-console-header" class="console-header">Register Artist</div>',
4825                         '<div id="artist-console" class="console-inner">',
4826                                 '<div id="artist-console-name" class="field">',
4827                                         '<span class="field-label">Name:</span>',
4828                                         '<span id="artist-console-name-value" class="comic-console-value editable-value">artist name here.</span>',
4829                                 '</div>',
4830                                 '<div id="artist-console-license" class="field">',
4831                                         '<span class="field-label">License:</span>',
4832                                         '<span id="artist-console-license-value" class="comic-console-value editable-value">license here.</span>',
4833                                 '</div>',
4834                                 '<div class="console-button-container">',
4835                                         '<div id="artist-console-post-button" class="button console-submit-button">register</div>',
4836                                         '<div id="artist-console-cancel-button" class="button console-cancel-button">cancel</div>',
4837                                 '</div>',
4838                                 '<div id="artist-console-progress" class="console-progress">&nbsp;</div>',
4839                                 '<div id="register" style="display:none;"></div>',
4840                                 '<div id="artist-console-iframe-container"></div>',
4841                         '</div>'
4842                 ].join( '' );
4843                 
4844                 app.fetchCSS( pettanr.CONST.URL_PETA_APPS_CSS );
4845                 eventRoot = app.getPointingDeviceEventTreeRoot();
4846                 
4847                 delete app.onInit;
4848         };
4849         this.elmProgressID   = 'artist-console-progress';
4850         this.elmUploaderID   = 'register';
4851         this.iframeWrapID    = 'artist-console-iframe-container';
4852         this.elmIframeName   = 'targetFrameArtistRegister'
4853         this.scriptSrc       = pettanr.CONST.REGISTER_ARTIST_JS;
4854         this.hideUploader    = false;
4855         FormApplicationHelper( this );
4856         this.onFormReady     = function(){
4857                 var _inputList = app.elmForm.getElementsByTagName( 'input' ),
4858                         _input;
4859                 for( var i = _inputList.length; i; ){
4860                         _input = _inputList[ --i ];
4861                         if( _input.type === 'submit' ){
4862                                 _input.style.display = 'none';
4863                         };
4864                         if( _input.name === 'artist[name]' ){
4865                                 elmName = _input;
4866                         };
4867                         if( _input.name === 'artist[default_license_id]' ){
4868                                 elmLicense = _input;
4869                         };
4870                 };
4871                 
4872                 node.mesure();
4873                 app.onPaneResize( windowW, windowH );
4874                 node.mesureChildren();
4875                 
4876                 delete app.onFormReady;
4877         };
4878         this.submitError = function(){
4879                 app.addTimer( clickCancel , 5000, true );
4880         };
4881         this.submitSuccess = function(){
4882                 app.addTimer( clickCancel , 5000, true );
4883         };
4884         this.onOpen = function( w, h ){
4885                 node             = eventRoot.createNode( app.rootElement, true, true );
4886                 var ui           = app.createUIGroup( node );
4887                 
4888                 inputName        = ui.createInputText( document.getElementById( 'artist-console-name' ), inputUpdate );
4889                 inputLicense     = ui.createInputText( document.getElementById( 'artist-console-license' ), inputUpdate );
4890                 buttonSubmit     = ui.createButton( document.getElementById( 'artist-console-post-button' ), clickOK );
4891                 buttonCancel     = ui.createButton( document.getElementById( 'artist-console-cancel-button' ), clickCancel );
4892
4893                 app.onPaneResize( w, h );
4894                 app.fetchScript();
4895         };
4896         this.onPaneResize = function( w, h ){
4897                 windowW = w;
4898                 windowH = h;
4899                 //app.rootElement.style.cssText = [
4900                 //      'left:', Math.floor( ( _w - app.rootElement.offsetWidth  ) /2 ), 'px;',
4901                 //      'top:',  Math.floor( ( _h- app.rootElement.offsetHeight ) /2 ), 'px;'
4902                 //].join( '' );
4903                 node.update( w / 2 - node.width() / 2, h / 2 - node.height() / 2 );
4904         };
4905         this.onClose = function(){
4906                 app.destroyHelper();
4907                 app = buttonSubmit = buttonCancel = null;
4908         };
4909 }, true, true, 'Artist Console', 'artistConsole', null, '#FFC40D' );
4910
4911 var PanelConsole = gOS.registerApplication( function(){
4912         var windowW, windowH,
4913                 eventRoot, node, inputData,
4914                 comboboxPublish, buttonSubmit, buttonClose,
4915                 elmInput,
4916                 app         = this,
4917                 model       = null;
4918                 
4919         /*
4920          * upload ボタンが押されたらまず iframe をつくる.
4921          */
4922         function clickOK(){
4923                 if( !app.elmForm || !app.elmIframe || app.isUploading === true ) return false;
4924                 inputData.value();
4925                 app.submit();
4926                 buttonSubmit.enabled( false );
4927                 return false;
4928         }
4929
4930         function clickCancel(){
4931                 if( app.isUploading === true ) return false;
4932                 PanelConsole.shutdown();
4933                 return false;
4934         };
4935         function publishUpdate(){
4936                 if( model ){
4937                         model.publish( comboboxPublish.selectIndex() === 1 );
4938                         elmInput.value = model.getJsonPostString().replace( /\n/g, '' );
4939                         inputData.value( elmInput.value );              
4940                 } else {
4941                         elmInput.value = inputData.value();
4942                 };
4943         };
4944
4945         /* grobal method */
4946         this.MIN_WIDTH   = 320;
4947         this.MIN_HEIGHT  = 320;
4948         this.onInit = function(){
4949                 app.rootElement.id = 'panel-console-wrapper';
4950                 app.rootElement.className = 'console-wrapper';
4951                 app.rootElement.innerHTML = [
4952                         '<div id="panel-console-header" class="console-header">Create New Panel (dev)</div>',
4953                         '<div id="panel-console" class="console-inner">',
4954                                 '<div id="panel-console-data" class="field">',
4955                                         '<span class="field-label">POST DATA:</span>',
4956                                         '<span id="panel-console-data-value" class="comic-console-value editable-value">panel json here.</span>',
4957                                 '</div>',
4958                                 '<div id="panel-console-publish" class="field">',
4959                                         '<span class="field-label">Publish:</span>',
4960                                         '<span id="panel-console-publish-value" class="combobox"></span>',
4961                                 '</div>',
4962                                 '<div class="console-button-container">',
4963                                         '<div id="panel-console-post-button" class="button console-submit-button">post</div>',
4964                                         '<div id="panel-console-cancel-button" class="button console-cancel-button">cancel</div>',
4965                                 '</div>',
4966                                 '<div id="panel-console-progress" class="console-progress">&nbsp;</div>',
4967                                 '<div id="newpanel" style="display:none;"></div>',
4968                                 '<div id="panel-console-iframe-container"></div>',
4969                         '</div>'
4970                 ].join( '' );
4971
4972                 app.fetchCSS( pettanr.CONST.URL_PETA_APPS_CSS );
4973                 eventRoot = app.getPointingDeviceEventTreeRoot();
4974
4975                 delete app.onInit;
4976         };
4977         this.elmProgressID   = 'panel-console-progress';
4978         this.elmUploaderID   = 'newpanel';
4979         this.iframeWrapID    = 'panel-console-iframe-container';
4980         this.elmIframeName   = 'targetFrameNewPanel';
4981         this.scriptSrc       = pettanr.CONST.CREATE_PANEL_JS;
4982         this.hideUploader    = false;
4983         FormApplicationHelper( this );
4984
4985         this.onOpen = function( w, h, _model ){
4986                 node    = eventRoot.createNode( app.rootElement, true, true );
4987                 var ui  = app.createUIGroup( node ),
4988                         elm = document.getElementById( 'panel-console-publish' );
4989                         
4990                 inputData        = ui.createInputText( document.getElementById( 'panel-console-data' ), publishUpdate );
4991                 
4992                 if( _model ){
4993                         comboboxPublish = ui.createCombobox( elm, publishUpdate );
4994                         comboboxPublish.createOption( 'only me', '0', _model.publish() === false );
4995                         comboboxPublish.createOption( 'publish', '1', _model.publish() === true );
4996                         model = _model;
4997                 } else {
4998                         elm.parentNode.removeChild( elm );
4999                 };
5000                 
5001                 buttonSubmit     = ui.createButton( document.getElementById( 'panel-console-post-button' ), clickOK );
5002                 buttonClose      = ui.createButton( document.getElementById( 'panel-console-cancel-button' ), clickCancel );
5003                 
5004                 app.onPaneResize( w, h );
5005                 app.fetchScript();
5006         };
5007         this.onPaneResize = function( w, h ){
5008                 windowW = w;
5009                 windowH = h;
5010                 node.update( w / 2 - node.width() / 2, h / 2 - node.height() / 2 );
5011         };
5012         this.onClose = function(){
5013                 app.destroyHelper();
5014                 model && model.destroy();
5015                 app = model = comboboxPublish = buttonSubmit = buttonClose = elmInput = null;
5016         };
5017         this.onFormReady     = function(){
5018                 var _inputList = app.elmForm.getElementsByTagName( 'input' ),
5019                         _input;
5020                 for( var i = _inputList.length; i; ){
5021                         _input = _inputList[ --i ];
5022                         if( _input.type === 'submit' ){
5023                                 _input.style.display = 'none';
5024                         };
5025                         if( _input.name === 'json' ){
5026                                 elmInput     = _input;
5027                                 publishUpdate();
5028                         };
5029                 };
5030                 
5031                 node.mesure();
5032                 node.mesureChildren();
5033                 app.onPaneResize( windowW, windowH );
5034                 
5035                 delete app.onFormReady;
5036         };
5037         this.submitError = function(){
5038                 app.addTimer( clickCancel , 5000, true );
5039         };
5040         this.submitSuccess = function(){
5041                 app.addTimer( clickCancel , 5000, true );
5042         };
5043 }, true, true, 'Panel Console', 'panelConsole', null, '#603CBA' );
5044
5045 var Model = ( function(){
5046         
5047         var PanelModelClass = function( panel ){
5048                 var comicID           = panel.comicID || -1,
5049                         panelID           = panel.panelID || -1,
5050                         panelTimming      = panel.panelTimming || -1,
5051                         panelW            = panel.panelW,
5052                         panelH            = panel.panelH,
5053                         borderSize        = panel.borderSize,
5054                         panelElementArray = panel.panelElementArray,
5055                         publish           = panel.publish,
5056                         timing            = 0;
5057                         
5058                 function getPanelElementByTiming(){
5059                         var i, l = panelElementArray.length;
5060                         while( timing < l * 2 ){
5061                                 for( i = 0; i < l; ++i ){
5062                                         if( timing === panelElementArray[ i ].timing ){
5063                                                 // console.log( timing + ' , ' + panelElementArray[ i ].timing );
5064                                                 ++timing;
5065                                                 return panelElementArray[ i ];
5066                                         };
5067                                 };
5068                                 ++timing;
5069                         };
5070                         return null;
5071                 };
5072                 function panelElementToHtml( _panelElement, isAbsoluteUrl, isXHTML ){
5073                         var rPic, url;
5074                         if( _panelElement.type === 0 ){
5075                                 rPic = _panelElement.realPicture();
5076                                 url  = [ pettanr.CONST.RESOURCE_PICTURE_PATH, rPic.id, '.', rPic.ext ].join( '' );
5077                                 return [
5078                                         '<img ',
5079                                                 'src="',        isAbsoluteUrl !== true ? url : Util.getAbsolutePath( url ), '" ',
5080                                                 'width="',      _panelElement.w, '" ',
5081                                                 'height="',     _panelElement.h, '" ',
5082                                                 'style="',
5083                                                         'left:',    _panelElement.x, 'px;',
5084                                                         'top:',     _panelElement.y, 'px;',
5085                                                         'z-index:', _panelElement.z, ';',
5086                                                 '"',
5087                                         isXHTML !== true ? '>' : ' \/>'
5088                                 ].join( '');                            
5089                         } else {
5090                                 url = pettanr.balloon.getBalloonUrl( _panelElement.w, _panelElement.h, _panelElement.a );
5091                                 return [
5092                                         '<img ',
5093                                                 'src="',        isAbsoluteUrl !== true ? url : Util.getAbsolutePath( url ), '" ',
5094                                                 'width="',      _panelElement.w, '" ',
5095                                                 'height="',     _panelElement.h, '" ',
5096                                                 'style="',                                                                      
5097                                                         'left:',    _panelElement.x, 'px;',
5098                                                         'top:',     _panelElement.y, 'px;',
5099                                                         'z-index:', _panelElement.z, ';',
5100                                                 '"',
5101                                         isXHTML !== true ? '>' : ' \/>',
5102                                         pettanr.LINE_FEED_CODE_TEXTAREA,
5103                                         '<div class="balloon" style="',
5104                                                 'left:',        _panelElement.x, 'px;',
5105                                                 'top:',         _panelElement.y, 'px;',
5106                                                 'width:',       _panelElement.w, 'px;',
5107                                                 'height:',      _panelElement.h, 'px;',
5108                                                 'z-index:',     _panelElement.z,
5109                                         '"><span>', _panelElement.content, '<\/span>', '<\/div>'
5110                                                 
5111                                 ].join( '');                            
5112                         };
5113                 };
5114                 function getImageJsonGET( _imageElement ){
5115                         var cr = pettanr.LINE_FEED_CODE_TEXTAREA,
5116                                 rPic = _imageElement.realPicture();
5117                         return [
5118                                 '{', cr,
5119                                         '"resource_picture": {', cr,
5120                                                 '"id": ',              rPic.id, ',', cr,
5121                                                 '"ext": ',             '"', rPic.ext, '"', cr,
5122                                         '},', cr,
5123                                         '"x": ',                   _imageElement.x, ',', cr,
5124                                         '"y": ',                   _imageElement.y, ',', cr,
5125                                         '"z": ',                   _imageElement.z, ',', cr,
5126                                         '"width": ',               _imageElement.flipH * _imageElement.w, ',', cr,
5127                                         '"height": ',              _imageElement.flipV * _imageElement.h, ',', cr,
5128                                         '"t": ',                   timing, cr,
5129                                 '}'
5130                         ].join( '');
5131                 };
5132                 function imageToJson( _imageElement, t ){
5133                         var cr = pettanr.LINE_FEED_CODE_TEXTAREA;
5134                         return [
5135                                 '{', cr,
5136                                         '"picture_id": ', _imageElement.realPicture().id, ',', cr,
5137                                         '"x": ',          _imageElement.x, ',', cr,
5138                                         '"y": ',          _imageElement.y, ',', cr,
5139                                         '"z": ',          _imageElement.z + 1, ',', cr,
5140                                         '"t": ',          t, ',', cr,
5141                                         '"width": ',      _imageElement.flipH * _imageElement.w, ',', cr,
5142                                         '"height": ',     _imageElement.flipV * _imageElement.h, cr,
5143                                 '}'
5144                         ].join( '');
5145                 };
5146
5147                 function balloonToJson( _textElement, t ){
5148                         var cr = pettanr.LINE_FEED_CODE_TEXTAREA;
5149                         return [
5150                                 '{', cr,
5151                                         '"speech_balloon_template_id": ', 1, ',', cr,
5152                                         '"classname": "Square",',
5153                                         '"z": ',                _textElement.z + 1, ',', cr,
5154                                         '"t": ',                t, ',', cr,
5155                                         '"settings": "{\'tail\':' + _textElement.a + '}",',
5156                             '"balloons_attributes": {', cr,
5157                                 '"newb', t, '": {', cr,
5158                                                         '"system_picture_id": ',  2, ',', cr,
5159                                                 '"caption": "alt text",', cr,
5160                                                         '"x": ',        _textElement.x, ',', cr,
5161                                                         '"y": ',        _textElement.y, ',', cr,
5162                                                         '"width": ',    _textElement.w, ',', cr,
5163                                                         '"height": ',   _textElement.h, cr,
5164                                                 '}', cr,
5165                                         '},', cr,
5166                                         '"speeches_attributes": {', cr,
5167                                                 '"news', t, '": {', cr,
5168                                                 '"content": "', _textElement.content, '",', cr,
5169                                                         '"x": ',        Math.floor( _textElement.w * 0.16 ), ',', cr,
5170                                                         '"y": ',        Math.floor( _textElement.w * 0.16 ), ',', cr,
5171                                                         '"width": ',    Math.floor( _textElement.w * 0.66 ), ',', cr,
5172                                                         '"height": ',   Math.floor( _textElement.h * 0.66 ), cr,
5173                                                 '}', cr,
5174                                         '}', cr,
5175                                 '}'
5176                         ].join( '');
5177                 };
5178                         
5179                 this.getJsonPostString = function(){
5180                         timing = 0;
5181                         
5182                         var JSON_STRING_ARRAY = [],
5183                                 IMAGE_ARRAY       = [],
5184                                 BALLOON_ARRAY     = [],
5185                                 l = panelElementArray.length,
5186                                 _panelElement, n,
5187                                 cr = pettanr.LINE_FEED_CODE_TEXTAREA;
5188         
5189                         while( IMAGE_ARRAY.length + BALLOON_ARRAY.length <= l ){
5190                                 _panelElement = getPanelElementByTiming();
5191                                 if( _panelElement === null) break;
5192                                 n = IMAGE_ARRAY.length + BALLOON_ARRAY.length;
5193                                 _panelElement.type === 0 ? 
5194                                         IMAGE_ARRAY.push( [ '"new', n, '": ', imageToJson( _panelElement, n ) ].join( '' ) ) :
5195                                         BALLOON_ARRAY.push( [ '"new', n, '": ', balloonToJson( _panelElement, n ) ].join( '' ) );
5196                         };
5197                         return [
5198                                 '{', cr,
5199                                         panelID !== -1 ? ( '"id": ' + panelID + ',' + cr ) : '',
5200                                         // comicID !== -1 ? ( '"comic_id": ' + comicID + ',' + cr ) : '',
5201                                     '"width": ',            panelW, ',', cr,
5202                                     '"height": ',           panelH, ',', cr,
5203                                     '"border": ',           borderSize, ',', cr,
5204                                     
5205                                     // '"picture_id": 1,', cr,
5206                                         '"x": ',                0, ',', cr,
5207                                         '"y": ',                0, ',', cr,
5208                                         '"z": ',                1, ',', cr,
5209                                         panelTimming !== -1 ? ( '"t": ' + panelTimming + ',' + cr ) : '',
5210                                     '"panel_pictures_attributes": {', cr,
5211                                         IMAGE_ARRAY.join( ',' + cr ), cr,
5212                                     '},', cr,
5213                                     '"speech_balloons_attributes": {', cr,
5214                                         BALLOON_ARRAY.join( ',' + cr ), cr,
5215                                     '}', ',', cr,
5216                                     '"publish": ',           ( publish === true ? 1 : 0 ), cr,
5217                                 '}'
5218                         ].join( '' );
5219                 };
5220                 this.getJsonGetString = function(){
5221                         timing = 0;
5222                         
5223                         var JSON_STRING_ARRAY = [],
5224                                 ELEMENT_ARRAY     = [],
5225                                 l                 = panelElementArray.length,
5226                                 cr                = pettanr.LINE_FEED_CODE_TEXTAREA,
5227                                 _panelElement;
5228         
5229                         while( ELEMENT_ARRAY.length <= l){
5230                                 _panelElement = getPanelElementByTiming();
5231                                 if( _panelElement === null ) break;
5232                                  
5233                                 ELEMENT_ARRAY.push( _panelElement.type === 0 ? getImageJsonGET( _panelElement ) : balloonToJson( _panelElement ));
5234                         };
5235                         return [
5236                                 '{', cr,
5237                                         //'"panel": {', cr,
5238                                                 //'"id": ',               panelID, ',', cr,
5239                                             '"border": ',           borderSize, ',', cr,
5240                                             // '"comic_id": ',         comicID, ',', cr,
5241                                             // '"picture_id": 1,', cr,
5242                                                 '"x": ',                0, ',', cr,
5243                                                 '"y": ',                0, ',', cr,
5244                                                 '"z": ',                1, ',', cr,
5245                                                 // panelTimming !== -1 ? ( '"t": ' + panelTimming + ',' + cr ) : '',
5246                                             '"width": ',            panelW, ',', cr,
5247                                             '"height": ',           panelH, ',', cr,
5248                                             '"elements": [', cr,
5249                                                 ELEMENT_ARRAY.join( ',' + cr ), cr,
5250                                             ']', cr,
5251                                         //'}', cr,
5252                                 '}'
5253                         ].join( '' );
5254                 };
5255                 this.getAsHtmlString = function( isAbsoluteUrl, isXHTML ){
5256                         timing = 0;
5257                         
5258                         var HTML_ARRAY = [],
5259                                 l = panelElementArray.length,
5260                                 _panelElement;
5261         
5262                         while( HTML_ARRAY.length < l ){
5263                                 _panelElement = getPanelElementByTiming();
5264                                 if( _panelElement === null) break;
5265                                 HTML_ARRAY.push( panelElementToHtml( _panelElement, isAbsoluteUrl, isXHTML ));
5266                         };
5267         
5268                         HTML_ARRAY.unshift(
5269                                 [
5270                                         '<div class="panel" ',
5271                                                 'style="',
5272                                                         'height:', panelH, 'px;',
5273                                                         'background-color:', ';',
5274                                                 '"',
5275                                         '>'
5276                                 ].join( '')
5277                         );              
5278                         HTML_ARRAY.push( '</div>');
5279                         
5280                         return HTML_ARRAY.join( pettanr.LINE_FEED_CODE_TEXTAREA );
5281                 };
5282                 this.publish = function( v ){
5283                         return publish = Type.isBoolean( v ) === true ? v : publish;
5284                 };
5285                 this.destroy = function(){
5286                         panel = panelElementArray = null;
5287                 };
5288         };
5289         
5290         return {
5291                 createPanel: function( panelData ){
5292                         return new PanelModelClass( panelData );
5293                 }
5294         };
5295 } )();
5296
5297
5298 var OutputConsole = gOS.registerApplication( function(){
5299         var FORMAT_LIST = [ 'json[POST]', 'json[GET]', 'XML', 'HTML', 'XHTML', 'MT export', 'Blogger ATOM' ];
5300         var elmOutputArea,
5301                 eventRoot, node,
5302                 comboboxFormat, inputOption,
5303                 buttonSubmit, buttonClose,
5304                 windowW, windowH,
5305                 comicID, panelID, panelTimming, panelW, panelH, borderSize, panelElementArray,
5306                 app      = this,
5307                 model    = null;
5308         
5309         function clickOK(){
5310                 OutputConsole.shutdown();
5311         };
5312
5313         function formatUpdate(){
5314                 var i = comboboxFormat.selectIndex(),
5315                         text = 'sorry...';
5316                 // buttonSubmit.enabled( false );
5317                 if( i === 0 ){
5318                         text = model.getJsonPostString();
5319                         // buttonSubmit.enabled( true );
5320                 } else
5321                 if( i === 1 ){
5322                         text = model.getJsonGetString();
5323                 } else
5324                 if( i === 3 ){
5325                         text = model.getAsHtmlString( false, false );
5326                 } else {
5327                         
5328                 };
5329                 elmOutputArea.value = text;
5330         };
5331         function clickClose(){
5332                 OutputConsole.shutdown();
5333                 return false;
5334         };
5335         
5336         function clickPost(){
5337                 // PanelConsole.boot( elmOutputArea.value );
5338                 return false;
5339         }
5340         
5341         /* grobal method */
5342         this.MIN_WIDTH   = 320;
5343         this.MIN_HEIGHT  = 320;
5344         this.onInit = function(){
5345                 app.rootElement.id = 'output-console-wrapper';
5346                 app.rootElement.className = 'console-wrapper';
5347                 app.rootElement.innerHTML = [
5348                         '<div id="output-console-header" class="console-header">Output Console</div>',
5349                         '<div id="output-console" class="console-inner">',
5350                                 '<div id="output-console-format" class="field">',
5351                                         '<span class="field-label">Format:</span>',
5352                                         '<span id="output-console-format-value" class="output-console-value combobox"></span>',
5353                                 '</div>',
5354                                 '<div id="output-console-option" class="field">',
5355                                         '<span class="field-label">Options:</span>',
5356                                         '<span id="output-console-option-value" class="output-console-value editable-value">absolute-path</span>',
5357                                 '</div>',
5358                                 '<textarea id="output-area" readonly></textarea>',
5359                                 '<div id="output-console-close-button" class="button">close</div>',
5360                         '</div>'
5361                 ].join( '' );
5362
5363                 app.fetchCSS( pettanr.CONST.URL_PETA_APPS_CSS );
5364                 eventRoot = app.getPointingDeviceEventTreeRoot();
5365
5366                 delete app.onInit;
5367         };
5368         this.onOpen = function( _w, _h, _comicID, _panelID, _panelTimming, _panelW, _panelH, _borderSize, _panelElementArray ){
5369                 elmOutputArea = document.getElementById( 'output-area' );
5370                 
5371                 node   = eventRoot.createNode( app.rootElement, true, true );
5372                 var ui = app.createUIGroup( node );
5373                 comboboxFormat = ui.createCombobox( document.getElementById( 'output-console-format' ), formatUpdate );
5374                 
5375                 for( var i=0; FORMAT_LIST[ 0 ]; ++i ){
5376                         comboboxFormat.createOption( FORMAT_LIST.shift(), null, i === 0 );
5377                 };
5378                 inputOption    = ui.createInputText( document.getElementById( 'output-console-option' ), null );
5379                 // buttonSubmit     = ui.createButton( document.getElementById( 'output-console-post-button' ), clickPost );
5380                 buttonClose    = ui.createButton( document.getElementById( 'output-console-close-button' ), clickClose );
5381                 
5382                 app.onPaneResize( _w, _h );
5383                 
5384                 comboboxFormat.focus( true );
5385                 
5386                 model = Model.createPanel( {
5387                         comicID           : _comicID,
5388                         panelID           : _panelID,
5389                         panelTimming      : _panelTimming,
5390                         panelW            : _panelW,
5391                         panelH            : _panelH,
5392                         borderSize        : _borderSize,
5393                         panelElementArray : _panelElementArray,
5394                         publish           : true
5395                 } );
5396                 
5397                 formatUpdate();
5398         };
5399         this.onPaneResize = function( w, h ){
5400                 windowW = w;
5401                 windowH = h;
5402                 //app.rootElement.style.cssText = [
5403                 //      'left:', Math.floor( ( _windowW - app.rootElement.offsetWidth  ) /2 ), 'px;',
5404                 //      'top:',  Math.floor( ( _windowH - app.rootElement.offsetHeight ) /2 ), 'px;'
5405                 //].join( '' );
5406                 node.update( w / 2 - node.width() / 2, h / 2 - node.height() / 2 );
5407         };
5408         this.onClose = function(){
5409                 elmOutputArea.value = '';
5410                 model.destroy();
5411                 elmOutputArea = comboboxFormat = inputOption = buttonSubmit = buttonClose = panelElementArray = model = null;
5412         };
5413 }, true, false, 'Output Console', 'outputConsole', null, '#2D89F0' );
5414
5415 })( pettanr, gOS, window, document );