From: itozyun Date: Wed, 11 Mar 2015 12:26:24 +0000 (+0900) Subject: Version 0.6.133, fix for closure compiler - ADVANCED_OPTIMIZATIONS X-Git-Url: http://git.osdn.jp/view?p=pettanr%2FclientJs.git;a=commitdiff_plain;h=a130cabd01fde8865990a59d849f5d5d08ed2119 Version 0.6.133, fix for closure compiler - ADVANCED_OPTIMIZATIONS --- diff --git a/0.6.x/js/01_core/01_X.js b/0.6.x/js/01_core/01_X.js index fabeeeb..28c783c 100644 --- a/0.6.x/js/01_core/01_X.js +++ b/0.6.x/js/01_core/01_X.js @@ -22,17 +22,36 @@ * この意識は常にありましたが、このたび pettanR フレームワークの API ドキュメントを作成するにあたり、それに付記していく形で取り組んでみようと思います。 * *

フレームワークのレイヤー構造について

+ *
\core 以下:javascript の整地を行い大規模開発の基礎を整える
+ *

ブラウザの種類とバージョンを調べ、続いて javascript 自体の差異を埋め、足りない関数を補います。 + *

続いて、ファーストオブジェクトとも呼ばれる function について、その能力を引き出しつつ安心して使えるように、再利用可能クロージャの生成・破棄ができるようにします。 + * ガベージコレクション周りが怪しいブラウザがあるため、クロージャを再利用可能にしておくことは重要です。 + *

javascript が大規模開発に使えるように、クラス定義関数を用意します。prototype 周りの差異やバグを吸収するためにも、クラス定義の共通化は有効です。 + *

このクラス定義関数を用いて EventDispatcher クラスを定義します。ブラウザの提供するイベントターゲットオブジェクトをラップしたり、単にアプリケーション独自のイベントを配信するためにも使えます。 + * フレームワークの各所でサブクラスや単にインスタンスを拡張して使われています。フレームワークの API 設計の性格を決めている、とても重要なクラスです。 + * 再利用可能クロージャや、タイマー(setTimeout のラッパー) とも密に結合しています。 * + *

\dom 以下:DHTML の差異を吸収し、非同期化された仮想 Node を提供する
+ *

jQuery ライクな構文で DOM ツリーの操作を行います。チェーンメソッドは速い、と聞きかじったのでこのデザインにしました。 + *

Real DOM の操作は非同期に行われるため高速です。Virtual DOM 時代のライバル達にひけをとることはありません。 + *

10 年後の変化に対応するため、確かな抽象化実装を行う。それを証明するために 10 年前の環境でも動作させます。 * - * ライブラリは X という名前空間を使用します。 - * @example //ショートハンド + *

\ui 以下:UI フレームワーク
+ *

\dom までで吸収できなかった Web ブラウザの差異を最終的に吸収し、HTML 要素を UI 部品として利用するためのレイヤーです。 + *

この層で吸収できなかった差異に関する情報を提供して、アプリケーションに UI をグレースフルグラデーションするための情報を提供します。 + *

任意の UI を実現するための最適な HTML タグ構造がブラウザ毎に異なる場合に、その差異をカプセル化します。 + *

Web ブラウザ自体のレンダリングコストを最小にし、高速な UI 部品を提供するために、独自のレイアウトルールを持ちます。 + *

フォントサイズをベースとしたレイアウト指定のため、レスポンシブな画面作りを後押しします。 + * + * @example // ライブラリは X という名前空間を使用します。 + * //ショートハンド * X( func ) == X.ViewPort.listenOnce(X.Event.XDOM_READY, func); * X('#mydiv') == X.Doc.find('#mydiv'); * @namespace X */ function X( v ){ - if( X.Type.isFunction( v ) ){ - X.ViewPort.listenOnce( X.Event.XDOM_READY, v ); + if( X_Type_isFunction( v ) ){ + X.ViewPort.listenOnce( X_Event[ 'XDOM_READY' ], v ); } else if( X_shortcutFunction ){ return X_shortcutFunction.apply( X_shortcutContext || X, arguments ); @@ -51,6 +70,9 @@ if( !window['console'] || ( window.parent && window.parent.log ) ) } }; //+DEV} +//{-AUDIO +//-AUDIO} + var undefined, X_EMPTY_OBJECT = {}, X_TEMP = { onSystemReady : [] }, diff --git a/0.6.x/js/01_core/02_XUA.js b/0.6.x/js/01_core/02_XUA.js index c0b57f4..7ccefca 100644 --- a/0.6.x/js/01_core/02_XUA.js +++ b/0.6.x/js/01_core/02_XUA.js @@ -2,11 +2,17 @@ // ------------------------------------------------------------------------- // // ------------ local variables -------------------------------------------- // // ------------------------------------------------------------------------- // -var X_UA = (function( n, undefined ){ - var - /** @alias X.UA */ - acme = {}, - dua = n.userAgent, + +/** + * UserAgent の関する定数を保持する。 + * @namespace X.UA + * @alias X.UA + * @type {object} + */ +var X_UA = X[ 'UA' ] = {}; + +(function( n ){ + var dua = n.userAgent, dav = n.appVersion, tv = parseFloat(dav), sys = n.platform, @@ -25,106 +31,124 @@ var X_UA = (function( n, undefined ){ v = dua.split( 'OS ' )[ 1 ].split( '_' ); i = window.devicePixelRatio === 1; - /** @memberof X.UA */ - acme.iOSMajor = parseFloat( v[ 0 ] ) || 0; - /** @memberof X.UA */ - acme.iOSMinor = parseFloat( v[ 1 ] ) || 0; - /** @memberof X.UA */ - acme.iOSPatch = parseFloat( v[ 2 ] ) || 0; - /** @memberof X.UA */ - acme.iOS = acme.iOSMajor + acme.iOSMinor / 10; + /** + * @alias X.UA.iOSMajor + * @type {number} + */ + X_UA[ 'iOSMajor' ] = parseFloat( v[ 0 ] ) || 0; + /** + * @alias X.UA.iOSMinor + * @type {number} + */ + X_UA[ 'iOSMinor' ] = parseFloat( v[ 1 ] ) || 0; + /** + * @alias X.UA.iOSPatch + * @type {number} + */ + X_UA[ 'iOSPatch' ] = parseFloat( v[ 2 ] ) || 0; + /** + * @alias X.UA.iOS + * @type {number} + */ + X_UA[ 'iOS' ] = X_UA[ 'iOSMajor' ] + X_UA[ 'iOSMinor' ] / 10; if( screen.width === screen.height * 1.5 || screen.width * 1.5 === screen.height ){ v = true; // 4:3 model }; if( sys === 'iPhone' ){ - /** @memberof X.UA */ - acme.iPhone = true; + /** + * @alias X.UA.iPhone + * @type {boolean} + */ + X_UA[ 'iPhone' ] = true; if( v ){ /** iPhone4s以下 * @memberof X.UA */ - acme.iPhone_4s = true; + X_UA[ 'iPhone_4s' ] = true; }; if( v && i ){ - /** iPhone3GS以下 - * @memberof X.UA */ - acme.iPhone_3GS = true; + /** + * iPhone3GS以下 + * @alias X.UA.iPhone_3GS + * @type {boolean} + */ + X_UA[ 'iPhone_3GS' ] = true; }; - //alert( 'iPhone ' + ( acme.iPhone_3GS ? '3GS以下' : acme.iPhone_4s ? '4s以下' : '5以上' ) ); + //alert( 'iPhone ' + ( X_UA[ 'iPhone_3GS' ] ? '3GS以下' : X_UA[ 'iPhone_4s' ] ? '4s以下' : '5以上' ) ); }; if( sys === 'iPad' ){ /** @memberof X.UA */ - acme.iPad = true; + X_UA[ 'iPad' ] = true; if( i ){ /** * iPad2以下または初代iPad mini 以下 * @memberof X.UA */ - acme.iPad_2Mini1 = true; + X_UA[ 'iPad_2Mini1' ] = true; }; }; if( sys === 'iPod' ){ /** @memberof X.UA */ - acme.iPod = true; + X_UA[ 'iPod' ] = true; if( v && i ){ /** * iPod3以下 * @memberof X.UA */ - acme.iPod_3 = true; + X_UA[ 'iPod_3' ] = true; }; if( v ){ /** * iPod4以下 * @memberof X.UA */ - acme.iPod_4 = true; + X_UA[ 'iPod_4' ] = true; }; - //alert( 'iPod touch ' + ( acme.iPod_3 ? '3以下' : acme.iPod_4 ? '4以下' : '5以上' ) ); + //alert( 'iPod touch ' + ( X_UA[ 'iPod_3' ] ? '3以下' : X_UA[ 'iPod_4' ] ? '4以下' : '5以上' ) ); }; - console.log( '>> iOS : ' + acme.iOS ); + console.log( '>> iOS : ' + X_UA[ 'iOS' ] ); } else if( dua.indexOf( 'hp-tablet' ) !== -1 || dua.indexOf( 'webOS' ) !== -1 ){ // http://user-agent-string.info/list-of-ua/os-detail?os=webOS /** @memberof X.UA */ - acme.webOS = true; // webOS + X_UA[ 'webOS' ] = true; // webOS } else if( sys.indexOf( 'Win' ) + 1 ){ console.log( 'Win' ); /** @memberof X.UA */ - acme.Windows = true; + X_UA[ 'Windows' ] = true; switch( sys ){ case 'Win16' : case 'Win32' : case 'Win64' : case 'WinCE' : - acme[ sys ] = true; + X_UA[ sys ] = true; }; // winRT } else if( sys.indexOf( 'Mac' ) + 1 ){ console.log( 'Mac' ); /** @memberof X.UA */ - acme.Mac = true; + X_UA[ 'Mac' ] = true; switch( sys ){ case 'MacPowerPC' : /** @memberof X.UA */ - acme.MacPPC = true; + X_UA[ 'MacPPC' ] = true; break; case 'MacPPC' : case 'Mac68K' : case 'MacIntel' : - acme[ sys] = true; + X_UA[ sys ] = true; }; } else if( ( sys.indexOf( 'Linux' ) + 1 ) || ( sys.indexOf( 'Android' ) + 1 ) ){ console.log( 'Linux' ); /** @memberof X.UA */ - acme.Linux = true; + X_UA[ 'Linux' ] = true; if( ( i = dua.indexOf( 'Android' ) ) !== -1 ){ /** @memberof X.UA */ - acme.Android = parseFloat( dua.substr( i + 8 ) ) || 0.1; // Firefox で Version が取れない! - console.log( '>> Android : ' + acme.Android ); + X_UA[ 'Android' ] = parseFloat( dua.substr( i + 8 ) ) || 0.1; // Firefox で Version が取れない! + console.log( '>> Android : ' + X_UA[ 'Android' ] ); }; }; @@ -141,93 +165,93 @@ Sleipnir Mobile Android 2.1以上 Fenrir i = dua.indexOf( 'Opera' ); // Opera/ j = dua.indexOf( 'Version/' ); /** @memberof X.UA */ - acme.Opera = Math.max( + X_UA[ 'Opera' ] = v = Math.max( i !== -1 ? parseFloat( dua.substr( i + 6 ) ) : 0, j !== -1 ? parseFloat( dua.substr( j + 8 ) ) : 0, tv ); // closure compiler で minify するとOpera7で動かない // --compilation_level WHITESPACE_ONLY --formatting pretty_print <- 動く /** @memberof X.UA */ - acme.Opera7 = acme.Opera < 8; + X_UA[ 'Opera7' ] = v < 8; /** @memberof X.UA */ - acme.Opera78 = acme.Opera < 9; + X_UA[ 'Opera78' ] = v < 9; /** @memberof X.UA */ - acme.OperaMini = 0 < dua.indexOf('Opera Mini'); + X_UA[ 'OperaMini' ] = 0 < dua.indexOf('Opera Mini'); /** @memberof X.UA */ - acme.OperaMobile = 0 < dua.indexOf('Opera Mobi'); + X_UA[ 'OperaMobile' ] = 0 < dua.indexOf('Opera Mobi'); /** @memberof X.UA */ - acme.OperaTablet = 0 < dua.indexOf('Opera Tablet'); + X_UA[ 'OperaTablet' ] = 0 < dua.indexOf('Opera Tablet'); /** @memberof X.UA */ - acme.Wii = dua.indexOf( 'Nintendo Wii' ) !== -1; + X_UA[ 'Wii' ] = dua.indexOf( 'Nintendo Wii' ) !== -1; /** @memberof X.UA */ - acme.NDS = dua.indexOf( 'Nitro' ) !== -1; - console.log( '>> Opera : ' + acme.Opera ); - return acme; + X_UA[ 'NDS' ] = dua.indexOf( 'Nitro' ) !== -1; + console.log( '>> Opera : ' + v ); + return; }; // Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko if( document.all || dav.indexOf( 'Trident/' ) !== -1 ){ /** @memberof X.UA */ - acme.ActiveX = !!window[ 'ActiveXObject' ]; + X_UA[ 'ActiveX' ] = !!window[ 'ActiveXObject' ]; /** * documentモードを考慮しないIEのバージョン * @memberof X.UA * @type {number}*/ - acme._IE = parseFloat(dua.split('MSIE ')[1]) || parseFloat(dua.split('rv:')[1]) || parseFloat(dav.split('MSIE ')[1]) || 0; - // IE11 の互換モードの dav にも Trident/7.0 が書かれているため互換モードか?判定ができる + X_UA[ '_IE' ] = parseFloat(dua.split('MSIE ')[1]) || parseFloat(dua.split('rv:')[1]) || parseFloat(dav.split('MSIE ')[1]) || 0; + // IE11 の互換モードの dav にも Trident/7.0 が書かれているため互換モードか?判定ができる // 互換モードでは Silverlight でエラーが出る? /** @memberof X.UA */ - acme.Trident = parseFloat(dav.split('Trident/')[1]) || 0; + X_UA[ 'Trident' ] = parseFloat(dav.split('Trident/')[1]) || 0; /** * documentモードを考慮したIEのバージョン * @memberof X.UA */ - acme.IE = document.documentMode || acme._IE; - tridentToVer = acme.Trident ? ( acme.Trident + 4 | 0 ) : acme._IE; + X_UA[ 'IE' ] = v = document.documentMode || X_UA[ '_IE' ]; + tridentToVer = X_UA[ 'Trident' ] ? ( X_UA[ 'Trident' ] + 4 | 0 ) : X_UA[ '_IE' ]; /** * IE11 の互換モードを使用しているか? * @memberof X.UA */ - acme.IECompat = /* acme.IE !== acme._IE || */ tridentToVer !== acme._IE && tridentToVer; + X_UA[ 'IECompat' ] = /* v !== X_UA[ '_IE' ] || */ tridentToVer !== X_UA[ '_IE' ] && tridentToVer; /** @memberof X.UA */ - acme.IE4 = acme.IE && acme.IE < 5; + X_UA[ 'IE4' ] = v && v < 5; /** @memberof X.UA */ - acme.IE5678 = 5 <= acme.IE && acme.IE < 9; + X_UA[ 'IE5678' ] = 5 <= v && v < 9; /** @memberof X.UA */ - acme.IE5 = 5 <= acme.IE && acme.IE < 5.5; + X_UA[ 'IE5' ] = 5 <= v && v < 5.5; /** @memberof X.UA */ - acme.IE55 = 5.5 <= acme.IE && acme.IE < 6; + X_UA[ 'IE55' ] = 5.5 <= v && v < 6; /** @memberof X.UA */ - acme.IE5x = acme.IE5 || acme.IE55; + X_UA[ 'IE5x' ] = X_UA[ 'IE5' ] || X_UA[ 'IE55' ]; /** @memberof X.UA */ - acme.IE6 = 6 <= acme.IE && acme.IE < 7; + X_UA[ 'IE6' ] = 6 <= v && v < 7; /** @memberof X.UA */ - acme.IE7 = 7 <= acme.IE && acme.IE < 8; + X_UA[ 'IE7' ] = 7 <= v && v < 8; /** @memberof X.UA */ - acme.IE8 = 8 <= acme.IE && acme.IE < 9; + X_UA[ 'IE8' ] = 8 <= v && v < 9; /** @memberof X.UA */ - acme.IE9 = 9 <= acme.IE && acme.IE < 10; + X_UA[ 'IE9' ] = 9 <= v && v < 10; /** @memberof X.UA */ - acme.MacIE = acme.Mac; + X_UA[ 'MacIE' ] = X_UA[ 'Mac' ]; /** @memberof X.UA */ - acme.IEMobile = dua.toLowerCase().indexOf( 'iemobile' ) !== -1 || acme.WinCE; + X_UA[ 'IEMobile' ] = dua.toLowerCase().indexOf( 'iemobile' ) !== -1 || X_UA[ 'WinCE' ]; /** @memberof X.UA */ - acme.WinPhone = dua.toLowerCase().indexOf( 'windows phone' ) !== -1 || 0 < dav.indexOf( 'ZuneWP' ); // ZuneWP は IEM のデスクトップモードで使用 - console.log( '>> IE : ' + acme.IE + ' ActiveX : ' + acme.ActiveX ); + X_UA[ 'WinPhone' ] = dua.toLowerCase().indexOf( 'windows phone' ) !== -1 || 0 < dav.indexOf( 'ZuneWP' ); // ZuneWP は IEM のデスクトップモードで使用 + console.log( '>> IE : ' + v + ' ActiveX : ' + X_UA[ 'ActiveX' ] ); // TODO XBox360, XBox1, Modern or Desktop, Standalone - return acme; + return; }; // http://qa.support.sony.jp/solution/S0812181056444/common/nfb34_dom_200jp/dom_dom0_JP.html if( ( i = dua.indexOf( 'NetFront\/' ) !== -1 ) ){ /** @memberof X.UA */ - acme.NetFront = parseFloat( dua.substr( i + 9 ) ) || 0.1; - console.log( '>> NetFront : ' + acme.NetFront ); - return acme; + X_UA[ 'NetFront' ] = parseFloat( dua.substr( i + 9 ) ) || 0.1; + console.log( '>> NetFront : ' + X_UA[ 'NetFront' ] ); + return; }; - if( acme.Linux && tv === 2 && dua.indexOf( 'Sony\/COM2\/' ) !== -1 ){ - acme.NetFront = 3.4; - console.log( '>> NetFront : ' + acme.NetFront ); - return acme; + if( X_UA[ 'Linux' ] && tv === 2 && dua.indexOf( 'Sony\/COM2\/' ) !== -1 ){ + X_UA[ 'NetFront' ] = 3.4; + console.log( '>> NetFront : ' + X_UA[ 'NetFront' ] ); + return; }; // http://www.useragentstring.com/pages/Playstation%203/ @@ -239,9 +263,9 @@ Sleipnir Mobile Android 2.1以上 Fenrir /** * PlayStation 3 システムバージョン 4.10 未満の SONY 独自ブラウザ * @memberof X.UA */ - acme.PS3 = parseFloat( dua.substr( i + 15 ) ) || 0.1; - console.log( '>> PS3 : ' + acme.PS3 ); - return acme; + X_UA[ 'PS3' ] = parseFloat( dua.substr( i + 15 ) ) || 0.1; + console.log( '>> PS3 : ' + X_UA[ 'PS3' ] ); + return; }; // http://www.useragentstring.com/pages/iCab/ @@ -249,31 +273,31 @@ Sleipnir Mobile Android 2.1以上 Fenrir // Mozilla/5.0 (Macintosh; U; PPC Mac OS; en) iCab 3 if( ( i = dua.indexOf( 'iCab' ) !== -1 ) ){ /** @memberof X.UA */ - acme.iCab = parseFloat( dua.substr( i + 5 ) ) || 0.1; - console.log( '>> iCab : ' + acme.iCab ); - return acme; + X_UA[ 'iCab' ] = parseFloat( dua.substr( i + 5 ) ) || 0.1; + console.log( '>> iCab : ' + X_UA[ 'iCab' ] ); + return; }; if( 0 < dua.indexOf( 'Gecko\/' ) && ( i = dua.indexOf( 'rv:' ) ) ){ v = dua.substr( i + 3 ).split( '.' ); /** @memberof X.UA */ - acme.Gecko = parseFloat( v[ 0 ] ) || 0 + + X_UA[ 'Gecko' ] = parseFloat( v[ 0 ] ) || 0 + ( parseFloat( v[ 1 ] ) || 0 ) / 10 + ( parseFloat( v[ 2 ] ) || 0 ) / 100; /** @memberof X.UA */ - acme.GeckoMajor = parseFloat( v[ 0 ] ) || 0; + X_UA[ 'GeckoMajor' ] = parseFloat( v[ 0 ] ) || 0; /** @memberof X.UA */ - acme.GeckoMinor = parseFloat( v[ 1 ] ) || 0; + X_UA[ 'GeckoMinor' ] = parseFloat( v[ 1 ] ) || 0; /** @memberof X.UA */ - acme.GeckoPatch = parseFloat( v[ 2 ] ) || 0; + X_UA[ 'GeckoPatch' ] = parseFloat( v[ 2 ] ) || 0; //Fennec // Mozilla/5.0 (Android; Linux armv7l; rv:9.0) Gecko/20111216 Firefox/9.0 Fennec/9.0 if( ( i = dua.indexOf( 'Fennec/' ) ) !== -1 ){ /** @memberof X.UA */ - acme.Fennec = parseFloat( dua.substr( i + 7 ) ); - console.log( '>> Fennec : ' + acme.Fennec + ', Gecko : ' + acme.Gecko ); - return acme; + X_UA[ 'Fennec' ] = parseFloat( dua.substr( i + 7 ) ); + console.log( '>> Fennec : ' + X_UA[ 'Fennec' ] + ', Gecko : ' + X_UA[ 'Gecko' ] ); + return; }; //Firefox @@ -281,116 +305,100 @@ Sleipnir Mobile Android 2.1以上 Fenrir //Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 if( ( i = dua.indexOf( 'Netscape6/' ) ) !== -1 ){ /** @memberof X.UA */ - acme.NN = parseFloat( dua.substr( i + 10 ) ) || 6; + X_UA[ 'NN' ] = parseFloat( dua.substr( i + 10 ) ) || 6; /** @memberof X.UA */ - acme.NN6 = true; - console.log( '>> NN : ' + acme.NN + ', Gecko : ' + acme.Gecko ); - return acme; + X_UA[ 'NN6' ] = true; + console.log( '>> NN : ' + X_UA[ 'NN' ] + ', Gecko : ' + X_UA[ 'Gecko' ] ); + return; } else //Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax) //Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20070321 Netscape/8.1.3 if( ( i = dua.indexOf( 'Netscape/' ) ) !== -1 ){ - acme.NN = parseFloat( dua.substr( i + 9 ) ) || 7; - console.log( '>> NN : ' + acme.NN + ', Gecko : ' + acme.Gecko ); - return acme; + X_UA[ 'NN' ] = parseFloat( dua.substr( i + 9 ) ) || 7; + console.log( '>> NN : ' + X_UA[ 'NN' ] + ', Gecko : ' + X_UA[ 'Gecko' ] ); + return; } else //Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080219 Firefox/2.0.0.12 Navigator/9.0.0.6 if( ( i = dua.indexOf( 'Navigator/' ) ) !== -1 ){ - acme.NN = parseFloat( dua.substr( i + 10 ) ) || 9; - console.log( '>> NN : ' + acme.NN + ', Gecko : ' + acme.Gecko ); - return acme; + X_UA[ 'NN' ] = parseFloat( dua.substr( i + 10 ) ) || 9; + console.log( '>> NN : ' + X_UA[ 'NN' ] + ', Gecko : ' + X_UA[ 'Gecko' ] ); + return; }; - console.log( '>> Gecko : ' + acme.Gecko ); + console.log( '>> Gecko : ' + X_UA[ 'Gecko' ] ); }; // TODO Blink if( window.chrome ){ /** @memberof X.UA */ - acme.Blink = tv; - console.log( '>>Blink : ' + acme.Blink ); + X_UA[ 'Blink' ] = tv; + console.log( '>>Blink : ' + X_UA[ 'Blink' ] ); } else if( dav.indexOf( 'Konqueror' ) !== -1 ){ /** @memberof X.UA */ - acme.Khtml = tv; - console.log( '>>Khtml : ' + acme.Khtml ); + X_UA[ 'Khtml' ] = tv; + console.log( '>>Khtml : ' + X_UA[ 'Khtml' ] ); } else if( ( i = dua.indexOf( 'Android ' ) ) !== -1 ){ /** @memberof X.UA */ - acme.AndroidBrowser = i = parseFloat( dua.substr( i + 8 ) ) || 0.1; + X_UA[ 'AndroidBrowser' ] = i = parseFloat( dua.substr( i + 8 ) ) || 0.1; /** @memberof X.UA */ - acme.AndroidBrowser1 = 1 <= i && i < 2; + X_UA[ 'AndroidBrowser1' ] = 1 <= i && i < 2; /** @memberof X.UA */ - acme.AndroidBrowser2 = 2 <= i && i < 3; + X_UA[ 'AndroidBrowser2' ] = 2 <= i && i < 3; /** @memberof X.UA */ - acme.AndroidBrowser3 = 3 <= i && i < 4; + X_UA[ 'AndroidBrowser3' ] = 3 <= i && i < 4; /** @memberof X.UA */ - acme.AndroidBrowser4 = 4 <= i && i < 5; + X_UA[ 'AndroidBrowser4' ] = 4 <= i && i < 5; /** @memberof X.UA */ - acme.AndroidBrowser5 = 5 <= i && i < 6; - console.log( '>> AndroidBrowser : ' + acme.Android ); + X_UA[ 'AndroidBrowser5' ] = 5 <= i && i < 6; + console.log( '>> AndroidBrowser : ' + X_UA[ 'Android' ] ); i = parseFloat(dua.split('WebKit\/')[1]); /** @memberof X.UA */ - acme.AndroidBrowserWebkit = i; + X_UA[ 'AndroidBrowserWebkit' ] = i; alert( 'AudioSprite調査:Android標準ブラウザ Webkit Version ' + i ); } else if( i = parseFloat(dua.split('WebKit\/')[1]) ){ /** @memberof X.UA */ - acme.WebKit = i; - /** @memberof X.UA */ - acme.Chrome = parseFloat(dua.split('Chrome\/')[1]) || undefined; + X_UA[ 'WebKit' ] = i; + + if( v = parseFloat(dua.split('Chrome\/')[1]) ){ + /** @memberof X.UA */ + X_UA[ 'Chrome' ] = v; + }; // TODO webkit Opera - console.log( '>>Webkit : ' + acme.WebKit ); + console.log( '>>Webkit : ' + X_UA[ 'WebKit' ] ); - if( i && !acme.Chrome && dua.indexOf( 'Safari' ) !== -1 ){ + if( i && !X_UA[ 'Chrome' ] && dua.indexOf( 'Safari' ) !== -1 ){ if( dav.indexOf( 'Version/' ) !== -1 ){ /** @memberof X.UA */ - acme.Safari = parseFloat( dav.split('Version/')[1] ); + X_UA[ 'Safari' ] = parseFloat( dav.split('Version/')[1] ); } else { - if( i < 73 ){ - acme.Safari = 0.8; - } else - if( i < 85 ){ - acme.Safari = 0.9; - } else - if( i < 100 ){ - acme.Safari = 1; - } else - if( i < 125 ){ - acme.Safari = 1.1; - } else - if( i < 312 ){ - acme.Safari = 1.2; - } else - if( i < 412 ){ - acme.Safari = 1.3; - } else - if( i <= 419.3 ){ - acme.Safari = 2; - } else - if( i <= 525.13 ){ - acme.Safari = 3; - } else - if( i <= 525.25 ){ - acme.Safari = 3.1; - } else if( i <= 528.16 ){ - acme.Safari = 3.2; + X_UA[ 'Safari' ] = i < 73 ? 0.8 : + i < 85 ? 0.9 : + i < 100 ? 1 : + i < 125 ? 1.1 : + i < 312 ? 1.2 : + i < 412 ? 1.3 : + i <= 419.3 ? 2 : + i <= 525.13 ? 3 : + i <= 525.25 ? 3.1 : 3.2; }; }; }; - console.log( '>> Webkit : ' + acme.WebKit + ' Safari : ' + acme.Safari ); + console.log( '>> Webkit : ' + X_UA[ 'WebKit' ] + ' Safari : ' + X_UA[ 'Safari' ] ); }; //http://www.useragentstring.com/pages/Iris/ - if( dua.toLowerCase().indexOf( 'iris' ) !== -1 ) acme.Iris = true; + if( dua.toLowerCase().indexOf( 'iris' ) !== -1 ) X_UA[ 'Iris' ] = true; if( // Kobo Mozilla/5.0 (Linux; U; Android 2.0; en-us;) AppleWebKit/533.1 (KHTML, like Gecko) Verson/4.0 Mobile Safari/533.1 (Kobo Touch) dua.indexOf( 'Kobo' ) !== -1 || @@ -400,25 +408,24 @@ Sleipnir Mobile Android 2.1以上 Fenrir dua.indexOf( 'EBRD' ) !== -1 ){ /** @memberof X.UA */ - acme.EInk = true; + X_UA[ 'EInk' ] = true; }; - return acme; -})( navigator ), +})( navigator ); -X_UA_DOM = {}, -X_UA_EVENT = {}, -X_UA_HID = {}; -//X_UA.IECompat && alert( X_UA.IE + ' ' + X_UA._IE + ' Tri:' + X_UA.Trident ); +var X_UA_DOM = {}, + X_UA_EVENT = {}, + X_UA_HID = {}; +//X_UA[ 'IECompat' ] && alert( X_UA[ 'IE' ] + ' ' + X_UA[ '_IE' ] + ' Tri:' + X_UA[ 'Trident' ] ); /* * http://d.hatena.ne.jp/t-uchima/20051003/p1 * MacIEにはattachEventが一応あるけどwindow.attachEventとdocument.attachEventしかなく他の要素にはattachEventはない。 */ -if( X_UA.IE4 && X_UA.IE < 5 ){ // ie4 & iemobi4 & macie4.x +if( X_UA[ 'IE4' ] && X_UA[ 'IE' ] < 5 ){ // ie4 & iemobi4 & macie4.x X_UA_DOM.IE4 = true; X_UA_EVENT.IE4 = true; } else -if( X_UA.MacIE ){ +if( X_UA[ 'MacIE' ] ){ X_UA_DOM.W3C = true; X_UA_EVENT.IE = true; } else @@ -442,12 +449,12 @@ if( document.layers ){ if( navigator.msPointerEnabled || navigator.pointerEnabled ) X_UA_HID.POINTER = true; if( !X_UA_HID.POINTER && window.ontouchstart !== undefined ) X_UA_HID.TOUCH = true; -//alert(X_UA.Safari + ' ' + X_UA.WebKit + '\n\n' + navigator.userAgent + '\n\n' + navigator.appVersion + '\n\n' + navigator.platform ); +//alert(X_UA[ 'Safari' ] + ' ' + X_UA[ 'WebKit' ] + '\n\n' + navigator.userAgent + '\n\n' + navigator.appVersion + '\n\n' + navigator.platform ); // Safari 3.1 未満は開発コンソールがない! // http://shimax.cocolog-nifty.com/search/2006/09/safarijavascrip_c54d.html /* -if( X_UA.Safari && X_UA.WebKit < 525.13 ){ +if( X_UA[ 'Safari' ] && X_UA[ 'WebKit' ] < 525.13 ){ window.onerror = function( x, y, z ){ var n = String.fromCharCode( 10 ); alert('window.onerrorによるエラーの捕捉:' + n + x + n + y + 'の' + z + '行目付近です。'); @@ -455,34 +462,25 @@ if( X_UA.Safari && X_UA.WebKit < 525.13 ){ }; };*/ -// ------------------------------------------------------------------------- // -// --- interface ----------------------------------------------------------- // -// ------------------------------------------------------------------------- // - -/** - * UserAgent の関する定数を保持する。 - * @namespace X.UA - * @alias X.UA - * @type {object} - */ -X.UA = X_UA; - // TODO 構文のサポート instanceof, in, try catch -if( X_UA.IE < 7 ){ // error @ NN7.2 - // bonus: hotfix for IE6 SP1 (bug KB823727) - // multipleIEs IE6 standalone 版では不可, IE5.5 は可,,, - X_UA.IE4 || X_UA.MacIE ? +if( X_UA[ 'IE' ] < 7 ){ // error @ NN7.2 + X_UA[ 'IE4' ] || X_UA[ 'MacIE' ] ? document.execCommand && document.execCommand( 'BackgroundImageCache', false, true ) : (function(){ - X_UA.IE_EXECOM_ERROR = eval( 'var a=1;try{document.execCommand&&document.execCommand("BackgroundImageCache",!1,!0)}catch(e){a=0}!a' ); + /** + * ie7 以下で実行する document.execCommand( 'BackgroundImageCache', false, true ) の失敗。 + * bonus: hotfix for IE6 SP1 (bug KB823727) + * multipleIEs IE6 standalone 版では不可, IE5.5 は可,,, + * @memberof X.UA */ + X_UA[ 'ieExeComError' ] = eval( 'var a=1;try{document.execCommand&&document.execCommand("BackgroundImageCache",!1,!0)}catch(e){a=0}!a' ); })(); - X_UA.IE_EXECOM_ERROR && alert( 'document.execCommand error!' ); + X_UA[ 'ieExeComError' ] && alert( 'document.execCommand error!' ); }; /* - * HTML5 に対応しない IE8 以下でも  の下に

