OSDN Git Service

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