OSDN Git Service

Version 0.6.41, fix for Opera8 & NN7.2+.
[pettanr/clientJs.git] / 0.6.x / js / core / 06_XEventDispatcher.js
index 5755238..a4a1338 100644 (file)
@@ -1,18 +1,54 @@
+/**\r
+ * use X.Callback\r
+ * \r
+ * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.addEventListener\r
+ * イベント発送中のリスナーの追加\r
+ * EventListener がイベント処理中に EventTarget に追加された場合、それが現在のアクションによって実行されることはありませんが、浮上フェーズのように、後の段階のイベントフローで実行されるかもしれません。\r
+ * \r
+ * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.removeEventListener\r
+ * イベントリスナーが イベントを処理中であるイベントターゲットから削除された場合、現在のアクションによってそのイベントリスナーが実行されることはありません。\r
+ * イベントリスナーは、決して削除された後に実行されることはありません。\r
+ * イベントターゲット上にある現在のどのイベントリスナーも指定していない引数付きの removeEventListener は、何の効果もありません。\r
+ */\r
+\r
+X.Event = {\r
+       COMPLETE    : 1,\r
+       SUCCESS     : 2,\r
+       ERROR       : 3,\r
+       PROGRESS    : 4,\r
+       _LAST_EVENT : 4\r
+};\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
-                       _needsIndex  : false,\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
-                                       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, X.EventDispatcher._once ];\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
-                               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
@@ -24,35 +60,53 @@ X.EventDispatcher =
                        },\r
                        unlisten : function( type, arg1, arg2, arg3 ){\r
                                var list = this._listeners,\r
-                                       i, f;\r
+                                       _list, reserves, 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 ){\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
                                \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
+                                       };\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( this._dispatching ){\r
-                                       this._unlistens[ this._unlistens.length ] = f;\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 && f.kill();\r
+                                       f.kill === X.Callback._kill && f.kill();\r
                                        list.splice( i, 1 );\r
                                        if( !list.length ){\r
                                                delete this._listeners[ type ];\r
@@ -62,10 +116,16 @@ X.EventDispatcher =
                                return this;\r
                        },\r
                        listening : function( type, arg1, arg2, arg3 ){\r
-                               var list = this._listeners, i, f;\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
                                        f = list[ --i ];\r
                                        if( f === arg1 || ( f.same && f.same( arg1, arg2, arg3 ) ) ) return this._needsIndex ? i : true;\r
@@ -76,29 +136,38 @@ X.EventDispatcher =
                         * 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
-\r
-                               if( !list || !( list = list[ e.type ] ) ) return ret;\r
+                               var list  = this._listeners,\r
+                                       ret   = X.Callback.NONE,\r
+                                       type  = e.type,\r
+                                       unlistens, i, l, f, r, sysOnly;\r
+                               \r
+                               // 数値, 文字が渡された場合\r
+                               if( !type ) e = { type : type = e };\r
+                               e.target = e.target || this;\r
+                               \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
@@ -109,16 +178,49 @@ X.EventDispatcher =
                                \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
+                                       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
+                                                       X.EventDispatcher._once = f[ 4 ];\r
+                                                       this.listen( f[ 0 ], f[ 1 ], f[ 2 ], f[ 3 ] );\r
+                                                       X.EventDispatcher._once = false;\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