X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2F01_core%2F15_XEventDispatcher.js;h=5a9864a7c49128ef149c81b9cfc1d2461e8261b8;hb=76ea1040608829b653422cf51b3490801d2ec1fa;hp=5a5b17ded20514fd5619e41e2440cad03102bf1c;hpb=3d352d8bf476ab57cc333e8d02d0e6ea5efa69b7;p=pettanr%2FclientJs.git diff --git a/0.6.x/js/01_core/15_XEventDispatcher.js b/0.6.x/js/01_core/15_XEventDispatcher.js index 5a5b17d..5a9864a 100644 --- a/0.6.x/js/01_core/15_XEventDispatcher.js +++ b/0.6.x/js/01_core/15_XEventDispatcher.js @@ -15,7 +15,7 @@ *
dispatch 中か?さらにインスタンス自身の dispatch がネストした場合、その深さを記憶します。 *
2:RESERVES Array *
イベント発火中に listen() が呼ばれた場合に引数を蓄え、完了時(DISPATCHING===0)に再度 listen() するための一時ストアです。 - *
3:UNLISTENS Array + *
3:UNLISTENS Object *
イベント発火中に unlisten() が呼ばれた場合に対象リスナを記憶し、リスナが呼ばれないようにします。完了時(DISPATCHING===0)に再度 unlisten() します。 *
4:KILL_RESERVED boolean *
dispatch 中に kill() が呼ばれた場合に一旦 kill をキャンセルし、完了時(DISPATCHING===0)に再度 kill() するためのフラグです。 @@ -36,22 +36,27 @@ var X_LISTENERS_ACTUAL_HANDLER = 0, // ------------------------------------------------------------------------- // // ------------ local variables -------------------------------------------- // // ------------------------------------------------------------------------- // +var X_EventDispatcher_EVENT_TARGET_OTHER = 0, + X_EventDispatcher_EVENT_TARGET_XHR = 1, + X_EventDispatcher_EVENT_TARGET_SILVER_LIGHT = 2; -var X_EventDispatcher_once = false, - X_EventDispatcher_lock = false, - X_EventDispatcher_unlock = false, - X_EventDispatcher_needsIndex = false, +var X_EventDispatcher_once = false, + X_EventDispatcher_lock = false, + X_EventDispatcher_unlock = false, + X_EventDispatcher_needsIndex = false, X_EventDispatcher_safariPreventDefault = false, // Safari3- + + X_EventDispatcher_LAZY_TIMERS = {},// Object. number は timerID - /* @const */ - X_EventDispatcher_EVENT_TARGET_OTHER = 0, - /* @const */ - X_EventDispatcher_EVENT_TARGET_XHR = 1, - /* @const */ - X_EventDispatcher_EVENT_TARGET_SILVER_LIGHT = 2, - - X_EventDispatcher_LAZY_TIMERS = {}; // Object. number は timerID + // iOS と MacOSX Iron36 で発生。連続してアニメーションが起こると、クロージャの束縛された obj へのアクセスに失敗する。Win では起きない? + // むしろ、MacOSX のブラウザ全般で起こる?? + X_EventDispatcher_ANIME_EVENTS = ( X_UA[ 'WebKit' ] || X_UA[ 'Blink' ] ) && { + 'transitionend' : true, 'webkitTransitionEnd' : true, 'mozTransitionEnd' : true, 'oTransitionEnd' : true, 'otransitionEnd' : true, + 'animationend' : true, 'webkitAnimationEnd' : true, 'oAnimationEnd' : true, + 'animationstart' : true, 'webkitAnimationStart' : true, 'oAnimationStart' : true, + 'animationiteration' : true, 'webkitAnimationIteration' : true, 'oAnimationIteration' : true + }; // ------------------------------------------------------------------------- // // --- interface ----------------------------------------------------------- // @@ -93,7 +98,9 @@ var X_EventDispatcher = X[ 'EventDispatcher' ] = { /** - * OTHER(Node,window,document,Image,Audio), XHR, Silverlight + * EventDispatcher がラップしている EventTarget オブジェクトのタイプです。
+ * X_EventDispatcher_actualAddEvent で使用されます。
+ * OTHER:0(node,window,document,Image,Audio), XHR:1, Silverlight:2 * @private * @type {number} */ @@ -101,7 +108,7 @@ var X_EventDispatcher = X[ 'EventDispatcher' ] = /** * イベントリスナをイベント名文字列や数値(5以上、フレームワーク内で定義)をキーとするArrayで記憶します。
- * Arrayには、{kind:種類,context:コンテキスト(thisObject),func:コールバック関数,supplement:サプリメントする引数の配列} というハッシュ、または関数が蓄えられています。 + * Arrayには、{cbKind:種類,context:コンテキスト(thisObject),func:コールバック関数,supplement:サプリメントする引数の配列} というハッシュ、または関数が蓄えられています。 * * @private * @type {__Listeners__} @@ -176,8 +183,8 @@ var X_EventDispatcher = X[ 'EventDispatcher' ] = if( !listeners || !( list = listeners[ opt_type ] ) ) return false; if( opt_arg1 === undefined ) return X_EventDispatcher_needsIndex ? 0 : true; - // TODO callbackHash か?判定が不十分! - if( opt_arg1.kind ){ + // TODO callbackHash か?判定が不十分! skipConvertion + if( opt_arg1.cbKind ){ cbHash = opt_arg1; } else { cbHash = X_Closure_classifyCallbackArgs( opt_arg1, opt_arg2, opt_arg3, this ); @@ -186,12 +193,13 @@ var X_EventDispatcher = X[ 'EventDispatcher' ] = if( ( unlistens = listeners[ X_LISTENERS_UNLISTENS ] ) && ( unlistens = unlistens[ opt_type ] ) ){ for( i = unlistens.length; i; ){ f = unlistens[ --i ]; - if( f === cbHash || ( f.context === cbHash.context && f.func === cbHash.func && f.name === cbHash.name && f.supplement === cbHash.supplement && f.lock === lock ) ) return false; + if( f === cbHash || ( f.context === cbHash.context && f.func === cbHash.func && f.funcName === cbHash.funcName && f.supplement === cbHash.supplement && f.lock === lock ) ) return false; }; }; + for( i = list.length; i; ){ f = list[ --i ]; - if( f === cbHash || ( f.context === cbHash.context && f.func === cbHash.func && f.name === cbHash.name && f.supplement === cbHash.supplement && f.lock === lock ) ){ + if( f === cbHash || ( f.context === cbHash.context && f.func === cbHash.func && f.funcName === cbHash.funcName && f.supplement === cbHash.supplement && f.lock === lock ) ){ // index を要求された場合、lock されていない、または unlock なら index を返す return X_EventDispatcher_needsIndex ? i : true; }; @@ -215,6 +223,9 @@ var X_EventDispatcher = X[ 'EventDispatcher' ] = e = delay; delay = 0; }; + //{+dev + delay === undefined && eval( 'throw "asyncDispatch で undefined イベントが指定されました"' ); + //}+dev timerID = X_Timer_add( delay, 1, this, X_EventDispatcher_dispatch, [ e ] ); X_EventDispatcher_LAZY_TIMERS[ timerID ] = this; return timerID; @@ -255,22 +266,24 @@ function X_EventDispatcher_dispatch( e ){ } else { listeners[ X_LISTENERS_DISPATCHING ] = 1; }; - - // todo: - // type も保存 - listeners[ X_LISTENERS_UNLISTENS ] = listeners[ X_LISTENERS_UNLISTENS ] || {}; - unlistens = listeners[ X_LISTENERS_UNLISTENS ][ type ]; + + //listeners[ X_LISTENERS_UNLISTENS ] = listeners[ X_LISTENERS_UNLISTENS ] || {}; + //unlistens = listeners[ X_LISTENERS_UNLISTENS ][ type ]; for( i = 0; i < list.length; ++i ){ f = list[ i ]; + // TODO removed フラグは? + if( f.removed ) continue; + /* if( !unlistens ){ unlistens = listeners[ X_LISTENERS_UNLISTENS ][ type ]; }; if( unlistens && unlistens.indexOf( f ) !== -1 ) continue; + */ - r = X_Closure_proxyCallback( f, args || ( args = [ e ] ) ) || 0; + r = X_Closure_proxyCallback( f, args || ( args = [ e ] ) ); - if( f.once || r & X_CALLBACK_UN_LISTEN ){ + if( f.once || ( r & X_CALLBACK_UN_LISTEN ) ){ // dispatch 中に unlisten が作られることがある if( !unlistens ){ unlistens = listeners[ X_LISTENERS_UNLISTENS ] || ( listeners[ X_LISTENERS_UNLISTENS ] = {} ); @@ -360,10 +373,6 @@ function X_EventDispatcher_dispatch( e ){ * this[ 'listen' ]( [ 'open', 'close', 'ready' ], onUpdate ); * * @alias EventDispatcher.prototype.listen - * @param {string|number|Array.} type 配列を指定した場合、複数のイベントタイプに対して同じコールバックを登録する。 - * @param {listener|function|Array} [opt_arg1=] - * @param {function|Array} [opt_arg2=] - * @param {Array} [opt_arg3=] コールバック時の引数を配列に入れる。引数がひとつでも配列を使用する。省略した場合引数なし。 * @return {EventDispatcher} チェインメソッド */ function X_EventDispatcher_listen( type, opt_arg1, opt_arg2, opt_arg3 ){ @@ -413,13 +422,10 @@ function X_EventDispatcher_systemListen( that, type, opt_arg1, opt_arg2, opt_arg }; /** - * イベントリスナの解除を行う。登録時と同じ引数を与える必要がある。kill() ですべてのイベントが解除されるので、途中で解除されるイベント以外は kill() に任せてしまってよい。 + * イベントリスナの解除を行う。登録時と同じ引数を与える必要がある。kill() で自信に登録されたすべてのイベントが解除されるので、途中で解除されるイベント以外は kill() に任せてしまってよい。
+ * 他人に登録したイベントを解除せずに kill するのは NG。 * @alias EventDispatcher.prototype.unlisten * @return {EventDispatcher} - * @param {string|number|Array.} opt_type イベントID, イベント名、またはその配列 - * @param {listener|function|Array} opt_arg1 - * @param {function|Array} opt_arg2 - * @param {Array} opt_arg3 */ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ var listeners = this[ '_listeners' ], @@ -455,13 +461,17 @@ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ f = ( list = listeners[ opt_type ] )[ i ]; - if( unlistens = listeners[ X_LISTENERS_UNLISTENS ] ){ + if( listeners[ X_LISTENERS_DISPATCHING ] ){ + unlistens = listeners[ X_LISTENERS_UNLISTENS ] || ( listeners[ X_LISTENERS_UNLISTENS ] = {} ); // _unlistens に入っている callbackHash は、lock のチェックは済んでいる ( unlistens = unlistens[ opt_type ] ) ? ( unlistens[ unlistens.length ] = f ) : ( listeners[ X_LISTENERS_UNLISTENS ][ opt_type ] = [ f ] ); + f.removed = true; } else { - delete f.once; + //delete f.once; + X_Object_clear( f ); + if( list.length !== 1 ){ list.splice( i, 1 ); } else { @@ -514,6 +524,7 @@ function X_EventDispatcher_unlistenAll( that ){ function X_EventDispatcher_actualAddEvent( that, type, raw, list ){ var i, f; + X_EventDispatcher_lock || ( type = X_Event_Rename[ type ] || type ); if( X_Type_isArray( type ) ){ @@ -542,13 +553,7 @@ function X_EventDispatcher_actualAddEvent( that, type, raw, list ){ }; default : - // iOS と MacOSX Iron36 で発生。連続してアニメーションが起こると、クロージャの束縛された obj へのアクセスに失敗する。Win では起きない? - // むしろ、MacOSX のブラウザ全般で起こる?? - if( ( X_UA[ 'WebKit' ] || X_UA[ 'Blink' ] ) && - ( type === 'webkitTransitionEnd' || type === 'transitionend' || - type === 'animationend' || type === 'webkitAnimationEnd' || - type === 'animationstart' || type === 'webkitAnimationStart' || - type === 'animationiteration' || type === 'webkitAnimationIteration' ) ){ + if( X_EventDispatcher_ANIME_EVENTS && X_EventDispatcher_ANIME_EVENTS[ type ] ){ raw.addEventListener( type, X_EventDispatcher_iOSTransitionEndDispatch, false ); } else { f = that[ '_listeners' ][ X_LISTENERS_ACTUAL_HANDLER ] || ( that[ '_listeners' ][ X_LISTENERS_ACTUAL_HANDLER ] = X_Closure_create( that, X_EventDispatcher_actualHandleEvent ) ); @@ -627,6 +632,7 @@ function X_EventDispatcher_sliverLightDispatch( sender, e, type ){ function X_EventDispatcher_actualRemoveEvent( that, type, raw, list, skip ){ var i; + X_EventDispatcher_unlock || ( type = X_Event_Rename[ type ] || type ); if( X_Type_isArray( type ) ){ @@ -652,13 +658,9 @@ function X_EventDispatcher_actualRemoveEvent( that, type, raw, list, skip ){ }; default : - if( ( X_UA[ 'WebKit' ] || X_UA[ 'Blink' ] ) && - ( type === 'webkitTransitionEnd' || type === 'transitionend' || - type === 'animationend' || type === 'webkitAnimationEnd' || - type === 'animationstart' || type === 'webkitAnimationStart' || - type === 'animationiteration' || type === 'webkitAnimationIteration' ) ){ + if( X_EventDispatcher_ANIME_EVENTS && X_EventDispatcher_ANIME_EVENTS[ type ] ){ raw.removeEventListener( type, X_EventDispatcher_iOSTransitionEndDispatch, false ); - } else + } else if( raw.addEventListener ){ raw.removeEventListener( type, that[ '_listeners' ][ X_LISTENERS_ACTUAL_HANDLER ], false ); } else { @@ -731,6 +733,7 @@ function X_EventDispatcher_actualRemoveEvent( that, type, raw, list, skip ){ // TODO ブラウザからの呼び出しの最後に登録された関数を呼び出す機能(例えば画面の更新) +var X_EventDispatcher_CURRENT_EVENTS = []; // handleEvent を拡張可能にするために、クロージャに移動した // Is this in regard to the Safari 1.x preventDefault bug on click/dblclick? @@ -738,9 +741,14 @@ function X_EventDispatcher_actualRemoveEvent( that, type, raw, list, skip ){ var X_EventDispatcher_actualHandleEvent = X_UA_EVENT.IE4 || X_UA_EVENT.IE ? // ie45678 EVENT_IE & EVENT_DOM0 for ie4 (function(){ - var e = event, ret; + var e = event, ret, + ev = new X_DomEvent( e, this, this[ '_rawObject' ] ); + + X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length ] = ev; - ret = this[ 'dispatch' ]( new X_DomEvent( e, this, this[ '_rawObject' ] ) ); + ret = this[ 'dispatch' ]( ev ); + + --X_EventDispatcher_CURRENT_EVENTS.length; if( ret & X_CALLBACK_STOP_PROPAGATION ){ e.cancelBubble = true; @@ -755,7 +763,9 @@ var X_EventDispatcher_actualHandleEvent = var ev = new X_DomEvent( e, this ), ret = X_CALLBACK_NONE, i, l; - //console.log( '>>>>>>>>>> ' + e.type ); + + X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length ] = ev; + // touch event -> pointer if( X_Type_isArray( ev ) ){ if( ev.length === 0 ){ @@ -771,6 +781,8 @@ var X_EventDispatcher_actualHandleEvent = ret = this[ 'dispatch' ]( ev ); }; + --X_EventDispatcher_CURRENT_EVENTS.length; + if( ret & X_CALLBACK_STOP_PROPAGATION ){ e.stopPropagation(); };