4 * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.addEventListener
\r
6 * EventListener がイベント処理中に EventTarget に追加された場合、それが現在のアクションによって実行されることはありませんが、浮上フェーズのように、後の段階のイベントフローで実行されるかもしれません。
\r
8 * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.removeEventListener
\r
9 * イベントリスナーが イベントを処理中であるイベントターゲットから削除された場合、現在のアクションによってそのイベントリスナーが実行されることはありません。
\r
10 * イベントリスナーは、決して削除された後に実行されることはありません。
\r
11 * イベントターゲット上にある現在のどのイベントリスナーも指定していない引数付きの removeEventListener は、何の効果もありません。
\r
31 _dispatching : 0, // dispatch 中の unlisten で使用
\r
32 _unlistens : null, // dispatch 中の unlisten で使用
\r
33 _needsIndex : false, // listening で index を返す
\r
35 _killReserved : false,
\r
37 listen : function( type, arg1, arg2, arg3 ){
\r
38 var list = this._listeners,
\r
40 if( this._dispatching ){
\r
41 if( !this._reserves ) this._reserves = [];
\r
42 this._reserves[ this._reserves.length ] = [ type, arg1, arg2, arg3, X.EventDispatcher._once ];
\r
46 if( X.Type.isArray( type ) ){
\r
47 for( i = type.length; i; ){
\r
48 this.listen( type[ --i ], arg1, arg2, arg3 );
\r
53 if( this.listening( type, arg1, arg2, arg3 ) ) return this;
\r
55 if( !list ) list = this._listeners = {};
\r
56 if( !( list = list[ type ] ) ) list = this._listeners[ type ] = [];
\r
58 f = X.Callback._classifyCallbackArgs( arg1, arg2, arg3, this );
\r
59 list[ list.length ] = f;
\r
60 f.once = X.EventDispatcher._once;
\r
64 listenOnce : function( type, arg1, arg2, arg3 ){
\r
65 X.EventDispatcher._once = true;
\r
66 this.listen( type, arg1, arg2, arg3 );
\r
67 X.EventDispatcher._once = false;
\r
70 unlisten : function( type, arg1, arg2, arg3 ){
\r
71 var list = this._listeners,
\r
72 _list, reserves, unlistens, i, f;
\r
73 if( !list ) return this;
\r
75 if( X.Type.isArray( type ) ){
\r
76 for( i = type.length; i; ){
\r
77 this.unlisten( type[ --i ], arg1, arg2, arg3 );
\r
82 if( type === undefined ){
\r
84 for( type in list ){
\r
85 _list = list[ type ];
\r
86 for( i = _list.length; i; ){
\r
87 this.unlisten( type, _list[ --i ] ); // override されていることがあるので、必ず unlisten を使用
\r
89 // this.unlisten( type ); これは無茶!
\r
93 if( arg1 === undefined ){
\r
95 if( _list = list[ type ] ){
\r
96 for( i = _list.length; i; ){
\r
97 this.unlisten( type, _list[ --i ] ); // override されていることがあるので、必ず unlisten を使用
\r
102 if( reserves = this._reserves ){
\r
103 for( i = reserves.length; i; ){
\r
104 f = reserves[ --i ];
\r
105 if( f[ 0 ] === type && f[ 1 ] === arg1 && f[ 2 ] === arg2 && f[ 3 ] === arg3 ){
\r
106 reserves.splice( i, 1 );
\r
107 if( !reserves.legth ) delete this._reserves;
\r
113 this._needsIndex = true;
\r
114 i = this.listening( type, arg1, arg2, arg3 );
\r
115 delete this._needsIndex;
\r
116 if( i === false ) return this;
\r
118 f = ( _list = list[ type ] )[ i ];
\r
119 if( unlistens = this._unlistens ){
\r
120 ( unlistens = unlistens[ type ] ) ?
\r
121 ( unlistens[ unlistens.length ] = f ) :
\r
122 ( this._unlistens[ type ] = [ f ] );
\r
125 f.kill === X.Callback._kill && f.kill();
\r
126 _list.splice( i, 1 );
\r
127 if( !_list.length ){
\r
128 delete this._listeners[ type ];
\r
129 if( X.isEmptyObject( this._listeners ) ) delete this._listeners;
\r
134 listening : function( type, arg1, arg2, arg3 ){
\r
135 var list = this._listeners, unlistens, i, f, hash;
\r
136 if( type === undefined ) return !!list;
\r
137 if( !list || !( list = list[ type ] ) ) return false;
\r
138 if( arg1 === undefined ) return true;
\r
143 hash = X.Callback._classifyCallbackArgs( arg1, arg2, arg3, this );
\r
146 if( ( unlistens = this._unlistens ) && ( unlistens = unlistens[ type ] ) ){
\r
147 for( i = unlistens.length; i; ){
\r
148 f = unlistens[ --i ];
\r
149 if( f === hash || ( f.x === hash.x && f.f === hash.f && f.s === hash.s ) ) return false;
\r
152 for( i = list.length; i; ){
\r
154 if( f === hash || ( f.x === hash.x && f.f === hash.f && f.s === hash.s ) ) return this._needsIndex ? i : true;
\r
159 * dispatch 中に dispatch が呼ばれるケースがあるため、
\r
160 * _dispatching では その深さを保存する
\r
161 * _dispatching が 0 のときに unlistens を削除する
\r
164 dispatch : function( e ){
\r
165 // dispatch 中の listen は?
\r
166 var list = this._listeners,
\r
167 ret = X.Callback.NONE,
\r
169 unlistens, i, l, f, r, sysOnly;
\r
171 if( !list ) return ret;
\r
174 if( !type ) e = { type : type = e };
\r
175 e.target = e.target || this;
\r
177 if( !( list = list[ type ] ) ) return ret;
\r
179 ++this._dispatching;
\r
183 this._unlistens = this._unlistens || {};
\r
184 unlistens = this._unlistens[ type ];
\r
186 for( i = 0; i < list.length; ++i ){
\r
189 unlistens = this._unlistens[ type ];
\r
191 if( unlistens && unlistens.indexOf( f ) !== -1 ) continue;
\r
195 r = X.Callback._proxyCallback( f );
\r
197 r = f.call( this, e );
\r
200 if( f.once || r & X.Callback.UN_LISTEN ){
\r
201 // dispatch 中に unlisten が作られることがある
\r
203 unlistens = this._unlistens || ( this._unlistens = {} );
\r
204 unlistens = unlistens[ type ] || ( unlistens[ type ] = [] );
\r
206 unlistens.indexOf( f ) === -1 && ( unlistens[ unlistens.length ] = f );
\r
209 if( r & X.Callback.STOP_NOW ){
\r
215 if( ( --this._dispatching ) === 0 ){
\r
216 // dispatch 中に unlisten された要素の削除
\r
217 unlistens = this._unlistens;
\r
218 delete this._dispatching;
\r
219 delete this._unlistens;
\r
221 for( type in unlistens ){
\r
222 list = unlistens[ type ];
\r
223 for( i = list.length; i; ){
\r
224 this.unlisten( type, list[ --i ] );
\r
227 delete unlistens[ type ];
\r
230 if( this._killReserved ){
\r
233 if( list = this._reserves ){
\r
234 for( i = 0, l = list.length; i < l; ++i ){
\r
236 X.EventDispatcher._once = f[ 4 ];
\r
237 this.listen( f[ 0 ], f[ 1 ], f[ 2 ], f[ 3 ] );
\r
238 X.EventDispatcher._once = false;
\r
242 delete this._reserves;
\r
249 onKill : function(){
\r
250 if( this._dispatching ){
\r
251 this._killReserved = true;
\r
254 this._listeners && this.unlisten();
\r
257 asyncDispatch : function( delay, e ){
\r
258 return X.Timer.add( delay, 1, this, this.dispatch, [ e ] );
\r
263 X.EventDispatcher._once = false;
\r
265 console.log( 'X.Core.EventDispatcher' );
\r