OSDN Git Service

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