OSDN Git Service

X.Node working on IE5-, bugfix X.Node.Anime.
[pettanr/clientJs.git] / 0.2.0 / main.js
1 /*
2  * html2comic Javascript Editor -
3  * 
4  *   main.js
5  *   version 0.2.0
6  *
7  * author:
8  *   itozyun
9  *
10  * licence:
11  *   3-clause BSD
12  * 
13  * ----------------------------------------
14  * - naming of comic's elements -
15  * 
16  *  0.comic strip(en) : koma manga(jp)
17  *
18  *  1.panel(en) : koma(jp)
19  *    +------------+
20  *    |            |
21  *    |            |
22  *    |            |
23  *    |            |
24  *    +------------+
25  *  
26  *  2.speach balloon(en) : fukidasi(jp)
27  *      ________
28  *     /        \
29  *     |         |
30  *    <  Hello!! |
31  *     |         |
32  *     \________/
33  *   
34  *  3.img
35  * 
36  * 
37  * ----------------------------------------
38  * window
39  * +----------------------------+
40  * |      CANVAS_CONTROL        |  
41  * |       - panel              |
42  * |        +----------+        | 
43  * |        | +----------+      | 
44  * |        | |          |      | 
45  * |        | |          |      | 
46  * |        +-|          |      |
47  * |          +----------+      | 
48  * |        - WHITE_GLASS_CONTROL | 
49  * +----------------------------+
50  * 
51  * ----------------------------------------
52  * naming rules
53  * 
54  *  Class
55  *    ThisIsClass
56  *  
57  *  const & Singleton Class
58  *    THIS_IS_CONST = 'this is const';
59  *  
60  *  var
61  *    thisIsVar
62  *   
63  *  value of jquery
64  *    jqWrapper, JQ_WRAPPER
65  *  
66  *  value of dom element
67  *    elmWrapper, ELM_WRAP
68  * 
69  *      value of vml element
70  *    vmkImg, VML_SHAPE
71  * 
72  */
73
74 var h2c = ( function(){
75         var     FUNCTION_ARRAY = [],
76                 URL = document.location.href.split( '#')[ 0],
77                 IS_LOCAL = URL.indexOf( 'file:') === 0,
78                 URL_PARAMS = ( function(){
79                         var search = document.location.search,
80                                 l = search.length;
81                     if( 1 < l){
82                         var     query = search.substring( 1),
83                                         params = query.split( '&'),
84                                         ret = {}, elm, name;
85                         while( params.length > 0){
86                             elm = params.shift().split( '=');
87                                         name = decodeURIComponent( elm[ 0]);
88                                         if( elm.length === 2){
89                                     ret[ name] = ( function( v){
90                                                         if( '' + parseFloat( v) === v) return parseFloat( v);
91                                                         if( v === 'true') return true;
92                                                         if( v === 'false') return false;
93                                                         if( v === 'null') return null;
94                                                         if( v === 'undefined') return undefined;
95                                                         return v;
96                                                 })( decodeURIComponent( elm[ 1]));
97                                         } else
98                                         if( elm.length === 1){
99                                                 ret[ name] = true;
100                                         }
101                         }
102                         return ret;
103                     }
104                     return {};
105                 })(),
106                 IS_DEBUG = IS_LOCAL === true || URL_PARAMS.debug === true,
107                 isIE = navigator.userAgent.toLowerCase().indexOf( 'msie') !== -1,
108                 ieVersion = isIE === true ? parseInt( navigator.appVersion.toLowerCase().replace( /.*msie[ ]/, '').match( /^[0-9]+/)) : 0,
109                 ieMode = ieVersion === 8 ? document.documentMode : 0,
110                 isStanderdMode = document.compatMode === 'CSS1Compat',
111                 jqWindow , jqDocument , jqBody;
112                 
113                 ( function(){
114                         var _elms = document.getElementsByTagName( '*'),
115                                 _elm,
116                                 i = 0;
117                         while( i < _elms.length){
118                                 _elm = _elms[ i];
119                                 if( _elm.nodeType === 8 && _elm.parentNode){
120                                         _elm.parentNode.removeChild( _elm);
121                                 } else {
122                                         ++i;
123                                 }
124                         }
125                 })();
126                 
127         return {
128                 version: '0.2.0',
129                 init: function(){
130                         jqWindow = $( window);
131                         jqDocument = $( document);
132                         jqBody = $( document.body);
133                         
134                         var l = FUNCTION_ARRAY.length,
135                                 _fn;
136                         for( var i=0; i<l; i++){
137                                 _fn = FUNCTION_ARRAY[ i];
138                                 _fn.init && _fn.init( _fn === h2c.view ? FUNCTION_ARRAY : undefined);
139                         }
140                         
141                         delete h2c.init;
142                 },
143                 fn: function( _fn){
144                         FUNCTION_ARRAY.push( _fn);
145                         h2c.init === undefined && _fn.init && _fn.init();
146                 },
147                 isIE: isIE,
148                 ieVersion: ieVersion,
149                 ieRenderingVersion: ieMode !== 0 ? ieMode : ieVersion,
150                 isStanderdMode: isStanderdMode,
151                 VENDER_PREFIX: ( function() {
152                         var ua = navigator.userAgent.toLowerCase();
153                         if ( ua.indexOf('opera') !== -1) {
154                                 return 'O';
155                         } else if ( ua.indexOf('msie') !== -1) {
156                                 return 'ms';
157                         } else if ( ua.indexOf('webkit') !== -1) {
158                                 return 'webkit';
159                         } else if ( navigator.product === 'Gecko') {
160                                 return 'Moz';
161                         }
162                         return '';
163                 })(),
164                 ACTIVEX: ( function(){
165                         if( isIE === false || ieVersion > 8) return false;
166                         var className = document.body.className,
167                                 test;
168                         if( className && className.indexOf( 'h2c-ActiveX-enabled') !== -1) return true;
169                         if( className && className.indexOf( 'h2c-ActiveX-disabled') !== -1) return false;
170                         try {
171                                 test = new ActiveXObject('DXImageTransform.Microsoft.gradient');
172                         } catch( e){
173                                 return false;
174                         }
175                         return !!test;
176                 })(),
177                 jqWindow: function(){
178                         return jqWindow;
179                 },
180                 jqDocument: function(){
181                         return jqDocument;
182                 },
183                 jqBody: function(){
184                         return jqBody;
185                 },
186                 URL_PARAMS: URL_PARAMS,
187                 LOCAL: IS_LOCAL,
188                 DEBUG: IS_DEBUG,
189                 LINE_FEED_CODE_TEXTAREA : ( function(){
190                         var text = document.getElementById( 'shadowTxtarea'),
191                                 form = text.parentNode;
192                         form.parentNode.removeChild( form);
193                         return text.value;
194                 })(),
195                 LINE_FEED_CODE_PRE : ( function(){
196                         var pre = document.getElementById( 'shadowPre');
197                         pre.parentNode.removeChild( pre);
198                         return isIE === true ? this.LINE_FEED_CODE_TEXTAREA : pre.innerHTML; // ie ??
199                 })()
200         }
201 })();
202
203 /*
204  * h2c.util
205  * 
206  * getElementSize( _elm)
207  * getImageSize()
208  * 
209  */
210
211 h2c.util = ( function(){
212         var ELM_SIZE_GETTER = ( function(){
213                         var ret = document.createElement( 'DIV'),
214                                 style = ret.style;
215                         ret.id = 'elmSizeGetter';
216                         style.position = 'absolute';
217                         style.left = '0px';
218                         style.top = '-9999px';
219                         style.visibility = 'hidden';
220                         document.body.appendChild( ret);
221                         return ret;
222                 })(),
223                 IMG_SIZE_GETTER = ( function(){
224                         var ret = ELM_SIZE_GETTER.cloneNode( true);
225                         ret.id = 'imgSizeGetter';
226                         document.body.appendChild( ret);
227                         return ret;
228                 })();
229         return {
230                 extend: function( baseInstance, extend){
231                         for( var key in extend){
232                                 baseInstance[ key] = extend[ key];
233                         }
234                         return baseInstance;
235                 },
236                 getElementSize: function( _elm){
237                         if( !_elm){
238                                 return {
239                                         width:  0,
240                                         height: 0
241                                 }
242                         }
243                         var     parentElm = _elm.parentNode,
244                                 prevElm = _elm.previousSibling,
245                                 nextElm = _elm.nextSibling,
246                                 displayNone = _elm.style.display === 'none';
247                         if( displayNone === true) _elm.style.display = '';
248                         ELM_SIZE_GETTER.appendChild( _elm);
249                         var ret = {
250                                 width:          _elm.offsetWidth,
251                                 height:         _elm.offsetHeight
252                         }
253                         if( displayNone === true) _elm.style.display = 'none';
254                         if( nextElm){
255                                 parentElm.insertBefore( _elm, nextElm);
256                         } else          
257                         if( prevElm && prevElm.nextSibling){
258                                 parentElm.insertBefore( _elm, prevElm.nextSibling);
259                         } else {
260                                 parentElm && parentElm.appendChild( _elm);
261                         }                       
262                         return ret;
263                 },
264                 getImageSize: function( img){
265                         var     parentElm = img.parentNode,
266                                 prevElm = img.previousSibling,
267                                 nextElm = img.nextSibling,
268                                 displayNone = img.style.display === 'none';
269                         if( displayNone === true) img.style.display = '';
270                         IMG_SIZE_GETTER.appendChild( img);
271                         var size = getActualDimension( img);
272                         IMG_SIZE_GETTER.removeChild( img);
273                         if( displayNone === true) img.style.display = 'none';
274                         if( nextElm){
275                                 parentElm.insertBefore( img, nextElm);
276                         } else          
277                         if( prevElm && prevElm.nextSibling){
278                                 parentElm.insertBefore( img, prevElm.nextSibling);
279                         } else {
280                                 parentElm && parentElm.appendChild( img);
281                         }
282                         return size;
283                         
284                 /* LICENSE: MIT
285                  * AUTHOR: uupaa.js@gmail.com
286                  */
287                         function getActualDimension(image) {
288                                 var run, mem, w, h, key = "actual";
289                         
290                         // for Firefox, Safari, Google Chrome
291                                 if ("naturalWidth" in image) {
292                                         return {
293                                                 width:  image.naturalWidth,
294                                                 height: image.naturalHeight
295                                         };
296                                 }
297                         
298                                 if ("src" in image) { // HTMLImageElement
299                                         if (image[key] && image[key].src === image.src) {
300                                                 return image[key];
301                                         }
302                                         if (document.uniqueID) { // for IE
303                                                 run = image.runtimeStyle;
304                                                 mem = { w: run.width, h: run.height }; // keep runtimeStyle
305                                                 run.width  = "auto"; // override
306                                                 run.height = "auto";
307                                                 w = image.width;
308                                                 h = image.height;
309                                                 run.width  = mem.w; // restore
310                                                 run.height = mem.h;
311                                         } else { // for Opera and Other
312                                         /*
313                                                 function fn() {
314                                                         w = image.width;
315                                                         h = image.height;
316                                                 }
317                                                 mem = { w: image.width, h: image.height }; // keep current style
318                                                 image.removeAttribute("width");
319                                                 image.addEventListener("DOMAttrModified", fn, false);
320                                                 image.removeAttribute("height");
321                                                 // call fn
322                                                 image.removeEventListener("DOMAttrModified", fn, false);
323                                                 image.width  = mem.w; // restore
324                                                 image.height = mem.h;
325                                         */
326                                                 mem = { w: image.width, h: image.height }; // keep current style
327                                                 image.removeAttribute("width");
328                                                 image.removeAttribute("height");
329                                                 w = image.width;
330                                                 h = image.height;
331                                                 image.width  = mem.w; // restore
332                                                 image.height = mem.h;
333                                         }
334                                         return image[key] = { width: w, height: h, src: image.src }; // bond
335                                 }
336                                 // HTMLCanvasElement
337                                 return { width: image.width, height: image.height };
338                         }
339                 },
340                 loadImage: function( URLorELM, onLoad, onError, delay, timeout){
341                         delay = delay || 250;
342                         timeout = timeout || 5000;
343                         var type = typeof URLorELM,
344                                 img, images, src, abstractPath;
345                         if( type === 'string'){
346                                 src = URLorELM;
347                                 // images = [];
348                         } else
349                         // http://d.hatena.ne.jp/hottolinkblog/20090228/1235823487
350                         if( type === 'object' && typeof URLorELM.hspace !== 'undefined' && typeof URLorELM.vspace !== 'undefined'){
351                                 img = URLorELM;
352                                 images = [ img];
353                                 src = img.src;
354                         } else {
355                                 return;
356                         }
357                         abstractPath = this.getAbsolutePath( src);
358                         
359                         loadImage( images, abstractPath,
360                                 function( abspath, actualW, actualH){
361                                         if( abstractPath !== abspath) return;
362                                         onLoad && setTimeout( function(){ // 一度読み込まれた画像は即座にonLoadされてしまうので遅延
363                                                 onLoad( src, actualW, actualH);
364                                         }, 0);
365                                 },
366                                 function( abspath){
367                                         if( abstractPath !== abspath) return;
368                                         onError && setTimeout( function(){
369                                                 onError( src);
370                                         }, 0);
371                                 }, delay, timeout
372                         );
373                         
374                 /*  LICENSE: MIT?
375                  *  URL: http://d.hatena.ne.jp/uupaa/20080413/1208067631
376                  *  AUTHOR: uupaa.js@gmail.com
377                  * 
378                  *  fixed for ie6-8 by h2c
379                  *   new Image -> document.createElement( 'IMG')
380                  */
381                         function loadImage( images, abspath, onLoad, onError, delay, timeout) {
382                                 images = images || document.images;
383                                 var img,
384                                         i = 0, l = images.length,
385                                         tick = 0;
386                                 for(; i < l; ++i) {
387                                         img = images[i];
388                                         if ( img.src === abspath && img.complete) {
389                                                 var size = h2c.util.getImageSize( img);
390                                                 onLoad( abspath, size.width, size.height);
391                                                 return;
392                                         }
393                                 }
394                                 img = document.createElement( 'IMG'); //var img = new Image(); ではieでimgのsizeが取れない、、、removeChildも失敗し、imgSizeGetterにimgが残る
395                                 img.finish = false;
396                                 img.onabort = img.onerror = function() {
397                                         if (img.finish) { return; }
398                                         img.finish = true;
399                                         onError(abspath);
400                                         img.onload = img.onabort = img.onerror = "";
401                                 };
402                                 img.onload  = function() {
403                                         img.finish = true;
404                                         if (window.opera && !img.complete) {
405                                                 onError(abspath);
406                                                 img.onload = img.onabort = img.onerror = "";
407                                                 return;
408                                         }
409                                         var size = h2c.util.getImageSize( img);
410                                         onLoad( abspath, size.width, size.height);
411                                         img.onload = img.onabort = img.onerror = "";
412                                         //img = void 0;
413                                 };
414                                 img.src = abspath;
415                                 if (!img.finish && timeout) {
416                                         setTimeout(function() {
417                                                 if (img.finish) { return; }
418                                                 if (img.complete) {
419                                                         img.finish = true;
420                                                         if (img.width) { return; }
421                                                         onError(abspath);
422                                                         img.onload = img.onabort = img.onerror = "";
423                                                         return;
424                                                 }
425                                                 if ((tick += delay) > timeout) {
426                                                         img.finish = true;
427                                                         onError(abspath);
428                                                         img.onload = img.onabort = img.onerror = "";
429                                                         return;
430                                                 }
431                                                 setTimeout(arguments.callee, delay);
432                                         }, 0);
433                                 }
434                         }
435                 },
436                 getAbsolutePath: function( path) {
437                         var e = document.createElement("div");
438                         e.innerHTML = '<a href=\"' + path + '\" />';
439                         return e.firstChild.href;
440                 }
441         }
442 })();
443
444 /*
445  * window resize event, overlay と currentなviewに流す
446  * view modeの保持
447  *       editor, overlay, comic-viewer, image-explorer
448  * fadeIn, faseOut
449  */
450 h2c.view = ( function(){
451         var jqWindow,
452                 funcArray,
453                 HOME_ID = 'home',
454                 currentView,
455                 elmCurrent,
456                 viewID = ( function(){
457                         var _viewID = h2c.URL_PARAMS.view || HOME_ID,
458                                 _elmView = document.getElementById( _viewID),
459                                 _elmHome = document.getElementById( HOME_ID);
460                         if( _elmView){
461                                 _elmHome.style.display = '';
462                                 _elmView.style.display = 'block';
463                                 elmCurrent = _elmView;
464                                 return _viewID;
465                         }
466                         elmCurrent = _elmHome;
467                         return HOME_ID;
468                 })();
469
470         function onWindowResize(){
471                 var _fn,
472                         l = funcArray.length,
473                         w = jqWindow.width(),
474                         h = jqWindow.height();
475                 for( var i=0; i<l; ++i){
476                         _fn = funcArray[ i];
477                         _fn.onWindowResize && _fn.onWindowResize( w, h);
478                 }
479         }
480         return {
481                 init: function( _funcArray){
482                         funcArray = _funcArray;
483                         jqWindow = h2c.jqWindow();
484                         jqWindow.resize( onWindowResize);
485                         
486                         setTimeout( onWindowResize, 100);
487                         
488                         delete h2c.view.init;
489                 },
490                 show: function( _view){
491                         for( var key in h2c){
492                                 if( h2c[ key] === _view){
493                                         var elm = document.getElementById( key);
494                                         if( currentView !== _view && elm){
495                                                 this.current = viewID = key;
496                                                 currentView = _view;
497                                                 elmCurrent.style.display = '';
498                                                 elm.style.display = 'block';
499                                                 elmCurrent = elm;
500                                         }
501                                         return;
502                                 }
503                         }
504                         alert( 'fault!!');
505                 },
506                 current: viewID
507         }
508 })();
509
510 h2c.view.HOME = 'home'; //
511 h2c.view.COMICS = 'comic-list';
512 h2c.view.IMAGES = 'image-list';
513 h2c.view.SETTING = 'setting';
514 h2c.view.EDITOR = 'editor'; // edit mode
515
516 h2c.overlay = ( function(){
517         var SHADOW_OPACITY = 0.5,
518                 jqBody, jqConteiner, jqShadow, jqCloseButton,
519                 currentOverlay = null,
520                 visible = false;
521         return {
522                 init: function(){
523                         jqBody = h2c.jqBody();
524                         jqConteiner = $( '#overlay-container');
525                         jqShadow = $( '#overlay-shadow');
526                         jqCloseButton = $( '#overlay-close-button').click( function( e){
527                                 currentOverlay && currentOverlay.onClose && currentOverlay.onClose();
528                                 h2c.overlay.hide();
529                                 return false;
530                         });
531                         
532                         delete h2c.overlay.init;
533                 },
534                 show: function( _currentOverlay){
535                         if( visible === true && currentOverlay === _currentOverlay) return;
536                         jqConteiner.stop().css( {
537                                 filter:         '',
538                                 opacity:        ''
539                         }).fadeIn();
540                         visible = true;
541                         currentOverlay = _currentOverlay;
542                         jqCloseButton.toggle( !!_currentOverlay.onClose);
543                 },
544                 hide: function(){
545                         currentOverlay = null;
546                         if( visible === false) return;
547                         jqConteiner.stop().css( {
548                                 filter:         '',
549                                 opacity:        ''
550                         }).fadeOut();
551                         visible = false;
552                 },
553                 onWindowResize: function( _windowW, _windowH){
554                         jqConteiner.css( { height:      _windowH});
555                         jqShadow.css( { height: _windowH});
556                         currentOverlay && currentOverlay.onWindowResize && setTimeout( function(){ // 先にeditorのcanvasを確定する。
557                                 currentOverlay.onWindowResize( _windowW, _windowH);
558                         }, 0);
559                 }
560         }
561 })();
562
563 /* ----------------------------------------
564  * KEY
565  * 
566  *  - EDITABLE_TEXT_CONTROL
567  *    - EDITABLE_TEXT_CLASS
568  *      .update: function,
569  *      .show: function,
570  *      .hide: function,
571  *      .start: function,
572  *      .finish: finish,
573  *      .enabled: function,
574  *      .index: function,
575  *      .instance: function
576  * 
577  *    .SHIFT_DOWN_EVENT:        'shiftDown',
578  *    .SHIFT_UP_EVENT:          'shiftUp',
579  *    .CTRL_DOWN_EVENT:         'ctrlDown',
580  *    .CTRL_UP_EVENT:           'ctrlUp',
581  *    .SPACE_DOWN_EVENT:        'spaceDown',
582  *    .SPACE_UP_EVENT:          'spaceUp',
583  *    .init:                            function,
584  *    .addKeyEvent:                     function,
585  *    .keyEventDispatcher:      function,
586  *    .createEditableText:      function,
587  * 
588  * ショートカットキーの監視とテキスト入力(input, textarea)を管理する。
589  * キー入力はdocumentで受けて、テキスト編集中(input, textarea)はそちらにキーイベント流す。
590  * 
591  */
592 h2c.key = ( function(){
593         var log,
594                 jqWindow,
595                 keyOperationChatcher,
596                 KEYEVENT_ARRAY = [],
597                 shiftEnabled = false,
598                 ctrlEnabled = false;
599                 spaceEnabled = false;
600         
601         var EDITABLE_TEXT_CONTROL = ( function(){
602                 var     EDITABLE_TEXT_TABLE = {},
603                         currentText = null;
604
605                 var EDITABLE_TEXT_CLASS = function( WRAPPER_ELM, ON_UPDATE_FUNCTION, GROUP_ID){
606                         var ELM = WRAPPER_ELM.children( '.editable-value').eq( 0),
607                                 value = ELM.html(),
608                                 jqInput,
609                                 index = EDITABLE_TEXT_TABLE[ GROUP_ID].length,
610                                 instance,
611                                 enabled = true,
612                                 A = $( '<a href="#" onclick="return false;"></a>').html( value).click( function(e){
613                                         instance = instance || EDITABLE_TEXT_TABLE[ GROUP_ID][ index];
614                                         EDITABLE_TEXT_CONTROL.start( instance);                                                         
615                                         A.hide();
616                                         jqInput = $( '<input type="text"/>').val( value)//.keydown( finish).keypress( finish);
617                                         ELM.append( jqInput);
618                                         jqInput.focus().select();
619                                 });
620                         ELM.addClass( 'editable-text').html( A);
621                         
622                         function finish(e){
623                                 if(e){
624                                         var keyCode = e.keyCode;
625                                         if( keyCode === 13 || keyCode === 27 || keyCode === 9 || keyCode === 18 || e.altKey === true){ // 13.return 27.esc 9.tab 18.alt
626                                                 _finish( keyCode !== 27 ? jqInput.val() : value);
627                                                 keyCode === 9 && GROUP_ID && EDITABLE_TEXT_CONTROL.tabShift( GROUP_ID, index, e.shiftKey === true ? -1 : 1);
628                                         }
629                                 } else {
630                                         _finish( jqInput.val());
631                                 }
632                                 function _finish( VALUE_NEW){
633                                         value = VALUE_NEW;
634                                         A.html( VALUE_NEW).show();
635                                         jqInput.remove();
636                                         jqInput = null;
637                                         ON_UPDATE_FUNCTION && VALUE_NEW !== value && ON_UPDATE_FUNCTION( VALUE_NEW, value);
638                                         EDITABLE_TEXT_CONTROL.finish( instance);
639                                 }
640                         }
641                         return {
642                                 update: function( _value){
643                                         value = _value !== undefined ? _value : value;
644                                         A.html( value);
645                                         jqInput && jqInput.val( value);
646                                         currentText === instance && finish();
647                                 },
648                                 show: function(){
649                                         enabled === false && WRAPPER_ELM.show();
650                                         enabled= true;
651                                 },
652                                 hide: function(){
653                                         enabled === true && WRAPPER_ELM.hide();
654                                         enabled = false;
655                                 },
656                                 start: function(){
657                                         !jqInput && A.click();
658                                 },
659                                 finish: finish,
660                                 enabled: function(){
661                                         return enabled;
662                                 }
663                         }
664                 }
665                 
666                 return {
667                         create: function( ELM, ON_UPDATE_FUNCTION, GROUP_ID){
668                                 if( GROUP_ID && !EDITABLE_TEXT_TABLE[ GROUP_ID]) EDITABLE_TEXT_TABLE[ GROUP_ID] = [];
669                                 var ret = EDITABLE_TEXT_CLASS.apply( {}, [ ELM, ON_UPDATE_FUNCTION, GROUP_ID])
670                                 GROUP_ID && EDITABLE_TEXT_TABLE[ GROUP_ID].push( ret);
671                                 return ret;
672                         },
673                         start: function( _currentText){
674                                 currentText !== _currentText && currentText && currentText.finish();
675                                 currentText = _currentText;
676                         },
677                         finish: function( _currentText){
678                                 if( currentText !== _currentText) return;
679                                 currentText = null 
680                         },
681                         keyEventRellay: function( e){
682                                 currentText && currentText.finish( e);
683                                 return !!currentText;
684                         },
685                         tabShift: function( _groupID, _index, _way){
686                                 var GROUP_ARRAY = EDITABLE_TEXT_TABLE[ _groupID] || [],
687                                         l = GROUP_ARRAY.length,
688                                         i = _index +_way;
689                                 if( l < 2) return;
690                                 while( i !== _index){
691                                         i = i < 0 ?
692                                                 l -1 :
693                                                 i === l ? 0 : i; // 0 < i < l
694                                         if( GROUP_ARRAY[ i].enabled() === true) break;
695                                         i += _way;
696                                 }
697                                 if( i === _index) return;
698                                 setTimeout( function(){ GROUP_ARRAY[ i].start();}, 0);
699                         }
700                 }
701         })();
702         
703         function keyHit( e){
704                 log.html( [ e.keyCode, e.shiftKey, e.ctrlKey, e.altKey].join( ','));
705                 //keyOperationChatcher.val( '');
706                 var cancel = false,
707                         key = e.keyCode;
708                 if( EDITABLE_TEXT_CONTROL.keyEventRellay( e) === false){
709                         if( key === 16 || e.shiftKey === true){
710                                 keyOperationChatcher.trigger( h2c.key.SHIFT_DOWN_EVENT);
711                                 shiftEnabled = true;
712                         }
713                         if( key === 17 || e.ctrlKey === true){
714                                 keyOperationChatcher.trigger( h2c.key.CTRL_DOWN_EVENT);
715                                 ctrlEnabled = true;
716                         }
717                         if( key === 32){
718                                 keyOperationChatcher.trigger( h2c.key.SPACE_DOWN_EVENT);
719                                 spaceEnabled = true;
720                         }
721                         
722                         var l = KEYEVENT_ARRAY.length,
723                                 d;
724                         for( var i=0; i<l; i++){
725                                 d = KEYEVENT_ARRAY[ i];
726                                 if( d.keyCode === key && d.shift === e.shiftKey && d.ctrl === e.ctrlKey){
727                                         setTimeout( d.callback, 0);
728                                         cancel = true;
729                                 }
730                         }                               
731                 }
732                 if( key === 13 ||key === 18 || key === 9 || key === 27 || e.altKey === true || cancel === true){ // 13.enter 18.esc 9.tab 27.esc
733                         e.preventDefault();
734                 e.keyCode = 0;
735                 e.cancelBubble = true;
736                 e.returnValue = false;
737                         return false;
738                 }
739         }
740
741         return {
742                 SHIFT_DOWN_EVENT:       'shiftDown',
743                 SHIFT_UP_EVENT:         'shiftUp',
744                 CTRL_DOWN_EVENT:        'ctrlDown',
745                 CTRL_UP_EVENT:          'ctrlUp',
746                 SPACE_DOWN_EVENT:       'spaceDown',
747                 SPACE_UP_EVENT:         'spaceUp',
748                 init: function(){
749                         log = $( '#key-event-log').html( 'ready');
750
751                         jqWindow = h2c.jqWindow().focus();
752                         keyOperationChatcher = h2c.jqDocument()
753                                 .keydown( keyHit)
754                                 .keyup( function( e){
755                                         log.html( '-' +e.altKey);
756                                         var key = e.keyCode;
757                                         if( key === 16 || e.shiftKey === true){
758                                                 keyOperationChatcher.trigger( h2c.key.SHIFT_UP_EVENT);
759                                                 shiftEnabled = false;
760                                         }
761                                         if( key === 17 || e.ctrlKey === true){
762                                                 keyOperationChatcher.trigger( h2c.key.CTRL_UP_EVENT);
763                                                 ctrlEnabled = false;
764                                         }
765                                         if( key === 32){
766                                                 keyOperationChatcher.trigger( h2c.key.SPACE_UP_EVENT);
767                                                 spaceEnabled = false;
768                                         }
769                                         e.preventDefault();
770                                 e.keyCode = 0;
771                                 e.cancelBubble = true;
772                                 e.returnValue = false;
773                                         return false;
774                                 }).mouseenter( function(){
775                                         jqWindow.focus();
776                                 });
777                         h2c.isIE === true && h2c.ieRenderingVersion < 8 && keyOperationChatcher.keypress( function( e){
778                                 var key = e.keyCode;
779                                 if( key === 13 || key === 27){
780                                         keyHit( e);
781                                         return false;
782                                 }
783                         });
784
785                         delete h2c.key.init;
786                 },
787                 addKeyEvent: function( _keyCode, _shift, _ctrl, _callbackFunction){
788                         KEYEVENT_ARRAY.push( {
789                                 keyCode:                _keyCode,
790                                 shift:                  _shift,
791                                 ctrl:                   _ctrl,
792                                 callback:               _callbackFunction
793                         });
794                 },
795                 addCursorEvent: function( _shift, _ctrl, _callbackFunction){
796                         
797                 },
798                 keyEventDispatcher: function(){
799                         return keyOperationChatcher;
800                 },
801                 createEditableText: EDITABLE_TEXT_CONTROL.create,
802                 shiftEnabled: function(){
803                         return shiftEnabled;
804                 },
805                 ctrlEnabled: function(){
806                         return ctrlEnabled;
807                 },
808                 spaceEnabled: function(){
809                         return spaceEnabled;
810                 }
811         }
812 })();
813
814 /* ----------------------------------------
815  * Vector Support
816  * 
817  *              __________
818  *             /          \
819  *            /            \
820  *            |,startX,Y    |
821  * tailX,Y - <              |
822  *            |'endX,Y      |
823  *            \            /
824  *                 \__________/
825  * 
826  * SVG
827  * -----------------------
828  * ie9, other modern browser
829  * 
830  * XML
831  * -----------------------
832  * ie5.5-8
833  * 
834  * 内部の角度計算は radian で統一したい。
835  * 当初 vectorEnabled = true で一度書いてみる。
836  * 駄目なら、代替のイメージのsrcの用意もここで担当。
837  * 閲覧と編集両方で使う。
838  * 
839  */
840 h2c.balloon = ( function() {
841         var MIN_BALLOON_WIDTH = 30,
842                 MIN_BALLOON_HEIGHT = 30,
843                 TAIL_WIDTH = 6,
844                 TAIL_HEIGHT = 10,
845                 STROKE_WIDTH = 1.2,
846                 PADDING_TOP = TAIL_HEIGHT,
847                 PADDING_LEFT = TAIL_HEIGHT,
848                 ACCURACY = 1, // 有効少数桁        
849                 IS_VML = h2c.isIE === true && h2c.ieVersion < 9,
850                 ELM_BALLOON_ORIGIN = ( function(){
851                         var ret;
852                         try {
853                                 if( IS_VML === true){
854                                         ret = document.createElement( 'DIV');
855                                         var shape = document.createElement( 'v:shape');
856                                         shape.coordorigin = "0,0";
857                                         shape.strokecolor = "black";
858                                         shape.strokeweight = STROKE_WIDTH;
859                                         shape.fillcolor = "white";
860                                         ret.appendChild( shape);
861                                 } else {
862                                         var kSVGNS = 'http://www.w3.org/2000/svg';
863                                         ret = document.createElementNS( kSVGNS, 'svg');
864                                         var path = document.createElementNS( kSVGNS, 'path');
865                                         path.setAttribute( 'fill', "white");
866                                         path.setAttribute( 'stroke', "black");
867                                         path.setAttribute( 'strokeWidth', STROKE_WIDTH);
868                                         ret.appendChild( path);
869                                 }
870                                 return ret;     
871                         } catch( e){
872                                 return null;
873                         }
874                 })(),
875                 vectorEnabled = ELM_BALLOON_ORIGIN !== null;
876
877         var XBROWSER_BALLOON_CLASS = function( w, h, a){
878                 var balloonElm = vectorEnabled === true ? ELM_BALLOON_ORIGIN.cloneNode( true) : document.createElement( 'IMG'), // h2c.imageに変更
879                         PI = Math.PI, cos = Math.cos, sin = Math.sin,
880                         abs = Math.abs, pow = Math.pow;
881                 
882                 draw( a, w, h);
883                 
884                 function draw( _a, _w, _h){
885                         a = _a !== undefined ? _a : a;
886                         w = _w ? _w -PADDING_TOP *2 : w;
887                         h = _h ? _h -PADDING_LEFT *2 : h;
888
889                         if( vectorEnabled === false){
890                                 balloonElm.setAttribute( 'src', balloonUrlBuilder( a));
891                                 return;
892                         }
893                         
894                         var rx = w /2,
895                                 ry = h /2,
896                                 tailRad = a * PI / 180,
897                                 tailX = rx +( rx +TAIL_HEIGHT) * cos( tailRad),
898                                 tailY = ry +( ry +TAIL_HEIGHT) * sin( tailRad),
899                                 startX, startY, endX, endY;
900                 /*
901                  * tailの太さをTAIL_WIDTHに一致させるため、角度を絞りつつ計算
902                  */
903                         ( function( a, rx, ry, sin, cos, pow){
904                                 var startRad, endRad,
905                                         _startX, _startY, _endX, _endY,
906                                         tailDeg = 0, d,
907                                         TARGET = TAIL_WIDTH * TAIL_WIDTH,
908                                         DEG_TO_RAD = PI / 180;
909                                 
910                                 for( var i = 45; i > 0.01; i /= 2){
911                                         d = ( tailDeg +i) /2;
912                                         startRad = ( a +d) * DEG_TO_RAD;
913                                         endRad = ( a -d) * DEG_TO_RAD;
914                                         
915                                         _startX = rx +cos( startRad) *rx;
916                                         _startY = ry +sin( startRad) *ry;
917                                         _endX = rx +cos( endRad) *rx;
918                                         _endY = ry +sin( endRad) *ry;   //円弧上のY位置=円中心Y+sin(角度×PI÷180)×円半径
919                                                 
920                                         if( pow( ( _startX -_endX), 2) + pow( ( _startY -_endY), 2) < TARGET){
921                                                 tailDeg += i;
922                                                 startX = _startX;
923                                                 startY = _startY;
924                                                 endX = _endX;
925                                                 endY = _endY;                                           
926                                         }
927                                 }                               
928                         })( a, rx, ry, sin, cos, pow);
929
930                 /*
931                  * 
932                  */                     
933                         IS_VML === true ?
934                         ( function ( tailX, tailY, startX, startY, rx, ry, endX, endY, _w, _h){
935                                 var l = ',',
936                                         round = Math.round,
937                                         shape = balloonElm.getElementsByTagName( 'shape')[ 0];
938                                 
939                                 shape.style.width = w +'px';
940                                 shape.style.height = h +'px';
941                                 shape.coordsize = [ _w, _h].join( l);
942                                 shape.path = [
943                                         ' ar ', 0, l, 0, l, _w, l, _h, l,
944                                         round( startX), l, round( startY), l,
945                                         round( endX), l, round( endY),
946                                         ' l ', round( tailX), l, round( tailY),
947                                         ' x e'
948                                 ].join( '');
949
950                                 balloonElm.style.marginTop =  tailY < 0 ? Math.floor( ( 60 +tailY) /10) : 10;
951                                 balloonElm.style.marginLeft = tailX < 0 ? Math.floor( ( 60 +tailX) /10) : 10;
952                                 
953                         })( tailX *10, tailY *10, endX *10, endY *10, rx *10, ry *10, startX *10, startY *10, w *10, h *10)
954                         :
955                         ( function (){
956                                 var l = ',',
957                                         path = balloonElm.getElementsByTagName( 'path')[ 0];
958                                 
959                                 balloonElm.setAttribute( 'width', w +PADDING_LEFT *2);
960                                 balloonElm.setAttribute( 'height', h +PADDING_TOP *2);
961                                 path.setAttribute( 'd', [
962                                         'M', cround( tailX + PADDING_LEFT), l, cround( tailY +PADDING_TOP),
963                                         'L', cround( startX +PADDING_LEFT), l, cround( startY +PADDING_TOP),
964                                         'A', rx, l, ry,
965                                         '0 1 1',                        // flag
966                                         cround( endX +PADDING_LEFT), l, cround( endY +PADDING_TOP),
967                                         'z'
968                                 ].join( ' '));
969                                 
970                                 function cround( v, r){
971                                         r = r || ACCURACY;
972                                         return Math.round( v *pow( 10.0, r)) /pow( 10.0, r);
973                                 }                       
974                         })();
975                 }
976                 
977                 function balloonUrlBuilder( _a){
978                         return 'url'//
979                 }
980                 return {
981                         elm: balloonElm,
982                         resize: draw,
983                         angle: function( _a){
984                                 if( _a && _a !== a){
985                                         draw( _a);
986                                 }
987                         },
988                         type: function( _type){
989                                 //draw( _a);
990                         },
991                         destroy: function(){
992                                 balloonElm.parentNode.removeChild( balloonElm);
993                                 balloonElm = null;
994                                 delete this.destroy;
995                         }
996                 }
997         };
998         
999         vectorEnabled === true && ( function(){
1000                 var detect = XBROWSER_BALLOON_CLASS.apply( {}, [ 100, 100, 0]),
1001                         size = h2c.util.getElementSize( detect.elm);
1002                 vectorEnabled = size.width !== 0 && size.height !== 0;
1003                 detect.destroy();
1004                 detect = size = null;   
1005         })();
1006
1007         return {
1008                 init: function(){
1009                         delete h2c.balloon.init;
1010                 },
1011             enabled: function() {
1012                 return vectorEnabled;
1013             },
1014                 VML: IS_VML === true && vectorEnabled === true,
1015             createBalloon: function( _w, _h, _a){
1016                 return XBROWSER_BALLOON_CLASS.apply( {}, [ _w, _h, _a]);
1017             },
1018                 TYPE_NONE:                              0,
1019                 TYPE_SPEACH_BALLOON:    1,
1020                 TYPE_THINKING:                  2,
1021                 TYPE_BOM:                               3,
1022                 TYPE_BLACK_BOX:                 4,
1023                 TYPE_BLUE_BOX:                  5
1024         }
1025 })();
1026
1027 /* ----------------------------------------
1028  *  h2c.image
1029  *  
1030  *   xBackendな画像反転、画像描画機能。
1031  *   
1032  *   画像の反転
1033  *     - css3
1034  *     - ActiveX (ie)
1035  *     - VML (ie)
1036  *     - canvas ??
1037  *     - flash(lite)
1038  *     - silverlight
1039  *     - pettan server
1040  *   
1041  *   png画像の表示(アルファpngをサポートしないie6以下のため)
1042  *     - ActiveX
1043  *     - VML
1044  *     - flash(lite)
1045  *     - silverlight
1046  *     
1047  *     -moz-transform:scale( -1, -1);
1048  */
1049 h2c.image = ( function(){
1050         var REG_PNG = /\.png?/i,
1051                 IS_CSS3 = 0,
1052                 IS_VML = 1,
1053                 IS_ACTIVEX = 2,
1054                 IS_CANVAS = 3,
1055                 IS_FLASH = 4,
1056                 IS_SILVERLIGHT = 5,
1057                 IS_SERVER = 6,
1058                 IS_ACTIVEX_SERVER = 7,
1059                 BACKEND = ( function(){
1060                         if( h2c.DEBUG === true && h2c.URL_PARAMS.rimg){
1061                                 var rimg = h2c.URL_PARAMS.rimg.toLowerCase();
1062                                 if( rimg === 'css3') return IS_CSS3;
1063                                 if( rimg === 'activex') return IS_ACTIVEX;
1064                                 if( rimg === 'vml') return IS_VML;
1065                         }
1066                         if( h2c.isIE === false || h2c.ieVersion >= 9) return IS_CSS3; // 不十分!
1067                         if( h2c.balloon.VML === true) return IS_VML;
1068                         if( h2c.ACTIVEX === true) return IS_ACTIVEX;
1069                         if( h2c.FLASH === true) return IS_FLASH;
1070                         if( h2c.SILVERLIGHT === true) return IS_SILVERLIGHT;
1071                         return IS_SERVER;
1072                 })(),
1073                 PNG_FIX = h2c.isIE === true && h2c.ieVersion <= 6,
1074                 BACKEND_WHEN_PNG = PNG_FIX === false ? BACKEND : ( function(){
1075                         if( h2c.balloon.VML === true) return IS_VML;
1076                         if( h2c.FLASH === true) return IS_FLASH;
1077                         if( h2c.SILVERLIGHT === true) return IS_SILVERLIGHT;
1078                         if( h2c.ACTIVEX === true) return IS_ACTIVEX_SERVER;
1079                         return IS_SERVER;
1080                 })();
1081         
1082         var XBackendReversibleImageClass = ( function(){
1083                 var CLASS_NAME = 'reversible-image-container',
1084                         CLASS_NAME_LOADING = CLASS_NAME + ' loading',
1085                         CLASS_NAME_ERROR = CLASS_NAME +' error',
1086                         RETRY_DELAY = 5000;
1087                         NUM_RETRY = 3;
1088                 
1089                 var css3Image = function( url, w, h, onLoadCallback){
1090                         var elmWrap = document.createElement( 'div'),
1091                                 elmImg,
1092                                 loaded = false,
1093                                 retryTimer = null;
1094                         elmWrap.className = CLASS_NAME_LOADING;
1095                         h2c.util.loadImage( url, onLoad, onError, 100, 10000);
1096                         function onLoad( _url, _actualW, _actualH){
1097                                 if( elmWrap === null) return;
1098                                 elmImg = new Image;
1099                                 elmImg.src = url;
1100                                 elmWrap.appendChild( elmImg); // load後にimg
1101                                 elmWrap.className = CLASS_NAME;
1102                                 onLoadCallback && onLoadCallback( _url, _actualW, _actualH);
1103                                 onLoadCallback = null;
1104                                 loaded = true;
1105                                 resize( w, h);
1106                         }
1107                         function onError( _url){
1108                                 if( elmWrap === null) return;
1109                                 elmWrap.className = CLASS_NAME_ERROR;
1110                                 retryTimer = setTimeout( function(){
1111                                         elmWrap.className = CLASS_NAME_LOADING;
1112                                         h2c.util.loadImage( url, onLoad, onError, 100, 10000);
1113                                 }, RETRY_DELAY);
1114                         }
1115                         function resize( _w, _h){
1116                                 w = _w !== undefined ? _w : w;
1117                                 h = _h !== undefined ? _h : h;
1118                                 if( loaded === false) return;
1119                                 elmImg.className = w < 0 || h < 0 ? ( 'img-flip-' + ( w < 0 && h < 0 ? 'vh' : ( w < 0 ? 'v' : 'h'))) : '';
1120                         }
1121                         return {
1122                                 elm : elmWrap,
1123                                 resize: resize,
1124                                 destroy: function(){
1125                                         loaded === true && elmWrap.removeChild( elmImg);
1126                                         retryTimer !== null && clearTimeout( retryTimer);
1127                                         elmWrap = vmlImg = onLoadCallback = retryTimer = null;
1128                                         elmWrap = elmImg = onLoadCallback = null;
1129                                         delete this.destroy;
1130                                 }
1131                         }
1132                 }
1133                 var activexImage = css3Image;
1134                 var vmlImage = function( url, w, h, onLoadCallback){
1135                         var elmWrap = document.createElement( 'div'),
1136                                 vmlImg,
1137                                 loaded = false,
1138                                 retryTimer = null;
1139                         elmWrap.className = CLASS_NAME_LOADING;
1140                         h2c.util.loadImage( url, onLoad, onError, 100, 10000);
1141                         function onLoad( _url, _actualW, _actualH){
1142                                 if( elmWrap === null) return;
1143                                 elmWrap.className = CLASS_NAME;
1144                                 vmlImg = document.createElement( 'v:image');
1145                                 vmlImg.src = url;
1146                                 loaded = true;
1147                                 resize( w, h);
1148                                 onLoadCallback && onLoadCallback( _url, _actualW, _actualH);
1149                                 onLoadCallback = null;
1150                         }
1151                         function onError( _url){
1152                                 if( elmWrap === null) return;
1153                                 elmWrap.className = CLASS_NAME_ERROR;
1154                                 retryTimer = setTimeout( function(){
1155                                         elmWrap.className = CLASS_NAME_LOADING;
1156                                         h2c.util.loadImage( url, onLoad, onError, 100, 10000);
1157                                 }, RETRY_DELAY);
1158                         }
1159                         function resize( _w, _h){
1160                                 w = _w !== undefined ? _w : w;
1161                                 h = _h !== undefined ? _h : h;
1162                                 if( loaded !== true) return;
1163                                 vmlImg.style.width = w < 0 ? -w : w +'px';
1164                                 vmlImg.style.height = h < 0 ? -h : h +'px';
1165                                 //if( flipH !== _flipH || flipV !== _flipV){
1166                                         vmlImg.parentNode === elmWrap && elmWrap.removeChild( vmlImg);
1167                                 //}
1168                                         vmlImg.className = w < 0 || h < 0 ? ( 'img-flip-' + ( w < 0 && h < 0 ? 'vh' : ( w < 0 ? 'v' : 'h'))) : '';
1169                                         elmWrap.appendChild( vmlImg);
1170                         }
1171                         return {
1172                                 elm : elmWrap,
1173                                 resize: resize,
1174                                 destroy: function(){
1175                                         loaded === true && elmWrap.removeChild( vmlImg);
1176                                         retryTimer !== null && clearTimeout( retryTimer);
1177                                         elmWrap = vmlImg = onLoadCallback = retryTimer = null;
1178                                         delete this.destroy;
1179                                 }
1180                         }
1181                 }
1182                 var serverImage = function( url, w, h, onLoadCallback){
1183                         
1184                 }
1185                 
1186                 return function( url, w, h, onLoadCallback){
1187                                 var flipH = w < 0,
1188                                         flipV = h < 0,
1189                                         onLoadCallbackAsync = onLoadCallback,// ? function(){ setTimeout( onLoadCallback, 0);} : undefined,// 一度読み込んだ画像は即座にonLoadになるため遅延
1190                                         xBackendImage = ( function( urlIsXDomain){
1191                                                 if( BACKEND === IS_CSS3) return css3Image.apply( {}, [ url, w, h, onLoadCallbackAsync]);
1192                                                 if( BACKEND === IS_VML) return vmlImage.apply( {}, [ url, w, h, onLoadCallbackAsync]);
1193                                                 if( BACKEND === IS_ACTIVEX) return activexImage.apply( {}, [ url, w, h, onLoadCallbackAsync]);
1194                                                 return serverImage.apply( {}, [ url, w, h, onLoadCallbackAsync]);
1195                                         })();
1196                                 return {
1197                                         elm: xBackendImage.elm,
1198                                         w: function( _w){
1199                                                 _w !== undefined && xBackendImage.resize( _w, h);
1200                                                 return w;
1201                                         },
1202                                         h: function( _h){
1203                                                 _h !== undefined && xBackendImage.resize( w, _h);
1204                                                 return h;
1205                                         },
1206                                         resize: xBackendImage.resize,
1207                                         destroy: function(){
1208                                                 xBackendImage.destroy && xBackendImage.destroy();
1209                                                 xBackendImage = onLoadCallback = onLoadCallbackAsync = null;
1210                                                 delete this.destroy;
1211                                         }
1212                                 }
1213                         }
1214         })();
1215         return {
1216                 init: function(){
1217                         
1218                 },
1219                 createReversibleImage: function( url, w, h, onLoadCallback){
1220                         return XBackendReversibleImageClass.apply( {}, [ url, w, h, onLoadCallback]);
1221                 }
1222         }
1223 })();
1224
1225 /* ----------------------------------------
1226  *   h2c.editor
1227  *    - HISTORY
1228  *    - WINDOW_CONTROL
1229  *       - WINDOW_CLASS
1230  *    - INFOMATION_WINDOW
1231  *    - TOOL_BOX_WINDOW
1232  *    - CANVAS_CONTROL
1233  *       - GRID_CONTROL
1234  *       - WHITE_GLASS_CONTROL
1235  *       - PANEL_BORDER_CONTROL
1236  *       - COMIC_ELEMENT_CONTROL
1237  *          - PanelResizerClass
1238  *          - COMIC_ELEMENT_OPERATOR
1239  *             - TAIL_MOVER
1240  *          - ImageElementClass
1241  *          - TextElementClass
1242  * 
1243  */
1244 h2c.editor = ( function(){
1245         var COMIC_ELEMENT_TYPE_IMAGE = 0,
1246                 COMIC_ELEMENT_TYPE_TEXT = 1,
1247                 MOUSE_LISTENER_ARRAY = [],
1248                 currentListener = null,
1249                 ELM_MOUSE_EVENT_CHATCHER = document.getElementById( 'mouse-operation-catcher'),
1250                 jqMouseEventChacher,
1251                 jqEditor,
1252                 windowW, windowH,
1253                 currentCursor = '';
1254
1255 /* ----------------------------------------
1256  * MENU BAR
1257  * div
1258  *   div.title
1259  *   ul
1260  *     li
1261  *        a
1262  *          span
1263  *          kbd shortcut
1264  *     li.separator
1265  */
1266         var MENU_BAR_CONTROL = ( function(){
1267                 var BAR_ID = 'menu-bar',
1268                         ELM_BAR = document.getElementById( BAR_ID),
1269                         ELM_ITEM_CLASSNAME = 'menu-bar-item',
1270                         ELM_ITEM_ORIGN = ( function(){
1271                                 var ret = document.createElement( 'DIV'),
1272                                         div = document.createElement( 'DIV'),
1273                                         ul = document.createElement( 'UL');
1274                                 ret.className = ELM_ITEM_CLASSNAME;
1275                                 ret.appendChild( div);
1276                                 ret.appendChild( ul);
1277                                 return ret;
1278                         })(),
1279                         ELM_SELECTION_ORIGN = ( function(){
1280                                 var ret = document.createElement( 'LI'),
1281                                         a = document.createElement( 'A'),
1282                                         span = document.createElement( 'SPAN'),
1283                                         key = document.createElement( 'KBD');
1284                                 a.href = '#';
1285                                 a.appendChild( span);
1286                                 a.appendChild( key);
1287                                 ret.appendChild( a);
1288                                 return ret;
1289                         })(),
1290                         EMPTY_FUNCTION = new Function,
1291                         ITEM_ARRAY = [],
1292                         barH,
1293                         itemW = h2c.util.getElementSize( ELM_ITEM_ORIGN).width,
1294                         selectionW = h2c.util.getElementSize( ELM_ITEM_ORIGN.getElementsByTagName( 'UL')[ 0]).width,
1295                         jqStage, jqBar;
1296                 barH = h2c.util.getElementSize( ELM_BAR).height;
1297                 ELM_BAR.style.top = ( -barH) +'px';
1298
1299                 var MenuBarItemClass = function( title){
1300                         var ELM_WRAPPER = ELM_ITEM_ORIGN.cloneNode( true),
1301                                 ELM_TITLE = ELM_WRAPPER.getElementsByTagName( 'DIV')[ 0],
1302                                 ELM_SELECTION = ELM_WRAPPER.getElementsByTagName( 'UL')[ 0],
1303                                 INDEX = ITEM_ARRAY.length,
1304                                 SELECTION_CALLBACK_ARRAY = [],
1305                                 numSelection = 0,
1306                                 visible = false;
1307                         ELM_TITLE.innerHTML = title;
1308                         
1309                         ELM_WRAPPER.style.left = ( itemW * INDEX) +'px';
1310                         ELM_BAR.appendChild( ELM_WRAPPER);
1311                         
1312                         function onClick( e){
1313                                 var that = this,
1314                                         i = ( function(){
1315                                                 var parent = that.parentNode,
1316                                                         children = parent.getElementsByTagName( 'LI'),
1317                                                         l = children.length;
1318                                                 for(var i=0; i<l; ++i){
1319                                                         if( children[ i] === that) return i;
1320                                                 }
1321                                                 return -1;
1322                                         })();
1323                                 i !== -1 && this.className !== 'disabled' && SELECTION_CALLBACK_ARRAY[ i]();
1324                                 e.stopPropagation();
1325                                 return false;                           
1326                         }
1327                         return {
1328                                 init: function(){
1329                                         $( ELM_SELECTION).children( 'li').click( onClick);
1330                                         delete this.init;
1331                                 },
1332                                 show: function(){
1333                                         if( visible === true) return;
1334                                         jqStage.append( ELM_WRAPPER);
1335                                         ELM_WRAPPER.className = ELM_ITEM_CLASSNAME +'-focus';
1336                                         this.onShow && setTimeout( this.onShow, 0);
1337                                         visible = true;
1338                                 },
1339                                 hide: function(){
1340                                         if( visible === false) return;
1341                                         ELM_BAR.appendChild( ELM_WRAPPER);
1342                                         ELM_WRAPPER.className = ELM_ITEM_CLASSNAME;
1343                                         this.onHide && setTimeout( this.onHide, 0);
1344                                         visible = false;
1345                                 },
1346                                 createSelection: function( title, shortcut, callback, visible, separateBefore, separateAfter){
1347                                         var ret = MenubarSelectionClass.apply( {}, [ ELM_SELECTION, title, shortcut, visible, separateAfter]),
1348                                                 before = SELECTION_CALLBACK_ARRAY.length > 0 ? SELECTION_CALLBACK_ARRAY[ SELECTION_CALLBACK_ARRAY.length -1] : null;
1349                                         SELECTION_CALLBACK_ARRAY.push( callback);
1350                                         if( ( separateBefore === true && before) || ( before && before.separateAfter === true)){
1351                                                 ret.elm.style.borderTop = '1px solid #ccc';
1352                                         }
1353                                         return ret;
1354                                 },
1355                                 createAjaxSelection: function(){
1356                                         var elmLoading = document.createElement( 'li');
1357                                         elmLoading.className = 'loading';
1358                                         elmLoading.style.height = '90px';
1359                                         ELM_SELECTION.appendChild( elmLoading);
1360                                         
1361                                         delete this.createAjaxSelection;
1362                                         return function(){
1363                                                 SELECTION_CALLBACK_ARRAY.shift();
1364                                                 ELM_SELECTION.removeChild( elmLoading);
1365                                                 elmLoading = null;
1366                                                 $( ELM_SELECTION).children( 'li').click( onClick);
1367                                         }
1368                                 }
1369                         }
1370                 }
1371                 var MenubarSelectionClass = function( container, title, shortcut, visible, separateAfter){
1372                         var ELM_WRAPPER = ELM_SELECTION_ORIGN.cloneNode( true),
1373                                 ELM_TITLE = ELM_WRAPPER.getElementsByTagName( 'SPAN')[ 0];
1374                         updateTitle( title);
1375                         updateVisible( visible);
1376                         
1377                         ( function(){
1378                                 var ELM_SHORTCUT = ELM_WRAPPER.getElementsByTagName( 'KBD')[ 0];
1379                                 if( shortcut){
1380                                         ELM_SHORTCUT.innerHTML = shortcut;
1381                                 } else {
1382                                         ELM_SHORTCUT.parentNode.removeChild( ELM_SHORTCUT);
1383                                 }                               
1384                         })();
1385
1386                         container.appendChild( ELM_WRAPPER);
1387                         
1388                         function updateTitle( _title){
1389                                 ELM_TITLE.innerHTML = title = _title;
1390                         }
1391                         function updateVisible( _visible){
1392                                 _visible !== undefined && ( function(){
1393                                         visible = !!_visible;
1394                                         ELM_WRAPPER.className = visible === true ? '' : 'disabled';
1395                                 })();
1396                         }
1397                         return {
1398                                 elm: ELM_WRAPPER,
1399                                 title: function( _title){
1400                                         _title !== undefined && updateTitle( _title);
1401                                         return title;
1402                                 },
1403                                 visible: function( _visible){
1404                                         visible !== !!_visible && updateVisible( _visible);
1405                                         return visible;
1406                                 },
1407                                 separateAfter: separateAfter
1408                         }
1409                 }
1410                 
1411                 function createMenubarItem( title){
1412                         var _item = MenuBarItemClass.apply( {}, [ title]);
1413                         ITEM_ARRAY.push( _item);
1414                         return _item;
1415                 }
1416                 return {
1417                         init: function(){
1418                                 jqStage = jqEditor;
1419                                 jqBar = $( '#' +BAR_ID).animate( { top: 0});
1420
1421                                 var l = ITEM_ARRAY.length;
1422                                 for( var i=0; i<l; ++i){
1423                                         ITEM_ARRAY[ i].init();
1424                                 }
1425
1426                                 delete MENU_BAR_CONTROL.init;
1427                         },
1428                         onMouseMove: function( _mouseX, _mouseY){
1429                                 if( barH >= _mouseY){
1430                                         return true;
1431                                 }
1432                                 var l = ITEM_ARRAY.length;
1433                                 for( var i=0; i<l; ++i){
1434                                         ITEM_ARRAY[ i].hide();
1435                                 }
1436                                 return false;
1437                         },
1438                         onMouseUp: function( _mouseX, _mouseY){
1439                                 return false;
1440                         },
1441                         onMouseDown: function( _mouseX, _mouseY){
1442                                 var l = ITEM_ARRAY.length;
1443                                 if( barH < _mouseY || itemW * l < _mouseX) return false;
1444                                 for( var i=0; i<l; ++i){
1445                                         if( i * itemW <= _mouseX && _mouseX < ( i +1) * itemW){
1446                                                 ITEM_ARRAY[ i].show();
1447                                         } else {
1448                                                 ITEM_ARRAY[ i].hide();
1449                                         }
1450                                 }
1451                                 return true;
1452                         },
1453                         busy: function( _busy){
1454                                 return false;
1455                         },
1456                         onWindowResize: function( _windowW, _windowH){
1457                                 
1458                         },
1459                         QUIT: createMenubarItem( 'Quit'),
1460                         EDIT: createMenubarItem( 'Edit'),
1461                         WINDOW: createMenubarItem( 'Window'),
1462                         HELP: h2c.util.extend( createMenubarItem( 'Help'), {
1463                                 
1464                         }) // extend, onShow, ajaxselection, HELP_DOCUMENTS_CONTROL.load()
1465                 }
1466         })();
1467
1468
1469 /* ----------------------------------------
1470  * HISTORY
1471  */
1472         var HISTORY = ( function() {
1473                 var     STACK_BACK = [], STACK_FORWARD = [],
1474                         menubarBack, menubarForward,
1475                         log;
1476                         
1477                 h2c.key.addKeyEvent( 90, false, true, back);    // ctrl + Z
1478                 h2c.key.addKeyEvent( 90, true, true, forward);  // ctrl + Y
1479                 h2c.key.addKeyEvent( 89, false, true, forward); // ctrl + shift + Z
1480                 
1481                 menubarBack = MENU_BAR_CONTROL.EDIT.createSelection( 'back', 'ctrl + z', back, false);
1482                 menubarForward = MENU_BAR_CONTROL.EDIT.createSelection( 'forward', 'ctrl + y', back, false, false, true);
1483
1484                 function back(){
1485                         /*
1486                          * currentを控えてSTACK_FORWARD.push(current)
1487                          * STACK_BACK.pop()を実行してcurrentに
1488                          */
1489                         if( STACK_BACK.length === 0) return;
1490
1491                         var state = STACK_BACK.pop();
1492                         state && state.fn( state.argBack);
1493                         menubarBack.visible( STACK_BACK.length !== 0);
1494                         
1495                         STACK_FORWARD.push( state);
1496                         menubarForward.visible( true);
1497                 }
1498                 function forward(){
1499                         if( STACK_FORWARD.length === 0) return;
1500                         
1501                         var state = STACK_FORWARD.pop();
1502                         state.fn( state.argForword);
1503                         menubarForward.visible( STACK_FORWARD.length !== 0);
1504                         
1505                         STACK_BACK.push( state);
1506                         menubarBack.visible( true);
1507                 }
1508                 return {
1509                         init: function(){
1510                                 log = $( '#history-log');
1511                                 delete HISTORY.init;
1512                         },
1513                     saveState: function( _function, _argBack, _argForword, _destory) {
1514                         STACK_BACK.push( {
1515                                 fn:                     _function,
1516                                 argBack:        _argBack,
1517                                         argForword:     _argForword,
1518                                         destroy:        _destroy
1519                         });
1520                         menubarBack.visible( true);
1521                         
1522                         //log.html( 'save' +STACK_BACK.length + '-' +'-' +STACK_FORWARD.length)
1523                         while( STACK_FORWARD.length > 0){
1524                                         var _stack = STACK_FORWARD.shift(),
1525                                                 __argBack = _stack.argBack,
1526                                                 __argForword = _stack.argForword,
1527                                                 _destroy = _stack.destroy,
1528                                                 _value;
1529                                         _stack.fn = null;
1530                                         if( typeof __argBack === 'array'){
1531                                                 while( __argBack.length > 0){
1532                                                         _value = __argBack.shift();
1533                                                         _destroy === true && _value.destroy && _value.destroy();
1534                                                 }
1535                                         }
1536                                         if( typeof _argForword === 'array'){
1537                                                 while( __argForword.length > 0){
1538                                                         _value = __argForword.shift();
1539                                                         _destroy === true && _value.destroy && _value.destroy();
1540                                                 }                                               
1541                                         }
1542                                 }
1543                                 menubarForward.visible( false);
1544                     }           
1545                 }
1546         })();
1547
1548
1549 /* ----------------------------------------
1550  * HELP_DOCUMENTS_CONTROL
1551  *  * menubar の help 下に help documents の index を挿入
1552  *  * help window に  help documents を挿入
1553  */
1554         var HELP_DOCUMENTS_CONTROL = ( function(){
1555                 var onLoadFunction = MENU_BAR_CONTROL.HELP.createAjaxSelection();
1556                 return {
1557                         load: function(){
1558                                 // HELP_DOCUMENTS_WINDOW.setAjaxContent();
1559                                 var help = MENU_BAR_CONTROL.HELP;
1560                                 //help.createSelection();
1561                                 //onLoadFunction();
1562                         }
1563                 }
1564         })();
1565
1566
1567 /* ----------------------------------------
1568  * WINDOWS_CONTROL
1569  */     
1570         var WINDOWS_CONTROL = ( function(){
1571                 /*
1572                  *  表示上手前にあるwindowは、WINDOW_ARRAYの先頭にあり、htmlでは後ろにある。
1573                  */
1574                 var DEFAULT_MIN_WINDOW_WIDTH = 200,
1575                         DEFAULT_MIN_WINDOW_HEIGHT = 200,
1576                         WINDOW_ARRAY = [],
1577                         jqContainer,
1578                         currentWindow,
1579                         currentWindowIndex = -1,
1580                         log;
1581
1582                 var jqWindowOrigin,
1583                         windowCloseButtonWidth;
1584                 var WindowClass = function( bodyTempleteID, title, x, y, w, h, visible, CLOSE_BUTTON_ENABLED, RESIZE_BUTTON_ENABLED, minWindowW, minWindowH){
1585                         var MOUSE_CURSOR = updateMouseCursor,
1586                                 MENUBAR_SELWCTION = MENU_BAR_CONTROL.WINDOW.createSelection( 
1587                                         ( visible !== true ? 'show ' : 'hide ') +title,
1588                                         null,
1589                                         function(){
1590                                                 visible === true ? instance.close() : instance.open();
1591                                         }, true
1592                                 ),
1593                                 jqStage,
1594                                 jqWrapper, jqHeader, elmBody, elmBodyStyle,
1595                                 startX, startY, startW, startH,
1596                                 xOffset, yOffset,
1597                                 headerH, bodyH,
1598                                 isDragging = false,
1599                                 isResizing = false,
1600                                 bodyIsTachable = false,
1601                                 instance;
1602                         
1603                         function update( _x, _y, _w, _h){
1604                                 ( w !== _w || h !== _h) && instance.onResize && instance.onResize( _w, _h);
1605                                 x = _x || x;
1606                                 y = _y || y;
1607                                 w = _w || w;
1608                                 h = _h || h;
1609                                 jqWrapper.css( {
1610                                         left:           x,
1611                                         top:            y,
1612                                         width:          w,
1613                                         height:         h
1614                                 });
1615                                 bodyH = h -headerH;
1616                                 elmBodyStyle.height = bodyH +'px';
1617                         }
1618                         function bodyBackOrForward( isBack){
1619                                 if( bodyIsTachable === !isBack) return;
1620                                 elmBodyStyle.position = isBack === true ? 'relative' : 'absolute';
1621                                 elmBodyStyle.left =             isBack === true ? 0  : x +'px';
1622                                 elmBodyStyle.top =              isBack === true ? 0  : y +headerH +'px';
1623                                 elmBodyStyle.width =    isBack === true ? '' : w +'px';
1624                                 bodyIsTachable === isBack && isBack === true ? jqWrapper.append( elmBody) : jqStage.append( elmBody);
1625                                 bodyIsTachable = !isBack;
1626                         }
1627                         
1628                         return {
1629                                 setInstance: function(){
1630                                         instance = this;
1631                                         delete this.setInstance;
1632                                 },
1633                                 init: function( jqContainer){
1634                                         jqWindowOrigin = jqWindowOrigin || ( function(){
1635                                                 return $( $( '#windowTemplete').remove().html());
1636                                         })();
1637                                         windowCloseButtonWidth = windowCloseButtonWidth || ( function(){
1638                                                 return h2c.util.getElementSize( jqWindowOrigin.clone( true).find( '.window-close-button').get( 0)).width;
1639                                         })();
1640                                         
1641                                         
1642                                         jqStage = jqEditor;
1643                                         this.$ = jqWrapper = jqWindowOrigin.clone( true);
1644                                         jqHeader = jqWrapper.children( '.window-header').eq( 0).html( title);
1645                                         headerH = h2c.util.getElementSize( jqHeader.get( 0)).height;
1646                                         elmBody = jqWrapper.children( '.window-body').get( 0);
1647                                         elmBodyStyle = elmBody.style;
1648                                         if( bodyTempleteID) {
1649                                                 jqWrapper.find( '.window-body-insert-position').replaceWith( $( $( '#' +bodyTempleteID).remove().html()));
1650                                         } else {
1651                                                 jqWrapper.find( '.window-body-insert-position').remove();
1652                                         }
1653                                         CLOSE_BUTTON_ENABLED !== true && jqWrapper.find( '.window-close-button').remove();
1654                                         
1655                                         jqContainer.append( jqWrapper); // domに追加しないと、this.onInit()が正しく動かない.
1656                                         jqWrapper.fadeIn(); // appendした後に fadeIn() しないと ie で filterが適用されない.
1657                                         if( RESIZE_BUTTON_ENABLED === true){
1658                                                 jqWrapper.find( '.window-resize-button').eq( 0)
1659                                                         .mousedown( function( e){
1660                                                                 bodyBackOrForward( true);
1661                                                                 isResizing = true;
1662                                                                 startX = x;
1663                                                                 startY = y;
1664                                                                 startW = w;
1665                                                                 startH = h;
1666                                                                 xOffset = e.pageX;
1667                                                                 yOffset = e.pageY;
1668                                                                 MOUSE_CURSOR( 'nw-resize');
1669                                                                 e.stopPropagation();
1670                                                                 return false;
1671                                                         });
1672                                         } else {
1673                                                 jqWrapper.find( '.window-resize-button').remove();
1674                                         }
1675                                         update( x, y, w, h);
1676                                         this.onInit && this.onInit();
1677                                         delete this.init;
1678                                 },
1679                                 x: function(){ return x;},
1680                                 y: function(){ return y;},
1681                                 w: function(){ return w;},
1682                                 h: function(){ return h;},
1683                                 $: null,
1684                                 visible: visible,
1685                                 open: function(){
1686                                         if( visible === true) return;
1687                                         this.visible = visible = true;
1688                                         this.onOpen && setTimeout( this.onOpen, 0);
1689                                         openWindow( this);
1690                                         MENUBAR_SELWCTION.title( 'hide ' +title);
1691                                 },
1692                                 close: function(){
1693                                         if( visible === false) return;
1694                                         this.visible = visible = false;
1695                                         this.onClose && setTimeout( this.onClose, 0);
1696                                         closeWindow( this);
1697                                         MENUBAR_SELWCTION.title( 'show ' +title);
1698                                 },
1699                                 onMouseDown: function( _mouseX, _mouseY){
1700                                         if( x > _mouseX || y > _mouseY || x +w < _mouseX || y +headerH < _mouseY ) return;
1701                                         if( CLOSE_BUTTON_ENABLED === true && x +w -windowCloseButtonWidth < _mouseX){
1702                                                 this.close();
1703                                                 return;
1704                                         }
1705                                         isDragging = true;
1706                                         MOUSE_CURSOR( 'move');                          
1707                                         startX = x;
1708                                         startY = y;
1709                                         startW = w;
1710                                         startH = h;
1711                                         xOffset = _mouseX;
1712                                         yOffset = _mouseY;
1713                                 },
1714                                 onMouseUp: function( _mouseX, _mouseY){
1715                                         isDragging = isResizing = false;
1716                                         MOUSE_CURSOR( '');
1717                                 },
1718                                 onMouseMove: function( _mouseX, _mouseY){
1719                                         var _updateX = _mouseX -xOffset,
1720                                                 _updateY = _mouseY -yOffset;
1721                                         
1722                                         if( isResizing === true){
1723                                                 var _w = startW +_updateX,
1724                                                         _h = startH +_updateY;
1725                                                 update( startX, startY, _w < minWindowW ? minWindowW : _w, _h < minWindowH ? minWindowH : _h);
1726                                                 return;
1727                                         } else
1728                                         if( isDragging === true) {
1729                                                 update( startX +_updateX, startY +_updateY);
1730                                                 return;
1731                                         } else
1732                                         if( x > _mouseX || x +w < _mouseX ) return;
1733         
1734                                         ( y <= _mouseY && y +headerH >= _mouseY ) ?
1735                                                 MOUSE_CURSOR( 'pointer') :      // hit to header
1736                                                 MOUSE_CURSOR( '');
1737                                         bodyBackOrForward( y +headerH > _mouseY || y +headerH +bodyH < _mouseY);
1738                                 },
1739                                 onMouseOut: function( _mouseX, _mouseY){
1740                                         bodyIsTachable === true && bodyBackOrForward( true);
1741                                         isDragging = false;
1742                                         MOUSE_CURSOR( '');
1743                                 },
1744                                 busy: function(){
1745                                         return isDragging === true || isResizing === true;
1746                                 },
1747                                 bodyHeight: function(){
1748                                         return  bodyH;
1749                                 }
1750                         }
1751                 };
1752                 
1753                 function getCurrentWindow( _mouseX, _mouseY){
1754                         if( currentWindow && currentWindow.busy() === true) return currentWindowIndex;
1755                         var l = WINDOW_ARRAY.length,
1756                                 _currentWindow = null,
1757                                 _win, _x, _y;
1758                         currentWindowIndex = -1;
1759                         for( var i=0; i<l; i++){
1760                                 _win = WINDOW_ARRAY[ i];
1761                                 _x = _win.x();
1762                                 _y = _win.y();
1763                                 if( _x <= _mouseX && _y <= _mouseY && _x +_win.w() >= _mouseX && _y +_win.h() >= _mouseY){
1764                                         _currentWindow = _win;
1765                                         currentWindowIndex = i;
1766                                         break;
1767                                 }
1768                         }
1769                         currentWindow && currentWindow !== _currentWindow && currentWindow.onMouseOut( _mouseX, _mouseY);
1770                         currentWindow = _currentWindow;
1771                         return currentWindowIndex;
1772                 }
1773                 function openWindow( _window){
1774                         if( _window.visible !== true) return;
1775                         WINDOW_ARRAY.unshift( _window);
1776                         WINDOWS_CONTROL.init === undefined &&
1777                                 ( _window.init === undefined ?
1778                                         jqContainer.append( _window.$.stop().fadeIn()) :
1779                                         _window.init( jqContainer)
1780                                 );
1781                 }
1782                 function closeWindow( _window){
1783                         var l = WINDOW_ARRAY.length;
1784                         for( var i=0; i<l; ++i){
1785                                 if( WINDOW_ARRAY[ i] === _window){
1786                                         WINDOW_ARRAY.splice( i, 1);
1787                                         _window.$.stop().fadeOut( function(){
1788                                                 this.parentNode.removeChild( this);
1789                                         });
1790                                         return;
1791                                 }
1792                         }
1793                 }
1794                 
1795                 return {
1796                         init: function(){
1797                                 jqContainer = $( '#window-container');
1798                                 
1799                                 var l = WINDOW_ARRAY.length,
1800                                         _window;
1801                                 for( var i=l-1; i >= 0; --i){
1802                                         _window = WINDOW_ARRAY[ i];
1803                                         _window.visible === true && _window.init && _window.init( jqContainer);
1804                                 }
1805                                 log = $( '#window-log');
1806                                 
1807                                 delete WINDOWS_CONTROL.init;
1808                         },
1809                         onMouseMove: function( _mouseX, _mouseY){
1810                                 var _index = getCurrentWindow( _mouseX, _mouseY);
1811                                 if( _index === 0){
1812                                         currentWindow.onMouseMove( _mouseX, _mouseY);
1813                                         return true;
1814                                 } else
1815                                 if( _index !== -1){ // 先頭のクリックでない場合
1816                                 // Array を前に
1817                                         WINDOW_ARRAY.splice( currentWindowIndex, 1);
1818                                         WINDOW_ARRAY.unshift( currentWindow);
1819                                 // Domを最後に
1820                                         jqContainer.append( currentWindow.$);
1821                                         currentWindowIndex = 0;
1822                                         return true;
1823                                 }
1824                                 return false;
1825                         },
1826                         onMouseUp: function( _mouseX, _mouseY){
1827                                 if( getCurrentWindow( _mouseX, _mouseY) === 0){
1828                                         currentWindow.onMouseUp( _mouseX, _mouseY);
1829                                         return true;
1830                                 }
1831                                 return false;
1832                         },
1833                         onMouseDown: function( _mouseX, _mouseY){
1834                                 if( getCurrentWindow( _mouseX, _mouseY) === 0){
1835                                         currentWindow.onMouseDown( _mouseX, _mouseY);
1836                                         return true;
1837                                 }
1838                                 return false;
1839                         },
1840                         onMouseClick: function( _mouseX, _mouseY){
1841                                 return false;
1842                         },
1843                         busy: function(){
1844                                 return currentWindow !== null;
1845                         },
1846                         onWindowResize: function( _windowW, _windowH){
1847                                 /*
1848                                  * 画面外に出るwindowの移動
1849                                  */
1850                         },
1851                         createWindow: function( scope, EXTENDS, bodyTempleteID, title, x, y, w, h, opt_visible, opt_closeButtonEnabled, opt_resizeButtonEnabled, opt_minWindowW, opt_minWindowH){
1852                                 opt_visible = opt_visible !== false;
1853                                 opt_closeButtonEnabled = opt_closeButtonEnabled === true;
1854                                 opt_resizeButtonEnabled = opt_resizeButtonEnabled === true;
1855                                 opt_minWindowW = opt_minWindowW || ( w < DEFAULT_MIN_WINDOW_WIDTH) ? w : DEFAULT_MIN_WINDOW_WIDTH;
1856                                 opt_minWindowH = opt_minWindowH || ( h < DEFAULT_MIN_WINDOW_HEIGHT) ? h : DEFAULT_MIN_WINDOW_HEIGHT;
1857                                 
1858                                 var _window = h2c.util.extend(
1859                                         WindowClass.apply( scope, [ bodyTempleteID, title, x, y, w, h, opt_visible, opt_closeButtonEnabled, opt_resizeButtonEnabled, opt_minWindowW, opt_minWindowH]),
1860                                         EXTENDS
1861                                 );
1862                                 _window.setInstance();
1863                                 opt_visible === true && openWindow( _window);
1864                                 return _window;
1865                         }
1866                 }
1867         })();
1868
1869 /* ----------------------------------------
1870  * TOOL_BOX_WINDOW
1871  */
1872         var TOOL_BOX_WINDOW = ( function(){
1873                 var addImageButton, addTextButton, editBgButton, switchGridButton, popupHelpButton, publishButton,
1874                         gridSwitchFunction;
1875                         
1876                 h2c.key.addKeyEvent( 73, false, true, addImage);
1877                 MENU_BAR_CONTROL.EDIT.createSelection( 'Add Image', 'ctrl + I', addImage, true, true, false);
1878                 
1879                 h2c.key.addKeyEvent( 84, false, true, addText);
1880                 MENU_BAR_CONTROL.EDIT.createSelection( 'Add Text', 'ctrl + T', addText, true, false, true);
1881
1882                 h2c.key.addKeyEvent( 71, false, true, switchGrid);
1883                 MENU_BAR_CONTROL.EDIT.createSelection( 'show Grid', 'ctrl + G', switchGrid, true, true, true);
1884
1885                 function addImage(){
1886                         setTimeout( function(){ CANVAS_CONTROL.createImageElement();}, 0);                      
1887                 }
1888                 function addText(){
1889                         setTimeout( function(){ CANVAS_CONTROL.createTextElement();}, 0);                       
1890                 }
1891                 function switchGrid(){
1892                         setTimeout( gridSwitchFunction, 0);
1893                 }
1894                 function popupHelp(){
1895                         setTimeout( function(){ HELP_DOCUMENTS_WINDOW.open();}, 0);     
1896                 }
1897                 
1898                 return WINDOWS_CONTROL.createWindow(
1899                         this,
1900                         {
1901                                 onInit: function(){
1902                                         addImageButton = $( '#toolbox-add-image-button').click( function(e){
1903                                                 addImage();
1904                                                 e.preventDefault();
1905                                                 return false;
1906                                         });
1907
1908                                         addTextButton = $( '#toolbox-add-text-button').click( function(e){
1909                                                 addText();
1910                                                 e.preventDefault();
1911                                                 return false;
1912                                         });
1913                                         
1914                                         editBgButton = $( '#toolbox-edit-bg-button').click( function( e){
1915                                                 setTimeout( function(){
1916                                                         INFOMATION_WINDOW.open();
1917                                                 }, 0);  
1918                                                 e.preventDefault();
1919                                                 return false;
1920                                         });
1921                                         
1922                                         switchGridButton = $( '#toolbox-switch-grid').click( function( e){
1923                                                 switchGrid();
1924                                                 e.preventDefault();
1925                                                 return false;
1926                                         });
1927                                         
1928                                         popupHelpButton = $( '#toolbox-popup-help-button').click( function( e){
1929                                                 popupHelp();
1930                                                 e.preventDefault();
1931                                                 return false;
1932                                         });
1933                                         
1934                                         publishButton = $( '#toolbox-publish-button');
1935                                         
1936                                         delete this.onInit;
1937                                 },
1938                                 setGridSwitchFunction: function( _gridSwitchFunction){
1939                                         gridSwitchFunction = _gridSwitchFunction || gridSwitchFunction;
1940                                 }
1941                         },
1942                         'toolbox-window', 'Tool box', 0, 215, 110, 290, true
1943                 );
1944         })();
1945
1946 /* ----------------------------------------
1947  * INFOMATION_WINDOW
1948  */                     
1949         var INFOMATION_WINDOW = ( function(){
1950                 var FADE_EFFECT_ENABLED = h2c.isIE === false || h2c.ieVersion >= 8,
1951                         FADE_IN_EFFECT = FADE_EFFECT_ENABLED === true ? 'fadeIn' : 'show',
1952                         FADE_OUT_EFFECT = FADE_EFFECT_ENABLED === true ? 'fadeOut' : 'hide',
1953                         backgroundInfomationElm,
1954                         jqComicElementInformation,
1955                         xValueElm, yValueElm, zValueElm, aValueElm, wValueElm, hValueElm,
1956                         wPercentElm, hPercentElm,
1957                         currentComicElement = null,
1958                         currentElementType = -1;
1959
1960                 return WINDOWS_CONTROL.createWindow(
1961                         this,
1962                         {
1963                                 onInit: function(){
1964                                         backgroundInfomationElm = $( '#panel-background-information');
1965                                         
1966                                         jqComicElementInformation = $( '#comic-element-infomation').hide().css( {
1967                                                 height:         this.bodyHeight()
1968                                         });
1969                                         var TAB_GROUP_ID = 'comic-element-attribute';
1970                                         var CREATER = h2c.key.createEditableText;
1971                                         xValueElm = CREATER( $( '#comic-element-x'), null, TAB_GROUP_ID);
1972                                         yValueElm = CREATER( $( '#comic-element-y'), null, TAB_GROUP_ID);
1973                                         zValueElm = CREATER( $( '#comic-element-z'), null, TAB_GROUP_ID);
1974                                         aValueElm = CREATER( $( '#comic-element-a'), null, TAB_GROUP_ID);
1975                                         wValueElm = CREATER( $( '#comic-element-w'), null, TAB_GROUP_ID);
1976                                         hValueElm = CREATER( $( '#comic-element-h'), null, TAB_GROUP_ID);
1977                                         wPercentElm = CREATER( $( '#comic-element-w-percent'), null, TAB_GROUP_ID);
1978                                         hPercentElm = CREATER( $( '#comic-element-h-percent'), null, TAB_GROUP_ID);
1979                                         delete this.onInit;
1980                                 },
1981                                 onResize: function( w, h){
1982                                         jqComicElementInformation && jqComicElementInformation.css( {
1983                                                 height: this.bodyHeight()
1984                                         });
1985                                 },
1986                                 update: function( _currentElementType, x, y, z, a, w, h, wPercent, hPercent){
1987                                         if( currentElementType !== _currentElementType){
1988                                                 if( _currentElementType !== -1){
1989                                                         if( _currentElementType === 1){
1990                                                                 aValueElm.show();
1991                                                                 wPercentElm.hide();
1992                                                                 hPercentElm.hide();
1993                                                         } else {
1994                                                                 aValueElm.hide();
1995                                                                 wPercentElm.show();
1996                                                                 hPercentElm.show();
1997                                                         }
1998                                                         currentElementType === -1 && jqComicElementInformation.stop().css( {
1999                                                                 filter:         '',
2000                                                                 opacity:        ''
2001                                                         })[ FADE_IN_EFFECT]();
2002                                                 } else {
2003                                                         currentElementType !== -1 && jqComicElementInformation.stop().css({
2004                                                                 filter:         '',
2005                                                                 opacity:        ''
2006                                                         })[ FADE_OUT_EFFECT]();
2007                                                 }
2008                                                 currentElementType = _currentElementType;
2009                                         }
2010                                         if( currentElementType !== -1){
2011                                                 xValueElm.update( x);
2012                                                 yValueElm.update( y);
2013                                                 zValueElm.update( z);
2014                                                 _currentElementType === 1 && aValueElm.update( a);
2015                                                 wValueElm.update( w);
2016                                                 hValueElm.update( h);
2017                                                 _currentElementType === 0 && wPercentElm.update( wPercent);
2018                                                 _currentElementType === 0 && hPercentElm.update( hPercent);                                     
2019                                         } else {
2020                                                 
2021                                         }
2022                                 }
2023                         },
2024                         'infomation-window', 'Infomation', 0, 30, 200, 180, true
2025                 );
2026         })();
2027
2028 /* ----------------------------------------
2029  * HELP_WINDOW
2030  */
2031         var HELP_DOCUMENTS_WINDOW = ( function(){
2032                 var visible = true,
2033                         hasAjaxContents = false,
2034                         jqAjaxContents,
2035                         jqNaviItems,
2036                         jqPages;
2037                 function jumpPage( _index){
2038                         
2039                 }
2040                 function onOpen( _pageIndex){
2041                         _pageIndex = _pageIndex || 0;
2042                         if( hasAjaxContents === false){
2043                                 $.ajax({
2044                                         url:            'help/jp.html',
2045                                         dataType:       'html',
2046                                         success:        function( html){
2047                                                 $( html).find( 'script,style,object,applet,embed,iframe,frame').remove();
2048                                                 jqNaviItems = jqAjaxContents.removeClass( 'loading').append( html)
2049                                                         .find( 'a.sidenavi-item').attr( 'href', '#')
2050                                                         .click( function( e){
2051                                                                 var that = this,
2052                                                                         parent = this.parentNode,
2053                                                                         i = ( function(){
2054                                                                                 var children = parent.getElementsByTagName( 'A'),
2055                                                                                         l = children.length;
2056                                                                                 for( var i=0; i<l; ++i){
2057                                                                                         if( children[ i] === that) return i;
2058                                                                                 }
2059                                                                                 return -1;
2060                                                                         })();
2061                                                                 e.stopPropagation();
2062                                                                 if( i === -1) return false;
2063                                                                 jqNaviItems.removeClass( 'current').eq( i).addClass( 'current');
2064                                                                 jqPages.hide().eq( i).show();
2065                                                                 
2066                                                                 return false;
2067                                                         });
2068                                                 jqNaviItems.eq( _pageIndex).addClass( 'current');
2069                                                 jqPages = jqAjaxContents.find( '.page-content');
2070                                                 jqPages.eq( _pageIndex).show();
2071                                         }
2072                                 });
2073                                 hasAjaxContents = true;
2074                         } else {
2075                                 jqNaviItems.removeClass( 'current').eq( _pageIndex).addClass( 'current');
2076                                 jqPages.hide().eq( _pageIndex).show();
2077                         }
2078                 }
2079                 return WINDOWS_CONTROL.createWindow(
2080                         this,
2081                         {
2082                                 onInit: function(){
2083                                         jqAjaxContents = this.$.find( '.window-body').addClass( 'loading').css( { height: this.bodyHeight()});
2084                                         onOpen( 0);
2085                                         delete this.onInit;
2086                                 },
2087                                 onResize: function( w, h){
2088                                         jqAjaxContents && jqAjaxContents.css( { height: this.bodyHeight()});
2089                                 },
2090                                 setAjaxContent: function( html){
2091                                         
2092                                         delete this.onLoadAjaxContent;
2093                                 }
2094                         },
2095                         null, 'Help', 0, 215, 400, 350, false, true, true, 300, 300
2096                 );
2097         })();
2098
2099 /* ----------------------------------------
2100  *    - CANVAS_CONTROL
2101  *       - GRID_CONTROL
2102  *       - WHITE_GLASS_CONTROL
2103  *       - PANEL_BORDER_CONTROL
2104  *       - COMIC_ELEMENT_CONTROL
2105  *          - PanelResizerClass
2106  *          - COMIC_ELEMENT_OPERATOR
2107  *          - ImageElementClass
2108  *          - TextElementClass
2109  */     
2110         var CANVAS_CONTROL = ( function(){
2111                 var DEFAULT_PANEL_WIDTH = 400,
2112                         DEFAULT_PANEL_HEIGHT = 300,
2113                         MIN_PANEL_HEIGHT = 20,
2114                         BORDER_WIDTH = 2,
2115                         RESIZER_BORDER_WIDTH = 1,
2116                         SPACE_ENABLED = h2c.key.spaceEnabled,
2117                         canvasW, canvasH, canvasX, canvasY,
2118                         xOffset, yOffset, startCanvasX, startCanvasY,
2119                         isDragging = false,
2120                         hasFocus = false;
2121                 
2122                 var GRID_CONTROL = ( function(){
2123                         var elmGrid = document.getElementById( 'grid'),
2124                                 jQGrid,
2125                                 visible = false;
2126                         
2127                         function update(){
2128                                 jQGrid.css( {
2129                                         opacity:        '',
2130                                         fliter:         ''
2131                                 }).stop()[ visible === true ? 'fadeOut' : 'fadeIn']();
2132                                 visible = !visible;
2133                                 if( visible === true){
2134                                         elmGrid.style.backgroundImage = "url('grid.gif')";
2135                                 }
2136                                 return visible;
2137                         }
2138                         return {
2139                                 init: function(){
2140                                         jQGrid = $( elmGrid);
2141                                         this.resize();
2142                                         TOOL_BOX_WINDOW.setGridSwitchFunction( update);
2143                                         delete GRID_CONTROL.init;
2144                                 },
2145                                 resize: function(){
2146                                         elmGrid.style.backgroundPosition = [ canvasX % 10, 'px ', canvasY % 10, 'px'].join( '');
2147                                         elmGrid.style.height = windowH +'px';                           
2148                                 },
2149                                 enabled: function(){
2150                                         return visible;
2151                                 }
2152                         }
2153                 })();
2154                 
2155         /*
2156          *      WHITE_GLASS_CONTROL
2157          */     
2158                 var WHITE_GLASS_CONTROL = ( function(){
2159                         var styleTop = document.getElementById( 'whiteGlass-top').style,
2160                                 styleLeft = document.getElementById( 'whiteGlass-left').style,
2161                                 styleRight = document.getElementById( 'whiteGlass-right').style,
2162                                 styleBottom = document.getElementById( 'whiteGlass-bottom').style;
2163                         function resize(){
2164                                 var     _w = canvasW,
2165                                         _h = canvasH,
2166                                         marginTop = canvasY,
2167                                         marginBottom = windowH -_h -marginTop,
2168                                         marginX = canvasX,
2169                                         rightWidth = windowW -_w -marginX;
2170                                 
2171                                 styleTop.height = ( marginTop < 0 ? 0 : marginTop) +'px';
2172                                 
2173                                 styleLeft.top = marginTop +'px';
2174                                 styleLeft.width = ( marginX < 0 ? 0 : marginX) +'px';
2175                                 styleLeft.height = ( _h + marginBottom) +'px';
2176                                 
2177                                 styleRight.top = marginTop +'px';
2178                                 styleRight.left = _w +marginX +'px';
2179                                 styleRight.width = ( rightWidth < 0 ? 0 : rightWidth) +'px';
2180                                 styleRight.height = ( _h + marginBottom) +'px';
2181                                 
2182                                 styleBottom.top = ( _h +marginTop) +'px';
2183                                 styleBottom.left = marginX +'px';
2184                                 styleBottom.width = _w +'px';
2185                                 styleBottom.height = ( marginBottom < 0 ? 0 : marginBottom) +'px';
2186                         }
2187                         return {
2188                                 resize: resize
2189                         }
2190                 })();
2191
2192         /*
2193          * PANEL_BORDER_CONTROL
2194          */
2195                 var PANEL_BORDER_CONTROL = ( function(){
2196                         var     panelElm, borderWidth;
2197                         
2198                         function resize(){
2199                                 panelElm.css( {
2200                                         left:   canvasX -BORDER_WIDTH,
2201                                         top:    canvasY -BORDER_WIDTH,
2202                                         width:  canvasW,
2203                                         height: canvasH
2204                                 });
2205                         }
2206                                                 
2207                         return {
2208                                 init: function(){
2209                                         panelElm = $( '#panel-border');
2210                                         borderWidth = panelElm.css( 'border-width');
2211                                         
2212                                         delete PANEL_BORDER_CONTROL.init;
2213                                 },
2214                                 resize: resize
2215                         }
2216                 })();
2217         
2218         /*
2219          * COMIC_ELEMENT_CONTROL
2220          *   - PanelResizerClass
2221          *   - COMIC_ELEMENT_OPERATOR
2222          *   - ImageElementClass
2223          *   - TextElementClass
2224          */
2225                 var COMIC_ELEMENT_CONTROL = ( function( _onResizeFunction){
2226                         var     MIN_OBJECT_SIZE = 19,
2227                                 log,
2228                                 currentElement = null,
2229                                 _canvasX, _canvasY, _canvasW, _canvasH,
2230                                 MOUSE_HIT_AREA = 10,
2231                                 SAVE = HISTORY.saveState;
2232                 /*
2233                  * --------------------------------------------------------------------------------------------
2234                  * panel resizer
2235                  */
2236                         var PanelResizerClass = function( ELM, onPanelResizeFunction, isTop){
2237                                 var     BORDER_WIDTH = 2,
2238                                         yOffset, y, _canvasY, _canvasH,
2239                                         RESIZER_HEIGHT = 30,
2240                                         isDragging = false,
2241                                         SAVE = HISTORY.saveState,
2242                                         MOUSE_CURSOR = updateMouseCursor;
2243                                         
2244                                 function restoreState( arg){
2245                                         if( arg && arg.length > 3){
2246                                                 canvasX = arg[ 0] || canvasX;
2247                                                 canvasY = arg[ 1] || canvasY;
2248                                                 canvasW = arg[ 2] || canvasW;
2249                                                 canvasH = arg[ 3] || canvasH;
2250                                                 
2251                                                 /*
2252                                                  * PANEL_RESIZER_TOP の場合、リサイズに併せてコミック要素を移動させている。
2253                                                  * currentElementを一度PANEL_RESIZER_TOPにしたのちresize
2254                                                  */
2255                                                 onPanelResizeFunction( isTop);
2256                                         }
2257                                 }
2258                                         
2259                                 return {
2260                                         init: function( _elm){
2261                                                 this.$ = $( ELM);
2262                                                 ELM.style.width = ( canvasW +2)+'px';
2263                                         },
2264                                         $: null,
2265                                         hitareaX: function(){ return -1;},
2266                                         hitareaY: function(){ return isTop === true ? ( -35 -BORDER_WIDTH) : ( canvasH +5 +BORDER_WIDTH);},
2267                                         hitareaW: function(){ return canvasW +2;},
2268                                         hitareaH: function(){ return RESIZER_HEIGHT;},
2269                                         resize: resize,
2270                                         dragging: function(){
2271                                                 return isDragging;
2272                                         },
2273                                         onMouseDown: function( _mouseX, _mouseY){
2274                                                 yOffset = _mouseY;
2275                                                 _canvasY = canvasY;
2276                                                 _canvasH = canvasH;
2277                                                 isDragging = true;
2278                                         },
2279                                         onMouseMove: function( _mouseX, _mouseY){
2280                                                 if( isDragging !== true){
2281                                                         COMIC_ELEMENT_OPERATOR.hide();
2282                                                         MOUSE_CURSOR( 'n-resize');
2283                                                 } else {
2284                                                         var move = _mouseY -yOffset;
2285                                                         if( isTop === true){    
2286                                                                 //if( 0 < _canvasH - move){
2287                                                                         if( _canvasH - move < MIN_PANEL_HEIGHT){
2288                                                                                 move = _canvasH -MIN_PANEL_HEIGHT;
2289                                                                         }
2290                                                                         canvasY = _canvasY +move;
2291                                                                         canvasH = _canvasH -move;
2292                                                                         log.html( move)
2293                                                                         onPanelResizeFunction( true);
2294                                                                 //}                                                             
2295                                                         } else {
2296                                                                 var _h = _canvasH +move;
2297                                                                 if( 0 < _h && _h < windowH -canvasY -RESIZER_HEIGHT -5 -BORDER_WIDTH){
2298                                                                         if( _h < MIN_PANEL_HEIGHT){
2299                                                                                 _h = MIN_PANEL_HEIGHT;
2300                                                                         }
2301                                                                         canvasH = _h;
2302                                                                         onPanelResizeFunction( false);
2303                                                                 }
2304                                                         }
2305                                                 }
2306                                         },
2307                                         onMouseUp: function( _mouseX, _mouseY){
2308                                                 ( _canvasY !== canvasY || _canvasH !== canvasH) && SAVE( restoreState, [ NaN, _canvasY, NaN, _canvasH], [ NaN, canvasY, NaN, canvasH]);
2309                                                 isDragging = false;
2310                                         }
2311                                 }
2312                         };
2313                         
2314                         var     PANEL_RESIZER_TOP = PanelResizerClass.apply( {}, [ document.getElementById( 'panel-resizer-top'), _onResizeFunction, true]),
2315                                 PANEL_RESIZER_BOTTOM = PanelResizerClass.apply( {}, [ document.getElementById( 'panel-resizer-bottom'), _onResizeFunction, false]),
2316                                 DRAGGABLE_ELEMENT_ARRAY = [ PANEL_RESIZER_TOP, PANEL_RESIZER_BOTTOM],
2317                                 NUM_RESIZER = DRAGGABLE_ELEMENT_ARRAY.length;
2318                         
2319                         _onResizeFunction = PanelResizerClass = undefined;
2320                 
2321                 /*
2322                  * --------------------------------------------------------------------------------------------
2323                  * COMIC_ELEMENT_OPERATOR
2324                  */
2325                         var COMIC_ELEMENT_OPERATOR = ( function(){
2326                                 var     MOUSE_CURSOR = updateMouseCursor,
2327                                         SAVE = HISTORY.saveState,
2328                                         INFOMATION = INFOMATION_WINDOW.update,
2329                                         GRID_ENABLED = GRID_CONTROL.enabled,
2330                                         HIT_AREA = MOUSE_HIT_AREA,
2331                                         RESIZER = ( function( HIT_AREA){
2332                                                 var POSITION_ARRAY = [],
2333                                                         FLOOR = Math.floor,
2334                                                         CURSOR_AND_FLIP = [
2335                                                                 { cursor:       'n-resize',             v: 3},
2336                                                                 { cursor:       'e-resize',             h: 2},
2337                                                                 { cursor:       'e-resize',             h: 1},
2338                                                                 { cursor:       'n-resize',             v: 0},
2339                                                                 { cursor:       'nw-resize',    h: 5, v: 6, vh: 7},
2340                                                                 { cursor:       'ne-resize',    h: 4, v: 7, vh: 6},
2341                                                                 { cursor:       'ne-resize',    h: 7, v: 4, vh: 5},
2342                                                                 { cursor:       'nw-resize',    h: 6, v: 5, vh: 4}
2343                                                         ],      
2344                                                         elmResizerContainerStyle = document.getElementById( 'comic-element-resizer-container').style,
2345                                                         elmResizerTopStyle = document.getElementById( 'comic-element-resizer-top').style,
2346                                                         elmResizerLeftStyle = document.getElementById( 'comic-element-resizer-left').style,
2347                                                         elmResizerRightStyle = document.getElementById( 'comic-element-resizer-right').style,
2348                                                         elmResizerBottomStyle = document.getElementById( 'comic-element-resizer-bottom').style,
2349                                                         x, y, w, h,
2350                                                         currentIndex;
2351                                                 elmResizerContainerStyle.display = 'none';
2352                                                 return {
2353                                                         x: function(){ return x;},
2354                                                         y: function(){ return y;},
2355                                                         w: function(){ return w;},
2356                                                         h: function(){ return h;},
2357                                                         update: function( _x, _y, _w, _h){
2358                                                                 x = _x !== undefined ? _x : x;
2359                                                                 y = _y !== undefined ? _y : y;
2360                                                                 w = _w !== undefined ? _w : w;
2361                                                                 h = _h !== undefined ? _h : h;
2362                                                                 elmResizerContainerStyle.left = x +'px';
2363                                                                 elmResizerContainerStyle.top = y +'px';
2364                                                                 elmResizerContainerStyle.width = w +'px';
2365                                                                 elmResizerContainerStyle.height = h +'px';
2366                                                                 elmResizerTopStyle.left = FLOOR( w /2 -10 /2) +'px';
2367                                                                 elmResizerLeftStyle.top = FLOOR( h /2 -10 /2) +'px';
2368                                                                 elmResizerRightStyle.top = FLOOR( h /2 -10 /2) +'px';
2369                                                                 elmResizerBottomStyle.left = FLOOR( w /2 -10 /2) +'px';
2370                                                                 
2371                                                                 POSITION_ARRAY.splice( 0, POSITION_ARRAY.length);
2372                                                                 POSITION_ARRAY.push(
2373                                                                         {x:     x +5,                                   y:      y -HIT_AREA,            w:      w -5 *2,                h:      HIT_AREA +5},
2374                                                                         {x: x -HIT_AREA,                        y:      y +HIT_AREA +5,         w:      HIT_AREA +5,    h:      h -5 *2},
2375                                                                         {x: x +w -5,                            y:      y +HIT_AREA +5,         w:      HIT_AREA +5,    h:      h -5 *2},
2376                                                                         {x:     x +5,                                   y:      y +h -5,                        w:      w -5 *2,                h:      HIT_AREA +5},
2377                                                                         {x:     x -HIT_AREA,                    y:      y -HIT_AREA,            w:      HIT_AREA +5,    h:      HIT_AREA +5},
2378                                                                         {x: x +w -HIT_AREA,                     y:      y -HIT_AREA,            w:      HIT_AREA +5,    h:      HIT_AREA +5},
2379                                                                         {x:     x -HIT_AREA,                    y:      y +h -5,                        w:      HIT_AREA +5,    h:      HIT_AREA +5},
2380                                                                         {x:     x +w -5,                                y:      y +h -5,                        w:      HIT_AREA +5,    h:      HIT_AREA +5}
2381                                                                 );
2382                                                         },
2383                                                         index: function( _mouseX, _mouseY){
2384                                                                 if( TAIL_MOVER.hitText( _mouseX -x, _mouseY -y) === true){
2385                                                                         MOUSE_CURSOR( 'move');
2386                                                                         return TAIL_MOVER_INDEX;
2387                                                                 }
2388                                                                 var     p,
2389                                                                         l = POSITION_ARRAY.length;
2390                                                                 for( var i=0; i<l; i++){
2391                                                                         p = POSITION_ARRAY[ i];
2392                                                                         if( p.x <= _mouseX && p.y <= _mouseY && p.x + p.w >= _mouseX && p.y +p.h >= _mouseY){
2393                                                                                 MOUSE_CURSOR( CURSOR_AND_FLIP[ i].cursor);
2394                                                                                 return currentIndex = i;
2395                                                                         }
2396                                                                 }
2397                                                                 return -1;
2398                                                         },
2399                                                         flip: function( _flipV, _flipH){
2400                                                                 var p = CURSOR_AND_FLIP[ currentIndex];
2401                                                                 currentIndex = _flipH === true || _flipV === true ? p[
2402                                                                         _flipH === true && _flipV === true ? 'vh' : ( _flipH === true ? 'h' : 'v')
2403                                                                 ] : currentIndex;
2404                                                                 MOUSE_CURSOR( CURSOR_AND_FLIP[ currentIndex].cursor);
2405                                                                 return currentIndex;
2406                                                         },
2407                                                         show: function(){
2408                                                                 elmResizerContainerStyle.display = '';
2409                                                         },
2410                                                         hide: function(){
2411                                                                 elmResizerContainerStyle.display = 'none';
2412                                                         }
2413                                                 }
2414                                         })( HIT_AREA),
2415                                         TAIL_MOVER = ( function(){
2416                                                 var     ELM_MOVER = document.getElementById( 'baloon-tail-mover'),
2417                                                         //ELM_MOVER_PARENT = ELM_MOVER.parentNode,
2418                                                         //ELM_MOVER_NEXT = ELM_MOVER.nextSibling,
2419                                                         SIZE = ( function(){
2420                                                                 var _size = h2c.util.getElementSize( ELM_MOVER);
2421                                                                 return _size.width;
2422                                                         })(),
2423                                                         SIN = Math.sin,
2424                                                         COS = Math.cos,
2425                                                         ATAN = Math.atan,
2426                                                         FLOOR = Math.floor,
2427                                                         DEG_TO_RAD = Math.PI / 180,
2428                                                         RAD_TO_DEG = 1 /DEG_TO_RAD,
2429                                                         currentText = null,
2430                                                         x, y, w, h, a, radA;
2431                                                 //ELM_MOVER_PARENT.removeChild( ELM_MOVER);
2432                                                 
2433                                                 function draw( _w, _h, _a){
2434                                                         w = _w !== undefined ? _w : w;
2435                                                         h = _h !== undefined ? _h : h;
2436                                                         a = _a !== undefined ? _a : a;
2437                                                         radA = a *DEG_TO_RAD;
2438                                                         x = FLOOR( ( ( COS( radA) /2 +0.5) *( w +SIZE)) -SIZE /2);
2439                                                         y = FLOOR( ( ( SIN( radA) /2 +0.5) *( h +SIZE)) -SIZE /2);
2440                                                         ELM_MOVER.style.left = x +'px';
2441                                                         ELM_MOVER.style.top = y +'px';
2442                                                         log.html( [ w, h, a].join());
2443                                                 }
2444                                                 
2445                                                 return {
2446                                                         update: draw,
2447                                                         show: function( _currentText){
2448                                                                 /*
2449                                                                  * domから抜かないとieで表示されてしまう。visibilityのほうがいい
2450                                                                  */
2451                                                                 //ELM_MOVER_NEXT !== ELM_MOVER.nextSibling && ELM_MOVER_PARENT.insertBefore(ELM_MOVER, ELM_MOVER_NEXT);
2452                                                                 ELM_MOVER.style.visibility = '';
2453                                                                 draw( _currentText.w, _currentText.h, _currentText.angle());
2454                                                                 currentText = _currentText;
2455                                                         },
2456                                                         hide: function(){
2457                                                                 //ELM_MOVER.parentNode === ELM_MOVER_PARENT && ELM_MOVER_PARENT.removeChild( ELM_MOVER);
2458                                                                 ELM_MOVER.style.visibility = 'hidden';
2459                                                                 currentText = null;
2460                                                         },
2461                                                         hitText: function( _mouseX, _mouseY){
2462                                                                 var _x = x -SIZE /2,
2463                                                                         _y = y -SIZE /2;
2464                                                                 return currentIsTextElement === true && _x <= _mouseX && _y <= _mouseY && _x +SIZE >= _mouseX && _y +SIZE >= _mouseY;
2465                                                         },
2466                                                         onDrag: function( _mouseX, _mouseY){
2467                                                                 draw( w, h,
2468                                                                         _mouseX !== 0 ?
2469                                                                                 ATAN( _mouseY /_mouseX) *RAD_TO_DEG +( _mouseX < 0 ? 180 : 0) :
2470                                                                                 _mouseY > 0 ? 0 : 180
2471                                                                 );
2472                                                                 currentText && currentText.angle( a);
2473                                                                 updateInfomation( undefined, undefined, undefined, a);
2474                                                         }
2475                                                 }
2476                                         })(),
2477                                         COMIC_ELEMENT_CONSOLE = ( function(){
2478                                                 var     jqStage,
2479                                                         jqConsoleParent,
2480                                                         jqConsoleWrapper,
2481                                                         jqConsoleTail,
2482                                                         jqImgConsole, jqTextConsole,
2483                                                         currentElement = null,
2484                                                         currentType = -1,
2485                                                         visible = false,
2486                                                         imgConsoleWidth, imgConsoleHeight,
2487                                                         textConsoleWidth, textConsoleHeight,
2488                                                         consoleWidth, consoleHeight,
2489                                                         consoleX, consoleY,
2490                                                         tailSize = 10,
2491                                                         buttonClickable = false;
2492                                                         
2493                                                 function buttonBackOrForward( isBack){
2494                                                         var     offest = jqConsoleWrapper.offset();
2495                                                         jqConsoleWrapper.css( {
2496                                                                 position:       isBack === true ? '' : 'absolute',
2497                                                                 left:           isBack === true ? consoleX  : offest.left,
2498                                                                 top:            isBack === true ? consoleY  : offest.top
2499                                                         });
2500                                                         buttonClickable === isBack && ( isBack === true ? jqConsoleParent : jqStage).append( jqConsoleWrapper);
2501                                                         buttonClickable = !isBack;
2502                                                 }
2503                                                 return {
2504                                                         init: function(){
2505                                                                 jqStage = jqEditor;
2506                                                                 jqConsoleTail = $( '#comic-element-consol-tail');
2507                                                                 jqImgConsole = $( '#image-element-consol').hide();
2508                                                                 var imgConsoleSize = h2c.util.getElementSize( jqImgConsole.get( 0));
2509                                                                 imgConsoleWidth = imgConsoleSize.width;
2510                                                                 imgConsoleHeight = imgConsoleSize.height;
2511                                                                 
2512                                                                 jqTextConsole = $( '#text-element-consol').hide();
2513                                                                 var textConsoleSize = h2c.util.getElementSize( jqTextConsole.get( 0));
2514                                                                 textConsoleWidth = textConsoleSize.width;
2515                                                                 textConsoleHeight = textConsoleSize.height;
2516                                                                 
2517                                                                 jqConsoleWrapper = $( '#comic-element-consol-wrapper').hide();
2518                                                                 jqConsoleParent = jqConsoleWrapper.parent();
2519                                                                 
2520                                                                 $( '#edit-text-button').click( function(){
2521                                                                         if( currentElement === null) return;
2522                                                                         TEXT_EDITOR_CONTROL.show( currentElement);
2523                                                                         buttonBackOrForward( true);
2524                                                                 });
2525                                                                 $( '#delete-image-button, #delete-text-button').click( function(){
2526                                                                         if( currentElement === null) return;
2527                                                                         buttonBackOrForward( true);
2528                                                                         removeComicElement( currentElement);
2529                                                                         SAVE( restoreComicElement, [ true, currentElement], [ false, currentElement], true);
2530                                                                         COMIC_ELEMENT_OPERATOR.hide();
2531                                                                 });
2532                                                                 $( '#change-image-button').click( function(){
2533                                                                         if( currentElement === null) return;
2534                                                                         buttonBackOrForward( true);
2535                                                                         IMAGE_GROUP_EXPROLER.show( currentElement.url);
2536                                                                 });
2537                                                                 $( '#layer-forward-button, #forward-text-button').click( function(){
2538                                                                         if( currentElement === null) return;
2539                                                                         replaceComicElement( currentElement, true);
2540                                                                         updateInfomation();
2541                                                                         SAVE( restoreReplaceObject, [ currentElement, false], [ currentElement, true]);
2542                                                                 });
2543                                                                 $( '#layer-back-button, #back-text-button').click( function(){
2544                                                                         if( currentElement === null) return;
2545                                                                         replaceComicElement( currentElement, false);
2546                                                                         updateInfomation();
2547                                                                         SAVE( restoreReplaceObject, [ currentElement, true], [ currentElement, false]);
2548                                                                 });
2549                                                                                                                         
2550                                                                 delete COMIC_ELEMENT_CONSOLE.init;
2551                                                         },
2552                                                         show: function( _currentElement, _w, _h){
2553                                                                 visible === false && jqConsoleWrapper.show();
2554                                                                 visible = true;
2555                                                                 currentElement = _currentElement;
2556                                                                 var _currentType = _currentElement.type;
2557                                                                 if( currentType !== _currentType){
2558                                                                         currentType = _currentType;
2559                                                                         jqImgConsole.toggle( _currentType === COMIC_ELEMENT_TYPE_IMAGE);
2560                                                                         jqTextConsole.toggle( _currentType === COMIC_ELEMENT_TYPE_TEXT);
2561                                                                         consoleWidth = _currentType === COMIC_ELEMENT_TYPE_IMAGE ? imgConsoleWidth : textConsoleWidth;
2562                                                                         consoleHeight = _currentType === COMIC_ELEMENT_TYPE_IMAGE ? imgConsoleHeight : textConsoleHeight;
2563                                                                 }
2564                                                                 consoleX = Math.floor( ( _w -consoleWidth) /2);
2565                                                                 
2566                                                                 if( _w > consoleWidth * 1.5 && _h > consoleHeight * 1.5){
2567                                                                         consoleY = Math.floor( ( _h -consoleHeight) /2);
2568                                                                         jqConsoleWrapper.css( {
2569                                                                                 left:                   consoleX,
2570                                                                                 top:                    consoleY
2571                                                                         }).removeClass( 'console-out');
2572                                                                 } else {
2573                                                                         consoleY = _h +tailSize;
2574                                                                         jqConsoleWrapper.css( {
2575                                                                                 left:                   consoleX,
2576                                                                                 top:                    consoleY
2577                                                                         }).addClass( 'console-out');
2578                                                                 }
2579                                                         },
2580                                                         hide: function (){
2581                                                                 visible === true && jqConsoleWrapper.hide();
2582                                                                 visible = false;
2583                                                                 currentElement = null;
2584                                                         },
2585                                                         x: function(){ return consoleX;},
2586                                                         y: function(){ return consoleY;},
2587                                                         w: function(){ return consoleWidth;},
2588                                                         h: function(){ return consoleHeight;},
2589                                                         onMouseMove: function( _mouseX, _mouseY){
2590                                                                 if( consoleX > _mouseX || consoleY > _mouseY || consoleX +consoleWidth < _mouseX || consoleY +consoleHeight < _mouseY){
2591                                                                         buttonClickable === true && buttonBackOrForward( true);
2592                                                                         return false;
2593                                                                 }
2594                                                                 buttonClickable === false && buttonBackOrForward( false);
2595                                                                 return true;
2596                                                         },
2597                                                         onMouseOut: function( _mouseX, _mouseY){
2598                                                                 buttonClickable === true && buttonBackOrForward( true);
2599                                                         }
2600                                                 }
2601                                         })(),
2602                                         TAIL_MOVER_INDEX = 99,
2603                                         RESIZE_COMMAND_ARRAY = [
2604                                                 { x:    0, w:    0, y:  1, h:   -1}, //top
2605                                                 { x:    1, w:   -1, y:  0, h:    0}, //left
2606                                                 { x:    0, w:    1, y:  0, h:    0}, //right
2607                                                 { x:    0, w:    0, y:  0, h:    1}, //bottom
2608                                                 { x:    1, w:   -1, y:  1, h:   -1}, //top-left
2609                                                 { x:    0, w:    1, y:  1, h:   -1}, //top-right
2610                                                 { x:    1, w:   -1, y:  0, h:    1}, //bottom-left
2611                                                 { x:    0, w:    1, y:  0, h:    1}  //bottom-right
2612                                         ],
2613                                         currentResizerIndex = -1,
2614                                         currentIsTextElement = false,
2615                                         currentElement = null,
2616                                         x, y, w, h, angle, flipV, flipH,
2617                                         startX, startY, startW, startH, startA, startFilpV, startFilpH,
2618                                         xOffset, yOffset,
2619                                         isDragging = false,
2620                                         currentUpdated = false;
2621
2622                                         function resize( _x, _y, _w, _h, _angle){
2623                                                 x = _x !== undefined ? _x : x;
2624                                                 y = _y !== undefined ? _y : y;
2625                                                 w = _w !== undefined ? _w : w;
2626                                                 h = _h !== undefined ? _h : h;
2627                                                 angle = _angle !== undefined ? _angle : angle;
2628
2629                                                 RESIZER.update( x, y, w, h);
2630                                                 currentIsTextElement === true && TAIL_MOVER.update( w, h, angle);
2631                                                 COMIC_ELEMENT_CONSOLE.show( currentElement, w, h);
2632                                                 updateInfomation( x, y, currentElement.z, angle, w, h);
2633                                         }
2634                                         function updateInfomation( _x, _y, _z, _a, _w, _h){
2635                                                 _w = _w !== undefined ? _w : w;
2636                                                 _h = _h !== undefined ? _h : h;
2637                                                 INFOMATION(
2638                                                         currentElement === null ? -1 : currentElement.type,
2639                                                         _x !== undefined ? _x : x,
2640                                                         _y !== undefined ? _y : y,
2641                                                         _z !== undefined ? _z : ( currentElement === null ? '*' : currentElement.z),
2642                                                         _a !== undefined ? Math.floor( _a) : ( currentIsTextElement === true ? Math.floor( angle) : '-'),
2643                                                         _w,
2644                                                         _h,
2645                                                         currentElement === null || currentIsTextElement === true ? '-' : ( currentElement.actualW() === 0 ? '?' : Math.floor( _w / currentElement.actualW() *100)),
2646                                                         currentElement === null || currentIsTextElement === true ? '-' : ( currentElement.actualH() === 0 ? '?' : Math.floor( _h / currentElement.actualH() *100))
2647                                                 );
2648                                         }
2649                                         function show( _currentElement){
2650                                                 currentElement === null && RESIZER.show();
2651                                                 if( currentElement !== _currentElement){
2652                                                         currentElement = _currentElement;
2653                                                         startX = _currentElement.x;
2654                                                         startY = _currentElement.y;
2655                                                         startW = _currentElement.w;
2656                                                         startH = _currentElement.h;
2657                                                         
2658                                                         currentIsTextElement = ( _currentElement.type === COMIC_ELEMENT_TYPE_TEXT);
2659                                                         startA = currentIsTextElement === true ? _currentElement.angle() : 0;
2660                                                         currentIsTextElement === true ? TAIL_MOVER.show( _currentElement) : TAIL_MOVER.hide();
2661                                                         
2662                                                         startFilpV = flipV = currentIsTextElement === false ? _currentElement.flipV() : 0;
2663                                                         startFilpH = flipH = currentIsTextElement === false ? _currentElement.flipH() : 0;
2664                                                         
2665                                                         resize( startX, startY, startW, startH, startA);
2666                                                         isDragging = currentUpdated = false;
2667                                                 }
2668                                         }
2669                                         function hide(){
2670                                                 currentElement !== null && RESIZER.hide();
2671                                                 currentElement = null;
2672                                                 MOUSE_CURSOR( '');
2673                                                 TAIL_MOVER.hide();
2674                                                 isDragging = currentUpdated = false;
2675                                                 COMIC_ELEMENT_CONSOLE.hide();
2676                                                 updateInfomation();
2677                                         }
2678                                         function restoreState( arg){
2679                                                 if( arg && arg.length !== 8) return;
2680                                                 var _currentElement = arg[ 0],
2681                                                         _x = arg[ 1], _y = arg[ 2], _w = arg[ 3], _h = arg[ 4],
2682                                                         _a = arg[ 5],
2683                                                         _flipV = arg[ 6], _flipH = arg[ 7];
2684                                                 if( !_currentElement) return;
2685                                                 _currentElement.type === COMIC_ELEMENT_TYPE_IMAGE ?
2686                                                         _currentElement.animate( _x, _y, _w, _h, _flipV, _flipH) :
2687                                                         _currentElement.animate( _x, _y, _w, _h, _a);
2688                                                 currentElement === _currentElement ? resize( _x, _y, _w, _h, _a) : show( _currentElement);
2689                                         }
2690                                         function saveState(){
2691                                                 currentElement && SAVE( restoreState,
2692                                                         [ currentElement, startX, startY, startW, startH, startA, startFilpV, startFilpH],
2693                                                         [ currentElement, x, y, w, h, angle, flipV, flipH]
2694                                                 );
2695                                                 startX = x;
2696                                                 startY = y;
2697                                                 startW = w;
2698                                                 startH = h;
2699                                                 startA = angle;
2700                                                 startFilpV = flipV;
2701                                                 startFilpH = flipH;
2702                                         }
2703                                 return {
2704                                         init: function(){
2705                                                 COMIC_ELEMENT_CONSOLE.init(); // COMIC_ELEMENT_CONSOLE が要素の高さを取得するため、RESIZER.initがあと。
2706                                                 
2707                                                 hide();
2708                                                 delete COMIC_ELEMENT_OPERATOR.init;
2709                                         },
2710                                         hide: hide,
2711                                         dragging: function(){
2712                                                 return isDragging;
2713                                         },
2714                                         hitareaX: function( _comicElement, _x){
2715                                                 if( _comicElement === currentElement){
2716                                                         var _consoleX = COMIC_ELEMENT_CONSOLE.x();
2717                                                         return x +( _consoleX < 0 ? _consoleX : 0) -HIT_AREA;
2718                                                 }
2719                                                 return _x -HIT_AREA;
2720                                         },
2721                                         hitareaY: function( _comicElement, _y){
2722                                                 return _y -HIT_AREA;
2723                                         },
2724                                         hitareaW: function( _comicElement, _w){
2725                                                 if( _comicElement === currentElement){
2726                                                         var _consoleW = COMIC_ELEMENT_CONSOLE.w();
2727                                                         return ( _consoleW < w ? w : _consoleW) +HIT_AREA *2;
2728                                                 }
2729                                                 return _w +HIT_AREA *2;
2730                                         },
2731                                         hitareaH: function( _comicElement, _h){
2732                                                 if( _comicElement === currentElement){
2733                                                         var _consoleY = COMIC_ELEMENT_CONSOLE.y();
2734                                                         return ( _consoleY < h ? h : _consoleY +COMIC_ELEMENT_CONSOLE.h()) +HIT_AREA *2;
2735                                                 }
2736                                                 return _h +HIT_AREA *2;
2737                                         },
2738                                         onMouseDown: function( _currentElement, _mouseX, _mouseY){
2739                                                 //show( _currentElement);
2740                                                 xOffset = _mouseX;
2741                                                 yOffset = _mouseY;
2742                                                 currentResizerIndex = RESIZER.index( _mouseX, _mouseY);
2743                                                 currentResizerIndex === -1 && MOUSE_CURSOR( 'move');
2744                                                 isDragging = true;
2745                                         },
2746                                         onMouseMove: function( _currentElement, _mouseX, _mouseY){
2747                                                 show( _currentElement);
2748                                                 var moveX = _mouseX -xOffset,
2749                                                         moveY = _mouseY -yOffset;
2750                                                 if( isDragging === true){
2751                                                         if( currentResizerIndex !== -1){
2752                                                                 if( currentResizerIndex === TAIL_MOVER_INDEX){
2753                                                                         TAIL_MOVER.onDrag( _mouseX -x -w /2, _mouseY -y -h /2); //Balloonの中心を0,0とする座標系に変換
2754                                                                 } else {
2755                                                                         var com = RESIZE_COMMAND_ARRAY[ currentResizerIndex],
2756                                                                                 _x = x +moveX *com.x,
2757                                                                                 _y = y +moveY *com.y,
2758                                                                                 _w = w +moveX *com.w,
2759                                                                                 _h = h +moveY *com.h,
2760                                                                                 update = false;
2761                                                                         
2762                                                                         if( _w > MIN_OBJECT_SIZE && _h > MIN_OBJECT_SIZE){
2763                                                                                 update = true;
2764                                                                         } else 
2765                                                                         if( currentElement.type === COMIC_ELEMENT_TYPE_TEXT){
2766                                                                         } else
2767                                                                         if( _w < -MIN_OBJECT_SIZE || _h < -MIN_OBJECT_SIZE){
2768                                                                                 var __x, __y;
2769                                                                                 if( _w < -MIN_OBJECT_SIZE && _h > MIN_OBJECT_SIZE){
2770                                                                                 // flipH
2771                                                                                         __x = _x;
2772                                                                                         x = _x = _x +_w;
2773                                                                                         y = _y;
2774                                                                                         w = _w = __x -_x;
2775                                                                                         h = _h;
2776                                                                                         currentElement.flip( false, true);
2777                                                                                         currentResizerIndex = RESIZER.flip( false, true);
2778                                                                                         flipV = currentElement.flipV();
2779                                                                                 } else
2780                                                                                 if( _w > MIN_OBJECT_SIZE && _h < -MIN_OBJECT_SIZE){
2781                                                                                 // flipV
2782                                                                                         __y = _y;
2783                                                                                         x = _x;
2784                                                                                         y = _y = _y +_h;
2785                                                                                         w = _w;
2786                                                                                         h = _h = __y -_y;
2787                                                                                         currentElement.flip( true, false);
2788                                                                                         currentResizerIndex = RESIZER.flip( true, false);
2789                                                                                         flipH = currentElement.flipH();
2790                                                                                 } else {
2791                                                                                 // flipVH
2792                                                                                         __x = _x;
2793                                                                                         __y = _y;
2794                                                                                         x = _x = _x +_w;
2795                                                                                         y = _y = _y +_h;
2796                                                                                         w = _w = __x -_x;
2797                                                                                         h = _h = __y -_y;
2798                                                                                         currentElement.flip( true, true);
2799                                                                                         currentResizerIndex = RESIZER.flip( true, true);
2800                                                                                         flipV = currentElement.flipV();
2801                                                                                         flipH = currentElement.flipH();
2802                                                                                 }
2803                                                                                 update = true;
2804                                                                                 xOffset = _mouseX;
2805                                                                                 yOffset = _mouseY;      
2806                                                                         }
2807                                                                         
2808                                                                         if( update === true){
2809                                                                                 RESIZER.update( _x, _y, _w, _h);
2810                                                                                 currentElement.resize( _x, _y, _w, _h);
2811                                                                                 currentIsTextElement === true && TAIL_MOVER.update( _w, _h);
2812                                                                                 COMIC_ELEMENT_CONSOLE.show( currentElement, _w, _h);
2813                                                                                 updateInfomation( _x, _y, undefined, undefined, _w, _h);                                                                                
2814                                                                         }
2815                                                                 }
2816                                                                 currentUpdated = ( currentUpdated === true) ? true : ( moveX !== 0 || moveY !== 0);
2817                                                         } else {
2818                                                                 var _x = x +moveX,
2819                                                                         _y = y +moveY;
2820                                                                 if( GRID_ENABLED() === true){
2821                                                                         _x = Math.floor( _x / 10) * 10;
2822                                                                         _y = Math.floor( _y / 10) * 10;
2823                                                                 }
2824                                                                 RESIZER.update( _x, _y);
2825                                                                 currentElement.resize( _x, _y);
2826                                                                 currentUpdated = ( currentUpdated === true) ? true : ( moveX !== 0 || moveY !== 0);
2827                                                                 updateInfomation( _x, _y);
2828                                                         }                                                       
2829                                                 } else {
2830                                                         currentElement && COMIC_ELEMENT_CONSOLE.onMouseMove( _mouseX -x, _mouseY -y);
2831                                                         RESIZER.index( _mouseX, _mouseY) === -1 && MOUSE_CURSOR( '');
2832                                                 }
2833                                         },
2834                                         onMouseUp: function( _currentElement, _mouseX, _mouseY){
2835                                                 resize(
2836                                                         RESIZER.x(), RESIZER.y(), RESIZER.w(), RESIZER.h(),
2837                                                         currentIsTextElement === true ? currentElement.angle() : 0
2838                                                 );
2839                                                 currentElement && currentElement.resize( x, y, w, h);
2840                                                 MOUSE_CURSOR( '');
2841                                                 currentUpdated === true && saveState();
2842                                                 isDragging = currentUpdated = false;
2843                                         },
2844                                         onMouseClick: function( _mouseX, _mouseY){
2845                                                 //return currentElement ? COMIC_ELEMENT_CONSOLE.onMouseClick( _mouseX -x, _mouseY -y) : false;
2846                                         }
2847                                 }
2848                         })();
2849                         /*
2850                          *  // COMIC_ELEMENT_OPERATOR
2851                          */
2852                 
2853                         var AbstractComicElement = function( JQ_WAPPER, COMIC_ELM_TYPE, update, x, y, w, h, z, domIndex){
2854                                 var OPERATOR = COMIC_ELEMENT_OPERATOR;
2855                                 return {
2856                                         $: JQ_WAPPER,
2857                                         type: COMIC_ELM_TYPE,
2858                                         x: x,
2859                                         y: y,
2860                                         w: w,
2861                                         h: h,                                   
2862                                         z: z,
2863                                         domIndex: domIndex,
2864                                         hitareaX: function(){ return OPERATOR.hitareaX( this, this.x);},
2865                                         hitareaY: function(){ return OPERATOR.hitareaY( this, this.y);},
2866                                         hitareaW: function(){ return OPERATOR.hitareaW( this, this.w);},
2867                                         hitareaH: function(){ return OPERATOR.hitareaH( this, this.h);},
2868                                         shift: function( _shiftX, _shiftY){
2869                                                 update( this.x +_shiftX, this.y +_shiftY);
2870                                         },
2871                                         dragging: function(){
2872                                                 return OPERATOR.dragging();
2873                                         },
2874                                         onMouseMove: function( _mouseX, _mouseY){
2875                                                 OPERATOR.onMouseMove( this, _mouseX, _mouseY);
2876                                         },
2877                                         onMouseUp: function( _mouseX, _mouseY){
2878                                                 OPERATOR.onMouseUp( this, _mouseX, _mouseY);
2879                                         },
2880                                         onMouseDown: function( _mouseX, _mouseY){
2881                                                 OPERATOR.onMouseDown( this, _mouseX, _mouseY);
2882                                         }
2883                                 }
2884                         };
2885                 /*
2886                  * --------------------------------------------------------------------------------------------
2887                  * ImageElementClass
2888                  */
2889                         var     jqImageElementOrigin;
2890                         var ImageElementClass = function( url, IMAGE_SET_ID, x, y, z, w, h, domIndex){
2891                                 jqImageElementOrigin = jqImageElementOrigin || $( $( '#imgElementTemplete').remove().html());
2892                                 
2893                                 var JQ_WRAPPER = jqImageElementOrigin.clone( true),
2894                                         OPERATOR = COMIC_ELEMENT_OPERATOR,
2895                                         SAVE = HISTORY.saveState,
2896                                         HIT_AREA = MOUSE_HIT_AREA,
2897                                         reversibleImage = null,
2898                                         actualW = 0, actualH = 0,
2899                                         flipH = w < 0 ? -1 : 1,
2900                                         flipV = h < 0 ? -1 : 1,
2901                                         instance;
2902                                 w = Math.floor( w);
2903                                 h = Math.floor( h);
2904                                 
2905                                 function update( _x, _y, _w, _h, animate){
2906                                         instance.x = x = _x !== undefined ? _x : x;
2907                                         instance.y = y = _y !== undefined ? _y : y;
2908                                         instance.w = w = _w !== undefined ? _w : w;
2909                                         instance.h = h = _h !== undefined ? _h : h;
2910                                         JQ_WRAPPER[ animate === true ? 'animate' : 'css']( { 
2911                                                 left:   x,
2912                                                 top:    y,
2913                                                 width:  w,
2914                                                 height: h
2915                                         }, 250, function(){ reversibleImage.resize( flipH * w, flipV * h);});
2916                                         animate !== true && reversibleImage.resize( flipH * w, flipV * h);
2917                                 }
2918                                 
2919                                 function updateUrl( _url){
2920                                         if( url === _url) return;
2921                                         url = _url || url;
2922                                         var _reversibleImage = h2c.image.createReversibleImage( url, flipH * w, flipV * h, function( _url, _actualW, _actualH){
2923                                                 actualW = _actualW;
2924                                                 actualH = _actualH;
2925                                         });
2926                                         if( reversibleImage !== null){
2927                                                 JQ_WRAPPER.children( reversibleImage.elm).replaceWith( _reversibleImage.elm);
2928                                                 reversibleImage.destroy();
2929                                         } else {
2930                                                 JQ_WRAPPER.append( _reversibleImage.elm);
2931                                         }
2932                                         reversibleImage = _reversibleImage;
2933                                 }
2934                                 return h2c.util.extend(
2935                                         AbstractComicElement.apply( this, [ JQ_WRAPPER, COMIC_ELEMENT_TYPE_IMAGE, update, x, y, w, h, z, domIndex]),
2936                                         {
2937                                                 init: function(){
2938                                                         instance = this;
2939                                                         updateUrl();
2940                                                         update();
2941                                                         delete this.init;
2942                                                 },
2943                                                 flip: function( _flipH, _flipV){
2944                                                         if( _flipH !== true && _flipV !== true) return;
2945                                                         flipH = _flipH === true ? -flipH : flipH;
2946                                                         flipV = _flipV === true ? -flipV : flipV;
2947                                                         reversibleImage.resize( flipH * w, flipV * h);
2948                                                 },
2949                                                 flipV: function(){
2950                                                         return flipV;
2951                                                 },
2952                                                 flipH: function(){
2953                                                         return flipH;
2954                                                 },
2955                                                 url: function( _url, _actualW, _actualH){
2956                                                         if( _url && _url !== url){
2957                                                                 SAVE( updateUrl, url, _url);
2958                                                                 actualW = _actualW;
2959                                                                 actualH = _actualH;
2960                                                                 updateUrl( _url);
2961                                                         }
2962                                                         return url
2963                                                 },
2964                                                 actualW: function(){ return actualW;},
2965                                                 actualH: function(){ return actualH;},
2966                                                 resize: update,
2967                                                 animate: function ( _x, _y, _w, _h, _flipH, _flipV){
2968                                                         flipH = _flipH !== undefined ? _flipH : flipH;
2969                                                         flipV = _flipV !== undefined ? _flipV : flipV;
2970                                                         update( _x, _y, _w, _h, true);
2971                                                 },
2972                                                 getAsHtml: function(){
2973                                                         
2974                                                 },
2975                                                 getAsJson: function(){
2976                                                         
2977                                                 },
2978                                                 destroy: function(){
2979                                                         reversibleImage.destroy();
2980                                                         JQ_WRAPPER.remove();
2981                                                         JQ_WRAPPER = reversibleImage = OPERATOR = null;
2982                                                         delete this.destroy;
2983                                                 }
2984                                         }
2985                                 );
2986                         }
2987                 /*
2988                  * / ImageElementClass
2989                  * --------------------------------------------------------------------------------------------
2990                  */
2991
2992
2993                 /*
2994                  * --------------------------------------------------------------------------------------------
2995                  * TextElementClass
2996                  * 
2997                  * ELM はh2c.domで書き出したものを突っ込むcreateの場合
2998                  * 
2999                  * type
3000                  * 0.none
3001                  * 1.speach balloon
3002                  * 2.think
3003                  * 3.bom
3004                  * 4.black-box( dq style)
3005                  * 5.blue-box( ff style)
3006                  * 
3007                  */
3008                         var jqTextElementOrigin;
3009                         var TextElementClass = function( type, a, text, x, y, z, w, h, domIndex){
3010                                 jqTextElementOrigin = jqTextElementOrigin || ( function(){
3011                                         var _OLD_IE = $( $( '#textElementTempleteForOldIE').remove().html()),
3012                                                 _MODERN = $( $( '#textElementTemplete').remove().html());
3013                                         return h2c.isIE === true && h2c.ieRenderingVersion < 8 ? _OLD_IE : _MODERN;
3014                                 })();
3015                                 
3016                                 var JQ_WRAPPER = jqTextElementOrigin.clone( true),
3017                                         XBROWSER_BALLOON = h2c.balloon.createBalloon( w, h, a, type),
3018                                         TEXT_ELM = JQ_WRAPPER.find( 'td,.speach-inner').eq( 0),
3019                                         OPERATOR = COMIC_ELEMENT_OPERATOR,
3020                                         HIT_AREA = MOUSE_HIT_AREA,
3021                                         SAVE = HISTORY.saveState,
3022                                         instance;
3023                                         
3024                                 JQ_WRAPPER.find( 'img').eq( 0).replaceWith( XBROWSER_BALLOON.elm);
3025                                 
3026                                 function update( _x, _y, _w, _h, _a, animate){
3027                                         instance.x = x = _x !== undefined ? _x : x;
3028                                         instance.y = y = _y !== undefined ? _y : y;
3029                                         instance.w = w = _w !== undefined ? _w : w;
3030                                         instance.h = h = _h !== undefined ? _h : h;
3031                                         a = _a !== undefined ? _a : a;
3032                                         
3033                                         JQ_WRAPPER[ animate === true ? 'animate' : 'css']( {
3034                                                         left:           x,
3035                                                         top:            y,
3036                                                         width:          w,
3037                                                         height:         h
3038                                                 }, 250,
3039                                                 function(){
3040                                                         XBROWSER_BALLOON.resize( a, w, h);
3041                                                 }
3042                                         );              
3043                                         animate !== true && XBROWSER_BALLOON.resize( a, w, h);
3044                                 }
3045                                 
3046                                 function updateType( _type){
3047                                         if( type !== _type){
3048                                                 type = _type || type;
3049                                                 XBROWSER_BALLOON.type( type);
3050                                         }
3051                                 }
3052                                 function updateAngle( _a){
3053                                         if( _a !== undefined && a !== _a){
3054                                                 a = _a !== undefined ? _a : a;
3055                                                 XBROWSER_BALLOON.angle( a);
3056                                         }
3057                                 }
3058                                 function updateText( _text){
3059                                         text = _text || text || '';
3060                                         TEXT_ELM.html( text);
3061                                 }
3062                                 
3063                                 return h2c.util.extend(
3064                                         AbstractComicElement.apply( this, [ JQ_WRAPPER, COMIC_ELEMENT_TYPE_TEXT, update, x, y, w, h, z, domIndex]),
3065                                         {
3066                                                 init: function(){
3067                                                         instance = this;
3068                                                         updateText();
3069                                                         update();
3070                                                         delete this.init;
3071                                                 },
3072                                                 angle: function( _a){
3073                                                         _a !== undefined && update( NaN, NaN, NaN, NaN, _a);
3074                                                         return a;
3075                                                 },
3076                                                 text: function( _text){
3077                                                         if( _text && text !== _text) {
3078                                                                 SAVE( updateText, text || '', _text);
3079                                                                 updateText( _text);
3080                                                         }
3081                                                         return text;
3082                                                 },
3083                                                 resize: update,
3084                                                 animate: function ( _x, _y, _w, _h, _a){
3085                                                         update( _x, _y, _w, _h, _a, true);
3086                                                 },
3087                                                 destroy: function(){
3088                                                         JQ_WRAPPER.remove();
3089                                                         XBROWSER_BALLOON.destroy();
3090                                                         OPERATOR = null;
3091                                                         delete this.destroy;
3092                                                 },
3093                                                 getAsJSON: function(){
3094                                                         
3095                                                 },
3096                                                 getAsJsonString: function(){
3097                                                         
3098                                                 },
3099                                                 getAsHTML: function(){},
3100                                                 getAsXML: function(){}
3101                                                 
3102                                         }
3103                                 );
3104                         }
3105                 /*
3106                  * リサイズが、ResizerTopによって行われた場合、comicElementのyを動かして見かけ上動かないようにする。
3107                  */     
3108                         function resize( isResizerTopAction){
3109                                 if( isResizerTopAction === true){
3110                                         var     _shiftX = canvasW -_canvasW,
3111                                                 _shiftY = canvasH -_canvasH,
3112                                                 l = DRAGGABLE_ELEMENT_ARRAY.length;
3113                                         for( var i = NUM_RESIZER; i < l; i++){
3114                                                 DRAGGABLE_ELEMENT_ARRAY[ i].shift( _shiftX, _shiftY);
3115                                         }
3116                                 }
3117                                 _canvasW = canvasW;
3118                                 _canvasH = canvasH;
3119                                 
3120                                 comicElementContainer.css( {
3121                                         width:  _canvasW,
3122                                         height: _canvasH,
3123                                         top:    canvasY,
3124                                         left:   canvasX
3125                                 });
3126                         }
3127                 
3128                 /*
3129                  * append, remove, replace
3130                  * 
3131                  * comicElement には、z-position と dom-index がある。
3132                  *   z-position は 表示上の位置。大きいほど前に表示される( z-index)
3133                  *   dom-index は 意味上の順番。htmlタグの登場順で、検索結果や音声読み上げブラウザで正しく意味が取れる順番。
3134                  * 
3135                  * editerでは、実際には z-index は使わず、htmlの順序で前後を表現する。
3136                  * dom-index は、数値のみ保持して、投稿時にcomicElementを適宜に並び替える。
3137                  * 
3138                  * append comicElement
3139                  * 1. 新しい comicElement の z-position を得る
3140                  * 2. z の同じ comicElementを見つけ、その前に加える。または一番先頭へ。(DRAGGABLE_ELEMENT_ARRAY)
3141                  *    zが大きいほど、DRAGGABLE_ELEMENT_ARRAYの先頭へ。但しNUM_RESIZER番目より下。
3142                  * 3. dom位置は、DRAGGABLE_ELEMENT_ARRAY とは反対に、前のものほど後ろへ。
3143                  * 
3144                  * 
3145                  * remove comicElement
3146                  * 1. remove
3147                  * 2. renumber z
3148                  */
3149                         function appendComicElement( _comicElement) {
3150                                 _comicElement.init && _comicElement.init();
3151                                 var z = _comicElement.z,
3152                                         l = DRAGGABLE_ELEMENT_ARRAY.length;
3153                                 _comicElement.$.stop().css( {
3154                                         filter:         '',
3155                                         opacity:        ''
3156                                 });
3157                                 if( z === undefined || z === NaN || z < 0 || z >= l -NUM_RESIZER){
3158                                         DRAGGABLE_ELEMENT_ARRAY.splice( NUM_RESIZER, 0, _comicElement);
3159                                         comicElementContainer.append( _comicElement.$.fadeIn());
3160                                 } else {
3161                                         var insertIndex = ( function(){
3162                                                         for( var ret = NUM_RESIZER; ret < l; ++ret){
3163                                                                 if( DRAGGABLE_ELEMENT_ARRAY[ ret].z <= z) return ret +1;
3164                                                         }
3165                                                         return NUM_RESIZER;
3166                                                 })();
3167                                         DRAGGABLE_ELEMENT_ARRAY[ insertIndex -1].$.after( _comicElement.$.fadeIn());
3168                                         DRAGGABLE_ELEMENT_ARRAY.splice( insertIndex, 0, _comicElement);
3169                                 }
3170                                 sortComicElement();
3171                         }
3172                         function removeComicElement( _comicElement) {
3173                                 var l = DRAGGABLE_ELEMENT_ARRAY.length;
3174                                 for( var i=NUM_RESIZER; i<l; ++i){
3175                                         if( DRAGGABLE_ELEMENT_ARRAY[ i] === _comicElement){
3176                                                 DRAGGABLE_ELEMENT_ARRAY.splice( i, 1);
3177                                                 sortComicElement();
3178                                                 _comicElement.$.stop().css( {
3179                                                         filter:         '',
3180                                                         opacity:        ''
3181                                                 }).fadeOut( function(){
3182                                                         this.parentNode.removeChild( this);
3183                                                 });
3184                                                 currentElement = currentElement === _comicElement ? null : currentElement;
3185                                                 return;
3186                                         }
3187                                 }
3188                         }
3189                         function restoreComicElement( arg){
3190                                 var isAppend = arg[ 0],
3191                                         comicElement = arg[ 1];
3192                                 isAppend === true ? appendComicElement( comicElement) : removeComicElement( comicElement);
3193                         }
3194                         /*
3195                          * DRAGGABLE_ELEMENT_ARRAY の順番を基準に、zの再計算
3196                          * jqElmの並び替え。
3197                          */
3198                         function sortComicElement(){
3199                                 var l = DRAGGABLE_ELEMENT_ARRAY.length,
3200                                         _comicElement, jqElm, jqNext;
3201                                 for( var i=NUM_RESIZER; i < l; ++i){
3202                                         _comicElement = DRAGGABLE_ELEMENT_ARRAY[ i];
3203                                         jqElm = _comicElement.$;
3204                                         jqNext && jqNext.before( jqElm);
3205                                         _comicElement.z = l -i -NUM_RESIZER +1;
3206                                         jqNext = jqElm;
3207                                 }
3208                         }
3209                         function replaceComicElement( _comicElement, goForward){
3210                                 // DRAGGABLE_ELEMENT_ARRAYの再構築
3211                                 var l = DRAGGABLE_ELEMENT_ARRAY.length,
3212                                         i = ( function(){
3213                                                 for( var ret = NUM_RESIZER; ret < l; ++ret){
3214                                                         if( DRAGGABLE_ELEMENT_ARRAY[ ret] === _comicElement) return ret;
3215                                                 }
3216                                                 return -1;
3217                                         })();
3218                                 if( i === -1) return;
3219                                 if( goForward === true){
3220                                         if( i === NUM_RESIZER) return;
3221                                         DRAGGABLE_ELEMENT_ARRAY.splice( i, 1);
3222                                         DRAGGABLE_ELEMENT_ARRAY.splice( i -1, 0, _comicElement);
3223                                 } else {
3224                                         if( i === l -1) return;
3225                                         DRAGGABLE_ELEMENT_ARRAY.splice( i, 1);
3226                                         DRAGGABLE_ELEMENT_ARRAY.splice( i +1, 0, _comicElement);
3227                                 }
3228                                 sortComicElement();
3229                         }
3230                         function restoreReplaceObject( arg){
3231                                 replaceComicElement( arg[ 0], arg[ 1]);
3232                         }
3233                         
3234                         return {
3235                                 init: function(){
3236                                 /*
3237                                  * Resizer
3238                                  */                                     
3239                                         PANEL_RESIZER_TOP.init();
3240                                         PANEL_RESIZER_BOTTOM.init();
3241                                 /*
3242                                  * comic-element
3243                                  */
3244                                         comicElementContainer = $( '#comic-element-container');
3245                                         
3246                                         appendComicElement( ImageElementClass.apply( {}, [ 'images/13.gif', 'penchan', 10, 10, 0, 100, 140]));
3247                                         appendComicElement( TextElementClass.apply( {}, [ 0, 270, 'Hello', 50, 70, 1, 200, 160]));
3248                                         
3249                                         COMIC_ELEMENT_OPERATOR.init( updateMouseCursor);
3250                                 /*
3251                                  * 
3252                                  */
3253                                         log = $( '#operation-catcher-log');
3254
3255                                         resize();
3256                                         log.html( 'vector' +h2c.balloon.enabled());
3257                                         delete COMIC_ELEMENT_CONTROL.init;
3258                                 },
3259                                 resize: resize,
3260                                 onMouseMove: function( _mouseX, _mouseY){
3261                                         var l = DRAGGABLE_ELEMENT_ARRAY.length,
3262                                                 _X = _mouseX -( _canvasX || canvasX),
3263                                                 _Y = _mouseY -( _canvasY || canvasY),
3264                                                 _elm, _x, _y;
3265                                                 
3266                                         if( currentElement !== null && currentElement.dragging() === true){
3267                                                 currentElement.onMouseMove( _X, _Y);
3268                                                 return true;
3269                                         }
3270                                         if( currentElement !== null){
3271                                                 _x = currentElement.hitareaX();
3272                                                 _y = currentElement.hitareaY();
3273                                                 if( _x <= _X && _y <= _Y && _x + currentElement.hitareaW() >= _X && _y +currentElement.hitareaH() >= _Y){
3274                                                         currentElement.onMouseMove( _X, _Y); // cursor
3275                                                         return true;
3276                                                 }
3277                                         }
3278                                         for( var i=0; i<l; i++){
3279                                                 _elm = DRAGGABLE_ELEMENT_ARRAY[ i];
3280                                                 _x = _elm.hitareaX();
3281                                                 _y = _elm.hitareaY();
3282                                                 // hitTest
3283                                                 if( _x <= _X && _y <= _Y && _x + _elm.hitareaW() >= _X && _y +_elm.hitareaH() >= _Y){
3284                                                         currentElement = _elm;
3285                                                         currentElement.onMouseMove( _X, _Y); // cursor
3286                                                         log.html( [ _X, _Y, _x, _y, i].join( ','));
3287                                                         return true;
3288                                                 }
3289                                         }
3290                                         currentElement = null;                                                  
3291                                         COMIC_ELEMENT_OPERATOR.hide();
3292                                         log.html( [ _X, _Y, _x, _y].join( ','));
3293                                         return false;
3294                                 },
3295                                 onMouseUp: function( _mouseX, _mouseY){
3296                                         var ret = currentElement !== null && currentElement.dragging() === true;
3297                                         ret === true && currentElement.onMouseUp( _mouseX -_canvasX || canvasX, _mouseY -_canvasY || canvasY);
3298                                         _canvasX = _canvasY = NaN;
3299                                         return ret;
3300                                 },
3301                                 onMouseDown: function( _mouseX, _mouseY){
3302                                         _canvasX = canvasX;
3303                                         _canvasY = canvasY;
3304                                         currentElement !== null && currentElement.onMouseDown( _mouseX -canvasX, _mouseY -canvasY);
3305                                         return currentElement !== null;
3306                                 },
3307                                 onMouseClick: function( _mouseX, _mouseY){
3308                                         return currentElement !== null &&
3309                                                 currentElement !== PANEL_RESIZER_TOP &&
3310                                                 currentElement !== PANEL_RESIZER_BOTTOM &&
3311                                                 COMIC_ELEMENT_OPERATOR.onMouseClick( _mouseX -canvasX, _mouseY -canvasY);
3312                                 },
3313                                 onMouseOut: function( _mouseX, _mouseY){
3314                                         currentElement !== null && currentElement.dragging() === true && currentElement.onMouseUp( _mouseX -canvasX, _mouseY -canvasY);
3315                                         _canvasX = _canvasY = NaN;
3316                                         currentElement = null;
3317                                         COMIC_ELEMENT_OPERATOR.hide();
3318                                         return false;
3319                                 },
3320                                 busy: function(){
3321                                         return currentElement !== null ? currentElement.dragging() : false;
3322                                 },
3323                                 createImageElement: function( url, imagesetID, x, y, z, w, h){
3324                                         w = w || 200; //ActualWidth
3325                                         h = h || 150; //ActualHeight
3326                                         x = x || Math.floor( canvasW /2 -w /2);
3327                                         y = y || Math.floor( canvasH /2 -h /2);
3328                                         IMAGE_GROUP_EXPROLER.show( function( _url, _w, _h){
3329                                                 var _comicElement = ImageElementClass.apply( {}, [ _url, imagesetID, x, y, z || -1, w, h]);
3330                                                 appendComicElement( _comicElement);
3331                                                 _comicElement.animate( undefined, undefined, _w, _h);
3332                                                 SAVE( restoreComicElement, [ false, _comicElement], [ true, _comicElement], true);
3333                                         });
3334                                 },
3335                                 createTextElement: function( type, angle, text, x, y, z, w, h){
3336                                         type = type || 0;
3337                                         angle = angle || 0;
3338                                         text = text || '';
3339                                         w = w || 200;
3340                                         h = h || 150;
3341                                         x = x || Math.floor( canvasW /2 -w /2 +Math.random() *10);
3342                                         y = y || Math.floor( canvasH /2 -h /2 +Math.random() *10);
3343                                         var _comicElement = TextElementClass.apply( {}, [ type, angle, text, x, y, z || -1, w, h]);
3344                                         TEXT_EDITOR_CONTROL.show( _comicElement, function( _comicElement){
3345                                                 appendComicElement( _comicElement);
3346                                                 SAVE( restoreComicElement, [ false, _comicElement], [ true, _comicElement], true);
3347                                         });
3348                                 }
3349                         }
3350                 })( resize);
3351         
3352         /*
3353          * 
3354          */
3355                 function resize( isResizerTopAction){
3356                         GRID_CONTROL.resize();
3357                         WHITE_GLASS_CONTROL.resize();
3358                         PANEL_BORDER_CONTROL.resize();
3359                         COMIC_ELEMENT_CONTROL.resize( isResizerTopAction);
3360                 }
3361                 return {
3362                         init: function( _canvasW, _canvasH){
3363                                 canvasW = _canvasW || DEFAULT_PANEL_WIDTH;
3364                                 canvasH = _canvasH || DEFAULT_PANEL_HEIGHT;
3365                                 canvasX = Math.floor( ( windowW -canvasW) /2);
3366                                 canvasY = Math.floor( ( windowH -canvasH) /2);
3367                                 
3368                                 GRID_CONTROL.init();
3369                                 // WHITE_GLASS_CONTROL.init();
3370                                 PANEL_BORDER_CONTROL.init();
3371                                 COMIC_ELEMENT_CONTROL.init();
3372                                 
3373                                 resize();
3374                                 
3375                                 h2c.jqDocument()
3376                                         .bind( h2c.key.SPACE_DOWN_EVENT, function(){
3377                                                 hasFocus === true && isDragging === false && COMIC_ELEMENT_CONTROL.busy() === false && updateMouseCursor( 'crosshair');
3378                                         })
3379                                         .bind( h2c.key.SPACE_UP_EVENT, function(){
3380                                                 hasFocus === true && COMIC_ELEMENT_CONTROL.busy() === false && updateMouseCursor( '');  
3381                                                 isDragging = false;
3382                                         });
3383                                 
3384                                 delete CANVAS_CONTROL.init;
3385                         },
3386                         x: function(){ return canvasX;},
3387                         y: function(){ return canvasY;},
3388                         onWindowResize: function( _windowW, _windowH){
3389                                 canvasX = Math.floor(( _windowW - canvasW) / 2);
3390                                 canvasY = Math.floor(( _windowH - canvasH) / 2);
3391                                 resize();
3392                         },
3393                         onMouseMove: function( _mouseX, _mouseY){
3394                                 hasFocus = true;
3395                                 if( isDragging === true){
3396                                         canvasX = startCanvasX +_mouseX -xOffset;
3397                                         canvasY = startCanvasY +_mouseY -yOffset;
3398                                         resize();
3399                                 } else {
3400                                         COMIC_ELEMENT_CONTROL.onMouseMove( _mouseX, _mouseY)
3401                                 }
3402                         },
3403                         onMouseUp: function( _mouseX, _mouseY){
3404                                 if( COMIC_ELEMENT_CONTROL.onMouseUp( _mouseX, _mouseY) === false && isDragging === true){
3405                                         isDragging = false;
3406                                         updateMouseCursor( '');
3407                                 }
3408                         },
3409                         onMouseDown: function( _mouseX, _mouseY){
3410                                 if( COMIC_ELEMENT_CONTROL.onMouseDown( _mouseX, _mouseY) === false && isDragging === false && SPACE_ENABLED() === true){
3411                                         xOffset = _mouseX;
3412                                         yOffset = _mouseY;
3413                                         startCanvasX = canvasX;
3414                                         startCanvasY = canvasY;
3415                                         isDragging = true;
3416                                         updateMouseCursor( 'move');
3417                                 }
3418                         },
3419                         onMouseClick: function( _mouseX, _mouseY){
3420                                 COMIC_ELEMENT_CONTROL.onMouseClick( _mouseX, _mouseY)
3421                         },
3422                         onMouseOut: function( _mouseX, _mouseY){
3423                                 if( COMIC_ELEMENT_CONTROL.onMouseOut( _mouseX, _mouseY) === false){
3424                                         
3425                                 }
3426                         },
3427                         busy: function( _busy){
3428                                 hasFocus = !!_busy;
3429                                 return isDragging === true || COMIC_ELEMENT_CONTROL.busy();
3430                         },
3431                         createImageElement: function( url, imagesetID, x, y, z, w, h){
3432                                 COMIC_ELEMENT_CONTROL.createImageElement( url, imagesetID, x, y, z, w, h);
3433                         },
3434                         createTextElement: function( type, angle, text, x, y, w, h, z){
3435                                 COMIC_ELEMENT_CONTROL.createTextElement( type, angle, text, x, y, w, h, z);
3436                         }
3437                 }
3438         })();
3439
3440 /* ----------------------------------------
3441  *     Text Editor (Overlay)
3442  */
3443         
3444         var TEXT_EDITOR_CONTROL = ( function(){
3445                 var jqWrap, jqTextarea, jqButton,
3446                         textElement, onUpdateFunction;
3447                 
3448                 function close(){
3449                         jqWrap.hide();
3450                         textElement = onUpdateFunction = null;          
3451                 }               
3452                 return {
3453                         init: function(){
3454                                 this.jqWrap = jqWrap = $( '#speach-editor-wrapper').hide();
3455                                 jqTextarea = $( '#speach-editor');
3456                                 jqButton = $( '#speach-edit-complete-button').click( function(){
3457                                         h2c.overlay.hide();
3458                                         textElement && textElement.text( jqTextarea.val());
3459                                         onUpdateFunction && onUpdateFunction( textElement);
3460                                         close();
3461                                 });
3462                                 delete TEXT_EDITOR_CONTROL.init;
3463                         },
3464                         jqWrap: null,
3465                         show: function( _textElement, _onUpdateFunction){
3466                                 textElement = _textElement;
3467                                 onUpdateFunction = _onUpdateFunction || null;
3468                                 h2c.overlay.show( this);
3469                                 var h = _textElement.h;
3470                                 jqWrap.show().css( {
3471                                         left:                   _textElement.x +CANVAS_CONTROL.x(),
3472                                         top:                    _textElement.y +CANVAS_CONTROL.y(),
3473                                         width:                  _textElement.w,
3474                                         height:                 h
3475                                 });
3476                                 jqTextarea.val( _textElement.text()).focus();
3477                                 
3478                                 /*
3479                                  * ie6,7は、textarea { width:100%}でも高さが変わらない。rowsを設定。
3480                                  */
3481                                 h2c.isIE === true && h2c.ieVersion <= 7 && setTimeout( function(){
3482                                         var rows = 0;
3483                                         while( jqTextarea.height() < h){
3484                                                 rows++;
3485                                                 jqTextarea.attr( 'rows', rows);
3486                                         }
3487                                         rows > 1 && jqTextarea.attr( 'rows', rows -1);
3488                                 }, 0);
3489                         },
3490                         onWindowResize: function(){
3491                                 textElement && this.show( textElement);
3492                         },
3493                         onClose: close
3494                 }
3495         })();
3496
3497 /* ----------------------------------------
3498  *     Image Group Exproler (Overlay)
3499  */
3500         var IMAGE_GROUP_EXPROLER = ( function(){
3501                 var ICON_ARRAY = [],
3502                         WHEEL_DELTA = 64,
3503                         containerW, containerH, wrapX,
3504                         jqWrap, jqContainer, jqItemOrigin,
3505                         itemW, itemH,
3506                         jqName, jqButton, buttonW,
3507                         onUpdateFunction,
3508                         winW,
3509                         onEnterInterval = null;
3510                 
3511                 var BASE_PATH = h2c.LOCAL === false ? 'http://pettan.heroku.com/images/' : 'images/',
3512                         THUMB_PATH = BASE_PATH, // + 'thumbnail/',
3513                         LIMIT_FILESIZE = 1024 * 10; // 10KB
3514                 var IMAGE_DATA = {
3515                                 pen001: [
3516                                     {
3517                                         "created_at": "2011-11-13T08:57:39Z", 
3518                                         "ext": "png", 
3519                                         "filesize": 9969, 
3520                                         "height": 463, 
3521                                         "id": 1, 
3522                                         "updated_at": "2011-11-13T08:57:39Z", 
3523                                         "width": 441
3524                                     }, 
3525                                     {
3526                                         "created_at": "2011-11-13T08:57:54Z", 
3527                                         "ext": "gif", 
3528                                         "filesize": 5418, 
3529                                         "height": 500, 
3530                                         "id": 2, 
3531                                         "updated_at": "2011-11-13T08:57:54Z", 
3532                                         "width": 500
3533                                     }, 
3534                                     {
3535                                         "created_at": "2011-11-13T08:58:06Z", 
3536                                         "ext": "gif", 
3537                                         "filesize": 8758, 
3538                                         "height": 464, 
3539                                         "id": 3, 
3540                                         "updated_at": "2011-11-13T08:58:06Z", 
3541                                         "width": 366
3542                                     }, 
3543                                     {
3544                                         "created_at": "2011-11-13T08:58:23Z", 
3545                                         "ext": "gif", 
3546                                         "filesize": 9383, 
3547                                         "height": 480, 
3548                                         "id": 4, 
3549                                         "updated_at": "2011-11-13T08:58:23Z", 
3550                                         "width": 392
3551                                     }, 
3552                                     {
3553                                         "created_at": "2011-11-13T08:58:33Z", 
3554                                         "ext": "gif", 
3555                                         "filesize": 11061, 
3556                                         "height": 500, 
3557                                         "id": 5, 
3558                                         "updated_at": "2011-11-13T08:58:33Z", 
3559                                         "width": 500
3560                                     }, 
3561                                     {
3562                                         "created_at": "2011-11-20T09:50:43Z", 
3563                                         "ext": "gif", 
3564                                         "filesize": 1131, 
3565                                         "height": 126, 
3566                                         "id": 6, 
3567                                         "updated_at": "2011-11-20T09:50:43Z", 
3568                                         "width": 259
3569                                     }, 
3570                                     {
3571                                         "created_at": "2011-11-20T09:50:55Z", 
3572                                         "ext": "gif", 
3573                                         "filesize": 1125, 
3574                                         "height": 126, 
3575                                         "id": 7, 
3576                                         "updated_at": "2011-11-20T09:50:55Z", 
3577                                         "width": 259
3578                                     }, 
3579                                     {
3580                                         "created_at": "2011-11-20T11:33:12Z", 
3581                                         "ext": "gif", 
3582                                         "filesize": 17919, 
3583                                         "height": 600, 
3584                                         "id": 8, 
3585                                         "updated_at": "2011-11-20T11:33:12Z", 
3586                                         "width": 800
3587                                     },
3588                                     {
3589                                         "created_at": "2011-11-20T11:33:12Z", 
3590                                         "ext": "gif", 
3591                                         "filesize": 17919, 
3592                                         "height": 600, 
3593                                         "id": 9, 
3594                                         "updated_at": "2011-11-20T11:33:12Z", 
3595                                         "width": 800
3596                                     },
3597                                     {
3598                                         "created_at": "2011-11-20T11:33:12Z", 
3599                                         "ext": "gif", 
3600                                         "filesize": 17919, 
3601                                         "height": 600, 
3602                                         "id": 10, 
3603                                         "updated_at": "2011-11-20T11:33:12Z", 
3604                                         "width": 800
3605                                     },
3606                                     {
3607                                         "created_at": "2011-11-20T11:33:12Z", 
3608                                         "ext": "gif", 
3609                                         "filesize": 17919, 
3610                                         "height": 600, 
3611                                         "id": 11, 
3612                                         "updated_at": "2011-11-20T11:33:12Z", 
3613                                         "width": 800
3614                                     },
3615                                     {
3616                                         "created_at": "2011-11-22T09:17:20Z", 
3617                                         "ext": "gif", 
3618                                         "filesize": 9055, 
3619                                         "height": 473, 
3620                                         "id": 12, 
3621                                         "updated_at": "2011-11-22T09:17:20Z", 
3622                                         "width": 405
3623                                     }, 
3624                                     {
3625                                         "created_at": "2011-11-22T10:11:07Z", 
3626                                         "ext": "gif", 
3627                                         "filesize": 8758, 
3628                                         "height": 464, 
3629                                         "id": 13, 
3630                                         "updated_at": "2011-11-22T10:11:07Z", 
3631                                         "width": 366
3632                                     }, 
3633                                     {
3634                                         "created_at": "2011-11-24T09:05:12Z", 
3635                                         "ext": "gif", 
3636                                         "filesize": 6431, 
3637                                         "height": 386, 
3638                                         "id": 16, 
3639                                         "updated_at": "2011-11-24T09:05:12Z", 
3640                                         "width": 453
3641                                     }, 
3642                                     {
3643                                         "created_at": "2011-11-26T04:52:12Z",
3644                                         "ext": "gif", 
3645                                         "filesize": 6421, 
3646                                         "height": 426, 
3647                                         "id": 17, 
3648                                         "updated_at": "2011-11-26T04:52:12Z", 
3649                                         "width": 306
3650                                     }, 
3651                                     {
3652                                         "created_at": "2011-11-26T04:52:12Z",
3653                                         "ext": "gif", 
3654                                         "filesize": 6421, 
3655                                         "height": 426, 
3656                                         "id": 18, 
3657                                         "updated_at": "2011-11-26T04:52:12Z", 
3658                                         "width": 306
3659                                     }, 
3660                                     {
3661                                         "created_at": "2011-11-26T04:52:12Z",
3662                                         "ext": "gif", 
3663                                         "filesize": 6421, 
3664                                         "height": 426, 
3665                                         "id": 19, 
3666                                         "updated_at": "2011-11-26T04:52:12Z", 
3667                                         "width": 306
3668                                     }, 
3669                                     {
3670                                         "created_at": "2011-11-26T04:52:12Z",
3671                                         "ext": "gif", 
3672                                         "filesize": 6421, 
3673                                         "height": 426, 
3674                                         "id": 20, 
3675                                         "updated_at": "2011-11-26T04:52:12Z", 
3676                                         "width": 306
3677                                     }, 
3678                                     {
3679                                         "created_at": "2011-11-26T04:52:12Z",
3680                                         "ext": "gif", 
3681                                         "filesize": 6421, 
3682                                         "height": 426, 
3683                                         "id": 21, 
3684                                         "updated_at": "2011-11-26T04:52:12Z",
3685                                         "width": 306
3686                                     }
3687                                 ]
3688                         }
3689                 
3690                 var ImageGroupIconClass = function( INDEX, data){
3691                         var JQ_ICON_WRAP = jqItemOrigin.clone( true),
3692                                 SRC = [ BASE_PATH, data.id, '.', data.ext].join( ''),
3693                                 LOW_SRC = data.filesize && data.filesize > LIMIT_FILESIZE ? [ THUMB_PATH, data.id, '.', data.ext].join( '') : null,
3694                                 reversibleImage = null,
3695                                 onEnterFlag = false;
3696                         JQ_ICON_WRAP.children( 'div').eq( 0).html( data.filesize + 'bytes');
3697                         jqContainer.append( JQ_ICON_WRAP.css( { left: INDEX * itemW}));
3698                         
3699                         return {
3700                                 onEnter: function(){
3701                                         if( onEnterFlag === true) return;
3702                                         reversibleImage = h2c.image.createReversibleImage( LOW_SRC || SRC, itemW, itemH, function( url, imgW, imgH){
3703                                                 if( reversibleImage === null) {
3704                                                         alert( url);
3705                                                         return;
3706                                                 }
3707                                                 /*
3708                                                  * ieでサイズが取れない、、、
3709                                                  */
3710                                                 imgW = imgW || data.width || 64;
3711                                                 imgH = imgH || data.height || 64;
3712                                                 JQ_ICON_WRAP.children( 'div').eq( 1).html( imgW +'x' +imgH);
3713                                                 var zoom = 128 /( imgW > imgH ? imgW : imgH),
3714                                                         h = Math.floor( imgH *zoom),
3715                                                         w = Math.floor( imgW *zoom);
3716                                                 reversibleImage.elm.style.width = w +'px';
3717                                                 reversibleImage.elm.style.height = h +'px';
3718                                                 reversibleImage.elm.style.margin = Math.floor( itemH /2 -h /2)+'px 0 0';
3719                                                 reversibleImage.resize( w, h);
3720                                                 JQ_ICON_WRAP.click( function( e){
3721                                                         h2c.overlay.hide();
3722                                                         if (onUpdateFunction) {
3723                                                                 if( LOW_SRC === null){
3724                                                                         onUpdateFunction( SRC, imgW, imgH);
3725                                                                 } else {
3726                                                                         ( function( onUpdate){
3727                                                                                 h2c.util.loadImage( SRC,
3728                                                                                         function( _abspath, imgW, imgH){
3729                                                                                                 onUpdate( SRC, imgW, imgH);
3730                                                                                                 onUpdate = null;
3731                                                                                         },
3732                                                                                         function( _abspath){
3733                                                                                                 onUpdate( SRC, data.width || 64, data.height || 64);
3734                                                                                                 onUpdate = null;
3735                                                                                         }
3736                                                                                 );                                                                              
3737                                                                         })( onUpdateFunction); // close()で値が消えるので、クロージャに保持
3738                                                                 }
3739                                                         }
3740                                                         close();
3741                                                 });
3742                                         });
3743                                         JQ_ICON_WRAP.children( 'img').replaceWith( reversibleImage.elm);
3744                                         onEnterFlag = true;                             
3745                                 },
3746                                 destroy: function(){
3747                                         reversibleImage && reversibleImage.destroy();
3748                                         JQ_ICON_WRAP.remove();
3749                                         reversibleImage = JQ_ICON_WRAP = null;
3750                                         delete this.destroy;
3751                                 }
3752                         }
3753                 }
3754                 
3755                 function close(){
3756                         jqContainer.stop().animate( {
3757                                         height: 0,
3758                                         top:    Math.floor( windowH /2)
3759                                 }, function(){
3760                                         jqWrap.hide()
3761                                 });
3762                         while( ICON_ARRAY.length > 0){
3763                                 ICON_ARRAY.shift().destroy();
3764                         }
3765                         onEnterInterval !== null && window.clearTimeout( onEnterInterval);
3766                         onUpdateFunction = onEnterInterval = null;
3767                 }
3768                 function onEnterShowImage(){
3769                         var l = ICON_ARRAY.length,
3770                                 _start = -wrapX /itemW -1,
3771                                 _end = _start + winW /itemW +1;
3772                         for( var i=0; i<l; ++i){
3773                                 _start < i && i < _end && ICON_ARRAY[ i].onEnter();
3774                         }
3775                         onEnterInterval !== null && window.clearTimeout( onEnterInterval);
3776                         onEnterInterval = null;
3777                 }
3778                 return {
3779                         init: function(){
3780                                 this.jqWrap = jqWrap = $( '#image-gruop-wrapper').hide();
3781                                 jqContainer = $( '#image-icon-container').mousewheel(
3782                                         function( e, delta){
3783                                                 if( winW < containerW){
3784                                                         wrapX += delta *WHEEL_DELTA;
3785                                                         wrapX = wrapX > 0 ? 0 : wrapX < winW -containerW ? winW -containerW : wrapX;
3786                                                         jqContainer.css( { left: wrapX});
3787                                                         
3788                                                         onEnterInterval !== null && window.clearTimeout( onEnterInterval);
3789                                                         onEnterInterval = window.setTimeout( onEnterShowImage, 500);
3790                                                 }
3791                                                 //e.stopPropagation();
3792                                                 return false;
3793                                         });
3794                                 containerH = h2c.util.getElementSize( jqContainer.get( 0)).height;
3795                                 jqItemOrigin = $( $( '#imageGruopItemTemplete').remove().html());
3796                                 var itemSize = h2c.util.getElementSize( jqItemOrigin.get( 0));
3797                                 itemW = itemSize.width;
3798                                 itemH = itemSize.height;
3799                                 jqName = $( '#gruop-name-display');
3800                                 jqButton = $( '#image-gruop-button').click( function(){
3801                                         h2c.overlay.hide();
3802                                         // onUpdateFunction && onUpdateFunction( textElement);
3803                                         close();
3804                                 });
3805                                 buttonW = h2c.util.getElementSize( jqButton.get( 0)).width;
3806                                 delete IMAGE_GROUP_EXPROLER.init;
3807                         },
3808                         jqWrap: null,
3809                         show: function( _onUpdateFunction){
3810                                 onUpdateFunction = _onUpdateFunction;
3811                                 h2c.overlay.show( this);
3812                                 
3813                                 var CURRENT_GROUP_ARRAY = IMAGE_DATA[ 'pen001'] || [],
3814                                         l = CURRENT_GROUP_ARRAY.length;
3815                                 for( var i=0; i<l; ++i){
3816                                         ICON_ARRAY.push( ImageGroupIconClass.apply( {}, [ i, CURRENT_GROUP_ARRAY[ i]]));
3817                                 }
3818                                 wrapX = 0;
3819                                 containerW = l * itemW;
3820                                 
3821                                 winW = windowW;
3822                                 var w = winW > containerW ? winW : containerW,
3823                                         h = windowH > containerH ? containerH : windowH;
3824                                 
3825                                 jqWrap.show();
3826                                 jqContainer.css( {
3827                                         width:          w,
3828                                         height:         0,
3829                                         left:           0,
3830                                         top:            Math.floor( windowH /2)
3831                                 }).stop().animate( {
3832                                         height:         h,
3833                                         top:            Math.floor( windowH /2 -h /2)
3834                                 });
3835                                 
3836                                 jqButton.css( {
3837                                         left:           Math.floor( winW /2 -buttonW /2),
3838                                         top:            Math.floor( windowH /2 +containerH /2 +10)
3839                                 });
3840                                 
3841                                 onEnterShowImage();
3842                         },
3843                         onWindowResize: function( _windowW, _windowH){
3844                                 var w = _windowW > containerW ? _windowW : containerW,
3845                                         h = _windowH > containerH ? containerH : _windowH,
3846                                         offsetW = Math.floor( _windowW /2 -winW /2);
3847                                 winW = _windowW;
3848                                 if( offsetW <= 0){ // smaller
3849                                         jqContainer.css( {
3850                                                 left:                           offsetW,
3851                                                 width:                          w
3852                                         }).animate( {
3853                                                 left:                           0,
3854                                                 top:                            Math.floor( _windowH /2 -h /2)
3855                                         });                                     
3856                                 } else {
3857                                         jqContainer.css( { // bigger
3858                                                 left:                           0,
3859                                                 width:                          w,
3860                                                 borderLeftWidth:        offsetW
3861                                         }).animate( {
3862                                                 top:                            Math.floor( _windowH /2 -h /2),
3863                                                 borderLeftWidth:        0
3864                                         });
3865                                 }
3866                                 jqButton.css( {
3867                                         left:           Math.floor( _windowW /2 -buttonW /2),
3868                                         top:            Math.floor( _windowH /2 +containerH /2 +10)
3869                                 });
3870                                 onEnterShowImage();
3871                         },
3872                         onClose: close
3873                 }
3874         })();
3875
3876         function updateMouseCursor( _cursor){
3877                 if( currentCursor !== _cursor){
3878                         currentCursor = _cursor;
3879                         ELM_MOUSE_EVENT_CHATCHER.style.cursor = _cursor;
3880                 }
3881         }
3882         function centering(){
3883                 h2c.editor.onWindowResize( windowW, windowH);
3884         }       
3885         function mouseEventRellay( rellayMethod, e){
3886                 var _mouseX = e.pageX,
3887                         _mouseY = e.pageY;
3888                 if( currentListener !== null && currentListener.busy() === true){
3889                         currentListener[ rellayMethod]( _mouseX, _mouseY);
3890                 } else {
3891                         currentListener = null;
3892                         var l = MOUSE_LISTENER_ARRAY.length,
3893                                 _listener;
3894                         for( var i=0; i<l; ++i){
3895                                 _listener = MOUSE_LISTENER_ARRAY[ i];
3896                                 if( typeof _listener[ rellayMethod] === 'function' && _listener[ rellayMethod]( _mouseX, _mouseY) === true){
3897                                         currentListener = _listener;
3898                                         break;
3899                                 } else {
3900                                         _listener.busy( false);
3901                                 }
3902                         }
3903                 }
3904                 e.stopPropagation();
3905                 return false;
3906         }
3907
3908         return {
3909                 init: function(){
3910                         var jqWindow = h2c.jqWindow();
3911                         windowW = jqWindow.width();
3912                         windowH = jqWindow.height();
3913                         
3914                         jqEditor = $( '#editor');
3915
3916                         h2c.key.addKeyEvent( 96, false, true, centering);
3917                         h2c.key.addKeyEvent( 48, false, true, centering);
3918
3919                         HISTORY.init();
3920                         MENU_BAR_CONTROL.EDIT.createSelection( 'centering', 'ctrl + 0', centering, true, true, true);
3921                         
3922                         WINDOWS_CONTROL.init();
3923                         CANVAS_CONTROL.init();
3924                         
3925                         // last
3926                         MENU_BAR_CONTROL.init();
3927                         
3928                         TEXT_EDITOR_CONTROL.init();
3929                         IMAGE_GROUP_EXPROLER.init();
3930                 /*
3931                  * jqMouseEventChacher は透明な要素で、
3932                  * マウスイベントをcurrentElement(currentElement)に伝えるのが仕事
3933                  * このような実装になるのは、ここの表示オブジェクトにイベントを設定した場合、表示が追いつかずマウスカーソルが外れたタイミングでイベントが終わってしまうため。
3934                  */
3935                 /*
3936                  * MOUSE_LISTENER_ARRAY は、表示順に格納.手前の要素が最初
3937                  * MENU_BAR_CONTROL,
3938                  * WINDOW_CONTROL,
3939                  * CANVAS_CONTROL
3940                  * .busy() === true なら、そのままonMouseMove()にイベントを流す.これはArrayの後ろから、奥の表示要素から
3941                  * onMouseMove()に流してみて、false が帰れば、次にリスナーにも流す.
3942                  */
3943                         MOUSE_LISTENER_ARRAY.push( MENU_BAR_CONTROL, WINDOWS_CONTROL, CANVAS_CONTROL);
3944                         
3945                         jqMouseEventChacher = $( ELM_MOUSE_EVENT_CHATCHER)
3946                                 .mousemove( function( e){
3947                                         return mouseEventRellay( 'onMouseMove', e);
3948                                 }).mousedown( function( e){
3949                                         return mouseEventRellay( 'onMouseDown', e);
3950                                 }).mouseup( function( e){
3951                                         return mouseEventRellay( 'onMouseUp', e);
3952                                 }).mouseout( function( e){
3953                                         return mouseEventRellay( 'onMouseUp', e);
3954                                 }).click( function( e){
3955                                         var _mouseX = e.pageX,
3956                                                 _mouseY = e.pageY;
3957                                         if( CANVAS_CONTROL.busy() === true || WINDOWS_CONTROL.onMouseClick( _mouseX, _mouseY) === false){
3958                                                 CANVAS_CONTROL.onMouseClick( _mouseX, _mouseY);
3959                                         }
3960                                         e.stopPropagation();
3961                                         return false;
3962                                 }).css( {
3963                                         height: windowH // ie6
3964                                 });
3965                         
3966                         delete h2c.editor.init;
3967                 },
3968                 onWindowResize: function( _windowW, _windowH){
3969                         windowW = _windowW;
3970                         windowH = _windowH;
3971                         
3972                         /*
3973                          * ieは +'px'が不要みたい
3974                          */
3975                         jqEditor.get( 0).style.height = _windowH +'px';
3976                         ELM_MOUSE_EVENT_CHATCHER.style.height = _windowH +'px';
3977                         
3978                         WINDOWS_CONTROL.onWindowResize( _windowW, _windowH);
3979                         MENU_BAR_CONTROL.onWindowResize( _windowW, _windowH);
3980                         CANVAS_CONTROL.onWindowResize( _windowW, _windowH);
3981                 },
3982                 MIN_WIDTH:      320,
3983                 MIN_HEIGHT:     320
3984         }
3985 })();
3986
3987 h2c.log = ( function(){
3988         return {
3989                 init: function(){}
3990         }
3991 })();
3992
3993 h2c.io = ( function(){
3994         
3995         return {
3996                 init: function(){}
3997         }
3998 })();
3999
4000
4001 /*
4002  * 画像一覧は
4003  *      お気に入り画像一覧 > tag:ペン次郎 > ペン次郎:笑う
4004  *  最近アップロードされた画像 > images
4005  *  最近使われた画像 > images
4006  *  キャラクター画像庫 > アニマル系 > tag:ペン次郎 > ペン次郎:笑う
4007  *  風景画像庫 >
4008  *  効果画像庫 >
4009  *  アイテム画像庫 >
4010  *  
4011  * 画像一覧を読み込むタイミング
4012  */
4013 h2c.file = ( function(){
4014         var TREE_TYPE_IS_COMIC = 1,
4015                 TREE_TYPE_IS_IMAGE = 2,
4016                 TREE_TYPE_IS_SETTING = 3,
4017                 TREE_TYPE_IS_HELP = 4,
4018                 FILE_TYPE_IS_FOLDER = 1,
4019                 FILE_TYPE_IS_IMAGE = 2,
4020                 FILE_TYPE_IS_PANEL = 3,
4021                 FILE_TYPE_IS_SETTING = 4,
4022                 FILE_TYPE_IS_HTML = 5,
4023                 FILE_STATE_IS_UNKNOWN = 0,
4024                 FILE_STATE_IS_OK = 1,
4025                 FILE_STATE_IS_LOADING = 2,
4026                 FILE_STATE_IS_ERROR = 3,
4027                 FILE_STATE_IS_BROKEN = 4,
4028                 TREE_EVENT_UPDTE = 'onUpdate',
4029                 FILE_EVENT_UPDATED_ATTRIVUTE = 'onUpdate',
4030                 FILE_EVENT_GET_SEQENTIAL_FILES = 'gotSeqentilFiles',
4031                 FILEDATA_RESITER = [],
4032                 FILEDATA_ACCESS = [];
4033                 
4034         var REQUEST_CONTROLER = ( function(){
4035                 var REQUEST_TICKET_RESISTER = [],
4036                         DATA_IS_JSON = 1;
4037                 
4038                 var RequestTicketClass = ( function(){
4039                         
4040                 })();
4041                 
4042                 return {
4043                         init: function(){
4044                                 delete REQUEST_CONTROLER.init;
4045                         },
4046                         getJson: function( _url, _onLoad, _onError){
4047                                 REQUEST_TICKET_RESISTER.push( RequestTicketClass.apply( {}, [ _url, _onLoad, _onError]));
4048                         }
4049                 }
4050         })();
4051         /* ----------------------
4052          * folder
4053          *  name
4054          *  file [],
4055          *  ID( imgGroupID, comicID)
4056          * ----------------------
4057          * 
4058          * img-group(folder)
4059          *  name - rename,
4060          *  groupID,
4061          *  img []
4062          *  author, licence,
4063          *  create, update
4064          * 
4065          * img
4066          *  name - rename
4067          *  src(id)
4068          *  groupID - updateGropuID
4069          *  actualWidth, actualHeight,
4070          *  author, licence( 'by,no-resize'),
4071          *  create, update, tag,
4072          *  actualWidth, actualHeight
4073          * 
4074          * ----------------------
4075          * 
4076          * comic
4077          *  id
4078          *  name - rename
4079          *  width
4080          *  editmode
4081          *  panel []
4082          *  
4083          * panel
4084          *  comicID,
4085          *  seqno,
4086          *      height,
4087          *  border,
4088          *  elments [
4089          *    height,
4090          *    bg-color,
4091          *    bg-image,
4092          *    bg-position,
4093          *    bg-repeate,
4094          *    border,  
4095          *  ]
4096          *  
4097          * ----------------------
4098          */
4099         var FILE_CONTROLER = ( function(){
4100                 var FILE_EVENT_LISTENER_RESISTER = [],
4101                         TREE_ACCESS = [];
4102
4103                 var TreeClass = function( TREE_ROOTFILE){
4104                         var UID = TREE_ACCESS.length,
4105                                 currentFile = TREE_ROOTFILE,
4106                                 PARENT_FILE_RESITER = [],
4107                                 ACCESS = {
4108                                         fileEventChatcher:      dispatchFileEvent,
4109                                         destroy:                        onDestroy
4110                                 };
4111                         
4112                         function dispatchFileEvent( fileEvent){
4113                                 
4114                         }
4115                         function onDestroy(){
4116                                 
4117                         }
4118                         
4119                         TREE_ACCESS.push( ACCESS);
4120                         
4121                         FILE_CONTROLER.getSeqentialFiles( currentFile);
4122                         return {
4123                                 ROOT_FILE :function(){
4124                                         return TREE_ROOTFILE;
4125                                 },
4126                                 currentFile: function(){
4127                                         return currentFile;
4128                                 },
4129                                 hierarky: function(){
4130                                         return PARENT_FILE_RESITER.length;
4131                                 },
4132                                 down: function( _index){
4133                                         if( typeof _index !== 'number' || _index < 0 || _index >= currentFile.getChildFileLength()) return;
4134                                         PARENT_FILE_RESITER.unshift( currentFile);
4135                                         currentFile = currentFile.getChildFileByIndex( _index);
4136                                         FILE_CONTROLER.getSeqentialFiles( currentFile);
4137                                         return currentFile;
4138                                 },
4139                                 up: function(){
4140                                         if( PARENT_FILE_RESITER.length === 0) return;
4141                                         currentFile = PARENT_FILE_RESITER.shift();
4142                                         FILE_CONTROLER.getSeqentialFiles( currentFile);
4143                                         return currentFile;
4144                                 },
4145                                 addEventListener: function( UID, _eventType, _callback){
4146                                         FILE_CONTROLER.addEventListener( UID, _eventType, _callback);
4147                                 },
4148                                 removeEventListener: function( UID, _eventType, _callback){
4149                                         FILE_CONTROLER.removeEventListener( UID, _eventType, _callback);
4150                                 },
4151                                 createSearchResultFolder: function( _searchParam){
4152                                         
4153                                 },
4154                                 destroySearchResultFolder: function( _searchParam){
4155                                         
4156                                 },
4157                                 destroy: function(){
4158                                         FILE_CONTROLER.destroyTree( UID);
4159                                 }
4160                         }
4161                 };
4162
4163                 var FileEventTicketClass = function( UID, _eventType, _callback){
4164                         return {
4165                                 fileUID:        UID,
4166                                 eventType:      _eventType,
4167                                 callBack:       _callback
4168                         }
4169                 }
4170                 
4171                 var FileEventClass = function( eventType, file, key, value){
4172                         return {
4173                                 eventType:                      eventType,
4174                                 targetFile:                     file,
4175                                 updatedAttribute:       key,
4176                                 updatedValue:           value
4177                         }
4178                 }
4179
4180                 function disptchFileEvent( eventType, fileUID, key, value){
4181                         var _fileEvent = FileEventClass.apply( {}, [ eventType, fileUID, key, value]),
4182                                 l = TREE_ACCESS.length,
4183                                 _tree;
4184                         for( var i=0; i<l; ++i){
4185                                 _tree = TREE_ACCESS[ i];
4186                                 _tree !== null && _tree.fileEventChatcher( _fileEvent);
4187                         }
4188                 }
4189                 function getFileDataAccess( UIDorFILE){
4190                         var l = FILEDATA_ACCESS.length,
4191                                 i = typeof UIDorFILE === 'number' ?
4192                                                 ( UIDorFILE > 0 && UIDorFILE > l ? UIDorFILE : -1) :
4193                                                 ( function(){
4194                                                         for( var i=0; i<l; ++i){
4195                                                                 if( FILEDATA_ACCESS[ i] === UIDorFILE) return i;
4196                                                         }
4197                                                         return -1;
4198                                                 })();
4199                         return i !== -1 ? FILEDATA_ACCESS[ i] : null;
4200                 }
4201                 
4202                 return {
4203                         init: function(){
4204                                 delete FILE_CONTROLER.init;
4205                         },
4206                         createTree: function( _rootFileData){
4207                                 return TreeClass.apply( {}, [ _rootFileData]);
4208                         },
4209                         getFileData: function( _file){
4210                                 var _access = getFileDataAccess( _file);
4211                                 return _access !== null ? _access.DATA : null;
4212                         },
4213                         getSeqentialFiles: function( _uid){
4214
4215                         },
4216                         updateFileAttribute: function( _uid, key, _value, _opt_callback){
4217                                 var _fileData = getFileDataAccess( _uid),
4218                                         _type = _fileData.TYPE;
4219                                 
4220                         },                      
4221                         getFileAttribute: function( _uid, KEYorKEYARRAY){
4222                                 var _fileData = getFileDataAccess( _uid),
4223                                         _type = _fileData.TYPE;
4224                         },
4225                         move: function( _prentUID, _targetfile, _newFolder, _newIndex, _opt_callback){
4226                                 var _parentData = getFileDataAccess( _prentUID),
4227                                         _parentType = _parentData.TYPE,
4228                                         _targetData =  getFileDataAccess( _targetfile),
4229                                         _targetType = _targetData.TYPE;
4230                         },
4231                         replace: function( _uid, _file, _newIndex){
4232                                 
4233                         }
4234                 }
4235         })();
4236         
4237         /*
4238          * fileのdataはobjectで保持している。
4239          * h2c.file.の外からファイルをみるときは、FileClassを通して操作する。
4240          * fileの変更、それに付随して追加されたイベントは、treeで管理される。
4241          * treeがdestryされると、fileのイベントリスナーも全て削除される。
4242          */
4243         
4244         var FileClass = function( TREE, PARENT_FILE, DATA){
4245                 var TYPE = DATA.type,
4246                         UID = FILEDATA_ACCESS.length,
4247                         CHILDREN = DATA.children;
4248                 
4249                 FILEDATA_ACCESS.push(
4250                         {
4251                                 TYPE:           TYPE,
4252                                 DATA:           DATA,
4253                                 CHILDREN:       CHILDREN,
4254                                 destroy:        function(){
4255                                                                 PARENT_FILE = DATA = CHILDREN = null;
4256                                                                 delete this.destroy;
4257                                                         }
4258                         }
4259                 );
4260                 return {
4261                         TYPE: function(){ return TYPE;},
4262                         state: function(){
4263                                 return DATA.state !== undefined ? DATA.state : FILE_STATE_IS_OK;
4264                         },
4265                         childFileLength: function(){
4266                                 return typeof CHILDREN === 'array' ? CHILDREN.length : 0;
4267                         },
4268                         getChildFileByIndex: function( _index){
4269                                 if( typeof _index !== 'number' || _index < 0 || typeof CHILDREN !== 'array' || _index >= CHILDREN.length) return;
4270                                 return FileClass.apply( {}, [ TREE, PARENT_FILE, this, CHILDREN[ _index]]);
4271                         },
4272                         getChildFileIndex: function( _FILEorFILEDATA){
4273                                 if( typeof CHILDREN !== 'array') return -1;
4274                                 var l = CHILDREN.length,
4275                                         _fileData = ( function(){
4276                                                 var l = FILEDATA_RESITER.length;
4277                                                 for( var i=0; i<l; ++i){
4278                                                         if( _FILEorFILEDATA === FILEDATA_RESITER[ i]) return _FILEorFILEDATA;
4279                                                 }
4280                                                 return FILE_CONTROLER.getFileData( _FILEorFILEDATA);
4281                                         })();
4282                                 if( _fileData === null) return -1;
4283                                 for( var i=0; i<l; ++i){
4284                                         if( CHILDREN[ i] === _fileData) return i;
4285                                 }
4286                                 return -1;
4287                         },
4288                         isChildFile: function( _FILEorFILEDATA){
4289                                 return this.getChildFileIndex( _FILEorFILEDATA) !== -1;
4290                         },                      
4291                         getAttribute: function( KEYorKEYARRAY){
4292                                 return FILE_CONTROLER.getFileAttribute( UID, KEYorKEYARRAY);
4293                         },
4294                         getSeqentialFiles: function(){
4295                                 FILE_CONTROLER.getSeqentialFiles( this);
4296                         },
4297                         updateAttribute: function( key, value, opt_callback){
4298                                 TREE.updateFileAttribute( UID, key, value, opt_callback);
4299                         },
4300                         move: function( _newFolder, _newIndex, opt_callback){
4301                                 TREE.move( PARENT_FILE, UID, _newFolder, _newIndex, opt_callback);
4302                         },
4303                         replace: function( _newIndex, opt_callback){
4304                                 TREE.replace( PARENT_FILE, UID, _newIndex, opt_callback);
4305                         },
4306                         addEventListener: function( _eventType, _callback){
4307                                 TREE.addEventListener( UID, _eventType, _callback);
4308                         },
4309                         removeEventListener: function( _eventType, _callback){
4310                                 TREE.removeEventListener( UID, _eventType, _callback);
4311                         }
4312                 }
4313         };
4314         
4315         var ROOT_FILEDATA = {
4316                         name:           'root',
4317                         type:           FILE_TYPE_IS_FOLDER,
4318                         children:       []
4319                 },
4320                 IMAGE_FILEDATA = {
4321                         name:           'image root',
4322                         type:           FILE_TYPE_IS_FOLDER
4323                 },
4324                 COMIC_FILEDATA = {
4325                         name:           'comic root',
4326                         type:           FILE_TYPE_IS_FOLDER
4327                 },
4328                 SETTING_FILEDATA = {
4329                         name:           'setting root',
4330                         type:           FILE_TYPE_IS_FOLDER
4331                 },
4332                 HELP_FILEDATA = {
4333                         name:           'help root',
4334                         type:           FILE_TYPE_IS_FOLDER
4335                 };
4336         FILEDATA_RESITER.push( ROOT_FILEDATA, IMAGE_FILEDATA, COMIC_FILEDATA, SETTING_FILEDATA, HELP_FILEDATA);
4337         ROOT_FILEDATA.children.push( IMAGE_FILEDATA, COMIC_FILEDATA, SETTING_FILEDATA, HELP_FILEDATA);
4338
4339         var SYSTEM_TREE = FILE_CONTROLER.createTree( FileClass.apply( {}, [ null, null, ROOT_FILEDATA])),
4340                 ROOT_FILE = SYSTEM_TREE.ROOT_FILE(),
4341                 COMIC_ROOT_INDEX = ROOT_FILE.getChildFileByIndex( COMIC_FILEDATA),
4342                 COMIC_ROOT_FILE = ROOT_FILE.getChildFileByIndex( COMIC_ROOT_INDEX),
4343                 IMAGE_ROOT_INDEX = ROOT_FILE.getChildFileByIndex( IMAGE_FILEDATA),
4344                 IMAGE_ROOT_FILE = ROOT_FILE.getChildFileByIndex( IMAGE_ROOT_INDEX),             
4345                 SETTING_ROOT_INDEX = ROOT_FILE.getChildFileByIndex( SETTING_FILEDATA),
4346                 SETTING_ROOT_FILE = ROOT_FILE.getChildFileByIndex( SETTING_ROOT_INDEX),
4347                 HELP_ROOT_INDEX = ROOT_FILE.getChildFileByIndex( HELP_FILEDATA),
4348                 HELP_ROOT_FILE = ROOT_FILE.getChildFileByIndex( HELP_ROOT_INDEX);
4349
4350         return {
4351                 init: function(){
4352                         REQUEST_CONTROLER.init();
4353                         FILE_CONTROLER.init();
4354                         delete h2c.file.init;
4355                 },
4356                 createTree: function( _treeType){
4357                         var _rootFile;
4358                         if( _treeType === TREE_TYPE_IS_COMIC) _rootFile = COMIC_ROOT_FILE;
4359                         if( _treeType === TREE_TYPE_IS_IMAGE) _rootFile = IMAGE_ROOT_FILE;
4360                         if( _treeType === TREE_TYPE_IS_SETTING) _rootFile = SETTING_ROOT_FILE;
4361                         if( _treeType === TREE_TYPE_IS_HELP) _rootFile = HELP_ROOT_FILE;
4362                         if( _rootFile === undefined) return;
4363                         return FILE_CONTROLER.createTree( _rootFile);
4364                 },
4365                 TREE_TYPE_IS_COMIC:             TREE_TYPE_IS_COMIC,
4366                 TREE_TYPE_IS_IMAGE:             TREE_TYPE_IS_IMAGE,
4367                 TREE_TYPE_IS_SETTING:   TREE_TYPE_IS_SETTING,
4368                 FILE_TYPE_IS_FOLDER:    FILE_TYPE_IS_FOLDER,
4369                 FILE_TYPE_IS_IMAGE:             FILE_TYPE_IS_IMAGE,
4370                 FILE_TYPE_IS_PANEL:             FILE_TYPE_IS_PANEL,
4371                 FILE_TYPE_IS_SETTING:   FILE_TYPE_IS_SETTING
4372         }
4373 })();
4374
4375 // i18n
4376 // login
4377 // lib
4378
4379 h2c.fn( h2c.view);
4380 h2c.fn( h2c.overlay);
4381 h2c.fn( h2c.key);
4382 h2c.fn( h2c.balloon);
4383 h2c.fn( h2c.editor);
4384 h2c.fn( h2c.file);
4385
4386 $(window).ready( h2c.init);