OSDN Git Service

Version 0.6.160, fix X.Net.
[pettanr/clientJs.git] / 0.6.x / js / 01_core / 10_XCallback.js
index ce295d6..781a255 100644 (file)
@@ -3,22 +3,43 @@
 // ------------ local variables -------------------------------------------- //\r
 // ------------------------------------------------------------------------- //\r
 \r
-var X_Callback_LIVE_LIST        = [],\r
+var \r
+       X_Callback_LIVE_LIST        = [],\r
+\r
        X_Callback_POOL_LIST        = [],\r
+\r
        X_Closure_COMMAND_BACK      = X_Callback_LIVE_LIST,\r
+\r
        X_Closure_COMMAND_DROP      = X_Callback_POOL_LIST,\r
        \r
+       /** @const */\r
        X_Callback_THIS_FUNC        = 1,\r
+       /** @const */\r
        X_Callback_HANDLEEVENT      = 2,\r
+       /** @const */\r
        X_Callback_FUNC_ONLY        = 3,\r
+       /** @const */\r
+       X_Callback_THIS_FUNCNAME    = 4,\r
 \r
+       /** @const */\r
        X_Callback_NONE             =  0,\r
+       /** @const */\r
        X_Callback_UN_LISTEN        =  1,\r
-       X_Callback_STOP_PROPAGATION =  2,  // 上位階層への伝播のキャンセル\r
+       /** @const */\r
+       X_Callback_STOP_PROPAGATION =  2,\r
+       /** @const */\r
        X_Callback_STOP_NOW         =  4 | 2,  // 同一階層のリスナーのキャンセル(上位へもキャンセル)\r
+       /** @const */\r
        X_Callback_PREVENT_DEFAULT  =  8,  // 結果動作のキャンセル,\r
-       X_Callback_MONOPOLY         = 16,  // move event を独占する\r
-       X_Callback_SYS_CANCEL       = 32 | 4 | 2;\r
+       /** @const */\r
+       X_Callback_CAPTURE_POINTER  = 16,\r
+       /** @const */\r
+       X_Callback_RELEASE_POINTER  = 32,\r
+       \r
+       /** @const */\r
+       X_Callback_SYS_CANCEL       = 64 | 4 | 2;\r
+\r
+\r
 \r
 /*\r
  * handleEvent という関数のメンバーを持つオブジェクト\r
@@ -26,25 +47,109 @@ var X_Callback_LIVE_LIST        = [],
  */\r
 var listener;\r
 \r
-/*\r
- * コールバックに thisObject や、追加の引数を設定するための情報を収めたハッシュ\r
- * @typedef {{ k : number, f : (function|undefined), x : (listener|undefined), s : (Array|undefined) }}\r
+/**\r
+ * <p>クロージャに関するポリシーと再利用可能クロージャについて次の記事をご覧ください。\r
+ *     <a href="http://outcloud.blogspot.jp/2015/05/reusable-closure.html" target="_blank">再利用できるクロージャを使ったWebアプリケーション開発</a>\r
+ * \r
+ * <h5>再利用可能クロージャの作成</h5>\r
+ * X_Callback_create() で再利用可能なクロージャの作成。次のパターンで呼び出します。<br>\r
+ * 最大で三つの引数を並べる一連のパターンは、 EventDispatcher.listen unlisten, listening や X.Timer.add, once でも使われますので、ここでよく目を通しておきます。\r
+ * \r
+ * <table>\r
+ * <tr><th>this コンテキスト+関数<td>X_Callback_create( thisObject, func )<td>func.call( thisObject );\r
+ * <tr><th>this コンテキスト+関数+追加引数<td>X_Callback_create( thisObject, func, [ arg1, ...args ] )<td>func.apply( thisObject, [ arg1, ...args ] );\r
+ * <tr><th>listener オブジェクト<td>X_Callback_create( listener )<td>listener.handleEvent(); コールバックに関数でなく handleEvent 関数をメンバに持つオブジェクトを渡すのは NN4 からある javascript のお約束です。\r
+ * <tr><th>listener オブジェクト+追加引数<td>X_Callback_create( listener, [ arg1, ...args ] )<td>listener.handleEvent.apply( listener, [ arg1, ...args ] );\r
+ * <tr><th>関数<td>X_Callback_create( func )<td>特別な操作は不要なので再利用可能クロージャは作られません。func をそのまま利用します。\r
+ * <tr><th>関数+引数<td>X_Callback_create( func, [ arg1, ...args ] )<td>func.apply( ?, [ arg1, ...args ] );\r
+ * </table>\r
+ * \r
+ * <h5>再利用可能クロージャの破棄と再利用</h5>\r
+ * X_Callback_correct() によってクロージャは回収され再利用に備えます。<br>\r
+ * 実は、クロージャが束縛するのは、this コンテキストやコールバック関数といった、<strong>そのもの</strong>ではなく、それらを一定のルールで格納したハッシュです。<br>\r
+ * このハッシュはクロージャに与えた後も、適宜に取得が可能です。このハッシュのメンバーを書き換えることで、クロージャの this コンテキストやコールバック関数を書き換えています。\r
+ * \r
+ * @class __CallbackHash__\r
+ * @classdesc コールバック関数に this コンテキストや、追加の引数を設定するための情報を収めたハッシュです。<br>\r
+ * フレームワークユーザは直接触ることにはないが、重要な情報なので書いておきます。\r
+ * @private\r
  */\r
