OSDN Git Service

Version 0.6.134, add comments for closure compiler.
[pettanr/clientJs.git] / 0.6.x / js / 06_net / 02_XNetJSONP.js
1 /*
2  * Operaでも非同期リクエストが並列処理できる img-JSONP
3  * http://developer.cybozu.co.jp/takesako/2007/06/opera_img-jsonp.html
4  * 
5  * iframe を使った jsonp の読み込みエラー判定の記事、
6  * JSONPのエラーを判断する は web archive でも観れない
7  * http://d.hatena.ne.jp/yuushimizu/20090128/1233146321
8  * TODO JSONPの動的取得+エラー処理
9  * http://d.hatena.ne.jp/NeoCat/20110206/1296934235
10  * 
11  * Safari が JavaScript ファイルを動的ロードできない件
12  * http://www.bricklife.com/weblog/000618.html
13  * 
14  * IE9でiframe内で遷移した場合window.parentのメソッドを呼べない 
15  * http://kozo002.blogspot.jp/2012/07/ie9iframewindowparent.html
16  * 
17  * IE6(IETester,localhost) で動かない,
18  * 
19  * TODO postMessage
20  */
21
22 X.Net.JSONP = {
23         cb : function( accessKey, jsonString, time, opt_json2FileSize ){
24                         if( accessKey !== X_NET_JSONP_ACCESS_KEY || !X_NET_JSONPWrapper._busy ) return;
25                         
26                         X_NET_JSONPWrapper._busy = false;
27                         
28                         X_NET_JSONPWrapper
29                                 [ 'asyncDispatch' ]( {
30                                         type : jsonString ? X_EVENT_SUCCESS : X_EVENT_ERROR,
31                                         data : window.JSON ? JSON.parse( jsonString ) : eval( 'var a=' + jsonString + ';a' )
32                                 } );
33                         
34                         console.log( 'ms : ' + time + ' speed : ' + ( ( jsonString.length + ( opt_json2FileSize || 0 ) ) / time * 1000 ) + ' バイト/秒.' );
35                 }
36 };
37
38 function X_Net_JSONP_reciveMessage( data ){
39         console.log( data );
40 };
41
42 var X_NET_JSONP_ACCESS_KEY = Math.random(),
43         
44         X_NET_JSONP_SEND_MSG_KEY = X_System.message( 'X.Net.JSONP', X_Net_JSONP_reciveMessage ),
45         
46         X_NET_JSONP_NinjaIframe,
47         
48         X_Net_JSONP_onloadCount;
49
50         
51
52 function X_NET_JSONP_loadScriptInNinjaIframe( url ){
53         var json2Path     = 'js/libs/json2.js',
54                 json2FileSize = 18103,
55                 html;
56         
57         X_NET_JSONP_NinjaIframe || ( X_NET_JSONP_NinjaIframe = new X.Util.NinjaIframe() );
58         
59         // TODO '<scr'+'ipt> 化 恐らくアンチウイルスソフトが反応しないための対策
60         // TODO postMessage の利用
61         // document.postMessage()→window.postMessage() (Opera 9.50 build 9841 -)
62         // http://d.hatena.ne.jp/cnrd/20080518/1211099169
63         // 最近の仕様変更(引数のtargetOriginとかMessageEventのoriginとか)にはまだ対応してないみたい 
64
65         if( X_UA[ 'Opera' ] ){
66                 html = [
67                         ( window[ 'JSON' ] ? '' : '<script src="' + json2Path + '"></script>' ),
68                         '<script>',
69                                 'onunload=function(){im.onload=im.onerror=""};',
70                                 'nw=+new Date;',
71                                 'function cb(o){if(nw){nw-=+new Date;parent.X.Net.JSONP.cb(' + X_NET_JSONP_ACCESS_KEY + ',JSON.stringify(o),-nw', window[ 'JSON' ] ? json2FileSize : 0 ,');nw=0}}',
72                         '</script>',    
73                         '<script id="jp"></script>',
74                         '<img id="im" src="', url, '" onload="jp.src=im.src" onerror="jp.src=im.src">'
75                 ];
76                 X_Net_JSONP_onloadCount = 2;
77         } else
78         if( X_UA[ 'IE8' ] ){
79                 html = [
80                         // JavaScriptでunicode文字列をunescapeする
81                         // http://perutago.seesaa.net/article/202801583.html
82                         
83                         // http://blog.livedoor.jp/dankogai/archives/51503830.html              
84                         // Ajax - IE8にもJSON入ってます。使えるとは限らないけど
85                         // Compatibility mode (別名Quirks mode) では、JSONオブジェクトは無効になります。iframeもだめです
86                         '<script id="jp"></script>',
87                         '<script>',
88                                 'onunload=function(){clearTimeout(id)};',
89                                 'nw=0;', // なぜか必要,,,
90                                 'function cb(o){nw-=+new Date;parent.X.Net.JSONP.cb(' + X_NET_JSONP_ACCESS_KEY + ',parent.JSON.stringify(o).replace(/\\\\u([a-fA-F0-9]{4})/g,function(a,b){return String.fromCharCode(parseInt(b,16))}),-nw)}',
91                                 //'function cb(o){if(nw){nw-=+new Date;postMessage("', X_NET_JSONP_SEND_MSG_KEY,' "+nw+"|"+parent.JSON.stringify(o).replace(/\\\\u([a-fA-F0-9]{4})/g,function(a,b){return String.fromCharCode(parseInt(b,16))}),"*");nw=0}}',                   
92                                 'function tm(){jp.src="', url ,'";nw=+new Date}',
93                                 'id=setTimeout(tm,16);',
94                         '</script>'
95                         
96                         /* 以下のコードは XP ie8 では動くけど、win8 IE11(8モード)で動かない 開発の便宜を取って,setTimeout を挟む
97                         '<script>',
98                                 'function cb(o){window.parent.X.Net.JSONP.cb(' + X_NET_JSONP_ACCESS_KEY + ',window.parent.JSON.stringify(o))}',
99                         '</script>',
100                         '<script src="', url, '"></script>' */
101                 ];
102                 X_Net_JSONP_onloadCount = 2;
103         } else
104         if( X_UA[ 'IE9' ] ){
105                 html = [
106                         '<script id="jp"></script>',
107                         '<script>',
108                                 'onunload=function(){clearTimeout(id)};',
109                                 'function cb(o){nw-=+new Date;parent.X.Net.JSONP.cb(' + X_NET_JSONP_ACCESS_KEY + ',JSON.stringify(o),-nw)}',
110                                 'function tm(){jp.src="', url ,'";nw=+new Date}',
111                                 'id=setTimeout(tm,16);',
112                         '</script>'
113                 ];
114                 X_Net_JSONP_onloadCount = 2;
115         } else
116         if( window[ 'JSON' ] ){
117                 html = [        
118                         '<script>',
119                                 'nw=+new Date;',
120                                 'function cb(o){if(nw){nw-=+new Date;parent.X.Net.JSONP.cb(' + X_NET_JSONP_ACCESS_KEY + ',JSON.stringify(o),-nw);nw=0}}',
121                                 //'function cb(o){if(nw){nw-=+new Date;parent.postMessage("', X_NET_JSONP_SEND_MSG_KEY,' "+nw+"|"+JSON.stringify(o),"', location.origin, '");nw=0}}',
122                         '</script>',
123                         '<script src="', url, '"></script>'
124                 ];
125                 X_Net_JSONP_onloadCount = 1;
126         } else
127         if( X_UA[ 'IE4' ] || X_UA[ 'MacIE' ] ){
128                 html = [
129                         '<script id="jn"></script>',
130                         '<script id="jp"></script>',
131                         '<script>',
132                                 'onunload=function(){clearTimeout(id)};',
133                                 'function cb(o){nw-=new Date;parent.X.Net.JSONP.cb(' + X_NET_JSONP_ACCESS_KEY + ',JSON.stringify(o),-nw-16,', json2FileSize, ')}',
134                                 'function t1(){document.all.jn.src="', json2Path ,'";id=setTimeout("t2()",16);nw=+new Date}',
135                                 'id=setTimeout("t1()",16);',
136                                 'function t2(){if(window.JSON){document.all.jp.src="', url ,'"}else{id=setTimeout("t2()",16)}}',
137                         '</script>'
138                 ];
139                 X_Net_JSONP_onloadCount = 3;
140         } else
141         if( X_UA[ 'IE' ] < 8 ){ // ie5-7
142                 html = [
143                         '<script id="jn"></script>',
144                         '<script id="jp"></script>',
145                         '<script>',
146                                 'onunload=function(){clearTimeout(id)};',
147                                 'function cb(o){nw-=new Date;parent.X.Net.JSONP.cb(' + X_NET_JSONP_ACCESS_KEY + ',JSON.stringify(o),-nw-16,', json2FileSize, ')}',
148                                 'function t1(){jn.src="', json2Path ,'";id=setTimeout(t2,16);nw=+new Date}',
149                                 'id=setTimeout(t1,16);',
150                                 'function t2(){if(window.JSON){jp.src="', url ,'"}else{id=setTimeout(t2,16)}}',
151                         '</script>'
152                 ];
153                 X_Net_JSONP_onloadCount = 3;
154         } else {
155                 html = [
156                         '<script>',
157                                 'function cb(o){if(nw){nw-=new Date;parent.X.Net.JSONP.cb(' + X_NET_JSONP_ACCESS_KEY + ',JSON.stringify(o),-nw,', json2FileSize, ');nw=0}}',
158                                 'nw=+new Date;',
159                         '</script>',
160                         '<script src="', json2Path, '"></script>',
161                         '<script src="', url, '"></script>'
162                 ];
163                 X_Net_JSONP_onloadCount = 1;
164         };
165         
166         X_NET_JSONP_NinjaIframe
167                 .refresh( html.join( '' ) )
168                 [ 'listen' ]( [ X_EVENT_SUCCESS, X_EVENT_ERROR ], X_NET_JSONPWrapper, X_NET_JSONP_iframeListener );
169 };
170
171
172 function X_NET_JSONP_iframeListener( e ){
173         switch( e.type ){
174                 case X_EVENT_SUCCESS :
175                         console.log( 'iframe onload, but' );
176                         if( ++X_NET_JSONPWrapper._onloadCount < X_Net_JSONP_onloadCount ) return;
177                         // TODO callback が無ければ error
178                         X_NET_JSONPWrapper[ 'asyncDispatch' ]( 1000, X_EVENT_ERROR );
179                         break;
180                 case X_EVENT_ERROR :
181                         console.log( 'iframe onerror' );
182                         X_NET_JSONPWrapper[ 'asyncDispatch' ]( X_EVENT_ERROR );
183                         break;
184         };
185         X_NET_JSONP_NinjaIframe[ 'unlisten' ]();
186         return X_Callback_UN_LISTEN;
187 };
188
189 // TODO extend NinjaIframe
190 X_NET_JSONPWrapper = X_Class_override(
191         X_EventDispatcher(),
192         {
193
194                 _busy         : false,
195                 _canceled     : false,
196                 _onloadCount  : 0,
197                 
198                 load : function( url, data, timeout ){
199                         //createURL
200                         X_NET_JSONP_loadScriptInNinjaIframe( url );
201                                                 
202                         this._busy = true;
203                 },
204                 
205                 cancel : function(){
206                         this._canceled = true;
207                 },
208                 
209                 reset : function(){
210                         this._busy = this._canceled = false;
211                         this._onloadCount = 0;
212                 }
213         }
214 );