X_Class_CALL_SUPER_STACK = [],\r
X_Class_traits = null,\r
X_Class_useObjectCreate = false, // !!Object.create, http://jsperf.com/prototype-vs-object-create-perf\r
+ // Opera Mobile 12.10 Android11 IS01 でクラスのメンバが欠落する問題に遭遇。__proto__ を辞めると動作,,,\r
X_Class_use_proto_ = !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] && !!X_emptyFunction.prototype.__proto__,\r
- // Opera Mobile 12.10 Android11 IS01 でクラスのメンバが欠落する問題に遭遇。__proto__ を辞めると動作,,,\r
+ X_Class_SEAL_KILLING = [],\r
\r
X_Class_CommonMethods =\r
/** @lends __ClassBase__.prototype */\r
* 全ての動的メンバを削除して、インスタンスを破棄する。<br>\r
* インスタンスが X.EventDispatcher とそのサブクラスの場合、次の動作をする。\r
* <ol>\r
- * <li>X.Event.BEFORE_KILL_INSTANCE を発火する。戻り値のビットフラグに X_Callback.PREVENT_DEFAULT が立つ場合、破棄をキャンセルし X.Event.KILL_INSTANCE_CANCELED を発火する。\r
+ * <li>X.Event.BEFORE_KILL_INSTANCE を発火する。戻り値のビットフラグに X_Callback.PREVENT_DEFAULT が立つ場合、破棄をキャンセルし X.Event.KILL_INSTANCE_CANCELED を発火する。この間に kill() が呼ばれても無視される。\r
* <li>破棄に進む場合は、X.Event.KILL_INSTANCE を発火する。\r
* <li>dispatch 中は、インスタンスの全ての dispatch が終了するまで実際の破棄を待つ。\r
* <li>実際の破棄では、インスタンスのメンバの削除に加えて全てのイベントリスナを解除する。\r
*/\r
// TODO kill したインスタンスのイベントが残っていないか?これは開発用のみ\r
'kill' : function(){\r
- var def, listeners, p;\r
+ var listeners, flag, p, timers, def;\r
\r
- // TODO kill 中の kill の呼び出しを防ぐ, 破棄済のインスタンスへの kill\r
+ // TODO 破棄済のインスタンスへの kill\r
\r
if( this[ 'instanceOf' ]( X_EventDispatcher ) ){\r
\r
- if( this[ 'dispatch' ]( X_EVENT_BEFORE_KILL_INSTANCE ) & X_Callback_PREVENT_DEFAULT ){\r
- this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE_CANCELED );\r
- return;\r
- };\r
- \r
listeners = this[ '_listeners' ];\r
- \r
- if( listeners && listeners[ X_LISTENERS_DISPATCHING ] ){\r
- listeners[ X_LISTENERS_KILL_RESERVED ] = true;\r
- return;\r
+\r
+ // SEAL のタイミングは、イベント中なので listeners が存在する\r
+ if( listeners && X_Class_SEAL_KILLING.length && X_Class_SEAL_KILLING.indexOf( this ) !== -1 ) return;\r
+\r
+ // listeners がない場合、イベントの登録がないため、BEFORE_KILL_INSTANCE は呼ばれない。\r
+ // KILL_RESERVED == true の場合、BEFORE_KILL_INSTANCE は呼ばれない。\r
+ if( listeners && !listeners[ X_LISTENERS_KILL_RESERVED ] && listeners[ X_EVENT_BEFORE_KILL_INSTANCE ] ){\r
+ X_Class_SEAL_KILLING[ X_Class_SEAL_KILLING.length ] = this;\r
+ \r
+ if( this[ 'dispatch' ]( X_EVENT_BEFORE_KILL_INSTANCE ) & X_Callback_PREVENT_DEFAULT ){\r
+ this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE_CANCELED );\r
+ // BEFORE_KILL_INSTANCE, KILL_INSTANCE_CANCELED 内で kill() しても PREVENT_DEFAULT の場合はこれを無視する。\r
+ flag = true;\r
+ };\r
+ \r
+ X_Class_SEAL_KILLING.length === 1 ?\r
+ ( X_Class_SEAL_KILLING.length = 0 ) :\r
+ X_Class_SEAL_KILLING.splice( X_Class_SEAL_KILLING.indexOf( this ), 1 );\r
+\r
+ if( flag ) return;\r
};\r
\r
+ if( listeners = this[ '_listeners' ] ){// unlisten 等で listeners が破棄されている場合があるので取り直し。\r
+ if( listeners[ X_LISTENERS_DISPATCHING ] ){\r
+ listeners[ X_LISTENERS_KILL_RESERVED ] = true;\r
+ return;\r
+ };\r
+ \r
+ if( listeners[ X_EVENT_KILL_INSTANCE ] ){\r
+ X_Class_SEAL_KILLING[ X_Class_SEAL_KILLING.length ] = this;\r
+\r
+ listeners[ X_LISTENERS_KILL_RESERVED ] = false; \r
+ this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE );\r
+ \r
+ X_Class_SEAL_KILLING.length === 1 ?\r
+ ( X_Class_SEAL_KILLING.length = 0 ) :\r
+ X_Class_SEAL_KILLING.splice( X_Class_SEAL_KILLING.indexOf( this ), 1 );\r
+ };\r
+ \r
+ X_EventDispatcher_unlistenAll( this );\r
+ };\r
+\r
+ timers = X_EventDispatcher_LAZY_TIMERS;\r
+\r
// asyncDispatch の削除\r
- for( p in X_EventDispatcher_LAZY_TIMERS ){\r
- if( X_EventDispatcher_LAZY_TIMERS[ p ] === this ){\r
+ for( p in timers ){\r
+ if( timers[ p ] === this ){\r
// delete X_EventDispatcher_LAZY_TIMERS[ p ]; コレ不要\r
X_Timer_remove( p );\r
};\r
};\r
- \r
- this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE );\r
- listeners && X_EventDispatcher_unlistenAll( this );\r
};\r
\r
X_Object_clear( this );\r
var listeners = this[ '_listeners' ],\r
ret = X_Callback_NONE,\r
type = e[ 'type' ],\r
- list, unlistens, i, l, args, f, r, sysOnly, timerID;\r
+ list, unlistens, i, l, args, f, r, sysOnly, timerID, k;\r
\r
if( !listeners || !( list = listeners[ type || e ] ) ) return X_Callback_NONE;\r
\r
\r
// _unlistens に入っている callbackHash は、lock をクリアしている\r
X_EventDispatcher_unlock = true;\r
- for( type in unlistens ){\r
- //if( X_EMPTY_OBJECT[ type ] ) continue;\r
- list = unlistens[ type ];\r
+ for( k in unlistens ){\r
+ //if( X_EMPTY_OBJECT[ k ] ) continue;\r
+ list = unlistens[ k ];\r
for( i = list.length; i; ){\r
- this[ 'unlisten' ]( type, list[ --i ] );\r
+ this[ 'unlisten' ]( k, list[ --i ] );\r
};\r
list.length = 0;\r
- delete unlistens[ type ];\r
+ delete unlistens[ k ];\r
};\r
X_EventDispatcher_unlock = false;\r
};\r
function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){\r
var listeners = this[ '_listeners' ],\r
list, reserves, unlistens, i, f, raw, k, empty;\r
+\r
if( !listeners ) return this;\r
\r
if( X_Type_isArray( opt_type ) ){\r
if( !list || !raw ) return;\r
for( type in list ){\r
//if( X_EMPTY_OBJECT[ type ] ) continue;\r
- //if( type <= X_LISTENERS_KILL_RESERVED ) continue;\r
// 数字イベントの除外\r
if( !X_String_isNumberString( type ) ){\r
// TODO type rename はここ\r
\r
\r
/**\r
- * <p>busy() メソッドだけを持つ。通信用のプロパティは X.Pair によって隠蔽される。\r
+ * <p>state() メソッドだけを持つ。通信用のプロパティは X.Pair によって隠蔽されています。\r
* <h4>通信のキャンセル</h4>\r
- * <p>kill() で通信待ち中はキャンセル&破棄、通信中の場合は通信の中断&破棄を行う。SUCCESS, ERROR, TIMEOUT イベント以降は kill() は無視される。\r
+ * <p>kill() で通信待ち中はキャンセル&破棄、通信中の場合は通信の中断&破棄を行う。\r
* <h4>イベント</h4>\r
* <dl>\r
* <dt>X.Event.PROGRESS<dd>通信進行状況\r
* <dt>X.Event.SUCCESS<dd>通信成功\r
- * <dt>X.Event.ERROR<dd>通信エラー\r
- * <dt>X.Event.TIMEOUT<dd>通信タイムアウト\r
- * <dt>X.Event.CANCELED<dd>通信のユーザー、プログラムによるキャンセル\r
- * <dt>X.Event.COMPLETE<dd>通信完了。SUCCESS, ERROR, TIMEOUT, CANCELED 後に発生。\r
+ * <dt>X.Event.ERROR<dd>通信エラー タイムアウトの場合、e.timeout == true で分かる。\r
+ * <dt>X.Event.CANCELED<dd>通信のユーザー、プログラムによるキャンセル。SUCCESS, ERROR, COMPLETE 後に kill()してもCANCELEDは呼ばれません。\r
+ * <dt>X.Event.COMPLETE<dd>通信完了。SUCCESS, ERROR, CANCELED 後に発生。\r
* </dl>\r
* <p>X.Net インスタンスは COMPLETE 後に自動で破棄される。\r
* <h4>必須プロパティ</h4>\r
'X.Net',\r
X_Class.NONE,\r
{\r
- 'netType' : '',\r
- 'netName' : '',\r
- 'netVersion' : 0,\r
\r
'Constructor' : function( urlOrObject, opt_options ){\r
var opt, url, type, auth;\r
X_NET_QUEUE_LIST[ X_NET_QUEUE_LIST.length ] = this;\r
!X_NET_currentQueue && X_NET_shiftQueue();\r
},\r
- \r
- /**\r
- * 現在通信中か?調べる。false の場合、通信の順番待ちか、通信が終了している。\r
- * @alias Net.prototype.busy\r
- */\r
- 'busy' : function(){\r
- return this === X_NET_currentQueue && X_NET_currentWrapper._busy;\r
- },\r
\r
/**\r
- * 現在の状態。1:待機中 2:通信中 3:通信完了フェーズ\r
+ * 現在の状態。1:順番待ち, 2:通信中, 3:通信完了フェーズ\r
* @alias Net.prototype.state\r
*/\r
'state' : function(){\r
switch( e.type ){\r
case X_EVENT_KILL_INSTANCE :\r
if( this === X_NET_currentQueue && X_NET_completePhase ){\r
- X_Pair_release( this );\r
+ if( X_NET_completePhase === 1 )\r
+ this[ 'unlisten' ]( X_EVENT_COMPLETE, X_NET_proxyDispatch )\r
+ [ 'dispatch' ]( X_EVENT_COMPLETE );\r
X_NET_shiftQueue();\r
- X_NET_completePhase = false;\r
+ X_Pair_release( this );\r
+ X_NET_completePhase = 0;\r
} else\r
if( this === X_NET_currentQueue ){\r
X_NET_currentWrapper.cancel();\r
if( e.status === 401 ){\r
if( auth = X_Pair_get( this )[ 'auth' ] ){\r
X_Pair_get( auth ).onAuthError( auth, e );\r
+ // TODO 破棄しないで待機。\r
};\r
};\r
\r
case X_EVENT_SUCCESS :\r
- X_NET_completePhase = true;\r
- this\r
- [ 'listenOnce' ]( X_EVENT_COMPLETE, X_NET_proxyDispatch )\r
- [ 'asyncDispatch' ]( e );\r
- this[ 'asyncDispatch' ]( 32, { type : X_EVENT_COMPLETE, 'lastEventType' : e.type } );\r
+ X_NET_completePhase = 1;\r
+ this[ 'listenOnce' ]( X_EVENT_COMPLETE, X_NET_proxyDispatch )\r
+ [ 'asyncDispatch' ]( 32, { type : X_EVENT_COMPLETE, 'lastEventType' : e.type } );\r
+\r
+ this[ 'asyncDispatch' ]( e );\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
+ X_NET_completePhase = 2;\r
this[ 'kill' ]();\r
break;\r
};\r
\r
if( X_NET_currentQueue ){\r
if( X_NET_currentWrapper._busy ) return;\r
+ \r
X_NET_currentWrapper\r
[ 'unlisten' ]( [ X_EVENT_PROGRESS, X_EVENT_SUCCESS, X_EVENT_ERROR ], X_NET_currentQueue, X_NET_proxyDispatch )\r
.reset();\r
+\r
X_NET_currentQueue = X_NET_currentWrapper = X_NET_currentData = null;\r
};\r
\r
case 1 :\r
case 2 :\r
if( !( auth[ 'dispatch' ]( X_EVENT_NEED_AUTH ) & X_Callback_PREVENT_DEFAULT ) ){\r
- authSettings.lazyReq = X_NET_currentQueue;\r
+ authSettings.lazyRequests = authSettings.lazyRequests || [];\r
+ authSettings.lazyRequests.indexOf( X_NET_currentQueue ) === -1 && authSettings.lazyRequests.push( X_NET_currentQueue );\r
};\r
X_NET_currentQueue = null;\r
X_NET_shiftQueue();\r
*
* original :
* oauth2.js , <opendata@oucs.ox.ac.uk>
+ * https://github.com/ox-it/javascript-oauth2/blob/master/oauth2/oauth2.js
*
* @alias X.OAuth2
* @class OAuth2 サービスを定義し接続状況をモニタする。適宜にトークンのアップデートなどを行う
'redirectURI' : X.URL.cleanup( document.location.href ), // 専用の軽量ページを用意してもよいが、現在のアドレスでも可能
'scopes' : [ 'https://www.googleapis.com/auth/blogger' ],
'refreshMargin' : 300000,
+ // canuse
'authorizeWindowWidth' : 500,
'authorizeWindowHeight' : 500
}).listen( [ X.Event.NEED_AUTH, X.Event.CANCELED, X.Event.SUCCESS, X.Event.ERROR, X.Event.PROGRESS ], updateOAuth2State );
'Accept' : 'application/json',
'Content-Type' : 'application/x-www-form-urlencoded'
},
- 'test' : 'gadget'
+ 'test' : 'gadget' // canuse
} ).listenOnce( [ X_EVENT_SUCCESS, X_EVENT_ERROR ], this, X_Net_OAuth2_responceHandler );
this[ 'asyncDispatch' ]( { type : X_EVENT_PROGRESS, message : 'Start to refresh token.' } );
};
pair.oauth2State = 4;
+
+ if( pair.lazyRequests && pair.lazyRequests.length ){
+ X_NET_QUEUE_LIST.push.apply( X_NET_QUEUE_LIST, pair.lazyRequests );
+ pair.lazyRequests.length = 0;
+ };
+
this[ 'asyncDispatch' ]( { type : X_EVENT_SUCCESS, message : isRefresh ? 'Refresh access token success.' : 'Get new access token success.' } );
break;
function X_NET_OAUTH2_onXHR401Error( oauth2, e ){
var pair = this,
headers = e[ 'headers' ],
- xhr, bearerParams, headersExposed = false;
+ bearerParams, headersExposed = false;
if( X_OAuth2_getAuthMechanism( oauth2 ) !== 'param' ){
- xhr = X_NET_currentWrapper[ '_rawObject' ];
- headersExposed = !X_Net_XHR_createXDR || !!headers; // this is a hack for Firefox and IE
+ headersExposed = !X_NET_currentWrapper.isXDR || !!headers; // this is a hack for Firefox and IE
bearerParams = headersExposed && ( headers[ 'WWW-Authenticate' ] || headers[ 'www-authenticate' ] );
X_Type_isArray( bearerParams ) && ( bearerParams = bearerParams.join( '\n' ) );
};
// http://d.hatena.ne.jp/ritou/20110402/1301679908
- if ( bearerParams && bearerParams.indexOf( ' error=' ) === -1 ) {
+ if ( bearerParams && bearerParams.indexOf( ' error=' ) === -1 ) { // bearerParams.error == undefined
pair.oauth2State = 0;
oauth2[ 'asyncDispatch' ]( X_EVENT_NEED_AUTH );
} else
pair.oauth2State = 3;
oauth2[ 'refreshToken' ]();
} else {
- //if (!headersExposed && !X_OAuth2_getRefreshToken( oauth2 )) {
X_OAuth2_removeAccessToken( oauth2 ); // It doesn't work any more.
pair.oauth2State = 0;
oauth2[ 'asyncDispatch' ]( X_EVENT_NEED_AUTH );
};
function X_OAuth2_getAccessToken( that ){ return X_OAuth2_updateLocalStorage( '', that, 'accessToken' ); }
-function X_OAuth2_getRefreshToken( that){ return X_OAuth2_updateLocalStorage( '', that, 'refreshToken' ); }
+function X_OAuth2_getRefreshToken( that ){ return X_OAuth2_updateLocalStorage( '', that, 'refreshToken' ); }
function X_OAuth2_getAccessTokenExpiry( that ){ return parseInt( X_OAuth2_updateLocalStorage( '', that, 'tokenExpiry' ) ) || 0; }
function X_OAuth2_getAuthMechanism( that ){
// TODO use gadget | flash ...
// IE's XDomainRequest doesn't support sending headers, so don't try.
- return X_Net_XHR_createXDR ? 'param' : X_OAuth2_updateLocalStorage( '', that, 'AuthMechanism' );
+ return ( X_NET_currentWrapper === X_NET_XHRWrapper ) && X_Net_XHR_createXDR ? 'param' : X_OAuth2_updateLocalStorage( '', that, 'AuthMechanism' );
}
function X_OAuth2_setAccessToken( that, value ){ X_OAuth2_updateLocalStorage( '+', that, 'accessToken' , value); }
function X_OAuth2_setRefreshToken( that, value ){ X_OAuth2_updateLocalStorage( '+', that, 'refreshToken', value); }