OSDN Git Service

fix X.UA & X.Audio, add X.KB.
authoritozyun <itozyun@user.sourceforge.jp>
Mon, 17 Aug 2015 08:53:10 +0000 (17:53 +0900)
committeritozyun <itozyun@user.sourceforge.jp>
Mon, 17 Aug 2015 08:53:10 +0000 (17:53 +0900)
16 files changed:
0.6.x/js/01_core/02_XUA.js
0.6.x/js/01_core/07_XNumber.js [new file with mode: 0644]
0.6.x/js/01_core/11_XCallback.js [moved from 0.6.x/js/01_core/11_Callback.js with 63% similarity]
0.6.x/js/01_core/12_XClosure.js [moved from 0.6.x/js/01_core/12_Closure.js with 65% similarity]
0.6.x/js/01_core/21_XViewPort.js
0.6.x/js/02_dom/00_XDoc.js
0.6.x/js/02_dom/03_XDomEvent.js
0.6.x/js/02_dom/20_XNode.js
0.6.x/js/06_net/01_XNetXHR.js
0.6.x/js/06_net/04_XNetImage.js
0.6.x/js/07_audio/00_XAudio.js
0.6.x/js/07_audio/01_XWebAudio.js
0.6.x/js/07_audio/02_XHTMLAudio.js
0.6.x/js/07_audio/10_XAudioSprite.js
0.6.x/js/11_hid/01_KB.js [new file with mode: 0644]
0.6.x/js/import.js

index 3ce9532..94799e4 100644 (file)
@@ -193,7 +193,23 @@ var X_UA = X[ 'UA' ] = {},
                 */\r
                X_UA[ 'Linux' ]  = true;\r
                \r
-               if( ( i = dua.indexOf( 'Android' ) ) !== -1 ){\r
+               if( dua.indexOf( 'Android ' ) !== -1 ){\r
+                       v = dua.split( 'Android ' )[ 1 ].split( '.' );\r
+                       /**\r
+                        * @alias X.UA.AndroidMajor\r
+                        * @type {number}\r
+                        */\r
+                       X_UA[ 'AndroidMajor' ] = parseFloat( v[ 0 ] ) || 0;\r
+                       /**\r
+                        * @alias X.UA.AndroidMinor\r
+                        * @type {number}\r
+                        */\r
+                       X_UA[ 'AndroidMinor' ]  = parseFloat( v[ 1 ] ) || 0;\r
+                       /**\r
+                        * @alias X.UA.AndroidPatch\r
+                        * @type {number}\r
+                        */\r
+                       X_UA[ 'AndroidPatch' ]  = parseFloat( v[ 2 ] ) || 0;\r
                        /**\r
                         * Firefox で Version が取れない!\r
                         * http://bizmakoto.jp/bizid/articles/1207/31/news004.html\r
@@ -205,7 +221,7 @@ var X_UA = X[ 'UA' ] = {},
                         * @alias X.UA.Android\r
                         * @type {number}\r
                         */\r
-                       X_UA[ 'Android' ]  = parseFloat( dua.substr( i + 8 ) ) || 0.1;\r
+                       X_UA[ 'Android' ]  = X_UA[ 'AndroidMajor' ] + X_UA[ 'AndroidMinor' ] / 10;\r
                        console.log( '>> Android : ' + X_UA[ 'Android' ]  );\r
                };\r
        };\r
@@ -486,57 +502,42 @@ var X_UA = X[ 'UA' ] = {},
                console.log( '>> Gecko : ' + X_UA[ 'Gecko' ] );\r
        };\r
        \r
-       // TODO Blink\r
-       if( window.chrome ){\r
-               /**\r
-                * @alias X.UA.Blink\r
-                * @type {number}\r
-                */\r
-               X_UA[ 'Blink' ] = tv;\r
-               console.log( '>>Blink : ' + X_UA[ 'Blink' ] );\r
-               \r
-       } else\r
-       if( dav.indexOf( 'Konqueror' ) !== -1 ){\r
-               /**\r
-                * @alias X.UA.Khtml\r
-                * @type {number}\r
-                */\r
-               X_UA[ 'Khtml' ] = tv;\r
-               console.log( '>>Khtml : ' + X_UA[ 'Khtml' ] );\r
-               \r
-       } else\r
-       if( ( i = dua.indexOf( 'Android ' ) ) !== -1 ){\r
+       if( dua.indexOf( 'Linux; U; Android ' ) !== -1 || dua.indexOf( 'Linux; Android ' ) !== -1 ){\r
                /**\r
                 * Android 標準ブラウザ\r
                 * @alias X.UA.AndroidBrowser\r
                 * @type {number}\r
                 */\r
-               X_UA[ 'AndroidBrowser' ] = i = parseFloat( dua.substr( i + 8 ) ) || 0.1;\r
+               X_UA[ 'AndroidBrowser' ] = X_UA[ 'Android' ];\r
+               \r
+               v = X_UA[ 'AndroidMajor' ];\r
+               \r
                /**\r
                 * @alias X.UA.AndroidBrowser1\r
                 * @type {boolean}\r
                 */\r
-               X_UA[ 'AndroidBrowser1' ] = 1 <= i && i < 2;\r
+               X_UA[ 'AndroidBrowser1' ] = v === 1;\r
                /**\r
                 * @alias X.UA.AndroidBrowser2\r
                 * @type {boolean}\r
                 */\r
-               X_UA[ 'AndroidBrowser2' ] = 2 <= i && i < 3;\r
+               X_UA[ 'AndroidBrowser2' ] = v === 2;\r
                /**\r
                 * @alias X.UA.AndroidBrowser3\r
                 * @type {boolean}\r
                 */\r
-               X_UA[ 'AndroidBrowser3' ] = 3 <= i && i < 4;\r
+               X_UA[ 'AndroidBrowser3' ] = v === 3;\r
                /**\r
                 * @alias X.UA.AndroidBrowser4\r
                 * @type {boolean}\r
                 */\r
-               X_UA[ 'AndroidBrowser4' ] = 4 <= i && i < 5;\r
+               X_UA[ 'AndroidBrowser4' ] = v === 4;\r
                /**\r
                 * @alias X.UA.AndroidBrowser5\r
                 * @type {boolean}\r
                 */\r
-               X_UA[ 'AndroidBrowser5' ] = 5 <= i && i < 6;\r
+               X_UA[ 'AndroidBrowser5' ] = v === 5;\r
+               \r
                console.log( '>> AndroidBrowser : ' + X_UA[ 'Android' ] );\r
                \r
                i = parseFloat(dua.split('WebKit\/')[1]);\r
@@ -547,7 +548,39 @@ var X_UA = X[ 'UA' ] = {},
                X_UA[ 'AndroidWebkit' ] = i;\r
                //alert( 'AudioSprite調査:Android標準ブラウザ Webkit Version ' + i );\r
                \r
+               if( window.chrome ){\r
+                       //X_UA[ 'Blink' ] = X_UA[ 'AndroidChromeBrowser' ] = tv;\r
+               } else\r
+               if( v = parseFloat(dua.split('Chrome\/')[1]) ){\r
+                       X_UA[ 'Chrome' ] = X_UA[ 'AndroidChromeBrowser' ] = v;\r
+               };\r
+               \r
+               //if( window[ 'webkitRequestFileSystem' ] ) alert( 'requestFileSystem' );\r
+               \r
+               //alert( 'html.style.WebkitAppearance:' + ( document.documentElement.style[ 'WebkitAppearance' ] === undefined ) + ' win.chrome:' + !!( window.chrome ) );\r
+\r
+       } else\r
+       \r
+       // TODO Blink\r
+       if( window.chrome ){ // Android3.1 の標準ブラウザで .chrome がいた、、、\r
+               /**\r
+                * @alias X.UA.Blink\r
+                * @type {number}\r
+                */\r
+               X_UA[ 'Blink' ] = tv;\r
+               console.log( '>>Blink : ' + X_UA[ 'Blink' ] );\r
+               \r
+       } else\r
+       if( dav.indexOf( 'Konqueror' ) !== -1 ){\r
+               /**\r
+                * @alias X.UA.Khtml\r
+                * @type {number}\r
+                */\r
+               X_UA[ 'Khtml' ] = tv;\r
+               console.log( '>>Khtml : ' + X_UA[ 'Khtml' ] );\r
+               \r
        } else\r
+       \r
        if( i = parseFloat(dua.split('WebKit\/')[1]) ){\r
                /**\r
                 * @alias X.UA.WebKit\r
diff --git a/0.6.x/js/01_core/07_XNumber.js b/0.6.x/js/01_core/07_XNumber.js
new file mode 100644 (file)
index 0000000..0d59f64
--- /dev/null
@@ -0,0 +1,37 @@
+/**\r
+ * Number に関する関数を集めたものです。\r
+ * @namespace X.Number\r
+ * @alias X.Number\r
+ */\r
+X[ 'Number' ] = {\r
+       'conpareVersion'      : X_Number_conpareVersion\r
+};\r
+\r
+/**\r
+ * X.X.X という形式のバージョン文字列同志の比較  \r
+ * -1 v1 < v2\r
+ *  0 v1 = v2\r
+ *  1 v1 > v2\r
+ * @alias X.Number.copy\r
+ * @param {Number} ary コピー元のオブジェクトです。\r
+ * @return {Number}\r
+ */\r
+ function X_Number_conpareVersion( v1, v2 ){\r
+       var i = 0,\r
+               l, n1, n2;\r
+       \r
+       v1 = v1.split( '.' );\r
+       v2 = v2.split( '.' );   \r
+       \r
+       l = Math.min( v1.length, v2.length );\r
+\r
+       for( ; i < l; ++i ){\r
+               n1 = parseFloat( v1[ i ] );\r
+               n2 = parseFloat( v2[ i ] );\r
+               if( n1 !== n2 ){\r
+                       return n1 > n2 ? 1 : -1;\r
+               };\r
+       };\r
+       if( v1.length === v2.length ) return 0;\r
+       return v1.length > v2.length ? 1 : -1;\r
+};\r
similarity index 63%
rename from 0.6.x/js/01_core/11_Callback.js
rename to 0.6.x/js/01_core/11_XCallback.js
index a7d69fb..2eff2e9 100644 (file)
@@ -3,23 +3,14 @@
 // ------------ local variables -------------------------------------------- //\r
 // ------------------------------------------------------------------------- //\r
 \r
-var /** @const */\r
-       X_Callback_NONE             =  0,\r
-       /** @const */\r
-       X_Callback_UN_LISTEN        =  1,\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
-       /** @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
+var X_CALLBACK_NONE             =  0,\r
+       X_CALLBACK_UN_LISTEN        =  1,\r
+       X_CALLBACK_STOP_PROPAGATION =  2,\r
+       X_CALLBACK_STOP_NOW         =  4 | 2,\r
+       X_CALLBACK_PREVENT_DEFAULT  =  8,\r
+       X_CALLBACK_CAPTURE_POINTER  = 16,\r
+       X_CALLBACK_RELEASE_POINTER  = 32,\r
+       X_CALLBACK_SYS_CANCEL       = 64 | 4 | 2;\r
 \r
 /**\r
  * X.Timer と X.EventDispatcher からのコールバックの返り値を定義。\r
@@ -30,45 +21,39 @@ X[ 'Callback' ] = {
         * このコールバックでは返り値による操作は無い。\r
         * @alias X.Callback.NONE\r
         */\r
-       'NONE'             : X_Callback_NONE,\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
+       '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
+       '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
+       '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
+       '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
+       '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
+       'RELEASE_POINTER'  : X_CALLBACK_RELEASE_POINTER\r
 };\r
 \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
 \r
similarity index 65%
rename from 0.6.x/js/01_core/12_Closure.js
rename to 0.6.x/js/01_core/12_XClosure.js
index 5d90451..82ff4a9 100644 (file)
@@ -1,31 +1,27 @@
 var \r
-       X_Callback_LIVE_LIST        = [],\r
+       X_CLOSURE_LIVE_LIST     = [],\r
 \r
-       X_Callback_POOL_LIST        = [],\r
+       X_CLOSURE_POOL_LIST     = [],\r
 \r
-       X_Closure_COMMAND_BACK      = X_Callback_LIVE_LIST,\r
+       X_Closure_COMMAND_BACK  = X_CLOSURE_LIVE_LIST,\r
 \r
-       X_Closure_COMMAND_DROP      = X_Callback_POOL_LIST,\r
+       X_Closure_COMMAND_DROP  = X_CLOSURE_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
+       X_CLOSURE_THIS_FUNC     = 1,\r
+       X_CLOSURE_HANDLEEVENT   = 2,\r
+       X_CLOSURE_FUNC_ONLY     = 3,\r
+       X_CLOSURE_THIS_FUNCNAME = 4;\r
 \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
+ * X_Closure_create() で再利用可能なクロージャの作成。次のパターンで呼び出します。<br>\r
  * 最大で三つの引数を並べる一連のパターンは、 EventDispatcher.listen unlisten, listening や X.Timer.add, once でも使われますので、ここでよく目を通しておきます。\r
  * \r
  * <h5>再利用可能クロージャの破棄と再利用</h5>\r
- * X_Callback_correct() によってクロージャは回収され再利用に備えます。<br>\r
+ * X_Closure_correct() によってクロージャは回収され再利用に備えます。<br>\r
  * 実は、クロージャが束縛するのは、this コンテキストやコールバック関数といった、<strong>そのもの</strong>ではなく、それらを一定のルールで格納したハッシュです。<br>\r
  * このハッシュはクロージャに与えた後も、適宜に取得が可能です。このハッシュのメンバーを書き換えることで、クロージャの this コンテキストやコールバック関数を書き換えています。\r
  * \r
@@ -41,7 +37,7 @@ var __CallbackHash__ =
         * コールバックの種類を表す数値。 this + function, this.handleEvent, function only がある。\r
         * @type {number} \r
         */\r
-       kind : X_Callback_THIS_FUNC,\r
+       kind : X_CLOSURE_THIS_FUNC,\r
        /**\r
         * コールバック。\r
         * @type {funciton|undefined} \r
@@ -66,21 +62,21 @@ var __CallbackHash__ =
         * __CallbackHash__ の情報を元に、コールバックを実施するプロキシ。\r
         * @type {Function}\r
         */\r
-       proxy : X_Callback_proxyCallback\r
+       proxy : X_Closure_proxyCallback\r
 };\r
 \r
 // ------------------------------------------------------------------------- //\r
 // --- implements ---------------------------------------------------------- //\r
 // ------------------------------------------------------------------------- //\r
 \r
