OSDN Git Service

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