OSDN Git Service

Client is version 0.5.49, start to post sppech balloon.
[pettanr/pettanr.git] / app / assets / javascripts / peta-common.js
1 /*\r
2  * pettanR peta.common.js\r
3  *   version 0.5.49\r
4  * \r
5  *   author:\r
6  *     itozyun\r
7  *   licence:\r
8  *     3-clause BSD\r
9  */\r
10 \r
11 var pettanr = ( function(){\r
12         var     IS_LOCAL = document.location.href.indexOf( 'file:') === 0,\r
13                 URL_PARAMS = ( function(){\r
14                         var search = document.location.search,\r
15                                 l = search.length;\r
16                     if( 1 < l){\r
17                         var     query = search.substring( 1),\r
18                                         params = query.split( '&'),\r
19                                         ret = {}, elm, name, v;\r
20                         while( params.length > 0){\r
21                             elm = params.shift().split( '=');\r
22                                         name = decodeURIComponent( elm[ 0 ]);\r
23                                         if( elm.length === 2){\r
24                                                 v = decodeURIComponent( elm[ 1]);\r
25                                                 if( '' + parseFloat( v ) === v ) v = parseFloat( v );\r
26                                                 if( '' + parseInt( v, 10 ) === '0' + v ) v = parseInt( v, 10 );\r
27                                                 if( v === 'true' ) v = true;\r
28                                                 if( v === 'false' ) v = false;\r
29                                                 if( v === 'null' ) v = null;\r
30                                                 if( v === 'undefined' ) v = undefined;\r
31                                     ret[ name] = v;\r
32                                         } else\r
33                                         if( elm.length === 1){\r
34                                                 ret[ name] = true;\r
35                                         };\r
36                                 };\r
37                         return ret;\r
38                     };\r
39                     return {};\r
40                 })(),\r
41                 IS_DEBUG = Type.isBoolean( URL_PARAMS.debug ) ? URL_PARAMS.debug : IS_LOCAL === true;\r
42         return {\r
43                 version: '0.5.40',\r
44                 URL_PARAMS: URL_PARAMS,\r
45                 LOCAL: IS_LOCAL,\r
46                 DEBUG: IS_DEBUG,\r
47                 LINE_FEED_CODE_TEXTAREA: ( function(){\r
48                         var text = document.createElement('textarea');\r
49                         text.value = '\n';\r
50                         return text.value;\r
51                 })(),\r
52                 LINE_FEED_CODE_PRE: ( function(){\r
53                         var pre = document.createElement('pre');\r
54                         pre.appendChild( document.createTextNode('\n'));\r
55                         return pre.firstChild.data;\r
56                 })()\r
57         }\r
58 })();\r
59 \r
60 pettanr.CONST = ( function(){\r
61         var SERVER_SUPPORT    = !( 'has_server_support' in window && has_server_support === false ),\r
62                 PETTANR_ROOT_PATH = ( function(){\r
63                         if( SERVER_SUPPORT === false ){\r
64                                 var h1 = document.getElementsByTagName( 'h1' )[ 0 ];\r
65                                 if( h1 ){\r
66                                         var a = h1.getElementsByTagName( 'a' )[ 0 ];\r
67                                         return a ? a.href : '';\r
68                                 }\r
69                                 return '';\r
70                         };\r
71                         var loc = document.location;\r
72                         return [ loc.protocol, '\/\/', loc.host, '\/' ].join( '' );\r
73                 })(),\r
74                 RELATIVE = ( function(){\r
75                         if( PETTANR_ROOT_PATH === '' ) return '';\r
76                         var ret  = '',\r
77                                 loc  = document.location,\r
78                                 path = [ loc.protocol, '\/', loc.host, '\/', loc.pathname.split( '\\' ).join( '\/' ) ].join( '' ),\r
79                                 l    = path.split( '\/' ).length - PETTANR_ROOT_PATH.split( '\/' ).length;\r
80                         for( var i=0; i<l; ++i ){\r
81                                 ret += '..\/';\r
82                         };\r
83                         return ret;\r
84                 })();\r
85                 \r
86         return {\r
87                 PETTANR_ROOT_PATH             : PETTANR_ROOT_PATH,\r
88                 URL_MY_ORIGINAL_PICTURES_JSON : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'original_pictures.json',\r
89                 URL_MY_RESOURCE_PICTURES_JSON : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/resource_pictures.json',\r
90                 URL_RESOURCE_PICTURES_JSON    : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'resource_pictures.json',\r
91                 URL_MY_RESOURCE_PICTURES_JSON : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/resource_picture.json',\r
92                 URL_COMICS_JSON               : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'comics.json',\r
93                 URL_MY_COMICS_JSON            : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/comic.json',\r
94                 URL_PANELS_JSON               : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'panels.json',\r
95                 URL_MY_PANELS_JSON            : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/panel.json',\r
96                 SPEECH_BALOON_TEMPLETE        : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'speech_balloon_templates.json\/',\r
97                 NS_PETTANR_COMIC              : 'pettanr-comic',\r
98                 THUMBNAIL_PATH                : SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/thumbnail\/' : PETTANR_ROOT_PATH + 'resource_pictures\/',\r
99                 RESOURCE_PICTURE_PATH         : SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/' : PETTANR_ROOT_PATH + 'resource_pictures\/full\/',\r
100                 ORIGINAL_PICTURE_PATH         : SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/' : PETTANR_ROOT_PATH + 'original_pictures\/',\r
101                 PICTURE_PATH                  : SERVER_SUPPORT === false ? RELATIVE + 'pictures\/' : PETTANR_ROOT_PATH + 'pictures\/',\r
102                 SYSTEM_PICTURE_PATH           : ( SERVER_SUPPORT === false ? RELATIVE : PETTANR_ROOT_PATH ) + 'system_pictures\/',\r
103                 CREATE_COMIC_JS               : SERVER_SUPPORT === false ? 'js\/create_new_comic.js' : PETTANR_ROOT_PATH + 'comics\/new.js',\r
104                 CREATE_PANEL_JS               : SERVER_SUPPORT === false ? 'js\/create_new_panel.js' : PETTANR_ROOT_PATH + 'panels\/new.js',\r
105                 UPLOAD_PICTURE_JS             : SERVER_SUPPORT === false ? 'js\/upload_picture.js' : PETTANR_ROOT_PATH + 'original_pictures\/new.js',\r
106                 REGISTER_ARTIST_JS            : SERVER_SUPPORT === false ? 'js\/register_artist.js' : PETTANR_ROOT_PATH + 'artists\/new.js',\r
107                 SERVER_SUPPORT                : SERVER_SUPPORT,\r
108                 URL_PETA_APPS_CSS             : ( SERVER_SUPPORT === false ? 'stylesheets' : '\/assets' ) + '\/peta.apps.css'\r
109         }\r
110 })();\r
111 \r
112 /* ----------------------------------------\r
113  * Vector Support\r
114  * \r
115  *              __________\r
116  *             /          \\r
117  *            /            \\r
118  *            |,startX,Y    |\r
119  * tailX,Y - <              |\r
120  *            |'endX,Y      |\r
121  *            \            /\r
122  *                 \__________/\r
123  * \r
124  * SVG\r
125  * -----------------------\r
126  * ie9, other modern browser\r
127  * \r
128  * XML\r
129  * -----------------------\r
130  * ie5.5-8\r
131  * \r
132  * 内部の角度計算は radian で統一したい。\r
133  * 当初 vectorEnabled = true で一度書いてみる。\r
134  * 駄目なら、代替のイメージのsrcの用意もここで担当。\r
135  * 閲覧と編集両方で使う。\r
136  * \r
137  */\r
138 pettanr.balloon = ( function() {\r
139         var MIN_BALLOON_WIDTH  = 30,\r
140                 MIN_BALLOON_HEIGHT = 30,\r
141                 NUM_BALLOON_IMAGE  = 24,\r
142                 TAIL_WIDTH         = 6,\r
143                 TAIL_HEIGHT        = 10,\r
144                 STROKE_WIDTH       = 1.2,\r
145                 PADDING_TOP        = TAIL_HEIGHT,\r
146                 PADDING_LEFT       = TAIL_HEIGHT,\r
147                 IS_VML             = UA.isIE === true && UA.ieVersion < 9,\r
148                 ELM_BALLOON_ORIGIN = ( function(){\r
149                         var ret;\r
150                         try {\r
151                                 if( IS_VML === true ){\r
152                                         ret = document.createElement( 'DIV');\r
153                                         var shape = document.createElement( 'v:shape');\r
154                                         shape.coordorigin = "0,0";\r
155                                         shape.strokecolor = "black";\r
156                                         shape.strokeweight = STROKE_WIDTH;\r
157                                         shape.fillcolor = "white";\r
158                                         ret.appendChild( shape);\r
159                                 } else {\r
160                                         var kSVGNS = 'http://www.w3.org/2000/svg';\r
161                                         // http://modernizr.com/downloads/modernizr.js\r
162                                         // Thanks to Erik Dahlstrom\r
163                                         if( !document.createElementNS || !document.createElementNS(kSVGNS, 'svg').createSVGRect ){\r
164                                                 return null;\r
165                                         };\r
166                                         ret = document.createElementNS( kSVGNS, 'svg');\r
167                                         var path = document.createElementNS( kSVGNS, 'path');\r
168                                         path.setAttribute( 'fill', "white");\r
169                                         path.setAttribute( 'stroke', "black");\r
170                                         path.setAttribute( 'strokeWidth', STROKE_WIDTH);\r
171                                         ret.appendChild( path );\r
172                                 };\r
173                                 return ret;     \r
174                         } catch( e){\r
175                                 return null;\r
176                         }\r
177                 })(),\r
178                 vectorEnabled = ELM_BALLOON_ORIGIN !== null &&\r
179                                                 pettanr.URL_PARAMS.vector !== false &&\r
180                                                 !( IS_VML === true && UA.VML === false );\r
181 \r
182         var cos        = Math.cos,\r
183                 sin        = Math.sin,\r
184                 abs        = function(v){ return v >= 0 ? v : -1; },\r
185                 pow        = Math.pow,\r
186                 round      = Math.round,\r
187                 floor      = Math.floor,\r
188                 TARGET     = TAIL_WIDTH * TAIL_WIDTH,\r
189                 isFinit    = Type.isFinite,\r
190                 ACCURACY   = 1, // 有効少数桁      \r
191                 cround     = function( v, r ){\r
192                                                 r = r || ACCURACY;\r
193                                                 return round( v * pow( 10.0, r )) / pow( 10.0, r );\r
194                                         },\r
195                 DEG_TO_RAD = Math.PI / 180;\r
196 \r
197         var XBROWSER_BALLOON_CLASS = function( w, h, a ){\r
198                 this.elm   = vectorEnabled === true ? ELM_BALLOON_ORIGIN.cloneNode( true ) : document.createElement( 'img' ); // pettanr.imageに変更\r
199                 this.path  = this.elm.getElementsByTagName( IS_VML === true ? 'shape' : 'path' )[ 0 ];\r
200                 this.resize( a, w, h );\r
201         };\r
202         XBROWSER_BALLOON_CLASS.prototype = {\r
203                 elm   : null,\r
204                 path  : null,\r
205                 w     : 0,\r
206                 h     : 0,\r
207                 a     : 0,\r
208                 resize : function ( _a, _w, _h ){\r
209                         this.w  = isFinit( _w ) === true ? _w - PADDING_TOP  * 2 : this.w;\r
210                         this.h  = isFinit( _h ) === true ? _h - PADDING_LEFT * 2 : this.h;\r
211                         // ie6 でリサイズが反応しない対策\r
212                         if( vectorEnabled === false && UA.isIE === true && UA.ieVersion < 7 ){\r
213                                 var parent = this.elm.parentNode;\r
214                                 parent.removeChild( this.elm );\r
215                                 parent.insertBefore( this.elm, parent.firstChild );\r
216                         };\r
217                         this.angle( _a );\r
218                 },\r
219                 angle : function( _a ){\r
220                         if( isFinit( _a ) === true ){\r
221                                 this.a = _a;\r
222                                 if( vectorEnabled === false ){\r
223                                         this.elm.src = pettanr.balloon.getBalloonUrl( this.w, this.h, _a );\r
224                                 } else {\r
225                                         this.draw( _a );\r
226                                 };\r
227                         };\r
228                         return this.a;\r
229                 },\r
230                 type : function( _type ){\r
231                         //draw( _a);\r
232                 },\r
233                 destroy : function(){\r
234                         this.elm.parentNode && this.elm.parentNode.removeChild( this.elm );\r
235                         delete this.elm;\r
236                         delete this.path;\r
237                 },\r
238                 draw : function( _a ){\r
239                         var rx      = this.w / 2,\r
240                                 ry      = this.h / 2,\r
241                                 l       = ',',\r
242                                 tailRad = _a * DEG_TO_RAD,\r
243                                 tailX   = rx + ( rx + TAIL_HEIGHT ) * sin( tailRad ),\r
244                                 tailY   = ry - ( ry + TAIL_HEIGHT ) * cos( tailRad ),\r
245                                 startX, startY, endX, endY;\r
246                 /*\r
247                  * tailの太さをTAIL_WIDTHに一致させるため、角度を絞りつつ計算\r
248                  */\r
249                         var startRad, endRad,\r
250                                 _startX, _startY, _endX, _endY,\r
251                                 tailDeg = 0, d;\r
252                         \r
253                         for( var i = 45; i > 0.01; i /= 2){\r
254                                 d = ( tailDeg + i ) / 2;\r
255                                 startRad = ( _a + d ) * DEG_TO_RAD;\r
256                                 endRad   = ( _a - d ) * DEG_TO_RAD;\r
257                                 \r
258                                 _startX  = rx + sin( startRad ) * rx;\r
259                                 _startY  = ry - cos( startRad ) * ry;\r
260                                 _endX    = rx + sin( endRad ) * rx;\r
261                                 _endY    = ry - cos( endRad ) * ry;     //円弧上のY位置=円中心Y+sin(角度×PI÷180)×円半径\r
262                                         \r
263                                 if( pow( ( _startX - _endX ), 2 ) + pow( ( _startY - _endY ), 2 ) < TARGET ){\r
264                                         tailDeg += i;\r
265                                         startX  = _startX;\r
266                                         startY  = _startY;\r
267                                         endX    = _endX;\r
268                                         endY    = _endY;\r
269                                 };\r
270                         };\r
271 \r
272                 /*\r
273                  * \r
274                  */                     \r
275                         if( IS_VML === true ){\r
276                                 var _tailX = tailX *10,\r
277                                         _tailY = tailY *10,\r
278                                         __w = this.w *10,\r
279                                         __h = this.h *10;\r
280                                 \r
281                                 this.path.style.width  = this.w + 'px';\r
282                                 this.path.style.height = this.h + 'px';\r
283                                 this.path.coordsize = [ __w, __h ].join( l );\r
284                                 this.path.path = [\r
285                                         ' ar ', 0, l, 0, l, __w, l, __h, l,\r
286                                         round( endX * 10 ), l, round( endY * 10 ), l,\r
287                                         round( startX * 10 ), l, round( startY * 10 ),\r
288                                         ' l ', round( _tailX ), l, round( _tailY ),\r
289                                         ' x e'\r
290                                 ].join( '' );\r
291 \r
292                                 this.elm.style.marginTop =  _tailY < 0 ? floor( ( 60 + _tailY) / 10 ) : 10;\r
293                                 this.elm.style.marginLeft = _tailX < 0 ? floor( ( 60 + _tailX) / 10 ) : 10;\r
294                         } else {\r
295                                 this.elm.setAttribute( 'width',  this.w + PADDING_LEFT *2 );\r
296                                 this.elm.setAttribute( 'height', this.h + PADDING_TOP *2 );\r
297                                 this.path.setAttribute( 'd', [\r
298                                         'M', cround( tailX + PADDING_LEFT ),  l, cround( tailY  + PADDING_TOP ),\r
299                                         'L', cround( startX + PADDING_LEFT ), l, cround( startY + PADDING_TOP ),\r
300                                         'A', rx, l, ry,\r
301                                         '0 1 1',                        // flag\r
302                                         cround( endX + PADDING_LEFT ), l, cround( endY + PADDING_TOP ),\r
303                                         'z'\r
304                                 ].join( ' '));\r
305                         }\r
306                 }\r
307         };\r
308         \r
309         return {\r
310             createBalloon: function( _w, _h, _a ){\r
311                 return new XBROWSER_BALLOON_CLASS( _w, _h, _a );\r
312             },\r
313             isBalloonInstance: function( _ballon ){\r
314                 \r
315             },\r
316             getBalloonUrl: function( _w, _h, _a ){\r
317                         var d = 360 / NUM_BALLOON_IMAGE;\r
318                         _a = _a + d / 2;\r
319                         return [\r
320                                 pettanr.CONST.SYSTEM_PICTURE_PATH, '_w',\r
321                                 _a < 360 - d / 2 ? floor( _a / d ) : 0,\r
322                                 _w <= 400 || _h <= 400 ? '_b1' : '',\r
323                                 '.gif' ].join( '' );\r
324             },\r
325                 TYPE_NONE:                              0,\r
326                 TYPE_SPEACH_BALLOON:    1,\r
327                 TYPE_THINKING:                  2,\r
328                 TYPE_BOM:                               3,\r
329                 TYPE_BLACK_BOX:                 4,\r
330                 TYPE_BLUE_BOX:                  5\r
331         }\r
332 })();\r
333 \r
334 pettanr.newBalloon = ( function(){\r
335         return {\r
336                 register : function( className ){\r
337                         \r
338                 },\r
339                 isBalloonClass : function(){\r
340                         \r
341                 },\r
342                 isBalloonInstance : function(){\r
343                         \r
344                 }\r
345         }\r
346 })();\r
347 \r
348 /* ----------------------------------------\r
349  *  pettanr.image\r
350  *  \r
351  *   xBackendな画像反転、画像描画機能。\r
352  *   \r
353  *   画像の反転\r
354  *     - css3\r
355  *     - ActiveX (ie)\r
356  *     - VML (ie)\r
357  *     - canvas ??\r
358  *     - flash(lite)\r
359  *     - silverlight\r
360  *     - pettan server\r
361  *   \r
362  *   png画像の表示(アルファpngをサポートしないie6以下のため)\r
363  *     - ActiveX\r
364  *     - VML\r
365  *     - flash(lite)\r
366  *     - silverlight\r
367  *     - pettan server\r
368  * \r
369  *     -moz-transform:scale( -1, -1);\r
370  */\r
371 pettanr.image = ( function(){\r
372         \r
373         var FetchImageControl = ( function(){\r
374                 var TASK_LIST = [];\r
375 \r
376                 /* \r
377                  * FetchClass original is\r
378                  * \r
379                  * LICENSE: MIT?\r
380                  *  URL: http://d.hatena.ne.jp/uupaa/20080413/1208067631\r
381                  *  AUTHOR: uupaa.js@gmail.com\r
382                  * \r
383                  */\r
384 \r
385                 var FetchClass = function( abspath, onLoadCallback, onErrorCallback, delay, timeout ){\r
386                         var img,\r
387                                 size,\r
388                                 tick = 0,\r
389                                 timer = null,\r
390                                 finish = false;\r
391                                 /*\r
392                         if( UA.isIE === false && UA.ieVersion < 8 ){\r
393                                 var images = document.images,\r
394                                         i=0, l= images.length;\r
395                                 for( i=0; i<l; ++i ){\r
396                                         img = images[ i ];\r
397                                         if( img.src === abspath && img.complete ){\r
398                                                 finish = true;\r
399                                                 size = Util.getImageSize( img );\r
400                                                 timer = window.setTimeout( asyncCallback, 0 );\r
401                                                 break;\r
402                                         }\r
403                                 }\r
404                                 images = null;\r
405                         }*/\r
406                         //if( finish === false ){\r
407                                 img = document.createElement( 'img' ); //var img = new Image(); ではieでimgのsizeが取れない、、、removeChildも失敗し、imgSizeGetterにimgが残る\r
408                                 img.onabort = img.onerror = onError;\r
409                                 img.onload = onLoad;\r
410                                 img.src = abspath;\r
411                                 finish === false && timeout && detect();\r
412                         //}\r
413                         \r
414                         function onError(){\r
415                                 if( finish === true ) return;\r
416                                 finish = true;\r
417                                 timer = window.setTimeout( asyncCallback, 10 );\r
418                         }                       \r
419                         function onLoad(){\r
420                                 // if( finish === true ) return; // これがあると firefox3.6 で駄目、、、\r
421                                 // if( timer ) return; // これがあると safari3.2 で駄目、、、\r
422                                 finish = true;\r
423                                 timer !== null && window.clearTimeout( timer );\r
424                                 if( window.opera && !img.complete ){\r
425                                         timer = window.setTimeout( asyncCallback, 10 );\r
426                                         return;\r
427                                 }\r
428                                 size = Util.getImageSize( img );\r
429                                 timer = window.setTimeout( asyncCallback, 10 );\r
430                         }\r
431                         function detect(){\r
432                                 if( finish === true ) return;\r
433                                 if( img.complete ){\r
434                                         finish = true;\r
435                                         if( img.width ) return;\r
436                                         timer = window.setTimeout( asyncCallback, 10 );\r
437                                         return;\r
438                                 }\r
439                                 if( ( tick += delay ) > timeout ){\r
440                                         finish = true;\r
441                                         timer = window.setTimeout( asyncCallback, 10 );\r
442                                         return;\r
443                                 }\r
444                                 timer = window.setTimeout( detect, delay );\r
445                         }\r
446                         \r
447                         function asyncCallback(){\r
448                                 size ? onLoadCallback( abspath, size.width, size.height ) : onErrorCallback( abspath );\r
449                                 destroy();\r
450                         }\r
451                         function destroy(){\r
452                                 finish  = true;\r
453                                 img.src = img.onload = img.onabort = img.onerror = '';\r
454                                 img     = void 0;\r
455                                 size    = onLoadCallback = onErrorCallback = timer = null;\r
456                         }\r
457                         this.stop = function(){\r
458                                 timer !== null && window.clearTimeout( timer );\r
459                                 destroy();                      \r
460                         }\r
461                 }\r
462                 \r
463                 return {\r
464                         load: function( URLorELM, onLoad, onError, delay, opt_timeout ){\r
465                                 var src, fetch;\r
466                                 if( Type.isString( URLorELM ) === true ){\r
467                                         src = URLorELM;\r
468                                 } else\r
469                                 if( Type.isHTMLElement( URLorELM ) === true && URLorELM.tagName.toLowerCase() === 'img' ){\r
470                                         src = URLorELM.src;\r
471                                 } else {\r
472                                         return;\r
473                                 }\r
474                                 \r
475                                 fetch = new FetchClass(\r
476                                         Util.getAbsolutePath( src ),\r
477                                         onLoad, onError,\r
478                                         Type.isFinite( delay ) === true ? delay : 250,\r
479                                         Type.isFinite( opt_timeout ) === true ? opt_timeout : undefined\r
480                                 );\r
481                                 // TASK_LIST.push( fetch );\r
482                                 \r
483                                 return fetch;\r
484                         }\r
485                 }\r
486         })();\r
487         \r
488         var REG_PNG           = /\.png?/i,\r
489                 IS_CSS3           = 0,\r
490                 IS_VML            = 1,\r
491                 IS_ACTIVEX        = 2,\r
492                 IS_CANVAS         = 3,\r
493                 IS_FLASH          = 4,\r
494                 IS_SILVERLIGHT    = 5,\r
495                 IS_SERVER         = 6,\r
496                 IS_ACTIVEX_SERVER = 7,\r
497                 BACKEND = ( function(){\r
498                         if( pettanr.DEBUG === true && pettanr.URL_PARAMS.rimg ){\r
499                                 var rimg = pettanr.URL_PARAMS.rimg.toLowerCase();\r
500                                 if( rimg === 'css3' ) return IS_CSS3;\r
501                                 if( rimg === 'activex' ) return IS_ACTIVEX;\r
502                                 if( rimg === 'vml' ) return IS_VML;\r
503                         }\r
504                         if( UA.isIE === false || UA.ieVersion >= 9 ) return IS_CSS3; // 不十分!\r
505                         if( UA.VML === true ) return IS_VML;\r
506                         if( UA.ACTIVEX === true ) return IS_ACTIVEX;\r
507                         if( pettanr.FLASH === true ) return IS_FLASH;\r
508                         if( pettanr.SILVERLIGHT === true ) return IS_SILVERLIGHT;\r
509                         return IS_SERVER;\r
510                 })(),\r
511                 BACKEND_WHEN_PNG = ( function(){\r
512                         if( UA.isIE === false || UA.ieVersion > 6 ) return BACKEND;\r
513                         if( UA.VML === true ) return IS_VML;\r
514                         if( pettanr.FLASH === true ) return IS_FLASH;\r
515                         if( pettanr.SILVERLIGHT === true ) return IS_SILVERLIGHT;\r
516                         if( UA.ACTIVEX === true ) return IS_ACTIVEX_SERVER;\r
517                         return IS_SERVER;\r
518                 })(),\r
519                 CLASS_NAME         = 'reversible-image-container',\r
520                 CLASS_NAME_LOADING = CLASS_NAME + ' loading',\r
521                 CLASS_NAME_ERROR   = CLASS_NAME +' error',\r
522                 RETRY_DELAY        = 5000,\r
523                 NUM_RETRY          = 3,\r
524                 ReversibleImageClass,\r
525                 ReversibleImageClassWithPingfix;\r
526         \r
527         var css3Image = function( url, w, h, onLoadCallback ){\r
528                 var elmWrap    = document.createElement( 'div' ),\r
529                         elmImg     = null,\r
530                         retryTimer = null,\r
531                         fetch      = FetchImageControl.load( url, onLoad, onError, 100, 10000 ),\r
532                         instance   = this;\r
533                 elmWrap.className = CLASS_NAME_LOADING;\r
534 \r
535                 function onLoad( _url, _actualW, _actualH ){\r
536                         if( elmWrap === null ) return;\r
537                         elmImg = new Image; // new Image でないと ie6,7 でクラッシュするかも、、、?\r
538                         /*\r
539                          * createElement 直後に append しないと、ie(ActiveX)で img が正しく表示されない.\r
540                          */\r
541                         elmWrap.appendChild( elmImg );\r
542                         elmImg.setAttribute( 'src', url );\r
543                         elmWrap.className = CLASS_NAME;\r
544                         onLoadCallback && onLoadCallback( _url, _actualW, _actualH );\r
545                         onLoadCallback = fetch = null;\r
546                         instance.resize( w, h );\r
547                 }\r
548                 function onError( _url ){\r
549                         if( elmWrap === null ) return;\r
550                         elmWrap.className = CLASS_NAME_ERROR;\r
551                         retryTimer = window.setTimeout( retry, RETRY_DELAY );\r
552                         fetch = null;\r
553                 }\r
554                 function retry(){\r
555                         elmWrap.className = CLASS_NAME_LOADING;\r
556                         fetch = FetchImageControl.load( url, onLoad, onError, 100, 10000 );\r
557                 }\r
558 \r
559                 this.elm = elmWrap;\r
560                 this.resize = function( _w, _h ){\r
561                         w = _w !== undefined ? _w : w;\r
562                         h = _h !== undefined ? _h : h;\r
563                         if( elmImg === null ) return;\r
564                         elmImg.className = w < 0 || h < 0 ? ( 'img-flip-' + ( w < 0 && h < 0 ? 'vh' : ( w < 0 ? 'h' : 'v'))) : '';\r
565                 }\r
566                 this.destroy = function(){\r
567                         delete instance.destroy;\r
568                         \r
569                         elmImg !== null && elmWrap.removeChild( elmImg );\r
570                         retryTimer !== null && window.clearTimeout( retryTimer );\r
571                         fetch !== null && fetch.stop();\r
572                         elmWrap = elmImg = onLoadCallback = retryTimer = fetch = instance = null;\r
573                 }\r
574         }\r
575                 \r
576         var activexImage = css3Image;\r
577         \r
578         var vmlImage = function( url, w, h, onLoadCallback ){\r
579                 var elmWrap = document.createElement( 'div' ),\r
580                         vmlImg = null,\r
581                         retryTimer = null,\r
582                         fetch = FetchImageControl.load( url, onLoad, onError, 100, 10000 ),\r
583                         instance = this;\r
584                 elmWrap.className = CLASS_NAME_LOADING;\r
585                 function onLoad( _url, _actualW, _actualH ){\r
586                         if( elmWrap === null ) return;\r
587                         elmWrap.className = CLASS_NAME;\r
588                         vmlImg = document.createElement( 'v:image' );\r
589                         vmlImg.src = url;\r
590                         onLoadCallback && onLoadCallback( _url, _actualW, _actualH );\r
591                         onLoadCallback = fetch = null;\r
592                         instance.resize( w, h );\r
593                 }\r
594                 function onError( _url ){\r
595                         if( elmWrap === null ) return;\r
596                         elmWrap.className = CLASS_NAME_ERROR;\r
597                         retryTimer = window.setTimeout( retry, RETRY_DELAY );\r
598                         fetch = null;\r
599                 }\r
600                 function retry(){\r
601                         elmWrap.className = CLASS_NAME_LOADING;\r
602                         fetch = FetchImageControl.load( url, onLoad, onError, 100, 10000 );\r
603                 }\r
604                 \r
605                 this.elm = elmWrap;\r
606                 this.resize = function( _w, _h ){\r
607                         w = _w !== undefined ? _w : w;\r
608                         h = _h !== undefined ? _h : h;\r
609                         if( vmlImg === null ) return;\r
610                         vmlImg.style.width  = ( w < 0 ? -w : w ) + 'px';\r
611                         vmlImg.style.height = ( h < 0 ? -h : h ) + 'px';\r
612                         //if( flipH !== _flipH || flipV !== _flipV){\r
613                                 vmlImg.parentNode === elmWrap && elmWrap.removeChild( vmlImg );\r
614                         //}\r
615                                 vmlImg.className = w < 0 || h < 0 ? ( 'img-flip-' + ( w < 0 && h < 0 ? 'vh' : ( w < 0 ? 'h' : 'v'))) : '';\r
616                                 elmWrap.appendChild( vmlImg );\r
617                 }\r
618                 this.destroy = function(){\r
619                         delete instance.destroy;\r
620                         \r
621                         vmlImg !== null && elmWrap.removeChild( vmlImg );\r
622                         retryTimer !== null && window.clearTimeout( retryTimer );\r
623                         fetch !== null && fetch.stop();\r
624                         elmWrap = vmlImg = onLoadCallback = retryTimer = fetch = instance = null;\r
625                 }\r
626         }\r
627         \r
628         var serverImage = css3Image; // function( url, w, h, onLoadCallback ){}\r
629         \r
630         if( BACKEND === IS_CSS3 )    ReversibleImageClass = css3Image;\r
631         if( BACKEND === IS_VML )     ReversibleImageClass = vmlImage;\r
632         if( BACKEND === IS_ACTIVEX ) ReversibleImageClass = activexImage;\r
633         if( BACKEND === IS_SERVER )  ReversibleImageClass = activexImage;\r
634         \r
635         css3Image = vmlImage = activexImage = activexImage = null;\r
636         \r
637         return {\r
638                 createReversibleImage: function( url, w, h, onLoadCallback){\r
639                         return new ReversibleImageClass( url, w, h, onLoadCallback );\r
640                 }\r
641         }\r
642 })();\r
643 \r
644 /*\r
645  * bind : 製本\r
646  */\r
647 pettanr.bind = ( function(){\r
648         var BIND_WORKER_ARRAY   = [],\r
649                 NAMESPACE_CLASSNAME = pettanr.CONST.NS_PETTANR_COMIC + '-',\r
650                 PICTURE_PATH        = pettanr.CONST.PICTURE_PATH,\r
651                 ELM_DETECT_WIDTH    = ( function(){\r
652                         var ret = document.createElement( 'div' );\r
653                         ret.style.cssText = 'width: auto;height: 0;padding: 0;margin: 0;display: block;visibility: hidden;float: none;position: static;';\r
654                         return ret;\r
655                 })(),\r
656                 ELM_TITLE_ORIGN = ( function(){\r
657                         \r
658                 })();\r
659 \r
660         /*\r
661          * original\r
662          *   http://d.hatena.ne.jp/uupaa/20090720/1248097177\r
663          */\r
664         var ResizeAgentClass = function( onResizeFunction, opt_elmCheck){\r
665                 var     _globalLock = 0,\r
666                         _size = { w: 0, h: 0 },\r
667                         _ie = !!document.all,\r
668                         _quirks = (document.compatMode || "") !== "CSS1Compat",\r
669                         _ieroot = _quirks ? "body" : "documentElement",\r
670                         _root = opt_elmCheck ? opt_elmCheck : ( _ie ? document[_ieroot] : window);\r
671 \r
672                 function getInnerSize(){\r
673                         return {\r
674                                 w: _root.innerWidth  || _root.clientWidth,\r
675                                 h: _root.innerHeight || _root.clientHeight\r
676                         };\r
677                 };\r
678 \r
679                 function loop(){\r
680                         if (!_globalLock++) {\r
681                                 var size = getInnerSize();\r
682                                 if (_size.w !== size.w || _size.h !== size.h) { // resized\r
683                                         _size = size; // update\r
684                                         onResizeFunction( _size );\r
685                                 };\r
686                                 setTimeout( unlock, 0); // delay unlock\r
687                         };\r
688                         setTimeout(loop, 500);\r
689                 };\r
690                 function unlock(){\r
691                         _globalLock = 0;\r
692                 };\r
693                 loop();\r
694         };\r
695         \r
696         \r
697         var ElementBuilder = function( elmTarget, noClassname ){\r
698                 this.imageList    = [];\r
699                 this.balloonList  = [];\r
700                 this.elmTarget    = elmTarget;\r
701                 this.noClassname  = noClassname;\r
702         };\r
703         ElementBuilder.prototype = {\r
704                 build : function( json, zoom ){\r
705                         this.clean();\r
706                         \r
707                         // json is Comic ? Panel ?\r
708                         var stories = json.children || json.stories,\r
709                                 i, l;\r
710                         if( Type.isArray( stories ) === true ){\r
711                                 // comic\r
712                                 for( i = 0, l = stories.length; i<l; ++i ){\r
713                                         this.buildPanelElement( stories[ i ], zoom );\r
714                                 };\r
715                         } else\r
716                         if( json.elements ){\r
717                                 // panel\r
718                                 this.buildPanelElement( json, zoom );\r
719                         } else {\r
720                                 // invalid json\r
721                         };\r
722                 },\r
723                 buildFromFile : function( file, zoom ){\r
724                         this.clean();\r
725                         \r
726                         var l    = file.getChildFileLength(),\r
727                                 data = file.read(),\r
728                                 i, story;\r
729                         if( data.title ){\r
730                                 // comic\r
731                                 for( i = 0; i<l; ++i ){\r
732                                         story = file.getChildFileAt( i ).read();\r
733                                         this.buildPanelElement( story.panel, zoom );\r
734                                 };\r
735                         } else\r
736                         if( data.panel ){\r
737                                 // story\r
738                                 this.buildPanelElement( data.panel, zoom );\r
739                         } else\r
740                         if( data.border ){\r
741                                 // panel\r
742                                 this.buildPanelElement( data, zoom );\r
743                         } else {\r
744                                 // invalid json\r
745                         };\r
746                 },\r
747                 buildComicElement : function(){\r
748                         \r
749                 },\r
750                 buildPanelElement : function( json, zoom ){\r
751                         var elmPanel = document.createElement( 'div' ),\r
752                                 style = {\r
753                                                 'border-width':         typeof json.border === 'number' ? json.border + 'px' : 0,\r
754                                                 width:                          json.width  + 'px',\r
755                                                 height:                         json.height + 'px'\r
756                                 },\r
757                                 cssText  = [],\r
758                                 elements = json.elements,\r
759                                 realPic,\r
760                                 p, i, l, data;\r
761                         this.elmTarget.appendChild( elmPanel );\r
762                         \r
763                         if( this.noClassname === true ){\r
764                                 \r
765                         } else {\r
766                                 elmPanel.className = NAMESPACE_CLASSNAME + 'panel';\r
767                         };\r
768                         for( p in style ){\r
769                                 cssText.push( p + ':' + style[ p ] );\r
770                         };\r
771                         elmPanel.style.cssText = cssText.join( ';' );\r
772                         \r
773                         if( !elements ) return;\r
774                         for( i = 0, l = elements.length; i < l; ++i ){\r
775                                 data    = elements[ i ];\r
776                                 realPic = data.picture;\r
777                                 if( realPic ){\r
778                                         this.buildImage( elmPanel, data, realPic );\r
779                                 } else {\r
780                                         this.buildBalloon( elmPanel, data );\r
781                                 };\r
782                         };\r
783                 },\r
784                 buildImage : function( elmPanel, data, realPic ){\r
785                         var rImg = pettanr.image.createReversibleImage(\r
786                                         [ PICTURE_PATH, realPic.id, '.', realPic.ext ].join( '' ),\r
787                                         data.width, data.height\r
788                                 ),\r
789                                 elmImg = rImg.elm;\r
790                         elmPanel.appendChild( elmImg );\r
791                         elmImg.className = NAMESPACE_CLASSNAME + 'image';\r
792                         elmImg.style.cssText = [\r
793                                 'left:',    data.x, 'px;',\r
794                                 'top:',     data.y, 'px;',\r
795                                 'z-index:', data.z, ';'\r
796                         ].join( '');                                    \r
797                         if( elmImg.tagName === 'img' ){\r
798                                 elmImg.width        = Math.abs( data.width );\r
799                                 elmImg.height       = Math.abs( data.height );\r
800                         } else {\r
801                                 elmImg.style.width  = Math.abs( data.width ) + 'px';\r
802                                 elmImg.style.height = Math.abs( data.height ) + 'px';\r
803                         };\r
804                         \r
805                         this.imageList.push( rImg );                    \r
806                 },\r
807                 buildBalloon : function( elmPanel, data ){\r
808                         var elmBalloonWrap = document.createElement( 'div' ),\r
809                                 elmText        = document.createElement( 'p' ),\r
810                                 content        = '',\r
811                                 speechesAttr   = data.speeches_attributes,\r
812                                 balloon, p;\r
813                         elmPanel.appendChild( elmBalloonWrap );\r
814                         elmBalloonWrap.className = NAMESPACE_CLASSNAME + 'balloon';\r
815                         elmBalloonWrap.style.cssText = [\r
816                                 'width:',   data.width, 'px;',\r
817                                 'height:',  data.height, 'px;',\r
818                                 'left:',    data.x, 'px;',\r
819                                 'top:',     data.y, 'px;',\r
820                                 'z-index:', data.z, ';'\r
821                         ].join( '' );\r
822 \r
823                         balloon = pettanr.balloon.createBalloon( data.width, data.height, data.tail );\r
824                         elmBalloonWrap.appendChild( balloon.elm );\r
825                         \r
826                         elmBalloonWrap.appendChild( elmText );\r
827                         \r
828                         elmText.appendChild( document.createElement( 'span' ) );\r
829                         \r
830                         if( speechesAttr ){\r
831                                 for( p in speechesAttr ){\r
832                                         content += speechesAttr[ p ] && speechesAttr[ p ].content ? speechesAttr[ p ].content : '';\r
833                                 };\r
834                         };\r
835                         elmText.firstChild.appendChild( document.createTextNode( content ));\r
836                         this.balloonList.push( balloon );\r
837                 },\r
838                 clean : function(){\r
839                         // clean elmTarget\r
840                         while( this.imageList.length > 0 ){\r
841                                 this.imageList.shift().destroy();\r
842                         };\r
843                         while( this.balloonList.length > 0 ){\r
844                                 this.balloonList.shift().destroy();\r
845                         };\r
846                         Util.removeAllChildren( this.elmTarget );\r
847                 },\r
848                 zoom : function(){},\r
849                 destroy : function(){\r
850                         this.clean();\r
851                 }                       \r
852         };\r
853         \r
854         var BindWorker = function( elmTarget, json, zoomSelfEnabled, noClassname ){\r
855                 this.builder     = new ElementBuilder( elmTarget, noClassname );\r
856                 this.elmDetectW  = ELM_DETECT_WIDTH.cloneNode( false );\r
857                 this._json        = json;\r
858                 this.noClassname = noClassname;\r
859                 if( zoomSelfEnabled === true ){\r
860                         elmTarget.parentNode.insertBefore( this.elmDetectW, elmTarget );\r
861                         this.resizer = new ResizeAgentClass( onResize, this.elmDetectW );\r
862                 };\r
863                 function onResize(){\r
864                         \r
865                 };\r
866                 json && typeof json === 'object' && this.builder.build( json );\r
867         };\r
868         BindWorker.prototype = {\r
869                 init : function(){\r
870                                 \r
871                 },\r
872                 zoom : function(){\r
873                         this.builder.zoom();\r
874                 },\r
875                 json : function( json ){\r
876                         this._json = json;\r
877                         this.builder.build( json, this.noClassname );\r
878                 },\r
879                 file : function( file ){\r
880                         this.builder.buildFromFile( file, this.noClassname );\r
881                 },\r
882                 targetElement : function(){\r
883                                 \r
884                 },\r
885                 layout : function(){\r
886                                 \r
887                 },\r
888                 destroy : function(){\r
889                         this.builder.destroy();\r
890                         delete this.json;\r
891                         delete this.builder;\r
892                 }               \r
893         };\r
894         return {\r
895                 createBindWorker: function( elmTarget, opt_COMICJSONorPANELJSON, opt_zoomSelfEnabled, opt_noClassnameMode ){\r
896                         var ret = new BindWorker( elmTarget, opt_COMICJSONorPANELJSON, !!opt_zoomSelfEnabled, !!opt_noClassnameMode );\r
897                         BIND_WORKER_ARRAY.push( ret );\r
898                         return ret;\r
899                 },\r
900                 isBindWorkerInstance: function( _bindWorker ){\r
901                         return _bindWorker instanceof BindWorkerClass;\r
902                 }\r
903         }\r
904 })();\r
905 \r
906 \r
907 /*\r
908  *  Google Analytics\r
909  */\r
910 \r
911 if( pettanr.LOCAL === false || document.location.href.indexOf( 'localhost:' ) === -1 ){\r
912         var _gaq = _gaq || [];\r
913         _gaq.push(['_setAccount', 'UA-28023955-1']);\r
914         _gaq.push(['_trackPageview']);\r
915         \r
916         ( function(){\r
917                 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\r
918                 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\r
919                 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\r
920         })();   \r
921 };