OSDN Git Service

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