OSDN Git Service

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