OSDN Git Service

Version 0.6.16.
[pettanr/clientJs.git] / 0.6.x / js / core / 06_XEventDispatcher.js
1 /**\r
2  * use X.Callback\r
3  */\r
4 \r
5 X.EventDispatcher =\r
6         X.Class.create(\r
7                 'EventDispatcher',\r
8                 {\r
9                         _listeners    : null,\r
10                         _dispatching  : 0, // dispatch 中の unlisten で使用\r
11                         _unlistens    : null, // dispatch 中の unlisten で使用\r
12                         _needsIndex   : false, // listening で index を返す\r
13                         _killReserved : false,\r
14                         \r
15                         listen : function( type, arg1, arg2, arg3 ){\r
16                                 var list = this._listeners,\r
17                                         f;\r
18                                 if( this.listening( type, arg1, arg2, arg3 ) ) return this;\r
19                                 if( !list ) list = this._listeners = {};\r
20                                 if( !( list = list[ type ] ) ) list = this._listeners[ type ] = [];\r
21                                 list[ list.length ] = f =\r
22                                         ( arg1 && !arg2 ) ?\r
23                                                 arg1 :\r
24                                                 X.Callback.create( arg1, arg2, arg3 );\r
25                                 f.once = X.EventDispatcher._once;\r
26                                 return this;\r
27                         },\r
28                         listenOnce : function( type, arg1, arg2, arg3 ){\r
29                                 X.EventDispatcher._once = true;\r
30                                 this.listen( type, arg1, arg2, arg3 );\r
31                                 X.EventDispatcher._once = false;\r
32                                 return this;\r
33                         },\r
34                         unlisten : function( type, arg1, arg2, arg3 ){\r
35                                 var list = this._listeners,\r
36                                         i, f;\r
37                                 if( !list ) return this;\r
38                                 if( type === undefined ){\r
39                                         // 全て削除\r
40                                         for( type in list ){\r
41                                                 this.unlisten( type ); // override されていることがあるので、必ず unlisten を使用\r
42                                         };\r
43                                         return this;\r
44                                 };\r
45                                 if( arg1 === undefined ){\r
46                                         // 同一タイプを全て削除\r
47                                         if( !( list = list[ type ] ) ) return this;\r
48                                         for( i = list.length; i; ){\r
49                                                 this.unisten( type, list[ --i ] ); // override されていることがあるので、必ず unlisten を使用\r
50                                         };\r
51                                         return this;\r
52                                 };\r
53                                 \r
54                                 this._needsIndex = true;\r
55                                 i = this.listening( type, arg1, arg2, arg3 );\r
56                                 delete this._needsIndex;\r
57                                 if( i === false ) return this;\r
58 \r
59                                 f = ( list = list[ type ] )[ i ];\r
60                                 if( this._dispatching ){\r
61                                         this._unlistens[ this._unlistens.length ] = f;\r
62                                 } else {\r
63                                         delete f.once;\r
64                                         f.kill === X.Callback._kill && f.kill();\r
65                                         list.splice( i, 1 );\r
66                                         if( !list.length ){\r
67                                                 delete this._listeners[ type ];\r
68                                                 if( X.isEmptyObject( this._listeners ) ) delete this._listeners;\r
69                                         };\r
70                                 };\r
71                                 return this;\r
72                         },\r
73                         listening : function( type, arg1, arg2, arg3 ){\r
74                                 var list = this._listeners, i, f;\r
75                                 if( type === undefined ) return !!list;\r
76                                 if( !list || !( list = list[ type ] ) ) return false;\r
77                                 if( arg1 === undefined ) return true;\r
78                                 for( i = list.length; i; ){\r
79                                         f = list[ --i ];\r
80                                         if( f === arg1 || ( f.same && f.same( arg1, arg2, arg3 ) ) ) return this._needsIndex ? i : true;\r
81                                 };\r
82                                 return false;\r
83                         },\r
84                         /*\r
85                          * dispatch 中に dispatch が呼ばれるケースがあるため、\r
86                          * _dispatching では その深さを保存する\r
87                          * _dispatching が 0 のときに unlistens を削除する\r
88                          *\r
89                          */\r
90                         dispatch : function( e ){\r
91                                 // dispatch 中の listen は?\r
92                                 var list = this._listeners,\r
93                                         ret  = X.Callback.NONE,\r
94                                         i, f, r, sysOnly;\r
95 \r
96                                 if( !list || !( list = list[ e.type ] ) ) return ret;\r
97                                 \r
98                                 ++this._dispatching;\r
99                                 this._unlistens = this._unlistens || [];\r
100                                 \r
101                                 for( i = 0; i < list.length; ++i ){\r
102                                         f = list[ i ];\r
103                                         if( this._unlistens.length && this._unlistens.indexOf( f ) !== -1 ){\r
104                                                 continue;\r
105                                         };\r
106 \r
107                                         r = typeof f === 'function' ? f( e ) : f.handleEvent( e );\r
108                                         \r
109                                         if( f.once === true || r & X.Callback.UN_LISTEN ){\r
110                                                 this._unlistens[ this._unlistens.length ] = f;\r
111                                         };\r
112 \r
113                                         if( r & X.Callback.STOP_NOW ){\r
114                                                 sysOnly = true;\r
115                                         };\r
116                                         ret |= r;\r
117                                 };\r
118                                 \r
119                                 if( ( --this._dispatching ) === 0 ){\r
120                                         // dispatch 中に unlisten された要素の削除\r
121                                         for( i = this._unlistens.length ; i; ){\r
122                                                 this.unlisten( e.type, this._unlistens[ --i ] );\r
123                                         };\r
124                                         delete this._dispatching;\r
125                                         delete this._unlistens;\r
126                                         \r
127                                         this._killReserved && this.kill();\r
128                                 };\r
129                                 \r
130                                 return ret;\r
131                         },\r
132                         \r
133                         onKill : function(){\r
134                                 if( this._dispatching ){\r
135                                         this._killReserved = true;\r
136                                         return false;\r
137                                 };\r
138                                 this._listeners && this.unlisten();\r
139                         },\r
140                         \r
141                         asyncDispatch : function( delay, e ){\r
142                                 return X.Timer.once( delay, this, this.dispatch, [ e ] );\r
143                         }\r
144                 }\r
145         );\r
146 \r
147 X.EventDispatcher._once = false;\r