OSDN Git Service

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