OSDN Git Service

Version 0.6.143, fix X.UI.ScrollBox for iOS3.
[pettanr/clientJs.git] / 0.6.x / js / 01_core / 14_XTimer.js
index be20ccc..741d12c 100644 (file)
@@ -1,4 +1,4 @@
-/**\r
+/*\r
  * use X.Callback\r
  */\r
 \r
 // ------------ local variables -------------------------------------------- //\r
 // ------------------------------------------------------------------------- //\r
 \r
-var X_Timer_now = Date.now || function(){ return +new Date; },\r
+var\r
+\r
+       /**\r
+        * 現在時の ms を返します。 new Date().getTime() の値です。\r
+        * @alias X.Timer.now\r
+        * @function\r
+        * @return {number} ミリ秒\r
+        */\r
+       X_Timer_now = Date.now || ( function(){ return +new Date; } ),\r
 \r
        X_Timer_SET_TIMEOUT   = window.setTimeout,\r
        X_Timer_CLEAR_TIMEOUT = window.clearTimeout,\r
-       \r
+\r
+       // http://uupaa.hatenablog.com/entry/2012/02/01/083607\r
+       // Firefox 4 partial (request only), Mobile Firefox5 ready (request only), Firefox 11 ready (cancel impl)       \r
        X_Timer_REQ_ANIME_FRAME =\r
                window.requestAnimationFrame ||\r
                window.webkitRequestAnimationFrame ||\r
@@ -46,6 +56,7 @@ var X_Timer_now = Date.now || function(){ return +new Date; },
                window.oRequestAnimationFrame ||\r
                window.msRequestAnimationFrame ||\r
                false,\r
+\r
        X_Timer_CANCEL_ANIME_FRAME =\r
                window.cancelRequestAnimationFrame ||\r
                window.webkitCancelAnimationFrame ||\r
@@ -64,92 +75,58 @@ var X_Timer_now = Date.now || function(){ return +new Date; },
        X_Timer_busyTimeout    = false,\r
        X_Timer_timeStamp      = 0, // setTimeout に登録した時間\r
        X_Timer_waitTime       = 0,     // 待ち時間\r
+       X_Timer_currentUID     = 0, // 現在発火中の uid\r
        \r
        X_Timer_REQ_FRAME_LIST = [],\r
        X_Timer_requestID      = 0,\r
-       X_Timer_busyOnFrame    = false;\r
+       X_Timer_busyOnFrame    = false,\r
 \r
