OSDN Git Service

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