-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
+function X_Closure_create( thisObject, opt_callback, opt_args /* [ listener || ( context + function ) || function ][ args... ] */ ){\r
+       var obj = X_Closure_classifyCallbackArgs( thisObject, opt_callback, opt_args ),\r
                l, ret, _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
+       if( l = X_CLOSURE_POOL_LIST.length ){\r
+               ret  = X_CLOSURE_POOL_LIST[ l - 1 ]; --X_CLOSURE_POOL_LIST.length; // ret = X_CLOSURE_POOL_LIST.pop();\r
                _obj = ret( X_Closure_COMMAND_BACK );\r
                \r
                _obj.kind       = obj.kind;\r
@@ -88,52 +84,52 @@ function X_Callback_create( thisObject, opt_callback, opt_args /* [ listener ||
                _obj.func       = obj.func;\r
                _obj.context    = obj.context;\r
                _obj.supplement = obj.supplement;\r
-               _obj.proxy      = X_Callback_proxyCallback;\r
+               _obj.proxy      = X_Closure_proxyCallback;\r
        } else {\r
-               ret             = X_Callback_actualClosure( obj );\r
-               obj.proxy       = X_Callback_proxyCallback;\r
+               ret             = X_Closure_actualClosure( obj );\r
+               obj.proxy       = X_Closure_proxyCallback;\r
        };\r
-       X_Callback_LIVE_LIST[ X_Callback_LIVE_LIST.length ] = ret;\r
+       X_CLOSURE_LIVE_LIST[ X_CLOSURE_LIVE_LIST.length ] = ret;\r
        return ret;\r
 };\r
 \r
 \r
-function X_Callback_classifyCallbackArgs( arg1, arg2, arg3, alt_context ){\r
+function X_Closure_classifyCallbackArgs( arg1, arg2, arg3, alt_context ){\r
        var obj;\r
        \r
        if( X_Type_isObject( arg1 ) && X_Type_isFunction( arg2 ) ){\r
-               obj  = { context : arg1, func : arg2, kind : X_Callback_THIS_FUNC };\r
+               obj  = { context : arg1, func : arg2, kind : X_CLOSURE_THIS_FUNC };\r
        } else\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
+                       obj  = { context : arg1, name : arg2, kind : X_CLOSURE_THIS_FUNCNAME };\r
                } else {\r
-                       obj  = { context : arg1, kind : X_Callback_HANDLEEVENT };\r
+                       obj  = { context : arg1, kind : X_CLOSURE_HANDLEEVENT };\r
                        arg3 = arg2;                    \r
                };\r
        } else\r
        if( X_Type_isFunction( arg1 ) ){\r
                arg3 = arg2;\r
                if( alt_context ){\r
-                       obj  = { context : alt_context, func : arg1, kind : X_Callback_THIS_FUNC };\r
+                       obj  = { context : alt_context, func : arg1, kind : X_CLOSURE_THIS_FUNC };\r
                } else {\r
-                       obj  = { func : arg1, kind : X_Callback_FUNC_ONLY };\r
+                       obj  = { func : arg1, kind : X_CLOSURE_FUNC_ONLY };\r
                };\r
        } else\r
        if( X_Type_isFunction( arg2 ) ){\r
-               //console.log( 'X_Callback_classifyCallbackArgs : arg1 が ' + arg1 + 'です' ); ie4 で error\r
+               //console.log( 'X_Closure_classifyCallbackArgs : arg1 が ' + arg1 + 'です' ); ie4 で error\r
                if( alt_context ){\r
-                       obj  = { context : alt_context, func : arg2, kind : X_Callback_THIS_FUNC };\r
+                       obj  = { context : alt_context, func : arg2, kind : X_CLOSURE_THIS_FUNC };\r
                } else {\r
-                       obj  = { func : arg2, kind : X_Callback_FUNC_ONLY };\r
+                       obj  = { func : arg2, kind : X_CLOSURE_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
+               obj  = { context : alt_context, name : arg1, kind : X_CLOSURE_THIS_FUNCNAME };\r
        } else\r
        if( alt_context ){\r
-               obj  = { context : alt_context, kind : X_Callback_HANDLEEVENT };\r
+               obj  = { context : alt_context, kind : X_CLOSURE_HANDLEEVENT };\r
                arg3 = arg1;\r
        } else {\r
                console.log( '不正 ' + arg1 );\r
@@ -147,14 +143,14 @@ function X_Callback_classifyCallbackArgs( arg1, arg2, arg3, alt_context ){
        return ( obj.context || obj.supplement ) ? obj : arg1;\r
 };\r
 \r
-function X_Callback_actualClosure( obj ){\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 obj.proxy && obj.proxy( obj, arguments );\r
        };\r
 };\r
 \r
-function X_Callback_proxyCallback( xfunc, _args ){\r
+function X_Closure_proxyCallback( xfunc, _args ){\r
        var args    = _args || [],\r
                thisObj = xfunc.context,\r
                func    = xfunc.func,\r
@@ -177,12 +173,12 @@ function X_Callback_proxyCallback( xfunc, _args ){
        \r
        switch( xfunc.kind ){\r
 \r
-               case X_Callback_THIS_FUNC :\r
+               case X_CLOSURE_THIS_FUNC :\r
                        return args.length === 0 ? func.call( thisObj ) : func.apply( thisObj, args );\r
                \r
-               case X_Callback_THIS_FUNCNAME :\r
+               case X_CLOSURE_THIS_FUNCNAME :\r
                        funcName = xfunc.name;\r
-               case X_Callback_HANDLEEVENT :\r
+               case X_CLOSURE_HANDLEEVENT :\r
                        funcName = funcName || 'handleEvent';\r
                        temp = thisObj[ funcName ];\r
                        if( X_Type_isFunction( temp ) ){\r
@@ -199,40 +195,49 @@ function X_Callback_proxyCallback( xfunc, _args ){
                        };\r
                        return args.length === 0 ? func.call( thisObj ) : func.apply( thisObj, args );*/\r
                                                \r
-               case X_Callback_FUNC_ONLY :\r
+               case X_CLOSURE_FUNC_ONLY :\r
                        return args.length === 0 ?\r
                                        func() :\r
                                args.length === 1 ?\r
                                        func( args[ 0 ] ) :\r
                                        func.apply( null, args );\r
        };\r
-       return X_Callback_NONE;\r
+       return X_CALLBACK_NONE;\r
 };\r
 \r
-function X_Callback_correct( f ){\r
-       var i = X_Callback_LIVE_LIST.indexOf( f ),\r
+function X_Closure_correct( f ){\r
+       var i = X_CLOSURE_LIVE_LIST.indexOf( f ),\r
                obj;\r
        if( i !== -1 ){\r
-               X_Callback_LIVE_LIST.splice( i, 1 );\r
-               X_Callback_POOL_LIST[ X_Callback_POOL_LIST.length ] = f;\r
+               X_CLOSURE_LIVE_LIST.splice( i, 1 );\r
+               X_CLOSURE_POOL_LIST[ X_CLOSURE_POOL_LIST.length ] = f;\r
                obj = f( X_Closure_COMMAND_BACK );\r
+               /*\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
+               delete obj.proxy; */\r
+               X_Object_clear( obj );\r
                return true;\r
        };\r
        return false;\r
 };\r
 \r
-function X_Callback_monitor(){\r
+function X_Closure_monitor(){\r
        return {\r
-               'Callback:Live' : X_Callback_LIVE_LIST.length,\r
-               'Callback:Pool' : X_Callback_POOL_LIST.length\r
+               'Callback:Live' : X_CLOSURE_LIVE_LIST.length,\r
+               'Callback:Pool' : X_CLOSURE_POOL_LIST.length\r
        };\r
 };\r
-function X_Callback_gc(){\r
-       X_Callback_POOL_LIST.length = 0; // ?\r
-};
\ No newline at end of file
+function X_Closure_gc(){\r
+       X_CLOSURE_POOL_LIST.length = 0; // ?\r
+};\r
+\r
+X_TEMP.onSystemReady.push( function( sys ){\r
+       sys.monitor( X_Closure_monitor );\r
+       sys.gc( X_Closure_gc );\r
+});\r
+\r
+\r
index b4f53b8..2349dde 100644 (file)
@@ -35,7 +35,7 @@ X_ViewPort = X_Class_override(
        {
 
                'handleEvent' : function( e ){
-                       var href, i, name, active = false;
+                       var href, i, name, active = false, xnode;
                        
                        switch( e.type ){
                                case 'beforeunload' :
@@ -57,30 +57,43 @@ X_ViewPort = X_Class_override(
                                        break;
 
                                case 'visibilitychange' :
+                                       console.log( e.type + ':' + document[ 'hidden' ] );
                                        X_ViewPort[ 'dispatch' ]( ( X_ViewPort_active = document[ 'hidden' ] ) ? X_EVENT_VIEW_DEACTIVATE : X_EVENT_VIEW_ACTIVATE );
                                        break;
+                               case 'msvisibilitychange' :
+                                       X_ViewPort[ 'dispatch' ]( ( X_ViewPort_active = document[ 'msHidden' ] ) ? X_EVENT_VIEW_DEACTIVATE : X_EVENT_VIEW_ACTIVATE );
+                                       break;
                                case 'mozvisibilitychange' :
                                        X_ViewPort[ 'dispatch' ]( ( X_ViewPort_active = document[ 'mozHidden' ] ) ? X_EVENT_VIEW_DEACTIVATE : X_EVENT_VIEW_ACTIVATE );
                                        break;
                                case 'webkitvisibilitychange' :
+                                       console.log( e.type + ':' + document[ 'webkitHidden' ] );
                                        X_ViewPort[ 'dispatch' ]( ( X_ViewPort_active = document[ 'webkitHidden' ] ) ? X_EVENT_VIEW_DEACTIVATE : X_EVENT_VIEW_ACTIVATE );
                                        break;
-
        
                                case 'blur' :
                                case 'focusout' :
-                               case 'pagehide' :                               
+                                       if( X_UA[ 'IE' ] < 9 ){
+                                               xnode = X_Node_getXNode( document.activeElement );
+                                               if( xnode ){
+                                                       xnode[ 'listen' ]( [ 'focus', 'blur' ], X_ViewPort_detectFocusForIE );
+                                                       //break;
+                                               };
+                                               if( X_ViewPort_activeTimerID ){
+                                                       X_ViewPort_activeTimerID = X_Timer_remove( X_ViewPort_activeTimerID );
+                                               };
+                                               X_ViewPort_activeTimerID = X_Timer_once( 16, X_ViewPort_changeFocus );
+                                               return X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_STOP_PROPAGATION;
+                                       };
+                               case 'pagehide' :               
                                        active = true;
                                case 'focus' :
-                               case 'focusin' :
                                case 'pageshow' :
+                               case 'focusin' :
                                        if( X_ViewPort_active === active ){
                                                X_ViewPort_active = !active;
-                                               if( X_ViewPort_activeTimerID ){
-                                                       X_ViewPort_activeTimerID = X_Timer_remove( X_ViewPort_activeTimerID );
-                                               } else {
-                                                       X_ViewPort_activeTimerID = X_Timer_once( 1, X_ViewPort_changeFocus );
-                                               };
+                                               console.log( e.type + ':' + X_ViewPort_active );
+                                               X_ViewPort[ 'dispatch' ]( active ? X_EVENT_VIEW_DEACTIVATE : X_EVENT_VIEW_ACTIVATE );
                                        };
                                        break;
                        };
@@ -89,6 +102,22 @@ X_ViewPort = X_Class_override(
        }
 );
 
+function X_ViewPort_detectFocusForIE( e ){
+       console.log( 'iefix! ' + e.type + ':' + this.attr( 'tag' ) + ' isActive?:' + ( this[ '_rawObject' ] === document.activeElement ) );
+       
+       X_ViewPort_active = e.type === 'focus';
+       
+       if( this[ '_rawObject' ] !== document.activeElement ){
+               this[ 'unlisten' ]( X_ViewPort_active ? 'blur' : 'focus', X_ViewPort_detectFocusForIE );
+       };
+       if( X_ViewPort_activeTimerID ){
+               X_ViewPort_activeTimerID = X_Timer_remove( X_ViewPort_activeTimerID );
+       };
+       X_ViewPort_activeTimerID = X_Timer_once( 16, X_ViewPort_changeFocus );
+       
+       return X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_STOP_PROPAGATION;
+};
+
 function X_ViewPort_changeFocus(){
        X_ViewPort[ 'dispatch' ]( X_ViewPort_active ? X_EVENT_VIEW_ACTIVATE : X_EVENT_VIEW_DEACTIVATE );
        X_ViewPort_activeTimerID = 0;
@@ -106,14 +135,24 @@ X[ 'ViewPort' ] = {
         * @alias X.ViewPort.listen
         */
        'listen' : function( type, arg1, arg2, arg3 ){
+               var f;
+               
                if( type <= X_ViewPort_readyState ){
                        /*
                         * X_EVENT_XDOM_READY 以後に listen した場合の対策
                         */
                        X_ViewPort[ 'asyncDispatch' ]( type );
                };
-               // ie8-では keydown -> documentへ
-               type && arg1 && X_ViewPort[ 'listen' ]( type, arg1, arg2, arg3 );
+               
+               f = X_Closure_classifyCallbackArgs( arg1, arg2, arg3 );
+               if( !f.kind ){
+                       X_ViewPort[ 'listen' ]( type, this, arg1 );
+               } else
+               if( f.kind === X_CLOSURE_FUNC_ONLY ){
+                       X_ViewPort[ 'listen' ]( type, this, f.func, f.supplement );
+               } else {
+                       X_ViewPort[ 'listen' ]( type, arg1, arg2, arg3 );
+               };
                return X[ 'ViewPort' ];
        },
        
@@ -122,13 +161,24 @@ X[ 'ViewPort' ] = {
         * @alias X.ViewPort.listenOnce
         */
        'listenOnce' : function( type, arg1, arg2, arg3 ){
+               var f;
+               
                if( type <= X_ViewPort_readyState ){
                        /*
                         * X.Event.XDOM_READY 以後に listen した場合の対策
                         */
                        X_ViewPort[ 'asyncDispatch' ]( type );
                };
-               type && arg1 && X_ViewPort[ 'listenOnce' ]( type, arg1, arg2, arg3 );
+               
+               f = X_Closure_classifyCallbackArgs( arg1, arg2, arg3 );
+               if( !f.kind ){
+                       X_ViewPort[ 'listenOnce' ]( type, this, arg1 );
+               } else
+               if( f.kind === X_CLOSURE_FUNC_ONLY ){
+                       X_ViewPort[ 'listenOnce' ]( type, this, f.func, f.supplement );
+               } else {
+                       X_ViewPort[ 'listenOnce' ]( type, arg1, arg2, arg3 );
+               };
                return X[ 'ViewPort' ];
        },
        
@@ -137,7 +187,16 @@ X[ 'ViewPort' ] = {
         * @alias X.ViewPort.unlisten
         */
        'unlisten' : function( type, arg1, arg2, arg3 ){
-               type && arg1 && X_ViewPort[ 'unlisten' ]( type, arg1, arg2, arg3 );
+               var f = X_Closure_classifyCallbackArgs( arg1, arg2, arg3 );
+               
+               if( !f.kind ){
+                       X_ViewPort[ 'unlisten' ]( type, this, arg1 );
+               } else
+               if( f.kind === X_CLOSURE_FUNC_ONLY ){
+                       X_ViewPort[ 'unlisten' ]( type, this, f.func, f.supplement );
+               } else {
+                       X_ViewPort[ 'unlisten' ]( type, arg1, arg2, arg3 );
+               };
                return X[ 'ViewPort' ];
        },
        
@@ -146,6 +205,14 @@ X[ 'ViewPort' ] = {
         * @alias X.ViewPort.listening
         */
        'listening' : function( type, arg1, arg2, arg3 ){
+               var f = X_Closure_classifyCallbackArgs( arg1, arg2, arg3 );
+               
+               if( !f.kind ){
+                       return X_ViewPort[ 'listening' ]( type, this, arg1 );
+               } else
+               if( f.kind === X_CLOSURE_FUNC_ONLY ){
+                       return X_ViewPort[ 'listening' ]( type, this, f.func, f.supplement );
+               };
                return X_ViewPort[ 'listening' ]( type, arg1, arg2, arg3 );
        },
 
@@ -180,8 +247,8 @@ X[ 'ViewPort' ] = {
 //(((t = document.documentElement) || (t = document.body.parentNode)) && typeof t.ScrollLeft == 'number' ? t : document.body).ScrollLeft;
 //(((t = document.documentElement) || (t = document.body.parentNode)) && typeof t.ScrollTop == 'number' ? t : document.body).ScrollTop
        
-       /**
-        * 
+       /*
+        * TODO X.Doc へ
         * @alias X.ViewPort.getDocumentSize
         */
        'getDocumentSize' : function(){
@@ -448,24 +515,36 @@ X[ 'ViewPort' ] = {
 //ブラウザの戻るボタンで戻ったときに呼ばれるイベントとかキャッシュとかそこらへんのこと
 //http://d.hatena.ne.jp/koumiya/20080916/1221580149
 
+console.log( '------------------->' );
+
+                       if( document[ 'webkitHidden' ] !== undefined ){
+                               console.log( '--> has webkitvisibilitychange' );
+                               X_EventDispatcher_systemListen( X_ViewPort_document, 'webkitvisibilitychange', X_ViewPort );
+                       } else
                        if( document[ 'hidden' ] !== undefined ){// iOS 7+
+                               console.log( '--> has visibilitychange' );
                                X_EventDispatcher_systemListen( X_ViewPort_document, 'visibilitychange', X_ViewPort );
+                               document.onvisibilitychange = function(){ console.log( '!!!!!!!!!!!!!!!!' ) };
+                       } else
+                       if( document[ 'msHidden' ] !== undefined ){
+                               X_EventDispatcher_systemListen( X_ViewPort_document, 'msvisibilitychange', X_ViewPort );
                        } else
                        if( document[ 'mozHidden' ] !== undefined ){
                                X_EventDispatcher_systemListen( X_ViewPort_document, 'mozvisibilitychange', X_ViewPort );
-                       } else
-                       if( document[ 'webkitHidden' ] !== undefined ){
-                               X_EventDispatcher_systemListen( X_ViewPort_document, 'webkitvisibilitychange', X_ViewPort );
-                       } else
-                       if( X_UA[ 'iOS' ] && window[ 'onpageshow' ] !== undefined ){
+                       };
+                       
+                       if( window[ 'onpageshow' ] !== undefined ){
+                               console.log( '-------------------> pageshow, pagehide' );
                                X_EventDispatcher_systemListen( X_ViewPort, [ 'pageshow', 'pagehide' ] );
-                       } else
+                       };
+                       
                        if( document[ 'onfocusin' ] !== undefined ){
+                               console.log( '-------------------> focusin, focusout' );
                                // https://github.com/ai/visibilityjs/blob/master/lib/visibility.fallback.js
                                X_EventDispatcher_systemListen( X_ViewPort_document, [ 'focusin', 'focusout' ], X_ViewPort );
-                       } else {
-                               X_EventDispatcher_systemListen( X_ViewPort, [ 'focus', 'blur' ] );
                        };
+                       
+                       X_EventDispatcher_systemListen( X_ViewPort, [ 'focus', 'blur' ] );
 
                        return X_CALLBACK_UN_LISTEN;
                };
index 7232833..f4c88bb 100644 (file)
@@ -9,13 +9,24 @@ X[ 'Doc' ] = {
         * @alias X.Doc.listen
         */
        'listen' : function( type, arg1, arg2, arg3 ){
+               var f;
+               
                if( type <= X_ViewPort_readyState && type === 'DOMContentLoaded' ){
                        /*
                         * X.Event.XDOM_READY 以後に listen した場合の対策
                         */
                        X_ViewPort_document[ 'asyncDispatch' ]( type );
                };
-               type && arg1 && X_ViewPort_document[ 'listen' ]( type, arg1, arg2, arg3 );
+               
+               f = X_Closure_classifyCallbackArgs( arg1, arg2, arg3 );
+               if( !f.kind ){
+                       X_ViewPort_document[ 'listen' ]( type, this, arg1 );
+               } else
+               if( f.kind === X_CLOSURE_FUNC_ONLY ){
+                       X_ViewPort_document[ 'listen' ]( type, this, f.func, f.supplement );
+               } else {
+                       X_ViewPort_document[ 'listen' ]( type, arg1, arg2, arg3 );
+               };
                return X[ 'Doc' ];
        },
        
@@ -24,13 +35,23 @@ X[ 'Doc' ] = {
         * @alias X.Doc.listenOnce
         */
        'listenOnce' : function( type, arg1, arg2, arg3 ){
+               var f;
+               
                if( type <= X_ViewPort_readyState && type === 'DOMContentLoaded' ){
                        /*
                         * X.Event.XDOM_READY 以後に listen した場合の対策
                         */
                        X_ViewPort_document[ 'asyncDispatch' ]( type );
                };
-               type && arg1 && X_ViewPort_document[ 'listenOnce' ]( type, arg1, arg2, arg3 );
+               
+               f = X_Closure_classifyCallbackArgs( arg1, arg2, arg3 );
+               if( !f.kind ){
+                       X_ViewPort_document[ 'listenOnce' ]( type, this, arg1 );
+               } else
+               if( f.kind === X_CLOSURE_FUNC_ONLY ){
+                       X_ViewPort_document[ 'listenOnce' ]( type, this, f.func, f.supplement );
+               };
+               X_ViewPort_document[ 'listenOnce' ]( type, arg1, arg2, arg3 );
                return X[ 'Doc' ];
        },
 
@@ -39,7 +60,16 @@ X[ 'Doc' ] = {
         * @alias X.Doc.unlisten
         */     
        'unlisten' : function( type, arg1, arg2, arg3 ){
-               type && arg1 && X_ViewPort_document[ 'unlisten' ]( type, arg1, arg2, arg3 );
+               var f = X_Closure_classifyCallbackArgs( arg1, arg2, arg3 );
+               
+               if( !f.kind ){
+                       X_ViewPort_document[ 'unlisten' ]( type, this, arg1 );
+               } else
+               if( f.kind === X_CLOSURE_FUNC_ONLY ){
+                       X_ViewPort_document[ 'unlisten' ]( type, this, f.func, f.supplement );
+               } else {
+                       X_ViewPort_document[ 'unlisten' ]( type, arg1, arg2, arg3 );
+               };
                return X[ 'Doc' ];
        },
 
@@ -48,6 +78,14 @@ X[ 'Doc' ] = {
         * @alias X.Doc.listening
         */     
        'listening' : function( type, arg1, arg2, arg3 ){
+               var f = X_Closure_classifyCallbackArgs( arg1, arg2, arg3 );
+               
+               if( !f.kind ){
+                       return X_ViewPort_document[ 'listening' ]( type, this, arg1 );
+               } else
+               if( f.kind === X_CLOSURE_FUNC_ONLY ){
+                       return X_ViewPort_document[ 'listening' ]( type, this, f.func, f.supplement );
+               };
                return X_ViewPort_document[ 'listening' ]( type, arg1, arg2, arg3 );
        },
        
index 07886c0..391cdb9 100644 (file)
@@ -213,11 +213,12 @@ if( !X_UA[ 'IE' ] || 9 <= X_UA[ 'IE' ] ){
                } else {\r
                        // Other\r
                        \r
-                       this[ 'keyCode' ]       = e.keyCode || e.which;\r
-                       this[ 'altKey' ]        = e.altKey;\r
-                       this[ 'ctrlKey' ]       = e.ctrlKey;\r
-                       this[ 'shiftKey' ]      = e.shiftKey;\r
-                       this[ 'metaKey' ]       = e.metaKey;\r
+                       this[ 'keyCode' ]       = X_Type_isFinite( e.keyCode ) ? e.keyCode : X_Type_isFinite( e.charCode ) ? e.charCode : e.which;\r
+                       this[ 'charCode' ]      = X_Type_isFinite( e.charCode ) ? e.charCode : e.which;\r
+                       this[ 'altKey' ]        = e.altKey   || !!( e.modifiers & 1 );\r
+                       this[ 'ctrlKey' ]       = e.ctrlKey  || !!( e.modifiers & 2 );\r
+                       this[ 'shiftKey' ]      = e.shiftKey || !!( e.modifiers & 4 );\r
+                       this[ 'metaKey' ]       = e.metaKey  || !!( e.modifiers & 8 );;\r
                        \r
                        this[ 'button' ]        = e.button !== undefined ? e.button :\r
                                                                 e.which !== undefined ? e.which - 1 : -1;\r
@@ -272,9 +273,11 @@ if( !X_UA[ 'IE' ] || 9 <= X_UA[ 'IE' ] ){
                if( this[ 'target' ] && !this[ 'target' ][ '_tag' ] ) this[ 'target' ] = this[ 'target' ].parent; // ie4 の fake Textnode がヒットしていないか?\r
                this[ 'currentTarget' ] = xnode; // xnode\r
                this[ 'relatedTarget' ] = X_Node_getXNode( e.formElement || e.toElement ); // xnode\r
+               this[ 'relatedTarget' ] && console.dir( 'relatide...' );\r
                this[ 'eventPhase' ]    = e.srcElement === element ? 2: 3;\r
                \r
                this[ 'keyCode' ]       = e.keyCode;\r
+               this[ 'charCode' ]      = e.keyCode;\r
                this[ 'altKey' ]        = e.altKey;\r
                this[ 'ctrlKey' ]       = e.ctrlKey;\r
                this[ 'shiftKey' ]      = e.shiftKey;           \r
index de76d17..49ae640 100644 (file)
@@ -1188,7 +1188,7 @@ function X_Node_call( name /*, opt_args... */ ){
                };
                return raw[ name ]();           
        } else
-       if( X_Type_isUnknown( func ) ){
+       if( X_Type_isUnknown( func ) || ( X_UA[ 'IE' ] < 9 && X_Type_isObject( func ) ) ){
                // typeof func === unknown に対策
                // http://la.ma.la/blog/diary_200509031529.htm          
                if( l ){
index 785bcbf..d882cc1 100644 (file)
@@ -74,7 +74,7 @@ var // Opera7.6+, Safari1.2+, khtml3.?+, Gecko0.9.7+
        X_Net_XHR_msXMLVer    = 0,      \r
        X_Net_XHR_msXML       = X_Net_XHR_createMSXML && X_Net_XHR_createMSXML( true ),\r
        \r
-       X_Net_XHR_neverReuse  = X_UA[ 'IE' ] < 9 || X_UA[ 'iOS' ] || X_UA[ 'Android' ], // ie7,8 の xhr はリユース不可。msxml はリユース可能。\r
+       X_Net_XHR_neverReuse  = X_UA[ 'IE' ] < 9, // ie7,8 の xhr はリユース不可。msxml はリユース可能。\r
        \r
        X_Net_XHR_TYPE_FLASH  = 8,\r
        X_Net_XHR_TYPE_GADGET = 16;\r
index da48845..c7d95d5 100644 (file)
@@ -131,7 +131,6 @@ function X_NET_Image_handleEvent( e ){
 \r
                case X_EVENT_KILL_INSTANCE :\r
                        this.reset();\r
-                       !X_Net_Image_hasImage && this[ 'kill' ](); // if xnode\r
                        break;\r
        };\r
 };\r
index b12e679..4086c18 100644 (file)
@@ -432,8 +432,10 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ](
                                                        };\r
                                                };\r
                                                break;\r
+                                       case 'useVideo' :\r
+                                               break;\r
                                        default :\r
-                                               throw 'bad arg';\r
+                                               throw ( 'bad arg! ' + k );\r
                                };\r
                        };\r
                        \r
index dd90819..f1bc2bd 100644 (file)
@@ -5,7 +5,8 @@ var X_Audio_WebAudio_context = !X_UA[ 'iPhone_4s' ]  && !X_UA[ 'iPad_2Mini1' ]
                                                                ( window[ 'AudioContext' ] || window[ 'webkitAudioContext' ] ),
        X_Audio_BUFFER_LIST      = [],
        X_Audio_WebAudioWrapper,
-       X_Audio_BufferLoader;
+       X_Audio_BufferLoader,
+       X_Audio_fpsFix;
 
 /*
  * iPhone 4s 以下、iPad2以下、iPad mini 1以下, iPod touch 4G 以下は不可
@@ -138,6 +139,16 @@ if( X_Audio_WebAudio_context ){
                                        l = X_Audio_BUFFER_LIST.length,
                                        loader;
 
+                               /*
+                                * http://qiita.com/sou/items/5688d4e7d3a37b4e2ff1
+                                * L-01F 等の一部端末で Web Audio API の再生結果に特定条件下でノイズが混ざることがある。
+                                * 描画レート(描画 FPS)が下がるとノイズが混ざり始め、レートを上げると再生結果が正常になるというもので、オーディオ処理が描画スレッドに巻き込まれているような動作を見せる。
+                                */
+                               if( X_UA[ 'Android' ] && X_UA[ 'Chrome' ] && !X_Audio_fpsFix ){
+                                       X_Node_systemNode.create( 'div', { id : 'fps-slowdown-make-sound-noisy' } );
+                                       X_Audio_fpsFix = true;
+                               };
+
                                for( ; i < l; ++i ){
                                        loader = X_Audio_BUFFER_LIST[ i ];
                                        if( loader.url === url ){
@@ -336,15 +347,6 @@ if( X_Audio_WebAudio_context ){
                }
        );
 
-       /*
-        * http://qiita.com/sou/items/5688d4e7d3a37b4e2ff1
-        * L-01F 等の一部端末で Web Audio API の再生結果に特定条件下でノイズが混ざることがある。
-        * 描画レート(描画 FPS)が下がるとノイズが混ざり始め、レートを上げると再生結果が正常になるというもので、オーディオ処理が描画スレッドに巻き込まれているような動作を見せる。
-        */
-       if( X_UA[ 'Android' ] && X_UA[ 'Chrome' ] ){
-               X_Node_systemNode.create( 'div', { id : 'fps-slowdown-make-sound-noisy' } );
-       };
-
        X_Audio_BACKENDS.push(
                {
                        backendName : 'Web Audio',
index 3972841..dd71bde 100644 (file)
@@ -8,14 +8,17 @@ var X_Audio_HTMLAudio_playTrigger =
                6 <= X_UA[ 'iOS' ] ? 'loadeddata' :\r
                X_UA[ 'iOS' ] < 5  ? 'stalled' :\r
                X_UA[ 'iOS' ]      ? 'suspend' :\r
-               X_UA[ 'AndroidBrowser2' ] || X_UA[ 'AndroidBrowser3' ] ? 'stalled' : // Android 2.3.5(SBM101SH) では stalled は発生しない,,,\r
-               X_UA[ 'AndroidBrowser4' ] ? 'loadeddata' : \r
+               X_UA[ 'AndroidChromeBrowser' ] ? 'canplaythrough' :\r
+               // Android 2.3.5(SBM101SH) では stalled は発生しない,,, ので必ず loadeddata もチェックする\r
+               X_UA[ 'AndroidBrowser' ] ? 'stalled' :\r
                X_UA[ 'OperaMobile' ] || X_UA[ 'OperaTablet' ] ? 'loadeddata' :\r
                //X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ? 'canplay' :\r
                        'loadeddata', //'canplay',\r
        X_Audio_HTMLAudioWrapper,\r
        X_Audio_constructor = window[ 'Audio' ] || window.HTMLAudioElement,\r
        X_Audio_rawAudio,\r
+       // onended イベント時に再生を継続する場合、audio.play() を呼ぶ必要がある\r
+       X_Audio_HTMLAudioWrapper_needPlayOnended = !X_UA[ 'AndroidChromeBrowser' ] && X_UA[ 'AndroidBrowser' ],\r
        // Opera Mobile 12 android4.4.4 & 2.3.5 は 2回目以降の currentTime へのセットで currentTime が更新されなくなるため、タイマーを使用する\r
        X_Audio_HTMLAudioWrapper_currentTimeFix  = !!X_UA[ 'OperaMobile' ] || !!X_UA[ 'OperaTablet' ], // || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ),\r
        // Android1.6+MobileOpera12では無理っぽい、、、\r
@@ -30,9 +33,10 @@ var X_Audio_HTMLAudio_playTrigger =
        // opera11、10.54 WinXP はまとも、、、\r
        // X_Audio_Sprite_handleEvent でも使用\r
        X_Audio_HTMLAudioWrapper_ieMobile9Fix    = ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ),\r
-       X_Audio_HTMLAudioWrapper_durationFix     = ( !X_Audio_HTMLAudioWrapper_currentTimeFix && 12 <= X_UA[ 'Opera' ] ),\r
+       X_Audio_HTMLAudioWrapper_durationFix     = ( !X_Audio_HTMLAudioWrapper_currentTimeFix && 12 <= X_UA[ 'Opera' ] ) || X_UA[ 'AndroidChromeBrowser' ],\r
+       \r
+       X_Audio_HTMLAudioWrapper_shortPlayFix    = X_UA[ 'AndroidBrowser' ] && X_UA[ 'AndroidWebkit' ] <= 534.3, // Android 4.1.1 でも遭遇(ただしm4a, mp3は優秀, oggはシークが乱れる)\r
        \r
-       X_Audio_HTMLAudioWrapper_shortPlayFix    = X_UA[ 'AndroidBrowser' ] && X_UA[ 'AndroidWebkit' ] <= 534.3, // Android 4.1.1 でも遭遇\r
        \r
        X_Audio_codecs;\r
 \r
@@ -43,6 +47,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
 \r
        // https://html5experts.jp/miyuki-baba/3766/\r
        // Chrome for Android31 で HE-AAC が低速再生されるバグ\r
+       // TODO Android4 標準ブラウザで ogg のシークが正しくない!\r
        if( X_Audio_rawAudio.canPlayType ){\r
                X_Audio_codecs = {\r
              'mp3'  : X_Audio_rawAudio.canPlayType('audio/mpeg'),\r
@@ -54,25 +59,41 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
              'mp4'  : X_Audio_rawAudio.canPlayType('audio/x-mp4') + X_Audio_rawAudio.canPlayType('audio/mp4') + X_Audio_rawAudio.canPlayType('audio/aac'),\r
              'weba' : X_Audio_rawAudio.canPlayType('audio/webm; codecs="vorbis"')\r
                };\r
-               (function( k, v ){\r
+               (function( X_Audio_codecs, k, v ){\r
                        for( k in X_Audio_codecs ){\r
-                               if( X_EMPTY_OBJECT[ k ] ) continue;\r
+                               //if( X_EMPTY_OBJECT[ k ] ) continue;\r
                                v = X_Audio_codecs[ k ];\r
-                               X_Audio_codecs[ k ] = v && v.split( 'no' ).join( '' );\r
-                               console.log( k + ' ' + X_Audio_codecs[ k ] );\r
+                               v = v && !!( v.split( 'no' ).join( '' ) );\r
+                               if( v ){\r
+                                       console.log( k + ' ' + X_Audio_codecs[ k ] );\r
+                                       X_Audio_codecs[ k ] = true;\r
+                               } else {\r
+                                       delete X_Audio_codecs[ k ];\r
+                               };\r
                        };\r
-               })();\r
+               })( X_Audio_codecs );\r
        } else {\r
                // iOS3.2.3\r
                X_Audio_codecs = {\r
-             'mp3'  : X_UA[ 'IE' ] || X_UA[ 'Chrome' ] || ( X_UA[ 'Windows' ]  && X_UA[ 'Safari' ]  ),\r
+             'mp3'  : X_UA[ 'IE' ] || X_UA[ 'Chrome' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ]  ),\r
              'ogg'  : 5 <= X_UA[ 'Gecko' ] || X_UA[ 'Chrome' ] || X_UA[ 'Opera' ] ,\r
-             'wav'  : X_UA[ 'Gecko' ] || X_UA[ 'Opera' ] || ( X_UA[ 'Windows' ]  && X_UA[ 'Safari' ]  ),\r
+             'wav'  : X_UA[ 'Gecko' ] || X_UA[ 'Opera' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ]  ),\r
              'aac'  : X_UA[ 'IE' ] || X_UA[ 'WebKit' ],\r
              'm4a'  : X_UA[ 'IE' ] || X_UA[ 'WebKit' ],\r
              'mp4'  : X_UA[ 'IE' ] || X_UA[ 'WebKit' ],\r
              'weba' : 2 <= X_UA[ 'Gecko' ] || 10.6 <= X_UA[ 'Opera' ] // firefox4+(Gecko2+)\r
                };\r
+               (function( X_Audio_codecs, k ){\r
+                       for( k in X_Audio_codecs ){\r
+                               //if( X_EMPTY_OBJECT[ k ] ) continue;\r
+                               if( X_Audio_codecs[ k ] ){\r
+                                       console.log( k + ' ' + X_Audio_codecs[ k ] );\r
+                                       X_Audio_codecs[ k ] = true;\r
+                               } else {\r
+                                       delete X_Audio_codecs[ k ];\r
+                               };\r
+                       };\r
+               })( X_Audio_codecs );\r
        };\r
        \r
        X_Audio_HTMLAudioWrapper = X_Audio_AbstractAudioBackend[ 'inherits' ](\r
@@ -87,12 +108,17 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                        _lastCurrentTime : 0,\r
                        _src             : '',\r
                        \r
+                       isM4A            : false,\r
+                       shortPlayFix     : 0,\r
+                       \r
                        'Constructor' : function( target, source, option ){\r
                                var raw;\r
                                \r
                                this.target  = target || this;\r
                                this._closed = false;\r
                                \r
+                               this.isM4A   = X_URL_getEXT( source ) === 'm4a';\r
+                               \r
                                this.setState( option );\r
 \r
                                if( option[ 'useVideo' ] ){\r
@@ -169,7 +195,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                X_Audio_HTMLAudioWrapper_badOperaAndroid && alert( e.type );\r
                                \r
                                // global に公開\r
-                               window[ '__rawAudio' ] = this[ '_rawObject' ];\r
+                               //window[ '__rawAudio' ] = this[ '_rawObject' ];\r
                                \r
                                /* X_Audio_HTMLAudioWrapper_ieMobile9Fix && */ e.type !== 'timeupdate' && console.log( e.type );\r
                                \r
@@ -184,8 +210,8 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                                break;\r
                                        \r
                                        case 'canplay' :        //      今すぐに再生を再開できるが、バッファリングが不十分でコンテンツを最後まで表示できないと予測している場合に発生\r
-                                               if( X_Audio_HTMLAudioWrapper_durationFix && this._playForDuration === 0 ){\r
-                                                       //console.log( 'DurationFix開始 - ' + this[ '_rawObject' ].duration );\r
+                                               if( X_Audio_HTMLAudioWrapper_durationFix && this._playForDuration === 0 && !X_UA[ 'AndroidChromeBrowser' ] ){\r
+                                                       console.log( '[duration fix]開始 - ' + this[ '_rawObject' ].duration );\r
                                                        this._playForDuration = 1;\r
                                                        this[ '_rawObject' ].play();\r
                                                        this[ '_rawObject' ].currentTime = this._beginTime / 1000; // 必要!\r
@@ -194,6 +220,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                        case 'loadedmetadata' : //      ブラウザがメディアリソースの長さと寸法を判定した場合に発生\r
                                        case 'loadeddata' :     //      コンテンツの表示を現在の再生位置で初めて行えるようになった場合に発生\r
                                        case 'canplaythrough' : //      今すぐに再生を開始してもバッファリングで停止することなく最後まで表示できると予測している場合に発生\r
+                                               X_Audio_HTMLAudioWrapper_durationFix && console.log( '[duration fix]' + e.type + ' ' + this._playForDuration );\r
                                                if( X_Audio_HTMLAudioWrapper_durationFix && this._playForDuration !== 2 ) return;\r
                                                this.duration = this.duration || this[ '_rawObject' ].duration * 1000;\r
                                                break;\r
@@ -235,8 +262,9 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                                        if( !( this.target[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
                                                                this.looped = true;\r
                                                                this.target[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
-                                                               this.actualPlay();\r
+                                                               this.actualPlay( X_Audio_HTMLAudioWrapper_needPlayOnended );\r
                                                        };\r
+                                                       // Android4.1.1 ended 後に曲の再生が継続できない\r
                                                        return;\r
                                                };\r
                                                type = X_EVENT_MEDIA_ENDED;\r
@@ -249,11 +277,10 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                                if( X_Audio_HTMLAudioWrapper_ieMobile9Fix ){\r
                                                        if( this._playForDuration === 1 ){\r
                                                                console.log( 'tu ' + this[ '_rawObject' ].duration );\r
-                                                               if( !this.duration && X_Type_isFinite( this[ '_rawObject' ].duration ) ){\r
+                                                               if( !this.duration && X_Type_isFinite( this[ '_rawObject' ].duration ) && 0 < this[ '_rawObject' ].duration ){\r
                                                                        this.duration = this.duration || this[ '_rawObject' ].duration * 1000;\r
                                                                        this._playForDuration = 2;\r
                                                        loaded = true;\r
-                                                       //console.log( 'durationFix が完了' + this.duration );\r
                                                        break;\r
                                                                } else {\r
                                                                        this[ '_rawObject' ].currentTime = this._beginTime / 1000; // 必要!\r
@@ -261,7 +288,6 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                                                };\r
                                                        } else\r
                                                        if( this[ '_rawObject' ].currentTime === this._lastCurrentTime ){\r
-                                                               //this.target[ 'dispatch' ]( 'seeking' );\r
                                                                this.target[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
                                                                return;\r
                                                        };\r
@@ -270,10 +296,10 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                                this.duration = this.duration || this[ '_rawObject' ].duration * 1000;\r
 \r
                                    if( this.playing ){\r
-                                       end = X_AudioWrapper_getEndTime( this );\r
+                                       end = X_AudioWrapper_getEndTime( this ) + this.shortPlayFix;\r
                                        now = this.getActualCurrentTime();\r
                                        console.log( now + ' / ' + end );\r
-                                       if( 0 + end <= 0 + now ){ // なぜか iem9 で必要,,,\r
+                                       if( 0 + end <= 0 + now ){ // 0+ なぜか iem9 で必要,,,\r
                                                if( this.autoLoop ){\r
                                                        if( !( this.target[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
                                                                this.looped = true;\r
@@ -296,9 +322,10 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                                \r
                                                if( !X_Audio_HTMLAudioWrapper_durationFix ){\r
                                                        this.duration = this[ '_rawObject' ].duration * 1000;\r
+                                                       console.log( 'duration : ' + this.duration );\r
                                                } else\r
-                                               // Desktop Opera では Infinity, IEM9 では NaN\r
-                                               if( !this.duration && X_Type_isFinite( this[ '_rawObject' ].duration ) ){\r
+                                               // Desktop Opera では Infinity, IEM9 では NaN, Android標準ブラウザ(Chrome)では 0\r
+                                               if( !this.duration && X_Type_isFinite( this[ '_rawObject' ].duration ) && 0 < this[ '_rawObject' ].duration ){\r
                                                        \r
                                                        //console.log( this[ '_rawObject' ].duration );\r
                                                        \r
@@ -309,20 +336,21 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                                        if( this._playForDuration === 1 ){\r
                                                                this._playForDuration = 2;\r
                                                                \r
-                                                               console.log( 'Loaded ' + this._loaded );\r
+                                                               console.log( '[duration fix] Loaded ' + this._loaded );\r
                                                                \r
                                                                if( this._loaded ){\r
                                                                        this[ '_rawObject' ].currentTime = this._beginTime / 1000;\r
-                                                                       console.log( '設定 ' + this._beginTime );\r
+                                                                       console.log( '[duration fix] 設定 ' + this._beginTime );\r
                                                                        return;\r
                                                                };\r
 \r
                                                loaded = true;\r
-                                               console.log( 'durationFix が完了' + this.duration );\r
+                                               console.log( '[duration fix] 完了' + this.duration );\r
                                                \r
                                                if( this.autoplay ){\r
                                                                        this[ '_rawObject' ].currentTime = this._beginTime / 1000;      \r
-                                               } else {\r
+                                               } else\r
+                                               if( X_UA[ 'Opera' ] ){\r
                                                        // Opera12.17 WinXP で勝手に再生される不具合\r
                                                        // これで一応再生は止まる、、、\r
                                                                        this[ '_rawObject' ].src = '';\r
@@ -340,17 +368,18 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                        this.autoplay && X_Timer_once( 16, this, this.play );\r
                                        this._loaded = true;\r
                                        this.target[ 'asyncDispatch' ]( X_EVENT_READY );\r
-                                       console.log( 'Loaded! ' + e.type + ' d:' + ( this.duration | 0 ) );\r
+                                       console.log( '> Audio Loaded!! ' + e.type + ' d:' + ( this.duration | 0 ) );\r
                                        return;\r
                                };\r
                                \r
                                if( !loaded && type ){\r
+                                       console.log( '(2) ' + e.type + ' d:' + ( this.duration | 0 ) );\r
                                        this.target[ 'dispatch' ]( type );\r
                                        type === X_EVENT_ERROR && this[ 'kill' ]();\r
                                };\r
                        },\r
 \r
-                       actualPlay : function(){\r
+                       actualPlay : function( forcePlay ){\r
                                var begin, end;\r
                                \r
                                // もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気\r
@@ -368,9 +397,11 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                end   = X_AudioWrapper_getEndTime( this );\r
                                begin = this._beginTime = X_AudioWrapper_getStartTime( this, end, true );\r
 \r
-                   if( X_Audio_HTMLAudioWrapper_shortPlayFix ){\r
-                       begin -= ( end - begin > 1000 ) ? 200 : 400;\r
-                       begin  = begin < 0 ? 0 : begin;\r
+                   if( X_Audio_HTMLAudioWrapper_shortPlayFix && this.isM4A ){\r
+                       this.shortPlayFix = ( 1000 < end - begin ) ? 200 : 400;\r
+                       if( this.duration < end + this.shortPlayFix ){\r
+                               this.shortPlayFix = this.duration - end;\r
+                       };\r
                    };\r
 \r
                                if( !this[ '_rawObject' ].src ){\r
@@ -379,7 +410,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                                        delete this._playForDuration;\r
                                };\r
 \r
-                           if( !this.playing ){\r
+                           if( !this.playing || forcePlay ){\r
                                    if( X_UA[ 'Chrome' ] ){ // [CHROME][FIX] volume TODO どの version で 修正される?\r
                                        // [!] delay\r
                                        X_Timer_once( 0, this, this._fixForChrome );\r
@@ -423,7 +454,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
 \r
                        !this[ '_rawObject' ].error && this[ '_rawObject' ].pause();\r
                        \r
-                       if( X_Audio_HTMLAudioWrapper_durationFix ){\r
+                       if( X_Audio_HTMLAudioWrapper_durationFix && X_UA[ 'Opera' ] ){\r
                                this[ '_rawObject' ].src = '';\r
                                // load();\r
                        };\r
@@ -492,41 +523,6 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){
                 *  - FireFox3.6, Android 2.3.6については、src変更後、load()を呼び出さないと切り替わらなかった。iPhoneはload()が不要。\r
                 */     \r
                        detect : function( proxy, source, ext ){\r
-                               /*\r
-                               var ok, mineType = 'audio/' + ext;\r
-                               switch( ext ){\r
-                                       case 'mp3' :\r
-                                               ok = X_UA[ 'IE' ] || X_UA[ 'Chrome' ] || ( X_UA[ 'Windows' ]  && X_UA[ 'Safari' ]  );\r
-                                               mineType = 'audio/mpeg';\r
-                                               //if( X_UA[ 'Android' ] && X_UA[ 'Gecko' ] ) mineType = '';\r
-                                               break;\r
-                                       case 'ogg' :\r
-                                               ok = 15 <= X_UA[ 'Gecko' ] || X_UA[ 'Chrome' ] || X_UA[ 'Opera' ] ;\r
-                                               if( X_UA[ 'AndroidBrowser' ] ) mineType = '';\r
-                                               break;\r
-                                       case 'm4a' :\r
-                                               ok = X_UA[ 'IE' ] || X_UA[ 'WebKit' ];\r
-                                               mineType = 'audio/mp4';\r
-                                               break;\r
-                                       case 'webm' :\r
-                                               ok = 2 <= X_UA[ 'Gecko' ] || 10.6 <= X_UA[ 'Opera' ] ; // firefox4+(Gecko2+)\r
-                                               break;\r
-                                       case 'wav' :\r
-                                               ok = X_UA[ 'Gecko' ] || X_UA[ 'Opera' ] || ( X_UA[ 'Windows' ]  && X_UA[ 'Safari' ]  );\r
-                                               //mineType = 'audio/wav'; // audio/x-wav ?\r
-                                               break;\r
-                                       default :\r
-                                               mineType = '';\r
-                               };\r
-                               \r
-                               if( !ok && mineType ){\r
-                                       if( !X_Audio_rawAudio ) X_Audio_rawAudio = new Audio;\r
-                                       ok = X_Audio_rawAudio.canPlayType( mineType );\r
-                                       //console.log( 'HTML Audio ' + ok + ' ext:' + ext );\r
-                               };\r
-                               console.log( 'HTML Audio ' + ok + ' ext:' + ext );\r
-                               */\r
-                               \r
                                proxy[ 'asyncDispatch' ]( { type : X_EVENT_COMPLETE, canPlay : X_Audio_codecs[ ext ] } );\r
                        },\r
                        \r
index ac5b19e..53f5ed0 100644 (file)
@@ -5,12 +5,17 @@
  * iframe 内で生成して、Audio Sprite の preset で再生できないか?\r
  */\r
 var X_Audio_Sprite_shouldUse        = window.HTMLAudioElement && ( X_UA[ 'iOS' ] || X_UA[ 'AndroidBrowser' ] || X_UA[ 'OperaMobile' ] || X_UA[ 'OperaTablet' ] ), // Flash がない\r
-       X_Audio_Sprite_useVideoForMulti = 4 <= X_UA[ 'AndroidBrowser' ] && 534.3 < X_UA[ 'AndroidWebkit' ], // ドスパラパッドはビデオのインライン再生が不可 \r
-       X_Audio_Sprite_needTouchAndroid = X_Audio_Sprite_useVideoForMulti,      \r
+       X_Audio_Sprite_useVideoForMulti = //( X_UA[ 'AndroidBrowser3' ] && 3.1 <= X_UA[ 'AndroidBrowser' ] ) || \r
+                                                                         //( ( 4.2 <= X_UA[ 'AndroidBrowser' ] || ( 4.1 <= X_UA[ 'AndroidBrowser' ] && 2 <= X_UA[ 'AndroidPatch' ] ) ) && X_UA[ 'AndroidWebkit' ] <= 534.3 ),\r
+                                                                         // ドスパラパッドはビデオのインライン再生が不可, 534.30 で Webkit系は終了, 次は 537.36 で Chrome系\r
+                                                                         false, //X_UA[ 'AndroidChromeBrowser' ],\r
+       X_Audio_Sprite_needTouchAndroid = X_UA[ 'AndroidChromeBrowser' ] && !X_Audio_WebAudioWrapper,\r
        X_Audio_Sprite_needTouchFirst   = X_UA[ 'iOS' ] || X_Audio_Sprite_needTouchAndroid || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ),\r
-       X_Audio_Sprite_enableMultiTrack = !( X_UA[ 'iOS' ] && !X_Audio_WebAudio_context ) && !( X_UA[ 'AndroidBrowser4' ] && X_UA[ 'AndroidWebkit' ] <= 534.3 ) && !( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ),\r
+       X_Audio_Sprite_disableMultiTrack = ( X_UA[ 'iOS' ] && !X_Audio_WebAudio_context ) || ( !X_UA[ 'AndroidChromeBrowser' ] && X_UA[ 'AndroidBrowser4' ] ) || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ),\r
        X_Audio_Sprite_enableVolume     = window.HTMLAudioElement && ( !X_UA[ 'iOS' ] && !X_UA[ 'AndroidBrowser' ] && !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] ), // TODO fennec は 25以上\r
-       X_Audio_Sprite_maxTracks        = !X_Audio_Sprite_enableMultiTrack ? 1 : X_Audio_Sprite_useVideoForMulti ? 2 : 9,\r
+       // http://tukumemo.com/html5-audio-sp/\r
+       // iOS6、Android4.1から同時再生が可能になりました。\r
+       X_Audio_Sprite_maxTracks        = X_Audio_Sprite_useVideoForMulti ? 2 : X_Audio_Sprite_disableMultiTrack ? 1 : 9,\r
        X_Audio_Sprite_lengthSilence    = 10000, // 一番最初の無音部分の長さ\r
        X_Audio_Sprite_lengthDistance   = 5000,  // 音間の無音の長さ\r
        X_Audio_Sprite_uid              = 0,\r
@@ -54,6 +59,12 @@ X[ 'AudioSprite' ] = function( setting ){
        \r
        n = n <= X_Audio_Sprite_maxTracks ? n : X_Audio_Sprite_maxTracks;\r
        \r
+       // TODO\r
+       // Android4.x標準ブラウザ(Chrome系)でブラウザが隠れた場合に音が鳴り続ける問題、ビデオで解決できる?\r
+       //if( X_Audio_Sprite_needTouchAndroid && n === 1 ){\r
+       //      video = true;\r
+       //};\r
+       \r
        for( k in setting ){\r
                v = setting[ k ];\r
                if( X_Type_isArray( v ) && v !== urls ){\r
@@ -80,7 +91,7 @@ X[ 'AudioSprite' ] = function( setting ){
 \r
 X[ 'AudioSprite' ][ 'shouldUse'        ] = X_Audio_Sprite_shouldUse;\r
 X[ 'AudioSprite' ][ 'needTouchFirst'   ] = X_Audio_Sprite_needTouchFirst;\r
-X[ 'AudioSprite' ][ 'enableMultiTrack' ] = X_Audio_Sprite_enableMultiTrack;\r
+X[ 'AudioSprite' ][ 'enableMultiTrack' ] = !X_Audio_Sprite_disableMultiTrack;\r
 \r
 // 再生が終わっているもの、終わりかけのものを探す\r
 // TODO 終わりかけのもの、と一番古いもの、どちらを再利用するか?これ以上に細かい実装を望む場合は X.Audio.Sprite は使わず自力で実装\r
@@ -130,7 +141,13 @@ X_Audio_Sprite_members = {
                'load' : function(){\r
                        var tracks = X_Audio_Sprite_TEMP.tracks,\r
                                i = 0, l = tracks.length;\r
+\r
                        for( ; i < l; ++i ){\r
+                               if( X_Audio_Sprite_needTouchAndroid ){\r
+                                       console.log( '[duration fix]開始 - ' + tracks[ i ][ '_rawObject' ].duration );\r
+                                       tracks[ i ]._playForDuration = 1;\r
+                                       tracks[ i ][ '_rawObject' ].play();\r
+                               } else\r
                                if( X_UA[ 'WinPhone' ] ){\r
                                        console.log( 'WinPhone : touch -> play()' );\r
                                        //tracks[ i ].play( 0, X_Audio_Sprite_lengthSilence, true, 0, X_Audio_Sprite_lengthSilence ).seek( 0 );\r
@@ -142,7 +159,7 @@ X_Audio_Sprite_members = {
                },\r
                \r
                /*\r
-                * @return uid Number\r
+                * @return {number} uid\r
                 */\r
                'play' : function( name ){\r
                        var bgm     = X_Audio_Sprite_TEMP.bgmTrack,\r
@@ -309,6 +326,7 @@ function X_AudioSprite_backendHandler( e ){
                        for( i = 0; i < X_Audio_Sprite_numTracks; ++i ){\r
                                if( X_Audio_Sprite_useVideo || ( i === 1 && X_Audio_Sprite_useVideoForMulti ) ){\r
                                        option[ 'useVideo' ] = true;\r
+                                       console.log( 'use video' );\r
                                };\r
                                // Audiobackend の owner として null を渡すとAudioBackend 自身へ dispatch する\r
                                X_Audio_Sprite_TEMP.tracks.push( last = backend.klass( null, e[ 'source' ], option ) );\r
@@ -338,7 +356,7 @@ function X_AudioSprite_backendHandler( e ){
                        last[ 'listenOnce' ]( X_EVENT_READY, this, X_AudioSprite_backendHandler );\r
 \r
                        // READY, needTouchForPlay, needTouchForLoad\r
-                       if( X_Audio_HTMLAudioWrapper_durationFix ){\r
+                       if( X_Audio_HTMLAudioWrapper_durationFix && !X_Audio_Sprite_needTouchFirst ){\r
                                for( i = 0; i < X_Audio_Sprite_TEMP.tracks.length; ++i ){\r
                                        this[ 'pause' ]( i );\r
                                };\r
@@ -352,15 +370,15 @@ function X_AudioSprite_backendHandler( e ){
                        return X_CALLBACK_STOP_NOW;\r
                \r
                case X_EVENT_READY :\r
-                       console.log( 'X.AudioSprite - Ready!' );\r
-                       \r
                        if( X_Audio_Sprite_needTouchAndroid ){\r
                                for( i = 0; i < X_Audio_Sprite_TEMP.tracks.length; ++i ){\r
                                        this[ 'pause' ]( i );\r
                                };\r
-                               e.target[ 'listenOnce' ]( X_EVENT_MEDIA_PLAYING, this, this[ 'asyncDispatch' ], [ X_EVENT_READY ] ); // Android 標準ブラウザ\r
+                               e.target[ 'listenOnce' ]( X_EVENT_MEDIA_PLAYING, this, this[ 'asyncDispatch' ], [ X_EVENT_READY ] );\r
                                return;\r
                        };\r
+                       \r
+                       console.log( 'X.AudioSprite - Ready!' );\r
                        this[ 'asyncDispatch' ]( X_EVENT_READY );\r
                        break;\r
        };\r
diff --git a/0.6.x/js/11_hid/01_KB.js b/0.6.x/js/11_hid/01_KB.js
new file mode 100644 (file)
index 0000000..584cf0a
--- /dev/null
@@ -0,0 +1,318 @@
+/*\r
+ * JavaScript : Opera と Firefox でのキーイベントの違い\r
+ * http://blog.livedoor.jp/tzifa/archives/50776590.html\r
+ *  keydown について。Firefox では押している間中リスナの関数が実行される\r
+ *  デフォルトイベントの制御・抑止 (opera)keypress を用いる。\r
+ * \r
+ * キーイベント処理の工夫\r
+ * http://www.keynavi.net/ja/tipsj/kfunc.html\r
+ *  keydown/up時にピリオドが文字化け (IE4-6) IE4+では「keypress」でキーコードを処理する 但しCtrlやALTが押されている場合は逆にkeydownで処理する必要があります\r
+ * \r
+ * \r
+ * keydown をトリガーにイベントを発火するもの\r
+ *  1. テンキーの 0~9 keyCode:96-105\r
+ *  2. ScrollLock:145, Ins:45, PuaseBreak:19, HOME:36, PageUp:33, del:46, END:35, PageDown:34,\r
+ *     ←↑→↓:37-40, tab:9, capsLock:240or208, Shift+capslock:20, shift:16, ctrl:17, LWIN:91, BS:8,\r
+ *    \r
+ *  3. RWIN:92!(Opera<9.5), alt:18, [F1]-[F12]:112-123\r
+ * \r
+ */\r
+\r
+var X_KB_TABLE     = {\r
+               specials : {\r
+                       '96'   : 48,\r
+                       '97'   : 49,\r
+                       '98'   : 50,\r
+                       '99'   : 51,\r
+                       '100'  : 52,\r
+                       '101'  : 53,\r
+                       '102'  : 54,\r
+                       '103'  : 55,\r
+                       '104'  : 56,\r
+                       '105'  : 57,\r
+\r
+                       '8'    : 'BS',\r
+                       '9'    : 'TAB',\r
+                       '13'   : 'ENTER',\r
+                       '16'   : 'SHIFT',\r
+                       '17'   : 'CTRL',\r
+                       '18'   : 'ALT',\r
+                       '19'   : 'PAUSE_BREAK',\r
+                       '20'   : 'SHIFT+CAPS_LOCK',\r
+                       \r
+                       '27'   : 'ESC',\r
+                       '28'   : 'trans',\r
+                       '29'   : 'no trans',\r
+                       \r
+                       '33'  : 'PAGE_UP',\r
+                       '34'  : 'PAGE_DOWN',\r
+                       '35'  : 'END',\r
+                       '36'  : 'HOME', \r
+                       '37'  : 'CSR_L',\r
+                       '38'  : 'CSR_U',\r
+                       '39'  : 'CSR_R',\r
+                       '40'  : 'CSR_D',\r
+                       '45'  : 'INS',\r
+                       '44'  : 'PRT_SCRN',\r
+                       '46'  : 'DEL',\r
+                       \r
+                       '91'  : 'LWIN',\r
+                       '92'  : 'RWIN',\r
+                       '93'  : 'APP',\r
+                       \r
+                       '106' : 42,\r
+                       '107' : 43,\r
+                       '109' : 45,\r
+                       '111' : 47,\r
+                       '112' : 'F1',\r
+                       '113' : 'F2',\r
+                       '114' : 'F3',\r
+                       '115' : 'F4',\r
+                       '116' : 'F5',\r
+                       '117' : 'F6',\r
+                       '118' : 'F7',\r
+                       '119' : 'F8',\r
+                       '120' : 'F9',\r
+                       '121' : 'F10',\r
+                       '122' : 'F11',\r
+                       '123' : 'F12',\r
+\r
+                       '144' : 'NUM_LOCK',\r
+                       '145' : 'SCROLL_LOCK',\r
+                       '208' : 'CAPS_LOCK',\r
+                       '240' : 'CAPS_LOCK',\r
+                       '242' : 'K/H',\r
+                       '243' : 'H/Z',\r
+                       '244' : 'H/Z'\r
+                       \r
+               },\r
+       // keypress 時に keyCode を直す 0 の場合、イベント発火せず。どのキーが押されたか?判定できないため\r
+               'keypress' : {\r
+                       // !-):33-41, *:42, +:43, ,:44, -:45, .:46, /:47, 0-9:48-57 , ::58 , ;:59 , <:60 , =:61, >:62, ?:63, @:64\r
+                       // A-Z:65-90, [:91, \:92, ]:93, ^:94, _:95, `:96, a-z:97-122, {:123, |:124, }:125, ~:126\r
+               },\r
+               \r
+               'keyup' : {\r
+                       '189' : '45,61', // ie, safari\r
+                       '109' : '45,61', // firefox, opera\r
+                       \r
+                       '222' : '94,126', // firefox, ie, safari\r
+                       '94'  : '94,126', // opera\r
+\r
+                       '226' : '92,95', // firefox, ie, safari,\r
+                       '220' : 9.5 <= X_UA[ 'Opera' ] ? '92,95,124' : '92,124', // firefox, ie, safari, opera9.50+\r
+                       '92'  : '92,95,124', // opera9.25\r
+                       \r
+                       '192' : '64,96', // firefox, ie, safari\r
+                       '64'  : '64,96', // opera\r
+                       \r
+                       '219' : '91,123', // firefox, ie, safari, opera9.50+\r
+                       '91'  : '91,123', // opera9.25\r
+                       \r
+                       '187' : '59,43', // ie, safari\r
+                       '61'  : '59,43', // firefox, opera\r
+                       \r
+                       '186' : '58,42', // ie, safari\r
+                       '59'  : '58,42', // firefox, opera\r
+                       \r
+                       '221' : '93,125', // firefox, ie, safari, opera9.50+\r
+                       '93'  : '93,125', // opera9.25\r
+                       \r
+                       '188' : '44,60', // firefox, ie, safari, opera9.50+\r
+                       '44'  : '44,60', // opera9.25\r
+                       \r
+                       '190' : '46,62', // firefox, ie, safari, opera9.50+\r
+                       '46'  : '46,62', // opera9.25\r
+                       \r
+                       '191' : '47,63', // firefox, ie, safari, opera9.50+\r
+                       '47'  : '47,63' // opera9.25\r
+               }\r
+       },\r
+       X_KB_DOWN_KEYS   = {},\r
+       X_KB_CANCELED    = {},\r
+       X_KB_lastIs10Key = 0,\r
+       X_KB_lastKeyCode = 0, \r
+       X_KB_TRANSFOEM   = {},\r
+       \r
+       X_kbManager    =\r
+               X_Class_override(\r
+                       X_EventDispatcher(),\r
+                       {       \r
+                               handleEvent : function( e ){\r
+                                       var keyCode = e.keyCode,  // keyCode says something about the actual keyboard key the user pressed\r
+                                               chrCode = e.charCode, // while charCode gives the ASCII value of the resulting character\r
+                                               cb      = X_CALLBACK_NONE,\r
+                                               special, is10Key, _keyCode;\r
+                                       \r
+                                       console.log( e.type + ' > keyCode:' + keyCode + ' chrCode:' + chrCode );\r
+                                       \r
+                                       switch( e.type ){\r
+                                               case 'keydown' :\r
+\r
+                                                       if( X_KB_DOWN_KEYS[ keyCode ] ){\r
+                                                               // 既に押されている、メタキー[shift,ctrl,alt]の変化はある?\r
+                                                               return cb;\r
+                                                       } else\r
+                                                       if( special = X_KB_TABLE.specials[ keyCode ] ){\r
+                                                               \r
+                                                               if( X_Type_isNumber( special ) ){\r
+                                                                       // テンキーの [0]~[9]\r
+                                                                       //chrCode = special;\r
+                                                                       X_KB_lastKeyCode  = keyCode;\r
+                                                                       X_KB_lastIs10Key = true;\r
+                                                                       return cb;\r
+                                                               } else {\r
+                                                                       X_KB_DOWN_KEYS[ keyCode ] = true;\r
+                                                                       chrCode = 0;\r
+                                                               };\r
+                                                               \r
+                                                               cb = this[ 'dispatch' ]( {\r
+                                                                       type     : 'keydown',\r
+                                                                       keyCode  : keyCode,\r
+                                                                       charCode : chrCode,\r
+                                                                       keyName  : X_Type_isString( special ) ? special : '',\r
+                                                                       is10key  : !!is10Key,\r
+                                                                       shiftKey : !!X_KB_DOWN_KEYS[ 16 ],\r
+                                                                       ctrlKey  : !!X_KB_DOWN_KEYS[ 17 ],\r
+                                                                       altKey   : !!X_KB_DOWN_KEYS[ 18 ],\r
+                                                                       metaKey  : !!X_KB_DOWN_KEYS[ 224 ]\r
+                                                               } );\r
+                                                               \r
+                                                               if( cb & X_CALLBACK_PREVENT_DEFAULT ){\r
+                                                                       X_KB_CANCELED[ keyCode ] = true;\r
+                                                               };\r
+                                                       } else {\r
+                                                               X_KB_lastKeyCode = keyCode;\r
+                                                       };\r
+\r
+                                                       return cb;\r
+                                                       \r
+                                               case 'keypress' :\r
+                                                       // keydown 側で発火しているものは再び発火しない\r
+                                                       console.log( 'kp : ' + X_KB_DOWN_KEYS[ chrCode ] + ( X_KB_CANCELED[ chrCode ] ? ' Cancel!' : '' ) );\r
+                                                       if( X_KB_DOWN_KEYS[ chrCode ] ){\r
+                                                               return X_KB_CANCELED[ chrCode ] ? X_CALLBACK_PREVENT_DEFAULT : cb;\r
+                                                       };\r
+\r
+                                                       if( 33 <= chrCode && chrCode <= 126 ){\r
+                                                               X_KB_TRANSFOEM[ X_KB_lastKeyCode ] = chrCode;\r
+                                                               \r
+                                                               cb = this[ 'dispatch' ]( {\r
+                                                                       type     : 'keydown',\r
+                                                                       keyCode  : X_KB_lastIs10Key ? X_KB_lastKeyCode : 0,\r
+                                                                       charCode : chrCode,\r
+                                                                       is10key  : X_KB_lastIs10Key,\r
+                                                                       shiftKey : !!X_KB_DOWN_KEYS[ 16 ],\r
+                                                                       ctrlKey  : !!X_KB_DOWN_KEYS[ 17 ],\r
+                                                                       altKey   : !!X_KB_DOWN_KEYS[ 18 ],\r
+                                                                       metaKey  : !!X_KB_DOWN_KEYS[ 224 ]\r
+                                                               } );\r
+                                                               \r
+                                                               X_KB_lastIs10Key = true;\r
+                                                       };\r
+                                                       return cb;\r
+                                                       \r
+                                               case 'keyup' :\r
+                                                       if( X_KB_CANCELED[ keyCode ] ){\r
+                                                               cb = X_CALLBACK_PREVENT_DEFAULT;\r
+                                                       };\r
+                                               \r
+                                                       if( ( special = X_KB_TABLE.specials[ keyCode ] ) && ( !X_KB_DOWN_KEYS[ keyCode ] && !X_KB_DOWN_KEYS[ special ] ) ){\r
+                                                               cb |= this[ 'dispatch' ]( {\r
+                                                                       type      : 'keydown',\r
+                                                                       keyCode   : keyCode,\r
+                                                                       charCode  : 0,\r
+                                                                       keyName   : special,\r
+                                                                       is10key   : false,\r
+                                                                       isVirtual : true,\r
+                                                                       shiftKey  : !!X_KB_DOWN_KEYS[ 16 ],\r
+                                                                       ctrlKey   : !!X_KB_DOWN_KEYS[ 17 ],\r
+                                                                       altKey    : !!X_KB_DOWN_KEYS[ 18 ],\r
+                                                                       metaKey   : !!X_KB_DOWN_KEYS[ 224 ]\r
+                                                               } );\r
+                                                       };\r
+                                               \r
+                                                       if( X_KB_DOWN_KEYS[ keyCode ] ) delete X_KB_DOWN_KEYS[ keyCode ];\r
+                                                       if( X_KB_CANCELED[ keyCode ]  ) delete X_KB_CANCELED[ keyCode ];\r
+                                                       \r
+                                                       chrCode = 0;\r
+                                                       if( !special ){\r
+                                                               chrCode = X_KB_TRANSFOEM[ keyCode ];\r
+                                                               if( !chrCode ) return cb;\r
+                                                               delete X_KB_TRANSFOEM[ keyCode ];\r
+                                                               //keyCode = 0;\r
+                                                       };\r
+                                               \r
+                                                       cb |= this[ 'dispatch' ]( {\r
+                                                               type     : 'keyup',\r
+                                                               keyCode  : keyCode,\r
+                                                               charCode : chrCode,\r
+                                                               keyName  : X_Type_isString( special ) ? special : '',\r
+                                                               shiftKey : X_KB_DOWN_KEYS[ 16 ],\r
+                                                               ctrlKey  : X_KB_DOWN_KEYS[ 17 ],\r
+                                                               altKey   : X_KB_DOWN_KEYS[ 18 ],\r
+                                                               metaKey  : X_KB_DOWN_KEYS[ 224 ]\r
+                                                       } );\r
+\r
+                                                       return cb;\r
+                                               \r
+                                               case X_EVENT_VIEW_ACTIVATE :\r
+                                                       //\r
+                                                       break;\r
+                                               case X_EVENT_VIEW_DEACTIVATE :\r
+                                                       //\r
+                                                       break;  \r
+                                       };\r
+                               }\r
+                       }\r
+               ),\r
+\r
+/**\r
+ * キーボードイベント情報を提供するオブジェクト。\r
+ * @namespace X.KB\r
+ * @alias X.KB\r
+ */\r
+       X_KB = X[ 'KB' ] = {\r
+               /**\r
+                * \r
+                * @alias X.KB.listen\r
+                */\r
+               'listen' : function( type, arg1, arg2, arg3 ){\r
+                       type && arg1 && X_kbManager[ 'listen' ]( type, arg1, arg2, arg3 );\r
+                       return X_KB;\r
+               },\r
+               \r
+               /**\r
+                * \r
+                * @alias X.KB.listenOnce\r
+                */\r
+               'listenOnce' : function( type, arg1, arg2, arg3 ){\r
+                       type && arg1 && X_kbManager[ 'listenOnce' ]( type, arg1, arg2, arg3 );\r
+                       return X_KB;\r
+               },\r
+               \r
+               /**\r
+                * \r
+                * @alias X.KB.unlisten\r
+                */\r
+               'unlisten' : function( type, arg1, arg2, arg3 ){\r
+                       type && arg1 && X_kbManager[ 'unlisten' ]( type, arg1, arg2, arg3 );\r
+                       return X_KB;\r
+               },\r
+               \r
+               /**\r
+                * \r
+                * @alias X.KB.listening\r
+                */\r
+               'listening' : function( type, arg1, arg2, arg3 ){\r
+                       return X_kbManager[ 'listening' ]( type, arg1, arg2, arg3 );\r
+               }\r
+       };\r
+\r
+X_ViewPort[ 'listen' ]( [ X_EVENT_VIEW_ACTIVATE, X_EVENT_VIEW_DEACTIVATE ], X_kbManager );\r
+\r
+if( X_UA[ 'IE' ] < 9 ){\r
+       X_ViewPort_document[ 'listen' ]( [ 'keyup', 'keydown', 'keypress' ], X_kbManager );\r
+} else {\r
+       X_ViewPort[ 'listen' ]( [ 'keyup', 'keydown', 'keypress' ], X_kbManager );\r
+};\r
index 7d9dd92..8063af2 100644 (file)
@@ -64,7 +64,9 @@ document.write( [
                'js/07_audio/01_XWebAudio.js',\r
                'js/07_audio/02_XHTMLAudio.js',\r
                'js/07_audio/03_XSilverlightAudio.js',\r
-               'js/07_audio/10_XAudioSprite.js'\r
+               'js/07_audio/10_XAudioSprite.js',\r
+\r
+               'js/11_hid/01_KB.js'\r
 \r
        + '"></script>'\r
 ].join( '"></script><script src="' + basePath ));\r