-var callbackHash;\r
+var __CallbackHash__ =\r
+/** @lends __CallbackHash__.prototype */\r
+{\r
+       /**\r
+        * コールバックの種類を表す数値。 this + function, this.handleEvent, function only がある。\r
+        * @type {number} \r
+        */\r
+       kind : X_Callback_THIS_FUNC,\r
+       /**\r
+        * コールバック。\r
+        * @type {funciton|undefined} \r
+        */\r
+       func : undefined,\r
+       /**\r
+        * コールバック名。コールバック作成時に関数が無い、関数が入れ替わっていても動作する。\r
+        * @type {string|undefined} \r
+        */\r
+       name : undefined,\r
+       /**\r
+        * コールバックの this コンテキスト。 \r
+        * @type {listener|object|undefined}\r
+        */\r
+       context : undefined,\r
+       /**\r
+        * コールバックに追加する引数。イベントのコールバックでは event オブジェクトのあとに追加されるため supplement[0] が第一引数にならない点に注意。\r
+        * @type {Array|undefined}\r
+        */\r
+       supplement : undefined,\r
+       /**\r
+        * __CallbackHash__ の情報を元に、コールバックを実施するプロキシ。\r
+        * @type {Function}\r
+        */\r
+       proxy : X_Callback_proxyCallback\r
+};\r
 \r
-/*\r
- * \r
- * @typedef {(funciton|{ _ : function, same : function, kill : function, a : (Array|undefined) })}\r
+/**\r
+ * X.Timer と X.EventDispatcher からのコールバックの返り値を定義。\r
+ * @namespace X.Callback\r
  */\r
