OSDN Git Service

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