OSDN Git Service

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