-var functionHash;\r
-\r
-X.Callback = {\r
-       NONE             : X_Callback_NONE,\r
-       UN_LISTEN        : X_Callback_UN_LISTEN,\r
-       STOP_PROPAGATION : X_Callback_STOP_PROPAGATION,\r
-       STOP_NOW         : X_Callback_STOP_NOW,\r
-       PREVENT_DEFAULT  : X_Callback_PREVENT_DEFAULT,\r
-       MONOPOLY         : X_Callback_MONOPOLY\r
+X[ 'Callback' ] = {\r
+       /**\r
+        * このコールバックでは返り値による操作は無い。\r
+        * @alias X.Callback.NONE\r
+        */\r
+       'NONE'             : X_Callback_NONE,\r
+       /**\r
+        * X.Timer, X.EventDispatcher のコールバックでタイマーやイベントリスナの解除に使用。\r
+        * @alias X.Callback.UN_LISTEN\r
+        */\r
+       'UN_LISTEN'        : X_Callback_UN_LISTEN,\r
+       /**\r
+        * 上位階層へのイベント伝播のキャンセル。DOM イベントのコールバックの戻り値に指定すると e.stopPropagation() が呼ばれる。\r
+        * @alias X.Callback.STOP_PROPAGATION\r
+        */\r
+       'STOP_PROPAGATION' : X_Callback_STOP_PROPAGATION,\r
+       /**\r
+        * 以降のイベントのディスパッチを中断する。STOP_PROPAGATION との違いは、次に控えているコールバックもキャンセルされる点。但し system によって追加されたイベントはキャンセルされない。\r
+        * @alias X.Callback.STOP_NOW\r
+        */\r
+       'STOP_NOW'         : X_Callback_STOP_NOW,\r
+       /**\r
+        * DOM イベントのコールバックの戻り値に指定すると e.preventDefault() が呼ばれる。\r
+        * またフレームワーク内で定義されたデフォルト動作の回避にも使用される。\r
+        * @alias X.Callback.PREVENT_DEFAULT\r
+        */\r
+       'PREVENT_DEFAULT'  : X_Callback_PREVENT_DEFAULT,\r
+       /**\r
+        * X.UI の uinode でポインターイベントの戻り値に指定すると、以降のポインターベントを独占する。\r
+        * @alias X.Callback.CAPTURE_POINTER\r
+        */\r
+       'CAPTURE_POINTER'  : X_Callback_CAPTURE_POINTER,\r
+       /**\r
+        * X.UI の uinode でポインターイベントの戻り値に指定すると、以降のポインターベントを独占を解除する。\r
+        * @alias X.Callback.RELEASE_POINTER\r
+        */\r
+       'RELEASE_POINTER'  : X_Callback_RELEASE_POINTER\r
 };\r
 \r
 // ------------------------------------------------------------------------- //\r
@@ -54,56 +159,64 @@ X.Callback = {
 function X_Callback_create( thisObject, opt_callback, opt_args /* [ listener || ( context + function ) || function ][ args... ] */ ){\r
        var obj = X_Callback_classifyCallbackArgs( thisObject, opt_callback, opt_args ),\r
                l, ret, _obj;\r
-       if( !obj.k ) return obj;\r
+       \r
+       if( !obj.kind ) return obj;\r
+       \r
        if( l = X_Callback_POOL_LIST.length ){\r
-               ret    = X_Callback_POOL_LIST[ l - 1 ]; --X_Callback_POOL_LIST.length; // ret = X_Callback_POOL_LIST.pop();\r
-               _obj   = ret( X_Closure_COMMAND_BACK );\r
-               _obj.k = obj.k;\r
-               _obj.f = obj.f;\r
-               _obj.x = obj.x;\r
-               _obj.s = obj.s;\r
+               ret  = X_Callback_POOL_LIST[ l - 1 ]; --X_Callback_POOL_LIST.length; // ret = X_Callback_POOL_LIST.pop();\r
+               _obj = ret( X_Closure_COMMAND_BACK );\r
+               \r
+               _obj.kind       = obj.kind;\r
+               _obj.name       = obj.name;\r
+               _obj.func       = obj.func;\r
+               _obj.context    = obj.context;\r
+               _obj.supplement = obj.supplement;\r
+               _obj.proxy      = X_Callback_proxyCallback;\r
        } else {\r
-               ret = X_Closure_actualClosure( obj );\r
+               ret             = X_Callback_actualClosure( obj );\r
+               obj.proxy       = X_Callback_proxyCallback;\r
        };\r
        X_Callback_LIVE_LIST[ X_Callback_LIVE_LIST.length ] = ret;\r
        return ret;\r
 };\r
 \r
-function X_Closure_actualClosure( obj ){\r
-       return function(){\r
-               if( arguments[ 0 ] === X_Closure_COMMAND_BACK ) return obj;\r
-               if( arguments[ 0 ] !== X_Closure_COMMAND_DROP ) return X_Callback_proxyCallback( obj, arguments );\r
-       };\r
-};\r
 \r
 function X_Callback_classifyCallbackArgs( arg1, arg2, arg3, alt_context ){\r
        var obj;\r
        \r
-       if( arg1 && X.Type.isFunction( arg2 ) ){\r
-               obj  = { x : arg1, f : arg2, k : X_Callback_THIS_FUNC };\r
+       if( X_Type_isObject( arg1 ) && X_Type_isFunction( arg2 ) ){\r
+               obj  = { context : arg1, func : arg2, kind : X_Callback_THIS_FUNC };\r
        } else\r
-       if( arg1 && X.Type.isFunction( arg1[ 'handleEvent' ] ) ){\r
-               obj  = { x : arg1, k : X_Callback_HANDLEEVENT };\r
-               arg3 = arg2;\r
+       if( X_Type_isObject( arg1 ) ){\r
+               if( arg2 && X_Type_isString( arg2 ) ){\r
+                       obj  = { context : arg1, name : arg2, kind : X_Callback_THIS_FUNCNAME };\r
+               } else {\r
+                       obj  = { context : arg1, kind : X_Callback_HANDLEEVENT };\r
+                       arg3 = arg2;                    \r
+               };\r
        } else\r
-       if( X.Type.isFunction( arg1 ) ){\r
+       if( X_Type_isFunction( arg1 ) ){\r
                arg3 = arg2;\r
                if( alt_context ){\r
-                       obj  = { x : alt_context, f : arg1, k : X_Callback_THIS_FUNC };\r
+                       obj  = { context : alt_context, func : arg1, kind : X_Callback_THIS_FUNC };\r
                } else {\r
-                       obj  = { f : arg1, k : X_Callback_FUNC_ONLY };\r
+                       obj  = { func : arg1, kind : X_Callback_FUNC_ONLY };\r
                };\r
        } else\r
-       if( X.Type.isFunction( arg2 ) ){\r
+       if( X_Type_isFunction( arg2 ) ){\r
                //console.log( 'X_Callback_classifyCallbackArgs : arg1 が ' + arg1 + 'です' ); ie4 で error\r
                if( alt_context ){\r
-                       obj  = { x : alt_context, f : arg2, k : X_Callback_THIS_FUNC };\r
+                       obj  = { context : alt_context, func : arg2, kind : X_Callback_THIS_FUNC };\r
                } else {\r
-                       obj  = { f : arg2, k : X_Callback_FUNC_ONLY };\r
+                       obj  = { func : arg2, kind : X_Callback_FUNC_ONLY };\r
                };\r
        } else\r
+       if( alt_context && X_Type_isString( arg1 ) ){\r
+               arg3 = arg2;\r
+               obj  = { context : alt_context, name : arg1, kind : X_Callback_THIS_FUNCNAME };\r
+       } else\r
        if( alt_context ){\r
-               obj  = { x : alt_context, k : X_Callback_HANDLEEVENT };\r
+               obj  = { context : alt_context, kind : X_Callback_HANDLEEVENT };\r
                arg3 = arg1;\r
        } else {\r
                console.log( '不正 ' + arg1 );\r
@@ -111,18 +224,25 @@ function X_Callback_classifyCallbackArgs( arg1, arg2, arg3, alt_context ){
                return;\r
        };\r
        \r
-       if( X.Type.isArray( arg3 )){\r
-               obj.s = arg3;\r
+       if( X_Type_isArray( arg3 )){\r
+               obj.supplement = arg3;\r
+       };\r
+       return ( obj.context || obj.supplement ) ? obj : arg1;\r
+};\r
+\r
+function X_Callback_actualClosure( obj ){\r
+       return function(){\r
+               if( arguments[ 0 ] === X_Closure_COMMAND_BACK ) return obj;\r
+               if( arguments[ 0 ] !== X_Closure_COMMAND_DROP ) return obj.proxy( obj, arguments );\r
        };\r
-       return ( obj.x || obj.s ) ? obj : arg1;\r
 };\r
 \r
 function X_Callback_proxyCallback( xfunc, _args ){\r
        var args    = _args || [],\r
-               thisObj = xfunc.x,\r
-               func    = xfunc.f,\r
-               supp    = xfunc.s,\r
-               temp, ret;      \r
+               thisObj = xfunc.context,\r
+               func    = xfunc.func,\r
+               supp    = xfunc.supplement,\r
+               temp, ret, funcName;    \r
        \r
        if( supp && supp.length ){\r
                temp = [];\r
@@ -138,23 +258,26 @@ function X_Callback_proxyCallback( xfunc, _args ){
                args = temp;\r
        };\r
        \r
-       switch( xfunc.k ){\r
+       switch( xfunc.kind ){\r
 \r
                case X_Callback_THIS_FUNC :\r
                        return args.length === 0 ? func.call( thisObj ) : func.apply( thisObj, args );\r
-                       \r
+               \r
+               case X_Callback_THIS_FUNCNAME :\r
+                       funcName = xfunc.name;\r
                case X_Callback_HANDLEEVENT :\r
-                       temp = thisObj[ 'handleEvent' ];\r
-                       if( X.Type.isFunction( temp ) ){\r
+                       funcName = funcName || 'handleEvent';\r
+                       temp = thisObj[ funcName ];\r
+                       if( X_Type_isFunction( temp ) ){\r
                                return args.length === 0 ? thisObj[ 'handleEvent' ]() :\r
                                           args.length === 1 ? thisObj[ 'handleEvent' ]( args[ 0 ] ) : temp.apply( thisObj, args );\r
                        };\r
                        break;\r
                        /*\r
-                       if( temp !== func && X.Type.isFunction( temp ) ){\r
+                       if( temp !== func && X_Type_isFunction( temp ) ){\r
                                return args.length === 0 ? thisObj[ 'handleEvent' ]() : temp.apply( thisObj, args );\r
                        } else\r
-                       if( X.Type.isFunction( thisObj ) ){\r
+                       if( X_Type_isFunction( thisObj ) ){\r
                                return args.length === 0 ? thisObj.call( thisObj ) : thisObj.apply( thisObj, args );\r
                        };\r
                        return args.length === 0 ? func.call( thisObj ) : func.apply( thisObj, args );*/\r
@@ -176,23 +299,17 @@ function X_Callback_correct( f ){
                X_Callback_LIVE_LIST.splice( i, 1 );\r
                X_Callback_POOL_LIST[ X_Callback_POOL_LIST.length ] = f;\r
                obj = f( X_Closure_COMMAND_BACK );\r
-               delete obj.k;\r
-               if( obj.f ) delete obj.f;\r
-               if( obj.x ) delete obj.x;\r
-               if( obj.s ) delete obj.s;\r
+               delete obj.kind;\r
+               if( obj.name ) delete obj.name;\r
+               if( obj.func ) delete obj.func;\r
+               if( obj.context ) delete obj.context;\r
+               if( obj.supplement ) delete obj.supplement;\r
+               delete obj.proxy;\r
                return true;\r
        };\r
        return false;\r
 };\r
 \r
-\r
-// sys\r
-X_TEMP.X_Callback_onSystemReady = function( sys ){\r
-       delete X_TEMP.X_Callback_onSystemReady;\r
-       sys.monitor( X_Callback_monitor );\r
-       sys.gc( X_Callback_gc );\r
-};\r
-\r
 function X_Callback_monitor(){\r
        return {\r
                'Callback:Live' : X_Callback_LIVE_LIST.length,\r
@@ -203,7 +320,10 @@ function X_Callback_gc(){
        X_Callback_POOL_LIST.length = 0; // ?\r
 };\r
 \r
-X_TEMP.onSystemReady.push( X_TEMP.X_Callback_onSystemReady );\r
+X_TEMP.onSystemReady.push( function( sys ){\r
+       sys.monitor( X_Callback_monitor );\r
+       sys.gc( X_Callback_gc );\r
+});\r
 \r
 \r
 console.log( 'X.Core.Callback' );\r