+/**\r
+ * use X.Callback\r
+ */\r
+\r
X.EventDispatcher =\r
X.Class.create(\r
'EventDispatcher',\r
{\r
- _listeners : null,\r
- _dispatching : 0, // dispatch 中の unlisten で使用\r
- _unlistens : null, // dispatch 中の unlisten で使用\r
+ _listeners : null,\r
+ _dispatching : 0, // dispatch 中の unlisten で使用\r
+ _unlistens : null, // dispatch 中の unlisten で使用\r
+ _needsIndex : false, // listening で index を返す\r
+ _reserves : null,\r
+ _killReserved : false,\r
+ \r
listen : function( type, arg1, arg2, arg3 ){\r
var list = this._listeners,\r
- i, f;\r
+ r, f;\r
+ if( this._dispatching ){\r
+ // todo\r
+ // reserve\r
+ if( !this._reserves ) this._reserves = [];\r
+ this._reserves[ this._reserves.length ] = [ type, arg1, arg2, arg3 ];\r
+ return this;\r
+ } else\r
+ if( this.listening( type, arg1, arg2, arg3 ) ) return this;\r
+\r
if( !list ) list = this._listeners = {};\r
if( !( list = list[ type ] ) ) list = this._listeners[ type ] = [];\r
- for( i = list.length; i; ){\r
- if( list[ --i ].same( arg1, arg2/* , arg3 */ ) ) return this;\r
- };\r
- list[ list.length ] = f = X.Callback.create( arg1, arg2, arg3 );\r
+ list[ list.length ] = f =\r
+ ( arg1 && !arg2 ) ?\r
+ arg1 :\r
+ X.Callback.create( arg1, arg2, arg3 );\r
f.once = X.EventDispatcher._once;\r
return this;\r
},\r
},\r
unlisten : function( type, arg1, arg2, arg3 ){\r
var list = this._listeners,\r
- i, f;\r
+ _list, reservess, unlistens, i, f;\r
if( !list ) return this;\r
if( type === undefined ){\r
// 全て削除\r
for( type in list ){\r
- this.unlisten( type ); // override されていることがあるので、必ず unlisten を使用\r
+ _list = list[ type ];\r
+ if( !( i = _list.length ) ) continue;\r
+ for( ; i; ){\r
+ this.unlisten( type, _list[ --i ] ); // override されていることがあるので、必ず unlisten を使用\r
+ };\r
+ // this.unlisten( type ); これは無茶!\r
};\r
return this;\r
};\r
- if( arg1 === undefined && arg2 === undefined ){\r
+ if( arg1 === undefined ){\r
// 同一タイプを全て削除\r
- if( !( list = list[ type ] ) ) return this;\r
- for( i = list.length; i; ){\r
- this.unisten( type, list[ --i ] ); // override されていることがあるので、必ず unlisten を使用\r
+ if( !( list = list[ type ] ) || !( i = list.length ) ) return this;\r
+ for( ; i; ){\r
+ this.unlisten( type, list[ --i ] ); // override されていることがあるので、必ず unlisten を使用\r
};\r
return this;\r
};\r
- if( !list || !( list = list[ type ] ) ) return this;\r
- for( i = list.length; i; ){\r
- f = list[ --i ];\r
- if( f.same( arg1, arg2, arg3 ) ){\r
- if( this._dispatching ){\r
- this._unlistens[ this._unlistens.length ] = f;\r
- } else {\r
- delete f.once;\r
- f.kill();\r
- list.splice( i, 1 );\r
- if( !list.length ){\r
- delete this._listeners[ type ];\r
- if( X.isEmptyObject( this._listeners ) ) delete this._listeners;\r
- };\r
+ \r
+ if( reserves = this._reserves ){\r
+ for( i = reserves.length; i; ){\r
+ f = reserves[ --i ];\r
+ if( f[ 0 ] === type && f[ 1 ] === arg1 && f[ 2 ] === arg2 && f[ 3 ] === arg3 ){\r
+ reserves.splice( i, 1 );\r
+ if( !reserves.legth ) delete this._reserves;\r
+ return this;\r
};\r
- return this;\r
+ };\r
+ };\r
+ \r
+ this._needsIndex = true;\r
+ i = this.listening( type, arg1, arg2, arg3 );\r
+ delete this._needsIndex;\r
+ if( i === false ) return this;\r
+\r
+ f = ( list = list[ type ] )[ i ];\r
+ if( unlistens = this._unlistens ){\r
+ ( unlistens = unlistens[ type ] ) ?\r
+ ( unlistens[ unlistens.length ] = f ) :\r
+ ( this._unlistens[ type ] = [ f ] );\r
+ } else {\r
+ delete f.once;\r
+ f.kill === X.Callback._kill && f.kill();\r
+ list.splice( i, 1 );\r
+ if( !list.length ){\r
+ delete this._listeners[ type ];\r
+ if( X.isEmptyObject( this._listeners ) ) delete this._listeners;\r
};\r
};\r
return this;\r
},\r
listening : function( type, arg1, arg2, arg3 ){\r
- var list = this._listeners, i;\r
+ var list = this._listeners, unlistens, i, f;\r
+ if( type === undefined ) return !!list;\r
if( !list || !( list = list[ type ] ) ) return false;\r
+ if( arg1 === undefined ) return true;\r
+ if( ( unlistens = this._unlistens ) && ( unlistens = unlistens[ type ] ) ){\r
+ for( i = unlistens.length; i; ){\r
+ f = unlistens[ --i ];\r
+ if( f === arg1 || ( f.same && f.same( arg1, arg2, arg3 ) ) ) return false;\r
+ };\r
+ };\r
for( i = list.length; i; ){\r
- if( list[ --i ].same( arg1, arg2 /* , arg3 */ ) ) return true;\r
+ f = list[ --i ];\r
+ if( f === arg1 || ( f.same && f.same( arg1, arg2, arg3 ) ) ) return this._needsIndex ? i : true;\r
};\r
return false;\r
},\r
* dispatch 中に dispatch が呼ばれるケースがあるため、\r
* _dispatching では その深さを保存する\r
* _dispatching が 0 のときに unlistens を削除する\r
- * \r
+ *\r
*/\r
dispatch : function( e ){\r
// dispatch 中の listen は?\r
- var list = this._listeners,\r
- ret = X.Callback.NONE,\r
- i, f, r, sysOnly;\r
+ var list = this._listeners,\r
+ ret = X.Callback.NONE,\r
+ type = e.type,\r
+ unlistens, i, l, f, r, sysOnly;\r
\r
- if( !list || !( list = list[ e.type ] ) ) return ret;\r
+ if( !list || !( list = list[ type ] ) ) return ret;\r
\r
++this._dispatching;\r
- this._unlistens = this._unlistens || [];\r
+ \r
+ // todo:\r
+ // type も保存\r
+ this._unlistens = this._unlistens || {};\r
+ unlistens = this._unlistens[ type ];\r
\r
for( i = 0; i < list.length; ++i ){\r
f = list[ i ];\r
- if( this._unlistens.length && this._unlistens.indexOf( f ) !== -1 ){\r
- continue;\r
- };\r
- \r
- r = f( e );\r
+ if( unlistens && unlistens.indexOf( f ) !== -1 ) continue;\r
+\r
+ r = typeof f === 'function' ? f( e ) : f.handleEvent( e );\r
\r
if( f.once === true || r & X.Callback.UN_LISTEN ){\r
- this._unlistens[ this._unlistens.length ] = f;\r
+ unlistens ?\r
+ ( unlistens[ unlistens.length ] = f ) :\r
+ ( unlistens = this._unlistens[ type ] = [ f ] );\r
};\r
\r
if( r & X.Callback.STOP_NOW ){\r
\r
if( ( --this._dispatching ) === 0 ){\r
// dispatch 中に unlisten された要素の削除\r
- for( i = this._unlistens.length ; i; ){\r
- this.unlisten( e.type, this._unlistens[ --i ] );\r
- };\r
- delete this._dispatching\r
+ unlistens = this._unlistens;\r
+ delete this._dispatching;\r
delete this._unlistens; \r
+ \r
+ for( type in unlistens ){\r
+ list = unlistens[ type ];\r
+ for( i = list.length; i; ){\r
+ this.unlisten( type, list[ --i ] );\r
+ };\r
+ unlistens.length = 0;\r
+ };\r
+ \r
+ if( this._killReserved ){\r
+ this.kill();\r
+ } else\r
+ if( list = this._reserves ){\r
+ for( i = 0, l = list.length; i < l; ++i ){\r
+ f = list[ i ];\r
+ this.listen( f[ 0 ], f[ 1 ], f[ 2 ], f[ 3 ] );\r
+ f.length = 0;\r
+ };\r
+ list.length = 0;\r
+ delete this._reserves;\r
+ };\r
};\r
\r
return ret;\r
+ },\r
+ \r
+ onKill : function(){\r
+ if( this._dispatching ){\r
+ this._killReserved = true;\r
+ return false;\r
+ };\r
+ this._listeners && this.unlisten();\r
+ },\r
+ \r
+ asyncDispatch : function( delay, e ){\r
+ return X.Timer.once( delay, this, this.dispatch, [ e ] );\r
}\r
- }//, onKillCallback( instance )\r
+ }\r
);\r
\r
X.EventDispatcher._once = false;\r