\r
/**\r
- * <h4>はじめに:Web 開発の世界へようこそ!</h4>\r
- * DHTML と XHR 等を活用した Ajax によってその真価を発揮した javascript は、現在では RIA に SPA や 3D ゲームなど、あらゆるアプリケーションがブラウザ上で動きつつあります。\r
- * それらの素晴らしいデモに触れ、これから Web 開発に望む皆さんは、胸をときめかせていることでしょう。\r
- * そうです、今や Web ブラウザは、あなたの夢を何でも描くことの出来る自由なフロンティアです。\r
- * \r
- * しかし、いざ Javascript を触り始め、初めての開発に着手すると、Web ブラウザというフロンティアは、少し雑草の茂るだけの荒野だと気付くでしょう。\r
- * ここに RIA や 3D ゲームといった素晴らしいテーマパークを築機上げるには、まずは測量に整地、地盤や土壌の改良といった膨大な作業をしなくてはいけません。\r
- * \r
- * 簡素な物置小屋のための最初の柱を建てるのにも、それ以前に膨大な作業の必要なことに、あなたは唖然となるでしょう。\r
- * そのような基礎もそこそこに、勇んで建てた一本目の柱は傾き、または無残に朽ち果てるのを目撃し、あなたは深いため息をつくかもしれません。\r
- * \r
- * Javascript は様々な問題を孕みつつも、今や最もあらゆるプラットフォームで動作する言語のひとつへと躍進しました。\r
- * これから、このフロンティアに如何に基礎を作り、その上にテーマパークを作るのか?一緒に考えていきましょう。\r
- * ようこそ、Web 開発の世界へ!\r
- * \r
- * <h4>pettanR フレームワーク API ドキュメントについて</h4>\r
- * このAPIドキュメントには、折に触れこのような長文が登場します。\r
- * Web 開発は今では、そのカジュアルなイメージとは裏腹に、膨大な知識と経験が必要なものになってしまっています。\r
- * どのようにして、それらの情報を、妥当な業務時間の間に継承していけばよいか?\r
- * \r
- * この意識は常にありましたが、このたび pettanR フレームワークの API ドキュメントを作成するにあたり、それに付記していく形で取り組んでみようと思います。\r
- * \r
- * <h4>フレームワークのレイヤー構造について</h4>\r
- * <h5>\core 以下:javascript の整地を行い大規模開発の基礎を整える</h5>\r
- * <p>ブラウザの種類とバージョンを調べ、続いて javascript 自体の差異を埋め、足りない関数を補います。\r
- * <p>続いて、ファーストオブジェクトとも呼ばれる function について、その能力を引き出しつつ安心して使えるように、再利用可能クロージャの生成・破棄ができるようにします。\r
- * ガベージコレクション周りが怪しいブラウザがあるため、クロージャを再利用可能にしておくことは重要です。\r
- * <p>javascript が大規模開発に使えるように、クラス定義関数を用意します。prototype 周りの差異やバグを吸収するためにも、クラス定義の共通化は有効です。\r
- * <p>このクラス定義関数を用いて EventDispatcher クラスを定義します。ブラウザの提供するイベントターゲットオブジェクトをラップしたり、単にアプリケーション独自のイベントを配信するためにも使えます。\r
- * フレームワークの各所でサブクラスや単にインスタンスを拡張して使われています。フレームワークの API 設計の性格を決めている、とても重要なクラスです。\r
- * 再利用可能クロージャや、タイマー(setTimeout のラッパー) とも密に結合しています。\r
- * \r
- * <h5>\dom 以下:DHTML の差異を吸収し、非同期化された仮想 Node を提供する</h5>\r
- * <p>jQuery ライクな構文で DOM ツリーの操作を行います。チェーンメソッドは速い、と聞きかじったのでこのデザインにしました。\r
- * <p>Real DOM の操作は非同期に行われるため高速です。Virtual DOM 時代のライバル達にひけをとることはありません。\r
- * <p>10 年後の変化に対応するため、確かな抽象化実装を行う。それを証明するために 10 年前の環境でも動作させます。\r
- * \r
- * <h5>\ui 以下:UI フレームワーク</h5>\r
- * <p>\dom までで吸収できなかった Web ブラウザの差異を最終的に吸収し、HTML 要素を UI 部品として利用するためのレイヤーです。\r
- * <p>この層で吸収できなかった差異に関する情報を提供して、アプリケーションに UI をグレースフルグラデーションするための情報を提供します。\r
- * <p>任意の UI を実現するための最適な HTML タグ構造がブラウザ毎に異なる場合に、その差異をカプセル化します。\r
- * <p>Web ブラウザ自体のレンダリングコストを最小にし、高速な UI 部品を提供するために、独自のレイアウトルールを持ちます。\r
- * <p>フォントサイズをベースとしたレイアウト指定のため、レスポンシブな画面作りを後押しします。\r
+ * <p>API ドキュメントと併せて、その意図や背景を綴っていく副読本もご覧ください。\r
+ * <a href="http://outcloud.blogspot.jp/p/pettanr-api-docs-supplementary-reader.html">クラウド番外地 > ぺったんR API文書の副読本</a>\r
* \r
* @example // ライブラリは X という名前空間を使用します。\r
* //ショートハンド\r
var listener;\r
\r
/**\r
- * <h4>クロージャについて</h4>\r
- * javascript 開発で多用されるクロージャですが、次の理由によりその使用は慎重になるべきです。\r
- * <ol>\r
- * <li>正しく参照を切ってガベージコレクトされる条件を満たしたか?プログラマが見落としやすく、結果メモリリークを起こしやすい。特にコードがコールバック地獄になると目も当てられない。\r
- * </ol>\r
- * \r
- * とくに次のようなページでは、クロージャの使用を極力避けるべきです。破棄が行われることが確実で即時関数によって新しい名前を追加したくない場合と、次項で紹介する絶対に必要なケース以外で使わないようにします。\r
- * <ol>\r
- * <li>ajax によりデータ取得がたびたび起こり、合わせて不要なデータの破棄も行う。\r
- * <li>シングルページアプリケーションで画面の生成と破棄が繰り返される。\r
- * <li>Web アプリケーションで、一度開いたら一日中操作し続けるユーザーも想定される。\r
- * </ol>\r
- * \r
- * <h4>クロージャが絶対に必要な場合</h4>\r
- * IE5 ~ IE8 の独自イベントモデルに於いて、イベントオブジェクトに event.currentTarget に相当するものがなく、現在どの HTML 要素でイベントが起こっているか分かりません。<br>\r
- * そのため HTML 要素とコールバック関数を束縛するクロージャを使う必要があります。<br>\r
- * 参照:『Javascript 第5版』 オライリー p430 17.3.6 attachEvent() と this キーワード<br>\r
- * \r
- * このほかに IE8 以下と Opera11 以下の XHR ではイベントオブジェクトが用意されないため、eventType が分からない問題があります。このために eventType とコールバック関数を束縛するクロージャが必要です。<br>\r
- * \r
- * このように、Web ブラウザと javascript の接点では、どうしてもクロージャが必要なケースがあります。<br>\r
- * さて、クロージャの使用を最小限に留め、残った僅かなクロージャのメモリリークをチェックし、といくら慎重に開発を行っても、そもそもクロージャが破棄されるのか?ガベージコレクションの怪しいブラウザもあり問題はまだ続きます。\r
- * \r
- * <h4>再利用可能なクロージャ</h4>\r
- * クロージャの使用を最小限にしたうえで、なおかつクロージャがガベージコレクションされない可能性を考慮して、pettanR フレームワークでは再利用可能なクロージャを用意します。<br>\r
- * 再利用可能クロージャはフレームワーク内で生成・破棄されるため、ユーザーが直接触ることはありません。しかし debug ツールのコールスタックには登場するため、知識を持っておくことは有益です。<br>\r
+ * <p>クロージャに関するポリシーと再利用可能クロージャについて次の記事をご覧ください。\r
+ * <a href="http://outcloud.blogspot.jp/2015/05/reusable-closure.html" target="_blank">再利用できるクロージャを使ったWebアプリケーション開発</a>\r
* \r
* <h5>再利用可能クロージャの作成</h5>\r
* X_Callback_create() で再利用可能なクロージャの作成。次のパターンで呼び出します。<br>\r
'touchcancel' : 'pointercancel',\r
'contextmenu' : 'contextmenu',\r
'dbclick' : 'dbclick',\r
- 'click' : 'click',\r
- 'tap' : 'click'\r
+ 'click' : 'click'\r
} :\r
{\r
'mousedown' : 'pointerdown',\r
-var X_JSON = X[ 'JSON' ] = window.JSON || {\r
+\r
+\r
+var X_JSON = X[ 'JSON' ] =\r
+\r
+// TODO ie8 は子フレームには JSON がいない…アクセス可能な親を探索\r
+\r
+ // JavaScriptでunicode文字列をunescapeする\r
+ // http://perutago.seesaa.net/article/202801583.html\r
+ \r
+ // http://blog.livedoor.jp/dankogai/archives/51503830.html \r
+ // Ajax - IE8にもJSON入ってます。使えるとは限らないけど\r
+ // Compatibility mode (別名Quirks mode) では、JSONオブジェクトは無効になります。iframeもだめです\r
+X_UA[ 'IE8' ] ? {\r
+ 'stringify' : function( o ){\r
+ return unescape( JSON.stringify( o ) );\r
+ },\r
+ \r
+ 'parse' : JSON.parse\r
+} :\r
+\r
+window.JSON || {\r
'stringify' : X_JSON_stringify,\r
\r
'parse' : X_String_parseTrustedJsonString\r
};\r
\r
+\r
+\r
function X_JSON_stringify( obj ){\r
var json = '', k, v;\r
for( k in obj ){\r
if( json ) json += ',';\r
v = obj[ k ];\r
v = v || v === 0 ? v : null;\r
- json += '"' + k + '":' + ( X_Type_isObject( v ) ? X_NET_GIMR_toJSONString( v ) : X_Type_isString( v ) ? '"' + v + '"' : v );\r
+ json += '"' + k + '":' + ( X_Type_isObject( v ) ? X_JSON_stringify( v ) : X_Type_isString( v ) ? '"' + v + '"' : v );\r
};\r
//console.log( json );\r
return '{' + json + '}';\r
\r
X_Pair_create( this, opt );\r
\r
- this[ 'listen' ]( [ X_EVENT_BEFORE_KILL_INSTANCE, X_EVENT_KILL_INSTANCE ], X_NET_proxyDispatch );\r
+ this[ 'listen' ]( X_EVENT_KILL_INSTANCE, X_NET_proxyDispatch );\r
\r
X_NET_QUEUE_LIST[ X_NET_QUEUE_LIST.length ] = this;\r
!X_NET_currentQueue && X_NET_shiftQueue();\r
var i, flag, auth;\r
\r
switch( e.type ){\r
- case X_EVENT_BEFORE_KILL_INSTANCE :\r
- if( this === X_NET_currentQueue && X_NET_completePhase ) return X_Callback_PREVENT_DEFAULT;\r
- break;\r
- \r
case X_EVENT_KILL_INSTANCE :\r
- i = X_NET_QUEUE_LIST.indexOf( this );\r
- \r
- if( i !== -1 ){\r
- X_NET_QUEUE_LIST.splice( i, 1 );\r
- flag = true;\r
+ if( this === X_NET_currentQueue && X_NET_completePhase ){\r
+ X_Pair_release( this );\r
+ X_NET_shiftQueue();\r
+ X_NET_completePhase = false;\r
} else\r
if( this === X_NET_currentQueue ){\r
X_NET_currentWrapper.cancel();\r
X_NET_shiftQueue();\r
flag = true;\r
+ } else\r
+ if( ( i = X_NET_QUEUE_LIST.indexOf( this ) ) !== -1 ){\r
+ X_NET_QUEUE_LIST.splice( i, 1 );\r
+ flag = true;\r
};\r
\r
if( flag ){ // flag が立つ場合、これは中断\r
};\r
\r
case X_EVENT_SUCCESS :\r
- case X_EVENT_TIMEOUT :\r
X_NET_completePhase = true;\r
this\r
[ 'listenOnce' ]( X_EVENT_COMPLETE, X_NET_proxyDispatch )\r
- [ 'unlisten' ]( [ X_EVENT_BEFORE_KILL_INSTANCE, X_EVENT_KILL_INSTANCE ], X_NET_proxyDispatch )\r
[ 'asyncDispatch' ]( e );\r
this[ 'asyncDispatch' ]( 32, { type : X_EVENT_COMPLETE, 'lastEventType' : e.type } );\r
break;\r
+\r
case X_EVENT_COMPLETE :\r
X_Pair_release( this );\r
X_NET_shiftQueue();\r
X_NET_completePhase = false;\r
+ this[ 'unlisten' ]( X_EVENT_KILL_INSTANCE, X_NET_proxyDispatch );\r
this[ 'kill' ]();\r
break;\r
};\r
if( X_NET_currentQueue ){\r
if( X_NET_currentWrapper._busy ) return;\r
X_NET_currentWrapper\r
- [ 'unlisten' ]( [ X_EVENT_PROGRESS, X_EVENT_SUCCESS, X_EVENT_ERROR, X_EVENT_TIMEOUT ], X_NET_currentQueue, X_NET_proxyDispatch )\r
+ [ 'unlisten' ]( [ X_EVENT_PROGRESS, X_EVENT_SUCCESS, X_EVENT_ERROR ], X_NET_currentQueue, X_NET_proxyDispatch )\r
.reset();\r
X_NET_currentQueue = X_NET_currentWrapper = X_NET_currentData = null;\r
};\r
break;\r
};\r
\r
- X_NET_currentWrapper[ 'listen' ]( [ X_EVENT_PROGRESS, X_EVENT_SUCCESS, X_EVENT_ERROR, X_EVENT_TIMEOUT ], X_NET_currentQueue, X_NET_proxyDispatch );\r
+ X_NET_currentWrapper[ 'listen' ]( [ X_EVENT_PROGRESS, X_EVENT_SUCCESS, X_EVENT_ERROR ], X_NET_currentQueue, X_NET_proxyDispatch );\r
\r
X_NET_currentWrapper.load( X_NET_currentData );\r
};\r
break;\r
};\r
\r
- X_NET_XHRWrapper[ 'asyncDispatch' ]( 32, { type : X_EVENT_SUCCESS, status : status || 200, data : data, headers : headers || null } );\r
+ X_NET_XHRWrapper[ 'asyncDispatch' ]( 32, { type : X_EVENT_SUCCESS, status : status || 200, response : data, headers : headers || null } );\r
} else {\r
X_NET_XHRWrapper[ 'asyncDispatch' ]( 32, { type : X_EVENT_ERROR, status : raw.status || 0, 'percent' : 100, headers : headers || null } );\r
};\r
case 'timeout' : // Gecko 12.0 https://developer.mozilla.org/ja/docs/XMLHttpRequest/Synchronous_and_Asynchronous_Requests\r
X_NET_XHRWrapper._busy = false;\r
X_NET_XHRWrapper._error = !!X_UA[ 'Gecko' ];\r
- X_NET_XHRWrapper[ 'asyncDispatch' ]( X_EVENT_TIMEOUT );\r
+ X_NET_XHRWrapper[ 'asyncDispatch' ]( { type :X_EVENT_ERROR, 'timeout' : true } );\r
break;\r
};\r
},\r
\r
if( live || raw.readyState < 3 ){\r
this._busy = false;\r
- live && this[ 'asyncDispatch' ]( X_EVENT_TIMEOUT );\r
+ live && this[ 'asyncDispatch' ]( { type : X_EVENT_ERROR, 'timeout' : true } );\r
};\r
this._timerID = 0;\r
},\r
X_NET_JSONPWrapper
[ 'asyncDispatch' ]( {
- type : jsonString ? X_EVENT_SUCCESS : X_EVENT_ERROR,
- data : X_String_parseTrustedJsonString( jsonString )
+ type : jsonString ? X_EVENT_SUCCESS : X_EVENT_ERROR,
+ response : X_String_parseTrustedJsonString( jsonString )
} );
X_Net_JSONP_errorTimerID && X_Timer_remove( X_Net_JSONP_errorTimerID );
} else
if( X_UA[ 'IE8' ] ){
html = [
- // JavaScriptでunicode文字列をunescapeする
- // http://perutago.seesaa.net/article/202801583.html
-
- // http://blog.livedoor.jp/dankogai/archives/51503830.html
- // Ajax - IE8にもJSON入ってます。使えるとは限らないけど
- // Compatibility mode (別名Quirks mode) では、JSONオブジェクトは無効になります。iframeもだめです
'<script', charset, ' id="jp"></script>',
'<script>',
'onunload=function(){clearTimeout(id)};',
'nw=0;', // なぜか必要,,,
- 'function ', callback, '(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)}',
+ 'function ', callback, '(o){nw-=+new Date;parent.X.Net.JSONP.cb(' + X_NET_JSONP_ACCESS_KEY + ',parent.X.JSON.stringify(o),-nw)}',
//'function ', callback, '(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}}',
'function tm(){jp.src="', url ,'";nw=+new Date}',
'id=setTimeout(tm,16);',
\r
idoc = this[ '_rawObject' ].contentDocument || this._iwin.document,\r
\r
- X_NET_FormWrapper[ 'asyncDispatch' ]( { type : X_EVENT_SUCCESS, responce : idoc && idoc.body ? idoc.body.innerHTML : '' } );\r
+ X_NET_FormWrapper[ 'asyncDispatch' ]( { type : X_EVENT_SUCCESS, response : idoc && idoc.body ? idoc.body.innerHTML : '' } );\r
};\r
break;\r
case 'ninjaerror' :\r
this._busy = false;\r
this.finish = true;\r
X_Timer_remove( this.timerID );\r
- this.timerID = this[ 'asyncDispatch' ]( X_EVENT_TIMEOUT );\r
+ this.timerID = this[ 'asyncDispatch' ]( { type : X_EVENT_ERROR, 'timeout' : true } );\r
};\r
};\r
\r
switch( X_NET_GIMR_phase ){\r
case 0 : // init\r
// TODO 分割\r
- iwin.location.href = X_NET_GIMR_GADGET_URL + '#' + encodeURIComponent( X_NET_GIMR_toJSONString( X_NET_GIMR_requestOptions ) );\r
+ iwin.location.href = X_NET_GIMR_GADGET_URL + '#' + encodeURIComponent( X_JSON_stringify( X_NET_GIMR_requestOptions ) );\r
break;\r
\r
case 1 : // after makeRequest > :ok 待ち\r
[ 'asyncDispatch' ]( e = {\r
type : error || ret[ 'rc' ] < 200 || 400 < ret[ 'rc' ] ? X_EVENT_ERROR : X_EVENT_SUCCESS,\r
status : ret[ 'rc' ] || ( error ? ret[ 'code' ] || 400 : 200 ),\r
- data : data,\r
+ response : data,\r
'headers' : ret[ 'headers' ],\r
'message' : error && ret[ 'errors' ].join( '\n' )\r
});\r
\r
- //console.dir( e );\r
+ console.dir( e );\r
\r
X_NET_GIMR_timerID = X_NET_GIMR_phase = 0;\r
X_NET_GIMR_lastHashString = ''; \r
};\r
};\r
};\r
-/*\r
-(function( i, l, res ){\r
- var start = X.Timer.now(), loc = location, res = [], hash;\r
- for( ; i < l; ++i ){\r
- loc.replace = chr = '#' + String.fromCharCode( i );\r
- hash = _builtin_decodeURI( loc.hash );\r
- if( _builtin_decodeURI( chr ) !== hash ) res.push( i + ':' + _builtin_decodeURI( chr ) );\r
- if( start + 16 < X.Timer.now() ){\r
- //console.log( i + ' / ' + l + ' ' + start + ' ' + X.Timer.now() );\r
- X.Timer.once( 16, arguments.callee, [ ++i, l, res ] );\r
- return;\r
- };\r
- };\r
- alert( res.length + '\n' + res.join() );\r
-})( 0xff, 0xffff, [] ); */\r
\r
// http://outcloud.blogspot.jp/2015/06/gecko-location-hash.html\r
function X_Net_GIMR_decodeLocationHash( str ){\r
return X_UA[ 'Gecko' ] ? unescape( str ) : decodeURIComponent( str );\r
};\r
\r
-// コマンドが長い場合、分割する\r
-function X_NET_GIMR_toJSONString( obj ){\r
- var json = '', k, v;\r
- for( k in obj ){\r
- if( json ) json += ',';\r
- v = obj[ k ];\r
- v = v || v === 0 ? v : null;\r
- json += '"' + k + '":' + ( X_Type_isObject( v ) ? X_NET_GIMR_toJSONString( v ) : X_Type_isString( v ) ? '"' + v + '"' : v );\r
- };\r
- console.log( json );\r
- return '{' + json + '}';\r
-};\r
-\r
-\r
X_TEMP.X_Net_GIMR_init = function(){\r
// TODO extend NinjaIframe\r
X_NET_GIMRWrapper = X_Class_override(\r
name : X_NET_GIMR_iframeName,\r
id : X_NET_GIMR_iframeName,\r
src : X_NET_GIMR_GADGET_URL + '#' + encodeURIComponent(\r
- X_NET_GIMR_toJSONString( { 'img' : X_URL_toAbsolutePath( X_NET_GIMR_IMAGE_URL ), 'len' : 1000, 'itvl' : 200 } ) ),\r
+ X_JSON_stringify( { 'img' : X_URL_toAbsolutePath( X_NET_GIMR_IMAGE_URL ), 'len' : 1000, 'itvl' : 200 } ) ),\r
scrolling : 'no',\r
allowtransparency : 'no', \r
frameborder : 0,\r
};
function X_Net_OAuth2_responceHandler( e ){
- var data = e.data,
+ var data = e.response,
pair = X_Pair_get( this ),
isRefresh = pair.oauth2State === 3;
if( isRefresh && data.error ){
_removeRefreshToken( this );
pair.oauth2State = 0;
- this[ 'asyncDispatch' ]( { type : X_EVENT_ERROR, message : 'Refresh access token error.' + data.error, data : data } );
+ this[ 'asyncDispatch' ]( { type : X_EVENT_ERROR, message : 'Refresh access token error.' } );
this[ 'asyncDispatch' ]( X_EVENT_NEED_AUTH );
return;
} else
if( data.error ){
pair.oauth2State = 0;
- this[ 'asyncDispatch' ]( { type : X_EVENT_ERROR, message : 'Get new access token error.' + data.error, data : data } );
+ this[ 'asyncDispatch' ]( { type : X_EVENT_ERROR, message : 'Get new access token error.' } );
this[ 'asyncDispatch' ]( X_EVENT_NEED_AUTH );
return;
};
// decoeAudioData の処理がキャンセルされることがある(エラーやコールバックの発火もなく、ただ処理が消滅する)。
// ただし iOS 8.1.2 では エラーになる
if( X_Audio_WebAudio_context.createBuffer && X_UA[ 'iOS' ] < 8 ){
- this._onDecodeSuccess( X_Audio_WebAudio_context.createBuffer( e.data, false ) );
+ this._onDecodeSuccess( X_Audio_WebAudio_context.createBuffer( e.response, false ) );
} else
if( X_Audio_WebAudio_context.decodeAudioData ){
- X_Audio_WebAudio_context.decodeAudioData( e.data,
+ X_Audio_WebAudio_context.decodeAudioData( e.response,
this.onDecodeSuccess = X_Callback_create( this, this._onDecodeSuccess ),
this.onDecodeError = X_Callback_create( this, this._onDecodeError ) );
} else {
- this._onDecodeSuccess( X_Audio_WebAudio_context.createBuffer( e.data, false ) );
+ this._onDecodeSuccess( X_Audio_WebAudio_context.createBuffer( e.response, false ) );
};
break;