OSDN Git Service

Version 0.6.68, fix X.Type.isArray().
[pettanr/clientJs.git] / 0.6.x / js / 00_core / 06_XEventDispatcher.js
1 /**\r
2  * use X.Callback\r
3  * \r
4  * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.addEventListener\r
5  * イベント発送中のリスナーの追加\r
6  * EventListener がイベント処理中に EventTarget に追加された場合、それが現在のアクションによって実行されることはありませんが、浮上フェーズのように、後の段階のイベントフローで実行されるかもしれません。\r
7  * \r
8  * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.removeEventListener\r
9  * イベントリスナーが イベントを処理中であるイベントターゲットから削除された場合、現在のアクションによってそのイベントリスナーが実行されることはありません。\r
10  * イベントリスナーは、決して削除された後に実行されることはありません。\r
11  * イベントターゲット上にある現在のどのイベントリスナーも指定していない引数付きの removeEventListener は、何の効果もありません。\r
12  */\r
13 \r
14 X.Event = {\r
15         COMPLETE      : 1,\r
16         SUCCESS       : 2,\r
17         ERROR         : 3,\r
18         PROGRESS      : 4,\r
19         BEFORE_CANCEL : 5,\r
20         CANCELED      : 6,\r
21         TIMEOUT       : 7,\r
22         _LAST_EVENT   : 7\r
23 };\r
24 \r
25 \r
26 X.EventDispatcher =\r
27         X.Class.create(\r
28                 'EventDispatcher',\r
29                 {\r
30                         _listeners    : null,\r
31                         _dispatching  : 0, // dispatch 中の unlisten で使用\r
32                         _unlistens    : null, // dispatch 中の unlisten で使用\r
33                         _needsIndex   : false, // listening で index を返す\r
34                         _reserves     : null,\r
35                         _killReserved : false,\r
36                         \r
37                         listen : function( type, arg1, arg2, arg3 ){\r
38                                 var list = this._listeners,\r
39                                         i, r, f;\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
43                                         return this;\r
44                                 };\r
45                                 \r
46                                 if( X.Type.isArray( type ) ){\r
47                                         for( i = type.length; i; ){\r
48                                                 this.listen( type[ --i ], arg1, arg2, arg3 );\r
49                                         };\r
50                                         return this;\r
51                                 };\r
52                                 \r
53                                 if( this.listening( type, arg1, arg2, arg3 ) ) return this;\r
54 \r
55                                 if( !list ) list = this._listeners = {};\r
56                                 if( !( list = list[ type ] ) ) list = this._listeners[ type ] = [];\r
57                                 \r
58                                 f = X.Callback._classifyCallbackArgs( arg1, arg2, arg3, this );\r
59                                 list[ list.length ] = f;\r
60                                 f.once = X.EventDispatcher._once;\r
61                                 \r
62                                 return this;\r
63                         },\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
68                                 return this;\r
69                         },\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
74                                 \r
75                                 if( X.Type.isArray( type ) ){\r
76                                         for( i = type.length; i; ){\r
77                                                 this.unlisten( type[ --i ], arg1, arg2, arg3 );\r
78                                         };\r
79                                         return this;\r
80                                 };\r
81                                 \r
82                                 if( type === undefined ){\r
83                                         // 全て削除\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
88                                                 };\r
89                                                 // this.unlisten( type ); これは無茶!\r
90                                         };\r
91                                         return this;\r
92                                 } else\r
93                                 if( arg1 === undefined ){\r
94                                         // 同一タイプを全て削除\r
95                                         if( _list = list[ type ] ){\r
96                                                 for( i = _list.length; i; ){\r
97                                                         this.unlisten( type, _list[ --i ] ); // override されていることがあるので、必ず unlisten を使用\r
98                                                 };\r
99                                         };\r
100                                         return this;\r
101                                 } else\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
108                                                         return this;\r
109                                                 };\r
110                                         };\r
111                                 };\r
112                                 \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
117 \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
123                                 } else {\r
124                                         delete f.once;\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
130                                         };\r
131                                 };\r
132                                 return this;\r
133                         },\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
139                                 \r
140                                 if( arg1.k ){\r
141                                         hash = arg1;\r
142                                 } else {\r
143                                         hash = X.Callback._classifyCallbackArgs( arg1, arg2, arg3, this );\r
144                                 };\r
145                                 \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
150                                         };\r
151                                 };\r
152                                 for( i = list.length; i; ){\r
153                                         f = list[ --i ];\r
154                                         if( f === hash || ( f.x === hash.x && f.f === hash.f && f.s === hash.s ) ) return this._needsIndex ? i : true;\r
155                                 };\r
156                                 return false;\r
157                         },\r
158                         /*\r
159                          * dispatch 中に dispatch が呼ばれるケースがあるため、\r
160                          * _dispatching では その深さを保存する\r
161                          * _dispatching が 0 のときに unlistens を削除する\r
162                          *\r
163                          */\r
164                         dispatch : function( e ){\r
165                                 // dispatch 中の listen は?\r
166                                 var list  = this._listeners,\r
167                                         ret   = X.Callback.NONE,\r
168                                         type  = e.type,\r
169                                         unlistens, i, l, f, r, sysOnly;\r
170                                 \r
171                                 if( !list ) return ret;\r
172                                 \r
173                                 // 数値, 文字が渡された場合\r
174                                 if( !type ) e = { type : type = e };\r
175                                 e.target = e.target || this;\r
176                                 \r
177                                 if( !( list = list[ type ] ) ) return ret;\r
178                                 \r
179                                 ++this._dispatching;\r
180                                 \r
181                                 // todo:\r
182                                 // type も保存\r
183                                 this._unlistens = this._unlistens || {};\r
184                                 unlistens = this._unlistens[ type ];\r
185                                 \r
186                                 for( i = 0; i < list.length; ++i ){\r
187                                         f = list[ i ];\r
188                                         if( !unlistens ){\r
189                                                 unlistens = this._unlistens[ type ];\r
190                                         };\r
191                                         if( unlistens && unlistens.indexOf( f ) !== -1 ) continue;\r
192                                         \r
193                                         if( f.k ){\r
194                                                 f.a = [ e ];\r
195                                                 r = X.Callback._proxyCallback( f );\r
196                                         } else {\r
197                                                 r = f.call( this, e );\r
198                                         };\r
199                                         \r
200                                         if( f.once || r & X.Callback.UN_LISTEN ){\r
201                                                 // dispatch 中に unlisten が作られることがある\r
202                                                 if( !unlistens ){\r
203                                                         unlistens = this._unlistens || ( this._unlistens = {} );\r
204                                                         unlistens = unlistens[ type ] || ( unlistens[ type ] = [] );\r
205                                                 };\r
206                                                 unlistens.indexOf( f ) === -1 && ( unlistens[ unlistens.length ] = f );\r
207                                         };\r
208 \r
209                                         if( r & X.Callback.STOP_NOW ){\r
210                                                 sysOnly = true;\r
211                                         };\r
212                                         ret |= r;\r
213                                 };\r
214                                 \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
220                                         \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
225                                                 };\r
226                                                 list.length = 0;\r
227                                                 delete unlistens[ type ];\r
228                                         };\r
229                                         \r
230                                         if( this._killReserved ){\r
231                                                 this.kill();\r
232                                         } else\r
233                                         if( list = this._reserves ){\r
234                                                 for( i = 0, l = list.length; i < l; ++i ){\r
235                                                         f = list[ 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
239                                                         f.length = 0;\r
240                                                 };\r
241                                                 list.length = 0;\r
242                                                 delete this._reserves;\r
243                                         };\r
244                                 };\r
245                                 \r
246                                 return ret;\r
247                         },\r
248                         \r
249                         onKill : function(){\r
250                                 if( this._dispatching ){\r
251                                         this._killReserved = true;\r
252                                         return false;\r
253                                 };\r
254                                 this._listeners && this.unlisten();\r
255                         },\r
256                         \r
257                         asyncDispatch : function( delay, e ){\r
258                                 return X.Timer.add( delay, 1, this, this.dispatch, [ e ] );\r
259                         }\r
260                 }\r
261         );\r
262 \r
263 X.EventDispatcher._once = false;\r
264 \r
265 console.log( 'X.Core.EventDispatcher' );\r