2 // ------------------------------------------------------------------------- //
\r
3 // ------------ local variables -------------------------------------------- //
\r
4 // ------------------------------------------------------------------------- //
\r
7 X_Callback_LIVE_LIST = [],
\r
9 X_Callback_POOL_LIST = [],
\r
11 X_Closure_COMMAND_BACK = X_Callback_LIVE_LIST,
\r
13 X_Closure_COMMAND_DROP = X_Callback_POOL_LIST,
\r
16 X_Callback_THIS_FUNC = 1,
\r
18 X_Callback_HANDLEEVENT = 2,
\r
20 X_Callback_FUNC_ONLY = 3,
\r
22 X_Callback_THIS_FUNCNAME = 4,
\r
25 X_Callback_NONE = 0,
\r
27 X_Callback_UN_LISTEN = 1,
\r
29 X_Callback_STOP_PROPAGATION = 2,
\r
31 X_Callback_STOP_NOW = 4 | 2, // 同一階層のリスナーのキャンセル(上位へもキャンセル)
\r
33 X_Callback_PREVENT_DEFAULT = 8, // 結果動作のキャンセル,
\r
35 X_Callback_CAPTURE_POINTER = 16,
\r
37 X_Callback_RELEASE_POINTER = 32,
\r
40 X_Callback_SYS_CANCEL = 64 | 4 | 2;
\r
45 * handleEvent という関数のメンバーを持つオブジェクト
\r
46 * @typedef {{ handleEvent : function }}
\r
51 * <p>クロージャに関するポリシーと再利用可能クロージャについて次の記事をご覧ください。
\r
52 * <a href="http://outcloud.blogspot.jp/2015/05/reusable-closure.html" target="_blank">再利用できるクロージャを使ったWebアプリケーション開発</a>
\r
54 * <h5>再利用可能クロージャの作成</h5>
\r
55 * X_Callback_create() で再利用可能なクロージャの作成。次のパターンで呼び出します。<br>
\r
56 * 最大で三つの引数を並べる一連のパターンは、 EventDispatcher.listen unlisten, listening や X.Timer.add, once でも使われますので、ここでよく目を通しておきます。
\r
59 * <tr><th>this コンテキスト+関数<td>X_Callback_create( thisObject, func )<td>func.call( thisObject );
\r
60 * <tr><th>this コンテキスト+関数+追加引数<td>X_Callback_create( thisObject, func, [ arg1, ...args ] )<td>func.apply( thisObject, [ arg1, ...args ] );
\r
61 * <tr><th>listener オブジェクト<td>X_Callback_create( listener )<td>listener.handleEvent(); コールバックに関数でなく handleEvent 関数をメンバに持つオブジェクトを渡すのは NN4 からある javascript のお約束です。
\r
62 * <tr><th>listener オブジェクト+追加引数<td>X_Callback_create( listener, [ arg1, ...args ] )<td>listener.handleEvent.apply( listener, [ arg1, ...args ] );
\r
63 * <tr><th>関数<td>X_Callback_create( func )<td>特別な操作は不要なので再利用可能クロージャは作られません。func をそのまま利用します。
\r
64 * <tr><th>関数+引数<td>X_Callback_create( func, [ arg1, ...args ] )<td>func.apply( ?, [ arg1, ...args ] );
\r
67 * <h5>再利用可能クロージャの破棄と再利用</h5>
\r
68 * X_Callback_correct() によってクロージャは回収され再利用に備えます。<br>
\r
69 * 実は、クロージャが束縛するのは、this コンテキストやコールバック関数といった、<strong>そのもの</strong>ではなく、それらを一定のルールで格納したハッシュです。<br>
\r
70 * このハッシュはクロージャに与えた後も、適宜に取得が可能です。このハッシュのメンバーを書き換えることで、クロージャの this コンテキストやコールバック関数を書き換えています。
\r
72 * @class __CallbackHash__
\r
73 * @classdesc コールバック関数に this コンテキストや、追加の引数を設定するための情報を収めたハッシュです。<br>
\r
74 * フレームワークユーザは直接触ることにはないが、重要な情報なので書いておきます。
\r
77 var __CallbackHash__ =
\r
78 /** @lends __CallbackHash__.prototype */
\r
81 * コールバックの種類を表す数値。 this + function, this.handleEvent, function only がある。
\r
84 kind : X_Callback_THIS_FUNC,
\r
87 * @type {funciton|undefined}
\r
91 * コールバック名。コールバック作成時に関数が無い、関数が入れ替わっていても動作する。
\r
92 * @type {string|undefined}
\r
96 * コールバックの this コンテキスト。
\r
97 * @type {listener|object|undefined}
\r
99 context : undefined,
\r
101 * コールバックに追加する引数。イベントのコールバックでは event オブジェクトのあとに追加されるため supplement[0] が第一引数にならない点に注意。
\r
102 * @type {Array|undefined}
\r
104 supplement : undefined,
\r
106 * __CallbackHash__ の情報を元に、コールバックを実施するプロキシ。
\r
109 proxy : X_Callback_proxyCallback
\r
113 * X.Timer と X.EventDispatcher からのコールバックの返り値を定義。
\r
114 * @namespace X.Callback
\r
116 X[ 'Callback' ] = {
\r
118 * このコールバックでは返り値による操作は無い。
\r
119 * @alias X.Callback.NONE
\r
121 'NONE' : X_Callback_NONE,
\r
123 * X.Timer, X.EventDispatcher のコールバックでタイマーやイベントリスナの解除に使用。
\r
124 * @alias X.Callback.UN_LISTEN
\r
126 'UN_LISTEN' : X_Callback_UN_LISTEN,
\r
128 * 上位階層へのイベント伝播のキャンセル。DOM イベントのコールバックの戻り値に指定すると e.stopPropagation() が呼ばれる。
\r
129 * @alias X.Callback.STOP_PROPAGATION
\r
131 'STOP_PROPAGATION' : X_Callback_STOP_PROPAGATION,
\r
133 * 以降のイベントのディスパッチを中断する。STOP_PROPAGATION との違いは、次に控えているコールバックもキャンセルされる点。但し system によって追加されたイベントはキャンセルされない。
\r
134 * @alias X.Callback.STOP_NOW
\r
136 'STOP_NOW' : X_Callback_STOP_NOW,
\r
138 * DOM イベントのコールバックの戻り値に指定すると e.preventDefault() が呼ばれる。
\r
139 * またフレームワーク内で定義されたデフォルト動作の回避にも使用される。
\r
140 * @alias X.Callback.PREVENT_DEFAULT
\r
142 'PREVENT_DEFAULT' : X_Callback_PREVENT_DEFAULT,
\r
144 * X.UI の uinode でポインターイベントの戻り値に指定すると、以降のポインターベントを独占する。
\r
145 * @alias X.Callback.CAPTURE_POINTER
\r
147 'CAPTURE_POINTER' : X_Callback_CAPTURE_POINTER,
\r
149 * X.UI の uinode でポインターイベントの戻り値に指定すると、以降のポインターベントを独占を解除する。
\r
150 * @alias X.Callback.RELEASE_POINTER
\r
152 'RELEASE_POINTER' : X_Callback_RELEASE_POINTER
\r
155 // ------------------------------------------------------------------------- //
\r
156 // --- implements ---------------------------------------------------------- //
\r
157 // ------------------------------------------------------------------------- //
\r
159 function X_Callback_create( thisObject, opt_callback, opt_args /* [ listener || ( context + function ) || function ][ args... ] */ ){
\r
160 var obj = X_Callback_classifyCallbackArgs( thisObject, opt_callback, opt_args ),
\r
163 if( !obj.kind ) return obj;
\r
165 if( l = X_Callback_POOL_LIST.length ){
\r
166 ret = X_Callback_POOL_LIST[ l - 1 ]; --X_Callback_POOL_LIST.length; // ret = X_Callback_POOL_LIST.pop();
\r
167 _obj = ret( X_Closure_COMMAND_BACK );
\r
169 _obj.kind = obj.kind;
\r
170 _obj.name = obj.name;
\r
171 _obj.func = obj.func;
\r
172 _obj.context = obj.context;
\r
173 _obj.supplement = obj.supplement;
\r
174 _obj.proxy = X_Callback_proxyCallback;
\r
176 ret = X_Callback_actualClosure( obj );
\r
177 obj.proxy = X_Callback_proxyCallback;
\r
179 X_Callback_LIVE_LIST[ X_Callback_LIVE_LIST.length ] = ret;
\r
184 function X_Callback_classifyCallbackArgs( arg1, arg2, arg3, alt_context ){
\r
187 if( X_Type_isObject( arg1 ) && X_Type_isFunction( arg2 ) ){
\r
188 obj = { context : arg1, func : arg2, kind : X_Callback_THIS_FUNC };
\r
190 if( X_Type_isObject( arg1 ) ){
\r
191 if( arg2 && X_Type_isString( arg2 ) ){
\r
192 obj = { context : arg1, name : arg2, kind : X_Callback_THIS_FUNCNAME };
\r
194 obj = { context : arg1, kind : X_Callback_HANDLEEVENT };
\r
198 if( X_Type_isFunction( arg1 ) ){
\r
201 obj = { context : alt_context, func : arg1, kind : X_Callback_THIS_FUNC };
\r
203 obj = { func : arg1, kind : X_Callback_FUNC_ONLY };
\r
206 if( X_Type_isFunction( arg2 ) ){
\r
207 //console.log( 'X_Callback_classifyCallbackArgs : arg1 が ' + arg1 + 'です' ); ie4 で error
\r
209 obj = { context : alt_context, func : arg2, kind : X_Callback_THIS_FUNC };
\r
211 obj = { func : arg2, kind : X_Callback_FUNC_ONLY };
\r
214 if( alt_context && X_Type_isString( arg1 ) ){
\r
216 obj = { context : alt_context, name : arg1, kind : X_Callback_THIS_FUNCNAME };
\r
219 obj = { context : alt_context, kind : X_Callback_HANDLEEVENT };
\r
222 console.log( '不正 ' + arg1 );
\r
223 console.dir( arg1 );
\r
227 if( X_Type_isArray( arg3 )){
\r
228 obj.supplement = arg3;
\r
230 return ( obj.context || obj.supplement ) ? obj : arg1;
\r
233 function X_Callback_actualClosure( obj ){
\r
235 if( arguments[ 0 ] === X_Closure_COMMAND_BACK ) return obj;
\r
236 if( arguments[ 0 ] !== X_Closure_COMMAND_DROP ) return obj.proxy( obj, arguments );
\r
240 function X_Callback_proxyCallback( xfunc, _args ){
\r
241 var args = _args || [],
\r
242 thisObj = xfunc.context,
\r
244 supp = xfunc.supplement,
\r
245 temp, ret, funcName;
\r
247 if( supp && supp.length ){
\r
251 args.length === 1 ?
\r
252 ( temp[ 0 ] = args[ 0 ] ) :
\r
253 temp.push.apply( temp, args )
\r
255 supp.length === 1 ?
\r
256 ( temp[ temp.length ] = supp[ 0 ] ) :
\r
257 temp.push.apply( temp, supp );
\r
261 switch( xfunc.kind ){
\r
263 case X_Callback_THIS_FUNC :
\r
264 return args.length === 0 ? func.call( thisObj ) : func.apply( thisObj, args );
\r
266 case X_Callback_THIS_FUNCNAME :
\r
267 funcName = xfunc.name;
\r
268 case X_Callback_HANDLEEVENT :
\r
269 funcName = funcName || 'handleEvent';
\r
270 temp = thisObj[ funcName ];
\r
271 if( X_Type_isFunction( temp ) ){
\r
272 return args.length === 0 ? thisObj[ 'handleEvent' ]() :
\r
273 args.length === 1 ? thisObj[ 'handleEvent' ]( args[ 0 ] ) : temp.apply( thisObj, args );
\r
277 if( temp !== func && X_Type_isFunction( temp ) ){
\r
278 return args.length === 0 ? thisObj[ 'handleEvent' ]() : temp.apply( thisObj, args );
\r
280 if( X_Type_isFunction( thisObj ) ){
\r
281 return args.length === 0 ? thisObj.call( thisObj ) : thisObj.apply( thisObj, args );
\r
283 return args.length === 0 ? func.call( thisObj ) : func.apply( thisObj, args );*/
\r
285 case X_Callback_FUNC_ONLY :
\r
286 return args.length === 0 ?
\r
288 args.length === 1 ?
\r
289 func( args[ 0 ] ) :
\r
290 func.apply( null, args );
\r
292 return X_Callback_NONE;
\r
295 function X_Callback_correct( f ){
\r
296 var i = X_Callback_LIVE_LIST.indexOf( f ),
\r
299 X_Callback_LIVE_LIST.splice( i, 1 );
\r
300 X_Callback_POOL_LIST[ X_Callback_POOL_LIST.length ] = f;
\r
301 obj = f( X_Closure_COMMAND_BACK );
\r
303 if( obj.name ) delete obj.name;
\r
304 if( obj.func ) delete obj.func;
\r
305 if( obj.context ) delete obj.context;
\r
306 if( obj.supplement ) delete obj.supplement;
\r
313 function X_Callback_monitor(){
\r
315 'Callback:Live' : X_Callback_LIVE_LIST.length,
\r
316 'Callback:Pool' : X_Callback_POOL_LIST.length
\r
319 function X_Callback_gc(){
\r
320 X_Callback_POOL_LIST.length = 0; // ?
\r
323 X_TEMP.onSystemReady.push( function( sys ){
\r
324 sys.monitor( X_Callback_monitor );
\r
325 sys.gc( X_Callback_gc );
\r
329 console.log( 'X.Core.Callback' );
\r