-// ------------------------------------------------------------------------- //\r
-// --- interface ----------------------------------------------------------- //\r
-// ------------------------------------------------------------------------- //\r
-X.Timer = {\r
-       \r
-       now : X_Timer_now,\r
-       \r
-       add : function( time, opt_count, args1, args2, args3 ){\r
-               var list = X_Timer_TICKET_LIST,\r
-                       hash, obj;\r
-               time = time < X_Timer_INTERVAL_TIME ? 1 : time / X_Timer_INTERVAL_TIME | 0; // 正の数で使える「Math.floor(x)」を「(x | 0)」に;\r
-               \r
-               if( !X.Type.isNumber( opt_count ) ){\r
-                       args3 = args2;\r
-                       args2 = args1;\r
-                       args1 = opt_count;\r
-                       opt_count = 0;\r
-               };\r
-               \r
-               hash = X_Callback_classifyCallbackArgs( args1, args2, args3 );\r
-               if( !hash ) return -1; // dev only\r
-               \r
-               if( !hash.k ) hash = { f : hash };\r
-               hash.time  = time;\r
-               hash.last  = time;\r
-               hash.count = opt_count;\r
-               hash.uid   = ++X_Timer_uid;\r
-               list[ list.length ] = hash;\r
-               \r
-           !X_Timer_busyTimeout && X_Timer_update();\r
-           return X_Timer_uid;\r
-       },\r
-       \r
-       once : function( time, args1, args2, args3 ){\r
-               return X.Timer.add( time, 1, args1, args2, args3 );\r
-       },\r
-       \r
-       remove : function( uid ){\r
-               var list = X_Timer_TICKET_LIST,\r
-                       i    = list.length,\r
-                       l    = i,\r
-                       f, q;\r
-               // fire 中の cancel\r
-               if( X_Timer_busyTimeout ){\r
-                       if( !X_Timer_removal ) X_Timer_removal = {};\r
-                       X_Timer_removal[ uid ] = true;\r
-               } else {\r
-                       for( ; i; ){\r
-                               if( ( q = list[ --i ] ).uid === uid ){\r
-                                       list.splice( i, 1 );\r
-                                       !X_Timer_skipUpdate && ( q.last <= X_Timer_waitTime || l === 1 ) && X_Timer_update();\r
-                                       break;\r
-                               };\r
-                       };                              \r
-               };\r
-       },\r
-       \r
-       requestFrame : X_Timer_REQ_ANIME_FRAME ?\r
+       /**\r
+        * requestAnimationFrame をセットします。\r
+        * @alias X.Timer.requestFrame\r
+        * @function\r
+        * @param {*} args1 コールバックのための最大で 3 つの引数を指定します。参考:__CallbackHash__\r
+        * @param {*} args2\r
+        * @param {*} args3\r
+        * @return {number} タイマーID。1 以上の数値。タイマーの解除に使用。\r
+        */\r
+       X_Timer_requestFrame = X_Timer_REQ_ANIME_FRAME ?\r
                (function( args1, args2, args3 ){\r
                        var i = X_Timer_REQ_FRAME_LIST.length,\r
                                f;\r
                        i === 0 && ( X_Timer_requestID = X_Timer_REQ_ANIME_FRAME( X_Timer_onEnterFrame ) );\r
-                       f = X_Timer_REQ_FRAME_LIST[ i ] = X_Callback_classifyCallbackArgs( args1, args2, args3 );\r
+                       f = X_Callback_classifyCallbackArgs( args1, args2, args3 );\r
+                       if( !f.kind ) f = { func : f };\r
+                       X_Timer_REQ_FRAME_LIST[ i ] = f;\r
                        return f.uid = ++X_Timer_uid;\r
                }) :\r
                (function( args1, args2, args3 ){\r
                        var i = X_Timer_REQ_FRAME_LIST.length,\r
                                f;\r
-                       i === 0 && ( X_Timer_requestID = X.Timer.add( 0, 1, X_Timer_onEnterFrame ) );\r
-                       f = X_Timer_REQ_FRAME_LIST[ i ] = X_Callback_classifyCallbackArgs( args1, args2, args3 );\r
+                       i === 0 && ( X_Timer_requestID = X_Timer_add( 0, 1, X_Timer_onEnterFrame ) );\r
+                       f = X_Callback_classifyCallbackArgs( args1, args2, args3 );\r
+                       if( !f.kind ) f = { func : f };\r
+                       X_Timer_REQ_FRAME_LIST[ i ] = f;\r
                        return f.uid = ++X_Timer_uid;\r
                }),\r
-       \r
-       cancelFrame : X_Timer_CANCEL_ANIME_FRAME ?\r
+\r
+       /**\r
+        * requestAnimationFrame を解除します。登録時に受け取ったタイマーIDを使用します。\r
+        * @alias X.Timer.cancelFrame\r
+        * @function\r
+        * @param {number|string} タイマーID, 数字文字の場合もある!\r
+        * @return {number} 0 が返る\r
+        * @example if( timerID ) timerID = X.Timer.cancelFrame( timerID );\r
+        */\r
+       X_Timer_cancelFrame = X_Timer_CANCEL_ANIME_FRAME ?\r
                (function( uid ){\r
                        var list = X_Timer_REQ_FRAME_LIST,\r
                                l    = list.length,\r
                                i    = l,\r
                                f;\r
-                       // fire 中の cancel\r
+\r
                        if( X_Timer_busyOnFrame ){\r
+                               // fire 中の cancel\r
                                if( !X_Timer_removal ) X_Timer_removal = {};\r
                                X_Timer_removal[ uid ] = true;\r
                        } else {\r
@@ -157,19 +134,22 @@ X.Timer = {
                                        if( ( f = list[ --i ] ).uid < uid ) break;\r
                                        if( f.uid === uid ){\r
                                                list.splice( i, 1 );\r
-                                               l === 1 && X_Timer_CANCEL_ANIME_FRAME( X_Timer_requestID );\r
+                                               // gecko では cancelRequestAnimationFrame が無い場合がある\r
+                                               l === 1 && X_Timer_CANCEL_ANIME_FRAME && X_Timer_CANCEL_ANIME_FRAME( X_Timer_requestID );\r
                                                break;\r
                                        };\r
                                };                              \r
                        };\r
+                       return 0;\r
                }) :\r
                (function( uid ){\r
                        var list = X_Timer_REQ_FRAME_LIST,\r
                                l    = list.length,\r
                                i    = l,\r
                                f;\r
-                       // fire 中の cancel\r
+\r
                        if( X_Timer_busyOnFrame ){\r
+                               // fire 中の cancel\r
                                if( !X_Timer_removal ) X_Timer_removal = {};\r
                                X_Timer_removal[ uid ] = true;\r
                        } else {\r
@@ -177,12 +157,43 @@ X.Timer = {
                                        if( ( f = list[ --i ] ).uid < uid ) break;\r
                                        if( f.uid === uid ){\r
                                                list.splice( i, 1 );\r
-                                               l === 1 && X.Timer.remove( X_Timer_requestID );\r
+                                               l === 1 && X_Timer_remove( X_Timer_requestID );\r
                                                break;\r
                                        };\r
                                };\r
                        };\r
-               })\r
+                       return 0;\r
+               });\r
+\r
+\r
+// ------------------------------------------------------------------------- //\r
+// --- interface ----------------------------------------------------------- //\r
+// ------------------------------------------------------------------------- //\r
+\r
+/**\r
+ * <p>setTimeout をラップします。複数のタイマーを登録しても Web ブラウザにはひとつのタイマーを登録します。\r
+ * <p>参考:<a href="http://d.hatena.ne.jp/amachang/20060924/1159084608" target="_blank">複雑で重くなった JavaScript を超高速化する方法3</a>,\r
+ * <a href="http://d.hatena.ne.jp/sawat/20070329" target="_blank">[JavaScript]setIntervalを実験する</a>\r
+ * <p>指定時間の経過したタイマーは、より過去のものから順番にコールバックされます。\r
+ * <p>setTimeout のコールバックに文字列しか指定できないブラウザがあり対策しています。\r
+ * <p>requestAnimationFrame をラップします。ベンダープレフィックス付の requestAnimationFrame もない場合、setTimeout にフォールバックします。\r
+ * \r
+ * @namespace X.Timer\r
+ * @alias X.Timer\r
+ */ \r
+X[ 'Timer' ] = {\r
+\r
+       'now'          : X_Timer_now,\r
+       \r
+       'add'          : X_Timer_add,\r
+       \r
+       'once'         : X_Timer_once,\r
+       \r
+       'remove'       : X_Timer_remove,\r
+       \r
+       'requestFrame' : X_Timer_requestFrame,\r
+       \r
+       'cancelFrame'  : X_Timer_cancelFrame\r
        \r
 };\r
 \r
