2 * html2comic Javascript Editor -
13 * ----------------------------------------
14 * - naming of comic's elements -
16 * 0.comic strip(en) : koma manga(jp)
18 * 1.panel(en) : koma(jp)
26 * 2.speach balloon(en) : fukidasi(jp)
37 * ----------------------------------------
39 * +----------------------------+
48 * | - WHITE_GLASS_CONTROL |
49 * +----------------------------+
51 * ----------------------------------------
57 * const & Singleton Class
58 * THIS_IS_CONST = 'this is const';
64 * jqWrapper, JQ_WRAPPER
66 * value of dom element
67 * elmWrapper, ELM_WRAP
69 * value of vml element
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,
82 var query = search.substring( 1),
83 params = query.split( '&'),
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;
96 })( decodeURIComponent( elm[ 1]));
98 if( elm.length === 1){
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;
114 var _elms = document.getElementsByTagName( '*'),
117 while( i < _elms.length){
119 if( _elm.nodeType === 8 && _elm.parentNode){
120 _elm.parentNode.removeChild( _elm);
130 jqWindow = $( window);
131 jqDocument = $( document);
132 jqBody = $( document.body);
134 var l = FUNCTION_ARRAY.length,
136 for( var i=0; i<l; i++){
137 _fn = FUNCTION_ARRAY[ i];
138 _fn.init && _fn.init( _fn === h2c.view ? FUNCTION_ARRAY : undefined);
144 FUNCTION_ARRAY.push( _fn);
145 h2c.init === undefined && _fn.init && _fn.init();
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) {
155 } else if ( ua.indexOf('msie') !== -1) {
157 } else if ( ua.indexOf('webkit') !== -1) {
159 } else if ( navigator.product === 'Gecko') {
164 ACTIVEX: ( function(){
165 if( isIE === false || ieVersion > 8) return false;
166 var className = document.body.className,
168 if( className && className.indexOf( 'h2c-ActiveX-enabled') !== -1) return true;
169 if( className && className.indexOf( 'h2c-ActiveX-disabled') !== -1) return false;
171 test = new ActiveXObject('DXImageTransform.Microsoft.gradient');
177 jqWindow: function(){
180 jqDocument: function(){
186 URL_PARAMS: URL_PARAMS,
189 LINE_FEED_CODE_TEXTAREA : ( function(){
190 var text = document.getElementById( 'shadowTxtarea'),
191 form = text.parentNode;
192 form.parentNode.removeChild( form);
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 ??
206 * getElementSize( _elm)
211 h2c.util = ( function(){
212 var ELM_SIZE_GETTER = ( function(){
213 var ret = document.createElement( 'DIV'),
215 ret.id = 'elmSizeGetter';
216 style.position = 'absolute';
218 style.top = '-9999px';
219 style.visibility = 'hidden';
220 document.body.appendChild( ret);
223 IMG_SIZE_GETTER = ( function(){
224 var ret = ELM_SIZE_GETTER.cloneNode( true);
225 ret.id = 'imgSizeGetter';
226 document.body.appendChild( ret);
230 extend: function( baseInstance, extend){
231 for( var key in extend){
232 baseInstance[ key] = extend[ key];
236 getElementSize: function( _elm){
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);
250 width: _elm.offsetWidth,
251 height: _elm.offsetHeight
253 if( displayNone === true) _elm.style.display = 'none';
255 parentElm.insertBefore( _elm, nextElm);
257 if( prevElm && prevElm.nextSibling){
258 parentElm.insertBefore( _elm, prevElm.nextSibling);
260 parentElm && parentElm.appendChild( _elm);
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';
275 parentElm.insertBefore( img, nextElm);
277 if( prevElm && prevElm.nextSibling){
278 parentElm.insertBefore( img, prevElm.nextSibling);
280 parentElm && parentElm.appendChild( img);
285 * AUTHOR: uupaa.js@gmail.com
287 function getActualDimension(image) {
288 var run, mem, w, h, key = "actual";
290 // for Firefox, Safari, Google Chrome
291 if ("naturalWidth" in image) {
293 width: image.naturalWidth,
294 height: image.naturalHeight
298 if ("src" in image) { // HTMLImageElement
299 if (image[key] && image[key].src === image.src) {
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
309 run.width = mem.w; // restore
311 } else { // for Opera and Other
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");
322 image.removeEventListener("DOMAttrModified", fn, false);
323 image.width = mem.w; // restore
324 image.height = mem.h;
326 mem = { w: image.width, h: image.height }; // keep current style
327 image.removeAttribute("width");
328 image.removeAttribute("height");
331 image.width = mem.w; // restore
332 image.height = mem.h;
334 return image[key] = { width: w, height: h, src: image.src }; // bond
337 return { width: image.width, height: image.height };
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'){
349 // http://d.hatena.ne.jp/hottolinkblog/20090228/1235823487
350 if( type === 'object' && typeof URLorELM.hspace !== 'undefined' && typeof URLorELM.vspace !== 'undefined'){
357 abstractPath = this.getAbsolutePath( src);
359 loadImage( images, abstractPath,
360 function( abspath, actualW, actualH){
361 if( abstractPath !== abspath) return;
362 onLoad && setTimeout( function(){ // 一度読み込まれた画像は即座にonLoadされてしまうので遅延
363 onLoad( src, actualW, actualH);
367 if( abstractPath !== abspath) return;
368 onError && setTimeout( function(){
375 * URL: http://d.hatena.ne.jp/uupaa/20080413/1208067631
376 * AUTHOR: uupaa.js@gmail.com
378 * fixed for ie6-8 by h2c
379 * new Image -> document.createElement( 'IMG')
381 function loadImage( images, abspath, onLoad, onError, delay, timeout) {
382 images = images || document.images;
384 i = 0, l = images.length,
388 if ( img.src === abspath && img.complete) {
389 var size = h2c.util.getImageSize( img);
390 onLoad( abspath, size.width, size.height);
394 img = document.createElement( 'IMG'); //var img = new Image(); ではieでimgのsizeが取れない、、、removeChildも失敗し、imgSizeGetterにimgが残る
396 img.onabort = img.onerror = function() {
397 if (img.finish) { return; }
400 img.onload = img.onabort = img.onerror = "";
402 img.onload = function() {
404 if (window.opera && !img.complete) {
406 img.onload = img.onabort = img.onerror = "";
409 var size = h2c.util.getImageSize( img);
410 onLoad( abspath, size.width, size.height);
411 img.onload = img.onabort = img.onerror = "";
415 if (!img.finish && timeout) {
416 setTimeout(function() {
417 if (img.finish) { return; }
420 if (img.width) { return; }
422 img.onload = img.onabort = img.onerror = "";
425 if ((tick += delay) > timeout) {
428 img.onload = img.onabort = img.onerror = "";
431 setTimeout(arguments.callee, delay);
436 getAbsolutePath: function( path) {
437 var e = document.createElement("div");
438 e.innerHTML = '<a href=\"' + path + '\" />';
439 return e.firstChild.href;
445 * window resize event, overlay と currentなviewに流す
447 * editor, overlay, comic-viewer, image-explorer
450 h2c.view = ( function(){
456 viewID = ( function(){
457 var _viewID = h2c.URL_PARAMS.view || HOME_ID,
458 _elmView = document.getElementById( _viewID),
459 _elmHome = document.getElementById( HOME_ID);
461 _elmHome.style.display = '';
462 _elmView.style.display = 'block';
463 elmCurrent = _elmView;
466 elmCurrent = _elmHome;
470 function onWindowResize(){
472 l = funcArray.length,
473 w = jqWindow.width(),
474 h = jqWindow.height();
475 for( var i=0; i<l; ++i){
477 _fn.onWindowResize && _fn.onWindowResize( w, h);
481 init: function( _funcArray){
482 funcArray = _funcArray;
483 jqWindow = h2c.jqWindow();
484 jqWindow.resize( onWindowResize);
486 setTimeout( onWindowResize, 100);
488 delete h2c.view.init;
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;
497 elmCurrent.style.display = '';
498 elm.style.display = 'block';
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
516 h2c.overlay = ( function(){
517 var SHADOW_OPACITY = 0.5,
518 jqBody, jqConteiner, jqShadow, jqCloseButton,
519 currentOverlay = null,
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();
532 delete h2c.overlay.init;
534 show: function( _currentOverlay){
535 if( visible === true && currentOverlay === _currentOverlay) return;
536 jqConteiner.stop().css( {
541 currentOverlay = _currentOverlay;
542 jqCloseButton.toggle( !!_currentOverlay.onClose);
545 currentOverlay = null;
546 if( visible === false) return;
547 jqConteiner.stop().css( {
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);
563 /* ----------------------------------------
566 * - EDITABLE_TEXT_CONTROL
567 * - EDITABLE_TEXT_CLASS
573 * .enabled: function,
575 * .instance: function
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',
584 * .addKeyEvent: function,
585 * .keyEventDispatcher: function,
586 * .createEditableText: function,
588 * ショートカットキーの監視とテキスト入力(input, textarea)を管理する。
589 * キー入力はdocumentで受けて、テキスト編集中(input, textarea)はそちらにキーイベント流す。
592 h2c.key = ( function(){
595 keyOperationChatcher,
597 shiftEnabled = false,
599 spaceEnabled = false;
601 var EDITABLE_TEXT_CONTROL = ( function(){
602 var EDITABLE_TEXT_TABLE = {},
605 var EDITABLE_TEXT_CLASS = function( WRAPPER_ELM, ON_UPDATE_FUNCTION, GROUP_ID){
606 var ELM = WRAPPER_ELM.children( '.editable-value').eq( 0),
609 index = EDITABLE_TEXT_TABLE[ GROUP_ID].length,
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);
616 jqInput = $( '<input type="text"/>').val( value)//.keydown( finish).keypress( finish);
617 ELM.append( jqInput);
618 jqInput.focus().select();
620 ELM.addClass( 'editable-text').html( A);
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);
630 _finish( jqInput.val());
632 function _finish( VALUE_NEW){
634 A.html( VALUE_NEW).show();
637 ON_UPDATE_FUNCTION && VALUE_NEW !== value && ON_UPDATE_FUNCTION( VALUE_NEW, value);
638 EDITABLE_TEXT_CONTROL.finish( instance);
642 update: function( _value){
643 value = _value !== undefined ? _value : value;
645 jqInput && jqInput.val( value);
646 currentText === instance && finish();
649 enabled === false && WRAPPER_ELM.show();
653 enabled === true && WRAPPER_ELM.hide();
657 !jqInput && A.click();
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);
673 start: function( _currentText){
674 currentText !== _currentText && currentText && currentText.finish();
675 currentText = _currentText;
677 finish: function( _currentText){
678 if( currentText !== _currentText) return;
681 keyEventRellay: function( e){
682 currentText && currentText.finish( e);
683 return !!currentText;
685 tabShift: function( _groupID, _index, _way){
686 var GROUP_ARRAY = EDITABLE_TEXT_TABLE[ _groupID] || [],
687 l = GROUP_ARRAY.length,
690 while( i !== _index){
693 i === l ? 0 : i; // 0 < i < l
694 if( GROUP_ARRAY[ i].enabled() === true) break;
697 if( i === _index) return;
698 setTimeout( function(){ GROUP_ARRAY[ i].start();}, 0);
704 log.html( [ e.keyCode, e.shiftKey, e.ctrlKey, e.altKey].join( ','));
705 //keyOperationChatcher.val( '');
708 if( EDITABLE_TEXT_CONTROL.keyEventRellay( e) === false){
709 if( key === 16 || e.shiftKey === true){
710 keyOperationChatcher.trigger( h2c.key.SHIFT_DOWN_EVENT);
713 if( key === 17 || e.ctrlKey === true){
714 keyOperationChatcher.trigger( h2c.key.CTRL_DOWN_EVENT);
718 keyOperationChatcher.trigger( h2c.key.SPACE_DOWN_EVENT);
722 var l = KEYEVENT_ARRAY.length,
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);
732 if( key === 13 ||key === 18 || key === 9 || key === 27 || e.altKey === true || cancel === true){ // 13.enter 18.esc 9.tab 27.esc
735 e.cancelBubble = true;
736 e.returnValue = false;
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',
749 log = $( '#key-event-log').html( 'ready');
751 jqWindow = h2c.jqWindow().focus();
752 keyOperationChatcher = h2c.jqDocument()
754 .keyup( function( e){
755 log.html( '-' +e.altKey);
757 if( key === 16 || e.shiftKey === true){
758 keyOperationChatcher.trigger( h2c.key.SHIFT_UP_EVENT);
759 shiftEnabled = false;
761 if( key === 17 || e.ctrlKey === true){
762 keyOperationChatcher.trigger( h2c.key.CTRL_UP_EVENT);
766 keyOperationChatcher.trigger( h2c.key.SPACE_UP_EVENT);
767 spaceEnabled = false;
771 e.cancelBubble = true;
772 e.returnValue = false;
774 }).mouseenter( function(){
777 h2c.isIE === true && h2c.ieRenderingVersion < 8 && keyOperationChatcher.keypress( function( e){
779 if( key === 13 || key === 27){
787 addKeyEvent: function( _keyCode, _shift, _ctrl, _callbackFunction){
788 KEYEVENT_ARRAY.push( {
792 callback: _callbackFunction
795 addCursorEvent: function( _shift, _ctrl, _callbackFunction){
798 keyEventDispatcher: function(){
799 return keyOperationChatcher;
801 createEditableText: EDITABLE_TEXT_CONTROL.create,
802 shiftEnabled: function(){
805 ctrlEnabled: function(){
808 spaceEnabled: function(){
814 /* ----------------------------------------
827 * -----------------------
828 * ie9, other modern browser
831 * -----------------------
834 * 内部の角度計算は radian で統一したい。
835 * 当初 vectorEnabled = true で一度書いてみる。
836 * 駄目なら、代替のイメージのsrcの用意もここで担当。
840 h2c.balloon = ( function() {
841 var MIN_BALLOON_WIDTH = 30,
842 MIN_BALLOON_HEIGHT = 30,
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(){
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);
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);
875 vectorEnabled = ELM_BALLOON_ORIGIN !== null;
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;
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;
889 if( vectorEnabled === false){
890 balloonElm.setAttribute( 'src', balloonUrlBuilder( a));
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;
901 * tailの太さをTAIL_WIDTHに一致させるため、角度を絞りつつ計算
903 ( function( a, rx, ry, sin, cos, pow){
904 var startRad, endRad,
905 _startX, _startY, _endX, _endY,
907 TARGET = TAIL_WIDTH * TAIL_WIDTH,
908 DEG_TO_RAD = PI / 180;
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;
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)×円半径
920 if( pow( ( _startX -_endX), 2) + pow( ( _startY -_endY), 2) < TARGET){
928 })( a, rx, ry, sin, cos, pow);
934 ( function ( tailX, tailY, startX, startY, rx, ry, endX, endY, _w, _h){
937 shape = balloonElm.getElementsByTagName( 'shape')[ 0];
939 shape.style.width = w +'px';
940 shape.style.height = h +'px';
941 shape.coordsize = [ _w, _h].join( l);
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),
950 balloonElm.style.marginTop = tailY < 0 ? Math.floor( ( 60 +tailY) /10) : 10;
951 balloonElm.style.marginLeft = tailX < 0 ? Math.floor( ( 60 +tailX) /10) : 10;
953 })( tailX *10, tailY *10, endX *10, endY *10, rx *10, ry *10, startX *10, startY *10, w *10, h *10)
957 path = balloonElm.getElementsByTagName( 'path')[ 0];
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),
966 cround( endX +PADDING_LEFT), l, cround( endY +PADDING_TOP),
970 function cround( v, r){
972 return Math.round( v *pow( 10.0, r)) /pow( 10.0, r);
977 function balloonUrlBuilder( _a){
983 angle: function( _a){
988 type: function( _type){
992 balloonElm.parentNode.removeChild( balloonElm);
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;
1004 detect = size = null;
1009 delete h2c.balloon.init;
1011 enabled: function() {
1012 return vectorEnabled;
1014 VML: IS_VML === true && vectorEnabled === true,
1015 createBalloon: function( _w, _h, _a){
1016 return XBROWSER_BALLOON_CLASS.apply( {}, [ _w, _h, _a]);
1019 TYPE_SPEACH_BALLOON: 1,
1027 /* ----------------------------------------
1030 * xBackendな画像反転、画像描画機能。
1041 * png画像の表示(アルファpngをサポートしないie6以下のため)
1047 * -moz-transform:scale( -1, -1);
1049 h2c.image = ( function(){
1050 var REG_PNG = /\.png?/i,
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;
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;
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;
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',
1089 var css3Image = function( url, w, h, onLoadCallback){
1090 var elmWrap = document.createElement( 'div'),
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;
1100 elmWrap.appendChild( elmImg); // load後にimg
1101 elmWrap.className = CLASS_NAME;
1102 onLoadCallback && onLoadCallback( _url, _actualW, _actualH);
1103 onLoadCallback = null;
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);
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'))) : '';
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;
1133 var activexImage = css3Image;
1134 var vmlImage = function( url, w, h, onLoadCallback){
1135 var elmWrap = document.createElement( 'div'),
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');
1148 onLoadCallback && onLoadCallback( _url, _actualW, _actualH);
1149 onLoadCallback = null;
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);
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);
1168 vmlImg.className = w < 0 || h < 0 ? ( 'img-flip-' + ( w < 0 && h < 0 ? 'vh' : ( w < 0 ? 'v' : 'h'))) : '';
1169 elmWrap.appendChild( vmlImg);
1174 destroy: function(){
1175 loaded === true && elmWrap.removeChild( vmlImg);
1176 retryTimer !== null && clearTimeout( retryTimer);
1177 elmWrap = vmlImg = onLoadCallback = retryTimer = null;
1178 delete this.destroy;
1182 var serverImage = function( url, w, h, onLoadCallback){
1186 return function( url, w, h, onLoadCallback){
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]);
1197 elm: xBackendImage.elm,
1199 _w !== undefined && xBackendImage.resize( _w, h);
1203 _h !== undefined && xBackendImage.resize( w, _h);
1206 resize: xBackendImage.resize,
1207 destroy: function(){
1208 xBackendImage.destroy && xBackendImage.destroy();
1209 xBackendImage = onLoadCallback = onLoadCallbackAsync = null;
1210 delete this.destroy;
1219 createReversibleImage: function( url, w, h, onLoadCallback){
1220 return XBackendReversibleImageClass.apply( {}, [ url, w, h, onLoadCallback]);
1225 /* ----------------------------------------
1230 * - INFOMATION_WINDOW
1234 * - WHITE_GLASS_CONTROL
1235 * - PANEL_BORDER_CONTROL
1236 * - COMIC_ELEMENT_CONTROL
1237 * - PanelResizerClass
1238 * - COMIC_ELEMENT_OPERATOR
1240 * - ImageElementClass
1241 * - TextElementClass
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,
1255 /* ----------------------------------------
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);
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');
1285 a.appendChild( span);
1286 a.appendChild( key);
1287 ret.appendChild( a);
1290 EMPTY_FUNCTION = new Function,
1293 itemW = h2c.util.getElementSize( ELM_ITEM_ORIGN).width,
1294 selectionW = h2c.util.getElementSize( ELM_ITEM_ORIGN.getElementsByTagName( 'UL')[ 0]).width,
1296 barH = h2c.util.getElementSize( ELM_BAR).height;
1297 ELM_BAR.style.top = ( -barH) +'px';
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 = [],
1307 ELM_TITLE.innerHTML = title;
1309 ELM_WRAPPER.style.left = ( itemW * INDEX) +'px';
1310 ELM_BAR.appendChild( ELM_WRAPPER);
1312 function onClick( e){
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;
1323 i !== -1 && this.className !== 'disabled' && SELECTION_CALLBACK_ARRAY[ i]();
1324 e.stopPropagation();
1329 $( ELM_SELECTION).children( 'li').click( onClick);
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);
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);
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';
1355 createAjaxSelection: function(){
1356 var elmLoading = document.createElement( 'li');
1357 elmLoading.className = 'loading';
1358 elmLoading.style.height = '90px';
1359 ELM_SELECTION.appendChild( elmLoading);
1361 delete this.createAjaxSelection;
1363 SELECTION_CALLBACK_ARRAY.shift();
1364 ELM_SELECTION.removeChild( elmLoading);
1366 $( ELM_SELECTION).children( 'li').click( onClick);
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);
1378 var ELM_SHORTCUT = ELM_WRAPPER.getElementsByTagName( 'KBD')[ 0];
1380 ELM_SHORTCUT.innerHTML = shortcut;
1382 ELM_SHORTCUT.parentNode.removeChild( ELM_SHORTCUT);
1386 container.appendChild( ELM_WRAPPER);
1388 function updateTitle( _title){
1389 ELM_TITLE.innerHTML = title = _title;
1391 function updateVisible( _visible){
1392 _visible !== undefined && ( function(){
1393 visible = !!_visible;
1394 ELM_WRAPPER.className = visible === true ? '' : 'disabled';
1399 title: function( _title){
1400 _title !== undefined && updateTitle( _title);
1403 visible: function( _visible){
1404 visible !== !!_visible && updateVisible( _visible);
1407 separateAfter: separateAfter
1411 function createMenubarItem( title){
1412 var _item = MenuBarItemClass.apply( {}, [ title]);
1413 ITEM_ARRAY.push( _item);
1419 jqBar = $( '#' +BAR_ID).animate( { top: 0});
1421 var l = ITEM_ARRAY.length;
1422 for( var i=0; i<l; ++i){
1423 ITEM_ARRAY[ i].init();
1426 delete MENU_BAR_CONTROL.init;
1428 onMouseMove: function( _mouseX, _mouseY){
1429 if( barH >= _mouseY){
1432 var l = ITEM_ARRAY.length;
1433 for( var i=0; i<l; ++i){
1434 ITEM_ARRAY[ i].hide();
1438 onMouseUp: function( _mouseX, _mouseY){
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();
1448 ITEM_ARRAY[ i].hide();
1453 busy: function( _busy){
1456 onWindowResize: function( _windowW, _windowH){
1459 QUIT: createMenubarItem( 'Quit'),
1460 EDIT: createMenubarItem( 'Edit'),
1461 WINDOW: createMenubarItem( 'Window'),
1462 HELP: h2c.util.extend( createMenubarItem( 'Help'), {
1464 }) // extend, onShow, ajaxselection, HELP_DOCUMENTS_CONTROL.load()
1469 /* ----------------------------------------
1472 var HISTORY = ( function() {
1473 var STACK_BACK = [], STACK_FORWARD = [],
1474 menubarBack, menubarForward,
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
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);
1486 * currentを控えてSTACK_FORWARD.push(current)
1487 * STACK_BACK.pop()を実行してcurrentに
1489 if( STACK_BACK.length === 0) return;
1491 var state = STACK_BACK.pop();
1492 state && state.fn( state.argBack);
1493 menubarBack.visible( STACK_BACK.length !== 0);
1495 STACK_FORWARD.push( state);
1496 menubarForward.visible( true);
1499 if( STACK_FORWARD.length === 0) return;
1501 var state = STACK_FORWARD.pop();
1502 state.fn( state.argForword);
1503 menubarForward.visible( STACK_FORWARD.length !== 0);
1505 STACK_BACK.push( state);
1506 menubarBack.visible( true);
1510 log = $( '#history-log');
1511 delete HISTORY.init;
1513 saveState: function( _function, _argBack, _argForword, _destory) {
1517 argForword: _argForword,
1520 menubarBack.visible( true);
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,
1530 if( typeof __argBack === 'array'){
1531 while( __argBack.length > 0){
1532 _value = __argBack.shift();
1533 _destroy === true && _value.destroy && _value.destroy();
1536 if( typeof _argForword === 'array'){
1537 while( __argForword.length > 0){
1538 _value = __argForword.shift();
1539 _destroy === true && _value.destroy && _value.destroy();
1543 menubarForward.visible( false);
1549 /* ----------------------------------------
1550 * HELP_DOCUMENTS_CONTROL
1551 * * menubar の help 下に help documents の index を挿入
1552 * * help window に help documents を挿入
1554 var HELP_DOCUMENTS_CONTROL = ( function(){
1555 var onLoadFunction = MENU_BAR_CONTROL.HELP.createAjaxSelection();
1558 // HELP_DOCUMENTS_WINDOW.setAjaxContent();
1559 var help = MENU_BAR_CONTROL.HELP;
1560 //help.createSelection();
1567 /* ----------------------------------------
1570 var WINDOWS_CONTROL = ( function(){
1572 * 表示上手前にあるwindowは、WINDOW_ARRAYの先頭にあり、htmlでは後ろにある。
1574 var DEFAULT_MIN_WINDOW_WIDTH = 200,
1575 DEFAULT_MIN_WINDOW_HEIGHT = 200,
1579 currentWindowIndex = -1,
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,
1590 visible === true ? instance.close() : instance.open();
1594 jqWrapper, jqHeader, elmBody, elmBodyStyle,
1595 startX, startY, startW, startH,
1600 bodyIsTachable = false,
1603 function update( _x, _y, _w, _h){
1604 ( w !== _w || h !== _h) && instance.onResize && instance.onResize( _w, _h);
1616 elmBodyStyle.height = bodyH +'px';
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;
1629 setInstance: function(){
1631 delete this.setInstance;
1633 init: function( jqContainer){
1634 jqWindowOrigin = jqWindowOrigin || ( function(){
1635 return $( $( '#windowTemplete').remove().html());
1637 windowCloseButtonWidth = windowCloseButtonWidth || ( function(){
1638 return h2c.util.getElementSize( jqWindowOrigin.clone( true).find( '.window-close-button').get( 0)).width;
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()));
1651 jqWrapper.find( '.window-body-insert-position').remove();
1653 CLOSE_BUTTON_ENABLED !== true && jqWrapper.find( '.window-close-button').remove();
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);
1668 MOUSE_CURSOR( 'nw-resize');
1669 e.stopPropagation();
1673 jqWrapper.find( '.window-resize-button').remove();
1675 update( x, y, w, h);
1676 this.onInit && this.onInit();
1679 x: function(){ return x;},
1680 y: function(){ return y;},
1681 w: function(){ return w;},
1682 h: function(){ return h;},
1686 if( visible === true) return;
1687 this.visible = visible = true;
1688 this.onOpen && setTimeout( this.onOpen, 0);
1690 MENUBAR_SELWCTION.title( 'hide ' +title);
1693 if( visible === false) return;
1694 this.visible = visible = false;
1695 this.onClose && setTimeout( this.onClose, 0);
1697 MENUBAR_SELWCTION.title( 'show ' +title);
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){
1706 MOUSE_CURSOR( 'move');
1714 onMouseUp: function( _mouseX, _mouseY){
1715 isDragging = isResizing = false;
1718 onMouseMove: function( _mouseX, _mouseY){
1719 var _updateX = _mouseX -xOffset,
1720 _updateY = _mouseY -yOffset;
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);
1728 if( isDragging === true) {
1729 update( startX +_updateX, startY +_updateY);
1732 if( x > _mouseX || x +w < _mouseX ) return;
1734 ( y <= _mouseY && y +headerH >= _mouseY ) ?
1735 MOUSE_CURSOR( 'pointer') : // hit to header
1737 bodyBackOrForward( y +headerH > _mouseY || y +headerH +bodyH < _mouseY);
1739 onMouseOut: function( _mouseX, _mouseY){
1740 bodyIsTachable === true && bodyBackOrForward( true);
1745 return isDragging === true || isResizing === true;
1747 bodyHeight: function(){
1753 function getCurrentWindow( _mouseX, _mouseY){
1754 if( currentWindow && currentWindow.busy() === true) return currentWindowIndex;
1755 var l = WINDOW_ARRAY.length,
1756 _currentWindow = null,
1758 currentWindowIndex = -1;
1759 for( var i=0; i<l; i++){
1760 _win = WINDOW_ARRAY[ i];
1763 if( _x <= _mouseX && _y <= _mouseY && _x +_win.w() >= _mouseX && _y +_win.h() >= _mouseY){
1764 _currentWindow = _win;
1765 currentWindowIndex = i;
1769 currentWindow && currentWindow !== _currentWindow && currentWindow.onMouseOut( _mouseX, _mouseY);
1770 currentWindow = _currentWindow;
1771 return currentWindowIndex;
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)
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);
1797 jqContainer = $( '#window-container');
1799 var l = WINDOW_ARRAY.length,
1801 for( var i=l-1; i >= 0; --i){
1802 _window = WINDOW_ARRAY[ i];
1803 _window.visible === true && _window.init && _window.init( jqContainer);
1805 log = $( '#window-log');
1807 delete WINDOWS_CONTROL.init;
1809 onMouseMove: function( _mouseX, _mouseY){
1810 var _index = getCurrentWindow( _mouseX, _mouseY);
1812 currentWindow.onMouseMove( _mouseX, _mouseY);
1815 if( _index !== -1){ // 先頭のクリックでない場合
1817 WINDOW_ARRAY.splice( currentWindowIndex, 1);
1818 WINDOW_ARRAY.unshift( currentWindow);
1820 jqContainer.append( currentWindow.$);
1821 currentWindowIndex = 0;
1826 onMouseUp: function( _mouseX, _mouseY){
1827 if( getCurrentWindow( _mouseX, _mouseY) === 0){
1828 currentWindow.onMouseUp( _mouseX, _mouseY);
1833 onMouseDown: function( _mouseX, _mouseY){
1834 if( getCurrentWindow( _mouseX, _mouseY) === 0){
1835 currentWindow.onMouseDown( _mouseX, _mouseY);
1840 onMouseClick: function( _mouseX, _mouseY){
1844 return currentWindow !== null;
1846 onWindowResize: function( _windowW, _windowH){
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;
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]),
1862 _window.setInstance();
1863 opt_visible === true && openWindow( _window);
1869 /* ----------------------------------------
1872 var TOOL_BOX_WINDOW = ( function(){
1873 var addImageButton, addTextButton, editBgButton, switchGridButton, popupHelpButton, publishButton,
1876 h2c.key.addKeyEvent( 73, false, true, addImage);
1877 MENU_BAR_CONTROL.EDIT.createSelection( 'Add Image', 'ctrl + I', addImage, true, true, false);
1879 h2c.key.addKeyEvent( 84, false, true, addText);
1880 MENU_BAR_CONTROL.EDIT.createSelection( 'Add Text', 'ctrl + T', addText, true, false, true);
1882 h2c.key.addKeyEvent( 71, false, true, switchGrid);
1883 MENU_BAR_CONTROL.EDIT.createSelection( 'show Grid', 'ctrl + G', switchGrid, true, true, true);
1885 function addImage(){
1886 setTimeout( function(){ CANVAS_CONTROL.createImageElement();}, 0);
1889 setTimeout( function(){ CANVAS_CONTROL.createTextElement();}, 0);
1891 function switchGrid(){
1892 setTimeout( gridSwitchFunction, 0);
1894 function popupHelp(){
1895 setTimeout( function(){ HELP_DOCUMENTS_WINDOW.open();}, 0);
1898 return WINDOWS_CONTROL.createWindow(
1902 addImageButton = $( '#toolbox-add-image-button').click( function(e){
1908 addTextButton = $( '#toolbox-add-text-button').click( function(e){
1914 editBgButton = $( '#toolbox-edit-bg-button').click( function( e){
1915 setTimeout( function(){
1916 INFOMATION_WINDOW.open();
1922 switchGridButton = $( '#toolbox-switch-grid').click( function( e){
1928 popupHelpButton = $( '#toolbox-popup-help-button').click( function( e){
1934 publishButton = $( '#toolbox-publish-button');
1938 setGridSwitchFunction: function( _gridSwitchFunction){
1939 gridSwitchFunction = _gridSwitchFunction || gridSwitchFunction;
1942 'toolbox-window', 'Tool box', 0, 215, 110, 290, true
1946 /* ----------------------------------------
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;
1960 return WINDOWS_CONTROL.createWindow(
1964 backgroundInfomationElm = $( '#panel-background-information');
1966 jqComicElementInformation = $( '#comic-element-infomation').hide().css( {
1967 height: this.bodyHeight()
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);
1981 onResize: function( w, h){
1982 jqComicElementInformation && jqComicElementInformation.css( {
1983 height: this.bodyHeight()
1986 update: function( _currentElementType, x, y, z, a, w, h, wPercent, hPercent){
1987 if( currentElementType !== _currentElementType){
1988 if( _currentElementType !== -1){
1989 if( _currentElementType === 1){
1998 currentElementType === -1 && jqComicElementInformation.stop().css( {
2001 })[ FADE_IN_EFFECT]();
2003 currentElementType !== -1 && jqComicElementInformation.stop().css({
2006 })[ FADE_OUT_EFFECT]();
2008 currentElementType = _currentElementType;
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);
2024 'infomation-window', 'Infomation', 0, 30, 200, 180, true
2028 /* ----------------------------------------
2031 var HELP_DOCUMENTS_WINDOW = ( function(){
2033 hasAjaxContents = false,
2037 function jumpPage( _index){
2040 function onOpen( _pageIndex){
2041 _pageIndex = _pageIndex || 0;
2042 if( hasAjaxContents === false){
2044 url: 'help/jp.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){
2052 parent = this.parentNode,
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;
2061 e.stopPropagation();
2062 if( i === -1) return false;
2063 jqNaviItems.removeClass( 'current').eq( i).addClass( 'current');
2064 jqPages.hide().eq( i).show();
2068 jqNaviItems.eq( _pageIndex).addClass( 'current');
2069 jqPages = jqAjaxContents.find( '.page-content');
2070 jqPages.eq( _pageIndex).show();
2073 hasAjaxContents = true;
2075 jqNaviItems.removeClass( 'current').eq( _pageIndex).addClass( 'current');
2076 jqPages.hide().eq( _pageIndex).show();
2079 return WINDOWS_CONTROL.createWindow(
2083 jqAjaxContents = this.$.find( '.window-body').addClass( 'loading').css( { height: this.bodyHeight()});
2087 onResize: function( w, h){
2088 jqAjaxContents && jqAjaxContents.css( { height: this.bodyHeight()});
2090 setAjaxContent: function( html){
2092 delete this.onLoadAjaxContent;
2095 null, 'Help', 0, 215, 400, 350, false, true, true, 300, 300
2099 /* ----------------------------------------
2102 * - WHITE_GLASS_CONTROL
2103 * - PANEL_BORDER_CONTROL
2104 * - COMIC_ELEMENT_CONTROL
2105 * - PanelResizerClass
2106 * - COMIC_ELEMENT_OPERATOR
2107 * - ImageElementClass
2108 * - TextElementClass
2110 var CANVAS_CONTROL = ( function(){
2111 var DEFAULT_PANEL_WIDTH = 400,
2112 DEFAULT_PANEL_HEIGHT = 300,
2113 MIN_PANEL_HEIGHT = 20,
2115 RESIZER_BORDER_WIDTH = 1,
2116 SPACE_ENABLED = h2c.key.spaceEnabled,
2117 canvasW, canvasH, canvasX, canvasY,
2118 xOffset, yOffset, startCanvasX, startCanvasY,
2122 var GRID_CONTROL = ( function(){
2123 var elmGrid = document.getElementById( 'grid'),
2131 }).stop()[ visible === true ? 'fadeOut' : 'fadeIn']();
2133 if( visible === true){
2134 elmGrid.style.backgroundImage = "url('grid.gif')";
2140 jQGrid = $( elmGrid);
2142 TOOL_BOX_WINDOW.setGridSwitchFunction( update);
2143 delete GRID_CONTROL.init;
2146 elmGrid.style.backgroundPosition = [ canvasX % 10, 'px ', canvasY % 10, 'px'].join( '');
2147 elmGrid.style.height = windowH +'px';
2149 enabled: function(){
2156 * WHITE_GLASS_CONTROL
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;
2166 marginTop = canvasY,
2167 marginBottom = windowH -_h -marginTop,
2169 rightWidth = windowW -_w -marginX;
2171 styleTop.height = ( marginTop < 0 ? 0 : marginTop) +'px';
2173 styleLeft.top = marginTop +'px';
2174 styleLeft.width = ( marginX < 0 ? 0 : marginX) +'px';
2175 styleLeft.height = ( _h + marginBottom) +'px';
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';
2182 styleBottom.top = ( _h +marginTop) +'px';
2183 styleBottom.left = marginX +'px';
2184 styleBottom.width = _w +'px';
2185 styleBottom.height = ( marginBottom < 0 ? 0 : marginBottom) +'px';
2193 * PANEL_BORDER_CONTROL
2195 var PANEL_BORDER_CONTROL = ( function(){
2196 var panelElm, borderWidth;
2200 left: canvasX -BORDER_WIDTH,
2201 top: canvasY -BORDER_WIDTH,
2209 panelElm = $( '#panel-border');
2210 borderWidth = panelElm.css( 'border-width');
2212 delete PANEL_BORDER_CONTROL.init;
2219 * COMIC_ELEMENT_CONTROL
2220 * - PanelResizerClass
2221 * - COMIC_ELEMENT_OPERATOR
2222 * - ImageElementClass
2223 * - TextElementClass
2225 var COMIC_ELEMENT_CONTROL = ( function( _onResizeFunction){
2226 var MIN_OBJECT_SIZE = 19,
2228 currentElement = null,
2229 _canvasX, _canvasY, _canvasW, _canvasH,
2230 MOUSE_HIT_AREA = 10,
2231 SAVE = HISTORY.saveState;
2233 * --------------------------------------------------------------------------------------------
2236 var PanelResizerClass = function( ELM, onPanelResizeFunction, isTop){
2237 var BORDER_WIDTH = 2,
2238 yOffset, y, _canvasY, _canvasH,
2239 RESIZER_HEIGHT = 30,
2241 SAVE = HISTORY.saveState,
2242 MOUSE_CURSOR = updateMouseCursor;
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;
2252 * PANEL_RESIZER_TOP の場合、リサイズに併せてコミック要素を移動させている。
2253 * currentElementを一度PANEL_RESIZER_TOPにしたのちresize
2255 onPanelResizeFunction( isTop);
2260 init: function( _elm){
2262 ELM.style.width = ( canvasW +2)+'px';
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;},
2270 dragging: function(){
2273 onMouseDown: function( _mouseX, _mouseY){
2279 onMouseMove: function( _mouseX, _mouseY){
2280 if( isDragging !== true){
2281 COMIC_ELEMENT_OPERATOR.hide();
2282 MOUSE_CURSOR( 'n-resize');
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;
2290 canvasY = _canvasY +move;
2291 canvasH = _canvasH -move;
2293 onPanelResizeFunction( true);
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;
2302 onPanelResizeFunction( false);
2307 onMouseUp: function( _mouseX, _mouseY){
2308 ( _canvasY !== canvasY || _canvasH !== canvasH) && SAVE( restoreState, [ NaN, _canvasY, NaN, _canvasH], [ NaN, canvasY, NaN, canvasH]);
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;
2319 _onResizeFunction = PanelResizerClass = undefined;
2322 * --------------------------------------------------------------------------------------------
2323 * COMIC_ELEMENT_OPERATOR
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 = [],
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}
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,
2351 elmResizerContainerStyle.display = 'none';
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';
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}
2383 index: function( _mouseX, _mouseY){
2384 if( TAIL_MOVER.hitText( _mouseX -x, _mouseY -y) === true){
2385 MOUSE_CURSOR( 'move');
2386 return TAIL_MOVER_INDEX;
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;
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')
2404 MOUSE_CURSOR( CURSOR_AND_FLIP[ currentIndex].cursor);
2405 return currentIndex;
2408 elmResizerContainerStyle.display = '';
2411 elmResizerContainerStyle.display = 'none';
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);
2427 DEG_TO_RAD = Math.PI / 180,
2428 RAD_TO_DEG = 1 /DEG_TO_RAD,
2430 x, y, w, h, a, radA;
2431 //ELM_MOVER_PARENT.removeChild( ELM_MOVER);
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());
2447 show: function( _currentText){
2449 * domから抜かないとieで表示されてしまう。visibilityのほうがいい
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;
2457 //ELM_MOVER.parentNode === ELM_MOVER_PARENT && ELM_MOVER_PARENT.removeChild( ELM_MOVER);
2458 ELM_MOVER.style.visibility = 'hidden';
2461 hitText: function( _mouseX, _mouseY){
2462 var _x = x -SIZE /2,
2464 return currentIsTextElement === true && _x <= _mouseX && _y <= _mouseY && _x +SIZE >= _mouseX && _y +SIZE >= _mouseY;
2466 onDrag: function( _mouseX, _mouseY){
2469 ATAN( _mouseY /_mouseX) *RAD_TO_DEG +( _mouseX < 0 ? 180 : 0) :
2470 _mouseY > 0 ? 0 : 180
2472 currentText && currentText.angle( a);
2473 updateInfomation( undefined, undefined, undefined, a);
2477 COMIC_ELEMENT_CONSOLE = ( function(){
2482 jqImgConsole, jqTextConsole,
2483 currentElement = null,
2486 imgConsoleWidth, imgConsoleHeight,
2487 textConsoleWidth, textConsoleHeight,
2488 consoleWidth, consoleHeight,
2491 buttonClickable = false;
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
2500 buttonClickable === isBack && ( isBack === true ? jqConsoleParent : jqStage).append( jqConsoleWrapper);
2501 buttonClickable = !isBack;
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;
2512 jqTextConsole = $( '#text-element-consol').hide();
2513 var textConsoleSize = h2c.util.getElementSize( jqTextConsole.get( 0));
2514 textConsoleWidth = textConsoleSize.width;
2515 textConsoleHeight = textConsoleSize.height;
2517 jqConsoleWrapper = $( '#comic-element-consol-wrapper').hide();
2518 jqConsoleParent = jqConsoleWrapper.parent();
2520 $( '#edit-text-button').click( function(){
2521 if( currentElement === null) return;
2522 TEXT_EDITOR_CONTROL.show( currentElement);
2523 buttonBackOrForward( true);
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();
2532 $( '#change-image-button').click( function(){
2533 if( currentElement === null) return;
2534 buttonBackOrForward( true);
2535 IMAGE_GROUP_EXPROLER.show( currentElement.url);
2537 $( '#layer-forward-button, #forward-text-button').click( function(){
2538 if( currentElement === null) return;
2539 replaceComicElement( currentElement, true);
2541 SAVE( restoreReplaceObject, [ currentElement, false], [ currentElement, true]);
2543 $( '#layer-back-button, #back-text-button').click( function(){
2544 if( currentElement === null) return;
2545 replaceComicElement( currentElement, false);
2547 SAVE( restoreReplaceObject, [ currentElement, true], [ currentElement, false]);
2550 delete COMIC_ELEMENT_CONSOLE.init;
2552 show: function( _currentElement, _w, _h){
2553 visible === false && jqConsoleWrapper.show();
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;
2564 consoleX = Math.floor( ( _w -consoleWidth) /2);
2566 if( _w > consoleWidth * 1.5 && _h > consoleHeight * 1.5){
2567 consoleY = Math.floor( ( _h -consoleHeight) /2);
2568 jqConsoleWrapper.css( {
2571 }).removeClass( 'console-out');
2573 consoleY = _h +tailSize;
2574 jqConsoleWrapper.css( {
2577 }).addClass( 'console-out');
2581 visible === true && jqConsoleWrapper.hide();
2583 currentElement = null;
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);
2594 buttonClickable === false && buttonBackOrForward( false);
2597 onMouseOut: function( _mouseX, _mouseY){
2598 buttonClickable === true && buttonBackOrForward( true);
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
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,
2620 currentUpdated = false;
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;
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);
2634 function updateInfomation( _x, _y, _z, _a, _w, _h){
2635 _w = _w !== undefined ? _w : w;
2636 _h = _h !== undefined ? _h : h;
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) : '-'),
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))
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;
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();
2662 startFilpV = flipV = currentIsTextElement === false ? _currentElement.flipV() : 0;
2663 startFilpH = flipH = currentIsTextElement === false ? _currentElement.flipH() : 0;
2665 resize( startX, startY, startW, startH, startA);
2666 isDragging = currentUpdated = false;
2670 currentElement !== null && RESIZER.hide();
2671 currentElement = null;
2674 isDragging = currentUpdated = false;
2675 COMIC_ELEMENT_CONSOLE.hide();
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],
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);
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]
2705 COMIC_ELEMENT_CONSOLE.init(); // COMIC_ELEMENT_CONSOLE が要素の高さを取得するため、RESIZER.initがあと。
2708 delete COMIC_ELEMENT_OPERATOR.init;
2711 dragging: function(){
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;
2719 return _x -HIT_AREA;
2721 hitareaY: function( _comicElement, _y){
2722 return _y -HIT_AREA;
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;
2729 return _w +HIT_AREA *2;
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;
2736 return _h +HIT_AREA *2;
2738 onMouseDown: function( _currentElement, _mouseX, _mouseY){
2739 //show( _currentElement);
2742 currentResizerIndex = RESIZER.index( _mouseX, _mouseY);
2743 currentResizerIndex === -1 && MOUSE_CURSOR( 'move');
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とする座標系に変換
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,
2762 if( _w > MIN_OBJECT_SIZE && _h > MIN_OBJECT_SIZE){
2765 if( currentElement.type === COMIC_ELEMENT_TYPE_TEXT){
2767 if( _w < -MIN_OBJECT_SIZE || _h < -MIN_OBJECT_SIZE){
2769 if( _w < -MIN_OBJECT_SIZE && _h > MIN_OBJECT_SIZE){
2776 currentElement.flip( false, true);
2777 currentResizerIndex = RESIZER.flip( false, true);
2778 flipV = currentElement.flipV();
2780 if( _w > MIN_OBJECT_SIZE && _h < -MIN_OBJECT_SIZE){
2787 currentElement.flip( true, false);
2788 currentResizerIndex = RESIZER.flip( true, false);
2789 flipH = currentElement.flipH();
2798 currentElement.flip( true, true);
2799 currentResizerIndex = RESIZER.flip( true, true);
2800 flipV = currentElement.flipV();
2801 flipH = currentElement.flipH();
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);
2816 currentUpdated = ( currentUpdated === true) ? true : ( moveX !== 0 || moveY !== 0);
2820 if( GRID_ENABLED() === true){
2821 _x = Math.floor( _x / 10) * 10;
2822 _y = Math.floor( _y / 10) * 10;
2824 RESIZER.update( _x, _y);
2825 currentElement.resize( _x, _y);
2826 currentUpdated = ( currentUpdated === true) ? true : ( moveX !== 0 || moveY !== 0);
2827 updateInfomation( _x, _y);
2830 currentElement && COMIC_ELEMENT_CONSOLE.onMouseMove( _mouseX -x, _mouseY -y);
2831 RESIZER.index( _mouseX, _mouseY) === -1 && MOUSE_CURSOR( '');
2834 onMouseUp: function( _currentElement, _mouseX, _mouseY){
2836 RESIZER.x(), RESIZER.y(), RESIZER.w(), RESIZER.h(),
2837 currentIsTextElement === true ? currentElement.angle() : 0
2839 currentElement && currentElement.resize( x, y, w, h);
2841 currentUpdated === true && saveState();
2842 isDragging = currentUpdated = false;
2844 onMouseClick: function( _mouseX, _mouseY){
2845 //return currentElement ? COMIC_ELEMENT_CONSOLE.onMouseClick( _mouseX -x, _mouseY -y) : false;
2850 * // COMIC_ELEMENT_OPERATOR
2853 var AbstractComicElement = function( JQ_WAPPER, COMIC_ELM_TYPE, update, x, y, w, h, z, domIndex){
2854 var OPERATOR = COMIC_ELEMENT_OPERATOR;
2857 type: COMIC_ELM_TYPE,
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);
2871 dragging: function(){
2872 return OPERATOR.dragging();
2874 onMouseMove: function( _mouseX, _mouseY){
2875 OPERATOR.onMouseMove( this, _mouseX, _mouseY);
2877 onMouseUp: function( _mouseX, _mouseY){
2878 OPERATOR.onMouseUp( this, _mouseX, _mouseY);
2880 onMouseDown: function( _mouseX, _mouseY){
2881 OPERATOR.onMouseDown( this, _mouseX, _mouseY);
2886 * --------------------------------------------------------------------------------------------
2889 var jqImageElementOrigin;
2890 var ImageElementClass = function( url, IMAGE_SET_ID, x, y, z, w, h, domIndex){
2891 jqImageElementOrigin = jqImageElementOrigin || $( $( '#imgElementTemplete').remove().html());
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,
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']( {
2915 }, 250, function(){ reversibleImage.resize( flipH * w, flipV * h);});
2916 animate !== true && reversibleImage.resize( flipH * w, flipV * h);
2919 function updateUrl( _url){
2920 if( url === _url) return;
2922 var _reversibleImage = h2c.image.createReversibleImage( url, flipH * w, flipV * h, function( _url, _actualW, _actualH){
2926 if( reversibleImage !== null){
2927 JQ_WRAPPER.children( reversibleImage.elm).replaceWith( _reversibleImage.elm);
2928 reversibleImage.destroy();
2930 JQ_WRAPPER.append( _reversibleImage.elm);
2932 reversibleImage = _reversibleImage;
2934 return h2c.util.extend(
2935 AbstractComicElement.apply( this, [ JQ_WRAPPER, COMIC_ELEMENT_TYPE_IMAGE, update, x, y, w, h, z, domIndex]),
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);
2955 url: function( _url, _actualW, _actualH){
2956 if( _url && _url !== url){
2957 SAVE( updateUrl, url, _url);
2964 actualW: function(){ return actualW;},
2965 actualH: function(){ return actualH;},
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);
2972 getAsHtml: function(){
2975 getAsJson: function(){
2978 destroy: function(){
2979 reversibleImage.destroy();
2980 JQ_WRAPPER.remove();
2981 JQ_WRAPPER = reversibleImage = OPERATOR = null;
2982 delete this.destroy;
2988 * / ImageElementClass
2989 * --------------------------------------------------------------------------------------------
2994 * --------------------------------------------------------------------------------------------
2997 * ELM はh2c.domで書き出したものを突っ込むcreateの場合
3004 * 4.black-box( dq style)
3005 * 5.blue-box( ff style)
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;
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,
3024 JQ_WRAPPER.find( 'img').eq( 0).replaceWith( XBROWSER_BALLOON.elm);
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;
3033 JQ_WRAPPER[ animate === true ? 'animate' : 'css']( {
3040 XBROWSER_BALLOON.resize( a, w, h);
3043 animate !== true && XBROWSER_BALLOON.resize( a, w, h);
3046 function updateType( _type){
3047 if( type !== _type){
3048 type = _type || type;
3049 XBROWSER_BALLOON.type( type);
3052 function updateAngle( _a){
3053 if( _a !== undefined && a !== _a){
3054 a = _a !== undefined ? _a : a;
3055 XBROWSER_BALLOON.angle( a);
3058 function updateText( _text){
3059 text = _text || text || '';
3060 TEXT_ELM.html( text);
3063 return h2c.util.extend(
3064 AbstractComicElement.apply( this, [ JQ_WRAPPER, COMIC_ELEMENT_TYPE_TEXT, update, x, y, w, h, z, domIndex]),
3072 angle: function( _a){
3073 _a !== undefined && update( NaN, NaN, NaN, NaN, _a);
3076 text: function( _text){
3077 if( _text && text !== _text) {
3078 SAVE( updateText, text || '', _text);
3084 animate: function ( _x, _y, _w, _h, _a){
3085 update( _x, _y, _w, _h, _a, true);
3087 destroy: function(){
3088 JQ_WRAPPER.remove();
3089 XBROWSER_BALLOON.destroy();
3091 delete this.destroy;
3093 getAsJSON: function(){
3096 getAsJsonString: function(){
3099 getAsHTML: function(){},
3100 getAsXML: function(){}
3106 * リサイズが、ResizerTopによって行われた場合、comicElementのyを動かして見かけ上動かないようにする。
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);
3120 comicElementContainer.css( {
3129 * append, remove, replace
3131 * comicElement には、z-position と dom-index がある。
3132 * z-position は 表示上の位置。大きいほど前に表示される( z-index)
3133 * dom-index は 意味上の順番。htmlタグの登場順で、検索結果や音声読み上げブラウザで正しく意味が取れる順番。
3135 * editerでは、実際には z-index は使わず、htmlの順序で前後を表現する。
3136 * dom-index は、数値のみ保持して、投稿時にcomicElementを適宜に並び替える。
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 とは反対に、前のものほど後ろへ。
3145 * remove comicElement
3149 function appendComicElement( _comicElement) {
3150 _comicElement.init && _comicElement.init();
3151 var z = _comicElement.z,
3152 l = DRAGGABLE_ELEMENT_ARRAY.length;
3153 _comicElement.$.stop().css( {
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());
3161 var insertIndex = ( function(){
3162 for( var ret = NUM_RESIZER; ret < l; ++ret){
3163 if( DRAGGABLE_ELEMENT_ARRAY[ ret].z <= z) return ret +1;
3167 DRAGGABLE_ELEMENT_ARRAY[ insertIndex -1].$.after( _comicElement.$.fadeIn());
3168 DRAGGABLE_ELEMENT_ARRAY.splice( insertIndex, 0, _comicElement);
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);
3178 _comicElement.$.stop().css( {
3181 }).fadeOut( function(){
3182 this.parentNode.removeChild( this);
3184 currentElement = currentElement === _comicElement ? null : currentElement;
3189 function restoreComicElement( arg){
3190 var isAppend = arg[ 0],
3191 comicElement = arg[ 1];
3192 isAppend === true ? appendComicElement( comicElement) : removeComicElement( comicElement);
3195 * DRAGGABLE_ELEMENT_ARRAY の順番を基準に、zの再計算
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;
3209 function replaceComicElement( _comicElement, goForward){
3210 // DRAGGABLE_ELEMENT_ARRAYの再構築
3211 var l = DRAGGABLE_ELEMENT_ARRAY.length,
3213 for( var ret = NUM_RESIZER; ret < l; ++ret){
3214 if( DRAGGABLE_ELEMENT_ARRAY[ ret] === _comicElement) return ret;
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);
3224 if( i === l -1) return;
3225 DRAGGABLE_ELEMENT_ARRAY.splice( i, 1);
3226 DRAGGABLE_ELEMENT_ARRAY.splice( i +1, 0, _comicElement);
3230 function restoreReplaceObject( arg){
3231 replaceComicElement( arg[ 0], arg[ 1]);
3239 PANEL_RESIZER_TOP.init();
3240 PANEL_RESIZER_BOTTOM.init();
3244 comicElementContainer = $( '#comic-element-container');
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]));
3249 COMIC_ELEMENT_OPERATOR.init( updateMouseCursor);
3253 log = $( '#operation-catcher-log');
3256 log.html( 'vector' +h2c.balloon.enabled());
3257 delete COMIC_ELEMENT_CONTROL.init;
3260 onMouseMove: function( _mouseX, _mouseY){
3261 var l = DRAGGABLE_ELEMENT_ARRAY.length,
3262 _X = _mouseX -( _canvasX || canvasX),
3263 _Y = _mouseY -( _canvasY || canvasY),
3266 if( currentElement !== null && currentElement.dragging() === true){
3267 currentElement.onMouseMove( _X, _Y);
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
3278 for( var i=0; i<l; i++){
3279 _elm = DRAGGABLE_ELEMENT_ARRAY[ i];
3280 _x = _elm.hitareaX();
3281 _y = _elm.hitareaY();
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( ','));
3290 currentElement = null;
3291 COMIC_ELEMENT_OPERATOR.hide();
3292 log.html( [ _X, _Y, _x, _y].join( ','));
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;
3301 onMouseDown: function( _mouseX, _mouseY){
3304 currentElement !== null && currentElement.onMouseDown( _mouseX -canvasX, _mouseY -canvasY);
3305 return currentElement !== null;
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);
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();
3321 return currentElement !== null ? currentElement.dragging() : false;
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);
3335 createTextElement: function( type, angle, text, x, y, z, w, h){
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);
3355 function resize( isResizerTopAction){
3356 GRID_CONTROL.resize();
3357 WHITE_GLASS_CONTROL.resize();
3358 PANEL_BORDER_CONTROL.resize();
3359 COMIC_ELEMENT_CONTROL.resize( isResizerTopAction);
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);
3368 GRID_CONTROL.init();
3369 // WHITE_GLASS_CONTROL.init();
3370 PANEL_BORDER_CONTROL.init();
3371 COMIC_ELEMENT_CONTROL.init();
3376 .bind( h2c.key.SPACE_DOWN_EVENT, function(){
3377 hasFocus === true && isDragging === false && COMIC_ELEMENT_CONTROL.busy() === false && updateMouseCursor( 'crosshair');
3379 .bind( h2c.key.SPACE_UP_EVENT, function(){
3380 hasFocus === true && COMIC_ELEMENT_CONTROL.busy() === false && updateMouseCursor( '');
3384 delete CANVAS_CONTROL.init;
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);
3393 onMouseMove: function( _mouseX, _mouseY){
3395 if( isDragging === true){
3396 canvasX = startCanvasX +_mouseX -xOffset;
3397 canvasY = startCanvasY +_mouseY -yOffset;
3400 COMIC_ELEMENT_CONTROL.onMouseMove( _mouseX, _mouseY)
3403 onMouseUp: function( _mouseX, _mouseY){
3404 if( COMIC_ELEMENT_CONTROL.onMouseUp( _mouseX, _mouseY) === false && isDragging === true){
3406 updateMouseCursor( '');
3409 onMouseDown: function( _mouseX, _mouseY){
3410 if( COMIC_ELEMENT_CONTROL.onMouseDown( _mouseX, _mouseY) === false && isDragging === false && SPACE_ENABLED() === true){
3413 startCanvasX = canvasX;
3414 startCanvasY = canvasY;
3416 updateMouseCursor( 'move');
3419 onMouseClick: function( _mouseX, _mouseY){
3420 COMIC_ELEMENT_CONTROL.onMouseClick( _mouseX, _mouseY)
3422 onMouseOut: function( _mouseX, _mouseY){
3423 if( COMIC_ELEMENT_CONTROL.onMouseOut( _mouseX, _mouseY) === false){
3427 busy: function( _busy){
3429 return isDragging === true || COMIC_ELEMENT_CONTROL.busy();
3431 createImageElement: function( url, imagesetID, x, y, z, w, h){
3432 COMIC_ELEMENT_CONTROL.createImageElement( url, imagesetID, x, y, z, w, h);
3434 createTextElement: function( type, angle, text, x, y, w, h, z){
3435 COMIC_ELEMENT_CONTROL.createTextElement( type, angle, text, x, y, w, h, z);
3440 /* ----------------------------------------
3441 * Text Editor (Overlay)
3444 var TEXT_EDITOR_CONTROL = ( function(){
3445 var jqWrap, jqTextarea, jqButton,
3446 textElement, onUpdateFunction;
3450 textElement = onUpdateFunction = null;
3454 this.jqWrap = jqWrap = $( '#speach-editor-wrapper').hide();
3455 jqTextarea = $( '#speach-editor');
3456 jqButton = $( '#speach-edit-complete-button').click( function(){
3458 textElement && textElement.text( jqTextarea.val());
3459 onUpdateFunction && onUpdateFunction( textElement);
3462 delete TEXT_EDITOR_CONTROL.init;
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,
3476 jqTextarea.val( _textElement.text()).focus();
3479 * ie6,7は、textarea { width:100%}でも高さが変わらない。rowsを設定。
3481 h2c.isIE === true && h2c.ieVersion <= 7 && setTimeout( function(){
3483 while( jqTextarea.height() < h){
3485 jqTextarea.attr( 'rows', rows);
3487 rows > 1 && jqTextarea.attr( 'rows', rows -1);
3490 onWindowResize: function(){
3491 textElement && this.show( textElement);
3497 /* ----------------------------------------
3498 * Image Group Exproler (Overlay)
3500 var IMAGE_GROUP_EXPROLER = ( function(){
3501 var ICON_ARRAY = [],
3503 containerW, containerH, wrapX,
3504 jqWrap, jqContainer, jqItemOrigin,
3506 jqName, jqButton, buttonW,
3509 onEnterInterval = null;
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
3517 "created_at": "2011-11-13T08:57:39Z",
3522 "updated_at": "2011-11-13T08:57:39Z",
3526 "created_at": "2011-11-13T08:57:54Z",
3531 "updated_at": "2011-11-13T08:57:54Z",
3535 "created_at": "2011-11-13T08:58:06Z",
3540 "updated_at": "2011-11-13T08:58:06Z",
3544 "created_at": "2011-11-13T08:58:23Z",
3549 "updated_at": "2011-11-13T08:58:23Z",
3553 "created_at": "2011-11-13T08:58:33Z",
3558 "updated_at": "2011-11-13T08:58:33Z",
3562 "created_at": "2011-11-20T09:50:43Z",
3567 "updated_at": "2011-11-20T09:50:43Z",
3571 "created_at": "2011-11-20T09:50:55Z",
3576 "updated_at": "2011-11-20T09:50:55Z",
3580 "created_at": "2011-11-20T11:33:12Z",
3585 "updated_at": "2011-11-20T11:33:12Z",
3589 "created_at": "2011-11-20T11:33:12Z",
3594 "updated_at": "2011-11-20T11:33:12Z",
3598 "created_at": "2011-11-20T11:33:12Z",
3603 "updated_at": "2011-11-20T11:33:12Z",
3607 "created_at": "2011-11-20T11:33:12Z",
3612 "updated_at": "2011-11-20T11:33:12Z",
3616 "created_at": "2011-11-22T09:17:20Z",
3621 "updated_at": "2011-11-22T09:17:20Z",
3625 "created_at": "2011-11-22T10:11:07Z",
3630 "updated_at": "2011-11-22T10:11:07Z",
3634 "created_at": "2011-11-24T09:05:12Z",
3639 "updated_at": "2011-11-24T09:05:12Z",
3643 "created_at": "2011-11-26T04:52:12Z",
3648 "updated_at": "2011-11-26T04:52:12Z",
3652 "created_at": "2011-11-26T04:52:12Z",
3657 "updated_at": "2011-11-26T04:52:12Z",
3661 "created_at": "2011-11-26T04:52:12Z",
3666 "updated_at": "2011-11-26T04:52:12Z",
3670 "created_at": "2011-11-26T04:52:12Z",
3675 "updated_at": "2011-11-26T04:52:12Z",
3679 "created_at": "2011-11-26T04:52:12Z",
3684 "updated_at": "2011-11-26T04:52:12Z",
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}));
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) {
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){
3722 if (onUpdateFunction) {
3723 if( LOW_SRC === null){
3724 onUpdateFunction( SRC, imgW, imgH);
3726 ( function( onUpdate){
3727 h2c.util.loadImage( SRC,
3728 function( _abspath, imgW, imgH){
3729 onUpdate( SRC, imgW, imgH);
3732 function( _abspath){
3733 onUpdate( SRC, data.width || 64, data.height || 64);
3737 })( onUpdateFunction); // close()で値が消えるので、クロージャに保持
3743 JQ_ICON_WRAP.children( 'img').replaceWith( reversibleImage.elm);
3746 destroy: function(){
3747 reversibleImage && reversibleImage.destroy();
3748 JQ_ICON_WRAP.remove();
3749 reversibleImage = JQ_ICON_WRAP = null;
3750 delete this.destroy;
3756 jqContainer.stop().animate( {
3758 top: Math.floor( windowH /2)
3762 while( ICON_ARRAY.length > 0){
3763 ICON_ARRAY.shift().destroy();
3765 onEnterInterval !== null && window.clearTimeout( onEnterInterval);
3766 onUpdateFunction = onEnterInterval = null;
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();
3775 onEnterInterval !== null && window.clearTimeout( onEnterInterval);
3776 onEnterInterval = null;
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});
3788 onEnterInterval !== null && window.clearTimeout( onEnterInterval);
3789 onEnterInterval = window.setTimeout( onEnterShowImage, 500);
3791 //e.stopPropagation();
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(){
3802 // onUpdateFunction && onUpdateFunction( textElement);
3805 buttonW = h2c.util.getElementSize( jqButton.get( 0)).width;
3806 delete IMAGE_GROUP_EXPROLER.init;
3809 show: function( _onUpdateFunction){
3810 onUpdateFunction = _onUpdateFunction;
3811 h2c.overlay.show( this);
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]]));
3819 containerW = l * itemW;
3822 var w = winW > containerW ? winW : containerW,
3823 h = windowH > containerH ? containerH : windowH;
3830 top: Math.floor( windowH /2)
3831 }).stop().animate( {
3833 top: Math.floor( windowH /2 -h /2)
3837 left: Math.floor( winW /2 -buttonW /2),
3838 top: Math.floor( windowH /2 +containerH /2 +10)
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);
3848 if( offsetW <= 0){ // smaller
3854 top: Math.floor( _windowH /2 -h /2)
3857 jqContainer.css( { // bigger
3860 borderLeftWidth: offsetW
3862 top: Math.floor( _windowH /2 -h /2),
3867 left: Math.floor( _windowW /2 -buttonW /2),
3868 top: Math.floor( _windowH /2 +containerH /2 +10)
3876 function updateMouseCursor( _cursor){
3877 if( currentCursor !== _cursor){
3878 currentCursor = _cursor;
3879 ELM_MOUSE_EVENT_CHATCHER.style.cursor = _cursor;
3882 function centering(){
3883 h2c.editor.onWindowResize( windowW, windowH);
3885 function mouseEventRellay( rellayMethod, e){
3886 var _mouseX = e.pageX,
3888 if( currentListener !== null && currentListener.busy() === true){
3889 currentListener[ rellayMethod]( _mouseX, _mouseY);
3891 currentListener = null;
3892 var l = MOUSE_LISTENER_ARRAY.length,
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;
3900 _listener.busy( false);
3904 e.stopPropagation();
3910 var jqWindow = h2c.jqWindow();
3911 windowW = jqWindow.width();
3912 windowH = jqWindow.height();
3914 jqEditor = $( '#editor');
3916 h2c.key.addKeyEvent( 96, false, true, centering);
3917 h2c.key.addKeyEvent( 48, false, true, centering);
3920 MENU_BAR_CONTROL.EDIT.createSelection( 'centering', 'ctrl + 0', centering, true, true, true);
3922 WINDOWS_CONTROL.init();
3923 CANVAS_CONTROL.init();
3926 MENU_BAR_CONTROL.init();
3928 TEXT_EDITOR_CONTROL.init();
3929 IMAGE_GROUP_EXPROLER.init();
3931 * jqMouseEventChacher は透明な要素で、
3932 * マウスイベントをcurrentElement(currentElement)に伝えるのが仕事
3933 * このような実装になるのは、ここの表示オブジェクトにイベントを設定した場合、表示が追いつかずマウスカーソルが外れたタイミングでイベントが終わってしまうため。
3936 * MOUSE_LISTENER_ARRAY は、表示順に格納.手前の要素が最初
3940 * .busy() === true なら、そのままonMouseMove()にイベントを流す.これはArrayの後ろから、奥の表示要素から
3941 * onMouseMove()に流してみて、false が帰れば、次にリスナーにも流す.
3943 MOUSE_LISTENER_ARRAY.push( MENU_BAR_CONTROL, WINDOWS_CONTROL, CANVAS_CONTROL);
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,
3957 if( CANVAS_CONTROL.busy() === true || WINDOWS_CONTROL.onMouseClick( _mouseX, _mouseY) === false){
3958 CANVAS_CONTROL.onMouseClick( _mouseX, _mouseY);
3960 e.stopPropagation();
3963 height: windowH // ie6
3966 delete h2c.editor.init;
3968 onWindowResize: function( _windowW, _windowH){
3975 jqEditor.get( 0).style.height = _windowH +'px';
3976 ELM_MOUSE_EVENT_CHATCHER.style.height = _windowH +'px';
3978 WINDOWS_CONTROL.onWindowResize( _windowW, _windowH);
3979 MENU_BAR_CONTROL.onWindowResize( _windowW, _windowH);
3980 CANVAS_CONTROL.onWindowResize( _windowW, _windowH);
3987 h2c.log = ( function(){
3993 h2c.io = ( function(){
4003 * お気に入り画像一覧 > tag:ペン次郎 > ペン次郎:笑う
4004 * 最近アップロードされた画像 > images
4006 * キャラクター画像庫 > アニマル系 > tag:ペン次郎 > ペン次郎:笑う
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 = [];
4034 var REQUEST_CONTROLER = ( function(){
4035 var REQUEST_TICKET_RESISTER = [],
4038 var RequestTicketClass = ( function(){
4044 delete REQUEST_CONTROLER.init;
4046 getJson: function( _url, _onLoad, _onError){
4047 REQUEST_TICKET_RESISTER.push( RequestTicketClass.apply( {}, [ _url, _onLoad, _onError]));
4051 /* ----------------------
4055 * ID( imgGroupID, comicID)
4056 * ----------------------
4068 * groupID - updateGropuID
4069 * actualWidth, actualHeight,
4070 * author, licence( 'by,no-resize'),
4071 * create, update, tag,
4072 * actualWidth, actualHeight
4074 * ----------------------
4097 * ----------------------
4099 var FILE_CONTROLER = ( function(){
4100 var FILE_EVENT_LISTENER_RESISTER = [],
4103 var TreeClass = function( TREE_ROOTFILE){
4104 var UID = TREE_ACCESS.length,
4105 currentFile = TREE_ROOTFILE,
4106 PARENT_FILE_RESITER = [],
4108 fileEventChatcher: dispatchFileEvent,
4112 function dispatchFileEvent( fileEvent){
4115 function onDestroy(){
4119 TREE_ACCESS.push( ACCESS);
4121 FILE_CONTROLER.getSeqentialFiles( currentFile);
4123 ROOT_FILE :function(){
4124 return TREE_ROOTFILE;
4126 currentFile: function(){
4129 hierarky: function(){
4130 return PARENT_FILE_RESITER.length;
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);
4140 if( PARENT_FILE_RESITER.length === 0) return;
4141 currentFile = PARENT_FILE_RESITER.shift();
4142 FILE_CONTROLER.getSeqentialFiles( currentFile);
4145 addEventListener: function( UID, _eventType, _callback){
4146 FILE_CONTROLER.addEventListener( UID, _eventType, _callback);
4148 removeEventListener: function( UID, _eventType, _callback){
4149 FILE_CONTROLER.removeEventListener( UID, _eventType, _callback);
4151 createSearchResultFolder: function( _searchParam){
4154 destroySearchResultFolder: function( _searchParam){
4157 destroy: function(){
4158 FILE_CONTROLER.destroyTree( UID);
4163 var FileEventTicketClass = function( UID, _eventType, _callback){
4166 eventType: _eventType,
4171 var FileEventClass = function( eventType, file, key, value){
4173 eventType: eventType,
4175 updatedAttribute: key,
4180 function disptchFileEvent( eventType, fileUID, key, value){
4181 var _fileEvent = FileEventClass.apply( {}, [ eventType, fileUID, key, value]),
4182 l = TREE_ACCESS.length,
4184 for( var i=0; i<l; ++i){
4185 _tree = TREE_ACCESS[ i];
4186 _tree !== null && _tree.fileEventChatcher( _fileEvent);
4189 function getFileDataAccess( UIDorFILE){
4190 var l = FILEDATA_ACCESS.length,
4191 i = typeof UIDorFILE === 'number' ?
4192 ( UIDorFILE > 0 && UIDorFILE > l ? UIDorFILE : -1) :
4194 for( var i=0; i<l; ++i){
4195 if( FILEDATA_ACCESS[ i] === UIDorFILE) return i;
4199 return i !== -1 ? FILEDATA_ACCESS[ i] : null;
4204 delete FILE_CONTROLER.init;
4206 createTree: function( _rootFileData){
4207 return TreeClass.apply( {}, [ _rootFileData]);
4209 getFileData: function( _file){
4210 var _access = getFileDataAccess( _file);
4211 return _access !== null ? _access.DATA : null;
4213 getSeqentialFiles: function( _uid){
4216 updateFileAttribute: function( _uid, key, _value, _opt_callback){
4217 var _fileData = getFileDataAccess( _uid),
4218 _type = _fileData.TYPE;
4221 getFileAttribute: function( _uid, KEYorKEYARRAY){
4222 var _fileData = getFileDataAccess( _uid),
4223 _type = _fileData.TYPE;
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;
4231 replace: function( _uid, _file, _newIndex){
4238 * fileのdataはobjectで保持している。
4239 * h2c.file.の外からファイルをみるときは、FileClassを通して操作する。
4240 * fileの変更、それに付随して追加されたイベントは、treeで管理される。
4241 * treeがdestryされると、fileのイベントリスナーも全て削除される。
4244 var FileClass = function( TREE, PARENT_FILE, DATA){
4245 var TYPE = DATA.type,
4246 UID = FILEDATA_ACCESS.length,
4247 CHILDREN = DATA.children;
4249 FILEDATA_ACCESS.push(
4254 destroy: function(){
4255 PARENT_FILE = DATA = CHILDREN = null;
4256 delete this.destroy;
4261 TYPE: function(){ return TYPE;},
4263 return DATA.state !== undefined ? DATA.state : FILE_STATE_IS_OK;
4265 childFileLength: function(){
4266 return typeof CHILDREN === 'array' ? CHILDREN.length : 0;
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]]);
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;
4280 return FILE_CONTROLER.getFileData( _FILEorFILEDATA);
4282 if( _fileData === null) return -1;
4283 for( var i=0; i<l; ++i){
4284 if( CHILDREN[ i] === _fileData) return i;
4288 isChildFile: function( _FILEorFILEDATA){
4289 return this.getChildFileIndex( _FILEorFILEDATA) !== -1;
4291 getAttribute: function( KEYorKEYARRAY){
4292 return FILE_CONTROLER.getFileAttribute( UID, KEYorKEYARRAY);
4294 getSeqentialFiles: function(){
4295 FILE_CONTROLER.getSeqentialFiles( this);
4297 updateAttribute: function( key, value, opt_callback){
4298 TREE.updateFileAttribute( UID, key, value, opt_callback);
4300 move: function( _newFolder, _newIndex, opt_callback){
4301 TREE.move( PARENT_FILE, UID, _newFolder, _newIndex, opt_callback);
4303 replace: function( _newIndex, opt_callback){
4304 TREE.replace( PARENT_FILE, UID, _newIndex, opt_callback);
4306 addEventListener: function( _eventType, _callback){
4307 TREE.addEventListener( UID, _eventType, _callback);
4309 removeEventListener: function( _eventType, _callback){
4310 TREE.removeEventListener( UID, _eventType, _callback);
4315 var ROOT_FILEDATA = {
4317 type: FILE_TYPE_IS_FOLDER,
4322 type: FILE_TYPE_IS_FOLDER
4326 type: FILE_TYPE_IS_FOLDER
4328 SETTING_FILEDATA = {
4329 name: 'setting root',
4330 type: FILE_TYPE_IS_FOLDER
4334 type: FILE_TYPE_IS_FOLDER
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);
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);
4352 REQUEST_CONTROLER.init();
4353 FILE_CONTROLER.init();
4354 delete h2c.file.init;
4356 createTree: function( _treeType){
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);
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
4380 h2c.fn( h2c.overlay);
4382 h2c.fn( h2c.balloon);
4383 h2c.fn( h2c.editor);
4386 $(window).ready( h2c.init);