OSDN Git Service

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