を作ることができる + * HTML5 に対応しない IE8 以下でも の下に
を作ることができる * その際に
の直前に改行文字が出現するが childNodes は長さ 1 で
だけの模様、、、 X_UA_ATagWrapDiv = (function( e, h ){ e = document.createElement( 'div' ); diff --git a/0.6.x/js/01_core/03_XType.js b/0.6.x/js/01_core/03_XType.js index 28c100a..fdf181c 100644 --- a/0.6.x/js/01_core/03_XType.js +++ b/0.6.x/js/01_core/03_XType.js @@ -1,3 +1,36 @@ +var + /** + * Array か?判定する。argumnets 等のフェイク Array は false なので注意。 + * @funciton + * @alias X.Type._isArray + */ + X_Type_isArray = + new Function( 'v', + X_UA[ 'IE' ] < 5.5 || X_UA[ 'NetFront' ] < 4 ? // netfront3.4 は html に instanceof をすると error になる + 'return v&&v.push===Array.prototype.push' : // win ie5-, MacIE5.2 + X_UA[ 'IE' ] ? + 'return v&&Object.prototype.toString.call(v)==="[object Array]"' : + 'return v instanceof Array' + ), + + /** + * HTMLElement か?判定する。ちなみに return v instanceof Element は ie8 でエラー。 + * @funciton + * @alias X.Type.isHTMLElement + */ + X_Type_isHTMLElement = + new Function( 'v', + ( X_UA[ 'IE4' ] || X_UA[ 'MacIE' ] ) ? + 'return v&&v.tagName&&v.insertAdjacentHTML&&true' : // ie4 or MacIE5.23, v.all <- error + X_UA[ 'NetFront' ] < 4 ? + 'return v&&v.nodeType===1' : // instanceof not a function. netfront3.4 は html に instanceof をすると error になる + window[ 'HTMLElement' ] ? + 'return v instanceof HTMLElement' : + 'return v&&v.appendChild&&v.nodeType===1' + ); + + + /** * http://pettanr.sourceforge.jp/test/type.html * ビルトイン方の判定に使用する関数を集めたもの。ブラウザのネイティブな判定関数には不可解な挙動があるので、X.Type を使用するほうがよい。 @@ -5,98 +38,95 @@ * @namespace X.Type * @alias X.Type */ -X.Type = { +X[ 'Type' ] = { + 'isObject' : X_Type_isObject, + 'isFunction' : X_Type_isFunction, + 'isUnknown' : X_Type_isUnknown, + 'isArray' : X_Type_isArray, + 'isBoolean' : X_Type_isBoolean, + 'isString' : X_Type_isString, + 'isNumber' : X_Type_isNumber, + 'isFinite' : X_Type_isFinite, + 'isNaN' : X_Type_isNaN, + 'isHTMLElement' : X_Type_isHTMLElement, + 'isImage' : X_Type_isImage, + 'isNull' : X_Type_isNull, + 'isUndefined' : X_Type_isUndefined +}; + /** * Object か?判定する。typeof null === 'object' に対策済なので null は Object ではない。 + * @alias X.Type.isObject */ - isObject : function( v ){ + function X_Type_isObject( v ){ return v && typeof v === 'object'; // typeof null === 'object' に対策 - }, + }; /** * Function か?判定する。 + * @alias X.Type.isFunction */ - isFunction : function( v ){ + function X_Type_isFunction( v ){ return typeof v === 'function'; - }, + }; /** * ie の XHR.open 等ビルトインオブジェクトか?判定する。 + * @alias X.Type.isUnknown */ - isUnknown : function( v ){ + function X_Type_isUnknown( v ){ return typeof v === 'unknown'; - }, - /** - * Array か?判定する。argumnets 等のファイク Array は false なので注意。 - * @funciton - */ - isArray : - new Function( 'v', - X_UA.IE < 5.5 || X_UA.NetFront < 4 ? // netfront3.4 は html に instanceof をすると error になる - 'return v&&v.push===Array.prototype.push' : // win ie5-, MacIE5.2 - X_UA.IE ? - 'return v&&Object.prototype.toString.call(v)==="[object Array]"' : - 'return v instanceof Array' - ), + }; + /** * 真偽値か?判定する。 + * @alias X.Type.isBoolean */ - isBoolean : function( v ){ + function X_Type_isBoolean( v ){ return v === true || v === false; - }, + }; /** * 文字列か?判定する。 + * @alias X.Type.isString */ - isString : function( v ){ + function X_Type_isString( v ){ return typeof v === 'string'; // v === v + ''; // 文字列の加算は IE で遅いかも。 - }, + }; /** * 数値値か?判定する。 + * @alias X.Type.isNumber */ - isNumber : function( v ){ + function X_Type_isNumber( v ){ return typeof v === 'number'; // v !== v || v + 0 === v; - }, + }; /** * finite か?判定する。isFinite( '123' ) === true に対策済。 + * @alias X.Type.isFinite */ - isFinite : function( v ){ + function X_Type_isFinite( v ){ return typeof v === 'number' && isFinite( v ); - }, + }; /** - * NaN か?判定する。isNaN( 'NaN' ) === true に対策済。 + * NaN か?判定する。isNaN( 'NaN' ) === true に対策済。 + * @alias X.Type.isNaN */ - isNaN : function( v ){ + function X_Type_isNaN( v ){ return v !== v; - }, - /** - * HTMLElement か?判定する。 - * @funciton - */ - isHTMLElement : - new Function( 'v', - ( X_UA.IE4 || X_UA.MacIE ) ? - 'return v&&v.tagName&&v.insertAdjacentHTML&&true' : // ie4 or MacIE5.23, v.all <- error - X_UA.NetFront < 4 ? - 'return v&&v.nodeType===1' : // instanceof not a function. netfront3.4 は html に instanceof をすると error になる - window[ 'HTMLElement' ] ? - 'return v instanceof HTMLElement' : - //window[ 'Element' ] ? - // 'return v instanceof Element' : // error @ie8 - 'return v&&v.appendChild&&v.nodeType===1' - ), + }; + /* * new Image した場合に HTMLImageElement が作られるブラウザと,そうでないブラウザ(IE8-)がある + * @alias X.Type.isImage */ - isImage : - function( v ){ - if( v && v.constructor === window.Image ) return true; - if( v && window.HTMLImageElement && v.constructor === window.HTMLImageElement ) return true; // ie6- は constructor が undef、HTMLImageElement が undef なので、HTMLElement の存在確認が必要 - if( X_UA.WebKit < 525.13 ){ // Safari3- - if( v && v.src !== undefined && v.onload !== undefined && X.Type.isNumber( v.height ) && X.Type.isNumber( v.width ) && X.Type.isBoolean( v.complete ) ){ - return true; - }; + function X_Type_isImage( v ){ + if( v && v.constructor === window.Image ) return true; + if( v && window.HTMLImageElement && v.constructor === window.HTMLImageElement ) return true; // ie6- は constructor が undef、HTMLImageElement が undef なので、HTMLElement の存在確認が必要 + if( X_UA[ 'WebKit' ] < 525.13 ){ // Safari3- + if( v && v.src !== undefined && v.onload !== undefined && X_Type_isNumber( v.height ) && X_Type_isNumber( v.width ) && X_Type_isBoolean( v.complete ) ){ + return true; }; - return false; - }, + }; + return false; + }; /* isElementCollection : function(v) { return (Object.prototype.toString.call(v) === "[object HTMLCollection]"); @@ -104,16 +134,17 @@ X.Type = { */ /** * Null か?判定する。 + * @alias X.Type.isNull */ - isNull : function( v ){ + function X_Type_isNull( v ){ return v === null; - }, + }; /** * undefined か?判定する。 + * @alias X.Type.isUndefined */ - isUndefined : function( v ){ + function X_Type_isUndefined( v ){ return v === void 0; - } -}; + }; console.log( 'X.Core.Type' ); diff --git a/0.6.x/js/01_core/04_XObject.js b/0.6.x/js/01_core/04_XObject.js index 283ade5..574b1e4 100644 --- a/0.6.x/js/01_core/04_XObject.js +++ b/0.6.x/js/01_core/04_XObject.js @@ -7,7 +7,7 @@ * @param {object} obj * @return {boolean} name が定義されている(値が undefined や null でも) -> true */ -var X_Object_inObject = X_UA.IE < 5.5 ? // TODO JScript で判定 +var X_Object_inObject = X_UA[ 'IE' ] < 5.5 ? // TODO JScript で判定 (function( name, obj ){ var p; if( obj[ name ] ) return true; // quick @@ -68,7 +68,7 @@ function X_Object_clone( src ){ */ function X_Object_override( target, src ){ var k; - if( !X.Type.isObject( src ) ) return target; + if( !X_Type_isObject( src ) ) return target; for( k in src ){ //if( X_EMPTY_OBJECT[ k ] ) continue; target[ k ] = src[ k ]; @@ -92,13 +92,13 @@ function X_Object_deepCopy_( src, objSrc, objCopy, n ) { if( !src ){ // 0, "", null, undefined, NaN, false return src; } else - if( X.Type.isArray( src ) ){ + if( X_Type_isArray( src ) ){ i = objSrc.indexOf( src ); if( i !== -1 ) return objCopy[ i ]; objSrc[ ++n ] = src; objCopy[ n ] = ret = []; } else - if( X.Type.isObject( src ) ){ + if( X_Type_isObject( src ) ){ i = objSrc.indexOf( src ); if( i !== -1 ) return objCopy[ i ]; objSrc[ ++n ] = src; diff --git a/0.6.x/js/01_core/05_XString.js b/0.6.x/js/01_core/05_XString.js index b5ba9ba..1ba48aa 100644 --- a/0.6.x/js/01_core/05_XString.js +++ b/0.6.x/js/01_core/05_XString.js @@ -32,7 +32,7 @@ X.String = { // ------------------------------------------------------------------------- // function X_String_parse( v ){ var _v, n; - if( X.Type.isString( v ) ){ + if( X_Type_isString( v ) ){ switch( v ){ case '' : return v; //case '{}' : return {}; diff --git a/0.6.x/js/01_core/10_XCallback.js b/0.6.x/js/01_core/10_XCallback.js index f042a01..189ba59 100644 --- a/0.6.x/js/01_core/10_XCallback.js +++ b/0.6.x/js/01_core/10_XCallback.js @@ -168,14 +168,14 @@ function X_Callback_create( thisObject, opt_callback, opt_args /* [ listener || function X_Callback_classifyCallbackArgs( arg1, arg2, arg3, alt_context ){ var obj; - if( arg1 && X.Type.isFunction( arg2 ) ){ + if( arg1 && X_Type_isFunction( arg2 ) ){ obj = { x : arg1, f : arg2, k : X_Callback_THIS_FUNC }; } else - if( arg1 && X.Type.isFunction( arg1[ 'handleEvent' ] ) ){ + if( arg1 && X_Type_isFunction( arg1[ 'handleEvent' ] ) ){ obj = { x : arg1, k : X_Callback_HANDLEEVENT }; arg3 = arg2; } else - if( X.Type.isFunction( arg1 ) ){ + if( X_Type_isFunction( arg1 ) ){ arg3 = arg2; if( alt_context ){ obj = { x : alt_context, f : arg1, k : X_Callback_THIS_FUNC }; @@ -183,7 +183,7 @@ function X_Callback_classifyCallbackArgs( arg1, arg2, arg3, alt_context ){ obj = { f : arg1, k : X_Callback_FUNC_ONLY }; }; } else - if( X.Type.isFunction( arg2 ) ){ + if( X_Type_isFunction( arg2 ) ){ //console.log( 'X_Callback_classifyCallbackArgs : arg1 が ' + arg1 + 'です' ); ie4 で error if( alt_context ){ obj = { x : alt_context, f : arg2, k : X_Callback_THIS_FUNC }; @@ -200,7 +200,7 @@ function X_Callback_classifyCallbackArgs( arg1, arg2, arg3, alt_context ){ return; }; - if( X.Type.isArray( arg3 )){ + if( X_Type_isArray( arg3 )){ obj.s = arg3; }; return ( obj.x || obj.s ) ? obj : arg1; @@ -241,16 +241,16 @@ function X_Callback_proxyCallback( xfunc, _args ){ case X_Callback_HANDLEEVENT : temp = thisObj[ 'handleEvent' ]; - if( X.Type.isFunction( temp ) ){ + if( X_Type_isFunction( temp ) ){ return args.length === 0 ? thisObj[ 'handleEvent' ]() : args.length === 1 ? thisObj[ 'handleEvent' ]( args[ 0 ] ) : temp.apply( thisObj, args ); }; break; /* - if( temp !== func && X.Type.isFunction( temp ) ){ + if( temp !== func && X_Type_isFunction( temp ) ){ return args.length === 0 ? thisObj[ 'handleEvent' ]() : temp.apply( thisObj, args ); } else - if( X.Type.isFunction( thisObj ) ){ + if( X_Type_isFunction( thisObj ) ){ return args.length === 0 ? thisObj.call( thisObj ) : thisObj.apply( thisObj, args ); }; return args.length === 0 ? func.call( thisObj ) : func.apply( thisObj, args );*/ diff --git a/0.6.x/js/01_core/11_XClass.js b/0.6.x/js/01_core/11_XClass.js index 8fa3773..815e4c1 100644 --- a/0.6.x/js/01_core/11_XClass.js +++ b/0.6.x/js/01_core/11_XClass.js @@ -27,7 +27,7 @@ var X_Class_killPrivateFlag = false, X_Class_traits = null, X_Class_useObjectCreate = false, // !!Object.create, http://jsperf.com/prototype-vs-object-create-perf - X_Class_use_proto_ = !X_UA.OperaMobile && !X_UA.OperaTablet && !!X.emptyFunction.prototype.__proto__, + X_Class_use_proto_ = !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] && !!X.emptyFunction.prototype.__proto__, // Opera Mobile 12.10 Android11 IS01 でクラスのメンバが欠落する問題に遭遇。__proto__ を使わないと動作,,, X_Class_CommonMethods = @@ -48,7 +48,7 @@ X_Class_CommonMethods = klass = X_Class_getClass( instance ), def = X_Class_getClassDef( klass ), data, p, i; - if( def.isPrivate && !X_Class_killPrivateFlag ){ + if( def.isPrivate && !X_Class_killPrivateFlag && ( !this[ '_listeners' ] || !this[ '_listeners' ][ X_Listeners_.KILL_RESERVED ] ) ){ X.Logger.critical( 'PrivateInstance.kill() work in PrivateUser.kill().' ); return; }; @@ -56,8 +56,8 @@ X_Class_CommonMethods = if( this.instanceOf( X.EventDispatcher ) ){ if( !def.isPrivate ){ - if( this.dispatch( X.Event.BEFORE_KILL_INSTANCE ) & X.Callback.PREVENT_DEFAULT ){ - this.dispatch( X.Event.KILL_INSTANCE_CANCELED ); + if( this.dispatch( X_Event.BEFORE_KILL_INSTANCE ) & X.Callback.PREVENT_DEFAULT ){ + this.dispatch( X_Event.KILL_INSTANCE_CANCELED ); return; }; if( this[ '_listeners' ] && this[ '_listeners' ][ X_Listeners_.DISPATCHING ] ){ @@ -65,7 +65,7 @@ X_Class_CommonMethods = return; }; } else { - this.dispatch( X.Event.BEFORE_KILL_INSTANCE ); + this.dispatch( X_Event.BEFORE_KILL_INSTANCE ); }; // asyncDispatch の削除 @@ -76,7 +76,7 @@ X_Class_CommonMethods = }; }; - this.dispatch( X.Event.KILL_INSTANCE ); + this.dispatch( X_Event.KILL_INSTANCE ); this._listeners && X_EventDispatcher_systemUnlisten( this ); }; @@ -92,10 +92,10 @@ X_Class_CommonMethods = i = def.userList.indexOf( instance ); if( i !== -1 ){ data = X_Class_getPrivate( instance ); - X_Class_killPrivateFlag = true; if( data[ '_listeners' ] && data[ '_listeners' ][ X_Listeners_.DISPATCHING ] && data.instanceOf( X.EventDispatcher ) ){ data[ '_listeners' ][ X_Listeners_.KILL_RESERVED ] = true; } else { + X_Class_killPrivateFlag = true; data.kill(); }; def.dataList.splice( i, 1 ); @@ -158,7 +158,7 @@ X_Class_CommonMethods = var sClass = this, args = arguments, name, p, sFunc, hit = false; - if( X.Type.isFunction( funcNameOrFunc ) ){ + if( X_Type_isFunction( funcNameOrFunc ) ){ for( p in this.constructor.prototype ){ if( this.constructor.prototype[ p ] === funcNameOrFunc ){ name = p; @@ -180,7 +180,7 @@ X_Class_CommonMethods = hit = true; // 現在の関数にヒット } else if( hit && X_Object_inObject( name, this ) ){ - if( X.Type.isFunction( sFunc ) ){ + if( X_Type_isFunction( sFunc ) ){ switch( args.length ){ case 1 : return sFunc.call( this ); @@ -224,14 +224,22 @@ X_Class_CommonMethods = // ------------------------------------------------------------------------- // /** - * Class を定義し システムの管理下に置く.
- * 全てのクラスと pool が有効の場合インスタンスへの参照が保持される. + *

Class を定義し システムの管理下に置く。 + *

prototype 継承のブラウザ毎の差異も吸収し、 以下から最適な方法をしてくれる。 + * + *

    + *
  1. Object.create はパフォーマンスが悪そうなので現在は使っていない。 + *
  2. SubClass.prototype.__proto__ = SuperClass.prototype; + *
  3. SubClass.prototype = new SuperClass; + *
+ * *
    *
  1. X.Class.create( opt_settings, opt_name, opt_privateClass, opt_props ) でクラスを登録. *
  2. コンストラクタ となるメソッドは、opt_props 内の Constructor : function( arg ){ ... }, に書く. *
  3. 通常通り new で インスタンス生成 *
  4. kill() でオブジェクトをクリーンして削除、pool が有効の場合は pool される. *
  5. pool が有効の場合、new で pool されたインスタンスが返される. + *
* @namespace X.Class * @alias X.Class */ @@ -291,14 +299,14 @@ X.Class = { props, klass, classDef = {}, hash; - if( X.Type.isString( displayName ) === true ){ + if( X_Type_isString( displayName ) === true ){ classDef.displayName = displayName; args.shift(); }; // クラス設定 classDef.setting = classSetting = args[ 0 ]; - if( X.Type.isNumber( classSetting ) ){ + if( X_Type_isNumber( classSetting ) ){ opt_pool = !!( classSetting & X.Class.POOL_OBJECT ); opt_abstract = !!( classSetting & X.Class.ABSTRACT ); opt_final = !!( classSetting & X.Class.FINAL ); @@ -328,16 +336,11 @@ X.Class = { // インスタンスのメンバー props = args[ 0 ]; - if( !X.Type.isObject( props ) ){ - // サブクラスの場合、クラス定義の上書きがなくても作成可能 - // サブクラスでなくても、クラスメンバ用オブジェクトが無しでも作成可能 - //if( !X_Class_traits ){ - // X.Logger.critical( 'No Class Def!' ); - // return; - //}; + if( !X_Type_isObject( props ) ){ + // クラスメンバ用オブジェクトが無しでもクラスは作成可能 props = {}; } else - if( props.Constructor && X.Type.isFunction( props.Constructor ) ){ + if( props.Constructor && X_Type_isFunction( props.Constructor ) ){ classDef.Constructor = props.Constructor; }; @@ -534,7 +537,7 @@ function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props if( superDef.Final ) X.Logger.critical( 'X.Class inherits, Class is final!' ); // サブクラス名 - if( X.Type.isString( displayName ) ){ + if( X_Type_isString( displayName ) ){ args.shift(); } else { displayName = 'SubClass of ' + superDef.displayName; @@ -543,7 +546,7 @@ function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props // サブクラス設定 classSetting = args[ 0 ]; - if( X.Type.isNumber( classSetting ) ){ + if( X_Type_isNumber( classSetting ) ){ args.shift(); } else { // クラス設定がない場合、親からコピーして、Abstract flag は落とす?? @@ -578,14 +581,9 @@ function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props def = X_Class_getClassDef( klass ); // 継承用プロパティを控える - //if( opt_super === true ){ - //def.superAccess = true; - def.SuperClass = Super; - def.SuperProto = Super.prototype; - def.SuperConstructor = superDef.Constructor || superDef.SuperConstructor; - // else { - // def.SuperClass = Super; // instanceOf() で親クラスを調べる! - //}; + def.SuperClass = Super; + def.SuperProto = Super.prototype; + def.SuperConstructor = superDef.Constructor || superDef.SuperConstructor; return klass; }; @@ -629,7 +627,7 @@ function X_Class_actualConstructor( f, args ){ def.Constructor.apply( instance, args ) : def.SuperConstructor && def.SuperConstructor.apply( instance, args ); - if( ( X.Type.isObject( obj ) && obj !== instance ) || X.Type.isFunction( obj ) ){ // Class + if( ( X_Type_isObject( obj ) && obj !== instance ) || X_Type_isFunction( obj ) ){ // Class instance.kill(); return obj; }; diff --git a/0.6.x/js/01_core/12_XEvent.js b/0.6.x/js/01_core/12_XEvent.js index b9ca82d..733d9e9 100644 --- a/0.6.x/js/01_core/12_XEvent.js +++ b/0.6.x/js/01_core/12_XEvent.js @@ -5,7 +5,7 @@ var X_Event_last = 0, X_Event_proxy = { - load : X_UA.IE < 9 && { + load : X_UA[ 'IE' ] < 9 && { check : function( eventDispatcher ){ return eventDispatcher._tag === 'IFRAME' || eventDispatcher._tag === 'SCRIPT'; }, @@ -16,7 +16,7 @@ var X_Event_last = 0, } }, - contextmenu : X_UA.Opera && { + contextmenu : X_UA[ 'Opera' ] && { rename : 'mousedown', @@ -60,61 +60,99 @@ X_TEMP.SYSTEM_EVENT_INIT = 7; * フレームワーク内で定義されたイベント。 * @namespace X.Event * @alias X.Event + * @enum {number} */ -X.Event = { - XDOM_READY : 8, +var X_Event = X[ 'Event' ] = { + /** + * X.ViewPort で発生する。DomContentLoaded に相当。document.body.innerHTML の内容から X.Node ツリーの作成が完了した。 + * このイベント以降、X.Doc.create(), X.Doc.find() 等が可能になる。 + * @const + */ + 'XDOM_READY' : 8, - COMPLETE : 9, - READY : 10, - SUCCESS : 11, - ERROR : 12, - PROGRESS : 13, - BEFORE_CANCEL : 14, - CANCELED : 15, - TIMEOUT : 16, - - BEFORE_KILL_INSTANCE : 17, - KILL_INSTANCE_CANCELED : 18, - KILL_INSTANCE : 19, + 'COMPLETE' : 9, + 'READY' : 10, + 'SUCCESS' : 11, + 'ERROR' : 12, + 'PROGRESS' : 13, + 'BEFORE_CANCEL' : 14, + 'CANCELED' : 15, + 'TIMEOUT' : 16, + + /** + * X.EventDispatcher インスタンスを kill() すると発生。キャンセル可能。 + */ + 'BEFORE_KILL_INSTANCE' : 17, + /** + * X.EventDispatcher インスタンスの kill() がキャンセルされた場合に発生。 + */ + 'KILL_INSTANCE_CANCELED' : 18, + /** + * X.EventDispatcher インスタンスの kill が確定し、kill プロセスの前に発生。 + */ + 'KILL_INSTANCE' : 19, + + /** + * X.ViewPort で発生する。'visibilitychange', 'pageshow', window.onfocus を検出している。 + */ + 'VIEW_ACTIVATE' : 20, + /** + * X.ViewPort で発生する。'visibilitychange', 'pagehide', window.onblur を検出している。 + */ + 'VIEW_DEACTIVATE' : 21, + /** + * X.ViewPort で発生する。 + */ + 'VIEW_RESIZED' : 22, + /** + * X.ViewPort で発生する。 + */ + 'VIEW_TURNED' : 23, + /** + * X.ViewPort で発生する。ベースフォントサイズが変化すると発生する。body 直下の隠し要素のテキストサイズの変化で検出している。 + */ + 'BASE_FONT_RESIZED' : 24, - VIEW_ACTIVATE : 20, - VIEW_DEACTIVATE : 21, - VIEW_RESIZED : 22, - VIEW_TURNED : 23, - BASE_FONT_RESIZED : 24, // in_page_jump // on_screen_keyboard_show // on_screen_keyboard_hide - BEFORE_UPDATE : 25,// X_System このイベントで要素のサイズを取得すると無限ループに! - UPDATED : 26,// X_System - AFTER_UPDATE : 27, - HASH_CHANGED : 28, + 'BEFORE_UPDATE' : 25,// X_System このイベントで要素のサイズを取得すると無限ループに! + 'UPDATED' : 26,// X_System + 'AFTER_UPDATE' : 27, + + 'HASH_CHANGED' : 28, - BEFORE_UNLOAD : 29, - UNLOAD : 30, + /** + * X.ViewPort で発生する。 + */ + 'BEFORE_UNLOAD' : 29, + /** + * X.ViewPort で発生する。 + */ + 'UNLOAD' : 30, - BACKEND_READY : 31, - BACKEND_NONE : 32, - BACKEND_RESEARCH : 33, - BACKEND_CHANGED : 34, + 'BACKEND_READY' : 31, + 'BACKEND_NONE' : 32, + 'BACKEND_RESEARCH' : 33, + 'BACKEND_CHANGED' : 34, - ANIME_BEFORE_START : 35, - ANIME_START : 36, - ANIME : 37, - ANIME_END : 38, - ANIME_BEFORE_STOP : 39, // xnode.stop() のみ、指定時間による停止では呼ばれない - ANIME_STOP : 40, + 'ANIME_BEFORE_START' : 35, + 'ANIME_START' : 36, + 'ANIME' : 37, + 'ANIME_END' : 38, + 'ANIME_BEFORE_STOP' : 39, // xnode.stop() のみ、指定時間による停止では呼ばれない + 'ANIME_STOP' : 40, - GPU_RELEASED : 41, + 'GPU_RELEASED' : 41, - MEDIA_PLAYING : 42, - MEDIA_BEFORE_LOOP : 43, // cancelable - MEDIA_LOOPED : 44, - MEDIA_PAUSED : 45, - MEDIA_ENDED : 46, - MEDIA_WAITING : 47, - MEDIA_SEEKING : 48 + 'MEDIA_PLAYING' : 42, + 'MEDIA_BEFORE_LOOP' : 43, // cancelable + 'MEDIA_LOOPED' : 44, + 'MEDIA_PAUSED' : 45, + 'MEDIA_ENDED' : 46, + 'MEDIA_WAITING' : 47, + 'MEDIA_SEEKING' : 48 }; X_Event_last = 48; @@ -125,7 +163,7 @@ X_TEMP.onSystemReady.push( for( k in X_Event_Rename ){ //if( X_EMPTY_OBJECT[ k ] ) continue; name = X_Event_Rename[ k ]; - if( X.Type.isArray( name ) ){ + if( X_Type_isArray( name ) ){ for( i = name.length; i; ){ X_Event_RenameTo[ name[ --i ] ] = k; }; diff --git a/0.6.x/js/01_core/13_XEventDispatcher.js b/0.6.x/js/01_core/13_XEventDispatcher.js index 29ec939..8741a0f 100644 --- a/0.6.x/js/01_core/13_XEventDispatcher.js +++ b/0.6.x/js/01_core/13_XEventDispatcher.js @@ -1,26 +1,35 @@ -/* - *

EventDispatcher インスタンスのメンバ(_listeners)でイベントリスナをイベント名(string)やイベントID(5~以上の number, フレームワーク内で定義、5 以上になる理由は後述)をキーとする Array で記憶します。 - * Arrayには、__CallbackHash__ というハッシュ、または関数が蓄えられています。 +/** + *

EventDispatcher インスタンスのメンバ(_listeners)でイベントリスナをイベント名(string)や + * イベントID(5~以上の number, フレームワーク内で定義、5 以上になる理由は後述)をキーとする Array で記憶します。 + * + *

Arrayには、__CallbackHash__ というハッシュ、または関数が蓄えられています。 + * + *

また、イベントターゲット(EventDispatcher._rawObject)に渡された再利用可能クロージャの控えを _listeners[0] に記憶します。(ACTUAL_HANDLER) * - * また、dispatch 中の状態と操作を記録し不整合が起きないようにするためのプロパティを持ち、0 から 4 の番号が与えられています。 + *

dispatch 中の状態と操作を記録し不整合が起きないようにするためのプロパティ(_listeners[1]~_listeners[4])を持ちます。イベントID が 5 から始まるのはこのためです。 * *

*
0:ACTUAL_HANDLER *
イベントターゲットの addEventListener 等に渡される実際の関数(再利用可能クロージャ)を控えています。 *
1:DISPATCHING number - *
イベントディスパッチ中か?またディスパッチがネストした場合、その深さを記憶します。 + *
dispatch 中か?さらにインスタンス自身の dispatch がネストした場合、その深さを記憶します。 *
2:RESERVES Array - *
イベント発火中に listen() が呼ばれた場合に引数を蓄え、全てのディスパッチの完了時(_dispatching===0)に再度 listen() するための一時ストアです。 + *
イベント発火中に listen() が呼ばれた場合に引数を蓄え、完了時(DISPATCHING===0)に再度 listen() するための一時ストアです。 *
3:UNLISTENS Array - *
イベント発火中に unlisten() が呼ばれた場合に対象リスナを記憶し、リスナが呼ばれないようにします。全てのディスパッチの完了時(_dispatching===0)に再度 unlisten() します。 + *
イベント発火中に unlisten() が呼ばれた場合に対象リスナを記憶し、リスナが呼ばれないようにします。完了時(DISPATCHING===0)に再度 unlisten() します。 *
4:KILL_RESERVED boolean - *
イベント発火中に kill() が呼ばれた場合に、全てのディスパッチの完了時(_dispatching===0)に再度 kill() するためのフラグです。 + *
dispatch 中に kill() が呼ばれた場合に一旦 kill をキャンセルし、完了時(DISPATCHING===0)に再度 kill() するためのフラグです。 *
+ * + * @class __X_EventDispatcher_Listeners__ + * @private + * @abstract */ -var X_Listeners, - +var /** @enum {number} */ - X_Listeners_ = { + X_Listeners_ = + /** @lends __X_EventDispatcher_Listeners__ */ + { ACTUAL_HANDLER : 0, DISPATCHING : 1, RESERVES : 2, @@ -112,7 +121,7 @@ var EventDispatcher = X.EventDispatcher = * Arrayには、{k:種類,x:コンテキスト(thisObject),f:関数,s:サプリメントする引数の配列} というハッシュ、または関数が蓄えられています。 * * @private - * @type {X_Listeners} + * @type {__X_EventDispatcher_Listeners__} */ '_listeners' : null, @@ -207,8 +216,8 @@ var EventDispatcher = X.EventDispatcher = }, /** - * delay(ミリ秒)後にイベントを dispatch する。戻り値は uid = X.Timer.add() のタイマーID(数値)。X.Timer.remove(uid) でタイマーを解除して dispatch を中止できる。 - * kill() 時には内部でまだ呼ばれていないタイマーの X.Timer.remove() が行われる。 + * delay(ミリ秒)後にイベントを dispatch する。戻り値は uid = X.Timer.once() のタイマーID(数値)。X.Timer.remove(uid) でタイマーを解除して dispatch を中止できる。 + * kill() 時には内部でまだ呼ばれていないタイマーの X.Timer.remove() が行われる。インスタンスが破棄された後にタイマーが呼ばれることがないので神経質にならなくても安全に使える。 * @example this.asyncDispatch( 'myevent' ); * // どちらのコードも同じ動作をする。 * this.asyncDispatch( 0, 'myevent' ); @@ -289,7 +298,7 @@ function X_EventDispatcher_dispatch( e ){ if( r & X.Callback.STOP_NOW ){ sysOnly = true; }; - ret |= X.Type.isFinite( r ) ? r : 0; + ret |= X_Type_isFinite( r ) ? r : 0; }; if( ( --listeners[ X_Listeners_.DISPATCHING ] ) === 0 ){ @@ -389,7 +398,7 @@ function X_EventDispatcher_listen( type, opt_arg1, opt_arg2, opt_arg3 ){ return this; }; - if( X.Type.isArray( type ) ){ + if( X_Type_isArray( type ) ){ for( i = type.length; i; ){ this.listen( type[ --i ], opt_arg1, opt_arg2, opt_arg3 ); }; @@ -397,7 +406,7 @@ function X_EventDispatcher_listen( type, opt_arg1, opt_arg2, opt_arg3 ){ }; raw = this._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ); - add = raw && ( !listeners || !listeners[ type ] ) && X.Type.isString( type ); + add = raw && ( !listeners || !listeners[ type ] ) && X_Type_isString( type ); if( this.listening( type, opt_arg1 || this, opt_arg2, opt_arg3 ) ) return this; @@ -439,7 +448,7 @@ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ list, reserves, unlistens, i, f, raw, k, empty; if( !listeners ) return this; - if( X.Type.isArray( opt_type ) ){ + if( X_Type_isArray( opt_type ) ){ for( i = opt_type.length; i; ){ this.unlisten( opt_type[ --i ], opt_arg1, opt_arg2, opt_arg3 ); if( !opt_type[ i ] ){ @@ -530,7 +539,7 @@ function X_EventDispatcher_addEvent( that, type, raw, list ){ var i; X_EventDispatcher_lock || ( type = X_Event_Rename[ type ] || type ); - if( X.Type.isArray( type ) ){ + if( X_Type_isArray( type ) ){ for( i = type.length; i; ){ X_EventDispatcher_systemListen( that, type[ --i ], X.emptyFunction ); console.log( 'events fix > ' + type[ i ] ); @@ -554,7 +563,7 @@ var X_EventDispatcher_actualAddEvent = break; case X_EventDispatcher_EVENT_TARGET_TYPE.XHR : - if( X_UA.Opera < 12 ){ + if( X_UA[ 'Opera' ] < 12 ){ // Opera11- の XHR は event オブジェクトが返らないため, eventType 毎に callback を指定する addEventListener もない raw[ 'on' + type ] = X_Callback_create( that, X_EventDispatcher_dispatch, [ type ] ); break; @@ -563,7 +572,7 @@ var X_EventDispatcher_actualAddEvent = default : // iOS と MacOSX Iron36 で発生。連続してアニメーションが起こると、クロージャの束縛された obj へのアクセスに失敗する。Win では起きない? // むしろ、MacOSX のブラウザ全般で起こる?? - if( ( X_UA.WebKit || X_UA.Blink ) && + if( ( X_UA[ 'WebKit' ] || X_UA[ 'Blink' ] ) && ( type === 'webkitTransitionEnd' || type === 'transitionend' || type === 'animationend' || type === 'webkitAnimationEnd' || type === 'animationstart' || type === 'webkitAnimationStart' || @@ -647,7 +656,7 @@ function X_EventDispatcher_removeEvent( that, type, raw, list, skip ){ var i; X_EventDispatcher_unlock || ( type = X_Event_Rename[ type ] || type ); - if( X.Type.isArray( type ) ){ + if( X_Type_isArray( type ) ){ for( i = type.length; i; ){ X_EventDispatcher_systemUnlisten( that, type[ --i ], X.emptyFunction ); }; @@ -668,7 +677,7 @@ var X_EventDispatcher_actualRemoveEvent = break; case X_EventDispatcher_EVENT_TARGET_TYPE.XHR : - if( X_UA.Opera < 12 ){ + if( X_UA[ 'Opera' ] < 12 ){ // Opera11- の XHR は event オブジェクトが返らないため, eventType 毎に callback を指定する addEventListener もない X_Callback_correct( raw[ 'on' + type ] ); raw[ 'on' + type ] = ''; @@ -676,7 +685,7 @@ var X_EventDispatcher_actualRemoveEvent = }; default : - if( ( X_UA.WebKit || X_UA.Blink ) && + if( ( X_UA[ 'WebKit' ] || X_UA[ 'Blink' ] ) && ( type === 'webkitTransitionEnd' || type === 'transitionend' || type === 'animationend' || type === 'webkitAnimationEnd' || type === 'animationstart' || type === 'webkitAnimationStart' || @@ -783,7 +792,7 @@ var X_EventDispatcher_actualHandleEvent = i, l; //console.log( '>>>>>>>>>> ' + e.type ); // touch event -> pointer - if( X.Type.isArray( ev ) ){ + if( X_Type_isArray( ev ) ){ if( ev.length === 0 ){ // TouchEvent の後に発生した MouseEvent のキャンセル ret = X.Callback.STOP_PROPAGATION | X.Callback.PREVENT_DEFAULT; @@ -803,7 +812,7 @@ var X_EventDispatcher_actualHandleEvent = if( ret & X.Callback.PREVENT_DEFAULT ){ this._tag === 'A' && this._rawObject.blur(); e.preventDefault(); - if( X_UA.WebKit < 525.13 ){ // Safari3- + if( X_UA[ 'WebKit' ] < 525.13 ){ // Safari3- if( e.type === 'click' || e.type === 'dbclick' ){ X_EventDispatcher_safariPreventDefault = true; }; @@ -812,7 +821,7 @@ var X_EventDispatcher_actualHandleEvent = }; }); -if( X_UA.WebKit < 525.13 ){ // Safari3- +if( X_UA[ 'WebKit' ] < 525.13 ){ // Safari3- document.documentElement.onclick = document.documentElement.ondbclick = function( e ){ if( X_EventDispatcher_safariPreventDefault ){ diff --git a/0.6.x/js/01_core/14_XTimer.js b/0.6.x/js/01_core/14_XTimer.js index 7846bf3..d2dbd8f 100644 --- a/0.6.x/js/01_core/14_XTimer.js +++ b/0.6.x/js/01_core/14_XTimer.js @@ -1,4 +1,4 @@ -/** +/* * use X.Callback */ @@ -34,7 +34,15 @@ // ------------ local variables -------------------------------------------- // // ------------------------------------------------------------------------- // -var X_Timer_now = Date.now || function(){ return +new Date; }, +var + + /** + * 現在時の ms を返します。 new Date().getTime() の値です。 + * @alias X.Timer.now + * @function + * @return {number} ミリ秒 + */ + X_Timer_now = Date.now || function(){ return +new Date; }, X_Timer_SET_TIMEOUT = window.setTimeout, X_Timer_CLEAR_TIMEOUT = window.clearTimeout, @@ -76,16 +84,39 @@ var X_Timer_now = Date.now || function(){ return +new Date; }, // ------------------------------------------------------------------------- // // --- interface ----------------------------------------------------------- // // ------------------------------------------------------------------------- // + +/** + *

setTimeout をラップします。複数のタイマーを登録しても Web ブラウザにはひとつのタイマーを登録します。 + *

参考:複雑で重くなった JavaScript を超高速化する方法3, + * [JavaScript]setIntervalを実験する + *

指定時間の経過したタイマーは、より過去のものから順番にコールバックされます。 + *

setTimeout のコールバックに文字列しか指定できないブラウザがあり対策しています。 + *

requestAnimationFrame をラップします。ベンダープレフィックス付の requestAnimationFrame もない場合、setTimeout にフォールバックします。 + * + * @example X.Timer.add( 1000, 5, thisContext, onTimer ); + * + * @namespace X.Timer + * @alias X.Timer + */ X.Timer = { - + now : X_Timer_now, + /** + * タイマーをセットします。 + * @param {number} time ミリ秒 + * @param {number} opt_count 回数。省略可能。指定回数で自動でタイマーを破棄します。0 を指定した場合無限にタイマーが呼ばれます。省略した場合 0 と同じです。 + * @param {*} args1 コールバックのための最大で 3 つの引数を指定します。参考:__CallbackHash__ + * @param {*} args2 + * @param {*} args3 + * @return {number} タイマーID。1 以上の数値。タイマーの解除に使用。 + */ add : function( time, opt_count, args1, args2, args3 ){ var list = X_Timer_TICKET_LIST, hash, obj; time = time < X_Timer_INTERVAL_TIME ? 1 : time / X_Timer_INTERVAL_TIME | 0; // 正の数で使える「Math.floor(x)」を「(x | 0)」に; - if( !X.Type.isNumber( opt_count ) ){ + if( !X_Type_isNumber( opt_count ) ){ args3 = args2; args2 = args1; args1 = opt_count; @@ -106,10 +137,22 @@ X.Timer = { return X_Timer_uid; }, + /** + * 1 回呼ばれたら解除されるタイマーをセットします。 + * @param {number} time ミリ秒 + * @param {*} args1 コールバックのための最大で 3 つの引数を指定します。参考:__CallbackHash__ + * @param {*} args2 + * @param {*} args3 + * @return {number} タイマーID。1 以上の数値。タイマーの解除に使用。 + */ once : function( time, args1, args2, args3 ){ return X.Timer.add( time, 1, args1, args2, args3 ); }, + /** + * タイマーを解除します。登録時に受け取ったタイマーIDを使用します。 + * @param {number} タイマーID + */ remove : function( uid ){ var list = X_Timer_TICKET_LIST, i = list.length, @@ -128,7 +171,7 @@ X.Timer = { * lazyDispatch 中の EventDispatcher の有無を調べる */ if( X_EventDispatcher_LAZY_TIMERS[ uid ] ){ - eventDispatcher = X_EventDispatcher_LAZY_TIMERS[ uid ]; + // eventDispatcher = X_EventDispatcher_LAZY_TIMERS[ uid ]; delete X_EventDispatcher_LAZY_TIMERS[ uid ]; /* listeners = eventDispatcher[ '_listeners' ]; @@ -150,6 +193,14 @@ X.Timer = { }; }, + /** + * requestAnimationFrame をセットします。 + * @function + * @param {*} args1 コールバックのための最大で 3 つの引数を指定します。参考:__CallbackHash__ + * @param {*} args2 + * @param {*} args3 + * @return {number} タイマーID。1 以上の数値。タイマーの解除に使用。 + */ requestFrame : X_Timer_REQ_ANIME_FRAME ? (function( args1, args2, args3 ){ var i = X_Timer_REQ_FRAME_LIST.length, @@ -165,7 +216,12 @@ X.Timer = { f = X_Timer_REQ_FRAME_LIST[ i ] = X_Callback_classifyCallbackArgs( args1, args2, args3 ); return f.uid = ++X_Timer_uid; }), - + + /** + * requestAnimationFrame を解除します。登録時に受け取ったタイマーIDを使用します。 + * @function + * @param {number} タイマーID + */ cancelFrame : X_Timer_CANCEL_ANIME_FRAME ? (function( uid ){ var list = X_Timer_REQ_FRAME_LIST, @@ -215,7 +271,7 @@ X.Timer = { // --- implements ---------------------------------------------------------- // // ------------------------------------------------------------------------- // -if( X_UA.IE4 || X_UA.MacIE ){ +if( X_UA[ 'IE4' ] || X_UA[ 'MacIE' ] ){ X.Timer[ '_' ] = X_Timer_onTimeout; X_Timer_onTimeout = 'X.Timer._()'; }; @@ -322,7 +378,7 @@ function X_Timer_compareQueue( a, b ){ // http://havelog.ayumusato.com/develop/javascript/e528-ios6_scrolling_timer_notcall.html // iOS6 スクロール中のタイマー発火絡みのバグ備忘 -if( X_UA.iOS ){ +if( X_UA[ 'iOS' ] ){ window.addEventListener( 'scroll', function(){ var last, now; if( X_Timer_timerId ){ diff --git a/0.6.x/js/01_core/16_XViewPort.js b/0.6.x/js/01_core/16_XViewPort.js index e838bb0..21a3547 100644 --- a/0.6.x/js/01_core/16_XViewPort.js +++ b/0.6.x/js/01_core/16_XViewPort.js @@ -9,10 +9,10 @@ var X_ViewPort_readyState, X_ViewPort_vScrollbarSize, X_ViewPort_hScrollbarSize, - X_Dom_detectFontSize = !( X_UA.IE < 9 || X_UA.iOS ) && function(){ + X_Dom_detectFontSize = !( X_UA[ 'IE' ] < 9 || X_UA[ 'iOS' ] ) && function(){ var size = X_Node_fontSizeNode._rawObject.offsetHeight; if( X_ViewPort_baseFontSize !== size ){ - X_ViewPort_baseFontSize && X_ViewPort.asyncDispatch( X.Event.BASE_FONT_RESIZED ); + X_ViewPort_baseFontSize && X_ViewPort.asyncDispatch( X_Event.BASE_FONT_RESIZED ); X_ViewPort_baseFontSize = size; }; }, @@ -20,7 +20,7 @@ var X_ViewPort_readyState, X_ViewPort_orientationFlag, X_Dom_orientationchange = window[ 'orientation' ] !== undefined && function( e ){ X_ViewPort_orientationFlag = true; - !X_UA.Android && X_ViewPort_resize(); + !X_UA[ 'Android' ] && X_ViewPort_resize(); //console.log( '-- orientationchange : ' + X.ViewPort.getSize[ 0 ] + ' ' + X.ViewPort.getSize[ 1 ] ); }, @@ -39,32 +39,32 @@ X_ViewPort = X_Class_override( href = e.target && e.target.attr && e.target.attr( 'href' ); if( href && href.indexOf && href.indexOf( 'javascript:' ) === 0 ) return X.Callback.PREVENT_DEFAULT | X.Callback.STOP_PROPAGATION; - return X_ViewPort.dispatch( X.Event.BEFORE_UNLOAD ); + return X_ViewPort.dispatch( X_Event.BEFORE_UNLOAD ); case 'unload' : - X_ViewPort.dispatch( X.Event.UNLOAD ); + X_ViewPort.dispatch( X_Event.UNLOAD ); //alert('unload'); X_ViewPort_document.kill(); this.kill(); - //X_System.dispatch( X.Event.SHUT_DOWN ); + //X_System.dispatch( X_Event.SHUT_DOWN ); break; case 'visibilitychange' : - X_ViewPort.dispatch( ( X_ViewPort_active = document[ 'hidden' ] ) ? X.Event.VIEW_DEACTIVATE : X.Event.VIEW_ACTIVATE ); + X_ViewPort.dispatch( ( X_ViewPort_active = document[ 'hidden' ] ) ? 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 ); + X_ViewPort.dispatch( ( X_ViewPort_active = document[ 'mozHidden' ] ) ? X_Event.VIEW_DEACTIVATE : X_Event.VIEW_ACTIVATE ); break; case 'webkitvisibilitychange' : - X_ViewPort.dispatch( ( X_ViewPort_active = document[ 'webkitHidden' ] ) ? X.Event.VIEW_DEACTIVATE : X.Event.VIEW_ACTIVATE ); + X_ViewPort.dispatch( ( X_ViewPort_active = document[ 'webkitHidden' ] ) ? X_Event.VIEW_DEACTIVATE : X_Event.VIEW_ACTIVATE ); break; case 'pageshow' : case 'focus' : if( !X_ViewPort_active ){ X_ViewPort_active = true; - X_ViewPort.dispatch( X.Event.VIEW_ACTIVATE ); + X_ViewPort.dispatch( X_Event.VIEW_ACTIVATE ); }; break; @@ -72,7 +72,7 @@ X_ViewPort = X_Class_override( case 'blur' : if( X_ViewPort_active ){ X_ViewPort_active = false; - X_ViewPort.dispatch( X.Event.VIEW_DEACTIVATE ); + X_ViewPort.dispatch( X_Event.VIEW_DEACTIVATE ); }; break; }; @@ -82,12 +82,17 @@ X_ViewPort = X_Class_override( ); +/** + * window に相当する ViewPort 情報を提供するオブジェクト。 + * @namespace X.ViewPort + * @alias X.ViewPort + */ X.ViewPort = { listen : function( type, arg1, arg2, arg3 ){ if( type <= X_ViewPort_readyState ){ /* - * X.Event.XDOM_READY 以後に listen した場合の対策 + * X_Event.XDOM_READY 以後に listen した場合の対策 */ X_ViewPort.asyncDispatch( type ); }; @@ -126,7 +131,9 @@ X.ViewPort = { }, - /* 要素が視界に入った http://remysharp.com/2009/01/26/element-in-view-event-plugin/ */ + /* 要素が視界に入った http://remysharp.com/2009/01/26/element-in-view-event-plugin/ + * TODO -> Node.call('inView') + */ inView : function( elm ){ }, @@ -146,7 +153,7 @@ X.ViewPort = { // Safari2.0.4では標準・互換どちらも document.body X_Node_updateTimerID && X_Node_startUpdate(); - /*X_UA.Opera ? + /*X_UA[ 'Opera' ] ? ( document.documentElement && document.documentElement.clientWidth ? new Function( 'return[document.documentElement.clientWidth,document.documentElement.clientHeight]' ) : new Function( 'return[document.body.clientWidth,document.body.clientHeight]' ) @@ -217,7 +224,7 @@ X.ViewPort = { */ var X_ViewPort_resize = // iOS もループで回す,,,iOS3.1.3, iOS6 で確認 - X_UA.IE < 9 || X_UA.iOS ? + X_UA[ 'IE' ] < 9 || X_UA[ 'iOS' ] ? (function(){ var size; if( !X_ViewPort_lock ){ @@ -232,7 +239,7 @@ X.ViewPort = { size = X_Node_fontSizeNode._rawObject.offsetHeight; if( X_ViewPort_baseFontSize !== size ){ - X_ViewPort_baseFontSize && X_ViewPort.asyncDispatch( X.Event.BASE_FONT_RESIZED ); + X_ViewPort_baseFontSize && X_ViewPort.asyncDispatch( X_Event.BASE_FONT_RESIZED ); X_ViewPort_baseFontSize = size; }; @@ -253,11 +260,11 @@ X.ViewPort = { } else { console.log( '-- detectFinishResizing : ' + X_Timer_now() ); - X_ViewPort.asyncDispatch( X.Event.VIEW_RESIZED ); + X_ViewPort.asyncDispatch( X_Event.VIEW_RESIZED ); X_ViewPort_lock = false; if( X_ViewPort_orientationFlag ){ X_ViewPort_orientationFlag = false; - X_ViewPort.asyncDispatch( 100, { type : X.Event.VIEW_TURNED, orientation : window.orientation } ); + X_ViewPort.asyncDispatch( 100, { type : X_Event.VIEW_TURNED, orientation : window.orientation } ); }; }; }; @@ -311,7 +318,7 @@ X.ViewPort = { X_ViewPort.listenOnce( X_TEMP.SYSTEM_EVENT_XTREE, function(){ X_ViewPort_readyState = X_TEMP.SYSTEM_EVENT_INIT; - //X_UA.Opera7 && alert( 'bc' ); + //X_UA[ 'Opera7' ] && alert( 'bc' ); X_Node_body.appendAt( 0, X_Node_systemNode = X_Doc_create( 'div', { 'class' : 'hidden-system-node' } ), X_Node_fontSizeNode = X_Doc_create( 'div', { 'class' : 'hidden-system-node' } ).cssText( 'line-height:1;height:1em;' ).text( 'X' ) @@ -362,8 +369,8 @@ X.ViewPort = { X_ViewPort_baseFontSize = X_Node_fontSizeNode._rawObject.offsetHeight; - X_ViewPort_readyState = X.Event.XDOM_READY; - X_ViewPort.asyncDispatch( { type : X.Event.XDOM_READY, w : X_ViewPort_width = size[ 0 ], h : X_ViewPort_height = size[ 1 ] } ); + X_ViewPort_readyState = X_Event.XDOM_READY; + X_ViewPort.asyncDispatch( { type : X_Event.XDOM_READY, w : X_ViewPort_width = size[ 0 ], h : X_ViewPort_height = size[ 1 ] } ); } ); X_ViewPort.asyncDispatch( X_TEMP.SYSTEM_EVENT_PRE_INIT ); @@ -383,7 +390,7 @@ X.ViewPort = { if( document[ 'webkitHidden' ] !== undefined ){ X_EventDispatcher_systemListen( X_ViewPort_document, 'webkitvisibilitychange', X_ViewPort ); } else - if( X_UA.iOS && window[ 'onpageshow' ] !== undefined ){ + if( X_UA[ 'iOS' ] && window[ 'onpageshow' ] !== undefined ){ X_EventDispatcher_systemListen( X_ViewPort, [ 'pageshow', 'pagehide' ] ); } else { X_EventDispatcher_systemListen( X_ViewPort, [ 'focus', 'blur' ] ); @@ -393,7 +400,7 @@ X.ViewPort = { }; function X_ViewPort_getWindowSize(){ - return X_UA.IE ? + return X_UA[ 'IE' ] ? [ X_ViewPort_rootElement.clientWidth, X_ViewPort_rootElement.clientHeight ] : [ window.innerWidth, window.innerHeight ]; }; @@ -414,7 +421,7 @@ console.log( 'X.Dom dom:w3c=' + X_UA_DOM.W3C + ' ev:w3c=' + X_UA_EVENT.W3C ); if( X_UA_EVENT.W3C ){ X_ViewPort_document.listenOnce( 'DOMContentLoaded', X_TEMP.onDomContentLoaded ); } else -if( 6 <= X_UA.IE && X.inHead ){ +if( 6 <= X_UA[ 'IE' ] && X.inHead ){ // if this script in Head document.write( "' ), '', '', '', @@ -138,7 +138,7 @@ function X_NET_JSONP_loadScriptInNinjaIframe( url ){ ]; X_Net_JSONP_onloadCount = 3; } else - if( X_UA.IE < 8 ){ // ie5-7 + if( X_UA[ 'IE' ] < 8 ){ // ie5-7 html = [ '', '', @@ -165,21 +165,21 @@ function X_NET_JSONP_loadScriptInNinjaIframe( url ){ X_NET_JSONP_NinjaIframe .refresh( html.join( '' ) ) - .listen( [ X.Event.SUCCESS, X.Event.ERROR ], X_NET_JSONPWrapper, X_NET_JSONP_iframeListener ); + .listen( [ X_Event.SUCCESS, X_Event.ERROR ], X_NET_JSONPWrapper, X_NET_JSONP_iframeListener ); }; function X_NET_JSONP_iframeListener( e ){ switch( e.type ){ - case X.Event.SUCCESS : + case X_Event.SUCCESS : console.log( 'iframe onload, but' ); if( ++X_NET_JSONPWrapper._onloadCount < X_Net_JSONP_onloadCount ) return; // TODO callback が無ければ error - X_NET_JSONPWrapper.asyncDispatch( 1000, X.Event.ERROR ); + X_NET_JSONPWrapper.asyncDispatch( 1000, X_Event.ERROR ); break; - case X.Event.ERROR : + case X_Event.ERROR : console.log( 'iframe onerror' ); - X_NET_JSONPWrapper.asyncDispatch( X.Event.ERROR ); + X_NET_JSONPWrapper.asyncDispatch( X_Event.ERROR ); break; }; X_NET_JSONP_NinjaIframe.unlisten(); diff --git a/0.6.x/js/06_net/04_XNetImage.js b/0.6.x/js/06_net/04_XNetImage.js index 8cca132..38a878b 100644 --- a/0.6.x/js/06_net/04_XNetImage.js +++ b/0.6.x/js/06_net/04_XNetImage.js @@ -9,7 +9,7 @@ var X_Net_Image_hasImage = !!window[ 'Image' ], X_Net_Image_image = X_Net_Image_hasImage && new Image(), // IE では厳密には HTMLImageElement ではなく、appendChild してもサイズが取れず、removeChild に失敗する - X_Net_Image_isElement = !( X_UA.IE < 9 ) && X.Type.isHTMLElement( X_Net_Image_image ); + X_Net_Image_isElement = !( X_UA[ 'IE' ] < 9 ) && X_Type_isHTMLElement( X_Net_Image_image ); if( !X_Net_Image_hasImage ){ @@ -46,7 +46,7 @@ X_NET_ImageWrapper = X_Class_override( this._rawObject.src = this.abspath; - if( X_UA.Opera7 && this._rawObject.complete ){ + if( X_UA[ 'Opera7' ] && this._rawObject.complete ){ this.asyncDispatch( 'load' ); } else { this.timerID = X.Timer.add( this.delay, 0, this, this._detect ); @@ -62,7 +62,7 @@ X_NET_ImageWrapper = X_Class_override( this._busy = false; this.finish = true; this.timerID && X.Timer.remove( this.timerID ); - this.timerID = this.asyncDispatch( /*e.type === 'error' ?*/ X.Event.ERROR /*: X.Event.CANCELED*/ ); + this.timerID = this.asyncDispatch( /*e.type === 'error' ?*/ X_Event.ERROR /*: X_Event.CANCELED*/ ); break; case 'load' : // if( finish === true ) return; // これがあると firefox3.6 で駄目、、、 @@ -70,13 +70,13 @@ X_NET_ImageWrapper = X_Class_override( this._busy = false; this.finish = true; this.timerID && X.Timer.remove( this.timerID ); - if( X_UA.Opera && !this._rawObject.complete ){ - this.timerID = this.asyncDispatch( X.Event.ERROR ); + if( X_UA[ 'Opera' ] && !this._rawObject.complete ){ + this.timerID = this.asyncDispatch( X_Event.ERROR ); return; }; size = X.Util.Image.getActualDimension( !X_Net_Image_isElement ? this.abspath : this ); this.timerID = this.asyncDispatch( { - type : X.Event.SUCCESS, + type : X_Event.SUCCESS, src : this.abspath, w : size[ 0 ], h : size[ 1 ] @@ -84,7 +84,7 @@ X_NET_ImageWrapper = X_Class_override( // time , this._rawObject.fileSize } ); break; - case X.Event.KILL_INSTANCE : + case X_Event.KILL_INSTANCE : this.reset(); !X_Net_Image_hasImage && this.destroy(); // if xnode break; @@ -98,13 +98,13 @@ X_NET_ImageWrapper = X_Class_override( this.finish = true; if( this._rawObject.width ) return; X.Timer.remove( this.timerID ); - this.timerID = this.asyncDispatch( X.Event.ERROR ); + this.timerID = this.asyncDispatch( X_Event.ERROR ); } else if( this.timeout < ( this.tick += this.delay ) ){ this._busy = false; this.finish = true; X.Timer.remove( this.timerID ); - this.timerID = this.asyncDispatch( X.Event.TIMEOUT ); + this.timerID = this.asyncDispatch( X_Event.TIMEOUT ); }; }, @@ -114,7 +114,7 @@ X_NET_ImageWrapper = X_Class_override( // this._rawObject.src = ''; this._busy = false; this.finish = true; - this.asyncDispatch( X.Event.CANCELED ); + this.asyncDispatch( X_Event.CANCELED ); }, reset : function(){ @@ -129,6 +129,6 @@ X_NET_ImageWrapper = X_Class_override( } ); -X_NET_ImageWrapper.listen( [ 'load', 'error' /*, 'abort'*/, X.Event.KILL_INSTANCE ] ); +X_NET_ImageWrapper.listen( [ 'load', 'error' /*, 'abort'*/, X_Event.KILL_INSTANCE ] ); // X_Net_Image_isElement && X_NET_ImageWrapper.appendTo( X.X_Node_systemNode ); diff --git a/0.6.x/js/07_audio/00_XAudio.js b/0.6.x/js/07_audio/00_XAudio.js index d33dee9..a7958a6 100644 --- a/0.6.x/js/07_audio/00_XAudio.js +++ b/0.6.x/js/07_audio/00_XAudio.js @@ -11,9 +11,7 @@ */ var X_Audio_BACKENDS = [], // Array. - X_Audio_WRAPPER_LIST = [], // Array. - X_Audio_CAN_PLAY = 1, - X_Audio_NOT_PLAY = 2; + X_Audio_WRAPPER_LIST = []; // Array. function X_Audio_getAudioWrapper( proxy ){ var i = X_Audio_WRAPPER_LIST.length; @@ -23,23 +21,23 @@ function X_Audio_getAudioWrapper( proxy ){ }; /* - * X.Event.BACKEND_READY - * X.Event.BACKEND_NONE + * X_Event.BACKEND_READY + * X_Event.BACKEND_NONE * - * X.Event.READY 再生可能、実際の状態は canplay から loadeddata まで様々、、、 - * X.Event.ERROR + * X_Event.READY 再生可能、実際の状態は canplay から loadeddata まで様々、、、 + * X_Event.ERROR * 1 : ユーザーによってメディアの取得が中断された * 2 : ネットワークエラー * 3 : メディアのデコードエラー * 4 : メディアがサポートされていない * - * X.Event.MEDIA_PLAYING 再生中に1秒以下のタイミングで発生.currentTime が取れる? - * X.Event.MEDIA_LOOP ループ直前に発生、キャンセル可能 - * X.Event.MEDIA_LOOPED ループ時に発生 - * X.Event.MEDIA_ENDED 再生位置の(音声の)最後についた - * X.Event.MEDIA_PAUSED ポーズした - * X.Event.MEDIA_WAITING 再生中に音声が待機状態に。間もなく X.Event.MEDIA_PLAYING に移行。 - * X.Event.MEDIA_SEEKING シーク中に音声が待機状態に。間もなく X.Event.MEDIA_PLAYING に移行。 + * X_Event.MEDIA_PLAYING 再生中に1秒以下のタイミングで発生.currentTime が取れる? + * X_Event.MEDIA_LOOP ループ直前に発生、キャンセル可能 + * X_Event.MEDIA_LOOPED ループ時に発生 + * X_Event.MEDIA_ENDED 再生位置の(音声の)最後についた + * X_Event.MEDIA_PAUSED ポーズした + * X_Event.MEDIA_WAITING 再生中に音声が待機状態に。間もなく X_Event.MEDIA_PLAYING に移行。 + * X_Event.MEDIA_SEEKING シーク中に音声が待機状態に。間もなく X_Event.MEDIA_PLAYING に移行。 */ X.Audio = X.EventDispatcher.inherits( @@ -53,9 +51,9 @@ X.Audio = X.EventDispatcher.inherits( Constructor : function( sourceList, opt_option ){ X_Audio_startDetectionBackend( X_Audio_BACKENDS[ 0 ], this, - X.Type.isArray( sourceList ) ? X_Object_cloneArray( sourceList ) : [ sourceList ], + X_Type_isArray( sourceList ) ? X_Object_cloneArray( sourceList ) : [ sourceList ], opt_option || {} ); - this.listenOnce( [ X.Event.BACKEND_READY, X.Event.BACKEND_NONE, X.Event.KILL_INSTANCE ], X_Audio_handleEvent ); + this.listenOnce( [ X_Event.BACKEND_READY, X_Event.BACKEND_NONE, X_Event.KILL_INSTANCE ], X_Audio_handleEvent ); }, play : function( startTime, endTime, loop, loopStartTime, loopEndTime ){ @@ -149,8 +147,8 @@ X.Audio = X.EventDispatcher.inherits( function X_Audio_handleEvent( e ){ switch( e.type ){ - case X.Event.BACKEND_READY : - this.unlisten( X.Event.BACKEND_NONE, X_Audio_handleEvent ); + case X_Event.BACKEND_READY : + this.unlisten( X_Event.BACKEND_NONE, X_Audio_handleEvent ); this.source = e.source; this.backendName = X_Audio_BACKENDS[ this._backend ].backendName; X_Audio_WRAPPER_LIST.push( @@ -158,11 +156,11 @@ function X_Audio_handleEvent( e ){ .klass( this, e.source, e.option ) ); break; - case X.Event.BACKEND_NONE : + case X_Event.BACKEND_NONE : this.kill(); break; - case X.Event.KILL_INSTANCE : + case X_Event.KILL_INSTANCE : this._backend !== -1 && X_Audio_getAudioWrapper( this ).close(); break; }; @@ -182,41 +180,36 @@ function X_Audio_startDetectionBackend( backend, proxy, sourceList, option ){ sup = [ proxy, sourceList, option, source, ext ]; sup[ 5 ] = sup; - proxy.listenOnce( [ X_Audio_CAN_PLAY, X_Audio_NOT_PLAY ], backend, X_Audio_onEndedDetection, sup ); + proxy.listenOnce( X_Event.COMPLETE, backend, X_Audio_onEndedDetection, sup ); backend.detect( proxy, source, ext ); } else { - proxy.asyncDispatch( X.Event.BACKEND_NONE ); + proxy.asyncDispatch( X_Event.BACKEND_NONE ); }; }; function X_Audio_onEndedDetection( e, proxy, sourceList, option, source, ext, sup ){ var i = X_Audio_BACKENDS.indexOf( this ), backend; - proxy.unlisten( [ X_Audio_CAN_PLAY, X_Audio_NOT_PLAY ], this, X_Audio_onEndedDetection, sup ); - - switch( e.type ){ - case X_Audio_CAN_PLAY : - proxy._backend = i; - proxy.asyncDispatch( { - type : X.Event.BACKEND_READY, - option : option, - source : source, - backendName : this.backendName - } ); - break; - case X_Audio_NOT_PLAY : - console.log( 'No ' + source + ' ' + this.backendName ); - if( sup[ 3 ] = source = sourceList[ sourceList.indexOf( source ) + 1 ] ){ - sup[ 4 ] = ext = X_URL_getEXT( source ); - proxy.listenOnce( [ X_Audio_CAN_PLAY, X_Audio_NOT_PLAY ], this, X_Audio_onEndedDetection, sup ); - this.detect( proxy, source, ext ); - } else - if( backend = X_Audio_BACKENDS[ i + 1 ] ){ - X_Audio_startDetectionBackend( backend, proxy, sourceList, option ); - } else { - proxy.asyncDispatch( X.Event.BACKEND_NONE ); - }; - break; + if( e.canPlay ){ + proxy._backend = i; + proxy.asyncDispatch( { + type : X_Event.BACKEND_READY, + option : option, + source : source, + backendName : this.backendName + } ); + } else { + console.log( 'No ' + source + ' ' + this.backendName ); + if( sup[ 3 ] = source = sourceList[ sourceList.indexOf( source ) + 1 ] ){ + sup[ 4 ] = ext = X_URL_getEXT( source ); + proxy.listenOnce( X_Event.COMPLETE, this, X_Audio_onEndedDetection, sup ); + this.detect( proxy, source, ext ); + } else + if( backend = X_Audio_BACKENDS[ i + 1 ] ){ + X_Audio_startDetectionBackend( backend, proxy, sourceList, option ); + } else { + proxy.asyncDispatch( X_Event.BACKEND_NONE ); + }; }; }; @@ -232,7 +225,7 @@ function X_AudioWrapper_updateStates( audioWrapper, obj ){ switch( k ){ case 'currentTime' : v = X_AudioWrapper_timeStringToNumber( v ); - if( X.Type.isNumber( v ) ){ + if( X_Type_isNumber( v ) ){ if( playing ){ if( audioWrapper.state().currentTime !== v ){ audioWrapper.seekTime = v; @@ -269,13 +262,13 @@ function X_AudioWrapper_updateStates( audioWrapper, obj ){ if( playing ) seek = 2; case 'loop' : case 'autoplay' : - if( X.Type.isBoolean( v ) && audioWrapper[ k ] !== v ){ + if( X_Type_isBoolean( v ) && audioWrapper[ k ] !== v ){ audioWrapper[ k ] = v; }; break; case 'volume' : - if( X.Type.isNumber( v ) ){ + if( X_Type_isNumber( v ) ){ v = v < 0 ? 0 : 1 < v ? 1 : v; if( audioWrapper[ k ] !== v ){ audioWrapper[ k ] = v; @@ -301,8 +294,8 @@ function X_AudioWrapper_updateStates( audioWrapper, obj ){ function X_AudioWrapper_timeStringToNumber( time ){ var ary, ms, s = 0, m = 0, h = 0; - if( X.Type.isNumber( time ) ) return time; - if( !X.Type.isString( time ) || !time.length ) return; + if( X_Type_isNumber( time ) ) return time; + if( !X_Type_isString( time ) || !time.length ) return; ary = time.split( '.' ); ms = parseInt( ( ary[ 1 ] + '000' ).substr( 0, 3 ) ) || 0; diff --git a/0.6.x/js/07_audio/01_XWebAudio.js b/0.6.x/js/07_audio/01_XWebAudio.js index d50aaa4..38a9e8c 100644 --- a/0.6.x/js/07_audio/01_XWebAudio.js +++ b/0.6.x/js/07_audio/01_XWebAudio.js @@ -1,6 +1,6 @@ -var X_Audio_WebAudio_context = !X_UA.iPhone_4s && !X_UA.iPad_2Mini1 && !X_UA.iPod_4 && - !( X_UA.Gecko && X_UA.Android ) && +var X_Audio_WebAudio_context = !X_UA[ 'iPhone_4s' ] && !X_UA[ 'iPad_2Mini1' ] && !X_UA[ 'iPod_4' ] && + !( X_UA[ 'Gecko' ] && X_UA[ 'Android' ] ) && ( window.AudioContext || window.webkitAudioContext ), X_Audio_WebAudioWrapper; @@ -40,9 +40,9 @@ if( X_Audio_WebAudio_context ){ autoplay : false, volume : 0.5, + _startPos : 0, + _endPosition : 0, _startTime : 0, - _endTime : 0, - _playTime : 0, _timerID : 0, _interval : 0, buffer : null, @@ -70,20 +70,20 @@ if( X_Audio_WebAudio_context ){ audio.proxy.listenOnce( 'canplaythrough', this, this._onBufferReady ); } else { this.xhr = X.Net.xhrGet( url, 'arraybuffer' ) - .listen( X.Event.PROGRESS, this ) - .listenOnce( [ X.Event.SUCCESS, X.Event.COMPLETE, X.Event.CANCELED ], this ); + .listen( X_Event.PROGRESS, this ) + .listenOnce( [ X_Event.SUCCESS, X_Event.COMPLETE, X_Event.CANCELED ], this ); }; }, handleEvent : function( e ){ switch( e.type ){ - case X.Event.PROGRESS : + case X_Event.PROGRESS : e.percent ? this.proxy.dispatch( { type : 'progress', percent : e.percent } ) : this.proxy.dispatch( 'loadstart' ); return; - case X.Event.SUCCESS : + case X_Event.SUCCESS : console.log( 'WebAudio xhr success! ' + !!X_Audio_WebAudio_context.decodeAudioData + ' t:' + typeof e.data ); // TODO 旧api // https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Porting_webkitAudioContext_code_to_standards_based_AudioContext @@ -92,7 +92,7 @@ if( X_Audio_WebAudio_context ){ // iOS 7.1 で decodeAudioData に処理が入った瞬間にスクリーンを長押しする(スクロールを繰り返す)と // decoeAudioData の処理がキャンセルされることがある(エラーやコールバックの発火もなく、ただ処理が消滅する)。 // ただし iOS 8.1.2 では エラーになる - if( X_Audio_WebAudio_context.createBuffer && X_UA.iOS < 8 ){ + if( X_Audio_WebAudio_context.createBuffer && X_UA[ 'iOS' ] < 8 ){ this._onDecodeSuccess( X_Audio_WebAudio_context.createBuffer( e.data, false ) ); } else if( X_Audio_WebAudio_context.decodeAudioData ){ @@ -104,17 +104,17 @@ if( X_Audio_WebAudio_context ){ }; break; - case X.Event.CANCELED : + case X_Event.CANCELED : this.error = 1; this.proxy.dispatch( 'aborted' ); break; - case X.Event.COMPLETE : + case X_Event.COMPLETE : this.error = 2; - this.proxy.asyncDispatch( { type : X.Event.ERROR, message : 'xhr error' } ); + this.proxy.asyncDispatch( { type : X_Event.ERROR, message : 'xhr error' } ); break; }; - this.xhr.unlisten( [ X.Event.PROGRESS, X.Event.SUCCESS, X.Event.COMPLETE, X.Event.CANCELED ], this ); + this.xhr.unlisten( [ X_Event.PROGRESS, X_Event.SUCCESS, X_Event.COMPLETE, X_Event.CANCELED ], this ); delete this.xhr; }, @@ -124,7 +124,7 @@ if( X_Audio_WebAudio_context ){ this.onDecodeSuccess && this._onDecodeComplete(); if ( !buffer ) { - this.proxy.asyncDispatch( { type : X.Event.ERROR, message : 'buffer is ' + buffer } ); + this.proxy.asyncDispatch( { type : X_Event.ERROR, message : 'buffer is ' + buffer } ); return; }; @@ -136,7 +136,7 @@ if( X_Audio_WebAudio_context ){ this.proxy.asyncDispatch( 'canplay' ); this.proxy.asyncDispatch( 'canplaythrough' ); */ - this.proxy.asyncDispatch( X.Event.READY ); + this.proxy.asyncDispatch( X_Event.READY ); this.autoplay && X.Timer.once( 16, this, this.play ); @@ -147,7 +147,7 @@ if( X_Audio_WebAudio_context ){ console.log( 'WebAudio decode error!' ); this._onDecodeComplete(); this.error = 3; - this.proxy.asyncDispatch( { type : X.Event.ERROR, message : 'decode error' } ); + this.proxy.asyncDispatch( { type : X_Event.ERROR, message : 'decode error' } ); }, _onDecodeComplete : function(){ @@ -225,11 +225,11 @@ if( X_Audio_WebAudio_context ){ this.source.noteGrainOn( 0, begin / 1000, end / 1000 ); }; - this.playing = true; - this._startTime = begin; - this._endTime = end; - this._playTime = X_Audio_WebAudio_context.currentTime * 1000; - this._interval = this._interval || X.Timer.add( 1000, 0, this, this._onInterval ); + this.playing = true; + this._startPos = begin; + this._endPosition = end; + this._startTime = X_Audio_WebAudio_context.currentTime * 1000; + this._interval = this._interval || X.Timer.add( 1000, 0, this, this._onInterval ); }, _onInterval : function(){ @@ -237,7 +237,7 @@ if( X_Audio_WebAudio_context ){ delete this._interval; return X_Callback_UN_LISTEN; }; - this.proxy.dispatch( X.Event.MEDIA_PLAYING ); + this.proxy.dispatch( X_Event.MEDIA_PLAYING ); }, _onEnded : function(){ @@ -245,28 +245,29 @@ if( X_Audio_WebAudio_context ){ delete this._timerID; if( this.playing ){ - time = X_Audio_WebAudio_context.currentTime * 1000 - this._playTime - this._endTime + this._startTime | 0; - //console.log( '> onEnd ' + ( this.playing && ( X_Audio_WebAudio_context.currentTime * 1000 - this._playTime ) ) + ' < ' + ( this._endTime - this._startTime ) ); + time = X_Audio_WebAudio_context.currentTime * 1000 - this._startTime - this._endPosition + this._startPos | 0; + //console.log( '> onEnd ' + ( this.playing && ( X_Audio_WebAudio_context.currentTime * 1000 - this._startTime ) ) + ' < ' + ( this._endPosition - this._startPos ) ); if( this._onended ){ // Firefox 用の対策,,, if( time < 0 ) return; } else { if( time < 0 ){ - console.log( '> onEnd ' + ( -time ) + ' start:' + this._startTime + '-' + this._endTime ); + console.log( '> onEnd crt:' + ( X_Audio_WebAudio_context.currentTime * 1000 ) + ' startTime:' + this._startTime + + ' from:' + this._startPos + ' to:' + this._endPosition ); this._timerID = X.Timer.once( -time, this, this._onEnded ); return; }; }; if( this.loop ){ - if( !( this.proxy.dispatch( X.Event.MEDIA_BEFORE_LOOP ) & X.Callback.PREVENT_DEFAULT ) ){ + if( !( this.proxy.dispatch( X_Event.MEDIA_BEFORE_LOOP ) & X.Callback.PREVENT_DEFAULT ) ){ this.looped = true; - this.proxy.dispatch( X.Event.MEDIA_LOOPED ); + this.proxy.dispatch( X_Event.MEDIA_LOOPED ); this.play(); }; } else { this.pause(); - this.proxy.dispatch( X.Event.MEDIA_ENDED ); + this.proxy.dispatch( X_Event.MEDIA_ENDED ); }; }; }, @@ -305,7 +306,7 @@ if( X_Audio_WebAudio_context ){ playing : this.playing, duration : this.duration, - currentTime : this.playing ? ( X_Audio_WebAudio_context.currentTime * 1000 - this._playTime + this._startTime | 0 ) : this.seekTime, + currentTime : this.playing ? ( X_Audio_WebAudio_context.currentTime * 1000 - this._startTime + this._startPos | 0 ) : this.seekTime, error : this.error }; }; @@ -330,7 +331,7 @@ if( X_Audio_WebAudio_context ){ // detect : function( proxy, source, ext ){ - proxy.asyncDispatch( X_Audio_codecs[ ext ] ? X_Audio_CAN_PLAY : X_Audio_NOT_PLAY ); + proxy.asyncDispatch( { type : X_Event.COMPLETE, canPlay : X_Audio_codecs[ ext ] } ); }, klass : X_Audio_WebAudioWrapper diff --git a/0.6.x/js/07_audio/02_XHTMLAudio.js b/0.6.x/js/07_audio/02_XHTMLAudio.js index df0024b..396a246 100644 --- a/0.6.x/js/07_audio/02_XHTMLAudio.js +++ b/0.6.x/js/07_audio/02_XHTMLAudio.js @@ -5,18 +5,18 @@ */ var X_Audio_HTMLAudio_playTrigger = - 6 <= X_UA.iOS ? 'loadeddata' : - X_UA.iOS ? 'suspend' : - X_UA.AndroidBrowser2 ? 'stalled' : // Android 2.3.5(SBM101SH) では stalled は発生しない,,, - X_UA.AndroidBrowser4 ? 'loadeddata' : - X_UA.OperaMobile || X_UA.OperaTablet ? 'loadeddata' : 'canplay', + 6 <= X_UA[ 'iOS' ] ? 'loadeddata' : + X_UA[ 'iOS' ] ? 'suspend' : + X_UA[ 'AndroidBrowser2' ] ? 'stalled' : // Android 2.3.5(SBM101SH) では stalled は発生しない,,, + X_UA[ 'AndroidBrowser4' ] ? 'loadeddata' : + X_UA[ 'OperaMobile' ] || X_UA[ 'OperaTablet' ] ? 'loadeddata' : 'canplay', X_Audio_HTMLAudioWrapper, X_Audio_constructor = window.Audio || window.HTMLAudioElement, X_Audio_rawAudio, // Opera Mobile 12 android4.4.4 & 2.3.5 は 2回目以降の currentTime へのセットで currentTime が更新されなくなるため、タイマーを使用する - X_Audio_HTMLAudioWrapper_currentTimeFix = !!X_UA.OperaMobile || !!X_UA.OperaTablet, // || ( X_UA.WinPhone && X_UA.IE9 ), + X_Audio_HTMLAudioWrapper_currentTimeFix = !!X_UA[ 'OperaMobile' ] || !!X_UA[ 'OperaTablet' ], // || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ), // Android1.6+MobileOpera12では無理っぽい、、、 - X_Audio_HTMLAudioWrapper_badOperaAndroid = X_Audio_HTMLAudioWrapper_currentTimeFix && X_UA.Android < 2, + X_Audio_HTMLAudioWrapper_badOperaAndroid = X_Audio_HTMLAudioWrapper_currentTimeFix && X_UA[ 'Android' ] < 2, // 一方 Desktop の Opera12 は、loadeddata 等では duration が infinity で、再生後の durationchange 時に duration が判明する。 // opera12 volume, mute の変更が2度目以降できない @@ -26,10 +26,10 @@ var X_Audio_HTMLAudio_playTrigger = // Opera12.17 Win32(XP) portable apps は勝手に再生が始まる、、、その際には timeupdate が発行されない、、、 iframe+image+audio で使わないときは破棄する、とか。 // opera11、10.54 WinXP はまとも、、、 // X_Audio_Sprite_handleEvent でも使用 - X_Audio_HTMLAudioWrapper_ieMobile9Fix = ( X_UA.WinPhone && X_UA.IE9 ), - X_Audio_HTMLAudioWrapper_durationFix = ( !X_Audio_HTMLAudioWrapper_currentTimeFix && 12 <= X_UA.Opera ), + X_Audio_HTMLAudioWrapper_ieMobile9Fix = ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ), + X_Audio_HTMLAudioWrapper_durationFix = ( !X_Audio_HTMLAudioWrapper_currentTimeFix && 12 <= X_UA[ 'Opera' ] ), - X_Audio_HTMLAudioWrapper_shortPlayFix = !!X_UA.AndroidBrowser4, + X_Audio_HTMLAudioWrapper_shortPlayFix = !!X_UA[ 'AndroidBrowser4' ], X_Audio_codecs; @@ -60,13 +60,13 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ } else { // iOS3.2.3 X_Audio_codecs = { - mp3 : X_UA.IE || X_UA.Chrome || ( X_UA.Windows && X_UA.Safari ), - ogg : 5 <= X_UA.Gecko || X_UA.Chrome || X_UA.Opera, - wav : X_UA.Gecko || X_UA.Opera || ( X_UA.Windows && X_UA.Safari ), - aac : X_UA.IE || X_UA.WebKit, - m4a : X_UA.IE || X_UA.WebKit, - mp4 : X_UA.IE || X_UA.WebKit, - weba : 2 <= X_UA.Gecko || 10.6 <= X_UA.Opera // firefox4+(Gecko2+) + mp3 : X_UA[ 'IE' ] || X_UA[ 'Chrome' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ] ), + ogg : 5 <= X_UA[ 'Gecko' ] || X_UA[ 'Chrome' ] || X_UA[ 'Opera' ] , + wav : X_UA[ 'Gecko' ] || X_UA[ 'Opera' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ] ), + aac : X_UA[ 'IE' ] || X_UA[ 'WebKit' ], + m4a : X_UA[ 'IE' ] || X_UA[ 'WebKit' ], + mp4 : X_UA[ 'IE' ] || X_UA[ 'WebKit' ], + weba : 2 <= X_UA[ 'Gecko' ] || 10.6 <= X_UA[ 'Opera' ] // firefox4+(Gecko2+) }; }; @@ -148,13 +148,13 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ X_Audio_rawAudio = null; }; - this.listenOnce( X.Event.KILL_INSTANCE ); + this.listenOnce( X_Event.KILL_INSTANCE ); }, handleEvent : function( e ){ switch( e.type ){ - case X.Event.KILL_INSTANCE : + case X_Event.KILL_INSTANCE : break; }; }, @@ -202,14 +202,14 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ break; case 'error' : // コンテンツの取得実行中にエラーが発生した場合に発生 - type = X.Event.ERROR; + type = X_Event.ERROR; break; case 'playing' : // 再生が開始された場合に発生 if( X_Audio_HTMLAudioWrapper_currentTimeFix ){ this._playTime = X_Timer_now(); }; - type = X.Event.MEDIA_PLAYING; + type = X_Event.MEDIA_PLAYING; case 'play' : // 再生が開始された。play()メソッドからの復帰後に発生する場合に発生 case 'pause' : // 再生が一時停止された。pauseメソッドからの復帰後に発生する場合に発生 case 'seeked' : // シークがfalseに変化した場合に発生 @@ -219,22 +219,22 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ break; case 'waiting' : // 次のフレームが利用不可のため再生を停止したが、そのフレームがやがて利用可能になると想定している場合に発生 - type = X.Event.MEDIA_WAITING; + type = X_Event.MEDIA_WAITING; case 'seeking' : // シークがtrueに変化し、イベントを発生させるのに十分な時間がシーク操作にかかっている場合に発生 - type = type || X.Event.MEDIA_SEEKING; + type = type || X_Event.MEDIA_SEEKING; if( this._playForDuration === 1 ) return; break; case 'ended' : if( !this._closed && this.loop ){ - if( !( this.proxy.dispatch( X.Event.MEDIA_BEFORE_LOOP ) & X.Callback.PREVENT_DEFAULT ) ){ + if( !( this.proxy.dispatch( X_Event.MEDIA_BEFORE_LOOP ) & X.Callback.PREVENT_DEFAULT ) ){ this.looped = true; - this.proxy.dispatch( X.Event.MEDIA_LOOPED ); + this.proxy.dispatch( X_Event.MEDIA_LOOPED ); this.play(); }; return; }; - type = X.Event.MEDIA_ENDED; + type = X_Event.MEDIA_ENDED; this.seekTime = 0; delete this.playing; break; @@ -243,7 +243,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ if( X_Audio_HTMLAudioWrapper_ieMobile9Fix ){ if( this._playForDuration === 1 ){ console.log( 'tu ' + this._rawObject.duration ); - if( !this.duration && X.Type.isFinite( this._rawObject.duration ) ){ + if( !this.duration && X_Type_isFinite( this._rawObject.duration ) ){ this.duration = this.duration || this._rawObject.duration * 1000; this._playForDuration = 2; @@ -261,7 +261,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ } else if( this._rawObject.currentTime === this._lastCurrentTime ){ //this.proxy.dispatch( 'seeking' ); - this.proxy.dispatch( X.Event.MEDIA_WAITING ); + this.proxy.dispatch( X_Event.MEDIA_WAITING ); return; }; this._lastCurrentTime = this._rawObject.currentTime; @@ -273,21 +273,21 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ now = X_Audio_HTMLAudioWrapper_currentTimeFix ? X_Timer_now() - this._playTime + this._beginTime : this._rawObject.currentTime * 1000 | 0; if( 0 + end <= 0 + now ){ // なぜか iem9 で必要,,, if( this.loop ){ - if( !( this.proxy.dispatch( X.Event.MEDIA_BEFORE_LOOP ) & X.Callback.PREVENT_DEFAULT ) ){ + if( !( this.proxy.dispatch( X_Event.MEDIA_BEFORE_LOOP ) & X.Callback.PREVENT_DEFAULT ) ){ this.looped = true; - this.proxy.dispatch( X.Event.MEDIA_LOOPED ); + this.proxy.dispatch( X_Event.MEDIA_LOOPED ); this.play(); }; } else { this.pause(); - this.proxy.dispatch( X.Event.MEDIA_ENDED ); + this.proxy.dispatch( X_Event.MEDIA_ENDED ); }; return; }; } else { return; }; - type = X.Event.MEDIA_PLAYING; + type = X_Event.MEDIA_PLAYING; break; case 'durationchange' : // duration属性が更新された場合に発生 @@ -296,7 +296,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ this.duration = this._rawObject.duration * 1000; } else // Desktop Opera では Infinity, IEM9 では NaN - if( !this.duration && X.Type.isFinite( this._rawObject.duration ) ){ + if( !this.duration && X_Type_isFinite( this._rawObject.duration ) ){ //console.log( this._rawObject.duration ); @@ -344,7 +344,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ if( !this._loaded && ( loaded || e.type === X_Audio_HTMLAudio_playTrigger || e.type === 'loadeddata' ) ){ this.autoplay && X.Timer.once( 16, this, this.play ); this._loaded = true; - this.proxy.dispatch( X.Event.READY ); + this.proxy.dispatch( X_Event.READY ); console.log( 'Loaded! ' + e.type + ' d:' + ( this.duration | 0 ) ); return; }; @@ -395,7 +395,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ if( !this.playing ){ - if( X_UA.Chrome ){ // [CHROME][FIX] volume TODO どの version で 修正される? + if( X_UA[ 'Chrome' ] ){ // [CHROME][FIX] volume TODO どの version で 修正される? // [!] delay X.Timer.once( 0, this, this._fixForChrome ); this._rawObject.volume = 0; @@ -420,7 +420,7 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ }, // [CHROME][FIX] volume - _fixForChrome : X_UA.Chrome && function(){ + _fixForChrome : X_UA[ 'Chrome' ] && function(){ !this._closed && ( this._rawObject.volume = this.volume ); }, @@ -529,23 +529,23 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ var ok, mineType = 'audio/' + ext; switch( ext ){ case 'mp3' : - ok = X_UA.IE || X_UA.Chrome || ( X_UA.Windows && X_UA.Safari ); + ok = X_UA[ 'IE' ] || X_UA[ 'Chrome' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ] ); mineType = 'audio/mpeg'; - //if( X_UA.Android && X_UA.Gecko ) mineType = ''; + //if( X_UA[ 'Android' ] && X_UA[ 'Gecko' ] ) mineType = ''; break; case 'ogg' : - ok = 15 <= X_UA.Gecko || X_UA.Chrome || X_UA.Opera; - if( X_UA.AndroidBrowser ) mineType = ''; + ok = 15 <= X_UA[ 'Gecko' ] || X_UA[ 'Chrome' ] || X_UA[ 'Opera' ] ; + if( X_UA[ 'AndroidBrowser' ] ) mineType = ''; break; case 'm4a' : - ok = X_UA.IE || X_UA.WebKit; + ok = X_UA[ 'IE' ] || X_UA[ 'WebKit' ]; mineType = 'audio/mp4'; break; case 'webm' : - ok = 2 <= X_UA.Gecko || 10.6 <= X_UA.Opera; // firefox4+(Gecko2+) + ok = 2 <= X_UA[ 'Gecko' ] || 10.6 <= X_UA[ 'Opera' ] ; // firefox4+(Gecko2+) break; case 'wav' : - ok = X_UA.Gecko || X_UA.Opera || ( X_UA.Windows && X_UA.Safari ); + ok = X_UA[ 'Gecko' ] || X_UA[ 'Opera' ] || ( X_UA[ 'Windows' ] && X_UA[ 'Safari' ] ); //mineType = 'audio/wav'; // audio/x-wav ? break; default : @@ -558,9 +558,9 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ //console.log( 'HTML Audio ' + ok + ' ext:' + ext ); }; console.log( 'HTML Audio ' + ok + ' ext:' + ext ); - proxy.asyncDispatch( ok ? X_Audio_CAN_PLAY : X_Audio_NOT_PLAY ); */ + */ - proxy.asyncDispatch( X_Audio_codecs[ ext ] ? X_Audio_CAN_PLAY : X_Audio_NOT_PLAY ); + proxy.asyncDispatch( { type : X_Event.COMPLETE, canPlay : X_Audio_codecs[ ext ] } ); }, klass : X_Audio_HTMLAudioWrapper diff --git a/0.6.x/js/07_audio/03_XSilverlightAudio.js b/0.6.x/js/07_audio/03_XSilverlightAudio.js index 9a792fd..ce8ffa7 100644 --- a/0.6.x/js/07_audio/03_XSilverlightAudio.js +++ b/0.6.x/js/07_audio/03_XSilverlightAudio.js @@ -90,7 +90,7 @@ if( X.Pulgin.SilverlightEnabled ){ ); X_AudioWrapper_updateStates( this, option ); - this.listenOnce( X.Event.KILL_INSTANCE ); + this.listenOnce( X_Event.KILL_INSTANCE ); }, onSLReady : function( sender ){ @@ -125,7 +125,7 @@ if( X.Pulgin.SilverlightEnabled ){ this.playing = false; this._ended = true; this._paused = false; - this.proxy.dispatch( X.Event.ERROR ); // open failed + this.proxy.dispatch( X_Event.ERROR ); // open failed break; case 'MediaOpened' : @@ -137,7 +137,7 @@ if( X.Pulgin.SilverlightEnabled ){ //this.proxy.asyncDispatch( 'loadeddata' ); //this.proxy.asyncDispatch( 'canplay' ); //this.proxy.asyncDispatch( 'canplaythrough' ); - this.proxy.asyncDispatch( X.Event.READY ); + this.proxy.asyncDispatch( X_Event.READY ); this.autoplay && X.Timer.once( 16, this, this.play ); break; @@ -162,10 +162,10 @@ if( X.Pulgin.SilverlightEnabled ){ case 'Opening' : switch( this._lastUserAction ){ case 'play' : - this.proxy.dispatch( X.Event.MEDIA_WAITING ); + this.proxy.dispatch( X_Event.MEDIA_WAITING ); break; case 'seek' : - this.proxy.dispatch( X.Event.MEDIA_SEEKING ); + this.proxy.dispatch( X_Event.MEDIA_SEEKING ); break; case 'pause' : break; @@ -182,7 +182,7 @@ if( X.Pulgin.SilverlightEnabled ){ this.playing = false; this._ended = true; this._paused = false; - this.proxy.dispatch( X.Event.ERROR ); + this.proxy.dispatch( X_Event.ERROR ); break; // userAction.pause() -> MediaState('Paused') -> x @@ -197,7 +197,7 @@ if( X.Pulgin.SilverlightEnabled ){ this.seekTime = 0; this._ended = true; this._paused = false; - this.proxy.dispatch( X.Event.MEDIA_ENDED ); + this.proxy.dispatch( X_Event.MEDIA_ENDED ); this._currentTime( this.startTime ); break; case 'pause': @@ -216,7 +216,7 @@ if( X.Pulgin.SilverlightEnabled ){ this.playing = true; this._ended = false; this._paused = false; - this.proxy.dispatch( X.Event.MEDIA_PLAYING ); + this.proxy.dispatch( X_Event.MEDIA_PLAYING ); break; // stop() @@ -229,7 +229,7 @@ if( X.Pulgin.SilverlightEnabled ){ }; break; - case X.Event.KILL_INSTANCE : + case X_Event.KILL_INSTANCE : if( this._onload ){ // window への delete に ie5 は対応しないが、そもそも ie5 は Silverlight に非対応 window[ this._onload ] = null; @@ -243,7 +243,7 @@ if( X.Pulgin.SilverlightEnabled ){ close : function(){ this.playing && this.pause(); - this.proxy.dispatch( X.Event.MEDIA_ENDED ); + this.proxy.dispatch( X_Event.MEDIA_ENDED ); this.kill(); }, @@ -294,7 +294,7 @@ if( X.Pulgin.SilverlightEnabled ){ delete this._interval; return X_Callback_UN_LISTEN; }; - this.proxy.dispatch( X.Event.MEDIA_PLAYING ); + this.proxy.dispatch( X_Event.MEDIA_PLAYING ); }, _onEnded : function(){ @@ -307,7 +307,7 @@ if( X.Pulgin.SilverlightEnabled ){ if( time <= this._beginTime ){ console.log( '== waiting' ); - this.proxy.dispatch( X.Event.MEDIA_WAITING ); + this.proxy.dispatch( X_Event.MEDIA_WAITING ); this._timerID = X.Timer.once( X_AudioWrapper_getEndTime( this ) - this._beginTime, this, this._onEnded ); return; }; @@ -320,14 +320,14 @@ if( X.Pulgin.SilverlightEnabled ){ }; if( this.loop ){ - if( !( this.proxy.dispatch( X.Event.MEDIA_BEFORE_LOOP ) & X.Callback.PREVENT_DEFAULT ) ){ + if( !( this.proxy.dispatch( X_Event.MEDIA_BEFORE_LOOP ) & X.Callback.PREVENT_DEFAULT ) ){ this.looped = true; - this.proxy.dispatch( X.Event.MEDIA_LOOPED ); + this.proxy.dispatch( X_Event.MEDIA_LOOPED ); this.play(); }; } else { this.pause(); - this.proxy.dispatch( X.Event.MEDIA_ENDED ); + this.proxy.dispatch( X_Event.MEDIA_ENDED ); }; }; }, @@ -413,7 +413,7 @@ if( X.Pulgin.SilverlightEnabled ){ detect : function( proxy, source, ext ){ var ok = ext === 'mp3' || ext === 'wma' || ext === 'wav'; - proxy.asyncDispatch( ok ? X_Audio_CAN_PLAY : X_Audio_NOT_PLAY ); + proxy.asyncDispatch( { type : X_Event.COMPLETE, canPlay : ok } ); }, klass : X_Audio_SLAudioWrapper diff --git a/0.6.x/js/07_audio/10_XAudioSprite.js b/0.6.x/js/07_audio/10_XAudioSprite.js index 6cdc290..289d319 100644 --- a/0.6.x/js/07_audio/10_XAudioSprite.js +++ b/0.6.x/js/07_audio/10_XAudioSprite.js @@ -4,12 +4,12 @@ * Mobile Opera11 は Audio をサポートするがイベントが取れない * iframe 内で生成して、Audio Sprite の preset で再生できないか? */ -var X_Audio_Sprite_shouldUse = window.HTMLAudioElement && ( X_UA.iOS || X_UA.AndroidBrowser || X_UA.OperaMobile || X_UA.OperaTablet ), // Flash がない - X_Audio_Sprite_useVideoForMulti = 4 <= X_UA.AndroidBrowser && 534.3 < X_UA.AndroidBrowserWebkit, // ドスパラパッドはビデオのインライン再生が不可 +var X_Audio_Sprite_shouldUse = window.HTMLAudioElement && ( X_UA[ 'iOS' ] || X_UA[ 'AndroidBrowser' ] || X_UA[ 'OperaMobile' ] || X_UA[ 'OperaTablet' ] ), // Flash がない + X_Audio_Sprite_useVideoForMulti = 4 <= X_UA[ 'AndroidBrowser' ] && 534.3 < X_UA[ 'AndroidBrowserWebkit' ], // ドスパラパッドはビデオのインライン再生が不可 X_Audio_Sprite_needTouchAndroid = X_Audio_Sprite_useVideoForMulti, - X_Audio_Sprite_needTouchFirst = X_UA.iOS || X_Audio_Sprite_needTouchAndroid || ( X_UA.WinPhone && X_UA.IE9 ), - X_Audio_Sprite_enableMultiTrack = !( X_UA.iOS && !X_Audio_WebAudio_context ) && !( X_UA.AndroidBrowser4 && X_UA.AndroidBrowserWebkit <= 534.3 ), - X_Audio_Sprite_enableVolume = window.HTMLAudioElement && ( !X_UA.iOS && !X_UA.AndroidBrowser && !X_UA.OperaMobile && !X_UA.OperaTablet ), // TODO fennec は 25以上 + X_Audio_Sprite_needTouchFirst = X_UA[ 'iOS' ] || X_Audio_Sprite_needTouchAndroid || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ), + X_Audio_Sprite_enableMultiTrack = !( X_UA[ 'iOS' ] && !X_Audio_WebAudio_context ) && !( X_UA[ 'AndroidBrowser4' ] && X_UA[ 'AndroidBrowserWebkit' ] <= 534.3 ), + X_Audio_Sprite_enableVolume = window.HTMLAudioElement && ( !X_UA[ 'iOS' ] && !X_UA[ 'AndroidBrowser' ] && !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] ), // TODO fennec は 25以上 X_Audio_Sprite_maxTracks = !X_Audio_Sprite_enableMultiTrack ? 1 : X_Audio_Sprite_useVideoForMulti ? 2 : 9, X_Audio_Sprite_lengthSilence = 10000, // 一番最初の無音部分の長さ X_Audio_Sprite_lengthDistance = 5000, // 音間の無音の長さ @@ -19,7 +19,7 @@ var X_Audio_Sprite_shouldUse = window.HTMLAudioElement && ( X_UA.iOS || X presets : {}, BGMs : {}, tracks : [], - pauseTracks : [], // X.Event.DEACTIVATE によって pause した再生中のトラックたち。 + pauseTracks : [], // X_Event.DEACTIVATE によって pause した再生中のトラックたち。 volume : 1, bgmTrack : null, bgmPosition : 0, @@ -43,7 +43,7 @@ X.Audio.Sprite = { X_Audio_Sprite_instance.close(); } else { X_Audio_Sprite_instance = X_Class_override( new X.EventDispatcher(), X_Audio_Sprite_members ); - X_ViewPort.listen( [ X.Event.VIEW_ACTIVATE, X.Event.VIEW_DEACTIVATE ], X_Audio_Sprite_instance, X_Audio_Sprite_handleEvent ); + X_ViewPort.listen( [ X_Event.VIEW_ACTIVATE, X_Event.VIEW_DEACTIVATE ], X_Audio_Sprite_instance, X_Audio_Sprite_handleEvent ); }; X_Audio_Sprite_instance.setup( setting ); return X_Audio_Sprite_instance; @@ -83,12 +83,12 @@ function X_Audio_Sprite_getTrackEnded(){ * BGM_02 : [ '56.00', '1:15.230', true ] * } * - * X.Event.BACKEND_READY - * X.Event.BACKEND_NONE + * X_Event.BACKEND_READY + * X_Event.BACKEND_NONE * - * X.Event.READY - * X.Event.MEDIA_LOOPED - * X.Event.MEDIA_ENDED + * X_Event.READY + * X_Event.MEDIA_LOOPED + * X_Event.MEDIA_ENDED * */ @@ -115,7 +115,7 @@ X_Audio_Sprite_members = { for( k in setting ){ v = setting[ k ]; - if( X.Type.isArray( v ) && v !== urls ){ + if( X_Type_isArray( v ) && v !== urls ){ v = X.Object.cloneArray( v ); for( i = v.length; i; ){ --i; @@ -133,7 +133,7 @@ X_Audio_Sprite_members = { tracks.push( X.Audio( urls, X.Object.clone( option ) ) ); }; - tracks[ n - 1 ].listenOnce( [ X.Event.BACKEND_READY, X.Event.BACKEND_NONE ], this, X_Audio_Sprite_handleEvent ); + tracks[ n - 1 ].listenOnce( [ X_Event.BACKEND_READY, X_Event.BACKEND_NONE ], this, X_Audio_Sprite_handleEvent ); X_Audio_Sprite_instance.numTracks = n; }, @@ -166,7 +166,7 @@ X_Audio_Sprite_members = { var tracks = X_Audio_Sprite_TEMP.tracks, i = 0, l = tracks.length; for( ; i < l; ++i ){ - if( X_UA.WinPhone ){ + if( X_UA[ 'WinPhone' ] ){ console.log( 'touch -> play()' ); //tracks[ i ].play( 0, X_Audio_Sprite_lengthSilence, true, 0, X_Audio_Sprite_lengthSilence ).seek( 0 ); this.pause( i ); @@ -205,7 +205,7 @@ X_Audio_Sprite_members = { track = X_Audio_Sprite_TEMP.bgmTrack = tracks[ 0 ]; }; - if( track.listen( [ X.Event.MEDIA_PLAYING, X.Event.MEDIA_BEFORE_LOOP ], this, X_Audio_Sprite_handleEvent ).isPlaying() ){ + if( track.listen( [ X_Event.MEDIA_PLAYING, X_Event.MEDIA_BEFORE_LOOP ], this, X_Audio_Sprite_handleEvent ).isPlaying() ){ track .state( { loop : true, @@ -227,7 +227,7 @@ X_Audio_Sprite_members = { if( 1 < tracks.length ){ track = X_Audio_Sprite_getTrackEnded( X_Audio_Sprite_TEMP.bgmPlaying ); track - .listen( [ X.Event.MEDIA_PLAYING, X.Event.MEDIA_BEFORE_LOOP ], this, X_Audio_Sprite_handleEvent ) + .listen( [ X_Event.MEDIA_PLAYING, X_Event.MEDIA_BEFORE_LOOP ], this, X_Audio_Sprite_handleEvent ) .state( { looped : false } ) .play( preset[ 0 ], preset[ 1 ], true, 0, X_Audio_Sprite_lengthSilence ); } else { @@ -239,7 +239,7 @@ X_Audio_Sprite_members = { }; track = tracks[ 0 ]; - if( track.listen( [ X.Event.MEDIA_PLAYING, X.Event.MEDIA_BEFORE_LOOP ], this, X_Audio_Sprite_handleEvent ).isPlaying() ){ + if( track.listen( [ X_Event.MEDIA_PLAYING, X_Event.MEDIA_BEFORE_LOOP ], this, X_Audio_Sprite_handleEvent ).isPlaying() ){ track .state( { loop : true, @@ -268,7 +268,7 @@ X_Audio_Sprite_members = { X_Audio_Sprite_TEMP.bgmTrack = null; }; track && track.play( 0, X_Audio_Sprite_lengthSilence, true, 0, X_Audio_Sprite_lengthSilence ).seek( 0 ); - this.asyncDispatch( X.Event.MEDIA_PAUSED ); + this.asyncDispatch( X_Event.MEDIA_PAUSED ); return this; }, @@ -318,9 +318,9 @@ function X_Audio_Sprite_handleEvent( e ){ var i, tracks, track, _e; switch( e.type ){ - case X.Event.BACKEND_READY : + case X_Event.BACKEND_READY : _e = { - type : e.type, + type : X_Event.BACKEND_READY, source : e.source, backendName : e.backendName }; @@ -335,8 +335,8 @@ function X_Audio_Sprite_handleEvent( e ){ this.asyncDispatch( _e ); e.target - .unlisten( X.Event.BACKEND_NONE, this, X_Audio_Sprite_handleEvent ) - .listenOnce( X.Event.READY, this, X_Audio_Sprite_handleEvent ); + .unlisten( X_Event.BACKEND_NONE, this, X_Audio_Sprite_handleEvent ) + .listenOnce( X_Event.READY, this, X_Audio_Sprite_handleEvent ); // READY, needTouchForPlay, needTouchForLoad if( X_Audio_HTMLAudioWrapper_durationFix ){ @@ -346,36 +346,36 @@ function X_Audio_Sprite_handleEvent( e ){ }; break; - case X.Event.BACKEND_NONE : - this.asyncDispatch( X.Event.BACKEND_NONE ); - e.target.unlisten( X.Event.BACKEND_READY, this, X_Audio_Sprite_handleEvent ); + case X_Event.BACKEND_NONE : + this.asyncDispatch( X_Event.BACKEND_NONE ); + e.target.unlisten( X_Event.BACKEND_READY, this, X_Audio_Sprite_handleEvent ); break; - case X.Event.READY : + case X_Event.READY : console.log( 'X.AudioSprite - Ready!' ); if( X_Audio_Sprite_needTouchAndroid ){ for( i = 0; i < X_Audio_Sprite_TEMP.tracks.length; ++i ){ X_Audio_Sprite_instance.pause( i ); }; - e.target.listenOnce( X.Event.MEDIA_PLAYING, this, this.asyncDispatch, [ X.Event.READY ] ); // Android 標準ブラウザ + e.target.listenOnce( X_Event.MEDIA_PLAYING, this, this.asyncDispatch, [ X_Event.READY ] ); // Android 標準ブラウザ return; }; - this.asyncDispatch( X.Event.READY ); + this.asyncDispatch( X_Event.READY ); break; - case X.Event.MEDIA_PLAYING : - ( e.target === X_Audio_Sprite_TEMP.bgmTrack || !e.target.state().looped ) && this.asyncDispatch( X.Event.MEDIA_PLAYING ); + case X_Event.MEDIA_PLAYING : + ( e.target === X_Audio_Sprite_TEMP.bgmTrack || !e.target.state().looped ) && this.asyncDispatch( X_Event.MEDIA_PLAYING ); break; - case X.Event.MEDIA_BEFORE_LOOP : + case X_Event.MEDIA_BEFORE_LOOP : if( e.target === X_Audio_Sprite_TEMP.bgmTrack ){ X_Audio_Sprite_TEMP.bgmLooped = true; - this.asyncDispatch( X.Event.MEDIA_LOOPED ); // TODO uid + this.asyncDispatch( X_Event.MEDIA_LOOPED ); // TODO uid } else { if( e.target.state().looped ){ - //this.asyncDispatch( X.Event.MEDIA_LOOPED ); // TODO uid + //this.asyncDispatch( X_Event.MEDIA_LOOPED ); // TODO uid } else { - this.asyncDispatch( X.Event.MEDIA_ENDED ); // TODO uid + this.asyncDispatch( X_Event.MEDIA_ENDED ); // TODO uid }; // single track | iOS @@ -387,14 +387,14 @@ function X_Audio_Sprite_handleEvent( e ){ }; break; - case X.Event.VIEW_ACTIVATE : + case X_Event.VIEW_ACTIVATE : console.log( '■ アクティブ' ); // track.play(); or iOS need touch?? tracks = X_Audio_Sprite_TEMP.pauseTracks; while( tracks.length ) tracks.pop().play(); break; - case X.Event.VIEW_DEACTIVATE : + case X_Event.VIEW_DEACTIVATE : console.log( '■ デアクティブ' ); // track.pause(); tracks = X_Audio_Sprite_TEMP.tracks; @@ -405,8 +405,8 @@ function X_Audio_Sprite_handleEvent( e ){ }; break; - case X.Event.KILL_INSTANCE : - X_ViewPort.unlisten( [ X.Event.VIEW_ACTIVATE, X.Event.VIEW_DEACTIVATE ], this, X_Audio_Sprite_handleEvent ); + case X_Event.KILL_INSTANCE : + X_ViewPort.unlisten( [ X_Event.VIEW_ACTIVATE, X_Event.VIEW_DEACTIVATE ], this, X_Audio_Sprite_handleEvent ); this.close(); break; }; diff --git a/0.6.x/js/20_ui/02_XUI_Attr.js b/0.6.x/js/20_ui/02_XUI_Attr.js index e29227f..36e8118 100644 --- a/0.6.x/js/20_ui/02_XUI_Attr.js +++ b/0.6.x/js/20_ui/02_XUI_Attr.js @@ -46,9 +46,9 @@ X.UI.Attr = { for( p in defs ){ if( X_EMPTY_OBJECT[ p ] ) continue; if( p === '_last' ) continue; - if( !X.Type.isArray( def = defs[ p ] ) ) continue; + if( !X_Type_isArray( def = defs[ p ] ) ) continue; F[ p ] = def; - if( !base || !X.Type.isArray( base[ p ] ) ){ + if( !base || !X_Type_isArray( base[ p ] ) ){ def.No = z += n; // add n = def[ 3 ] & X.UI.Attr.Type.QUARTET ? 4 : diff --git a/0.6.x/js/20_ui/04_XUI_Event.js b/0.6.x/js/20_ui/04_XUI_Event.js index fce156a..893359f 100644 --- a/0.6.x/js/20_ui/04_XUI_Event.js +++ b/0.6.x/js/20_ui/04_XUI_Event.js @@ -28,19 +28,10 @@ X.UI.Event = { _START_BUBLEUP : X_Event_last + 0.5, // raw pointing device event - _POINTER_DOWN : ++X_Event_last, _POINTER_UP : ++X_Event_last, _POINTER_MOVE : ++X_Event_last, _POINTER_CANCEL : ++X_Event_last, - _TOUCH_START : ++X_Event_last, - _TOUCH_END : ++X_Event_last, - _TOUCH_MOVE : ++X_Event_last, - _TOUCH_CANCEL : ++X_Event_last, - _MOUSE_DOWN : ++X_Event_last, - _MOUSE_UP : ++X_Event_last, - _MOUSE_MOVE : ++X_Event_last, - _MOUSE_CANCEL : ++X_Event_last, FILE_DRAG : ++X_Event_last, FILE_DRAG_START : ++X_Event_last, @@ -125,26 +116,11 @@ X.UI.Event = { NameToID : {} }; -// raw pointing device event -//if( X_UA_HID.POINTER ){ X.UI.Event.IdToName[ X.UI.Event._POINTER_DOWN ] = 'pointerdown'; X.UI.Event.IdToName[ X.UI.Event._POINTER_UP ] = 'pointerup'; X.UI.Event.IdToName[ X.UI.Event._POINTER_MOVE ] = 'pointermove'; X.UI.Event.IdToName[ X.UI.Event._POINTER_CANCEL ] = 'pointercancel'; -/*} else { - - if( X_UA_HID.TOUCH ){ - X.UI.Event.IdToName[ X.UI.Event._TOUCH_START ] = 'touchstart'; - X.UI.Event.IdToName[ X.UI.Event._TOUCH_END ] = 'touchend'; - X.UI.Event.IdToName[ X.UI.Event._TOUCH_MOVE ] = 'touchmove'; - X.UI.Event.IdToName[ X.UI.Event._TOUCH_CANCEL ] = 'touchcancel'; - }; - X.UI.Event.IdToName[ X.UI.Event._MOUSE_DOWN ] = 'mousedown'; - X.UI.Event.IdToName[ X.UI.Event._MOUSE_UP ] = 'mouseup'; - X.UI.Event.IdToName[ X.UI.Event._MOUSE_MOVE ] = 'mousemove'; - X.UI.Event.IdToName[ X.UI.Event._MOUSE_CANCEL ] = 'mouseleave'; // ?? -};*/ ( function( IdToName, NameToID, p ){ diff --git a/0.6.x/js/20_ui/05_XUI_Gesture.js b/0.6.x/js/20_ui/05_XUI_Gesture.js index 4d602f7..1378f7d 100644 --- a/0.6.x/js/20_ui/05_XUI_Gesture.js +++ b/0.6.x/js/20_ui/05_XUI_Gesture.js @@ -47,39 +47,30 @@ type |= POINTER; switch( e.pointerType ){ case 'touch' : - case 2 : //e.MSPOINTER_TYPE_TOUCH : type |= TOUCH; break; case 'pen' : - case 3 : //e.MSPOINTER_TYPE_PEN : type |= PEN; break; case 'mouse' : - case 4 : //e.MSPOINTER_TYPE_MOUSE : type |= MOUSE; break; default : return; }; - } else - if( e.touches ){ - type |= TOUCH; - } else { - type |= MOUSE; }; // onmouseup, but when touchend has been fired we do nothing. // this is for touchdevices which also fire a mouseup on touchend if( type & MOUSE && touch_triggered ){ return X.Callback.STOP_NOW | X.Callback.PREVENT_DEFAULT; - } + } else // mousebutton must be down or a touch event - else if ( - type & TOUCH || //sourceEventType.match(/touch/) || // touch events are always on screen + if( type & TOUCH || //sourceEventType.match(/touch/) || // touch events are always on screen ( type & POINTER && type & START ) || //sourceEventType.match(/pointerdown/) || // pointerevents touch ( type & MOUSE && e.button === 0 ) //(sourceEventType.match(/mouse/) && e.which === 1) // mouse is pressed ){ enable_detect = true; }; - console.log( 'Hammer@handleEvent ' + IdToGestureID[ e.type ] + ' ' + e.type + ' ' + X.UI.Event._POINTER_DOWN + ' ' + enable_detect ); + //console.log( 'Hammer@handleEvent ' + IdToGestureID[ e.type ] + ' ' + e.type + ' ' + X.UI.Event._POINTER_DOWN + ' ' + enable_detect ); // we are in a touch event, set the touch triggered bool to true, // this for the conflicts that may occur on ios and android @@ -266,18 +257,8 @@ Detection.register( Gestures[ name ] ); }; - //if( X_UA_HID.POINTER ){ - Hammer.EVENT_TYPES_START = [ X.UI.Event._POINTER_DOWN ]; - types = [ X.UI.Event._POINTER_MOVE, X.UI.Event._POINTER_UP, X.UI.Event._POINTER_CANCEL ]; - /*} else - if( X_UA_HID.TOUCH ){ - Hammer.EVENT_TYPES_START = [ X.UI.Event._TOUCH_START, X.UI.Event._MOUSE_DOWN ]; - types = [ X.UI.Event._MOUSE_MOVE, X.UI.Event._MOUSE_UP, X.UI.Event._MOUSE_CANCEL, - X.UI.Event._TOUCH_MOVE, X.UI.Event._TOUCH_END, X.UI.Event._TOUCH_CANCEL ]; - } else { - Hammer.EVENT_TYPES_START = [ X.UI.Event._MOUSE_DOWN ]; - types = [ X.UI.Event._MOUSE_MOVE, X.UI.Event._MOUSE_UP, X.UI.Event._MOUSE_CANCEL ]; - }; */ + Hammer.EVENT_TYPES_START = [ X.UI.Event._POINTER_DOWN ]; + types = [ X.UI.Event._POINTER_MOVE, X.UI.Event._POINTER_UP, X.UI.Event._POINTER_CANCEL ]; // Add touch events on the document Utils.addEvents( uinodeRoot, types, Hammer.prototype.handleEvent ); @@ -329,7 +310,7 @@ /* * "Android version < 2.2" return ev.touches.length === 1 when touchend, others return ev.touches.length === 0 */ - Hammer.DO_TOUCHES_FIX = Hammer.HAS_TOUCHEVENTS && ( X_UA.Android < 2.2 || X_UA.Blink || X_UA.Opera ); + Hammer.DO_TOUCHES_FIX = Hammer.HAS_TOUCHEVENTS && ( X_UA[ 'Android' ] < 2.2 || X_UA[ 'Blink' ] || X_UA[ 'Opera' ] ); // detect touchevents Hammer.HAS_POINTEREVENTS = true; // navigator.pointerEnabled || navigator.msPointerEnabled; @@ -365,16 +346,6 @@ IdToGestureID[ X.UI.Event._POINTER_UP ] = END; IdToGestureID[ X.UI.Event._POINTER_CANCEL ] = END; - IdToGestureID[ X.UI.Event._TOUCH_START ] = START; - IdToGestureID[ X.UI.Event._TOUCH_MOVE ] = MOVE; - IdToGestureID[ X.UI.Event._TOUCH_END ] = END; - IdToGestureID[ X.UI.Event._TOUCH_CANCEL ] = END; - - IdToGestureID[ X.UI.Event._MOUSE_DOWN ] = START; - IdToGestureID[ X.UI.Event._MOUSE_MOVE ] = MOVE; - IdToGestureID[ X.UI.Event._MOUSE_UP ] = END; - IdToGestureID[ X.UI.Event._MOUSE_CANCEL ] = END; - Utils = { /** diff --git a/0.6.x/js/20_ui/06_AbstractUINode.js b/0.6.x/js/20_ui/06_AbstractUINode.js index 14dea01..368c81d 100644 --- a/0.6.x/js/20_ui/06_AbstractUINode.js +++ b/0.6.x/js/20_ui/06_AbstractUINode.js @@ -123,7 +123,7 @@ X.UI._AbstractUINode = X.EventDispatcher.inherits( quartet = !!( type & X.UI.Attr.Type.QUARTET ), _v, i, l, nodes, root, roots; - if( X.Type.isString( v ) ){ + if( X_Type_isString( v ) ){ //v = v.toLowercase(); if( url || fontName ){ // good @@ -144,7 +144,7 @@ X.UI._AbstractUINode = X.EventDispatcher.inherits( if( v.indexOf( ' ' ) !== -1 ){ v = v.split( ' ' ); } else - if( color && X.Type.isNumber( _v = X_Node_CSS_objToIEFilterText( v ) ) ){ + if( color && X_Type_isNumber( _v = X_Node_CSS_objToIEFilterText( v ) ) ){ v = _v; } else { // bad @@ -152,11 +152,11 @@ X.UI._AbstractUINode = X.EventDispatcher.inherits( }; }; - if( ( quartet || combi ) && !X.Type.isArray( v ) ){ + if( ( quartet || combi ) && !X_Type_isArray( v ) ){ v = [ v ]; }; - if( X.Type.isNumber( v ) ){ + if( X_Type_isNumber( v ) ){ if( ( length && ( 0 <= v ) ) || ( minusLen && ( v <= 0 ) ) || @@ -173,10 +173,10 @@ X.UI._AbstractUINode = X.EventDispatcher.inherits( return; }; } else - if( X.Type.isBoolean( v ) && !flag ){ + if( X_Type_isBoolean( v ) && !flag ){ return; } else - if( X.Type.isArray( v ) ){ + if( X_Type_isArray( v ) ){ if( v.length <= 4 && quartet ){ type &= ~X.UI.Attr.Type.QUARTET; switch( v.length ){ @@ -245,11 +245,11 @@ X.UI._AbstractUINode = X.EventDispatcher.inherits( break; case X.UI.Attr.Support.width.No : this.autoWidth = v === X.UI.Attr.AUTO; - this.percentWidth = X.Type.isString( v ); + this.percentWidth = X_Type_isString( v ); break; case X.UI.Attr.Support.height.No : this.autoHeight = v === X.UI.Attr.AUTO; - this.percentHeight = X.Type.isString( v ); + this.percentHeight = X_Type_isString( v ); break; }; @@ -326,7 +326,7 @@ X.UI._AbstractUINode = X.EventDispatcher.inherits( url = !!( type & X.UI.Attr.Type.URL ), fontName = !!( type & X.UI.Attr.Type.FONT_NAME ); - if( X.Type.isNumber( v ) ){ + if( X_Type_isNumber( v ) ){ if( auto && v === X.UI.Attr.AUTO ) return 'auto'; if( length || minusLen ) return v + 'em'; if( numerical ) return v; @@ -339,7 +339,7 @@ X.UI._AbstractUINode = X.EventDispatcher.inherits( return '#' + v.toString( 16 ); }; }; - if( X.Type.isString( v ) ){ + if( X_Type_isString( v ) ){ if( percent || minusPct || url || fontName ) return v; }; }, @@ -368,8 +368,8 @@ X.UI._AbstractUINode = X.EventDispatcher.inherits( list = support[ 4 ]; if( list ) return list[ v ]; - if( type & X.UI.Attr.Type.COLOR && X.Type.isNumber( v ) ) return v; - if( !( type & X.UI.Attr.Type.NUMERICAL ) && X.Type.isNumber( v ) ) return v + 'em'; + if( type & X.UI.Attr.Type.COLOR && X_Type_isNumber( v ) ) return v; + if( !( type & X.UI.Attr.Type.NUMERICAL ) && X_Type_isNumber( v ) ) return v + 'em'; return v; }, @@ -420,7 +420,7 @@ X.UI._AbstractUINode = X.EventDispatcher.inherits( this.xnode .css( 'left', x ? x + 'em' : 0 ) .css( 'top', y ? y + 'em' : 0 ) - .css( 'width', this.contentWidth ? X.UI._AbstractUINode.ceil( this.contentWidth ) + 'em' : 0 ) + .css( 'width', this.contentWidth ? X.UI._AbstractUINode.ceil( this.contentWidth ) + 'em' : 0 ) .css( 'height', this.contentHeight ? X.UI._AbstractUINode.ceil( this.contentHeight ) + 'em' : 0 ) .css( 'padding', this._createCssText( 'padding' ) ) .css( 'borderWidth', this._createCssText( 'borderWidth' ) ); @@ -773,7 +773,7 @@ X.UI._AbstractUINode = X.EventDispatcher.inherits( ++counter[ type ]; } else { counter[ type ] = 1; - root.xnodeInteractiveLayer.listen( X.UI.Event.IdToName[ type ], X.UI._eventRellay ); + root.xnodeInteractiveLayer.listen( X.UI.Event.IdToName[ type ], X_UI_eventRellay ); }; }; }; @@ -809,7 +809,7 @@ X.UI._AbstractUINode = X.EventDispatcher.inherits( if( !counter[ type ] ) return this; --counter[ type ]; if( counter[ type ] === 0 ){ - root.xnodeInteractiveLayer.unlisten( X.UI.Event.IdToName[ type ], X.UI._eventRellay ); + root.xnodeInteractiveLayer.unlisten( X.UI.Event.IdToName[ type ], X_UI_eventRellay ); delete counter[ type ]; }; }; @@ -847,10 +847,10 @@ X.UI._AbstractUINode.calcValue = function( styleValue, srcValue ){ /* * String の場合は必ず % */ - if( X.Type.isString( styleValue ) ){ + if( X_Type_isString( styleValue ) ){ return srcValue * parseFloat( styleValue ) / 100; }; - if( !X.Type.isNumber( styleValue ) ) return 0; + if( !X_Type_isNumber( styleValue ) ) return 0; return styleValue; }; @@ -886,7 +886,7 @@ X.UI.AbstractUINode = X.Class.create( attr : function( nameOrObject, valueOrUnit ){ var p = X_Class_getPrivate( this ), layout, k, def, attrs, v; - if( nameOrObject && X.Type.isObject( nameOrObject ) ){ + if( nameOrObject && X_Type_isObject( nameOrObject ) ){ // setter layout = p.parentData && p.parentData.layout.overrideAttrsForChild; // root には parent がない for( k in nameOrObject ){ @@ -900,7 +900,7 @@ X.UI.AbstractUINode = X.Class.create( }; }; } else - if( X.Type.isString( nameOrObject ) ){ + if( X_Type_isString( nameOrObject ) ){ if( valueOrUnit !== undefined ){ if( 'em,%'.indexOf( valueOrUnit ) === -1 ){ // setter diff --git a/0.6.x/js/20_ui/08_Box.js b/0.6.x/js/20_ui/08_Box.js index c1a3cbe..9434254 100644 --- a/0.6.x/js/20_ui/08_Box.js +++ b/0.6.x/js/20_ui/08_Box.js @@ -90,10 +90,13 @@ X.UI._Box = X.UI._AbstractUINode.inherits( //throw new Error( 'インスタンスはすでに親に追加されています ' + arg ); }; } else + if( arg.instanceOf && arg.instanceOf( Node ) ){ + //this.layout = arg; + } else if( arg.instanceOf && arg.instanceOf( X.UI.Layout.Base ) ){ //this.layout = arg; } else - if( X.Type.isObject( arg ) ){ + if( X_Type_isObject( arg ) ){ if( attrs ){ attrs = X_Class_override( attrs, arg ); } else { @@ -244,7 +247,7 @@ X.UI._Box = X.UI._AbstractUINode.inherits( removeAt : function( from, length ){ var uinodes = this.uinodes, i = uinodes.length, - to = from + ( X.Type.isNumber( length ) && 1 <= length ? length : 1 ), + to = from + ( X_Type_isNumber( length ) && 1 <= length ? length : 1 ), node; for( ; i; ){ node = uinodes[ --i ]; @@ -357,14 +360,14 @@ X.UI.Box.presets = function(){ privateKlass = arg; layout = privateKlass.prototype.layout; } else - if( X.Type.isObject( arg ) ){ + if( X_Type_isObject( arg ) ){ if( attrs ){ X_Class_override( attrs, arg, true ); } else { attrs = arg; }; } else - if( X.Type.isString( arg ) ){ + if( X_Type_isString( arg ) ){ boxName = arg; }; }; diff --git a/0.6.x/js/20_ui/14_ChromeBox.js b/0.6.x/js/20_ui/14_ChromeBox.js index 4089730..065af2a 100644 --- a/0.6.x/js/20_ui/14_ChromeBox.js +++ b/0.6.x/js/20_ui/14_ChromeBox.js @@ -6,14 +6,13 @@ X.UI._ChromeBox = X.UI._Box.inherits( containerNode : null, Constructor : function( layout, args ){ + var uinodes, i, l, node, after, index = 0; this.Super( layout, args ); - - // xnode の追加が可能 - - var uinodes = this.uinodes, - i = uinodes.length, - node; + + uinodes = this.uinodes; + l = i = uinodes.length; + for( ; i; ){ node = uinodes[ --i ]; if( node.forContainer === true ){ @@ -29,6 +28,17 @@ X.UI._ChromeBox = X.UI._Box.inherits( if( !this.containerNode ){ //throw new Error( 'ContainerNode が設定されてい\ません!ContainerNode はクロームボックスにひとつ、生成時に設定できます ' ); }; + + for( i = 0, l = args.length; i < l; ++i ){ + node = args[ i ]; + if( node === this.containerNode ){ + after = true; + index = 0; + }; + if( node.instanceOf && node.instanceOf( Node ) ){ + + }; + }; } } ); diff --git a/0.6.x/js/20_ui/15_ScrollBox.js b/0.6.x/js/20_ui/15_ScrollBox.js index b1cec96..017fa70 100644 --- a/0.6.x/js/20_ui/15_ScrollBox.js +++ b/0.6.x/js/20_ui/15_ScrollBox.js @@ -1,905 +1,44 @@ -(function(){ -var m = Math, - ABS = new Function( 'v', 'return v<0?-v:v' ); - - function Options(){}; - - X_Class_override( Options.prototype, { - hScroll : true, - vScroll : true, - x : 0, - y : 0, - bounce : true, - bounceLock : false, - momentum : true, - lockDirection : true, - useTransform : true, - useTransition : true, - topOffset : 0, - checkDOMChanges : false, // Experimental - handleClick : true, - - // Scrollbar - hScrollbar : true, - vScrollbar : true, - fixedScrollbar : X_UA.Android, - hideScrollbar : X_UA.iOS, - fadeScrollbar : X_UA.iOS, //&& has3d, - scrollbarClass : '', - - // Zoom - zoom : false, - zoomMin : 1, - zoomMax : 4, - doubleTapZoom : 2, - wheelAction : 'scroll', - - // Snap - snap : false, - snapThreshold : 1 //, - }); - - function Scrollbar( owner, dir ){ - this.owner = owner; - this.options = owner.options; - this.dir = dir; - if( dir === 'h' ){ - this.XorY = 'x'; - this.widthOrHeight = 'width'; - this.transrateXorY = 'translateX('; - }; +function X_UI_ScrollBox_momentum( current, start, time, lowerMargin, wrapperSize, deceleration ){ + var distance = current - start, + speed = Math.abs( distance ) / time, + destination, + duration; + + deceleration = deceleration === undefined ? 0.0006 : deceleration; + + destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); + duration = speed / deceleration; + + if( destination < lowerMargin ){ + destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; + distance = Math.abs( destination - current ); + duration = distance / speed; + } else + if ( destination > 0 ) { + destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; + distance = Math.abs( current ) + destination; + duration = distance / speed; }; - X_Class_override( Scrollbar.prototype, { - owner : null, - dir : null, - options : null, - XorY : 'y', - widthOrHeight : 'height', - transrateXorY : 'translateY(', - active : false, - xnodeWrapper : null, - xnodeIndicator : null, - wrapperSize : 0, - indicatorSize : 0, - maxScroll : 0, - scrollPercent : 0, - - update : function(){ - // remove scrollbar - if( !this.active ){ - if( this.xnodeWrapper ){ - X.CSS.transform && this.xnodeIndicator.css( 'transform', '' ); - this.xnodeWrapper.css( 'display', 'none' ); - }; - return; - }; - - // create scrollbar - if( !this.xnodeWrapper ){ - // Create the scrollbar wrapper - this.xnodeWrapper = this.owner.xnodeTarget.create( 'div' ) - .className( - this.options.scrollbarClass ? - this.options.scrollbarClass + this.dir.toUpperCase() : - this.dir === 'h' ? - ( this.vScrollbar && this.vScrollbar.active ? 'ScrollBox-Scrollbar-Wrapper-V-withH' : 'ScrollBox-Scrollbar-Wrapper-H' ) : - ( this.hScrollbar && this.hScrollbar.active ? 'ScrollBox-Scrollbar-Wrapper-H-withV' : 'ScrollBox-Scrollbar-Wrapper-V' ) - ); - - this.options.fadeScrollbar && - this.xnodeWrapper.css( - { - opacity : 0, - transitionProperty : 'opacity', - transitionDuration : '350ms' - } - ); - - // Create the scrollbar indicator - - this.xnodeIndicator = this.xnodeWrapper.create( 'div' ); - - !this.options.scrollbarClass && - this.xnodeIndicator.className( - this.dir === 'h' ? - 'ScrollBox-Scrollbar-Indicator-H' : - 'ScrollBox-Scrollbar-Indicator-V' - ); - //if (this.options.useTransition) bar.style.cssText += ';' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)'; - }; - - if( this.dir === 'h' ){ - this.wrapperSize = this.hScrollbarWrapper.clientWidth; - this.indicatorSize = m.max( m.round( wrapperSize * wrapperSize / this.owner.scrollerW ), 8 ); - //this.hScrollbarIndicator.style.width = this.hScrollbarIndicatorSize + 'px'; - this.maxScroll = wrapperSize - indicatorSize; - this.scrollPercent = maxScroll / this.owner.maxScrollX; - } else { - this.wrapperSize = this.vScrollbarWrapper.clientHeight; - this.indicatorSize = m.max( m.round( wrapperSize * wrapperSize / this.owner.scrollerH ), 8); - // this.vScrollbarIndicator.style.height = indicatorSize + 'px'; - this.maxScroll = this.vScrollbarSize - indicatorSize; - this.scrollPercent = maxScroll / this.owner.maxScrollY; - }; - this.xnodeIndicator.css( this.widthOrHeight, size + 'px' ); - // Reset position - this.updatePosition( this.owner[ this.XorY ], true ); - }, - - updatePosition : function( pos, hidden ){ - var size; - pos = this.scrollPercent * pos; - - if( pos < 0 ){ - if( !this.options.fixedScrollbar ){ - size = this.indicatorSize + m.round( pos * 3 ); - if( size < 8 ) size = 8; - //this.xnodeIndicator.style[dir == 'h' ? 'width' : 'height'] = size + 'px'; - this.xnodeIndicator.css( this.widthOrHeight, size + 'px' ); - }; - pos = 0; - } else - if( this.maxScroll < pos ){ - if( !this.options.fixedScrollbar ){ - size = this.indicatorSize - m.round( ( pos - this.maxScroll ) * 3 ); - if( size < 8 ) size = 8; - //this.xnodeIndicator.style[dir == 'h' ? 'width' : 'height'] = size + 'px'; - this.xnodeIndicator.css( this.widthOrHeight, size + 'px' ); - pos = this.maxScroll + this.indicatorSize - size; - } else { - pos = this.maxScroll; - }; - }; - - if (this.options.useTransition){ - this.xnodeWrapper.css( { - transitionDelay : '0', - opacity : hidden && this.options.hideScrollbar ? '0' : '1' - }); - //this.xnodeIndicator.style[transform] = 'translate(' + (dir == 'h' ? pos + 'px,0)' : '0,' + pos + 'px)') + translateZ; - this.xnodeIndicator.anime( this.dir === 'h' ? { x : pos } : { y : pos } ); - }; - } - }); - - // Constructor - function iScroll( uinodeRoot, uinodeTarget, xnodeTarget, xnodeScroller, options ){ - var i; - - this.uinodeRoot = uinodeRoot; - this.uinodeTarget = uinodeTarget; - this.xnodeTarget = xnodeTarget; - this.xnodeScroller = xnodeScroller; - - // Default options - this.options = new Options(); - - // User defined options - if( options ) for (i in options) X_EMPTY_OBJECT[ k ] || ( this.options[i] = options[i] ); - - this.options.hScroll && ( this.hScrollbar = new Scrollbar( 'h', this ) ); - this.options.vScroll && ( this.vScrollbar = new Scrollbar( 'v', this ) ); - - // Set starting position - this.x = this.options.x; - this.y = this.options.y; - - // Normalize options - this.options.useTransform = X.CSS.transform && this.options.useTransform; - this.options.hScrollbar = this.options.hScroll && this.options.hScrollbar; - this.options.vScrollbar = this.options.vScroll && this.options.vScrollbar; - this.options.zoom = this.options.useTransform && this.options.zoom; - this.options.useTransition = X.CSS.transition && this.options.useTransition; - - // Helpers FIX ANDROID BUG! - // translate3d and scale doesn't work together! - // Ignoring 3d ONLY WHEN YOU SET this.options.zoom - //if ( this.options.zoom && X_UA.isAndroid ){ - // translateZ = ''; - //} - - // Set some default styles - if (this.options.useTransform){ - this.scroller.style[X.CSS.transform] = 'translate(' + this.x + 'px,' + this.y + 'px)' + translateZ; - this.scroller.style[X.CSS.transformOrigin] = '0 0'; - } else { - this.scroller.style.cssText += ';position:absolute;top:' + this.y + 'px;left:' + this.x + 'px'; - }; - - if (this.options.useTransition){ - this.scroller.style[X.CSS.transition.Property] = this.options.useTransform ? X.CSS.cssVendor + 'transform' : 'top left'; - this.scroller.style[X.CSS.transition.Duration] = '0'; - this.scroller.style[X.CSS.transition.TimingFunction] = 'cubic-bezier(0.33,0.66,0.66,1)'; - this.options.fixedScrollbar = true; - }; - - this.refresh(); - - //this._bind(RESIZE_EV, window); - X.Dom.Event.add( window, RESIZE_EV, this ); - //this._bind(START_EV); - uinodeTarget.listen( X.UI.Event.DRAG_START, this ); + return { + destination : Math.round( destination ), + duration : duration + }; +}; + +var X_UI_ScrollBox_SUPPORT_ATTRS = { + // スクロール開始するために必要な移動距離、縦か横、どちらか制限する場合、より重要 + directionLockThreshold : [ 10, X.UI.Dirty.CLEAN, X.UI.Attr.USER.UINODE, X.UI.Attr.Type.LENGTH ], + scrollX : [ true, X.UI.Dirty.CLEAN, X.UI.Attr.USER.UINODE, X.UI.Attr.Type.BOOLEAN ], + scrollY : [ true, X.UI.Dirty.CLEAN, X.UI.Attr.USER.UINODE, X.UI.Attr.Type.BOOLEAN ], + enabled : [ true, X.UI.Dirty.CLEAN, X.UI.Attr.USER.UINODE, X.UI.Attr.Type.BOOLEAN ], + bounce : [ true, X.UI.Dirty.CLEAN, X.UI.Attr.USER.UINODE, X.UI.Attr.Type.BOOLEAN ], + bounceTime : [ 600, X.UI.Dirty.CLEAN, X.UI.Attr.USER.UINODE, X.UI.Attr.Type.TIME ], + useWheel : [ true, X.UI.Dirty.CLEAN, X.UI.Attr.USER.UINODE, X.UI.Attr.Type.BOOLEAN ], + useKey : [ true, X.UI.Dirty.CLEAN, X.UI.Attr.USER.UINODE, X.UI.Attr.Type.BOOLEAN ], }; - -// Prototype -X_Class_override( iScroll.prototype, { - uinodeRoot : null, - uinodeTarget : null, - xnodeTarget : null, - xnodeScroller : null, - options : null, - enabled : true, - x : 0, - y : 0, - steps : [], - scale : 1, - currPageX : 0, - currPageY : 0, - pagesX : [], - pagesY : [], - animeTimerID : 0, - wheelZoomCount : 0, - - wrapperW : 0, - wrapperH : 0, - minScrollY : 0, - scrollerW : 0, - scrollerH : 0, - maxScrollX : 0, - maxScrollY : 0, - dirX : 0, - dirY : 0, - hScrollbar : false, - vScrollbar : false, - wrapperOffsetLeft : 0, - wrapperOffsetTop : 0, - - - currPageX : 0, - currPageY : 0, - - moved : false, - animating : false, - zoomed : false, - distX : false, - distY : false, - absDistX : false, - absDistY : false, - absStartX : false, // Needed by snap threshold - absStartY : false, - startX : false, - startY : false, - pointX : false, - pointY : false, - startTime : false, - - handleEvent: function (e) { - switch(e.type) { - case X.UI.Event.DRAG : - return this._move(e); - case X.UI.Event.WHEEL : - return this._wheel(e); - case X.UI.Event.DRAG_START : - //if (!hasTouch && e.button !== 0) return; - return this._start(e); - case X.UI.Event.DRAG_END : - return this._end(e); - case X.UI.Event.ANIME_END : - return this._transitionEnd(e); - case RESIZE_EV : - return this._resize(); - } - }, - - _trigger : function( type, e ){ - - return this.uinodeTarget.dispatch( ); - }, - - _resize: function () { - X.Timer.once( X_UA.Android ? 200 : 0, this, this.refresh ); - // setTimeout( this.refresh(), isAndroid ? 200 : 0); - }, - - _updateScrollPosition: function( x, y, time ){ - if (this.zoomed) return; - - this.xnodeScroller.anime({ - x : this.x = this.hScrollbar && this.hScrollbar.active ? m.round(x) : 0, - y : this.y = this.vScrollbar && this.vScrollbar.active ? m.round(y) : 0 - }, time ); - - this.hScrollbar && this.hScrollbar.active && this.hScrollbar.updatePosition( this.x ); - this.vScrollbar && this.vScrollbar.active && this.vScrollbar.updatePosition( this.y ); - }, - - _start: function (e) { - var point = hasTouch ? e.touches[0] : e, - matrix, x, y, - ret; - //c1, c2; - - if (!this.enabled) return; - - //if (this.options.onBeforeScrollStart) this.options.onBeforeScrollStart.call(this, e); - if( ( ret = this._trigger( X.UI.Event.SCROLL_BEFORE_START ) ) & X.Callback.PREVENT_DEFAULT ){ - return ret; - }; - - //if (this.options.useTransition || this.options.zoom) this._transitionTime(0); - - this.moved = false; - this.animating = false; - this.zoomed = false; - this.distX = 0; - this.distY = 0; - this.absDistX = 0; - this.absDistY = 0; - this.dirX = 0; - this.dirY = 0; - - if (this.options.momentum) { - if (this.options.useTransform) { - // Very lame general purpose alternative to CSSMatrix - matrix = getComputedStyle(this.scroller, null)[transform].replace(/[^0-9\-.,]/g, '').split(','); - x = +(matrix[12] || matrix[4]); - y = +(matrix[13] || matrix[5]); - } else { - x = +getComputedStyle(this.scroller, null).left.replace(/[^0-9-]/g, ''); - y = +getComputedStyle(this.scroller, null).top.replace(/[^0-9-]/g, ''); - }; - - if (x !== this.x || y !== this.y) { - if (this.options.useTransition){ - //this._unbind(TRNEND_EV); - X.Dom.Event.remove( this.scroller, TRNEND_EV, this ); - } else { - X.Timer.cancelFrame(this.animeTimerID); - }; - this.steps = this.steps ? ( this.steps.length = 0 ) : []; - this._updateScrollPosition( x, y, 0 ); - //if (this.options.onScrollEnd) this.options.onScrollEnd.call(this); - return this._trigger( X.UI.Event.SCROLL_END, e ); - }; - }; - - this.absStartX = this.x; // Needed by snap threshold - this.absStartY = this.y; - - this.startX = this.x; - this.startY = this.y; - this.pointX = point.pageX; - this.pointY = point.pageY; - - this.startTime = e.timeStamp || X.Timer.now(); - - this.uinodeRoot.listen( X.UI.Event.DRAG, this ); - this.uinodeRoot.listen( X.UI.Event.DRAG_END, this ); - - return this._trigger( X.UI.Event.SCROLL_START, e ); - }, - - _move: function (e) { - var point = hasTouch ? e.touches[0] : e, - deltaX = point.pageX - this.pointX, - deltaY = point.pageY - this.pointY, - newX = this.x + deltaX, - newY = this.y + deltaY, - c1, c2, scale, - timestamp = e.timeStamp ||X.Timer.now(), ret; - - //if (this.options.onBeforeScrollMove) this.options.onBeforeScrollMove.call(this, e); - if( ( ret = this._trigger( X.UI.Event.SCROLL_BEFORE_MOVE ) ) & X.Callback.PREVENT_DEFAULT ){ - return ret; - }; - - this.pointX = point.pageX; - this.pointY = point.pageY; - - // Slow down if outside of the boundaries - if (newX > 0 || newX < this.maxScrollX) { - newX = this.options.bounce ? this.x + (deltaX / 2) : newX >= 0 || this.maxScrollX >= 0 ? 0 : this.maxScrollX; - }; - if (newY > this.minScrollY || newY < this.maxScrollY) { - newY = this.options.bounce ? this.y + (deltaY / 2) : newY >= this.minScrollY || this.maxScrollY >= 0 ? this.minScrollY : this.maxScrollY; - }; - - this.distX += deltaX; - this.distY += deltaY; - this.absDistX = ABS(this.distX); - this.absDistY = ABS(this.distY); - - if (this.absDistX < 6 && this.absDistY < 6) { - return; - }; - - // Lock direction - if (this.options.lockDirection) { - if (this.absDistX > this.absDistY + 5) { - newY = this.y; - deltaY = 0; - } else if (this.absDistY > this.absDistX + 5) { - newX = this.x; - deltaX = 0; - }; - }; - - this.moved = true; - this._updateScrollPosition(newX, newY, 0); - this.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; - this.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; - - if (timestamp - this.startTime > 300) { - this.startTime = timestamp; - this.startX = this.x; - this.startY = this.y; - }; - - //if (this.options.onScrollMove) this.options.onScrollMove.call(this, e); - return this._trigger( X.UI.Event.SCROLL_MOVE, e ); - }, - - _end: function (e) { - if (hasTouch && e.touches.length !== 0) return; - - var point = hasTouch ? e.changedTouches[0] : e, - momentumX = { dist:0, time:0 }, - momentumY = { dist:0, time:0 }, - duration = ( e.timeStamp ||X.Timer.now() ) - this.startTime, - newPosX = this.x, - newPosY = this.y, - distX, distY, - newDuration, - snap, - scale; - - this.uinodeRoot.unlisten( X.UI.Event.DRAG, this ); - this.uinodeRoot.unlisten( X.UI.Event.DRAG_END, this ); - - //this._unbind(MOVE_EV, window); - //this._unbind(END_EV, window); - //this._unbind(CANCEL_EV, window); - - //if (this.options.onBeforeScrollEnd) this.options.onBeforeScrollEnd.call(this, e); - - - if (!this.moved) { - - - this._resetPos(400); - - //if (this.options.onTouchEnd) this.options.onTouchEnd.call(this, e); - return; - }; - - if (duration < 300 && this.options.momentum) { - momentumX = newPosX ? this._momentum(newPosX - this.startX, duration, -this.x, this.scrollerW - this.wrapperW + this.x, this.options.bounce ? this.wrapperW : 0) : momentumX; - momentumY = newPosY ? this._momentum(newPosY - this.startY, duration, -this.y, (this.maxScrollY < 0 ? this.scrollerH - this.wrapperH + this.y - this.minScrollY : 0), this.options.bounce ? this.wrapperH : 0) : momentumY; - - newPosX = this.x + momentumX.dist; - newPosY = this.y + momentumY.dist; - - if ((this.x > 0 && newPosX > 0) || (this.x < this.maxScrollX && newPosX < this.maxScrollX)) momentumX = { dist:0, time:0 }; - if ((this.y > this.minScrollY && newPosY > this.minScrollY) || (this.y < this.maxScrollY && newPosY < this.maxScrollY)) momentumY = { dist:0, time:0 }; - - if (momentumX.dist || momentumY.dist) { - newDuration = m.max(m.max(momentumX.time, momentumY.time), 10); - - this.scrollTo(m.round(newPosX), m.round(newPosY), newDuration); - - //if (this.options.onTouchEnd) this.options.onTouchEnd.call(this, e); - return; - }; - }; - - this._resetPos(200); - //if (this.options.onTouchEnd) this.options.onTouchEnd.call(this, e); - }, - - /* - _onZoomEndEvent : null, - _onZoomEndTimerComplete : function(){ - this.options.onZoomEnd.call( this, this._onZoomEndEvent ); - }, - */ - - /* - _onDobleTapTimerPoint : null, - _onDobleTapTimerComplete : function () { - var point = this._onDobleTapTimerPoint, - target, ev; - this.doubleTapTimer = null; - - // Find the last touched element - target = point.target; - while (target.nodeType !== 1) target = target.parentNode; - - if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') { - ev = document.createEvent('MouseEvents'); - ev.initMouseEvent('click', true, true, e.view, 1, - point.screenX, point.screenY, point.clientX, point.clientY, - e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, - 0, null); - ev._fake = true; - target.dispatchEvent(ev); - } - },*/ - - _resetPos: function (time) { - var resetX = - 0 <= this.x ? - 0 : - this.x < this.maxScrollX ? - this.maxScrollX : - this.x, - resetY = - this.minScrollY <= this.y || 0 < this.maxScrollY ? - this.minScrollY : - this.y < this.maxScrollY ? - this.maxScrollY : - this.y; - - if( resetX === this.x && resetY === this.y ){ - if( this.moved ){ - this.moved = false; - this._trigger( X.UI.Event.SCROLL_END ); - //if (this.options.onScrollEnd) this.options.onScrollEnd.call(this); // Execute custom code on scroll end - }; - if( this.options.hideScrollbar ){ - this.hScrollbar && this.hScrollbar.active && - - //if (vendor == 'webkit') this.hScrollbarWrapper.style[transitionDelay] = '300ms'; - //this.hScrollbarWrapper.style.opacity = '0'; - this.hScrollbar.xnodeWraper.anime( { - opacity : 0 - }, 300 ); - this.vScrollbar && this.vScrollbar.active && - //if (vendor == 'webkit') this.vScrollbarWrapper.style[transitionDelay] = '300ms'; - //this.vScrollbarWrapper.style.opacity = '0'; - this.hScrollbar.xnodeWraper.anime( { - opacity : 0 - }, 300 ); - }; - return; - }; - this.scrollTo(resetX, resetY, time || 0); - }, - - _wheel: function (e) { - var wheelDeltaX, wheelDeltaY, - deltaX, deltaY, - deltaScale; -/* - if ('wheelDeltaX' in e) { - wheelDeltaX = e.wheelDeltaX / 12; - wheelDeltaY = e.wheelDeltaY / 12; - } else if('wheelDelta' in e) { - wheelDeltaX = wheelDeltaY = e.wheelDelta / 12; - } else if ('detail' in e) { - wheelDeltaX = wheelDeltaY = -e.detail * 3; - } else { - return; - } */ - - deltaX = this.x + e.wheelDeltaX; - deltaY = this.y + e.wheelDeltaY; - - deltaX = - 0 < deltaX ? - 0 : - deltaX < this.maxScrollX ? - this.maxScrollX : deltaX; - - deltaY = - this.minScrollY < deltaY ? - this.minScrollY : - deltaY < this.maxScrollY ? - this.maxScrollY : deltaY; - - this.maxScrollY < 0 && this.scrollTo(deltaX, deltaY, 0); - }, - - /* - _wheelTimerCompleteEvent : null, - _wheelTimerComplete : function() { - this.wheelZoomCount--; - if (!this.wheelZoomCount && this.options.onZoomEnd) this.options.onZoomEnd.call(this, this._wheelTimerCompleteEvent ); - }, - */ - - _transitionEnd: function( e ){ - if( e.target !== this.xnodeScroller ) return; - - //this._unbind(TRNEND_EV); - //X.Dom.Event.remove( this.scroller, TRNEND_EV, this ); - this.animating = false; - - this._startAnime(); - - return X.Callback.UN_LISTEN; - }, - - - /** - * - * Utilities - * - */ - _startAnime: function () { - var startX = this.x, - startY = this.y, - step, animate; - - if (this.animating) return; - - if (!this.steps.length) { - this._resetPos(400); - return; - }; - - step = this.steps.shift(); - - if( step.x === startX && step.y === startY ) step.time = 0; - - this.animating = true; - this.moved = true; - - //if (this.options.useTransition) { - //this._transitionTime(step.time); - this._updateScrollPosition( step.x, step.y, step.time ); - //this.animating = false; - this.xnodeScroller.listenOnce( X.UI.Event.ANIME_END, this ); - //step.time ? X.Dom.Event.add( this.scroller, TRNEND_EV, this ) /* this._bind(TRNEND_EV) */ : this._resetPos(0); - //return; - //} - //this._doAnimate( X.Timer.now(), step, startX, startY ); - }, - -/* - _doAnimate : function( startTime, step, startX, startY ){ - var now =X.Timer.now(), - easeOut, newX, newY; - - if (now >= startTime + step.time) { - this._updateScrollPosition(step.x, step.y); - this.animating = false; - //if (this.options.onAnimationEnd) this.options.onAnimationEnd.call( this ); // Execute custom code on animation end - this._startAnime(); - return; - }; - - now = (now - startTime) / step.time - 1; - easeOut = m.sqrt(1 - now * now); - newX = (step.x - startX) * easeOut + startX; - newY = (step.y - startY) * easeOut + startY; - this._updateScrollPosition(newX, newY); - if( this.animating ) this.animeTimerID = X.Timer.requestFrame( this, this._doAnimate, [ startTime, step, startX, startY ] ); - }, -*/ - - _momentum: function (dist, time, maxDistUpper, maxDistLower, size) { - var deceleration = 0.0006, - speed = ABS(dist) / time, - newDist = (speed * speed) / (2 * deceleration), - newTime = 0, outsideDist = 0; - - // Proportinally reduce speed if we are outside of the boundaries - if (dist > 0 && newDist > maxDistUpper) { - outsideDist = size / (6 / (newDist / speed * deceleration)); - maxDistUpper = maxDistUpper + outsideDist; - speed = speed * maxDistUpper / newDist; - newDist = maxDistUpper; - } else if (dist < 0 && newDist > maxDistLower) { - outsideDist = size / (6 / (newDist / speed * deceleration)); - maxDistLower = maxDistLower + outsideDist; - speed = speed * maxDistLower / newDist; - newDist = maxDistLower; - } - - newDist = newDist * (dist < 0 ? -1 : 1); - newTime = speed / deceleration; - - return { dist: newDist, time: m.round(newTime) }; - }, - - _offset: function (el) { - var left = -el.offsetLeft, - top = -el.offsetTop; - - while (el = el.offsetParent) { - left -= el.offsetLeft; - top -= el.offsetTop; - } - - if (el != this.wrapper) { - left *= this.scale; - top *= this.scale; - } - - return { left: left, top: top }; - }, - - /* - _bind: function (type, el, bubble) { - X.Dom.Event.add( el || this.scroller, type, this ); - }, - - _unbind: function (type, el, bubble) { - X.Dom.Event.remove( el || this.scroller, type, this ); - }, - */ - - /** - * - * Public methods - * - */ - destroy: function () { - this.scroller.style[transform] = ''; - - // Remove the scrollbars - this.hScrollbar && this.hScrollbar.destroy(); - this.vScrollbar && this.vScrollbar.destroy(); - - // Remove the event listeners - X.Dom.Event.add( window, RESIZE_EV, this ); - this.uinodeTarget.unlisten( X.UI.Event.DRAG_START, this ); - this.uinodeRoot.unlisten( X.UI.Event.DRAG, this ); - this.uinodeRoot.unlisten( X.UI.Event.DRAG_END, this ); - - //this._unbind(RESIZE_EV, window); - //this._unbind(START_EV); - //this._unbind(MOVE_EV, window); - //this._unbind(END_EV, window); - //this._unbind(CANCEL_EV, window); - - if (!this.options.hasTouch) { - //this._unbind('wheel'); - } - - // if (this.options.useTransition) this._unbind(TRNEND_EV); - this.options.useTransition && X.Dom.Event.remove( this.scroller, TRNEND_EV, this ); - - //if (this.options.checkDOMChanges) clearInterval(this.checkDOMTime); - - //if (this.options.onDestroy) this.options.onDestroy.call(this); - }, - - refresh: function () { - var offset, - i, l, - els, - pos = 0, - page = 0; - - if (this.scale < this.options.zoomMin) this.scale = this.options.zoomMin; - this.wrapperW = this.wrapper.clientWidth || 1; - this.wrapperH = this.wrapper.clientHeight || 1; - - this.minScrollY = -this.options.topOffset || 0; - this.scrollerW = m.round(this.scroller.offsetWidth * this.scale); - this.scrollerH = m.round((this.scroller.offsetHeight + this.minScrollY) * this.scale); - this.maxScrollX = this.wrapperW - this.scrollerW; - this.maxScrollY = this.wrapperH - this.scrollerH + this.minScrollY; - this.dirX = 0; - this.dirY = 0; - - // if (this.options.onRefresh) this.options.onRefresh.call(this); - this._trigger( X.UI.Event.SCROLL_REFRESH, {} ); - - this.hScrollbar && ( this.hScrollbar.active = this.maxScrollX < 0 ); - this.vScrollbar && ( this.vScrollbar.active = !this.options.bounceLock && !this.hScroll || this.scrollerH > this.wrapperH ); - - offset = this._offset(this.wrapper); - this.wrapperOffsetLeft = -offset.left; - this.wrapperOffsetTop = -offset.top; - - // Prepare snap - if (typeof this.options.snap == 'string') { - this.pagesX = []; - this.pagesY = []; - els = this.scroller.querySelectorAll(this.options.snap); - for (i=0, l=els.length; i= this.maxScrollX) { - this.pagesX[page] = pos; - pos = pos - this.wrapperW; - page++; - } - if (this.maxScrollX%this.wrapperW) this.pagesX[this.pagesX.length] = this.maxScrollX - this.pagesX[this.pagesX.length-1] + this.pagesX[this.pagesX.length-1]; - - pos = 0; - page = 0; - this.pagesY = []; - while (pos >= this.maxScrollY) { - this.pagesY[page] = pos; - pos = pos - this.wrapperH; - page++; - } - if (this.maxScrollY%this.wrapperH) this.pagesY[this.pagesY.length] = this.maxScrollY - this.pagesY[this.pagesY.length-1] + this.pagesY[this.pagesY.length-1]; - } - - // Prepare the scrollbars - this._scrollbar('h'); - this._scrollbar('v'); - - if (!this.zoomed) { - this.scroller.style[transitionDuration] = '0'; - this._resetPos(400); - } - }, - - scrollTo: function (x, y, time, relative) { - var step = x, - i, l; - - this.stop(); - - if( !step.length ) step = [{ x: x, y: y, time: time, relative: relative }]; - - for( i = 0, l = step.length; i < l; ++i ){ - if( step[ i ].relative ){ - step[ i ].x = this.x - step[ i ].x; - step[ i ].y = this.y - step[ i ].y; - }; - this.steps.push( { - x : step[i].x, - y : step[i].y, - time : step[i].time || 0 - }); - }; - - this._startAnime(); - }, - - disable: function () { - this.stop(); - this._resetPos(0); - this.enabled = false; - - // If disabled after touchstart we make sure that there are no left over events - //this._unbind(MOVE_EV, window); - //this._unbind(END_EV, window); - //this._unbind(CANCEL_EV, window); - this.uinodeRoot.unlisten( X.UI.Event.DRAG, this ); - this.uinodeRoot.unlisten( X.UI.Event.DRAG_END, this ); - }, - - enable: function () { - this.enabled = true; - }, - - stop: function () { - //if (this.options.useTransition) this._unbind(TRNEND_EV); - //else X.Timer.cancelFrame( this.animeTimerID ); - /* - if (this.options.useTransition){ - X.Dom.Event.remove( this.scroller, TRNEND_EV, this ); - } else { - X.Timer.cancelFrame(this.animeTimerID); - }; - */ - this.xnodeScroller.stop(); - if( this.steps ) this.steps.length = 0; - this.moved = false; - this.animating = false; - }, - - isReady: function () { - return !this.moved && !this.zoomed && !this.animating; - } -} ); - X.UI._ScrollBox = X.UI._ChromeBox.inherits( @@ -910,40 +49,122 @@ X.UI._ScrollBox = X.UI._ChromeBox.inherits( //elmScroller : null, //elmScrollbar : null, + supportAttrs : X.UI.Attr.createAttrDef( X.UI.Attr.Support, X_UI_ScrollBox_SUPPORT_ATTRS ), + scrolling : false, - _scrollX : 0, - _scrollY : 0, - scrollXPercent : 0, - scrollYPercent : 0, + + initiated : '', + moved : false, + distX : 0, + distY : 0, + directionX : 0, + directionY : 0, + directionLocked : '', + startTime : 0, + endTime : 0, + isAnimating : false, + startX : 0, + startY : 0, + absStartX : 0, + absStartY : 0, + pointX : 0, + pointY : 0, + maxScrollX : 0, + maxScrollY : 0, + hasHScroll : false, + hasVScroll : false, + + wrapperOffset : 0, + wheelTimeout : 0, + requestFrameID : 0, + + _scrollX : 0, + _scrollY : 0, + scrollXPercent : 0, + scrollYPercent : 0, + + lastScrollWidth : 0, + lastScrollHeight : 0, + lastBoxWidth : 0, + lastBoxHeight : 0, _containerNode : null, scrollManager : null, Constructor : function( layout, args ){ this.Super( layout, args ); - this._containerNode = _X_Class_getPrivate( this.containerNode ); + this._containerNode = X_Class_getPrivate( this.containerNode ); }, creationComplete : function(){ - X.UI._AbstractUINode.prototype.creationComplete.call( this, arguments ); - this.scrollManager = new iScroll( this.root, this.User, this.rawElement, this._containerNode.rawElement ); + X.UI._Box.prototype.creationComplete.apply( this, arguments ); + this.scrollManager; this._check(); }, calculate : function(){ - X.UI._AbstractUINode.prototype.calculate.call( this, arguments ); - this._check(); + this.lastScrollWidth = this.scrollWidth; + this.lastScrollHeight = this.scrollHeight; + this.lastBoxWidth = this.boxWidth; + this.lastBoxHeight = this.boxHeight; + + X.UI._Box.prototype.calculate.apply( this, arguments ); + + if( + this.lastScrollWidth !== this.scrollWidth || this.lastScrollHeight !== this.scrollHeight || + this.lastBoxWidth !== this.boxWidth || this.lastBoxHeight !== this.boxHeight + ){ + // scroll の停止、GPU の解除 + this._check(); + }; + + }, + + scrollBy : function( x, y, opt_time, opt_easing ){ + this.scrollTo( this.x + x, this.y + y, opt_time, opt_easing ); + }, + + scrollTo : function( x, y, opt_time, opt_easing ){ + opt_time = 0 <= opt_time ? opt_time : 0; + opt_easing = opt_easing || 'circular'; + + this.isInTransition = !!opt_time; + + this.containerNode.animate( + { + x : this.x, + y : this.y + }, + { + x : x, + y : y + }, + opt_time, opt_easing, 1000 + ); + + this.x = x; + this.y = y; + + if( this.indicators ){ + for( i = this.indicators.length; i--; ){ + this.indicators[ i ].updatePosition( opt_time, opt_easing ); + }; + }; }, _check : function(){ - if( this.w < this._containerNode.w || this.h < this._containerNode.h ){ + var needVScroll, needHScroll; + if( this.boxWidth < this._containerNode.scrollWidth || this.boxHeight < this._containerNode.scrollHeight ){ // scroll if( this.scrolling ){ // fix scroll position from scrollXPercent, scrollYPercent + // } else { // create scroller - this.listen( X.UI.Event.POINTER_START, this ); + + + this.listen( X.UI.Event.POINTER_START, X_UI_ScrollBox_onStart ); this._move( 0, 0 ); @@ -954,6 +175,7 @@ X.UI._ScrollBox = X.UI._ChromeBox.inherits( // no scroll if( this.scrolling ){ // remove scroller + this.unlisten( X.UI.Event.POINTER_START ); ( this._scrollX !== 0 || this._scrollY !== 0 ) && this._move( 0, 0 ); @@ -961,30 +183,12 @@ X.UI._ScrollBox = X.UI._ChromeBox.inherits( }; }, - handleEvent : function( e ){ - switch( e.type ){ - case X.UI.Event.POINTER_START : - this.listen( X.UI.Event.POINTER_MOVE, this ); - this.listen( X.UI.Event.POINTER_END, this ); - - break; - case X.UI.Event.POINTER_MOVE : - - break; - case X.UI.Event.POINTER_END : - this.unlisten( X.UI.Event.POINTER_MOVE, this ); - this.unlisten( X.UI.Event.POINTER_END, this ); - - break; - }; - }, - _move : function( x, y ){ }, _remove : function(){ - X.UI._AbstractUINode.prototype._remove.call( this, arguments ); + X.UI._AbstractUINode.prototype._remove.apply( this, arguments ); if( this.scrolling ){ // remove scroll }; @@ -993,7 +197,285 @@ X.UI._ScrollBox = X.UI._ChromeBox.inherits( } ); -})(); + +function X_UI_ScrollBox_onStart( e ){ + var ret = X.Callback.NONE; + + // React to left mouse button only + if( e.pointerType === 'mouse' && e.button !== 0 ){ + return ret; + }; + + if( !this.enabled || ( this.initiated && e.pointerType !== this.initiated ) ){ + return ret; + }; + + this.initiated = e.pointerType; + this.moved = false; + this.distX = 0; + this.distY = 0; + this.directionX = 0; + this.directionY = 0; + this.directionLocked = ''; + this.startTime = X_Timer_now(); + + // スクロール中の停止 + if( this.isAnimating ){ + delete this.isAnimating; + this.dispatch( X.UI.Event.SCROLL_END ); + }; + + this.startX = this.x; + this.startY = this.y; + this.absStartX = this.x; + this.absStartY = this.y; + this.pointX = e.pageX; + this.pointY = e.pageY; + + this.listen( X.UI.Event.POINTER_MOVE, X_UI_ScrollBox_onMove ); + this.listen( X.UI.Event.POINTER_END , X_UI_ScrollBox_onEnd ); + + //console.log( 'start : 3' ); + return ret | X.Callback.PREVENT_DEFAULT; +}; + +function X_UI_ScrollBox_onMove( e ){ + var ret = X.Callback.NONE, + deltaX, deltaY, timestamp, + newX, newY, + absDistX, absDistY; + // 規定以上の move でスクロール開始 + + if( !this.enabled || e.pointerType !== this.initiated ){ + return ret; + }; + + // gpu の用意 + if( !this.containerNode._anime ){ + console.log( 'gpuレイヤーの用意' ); + this._translate( this.x, this.y ); + return ret; + }; + + deltaX = e.pageX - this.pointX; + deltaY = e.pageY - this.pointY; + timestamp = X_Timer_now(); + + this.pointX = e.pageX; + this.pointY = e.pageY; + + this.distX += deltaX; + this.distY += deltaY; + absDistX = Math.abs(this.distX); + absDistY = Math.abs(this.distY); + + // We need to move at least 10 pixels for the scrolling to initiate + if( 300 < timestamp - this.endTime && ( absDistX < 10 && absDistY < 10 ) ){ + return ret; + }; + + // If you are scrolling in one direction lock the other + if( !this.directionLocked ){ + if( absDistX > absDistY + this.directionLockThreshold ){ + this.directionLocked = 'h'; // lock horizontally + } else + if( absDistY >= absDistX + this.directionLockThreshold ){ + this.directionLocked = 'v'; // lock vertically + } else { + this.directionLocked = 'n'; // no lock + }; + }; + + if( this.directionLocked === 'h' ){ + deltaY = 0; + } else + if( this.directionLocked === 'v' ){ + deltaX = 0; + }; + + deltaX = this.hasHScroll ? deltaX : 0; + deltaY = this.hasVScroll ? deltaY : 0; + + if( !this.moved ){ + this.dispatch( X.UI.Event.SCROLL_BEFORE_MOVE ); + this.moved = true; + this.minusX = deltaX; + this.minusY = deltaY; + } else { + this.dispatch( X.UI.Event.SCROLL_MOVE ); + }; + + newX = this.x + deltaX;// - this.minusX; + newY = this.y + deltaY;// - this.minusY; + + // Slow down if outside of the boundaries + if( 0 < newX || newX < this.maxScrollX ){ + newX = this.bounce ? this.x + ( deltaX ) / 3 : 0 < newX ? 0 : this.maxScrollX; + }; + if( 0 < newY || newY < this.maxScrollY ){ + newY = this.bounce ? this.y + ( deltaY ) / 3 : 0 < newY ? 0 : this.maxScrollY; + }; + + this.directionX = 0 < deltaX ? -1 : deltaX < 0 ? 1 : 0; + this.directionY = 0 < deltaY ? -1 : deltaY < 0 ? 1 : 0; + + this._translate( newX, newY ); + + if( 300 < timestamp - this.startTime ){ + this.startTime = timestamp; + this.startX = this.x; + this.startY = this.y; + }; + // イベントの拘束 + return ret | X.Callback.PREVENT_DEFAULT | X.Callback.MONOPOLY; +}; + +function X_UI_ScrollBox_onEnd( e ){ + var ret = X.Callback.NONE, + time = 0, + easing = '', + newX, newY, + momentumX, momentumY, + duration, distanceX, distanceY; + + this.unlisten( X.UI.Event.POINTER_MOVE, X_UI_ScrollBox_onMove ); + this.unlisten( X.UI.Event.POINTER_END, X_UI_ScrollBox_onEnd ); + + if( !this.enabled || e.pointerType !== this.initiated ){ + return ret; + }; + + delete this.isInTransition; + delete this.initiated; + this.endTime = X_Timer_now(); + + duration = this.endTime - this.startTime; + newX = Math.round( this.x ); + newY = Math.round( this.y ); + distanceX = Math.abs(newX - this.startX); + distanceY = Math.abs(newY - this.startY); + + // reset if we are outside of the boundaries + if( X_UI_ScrollBox_resetPosition( this, this.options.bounceTime ) ){ + return ret; + }; + + // we scrolled less than 10 pixels + if( !this.moved ){ + // this.dispatch( X_Event.CANCELED ); + return ret; + }; + + this.scrollTo( newX, newY, 0 ); // ensures that the last position is rounded + + // start momentum animation if needed + if( this.options.momentum && duration < 300 ){ + momentumX = this.hasHScroll ? + X_UI_ScrollBox_momentum( this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration ) :{ destination: newX, duration: 0 }; + momentumY = this.hasVScroll ? + X_UI_ScrollBox_momentum( this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration ) : { destination: newY, duration: 0 }; + newX = momentumX.destination; + newY = momentumY.destination; + time = Math.max( momentumX.duration, momentumY.duration ); + this.isInTransition = 1; + }; + + if( newX != this.x || newY != this.y ){ + // change easing function when scroller goes out of the boundaries + if( 0 < newX || newX < this.maxScrollX || 0 < newY || newY < this.maxScrollY ){ + easing = 'quadratic'; + }; + + this.scrollTo( newX, newY, time, easing ); + return ret; + }; + + this.dispatch( X.UI.Event.SCROLL_END ); + + return ret; +}; + +function X_UI_ScrollBox_resetPosition( that, time ){ + var x = this.x, + y = this.y; + + time = time || 0; + + if( !this.hasHScroll || 0 < this.x ){ + x = 0; + } else + if( this.x < this.maxScrollX ){ + x = this.maxScrollX; + }; + + if( !this.hasVScroll || 0 < this.y ){ + y = 0; + } else + if( this.y < this.maxScrollY ){ + y = this.maxScrollY; + }; + + if( x === this.x && y === this.y ){ + console.log( 'no バウンド' ); + return false; + }; + + console.log( 'バウンド!' ); + this.scrollTo( x, y, time, this.options.bounceEasing ); + + return true; +}; + +function X_UI_ScrollBox_translate( x, y ){ + this.containerNode.animate( + { + x : this.x, + y : this.y + }, + { + x : x, + y : y + }, + 0, '', 300 + ); + + this.x = x; + this.y = y; + + if( this.indicators ){ + for( i = this.indicators.length; i--; ){ + this.indicators[ i ].updatePosition(); + }; + }; +}; + +function X_UI_ScrollBox_refresh( remove ){ + this.maxScrollX = this.boxWidth - this.containerNode.boxWidth; + this.maxScrollY = this.boxHeight - this.containerNode.boxHeight; + + this.hasHScroll = this.User.attr( 'scrollX' ) && this.maxScrollX < 0; + this.hasVScroll = this.User.attr( 'scrollY' ) && this.maxScrollY < 0; + + if( !this.hasHScroll ){ + this.maxScrollX = 0; + this.scrollerWidth = this.wrapperWidth; + }; + + if( !this.hasVScroll ){ + this.maxScrollY = 0; + this.scrollerHeight = this.wrapperHeight; + }; + + delete this.endTime; + delete this.directionX; + delete this.directionY; + + this.wrapperOffset = this.xnodeWrapper.offset(); + + //this.dispatch('refresh'); + + X_UI_ScrollBox_resetPosition( this, 0 ); +}; X.UI.ScrollBox = X.UI.ChromeBox.inherits( 'ScrollBox', diff --git a/0.6.x/js/20_ui/17_Text.js b/0.6.x/js/20_ui/17_Text.js index 4ecc8b8..ab57827 100644 --- a/0.6.x/js/20_ui/17_Text.js +++ b/0.6.x/js/20_ui/17_Text.js @@ -10,7 +10,7 @@ X.UI._Text = X.UI._AbstractUINode.inherits( }; this.xnode = X_Doc_create( 'div' ); - if( X.Type.isString( content ) && content ){ + if( X_Type_isString( content ) && content ){ this.content = content; this.xnode.text( this.content ); this.dirty = X.UI.Dirty.CONTENT; @@ -26,7 +26,7 @@ X.UI.Text = X.UI.AbstractUINode.inherits( { Constructor : function( opt_content, opt_cssObj ){ X_Class_newPrivate( this, opt_content ); - X.Type.isObject( opt_cssObj = opt_cssObj || opt_content ) && this.attr( opt_cssObj ); + X_Type_isObject( opt_cssObj = opt_cssObj || opt_content ) && this.attr( opt_cssObj ); }, content : function( v ){ var data = X_Class_getPrivate( this ); diff --git a/0.6.x/js/20_ui/20_PageRoot.js b/0.6.x/js/20_ui/20_PageRoot.js index fd84be3..915ec07 100644 --- a/0.6.x/js/20_ui/20_PageRoot.js +++ b/0.6.x/js/20_ui/20_PageRoot.js @@ -1,35 +1,37 @@ +var X_UI_rootData = null, + X_UI_eventBusy = false; -X.UI._eventRellay = function( e ){ +function X_UI_eventRellay( e ){ var font = X.ViewPort.getBaseFontSize(), x = e.clientX / font, y = e.clientY / font, type = X.UI.Event.NameToID[ e.type ], i = 0, - data = X.UI.currentRootData, + data = X_UI_rootData, sysOnly = false, ret = X.Callback.NONE, list, parent, _ret; // mouseup で alert を出すと mouseleave が発生、ということでイベント中のイベント発火を禁止 - if( !data || data._eventBusy ) return ret; + if( !data || X_UI_eventBusy ) return ret; data._eventBusy = true; - if( type !== '' + X.UI.Event._POINTER_MOVE && type !== '' + X.UI.Event._TOUCH_MOVE && type !== '' + X.UI.Event._MOUSE_MOVE ){ + if( type !== '' + X.UI.Event._POINTER_MOVE ){ //console.log( e.type + ' ' + type + ' x:' + x + ', y:' + y ); }; e.type = type; if( data && ( data = data.monopolyNodeData ) && ( ret = data.dispatch( e ) ) & X.Callback.MONOPOLY ){ - delete X.UI.currentRootData._eventBusy; + X_UI_eventBusy = false; return ret | X.Callback.PREVENT_DEFAULT; }; - list = X.UI.currentRootData.hoverList; - ( X.UI.currentRootData.targetNodeData = X.UI.currentRootData ).capcher( x, y ); - data = X.UI.currentRootData.targetNodeData; + list = X_UI_rootData.hoverList; + ( X_UI_rootData.targetNodeData = X_UI_rootData ).capcher( x, y ); + data = X_UI_rootData.targetNodeData; - //data !== X.UI.currentRootData && console.log( data.xnode.text() ); + //data !== X_UI_rootData && console.log( data.xnode.text() ); while( data ){ _ret = data.dispatch( e, sysOnly ); @@ -43,7 +45,7 @@ X.UI._eventRellay = function( e ){ while( parent.parentData && parent === parent.parentData.hitChildData ){ parent = parent.parentData; }; - if( parent !== X.UI.currentRootData ){ + if( parent !== X_UI_rootData ){ data.hoverClassName && data.xnode.removeClass( data.hoverClassName ); data._listeners && data._listeners[ X.UI.Event.POINTER_OUT ] && data.dispatch( e, X.UI.Event.POINTER_OUT, false ); // new Event delete data.hovering; @@ -56,7 +58,7 @@ X.UI._eventRellay = function( e ){ data.hovering = true; }; }; - delete X.UI.currentRootData._eventBusy; + X_UI_eventBusy = false; return ret | X.Callback.PREVENT_DEFAULT; }; @@ -80,21 +82,19 @@ X.UI._PageRoot = X.UI._Box.inherits( eventCounter : null, cursorStyle : null, - _eventBusy : false, - Constructor : function( layout, args ){ this.Super( layout, args ); - if( X_ViewPort_readyState === X.Event.XDOM_READY ){ + if( X_ViewPort_readyState === X_Event.XDOM_READY ){ X.Timer.once( 0, this, this.start ); } else { - X.ViewPort.listenOnce( X.Event.XDOM_READY, this, this.start ); + X.ViewPort.listenOnce( X_Event.XDOM_READY, this, this.start ); }; this.hoverList = []; this.eventCounter = {}; - X.UI.currentRootData = this; + X_UI_rootData = this; }, start : function(){ @@ -114,22 +114,13 @@ X.UI._PageRoot = X.UI._Box.inherits( } ); // hover や rollover rollout のための move イベントの追加 - // mouseout, mouseover - //if( X_UA_HID.POINTER ){ - this.xnodeInteractiveLayer.listen( X.UI.Event.IdToName[ X.UI.Event._POINTER_MOVE ], X.UI._eventRellay ); - if( counter[ X.UI.Event._POINTER_MOVE ] ){ - ++counter[ X.UI.Event._POINTER_MOVE ]; - } else { - counter[ X.UI.Event._POINTER_MOVE ] = 1; - }; - /*} else { - this.xnodeInteractiveLayer.listen( X.UI.Event.IdToName[ X.UI.Event._MOUSE_MOVE ], X.UI._eventRellay ); - if( counter[ X.UI.Event._MOUSE_MOVE ] ){ - ++counter[ X.UI.Event._MOUSE_MOVE ]; - } else { - counter[ X.UI.Event._MOUSE_MOVE ] = 1; - }; - };*/ + this.xnodeInteractiveLayer.listen( X.UI.Event.IdToName[ X.UI.Event._POINTER_MOVE ], X_UI_eventRellay ); + if( counter[ X.UI.Event._POINTER_MOVE ] ){ + ++counter[ X.UI.Event._POINTER_MOVE ]; + } else { + counter[ X.UI.Event._POINTER_MOVE ] = 1; + }; + X.Timer.once( 0, this, this.afterAddToView ); }, afterAddToView : function(){ @@ -143,8 +134,8 @@ X.UI._PageRoot = X.UI._Box.inherits( this.calculate(); this.phase = 4; X.ViewPort - .listen( X.Event.VIEW_RESIZED, this, this.calculate ) - .listen( X.Event.BASE_FONT_RESIZED, this, this.calculate ); + .listen( X_Event.VIEW_RESIZED, this, this.calculate ) + .listen( X_Event.BASE_FONT_RESIZED, this, this.calculate ); }, reserveCalc : function(){