@@ -190,7 +201,94 @@ X.Timer = {
 // --- implements ---------------------------------------------------------- //\r
 // ------------------------------------------------------------------------- //\r
 \r
-if( X_UA.IE4 || X_UA.MacIE ){\r
+       /**\r
+        * タイマーをセットします。\r
+        * @alias X.Timer.add\r
+        * @param {number} time ミリ秒\r
+        * @param {number} opt_count 回数。省略可能。指定回数で自動でタイマーを破棄します。0 を指定した場合無限にタイマーが呼ばれます。省略した場合 0 と同じです。\r
+        * @param {*} args1 コールバックのための最大で 3 つの引数を指定します。参考:__CallbackHash__\r
+        * @param {*} args2\r
+        * @param {*} args3\r
+        * @return {number} タイマーID。1 以上の数値。タイマーの解除に使用。\r
+        * @example timerID = X.Timer.add( 1000, 5, thisContext, onTimer );\r
+        */\r
+       function X_Timer_add( time, opt_count, args1, args2, args3 ){\r
+               var list = X_Timer_TICKET_LIST,\r
+                       hash, obj;\r
+               time = time < X_Timer_INTERVAL_TIME ? 1 : time / X_Timer_INTERVAL_TIME | 0; // 正の数で使える「Math.floor(x)」を「(x | 0)」に;\r
+               \r
+               if( !X_Type_isNumber( opt_count ) ){\r
+                       args3 = args2;\r
+                       args2 = args1;\r
+                       args1 = opt_count;\r
+                       opt_count = 0;\r
+               };\r
+               \r
+               hash = X_Callback_classifyCallbackArgs( args1, args2, args3 );\r
+               if( !hash ) return -1; // dev only\r
+               \r
+               if( !hash.kind ) hash = { func : hash };\r
+               hash.time  = time;\r
+               hash.last  = time;\r
+               hash.count = opt_count;\r
+               hash.uid   = ++X_Timer_uid;\r
+               list[ list.length ] = hash;\r
+               \r
+           !X_Timer_busyTimeout && X_Timer_update();\r
+           return X_Timer_uid;\r
+       };\r
+       \r
+       /**\r
+        * 1 回呼ばれたら解除されるタイマーをセットします。\r
+        * @alias X.Timer.once\r
+        * @param {number} time ミリ秒\r
+        * @param {*} args1 コールバックのための最大で 3 つの引数を指定します。参考:__CallbackHash__\r
+        * @param {*} args2\r
+        * @param {*} args3\r
+        * @return {number} タイマーID。1 以上の数値。タイマーの解除に使用。\r
+        */\r
+       function X_Timer_once( time, args1, args2, args3 ){\r
+               return X_Timer_add( time, 1, args1, args2, args3 );\r
+       };\r
+       \r
+       /**\r
+        * タイマーを解除します。登録時に受け取ったタイマーIDを使用します。\r
+        * @alias X.Timer.remove\r
+        * @param {number} タイマーID\r
+        * @return {number} 0 が返る\r
+        * @example if( timerID ) timerID = X.Timer.remove( timerID );\r
+        */\r
+       function X_Timer_remove( uid ){\r
+               var list = X_Timer_TICKET_LIST,\r
+                       i    = list.length,\r
+                       l    = i,\r
+                       f, q, eventDispatcher, lazy, listeners;\r
+               \r
+               if( X_Timer_busyTimeout ){\r
+                       // fire 中の cancel\r
+                       if( !X_Timer_removal ) X_Timer_removal = {};\r
+                       X_Timer_removal[ uid ] = true;\r
+               } else {\r
+                       for( ; i; ){\r
+                               if( ( q = list[ --i ] ).uid === uid ){\r
+                                       list.splice( i, 1 );\r
+                                       \r
+                                       /*\r
+                                        * lazyDispatch 中の EventDispatcher の有無を調べる\r
+                                        */\r
+                                       if( X_EventDispatcher_LAZY_TIMERS[ uid ] ){\r
+                                               delete X_EventDispatcher_LAZY_TIMERS[ uid ];\r
+                                       };\r
+                                       \r
+                                       !X_Timer_skipUpdate && ( q.last <= X_Timer_waitTime || l === 1 ) && X_Timer_update();\r
+                                       break;\r
+                               };\r
+                       };                              \r
+               };\r
+               return 0;\r
+       };\r
+\r
+if( X_UA[ 'IE4' ] || X_UA[ 'MacIE' ] ){\r
        X.Timer[ '_' ] = X_Timer_onTimeout;\r
        X_Timer_onTimeout = 'X.Timer._()';\r
 };\r
@@ -201,7 +299,7 @@ function X_Timer_onTimeout(){
                list  = X_Timer_TICKET_LIST,\r
                i     = 0,\r
                l     = list.length,\r
-               limit = X_Timer_now() + X_Timer_INTERVAL_TIME / 2,\r
+               limit = now + X_Timer_INTERVAL_TIME / 2,\r
                heavy,\r
                q, f, c, r, uid;\r
        \r
@@ -224,11 +322,12 @@ function X_Timer_onTimeout(){
                };\r
                c = q.count;\r
                \r
-               if( q.k ){\r
-                       //q.a = [];\r
+               X_Timer_currentUID = q.uid;\r
+               \r
+               if( q.kind ){\r
                        r = X_Callback_proxyCallback( q, [] );\r
                } else {\r
-                       r = q.f();\r
+                       r = q.func();\r
                };\r
                \r
                //console.log( 'fire....' );\r
@@ -248,13 +347,14 @@ function X_Timer_onTimeout(){
                if( 1 < c ) --q.count;\r
                q.last = q.time;\r
     };\r
-    X_Timer_timerId     = 0;\r
+    X_Timer_timerId     = X_Timer_currentUID = 0;\r
     X_Timer_busyTimeout = false;\r
     \r
     if( X_Timer_removal ){\r
        X_Timer_skipUpdate = true;\r
        for( uid in X_Timer_removal ){\r
-               X.Timer.remove( uid );\r
+               //if( X_EMPTY_OBJECT[ uid ] ) continue;\r
+               X_Timer_remove( uid );\r
        };\r
        X_Timer_skipUpdate = false;\r
        X_Timer_removal = null;\r
@@ -295,18 +395,19 @@ function X_Timer_compareQueue( a, b ){
 \r
 // http://havelog.ayumusato.com/develop/javascript/e528-ios6_scrolling_timer_notcall.html\r
 // iOS6 スクロール中のタイマー発火絡みのバグ備忘\r
-if( X_UA.iOS ){\r
+if( X_UA[ 'iOS' ] ){\r
        window.addEventListener( 'scroll', function(){\r
                var last, now;\r
                if( X_Timer_timerId ){\r
                        X_Timer_CLEAR_TIMEOUT( X_Timer_timerId );\r
-                       now  = X_Timer_now();\r
-                       last = X_Timer_timeStamp + X_Timer_INTERVAL_TIME * X_Timer_waitTime - now;\r
-                       X_Timer_timerId = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, 0 < last ? last : 0 );\r
+                       now               = X_Timer_now();\r
+                       last              = X_Timer_timeStamp + X_Timer_INTERVAL_TIME * X_Timer_waitTime - now;\r
+                       X_Timer_timerId   = X_Timer_SET_TIMEOUT( X_Timer_onTimeout, 0 < last ? last : 0 );\r
                        // 更新\r
                        X_Timer_timeStamp = now;\r
                        X_Timer_waitTime  = last / X_Timer_INTERVAL_TIME | 0;\r
                };\r
+               X_ViewPort[ 'getScrollPosition' ](); // X_DomEvent のための X_ViewPort_scrollX & Y の更新、\r
        });\r
 };\r
 \r
@@ -325,22 +426,23 @@ function X_Timer_onEnterFrame( time ){
        \r
        if( X_Timer_removal && X_Timer_removal[ q.uid ] ) continue;\r
        \r
-               if( q.k ){\r
+               if( q.kind ){\r
                        X_Callback_proxyCallback( q, args || ( args = [ time ] ) );\r
                } else {\r
-                       q( time );\r
+                       q.func( time );\r
                };\r
     };\r
 \r
     list.splice( 0, l );\r
     if( list.length ){\r
-       X_Timer_requestID = X_Timer_REQ_ANIME_FRAME ? X_Timer_REQ_ANIME_FRAME( X_Timer_onEnterFrame ) : X.Timer.add( 0, 1, X_Timer_onEnterFrame );\r
+       X_Timer_requestID = X_Timer_REQ_ANIME_FRAME ? X_Timer_REQ_ANIME_FRAME( X_Timer_onEnterFrame ) : X_Timer_add( 0, 1, X_Timer_onEnterFrame );\r
     };\r
     \r
     X_Timer_busyOnFrame = false;\r
     if( X_Timer_removal ){\r
        for( uid in X_Timer_removal ){\r
-               X.Timer.cancelFrame( X_Timer_removal[ uid ] );\r
+               //if( X_EMPTY_OBJECT[ uid ] ) continue;\r
+               X_Timer_cancelFrame( X_Timer_removal[ uid ] );\r
        };\r
        X_Timer_removal = null;\r
     };\r