From 9e30a8480de03f0b36d2411a0ecb7f1d0f47b61f Mon Sep 17 00:00:00 2001 From: itozyun Date: Mon, 9 Mar 2015 17:07:01 +0900 Subject: [PATCH] Version 0.6.132, fix X.Node._flags & fix X.EventDispatcher._listeners & start to add jsdoc3 comment. --- 0.6.x/js/01_core/01_X.js | 65 ++++-- 0.6.x/js/01_core/02_XUA.js | 123 ++++++++++-- 0.6.x/js/01_core/03_XType.js | 61 ++++-- 0.6.x/js/01_core/04_XObject.js | 56 +++++- 0.6.x/js/01_core/05_XString.js | 14 +- 0.6.x/js/01_core/06_XURL.js | 5 + 0.6.x/js/01_core/10_XCallback.js | 108 +++++++++- 0.6.x/js/01_core/11_XClass.js | 228 ++++++++++++++------- 0.6.x/js/01_core/12_XEvent.js | 95 ++++----- 0.6.x/js/01_core/13_XEventDispatcher.js | 339 +++++++++++++++++--------------- 0.6.x/js/01_core/14_XTimer.js | 6 +- 0.6.x/js/02_dom/02_XNode.js | 44 ++++- 0.6.x/js/06_net/00_XNet.js | 2 +- 0.6.x/js/06_net/01_XNetXHR.js | 29 ++- 0.6.x/js/06_net/04_XNetImage.js | 1 - 15 files changed, 816 insertions(+), 360 deletions(-) diff --git a/0.6.x/js/01_core/01_X.js b/0.6.x/js/01_core/01_X.js index 81ed30d..fabeeeb 100644 --- a/0.6.x/js/01_core/01_X.js +++ b/0.6.x/js/01_core/01_X.js @@ -1,3 +1,44 @@ +/** + *

はじめに:Web 開発の世界へようこそ!

+ * DHTML と XHR 等を活用した Ajax によってその真価を発揮した javascript は、現在では RIA に SPA や 3D ゲームなど、あらゆるアプリケーションがブラウザ上で動きつつあります。 + * それらの素晴らしいデモに触れ、これから Web 開発に望む皆さんは、胸をときめかせていることでしょう。 + * そうです、今や Web ブラウザは、あなたの夢を何でも描くことの出来る自由なフロンティアです。 + * + * しかし、いざ Javascript を触り始め、初めての開発に着手すると、Web ブラウザというフロンティアは、少し雑草の茂るだけの荒野だと気付くでしょう。 + * ここに RIA や 3D ゲームといった素晴らしいテーマパークを築機上げるには、まずは測量に整地、地盤や土壌の改良といった膨大な作業をしなくてはいけません。 + * + * 簡素な物置小屋のための最初の柱を建てるのにも、それ以前に膨大な作業の必要なことに、あなたは唖然となるでしょう。 + * そのような基礎もそこそこに、勇んで建てた一本目の柱は傾き、または無残に朽ち果てるのを目撃し、あなたは深いため息をつくかもしれません。 + * + * Javascript は様々な問題を孕みつつも、今や最もあらゆるプラットフォームで動作する言語のひとつへと躍進しました。 + * これから、このフロンティアに如何に基礎を作り、その上にテーマパークを作るのか?一緒に考えていきましょう。 + * ようこそ、Web 開発の世界へ! + * + *

pettanR フレームワーク API ドキュメントについて

+ * このAPIドキュメントには、折に触れこのような長文が登場します。 + * Web 開発は今では、そのカジュアルなイメージとは裏腹に、膨大な知識と経験が必要なものになってしまっています。 + * どのようにして、それらの情報を、妥当な業務時間の間に継承していけばよいか? + * + * この意識は常にありましたが、このたび pettanR フレームワークの API ドキュメントを作成するにあたり、それに付記していく形で取り組んでみようと思います。 + * + *

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

+ * + * + * ライブラリは X という名前空間を使用します。 + * @example //ショートハンド + * 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 ); + } else + if( X_shortcutFunction ){ + return X_shortcutFunction.apply( X_shortcutContext || X, arguments ); + }; +}; + //{+DEV if( !window['console'] || ( window.parent && window.parent.log ) ) console = { log : function(a){ @@ -17,23 +58,23 @@ var undefined, X_shortcutContext; /** - * @namespace ライブラリは X という名前空間を使用します。X( func ) で X.ViewPort.listenOnce(X.Event.XDOM_READY, func)、 X('#mydiv') として X.Doc.find('#mydiv') のショートハンドになります。 - */ -function X( 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 ); - }; -}; - + * バージョン文字列:"0.6.123" + * @type {string} */ X.VERSION = '0.6.127'; - + +/** + * ブートタイム ms + * @type {number} */ X.bootTime = + new Date; +/** + * 空の関数 + * @type {Function} */ X.emptyFunction = new Function; +/** + * このscriptはheadタグの中にあるか? + * @type {boolean} */ // TODO defer の場合もあるので、document.readyState を見る // MacIE で false X.inHead = (function( s ){ diff --git a/0.6.x/js/01_core/02_XUA.js b/0.6.x/js/01_core/02_XUA.js index 6f15535..c0b57f4 100644 --- a/0.6.x/js/01_core/02_XUA.js +++ b/0.6.x/js/01_core/02_XUA.js @@ -3,7 +3,9 @@ // ------------ local variables -------------------------------------------- // // ------------------------------------------------------------------------- // var X_UA = (function( n, undefined ){ - var acme = {}, + var + /** @alias X.UA */ + acme = {}, dua = n.userAgent, dav = n.appVersion, tv = parseFloat(dav), @@ -23,11 +25,13 @@ 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; if( screen.width === screen.height * 1.5 || screen.width * 1.5 === screen.height ){ @@ -35,19 +39,45 @@ var X_UA = (function( n, undefined ){ }; if( sys === 'iPhone' ){ + /** @memberof X.UA */ acme.iPhone = true; - if( v ) acme.iPhone_4s = true; // 4s以下 - if( v && i ) acme.iPhone_3GS = true; // 3GS以下 + if( v ){ + /** iPhone4s以下 + * @memberof X.UA */ + acme.iPhone_4s = true; + }; + if( v && i ){ + /** iPhone3GS以下 + * @memberof X.UA */ + acme.iPhone_3GS = true; + }; //alert( 'iPhone ' + ( acme.iPhone_3GS ? '3GS以下' : acme.iPhone_4s ? '4s以下' : '5以上' ) ); }; if( sys === 'iPad' ){ + /** @memberof X.UA */ acme.iPad = true; - if( i ) acme.iPad_2Mini1 = true; + if( i ){ + /** + * iPad2以下または初代iPad mini 以下 + * @memberof X.UA */ + acme.iPad_2Mini1 = true; + }; }; if( sys === 'iPod' ){ + /** @memberof X.UA */ acme.iPod = true; - if( v ) acme.iPod_4 = true; - if( v && i ) acme.iPod_3 = true; + if( v && i ){ + /** + * iPod3以下 + * @memberof X.UA */ + acme.iPod_3 = true; + }; + if( v ){ + /** + * iPod4以下 + * @memberof X.UA */ + acme.iPod_4 = true; + }; //alert( 'iPod touch ' + ( acme.iPod_3 ? '3以下' : acme.iPod_4 ? '4以下' : '5以上' ) ); }; @@ -55,10 +85,12 @@ var X_UA = (function( n, undefined ){ } 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 } else if( sys.indexOf( 'Win' ) + 1 ){ console.log( 'Win' ); + /** @memberof X.UA */ acme.Windows = true; switch( sys ){ case 'Win16' : @@ -71,9 +103,11 @@ var X_UA = (function( n, undefined ){ } else if( sys.indexOf( 'Mac' ) + 1 ){ console.log( 'Mac' ); + /** @memberof X.UA */ acme.Mac = true; switch( sys ){ case 'MacPowerPC' : + /** @memberof X.UA */ acme.MacPPC = true; break; case 'MacPPC' : @@ -84,9 +118,11 @@ var X_UA = (function( n, undefined ){ } else if( ( sys.indexOf( 'Linux' ) + 1 ) || ( sys.indexOf( 'Android' ) + 1 ) ){ console.log( 'Linux' ); + /** @memberof X.UA */ acme.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 ); }; @@ -104,18 +140,26 @@ Sleipnir Mobile Android 2.1以上 Fenrir if( window.opera ){ i = dua.indexOf( 'Opera' ); // Opera/ j = dua.indexOf( 'Version/' ); + /** @memberof X.UA */ acme.Opera = 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; + /** @memberof X.UA */ acme.Opera78 = acme.Opera < 9; + /** @memberof X.UA */ acme.OperaMini = 0 < dua.indexOf('Opera Mini'); + /** @memberof X.UA */ acme.OperaMobile = 0 < dua.indexOf('Opera Mobi'); + /** @memberof X.UA */ acme.OperaTablet = 0 < dua.indexOf('Opera Tablet'); + /** @memberof X.UA */ acme.Wii = dua.indexOf( 'Nintendo Wii' ) !== -1; + /** @memberof X.UA */ acme.NDS = dua.indexOf( 'Nitro' ) !== -1; console.log( '>> Opera : ' + acme.Opera ); return acme; @@ -123,25 +167,49 @@ Sleipnir Mobile Android 2.1以上 Fenrir // 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' ]; + /** + * 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 が書かれているため互換モードか?判定ができる // 互換モードでは Silverlight でエラーが出る? + /** @memberof X.UA */ acme.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; + /** + * IE11 の互換モードを使用しているか? + * @memberof X.UA */ acme.IECompat = /* acme.IE !== acme._IE || */ tridentToVer !== acme._IE && tridentToVer; + /** @memberof X.UA */ acme.IE4 = acme.IE && acme.IE < 5; + /** @memberof X.UA */ acme.IE5678 = 5 <= acme.IE && acme.IE < 9; + /** @memberof X.UA */ acme.IE5 = 5 <= acme.IE && acme.IE < 5.5; + /** @memberof X.UA */ acme.IE55 = 5.5 <= acme.IE && acme.IE < 6; + /** @memberof X.UA */ acme.IE5x = acme.IE5 || acme.IE55; + /** @memberof X.UA */ acme.IE6 = 6 <= acme.IE && acme.IE < 7; + /** @memberof X.UA */ acme.IE7 = 7 <= acme.IE && acme.IE < 8; + /** @memberof X.UA */ acme.IE8 = 8 <= acme.IE && acme.IE < 9; + /** @memberof X.UA */ acme.IE9 = 9 <= acme.IE && acme.IE < 10; + /** @memberof X.UA */ acme.MacIE = acme.Mac; + /** @memberof X.UA */ acme.IEMobile = dua.toLowerCase().indexOf( 'iemobile' ) !== -1 || acme.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 ); // TODO XBox360, XBox1, Modern or Desktop, Standalone @@ -150,6 +218,7 @@ Sleipnir Mobile Android 2.1以上 Fenrir // 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; @@ -167,6 +236,9 @@ Sleipnir Mobile Android 2.1以上 Fenrir // https://github.com/Famous/famous/blob/1a02c8084587d80519ea4bd3b55649ab32ee2e65/examples/assets/lib/require.js // PS3 ブラウザのロードイベントについて if( ( i = dua.toUpperCase().indexOf( 'PLAYSTATION 3' ) !== -1 ) ){ + /** + * PlayStation 3 システムバージョン 4.10 未満の SONY 独自ブラウザ + * @memberof X.UA */ acme.PS3 = parseFloat( dua.substr( i + 15 ) ) || 0.1; console.log( '>> PS3 : ' + acme.PS3 ); return acme; @@ -176,6 +248,7 @@ Sleipnir Mobile Android 2.1以上 Fenrir // iCab/3.0.2 (Macintosh; U; PPC Mac OS X) // 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; @@ -183,17 +256,21 @@ Sleipnir Mobile Android 2.1以上 Fenrir if( 0 < dua.indexOf( 'Gecko\/' ) && ( i = dua.indexOf( 'rv:' ) ) ){ v = dua.substr( i + 3 ).split( '.' ); + /** @memberof X.UA */ acme.Gecko = parseFloat( v[ 0 ] ) || 0 + ( parseFloat( v[ 1 ] ) || 0 ) / 10 + ( parseFloat( v[ 2 ] ) || 0 ) / 100; - + /** @memberof X.UA */ acme.GeckoMajor = parseFloat( v[ 0 ] ) || 0; + /** @memberof X.UA */ acme.GeckoMinor = parseFloat( v[ 1 ] ) || 0; + /** @memberof X.UA */ acme.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; @@ -203,7 +280,9 @@ Sleipnir Mobile Android 2.1以上 Fenrir //Netscape //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; + /** @memberof X.UA */ acme.NN6 = true; console.log( '>> NN : ' + acme.NN + ', Gecko : ' + acme.Gecko ); return acme; @@ -227,32 +306,42 @@ Sleipnir Mobile Android 2.1以上 Fenrir // TODO Blink if( window.chrome ){ + /** @memberof X.UA */ acme.Blink = tv; console.log( '>>Blink : ' + acme.Blink ); } else if( dav.indexOf( 'Konqueror' ) !== -1 ){ + /** @memberof X.UA */ acme.Khtml = tv; console.log( '>>Khtml : ' + acme.Khtml ); } else if( ( i = dua.indexOf( 'Android ' ) ) !== -1 ){ + /** @memberof X.UA */ acme.AndroidBrowser = i = parseFloat( dua.substr( i + 8 ) ) || 0.1; + /** @memberof X.UA */ acme.AndroidBrowser1 = 1 <= i && i < 2; + /** @memberof X.UA */ acme.AndroidBrowser2 = 2 <= i && i < 3; + /** @memberof X.UA */ acme.AndroidBrowser3 = 3 <= i && i < 4; + /** @memberof X.UA */ acme.AndroidBrowser4 = 4 <= i && i < 5; + /** @memberof X.UA */ acme.AndroidBrowser5 = 5 <= i && i < 6; console.log( '>> AndroidBrowser : ' + acme.Android ); i = parseFloat(dua.split('WebKit\/')[1]); + /** @memberof X.UA */ acme.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; // TODO webkit Opera @@ -261,6 +350,7 @@ Sleipnir Mobile Android 2.1以上 Fenrir if( i && !acme.Chrome && dua.indexOf( 'Safari' ) !== -1 ){ if( dav.indexOf( 'Version/' ) !== -1 ){ + /** @memberof X.UA */ acme.Safari = parseFloat( dav.split('Version/')[1] ); } else { if( i < 73 ){ @@ -308,8 +398,10 @@ Sleipnir Mobile Android 2.1以上 Fenrir dua.indexOf( 'Kindle' ) !== -1 || // Sony Reader Mozilla/5.0 (Linux; U; ja-jp; EBRD1101; EXT) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 dua.indexOf( 'EBRD' ) !== -1 - ) acme.EInk = true; - + ){ + /** @memberof X.UA */ + acme.EInk = true; + }; return acme; })( navigator ), @@ -366,6 +458,13 @@ 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 diff --git a/0.6.x/js/01_core/03_XType.js b/0.6.x/js/01_core/03_XType.js index e8067de..28c100a 100644 --- a/0.6.x/js/01_core/03_XType.js +++ b/0.6.x/js/01_core/03_XType.js @@ -1,22 +1,33 @@ -/* +/** * http://pettanr.sourceforge.jp/test/type.html + * ビルトイン方の判定に使用する関数を集めたもの。ブラウザのネイティブな判定関数には不可解な挙動があるので、X.Type を使用するほうがよい。 * - * need xua + * @namespace X.Type + * @alias X.Type */ - X.Type = { + /** + * Object か?判定する。typeof null === 'object' に対策済なので null は Object ではない。 + */ isObject : function( v ){ return v && typeof v === 'object'; // typeof null === 'object' に対策 }, - + /** + * Function か?判定する。 + */ isFunction : function( v ){ return typeof v === 'function'; }, - + /** + * ie の XHR.open 等ビルトインオブジェクトか?判定する。 + */ isUnknown : function( v ){ - return typeof v === 'unknown'; // ie の XHR.open など + 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 になる @@ -25,27 +36,40 @@ X.Type = { 'return v&&Object.prototype.toString.call(v)==="[object Array]"' : 'return v instanceof Array' ), - + /** + * 真偽値か?判定する。 + */ isBoolean : function( v ){ return v === true || v === false; }, - + /** + * 文字列か?判定する。 + */ isString : function( v ){ return typeof v === 'string'; // v === v + ''; // 文字列の加算は IE で遅いかも。 }, - + /** + * 数値値か?判定する。 + */ isNumber : function( v ){ return typeof v === 'number'; // v !== v || v + 0 === v; }, - + /** + * finite か?判定する。isFinite( '123' ) === true に対策済。 + */ isFinite : function( v ){ - return typeof v === 'number' && isFinite( v ); // isFinite( '123' ) === true に対策 + return typeof v === 'number' && isFinite( v ); }, - + /** + * NaN か?判定する。isNaN( 'NaN' ) === true に対策済。 + */ isNaN : function( v ){ - return v !== v; // isNaN( 'NaN' ) === true に対策 + return v !== v; }, - + /** + * HTMLElement か?判定する。 + * @funciton + */ isHTMLElement : new Function( 'v', ( X_UA.IE4 || X_UA.MacIE ) ? @@ -78,10 +102,15 @@ X.Type = { return (Object.prototype.toString.call(v) === "[object HTMLCollection]"); }, */ + /** + * Null か?判定する。 + */ isNull : function( v ){ return v === null; }, - + /** + * undefined か?判定する。 + */ isUndefined : function( v ){ return v === void 0; } diff --git a/0.6.x/js/01_core/04_XObject.js b/0.6.x/js/01_core/04_XObject.js index e9d96df..283ade5 100644 --- a/0.6.x/js/01_core/04_XObject.js +++ b/0.6.x/js/01_core/04_XObject.js @@ -1,4 +1,12 @@ - +/** + * name in object 構文が使えない環境で構文解析エラーを回避するためにこのメソッドを使用します。 + * 但し for( name in object ) については構文解析エラーになる環境はありません。 + * @alias X.Object.inObject + * @function + * @param {string} name + * @param {object} obj + * @return {boolean} name が定義されている(値が undefined や null でも) -> true + */ var X_Object_inObject = X_UA.IE < 5.5 ? // TODO JScript で判定 (function( name, obj ){ var p; @@ -11,21 +19,35 @@ var X_Object_inObject = X_UA.IE < 5.5 ? // TODO JScript で判定 }) : new Function( 'a,b', 'return a in b' );// なぜか ie5 でもerror - +/** + * Object に関するメソッドを集めたものです。 + * @namespace X.Object + * @alias X.Object + */ X.Object = { + // TODO rename to copy clone : X_Object_clone, override : X_Object_override, deepCopy : X_Object_deepCopy, + // TODO rename to X.Array.copy cloneArray : X_Object_cloneArray, isEmpty : X_Object_isEmpty, inObject : X_Object_inObject -}; + // TODO hasOwnProperty +}; + +/** + * 単純なクローンでメンバーをコピーしたオブジェクトを返します。 + * @alias X.Object.clone + * @param {object|Array} src コピー元のオブジェクトです。 + * @return {object|Array} + */ function X_Object_clone( src ){ var ret, k; if( typeof src !== 'object' ) return src; @@ -37,6 +59,13 @@ function X_Object_clone( src ){ return ret; }; +/** + * オブジェクトにオブジェトのメンバーをコピーします。同じ名前のメンバーは上書きされます。 + * @alias X.Object.override + * @param {object} target コピーされるオブジェクトです。返り値はこのオブジェクトです。 + * @param {object} src コピー元のオブジェクトです。 + * @return {object} target が返る。 + */ function X_Object_override( target, src ){ var k; if( !X.Type.isObject( src ) ) return target; @@ -47,6 +76,13 @@ function X_Object_override( target, src ){ return target; }; +/** + * オブジェクト(object, Array)のメンバーを探索して、ディープコピーしたオブジェクトを返します。 + * オブジェクトが循環参照している場合は、既にコピーしているオブジェクトが現れた時点で、先に作成しているコピーの参照を返すので無限にループすることはありません。 + * @alias X.Object.deepCopy + * @param {object|Array} src コピー元のオブジェクトです。 + * @return {object|Array} + */ function X_Object_deepCopy( src ){ return X_Object_deepCopy_( src, [], [], -1 ); }; @@ -78,6 +114,12 @@ function X_Object_deepCopy_( src, objSrc, objCopy, n ) { return ret; }; +/** + * 単純にメンバーをコピーした Array を返します。 + * @alias X.Object.cloneArray + * @param {Array} ary コピー元のオブジェクトです。 + * @return {Array} + */ function X_Object_cloneArray( ary ){ var ret = [], i = ary.length; @@ -87,7 +129,13 @@ function X_Object_cloneArray( ary ){ }; return ret; }; - + +/** + * object が空か?調べます。 + * @alias X.Object.isEmpty + * @param {object} v + * @return {boolean} + */ function X_Object_isEmpty( v ){ var k; for( k in v ){ diff --git a/0.6.x/js/01_core/05_XString.js b/0.6.x/js/01_core/05_XString.js index c05219d..b5ba9ba 100644 --- a/0.6.x/js/01_core/05_XString.js +++ b/0.6.x/js/01_core/05_XString.js @@ -7,6 +7,11 @@ var X_String_CRLF = String.fromCharCode( 13 ) + String.fromCharCode( 10 ); // ------------------------------------------------------------------------- // // --- interface ----------------------------------------------------------- // // ------------------------------------------------------------------------- // + +/** + * @namespace X.String + * @alias X.String + */ X.String = { parse : X_String_parse, @@ -17,7 +22,9 @@ X.String = { chrReferanceTo : X_String_chrReferanceTo, - toChrReferance : X_String_toChrReferance + toChrReferance : X_String_toChrReferance, + + isNumberString : X_String_isNumberString }; // ------------------------------------------------------------------------- // @@ -96,3 +103,8 @@ function X_String_toChrReferance( str ){ .split( ' ' ).join( ' ' ); }; +function X_String_isNumberString( v ){ + var n = v - 0; + return '' + n === v || '' + n === '0' + v; +}; + diff --git a/0.6.x/js/01_core/06_XURL.js b/0.6.x/js/01_core/06_XURL.js index 8bd31bc..091e3cf 100644 --- a/0.6.x/js/01_core/06_XURL.js +++ b/0.6.x/js/01_core/06_XURL.js @@ -41,6 +41,11 @@ var X_URL_BASE_URL = ( function( parts ){ // ------------------------------------------------------------------------- // // --- interface ----------------------------------------------------------- // // ------------------------------------------------------------------------- // + +/** + * @namespace X.URL + * @alias X.URL + */ X.URL = { BASE_URL : X_URL_BASE_URL, diff --git a/0.6.x/js/01_core/10_XCallback.js b/0.6.x/js/01_core/10_XCallback.js index 4dad3ff..f042a01 100644 --- a/0.6.x/js/01_core/10_XCallback.js +++ b/0.6.x/js/01_core/10_XCallback.js @@ -26,19 +26,117 @@ var X_Callback_LIVE_LIST = [], */ var listener; -/* - * コールバックに thisObject や、追加の引数を設定するための情報を収めたハッシュ - * @typedef {{ k : number, f : (function|undefined), x : (listener|undefined), s : (Array|undefined) }} +/** + *

クロージャについて

+ * javascript 開発で多用されるクロージャですが、次の理由によりその使用は慎重になるべきです。 + *
    + *
  1. 正しく参照を切ってガベージコレクトされる条件を満たしたか?プログラマが見落としやすく、結果メモリリークを起こしやすい。特にコードがコールバック地獄になると目も当てられない。 + *
+ * + * とくに次のようなページでは、クロージャの使用を極力避けるべきです。破棄が行われることが確実で即時関数によって新しい名前を追加したくない場合と、次項で紹介する絶対に必要なケース以外で使わないようにします。 + *
    + *
  1. ajax によりデータ取得がたびたび起こり、合わせて不要なデータの破棄も行う。 + *
  2. シングルページアプリケーションで画面の生成と破棄が繰り返される。 + *
  3. Web アプリケーションで、一度開いたら一日中操作し続けるユーザーも想定される。 + *
+ * + *

クロージャが絶対に必要な場合

+ * IE5 ~ IE8 の独自イベントモデルに於いて、イベントオブジェクトに event.currentTarget に相当するものがなく、現在どの HTML 要素でイベントが起こっているか分かりません。
+ * そのため HTML 要素とコールバック関数を束縛するクロージャを使う必要があります。
+ * 参照:『Javascript 第5版』 オライリー p430 17.3.6 attachEvent() と this キーワード
+ * + * このほかに IE8 以下と Opera11 以下の XHR ではイベントオブジェクトが用意されないため、eventType が分からない問題があります。このために eventType とコールバック関数を束縛するクロージャが必要です。
+ * + * このように、Web ブラウザと javascript の接点では、どうしてもクロージャが必要なケースがあります。
+ * さて、クロージャの使用を最小限に留め、残った僅かなクロージャのメモリリークをチェックし、といくら慎重に開発を行っても、そもそもクロージャが破棄されるのか?ガベージコレクションの怪しいブラウザもあり問題はまだ続きます。 + * + *

再利用可能なクロージャ

+ * クロージャの使用を最小限にしたうえで、なおかつクロージャがガベージコレクションされない可能性を考慮して、pettanR フレームワークでは再利用可能なクロージャを用意します。
+ * 再利用可能クロージャはフレームワーク内で生成・破棄されるため、ユーザーが直接触ることはありません。しかし debug ツールのコールスタックには登場するため、知識を持っておくことは有益です。
+ * + *
再利用可能クロージャの作成
+ * X_Callback_create() で再利用可能なクロージャの作成。次のパターンで呼び出します。
+ * 最大で三つの引数を並べる一連のパターンは、 EventDispatcher.listen unlisten, listening や X.Timer.add, once でも使われますので、ここでよく目を通しておきます。 + * + * + *
this コンテキスト+関数X_Callback_create( thisObject, func )func.call( thisObject ); + *
this コンテキスト+関数+追加引数X_Callback_create( thisObject, func, [ arg1, ...args ] )func.apply( thisObject, [ arg1, ...args ] ); + *
listener オブジェクトX_Callback_create( listener )listener.handleEvent(); コールバックに関数でなく handleEvent 関数をメンバに持つオブジェクトを渡すのは NN4 からある javascript のお約束です。 + *
listener オブジェクト+追加引数X_Callback_create( listener, [ arg1, ...args ] )listener.handleEvent.apply( listener, [ arg1, ...args ] ); + *
関数X_Callback_create( func )特別な操作は不要なので再利用可能クロージャは作られません。func をそのまま利用します。 + *
関数+引数X_Callback_create( func, [ arg1, ...args ] )func.apply( ?, [ arg1, ...args ] ); + *
+ * + *
再利用可能クロージャの破棄と再利用
+ * X_Callback_correct() によってクロージャは回収され再利用に備えます。
+ * 実は、クロージャが束縛するのは、this コンテキストやコールバック関数といった、そのものではなく、それらを一定のルールで格納したハッシュです。
+ * このハッシュはクロージャに与えた後も、適宜に取得が可能です。このハッシュのメンバーを書き換えることで、クロージャの this コンテキストやコールバック関数を書き換えています。 + * + * @class __CallbackHash__ + * @classdesc コールバック関数に this コンテキストや、追加の引数を設定するための情報を収めたハッシュです。
+ * フレームワークユーザは直接触ることにはないが、重要な情報なので書いておきます。 + * @private */ -var callbackHash; - +var __CallbackHash__ = +/** @lends __CallbackHash__.prototype */ +{ + /** + * コールバックの種類を表す数値。 this + function, this.handleEvent, function only がある。 + * @type {number} + */ + kind : X_Callback_THIS_FUNC, + /** + * コールバック。 + * @type {funciton|undefined} + */ + func : undefined, + /** + * コールバックの this コンテキスト。 + * @type {listener|object|undefined} + */ + context : undefined, + /** + * コールバックに追加する引数。イベントのコールバックでは event オブジェクトのあとに追加されるため supplement[0] が第一引数にならない点に注意。 + * @type {Array|undefined} + */ + supplement : undefined, + /** + * __CallbackHash__ の情報を元に、コールバックを実施するプロキシ。 + * @type {Function} + */ + proxy : X_Callback_proxyCallback +}; +/** + * X.Timer と X.EventDispatcher からのコールバックの返り値を定義。 + * @namespace X.Callback + * @alias X.Callback + */ X.Callback = { + /** + * このコールバックでは返り値による操作は無い。 + */ NONE : X_Callback_NONE, + /** + * X.Timer.add, X.EventDispatcher.listen のコールバックでタイマーやイベントリスナの解除に使用。 + */ UN_LISTEN : X_Callback_UN_LISTEN, + /** + * イベントのバブルアップを中止する。DOM イベントのコールバックの戻り値に指定すると e.stopPropagation() が呼ばれる。 + */ STOP_PROPAGATION : X_Callback_STOP_PROPAGATION, + /** + * 以降のイベントのディスパッチを中断する。 + */ STOP_NOW : X_Callback_STOP_NOW, + /** + * DOM イベントのコールバックの戻り値に指定すると e.preventDefault() が呼ばれる。 + * またフレームワーク内で定義されたデフォルト動作の回避にも使用される。 + */ PREVENT_DEFAULT : X_Callback_PREVENT_DEFAULT, + /** + * X.UI に於いて、ポインターイベントの戻り値に指定すると、以降のポインターベントを独占する。 + */ MONOPOLY : X_Callback_MONOPOLY }; diff --git a/0.6.x/js/01_core/11_XClass.js b/0.6.x/js/01_core/11_XClass.js index 248b5bd..8fa3773 100644 --- a/0.6.x/js/01_core/11_XClass.js +++ b/0.6.x/js/01_core/11_XClass.js @@ -1,19 +1,24 @@ -/** - * Class を定義し システムの管理下に置く. - * 全てのクラスと pool が有効の場合インスタンスへの参照が保持される. - * 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 されたインスタンスが返される. - * 6. - * - */ // ------------------------------------------------------------------------- // // ------------ local variables -------------------------------------------- // // ------------------------------------------------------------------------- // -var X_Class_CLASS_LIST = [], +var + /** + * 全てのクラスのスーパークラスのようなもの。(ライブラリ内にカプセル化されているため、ユーザが触ることはありません)
+ * X.Class.create() で定義されたクラスのインスタンスが共通で備えるメソッド を確認してください。 + * @class __ClassBase__ + * @private + * @abstract + */ + __ClassBase__ = { + /** + * クラス名 + * @type {string} + */ + name : '' + }, + + X_Class_CLASS_LIST = [], X_Class_DEF_LIST = [], X_Class_PRIVATE_CLASS_LIST = [], X_Class_PRIVATE_DEF_LIST = [], @@ -25,18 +30,19 @@ var X_Class_CLASS_LIST = [], X_Class_use_proto_ = !X_UA.OperaMobile && !X_UA.OperaTablet && !!X.emptyFunction.prototype.__proto__, // Opera Mobile 12.10 Android11 IS01 でクラスのメンバが欠落する問題に遭遇。__proto__ を使わないと動作,,, -/** - * X.Class.create で定義されたクラスのインスタンスが共通で備えるメソッド を格納 - * - * @class - */ -X_Class_CommonProps = - +X_Class_CommonMethods = +/** @lends __ClassBase__.prototype */ { - /* - * インスタンスの破棄。 - * TODO kill したインスタンスのイベントが残っていないか?これは開発用のみ + /** + * 全ての動的メンバを削除して、インスタンスを破棄する。
+ * インスタンスが X.EventDispatcher とそのサブクラスの場合、次の動作をする。 + *
    + *
  1. X.Event.BEFORE_KILL_INSTANCE を発火する。戻り値のビットフラグに X.Callback.PREVENT_DEFAULT が立つ場合、破棄をキャンセルし X.Event.KILL_INSTANCE_CANCELED を発火する。 + *
  2. 破棄に進む場合は、X.Event.KILL_INSTANCE を発火する。 + *
  3. dispatch 中は、インスタンスの全ての dispatch が終了するまで実際の破棄を待つ。 + *
  4. 実際の破棄では、インスタンスのメンバの削除に加えて全てのイベントリスナを解除する。 */ + // TODO kill したインスタンスのイベントが残っていないか?これは開発用のみ kill : function(){ var instance = this, klass = X_Class_getClass( instance ), @@ -48,28 +54,30 @@ X_Class_CommonProps = }; X_Class_killPrivateFlag = false; // instance.kill() 内で PrivateInstance.kill() を防ぐため - // X.EventDispatcher とそのサブクラスは kill() が呼ばれた通知を発行する。 - // X.Event.BEFORE_KILL_INSTANCE はキャンセル可能(private な class は不可) - // X.Event.KILL_INSTANCE は、プロパティやイベントリスナの削除直前に発行 - // X.Event.KILL_INSTANCE_CANCELED は kill() がキャンセルされた場合に発行。また dispatchループ中にkill()が呼ばれると一旦キャンセルされ発行。 - // (flagを立ててdispatchの終わりにkillする) if( this.instanceOf( X.EventDispatcher ) ){ if( !def.isPrivate ){ - if( this[ '_listeners' ] && this[ '_listeners' ]._dispatching ){ - this.dispatch( X.Event.BEFORE_KILL_INSTANCE ); - this[ '_listeners' ]._killReserved = true; - this.dispatch( X.Event.KILL_INSTANCE_CANCELED ); - return; - } else 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 ] ){ + this[ '_listeners' ][ X_Listeners_.KILL_RESERVED ] = true; + return; + }; } else { this.dispatch( X.Event.BEFORE_KILL_INSTANCE ); }; + + // asyncDispatch の削除 + for( p in X_EventDispatcher_LAZY_TIMERS ){ + if( X_EventDispatcher_LAZY_TIMERS[ p ] === this ){ + delete X_EventDispatcher_LAZY_TIMERS[ p ]; // 削除が先!理由は X.Timer.removeを確認。 + X.Timer.remove( parseFloat( p ) ); + }; + }; + this.dispatch( X.Event.KILL_INSTANCE ); - this._listeners && X_EventDispatcher_systemUnlisten( this ); //.unlisten(); + this._listeners && X_EventDispatcher_systemUnlisten( this ); }; for( p in instance ){ @@ -85,8 +93,8 @@ X_Class_CommonProps = if( i !== -1 ){ data = X_Class_getPrivate( instance ); X_Class_killPrivateFlag = true; - if( data[ '_listeners' ] && data[ '_listeners' ]._dispatching && data.instanceOf( X.EventDispatcher ) ){ - data[ '_listeners' ]._killReserved = true; + if( data[ '_listeners' ] && data[ '_listeners' ][ X_Listeners_.DISPATCHING ] && data.instanceOf( X.EventDispatcher ) ){ + data[ '_listeners' ][ X_Listeners_.KILL_RESERVED ] = true; } else { data.kill(); }; @@ -96,12 +104,17 @@ X_Class_CommonProps = }; }, - /* クラス定義を辿ってスーパークラスのコンストラクタを探す。 - * 呼び出したコンストラクタは配列に控える。 - * さらに呼ばれた場合、配列を元にさらに奥のコンストラクタを取得 - * TODO 現在 new しているインスタンスを保持してチェックする + /** + * 関数は Constructor 内で使用します。クラス定義を辿ってスーパークラスのコンストラクタを探します。
    + * 内部的には、呼び出したコンストラクタは配列に控え(X_Class_CALLING_SUPER)、呼び出したコンストラクタ内でさらに Super が呼ばれた場合、配列を元にさらにスーパーなコンストラクタを辿ります。 + * @example Constructor : function( arg1, arg2 ){ + * this.Super( aeg1, arg2 ); + * } + * @param var_args {...?} 親コンストラクタを呼ぶ際に渡す任意の数の引数 + * @return {*} */ - Super : function(){ + // TODO 現在 new しているインスタンスを保持してチェックする + Super : function( var_args ){ var sClass = this, i = X_Class_CALLING_SUPER.indexOf( sClass ), n = -1, @@ -132,18 +145,22 @@ X_Class_CommonProps = console.log( 'スーパークラスのコンストラクタが見つかりません' ); }, - /* - * func について、親クラスで設定されている同名の関数メンバーを呼び出す - * 2つ以上の異なる名前で同じ関数がメンバーだった場合、失敗します - * 例) this.superCall( arguments.callee, param0, param1, ... ) + /** + * func について、親クラスで設定されている同名の関数メンバーを呼び出す。
    + * 第一引数に関数を指定し、2つ以上の異なる名前で同じ関数がメンバーがいた場合、動作が不確実になります。
    + * 参考:ES5なJavascriptでモダンなクラス的継承&スーパー呼び出し + * @param funcNameOrFunc {Function|string} スーパークラスの関数名 または、オーバーライド済の自身の関数。 + * @param var_args {...*} オーバーライド元関数に渡す任意の数の引数 + * @example return this.superCall( arguments.callee, param0, param1, ... ); + * @return {*} オーバーライド元の関数を呼び出した戻り値。 */ - superCall : function( func /* ...args */ ){ + superCall : function( funcNameOrFunc, var_args ){ var sClass = this, args = arguments, name, p, sFunc, hit = false; - if( X.Type.isFunction( func ) ){ - for( p in this ){ - if( this[ p ] === func ){ + if( X.Type.isFunction( funcNameOrFunc ) ){ + for( p in this.constructor.prototype ){ + if( this.constructor.prototype[ p ] === funcNameOrFunc ){ name = p; break; }; @@ -159,7 +176,7 @@ X_Class_CommonProps = def = X_Class_getClassDef( sClass ); sClass = def.SuperClass; sFunc = sClass.prototype[ name ]; - if( sFunc === func ){ + if( sFunc === funcNameOrFunc ){ hit = true; // 現在の関数にヒット } else if( hit && X_Object_inObject( name, this ) ){ @@ -184,9 +201,14 @@ X_Class_CommonProps = }; }, - /* - * TODO instanceof に対応したブラウザはそちらを使用 + /** + * インスタンスのクラスか?またはスーパークラスか?調べる。
    + * instanceof 構文をサポートしない環境(IE4,Mac IE5)を想定する場合、必ずこのメソッドを使用すること。
    + * クラスのインスタンスか?だけ調べたい場合は this.constructor === klass が高速。 + * @param klass {__ClassBase__} クラス定義 + * @return {boolean} */ + // TODO instanceof に対応したブラウザはそちらを使用 instanceOf : function( klass ){ var Super = this; if( this.constructor === klass ) return true; @@ -201,32 +223,66 @@ X_Class_CommonProps = // --- interface ----------------------------------------------------------- // // ------------------------------------------------------------------------- // -/** @namespace */ +/** + * Class を定義し システムの管理下に置く.
    + * 全てのクラスと pool が有効の場合インスタンスへの参照が保持される. + *
      + *
    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 + */ X.Class = { - + + /** + * 設定なし。 + */ NONE : 0, /** * インスタンスは破棄時(this.kill())に回収され、次回の new MyClass() 時に再利用されます。 - * @memberof X.Class */ + */ POOL_OBJECT : 1, /** * 定義するクラスは抽象クラスになります。new AbstractClass() とするとエラーになります。 - * @memberof X.Class */ + */ ABSTRACT : 2, - - - /** @memberof X.Class */ + + /** + * クラスの継承を禁止する。 + */ FINAL : 4, - /** @memberof X.Class */ + + /** + * 使用を中止。petanR ライブラリ使用プロジェクトから SUPER_ACCESS を消したらここも削除。 + */ SUPER_ACCESS : 8, - /** @memberof X.Class */ + + /** + * 内部コード、主に X.UI フレームワークに対して、フレーム外に露出するインスタンスとペアで動作する、シャドウなインスタンスの使用を宣言する。 + * Javascript はインスタンス毎のカプセル化がとてもコスト高。微妙なコスト増で隠蔽されたインスタンスを使う。 + */ PRIVATE_DATA : 16, - /** @memberof X.Class */ - SINGLETON : 32, // 未実装 - - create : function( /* displayName, classSetting, opt_PrivateClass, props */ ){ + + /** + * 未実装。でも目印になるので付けておきましょう。 + */ + SINGLETON : 32, + + /** + * クラスを定義する。
      + * X.Class.create() によるクラス定義は必ずしもコンストラクタを必要としません。クラス定義時にコンストラクタが未設定の場合、スーパークラスがあればそのコンストラクタを使用します。 + * @param {string} [displayName] クラスの名前 + * @param {number} [classSetting=0] X.Class.POOL_OBJECT | X.Class.FINAL など + * @param {__ClassBase__=} [privateClass] このクラスとペアで動作するシャドウクラス + * @param {object} [props={}] このクラスのメンバと関数。コンストラクタは Constructor と書くこと + * @return {__ClassBase__} + */ + create : function( /* displayName, classSetting, privateClass, props */ ){ var args = X_Object_cloneArray( arguments ), displayName = args[ 0 ], classSetting, @@ -291,7 +347,7 @@ X.Class = { klass.subClassOf = X_Class_subClassOf; if( X_Class_useObjectCreate ){ - klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonProps, false ); + klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonMethods, false ); klass.prototype.constructor = klass; } else if( X_Class_use_proto_ ){ @@ -299,12 +355,13 @@ X.Class = { if( X_Class_traits ){ klass.prototype.__proto__ = X_Class_traits; } else { - X_Class_override( klass.prototype, X_Class_CommonProps, false ); + X_Class_override( klass.prototype, X_Class_CommonMethods, false ); }; } else { - klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonProps, false ); + klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonMethods, false ); klass.prototype.constructor = klass; }; + klass.name = displayName; if( opt_abstract ){ @@ -340,6 +397,8 @@ X.Class = { }; + + // ------------------------------------------------------------------------- // // --- implements ---------------------------------------------------------- // // ------------------------------------------------------------------------- // @@ -415,13 +474,19 @@ function X_Class_override( target, src, force ){ X.Logger.critical( p + ' is reserved!' ); return; }; - if( force || target[ p ] === void 0 ){ + if( force || target[ p ] === undefined ){ target[ p ] = src[ p ]; }; }; return target; }; +/** + * スーパークラスか?調べます。 + * @alias __ClassBase__.superClassOf + * @param klass {__ClassBase__} + * @return {boolean} + */ function X_Class_superClassOf( klass ){ var myDef = X_Class_getClassDef( this ), targetDef = X_Class_getClassDef( klass ), @@ -436,13 +501,26 @@ function X_Class_superClassOf( klass ){ return false; }; +/** + * サブクラスか?調べます。 + * @alias __ClassBase__.subClassOf + * @type {Function} + * @param klass {__ClassBase__} + * @return {boolean} + */ function X_Class_subClassOf( klass ){ - return X_Class_superClassOf.call( klass, this ); + return klass && X_Class_superClassOf.call( klass, this ); }; - -/* サブクラスを作るメソッド - * var subClass = superClass.inherits( ... ) - * http://d.hatena.ne.jp/m-hiyama/20051018/1129605002 + +/** + * サブクラスを作ります。与える引数は X.Class.create と同じです。http://d.hatena.ne.jp/m-hiyama/20051018/1129605002 + * @alias __ClassBase__.inherits + * @example var SubClass = SuperClass.inherits( 'Sub', X.Class.FINAL, { ... } ); + * @param {string} [displayName] クラスの名前 + * @param {number} [classSetting=0] X.Class.POOL_OBJECT | X.Class.FINAL など + * @param {__ClassBase__=} [privateClass] このクラスとペアで動作するシャドウクラス + * @param {object} [props={}] このクラスのメンバと関数。コンストラクタは Constructor と書くこと + * @return {__ClassBase__} */ function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props */ ){ var args = X_Object_cloneArray( arguments ), @@ -472,7 +550,7 @@ function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props classSetting = superDef.setting;// &= ~X.Class.ABSTRACT; }; if( superDef.isPrivate ) classSetting = classSetting | X.Class.PRIVATE_DATA; - //opt_super = !!( classSetting & X.Class.SUPER_ACCESS ); + params.push( classSetting ); // サブクラスのシャドウ diff --git a/0.6.x/js/01_core/12_XEvent.js b/0.6.x/js/01_core/12_XEvent.js index 6c2a208..b9ca82d 100644 --- a/0.6.x/js/01_core/12_XEvent.js +++ b/0.6.x/js/01_core/12_XEvent.js @@ -52,67 +52,72 @@ var X_Event_last = 0, }); // 内部イベント -X_TEMP.SYSTEM_EVENT_PRE_INIT = 1; -X_TEMP.SYSTEM_EVENT_XTREE = 2; -X_TEMP.SYSTEM_EVENT_INIT = 3; +X_TEMP.SYSTEM_EVENT_PRE_INIT = 5; // X_Listeners_.KILL_RESERVED に +1 した値から開始。 +X_TEMP.SYSTEM_EVENT_XTREE = 6; +X_TEMP.SYSTEM_EVENT_INIT = 7; +/** + * フレームワーク内で定義されたイベント。 + * @namespace X.Event + * @alias X.Event + */ X.Event = { - XDOM_READY : 4, + XDOM_READY : 8, - COMPLETE : 5, - READY : 6, - SUCCESS : 7, - ERROR : 8, - PROGRESS : 9, - BEFORE_CANCEL : 10, - CANCELED : 11, - TIMEOUT : 12, + COMPLETE : 9, + READY : 10, + SUCCESS : 11, + ERROR : 12, + PROGRESS : 13, + BEFORE_CANCEL : 14, + CANCELED : 15, + TIMEOUT : 16, - BEFORE_KILL_INSTANCE : 13, - KILL_INSTANCE_CANCELED : 14, - KILL_INSTANCE : 15, + BEFORE_KILL_INSTANCE : 17, + KILL_INSTANCE_CANCELED : 18, + KILL_INSTANCE : 19, - VIEW_ACTIVATE : 16, - VIEW_DEACTIVATE : 17, - VIEW_RESIZED : 18, - VIEW_TURNED : 19, - BASE_FONT_RESIZED : 20, + 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 : 21,// X_System このイベントで要素のサイズを取得すると無限ループに! - UPDATED : 22,// X_System - AFTER_UPDATE : 23, + BEFORE_UPDATE : 25,// X_System このイベントで要素のサイズを取得すると無限ループに! + UPDATED : 26,// X_System + AFTER_UPDATE : 27, - HASH_CHANGED : 24, + HASH_CHANGED : 28, - BEFORE_UNLOAD : 25, - UNLOAD : 26, + BEFORE_UNLOAD : 29, + UNLOAD : 30, - BACKEND_READY : 27, - BACKEND_NONE : 28, - BACKEND_RESEARCH : 29, - BACKEND_CHANGED : 30, + BACKEND_READY : 31, + BACKEND_NONE : 32, + BACKEND_RESEARCH : 33, + BACKEND_CHANGED : 34, - ANIME_BEFORE_START : 31, - ANIME_START : 32, - ANIME : 33, - ANIME_END : 34, - ANIME_BEFORE_STOP : 35, // xnode.stop() のみ、指定時間による停止では呼ばれない - ANIME_STOP : 36, + ANIME_BEFORE_START : 35, + ANIME_START : 36, + ANIME : 37, + ANIME_END : 38, + ANIME_BEFORE_STOP : 39, // xnode.stop() のみ、指定時間による停止では呼ばれない + ANIME_STOP : 40, - GPU_RELEASED : 37, + GPU_RELEASED : 41, - MEDIA_PLAYING : 38, - MEDIA_BEFORE_LOOP : 39, // cancelable - MEDIA_LOOPED : 40, - MEDIA_PAUSED : 41, - MEDIA_ENDED : 42, - MEDIA_WAITING : 43, - MEDIA_SEEKING : 44 + 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 = 44; +X_Event_last = 48; X_TEMP.onSystemReady.push( function(){ diff --git a/0.6.x/js/01_core/13_XEventDispatcher.js b/0.6.x/js/01_core/13_XEventDispatcher.js index 36a11fb..29ec939 100644 --- a/0.6.x/js/01_core/13_XEventDispatcher.js +++ b/0.6.x/js/01_core/13_XEventDispatcher.js @@ -1,29 +1,39 @@ -/** - * - */ - -/** - * X.EventDispatcher - * - * 1. as3 の EventDispatcher ライクなクラス。そのまま使ったり、継承したり。コールバック中にイベントを追加したら?削除したら?にも対処している。 - * 2. _rawObject メンバがいる場合、addEventListener, attachEvent, on 等で生のブラウザオブジェクトにリスナを登録する。 - * window, document, HTMLElement, Image, XHR などが _rawObject - * - * use X.Callback +/* + *

      EventDispatcher インスタンスのメンバ(_listeners)でイベントリスナをイベント名(string)やイベントID(5~以上の number, フレームワーク内で定義、5 以上になる理由は後述)をキーとする Array で記憶します。 + * Arrayには、__CallbackHash__ というハッシュ、または関数が蓄えられています。 * - * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.addEventListener - * イベント発送中のリスナーの追加 - * EventListener がイベント処理中に EventTarget に追加された場合、それが現在のアクションによって実行されることはありませんが、浮上フェーズのように、後の段階のイベントフローで実行されるかもしれません。 + * また、dispatch 中の状態と操作を記録し不整合が起きないようにするためのプロパティを持ち、0 から 4 の番号が与えられています。 * - * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.removeEventListener - * イベントリスナーが イベントを処理中であるイベントターゲットから削除された場合、現在のアクションによってそのイベントリスナーが実行されることはありません。 - * イベントリスナーは、決して削除された後に実行されることはありません。 - * イベントターゲット上にある現在のどのイベントリスナーも指定していない引数付きの removeEventListener は、何の効果もありません。 + *

      + *
      0:ACTUAL_HANDLER + *
      イベントターゲットの addEventListener 等に渡される実際の関数(再利用可能クロージャ)を控えています。 + *
      1:DISPATCHING number + *
      イベントディスパッチ中か?またディスパッチがネストした場合、その深さを記憶します。 + *
      2:RESERVES Array + *
      イベント発火中に listen() が呼ばれた場合に引数を蓄え、全てのディスパッチの完了時(_dispatching===0)に再度 listen() するための一時ストアです。 + *
      3:UNLISTENS Array + *
      イベント発火中に unlisten() が呼ばれた場合に対象リスナを記憶し、リスナが呼ばれないようにします。全てのディスパッチの完了時(_dispatching===0)に再度 unlisten() します。 + *
      4:KILL_RESERVED boolean + *
      イベント発火中に kill() が呼ばれた場合に、全てのディスパッチの完了時(_dispatching===0)に再度 kill() するためのフラグです。 + *
      */ +var X_Listeners, + + /** @enum {number} */ + X_Listeners_ = { + ACTUAL_HANDLER : 0, + DISPATCHING : 1, + RESERVES : 2, + UNLISTENS : 3, + KILL_RESERVED : 4 // X.Event で、イベントIDを 5 から始めているので注意。 + }; + + // ------------------------------------------------------------------------- // // ------------ local variables -------------------------------------------- // // ------------------------------------------------------------------------- // + var X_EventDispatcher_once = false, X_EventDispatcher_lock = false, X_EventDispatcher_unlock = false, @@ -38,53 +48,56 @@ var X_EventDispatcher_once = false, }, X_EventDispatcher_LAZY_TIMERS = {}; // Object. number は timerID - -/* - * イベントリスナをイベント名(string)や数値(1~,フレームワーク内で定義)をキーとするArrayで記憶します。 - * Arrayには、{k:種類,x:コンテキスト(thisObject),f:関数,s:サプリメントする引数の配列} というハッシュ、または関数が蓄えられています。 - * また、dispatch 中の状態と操作を記録し不整合が起きないようにするためのプロパティを持ちます。 - * @typedef {( - * { - * _handleEvent : function, - * _dispatching : number, - * _reserves : (Array|undefined), - * _unlistens : {Object.<(number|string), Array.<(X.Callback|function)>>}, - * _killReserved : (Boolean|undefiend) - * } - * | - * Object.<(number|string), Array.<(callbackHash|function)>> - * )} - */ -var X_EventDispatcher_listeners; // ------------------------------------------------------------------------- // // --- interface ----------------------------------------------------------- // // ------------------------------------------------------------------------- // /** - *

      イベントターゲット(widnow, document, Image, XHR, Silverlight 等)をラップする場合、通常は new 時に渡します。 - *

      参照:コンストラクタ実体 {@link X.EventDispatcher.Constructor} - *

      アプリケーション独自のイベントをやり取りしたい、という場合、イベントターゲットは不要です。 + *

        + *
      1. as3 の EventDispatcher ライクなクラス。そのまま使ったり、継承したり。 + *
      2. _rawObject メンバがいる場合、addEventListener, attachEvent, on 等で生のブラウザオブジェクトにリスナを登録する。 + * window, document, HTMLElement, Image, XHR, Silverlight などが _rawObject + *
      3. イベントディスパッチにリスナの追加が呼び出された場合、リスナはこれ以降のイベントから呼ばれます。同様にリスナの削除が呼ばれた場合、そのリスナが呼ばれることはありません。 + *
      + * + * + *

      + * MDN > 開発者向けのWeb技術 > Web API インターフェイス > EventTarget > EventTarget.addEventListener イベント発送中のリスナーの追加 + *

      EventListener がイベント処理中に EventTarget に追加された場合、それが現在のアクションによって実行されることはありませんが、浮上フェーズのように、後の段階のイベントフローで実行されるかもしれません。 + * + * + * + *

      + * MDN > 開発者向けのWeb技術 > Web API インターフェイス > EventTarget > EventTarget.removeEventListener 注記 + *

      イベントリスナーが イベントを処理中であるイベントターゲットから削除された場合、現在のアクションによってそのイベントリスナーが実行されることはありません。 + *

      イベントリスナーは、決して削除された後に実行されることはありません。 + *

      イベントターゲット上にある現在のどのイベントリスナーも指定していない引数付きの removeEventListener は、何の効果もありません。 + * + * + *

      listen, unlisten, dispatch という addEventListener, removeEventListener, dispatchEvent に対応する関数を持ちます。 + * また listening という ActionScript3 の hasEventListener に相当する関数を持ちます。 + * + *

      イベントターゲットオブジェクト(widnow, document, HTMLElement, XHR, Silverlight 等)が this._rawObject に設定されていた場合に、それらへ実際のイベント登録・解除も行います。 + * このイベントの登録・解除はクロスブラウザで、IE5~8 の独自イベントの差異を吸収し、DOM0 に対しても複数のコールバックを登録することができます。 + * + *

      またコールバックに対して、this コンテキストや、追加の引数を指定もできます。 this コンテキストを指定しなかった場合、EventDispatcher インスタンスがコールバックの this になります。 * - * @class - * @classdesc EventTarget オブジェクトをラップしたり、アプリケーションで独自に定義したイベントを発信するためのクラスです。 - *

      listen, unlisten, dispatch という addEventListener, removeEventListener, dispatchEvent に対応する関数を持ちます。 - *

      また listening という ActionScript3 の hasEventListener に相当する関数を持ちます。 - *

      イベントターゲットオブジェクト(widnow, document, HTMLElement, XHR 等)が this._rawObject に設定されていた場合に、それらへ実際のイベント登録・解除も行います。 - *

      このイベントの登録・解除はクロスブラウザで、IE5~8 の独自イベントの差異を吸収し、DOM0 に対しても複数のコールバックを登録することができます。 - *

      またコールバックに対して、this コンテキストや、追加の引数を指定もできます。 this コンテキストを指定しなかった場合、EventDispatcher インスタンスがコールバックの this になります。 - *

      unlisten() は、引数を指定しなかった場合、全てのイベントを解除します。ただし、systemListen 経由で登録されたハンドラは解除されません。 - * systemListen, systemUnlisten は、ライブラリ内のコードからしかアクセスできません。 + *

      unlisten() は、引数を指定しなかった場合、全てのイベントを解除します。ただし、systemListen 経由で登録されたハンドラは解除されません。 * - * @augments X_Class_CommonProps + * systemListen, systemUnlisten は、ライブラリ内のコードからしかアクセスできません。 * - * @param {object=} opt_rawObject イベントターゲット(EventTarget) + * @alias X.EventDispatcher + * @class EventDispatcher オブジェクトをラップしたり、アプリケーションで独自に定義したイベントを発信するためのクラスです。 + * @constructor + * @constructs EventDispatcher + * @extends {__ClassBase__} */ -X.EventDispatcher = +var EventDispatcher = X.EventDispatcher = X.Class.create( 'EventDispatcher', - /** @lends X.EventDispatcher.prototype */ + /** @lends EventDispatcher.prototype */ { /** @@ -95,11 +108,11 @@ X.EventDispatcher = '_rawType' : X_EventDispatcher_EVENT_TARGET_TYPE.OTHER, /** - * イベントリスナをイベント名(string)や数値(1~,フレームワーク内で定義)をキーとするArrayで記憶します。 + * イベントリスナをイベント名文字列や数値(1~,フレームワーク内で定義)をキーとするArrayで記憶します。
      * Arrayには、{k:種類,x:コンテキスト(thisObject),f:関数,s:サプリメントする引数の配列} というハッシュ、または関数が蓄えられています。 * * @private - * @type {X_EventDispatcher_listeners} + * @type {X_Listeners} */ '_listeners' : null, @@ -114,9 +127,9 @@ X.EventDispatcher = '_rawObject' : null, /** - * X.EventDispatcher のコンストラクタの実体。 - * @constructs - * @this {X.EventDispatcher} + * X.EventDispatcher のコンストラクタの実体。
      + * イベントターゲットをラップする場合、通常は new 時に渡します。
      + * アプリケーション独自のイベントをやり取りしたいだけ、という場合イベントターゲットは指定しません。 * @param {object=} opt_rawObject */ Constructor : function( opt_rawObject ){ @@ -125,33 +138,17 @@ X.EventDispatcher = }; }, - /** - * 登録されたイベントリスナを呼び出す。イベントリスナの返り値(数値)を OR したものを返す。 - * @this {X.EventDispatcher} - * @return {number} - * @param {(eventHash|string|number)} e - */ dispatch : X_EventDispatcher_dispatch, - /** - * - * @this {X.EventDispatcher} - * @param {(string|number|Array.<(string,number)>)} type - * @param {(listener|function|Array)=} opt_arg1 - * @param {(function|Array=} opt_arg2 - * @param {Array=} opt_arg3 - * @return {X.EventDispatcher} - */ listen : X_EventDispatcher_listen, /** - * 一度 dispatch された時に自動で unlisten されるフラグを立てて listen する。 - * @this {X.EventDispatcher} - * @return {X.EventDispatcher} - * @param {(string|number|Array.<(string,number)>)} type - * @param {(listener|function|Array)=} opt_arg1 - * @param {(function|Array=} opt_arg2 - * @param {Array=} opt_arg3 + * dispatch 時に自動で unlisten されるフラグを立てて listen する。 + * @param {string|number|Array.} type 配列を指定した場合、複数のイベントタイプに対して同じコールバックを登録する。 + * @param {listener|function|Array} [opt_arg1=] + * @param {function|Array} [opt_arg2=] + * @param {Array} [opt_arg3=] コールバック時の引数を配列に入れる。引数がひとつでも配列を使用する。省略した場合引数なし。unlisten() に使用するので、配列も適宜に保持しておくこと。 + * @return {EventDispatcher} チェインメソッド */ listenOnce : function( type, opt_arg1, opt_arg2, opt_arg3 ){ X_EventDispatcher_once = true; @@ -172,12 +169,11 @@ X.EventDispatcher = * this.listen( [ 'myevent', 'yourevent' ], this, onMyEvent, args = [ 1, 'a' ] ); * this.listening( 'myevent', this, onMyEvent, args ) === true; * - * @this {X.EventDispatcher} - * @return {(number|boolean)} - * @param {(string|number)=} opt_type - * @param {(listener|function|Array|callbackHash)=} opt_arg1 - * @param {(function|Array=} opt_arg2 - * @param {Array=} opt_arg3 + * @return {number|boolean} + * @param {string|number} opt_type + * @param {listener|function|Array|callbackHash} opt_arg1 + * @param {function|Array} opt_arg2 + * @param {Array} opt_arg3 */ listening : function( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ var listeners = this[ '_listeners' ], @@ -194,7 +190,7 @@ X.EventDispatcher = cbHash = X_Callback_classifyCallbackArgs( opt_arg1, opt_arg2, opt_arg3, this ); }; - if( ( unlistens = listeners._unlistens ) && ( unlistens = unlistens[ opt_type ] ) ){ + if( ( unlistens = listeners[ X_Listeners_.UNLISTENS ] ) && ( unlistens = unlistens[ opt_type ] ) ){ for( i = unlistens.length; i; ){ f = unlistens[ --i ]; if( f === cbHash || ( f.x === cbHash.x && f.f === cbHash.f && f.s === cbHash.s && f.lock === lock ) ) return false; @@ -212,9 +208,12 @@ X.EventDispatcher = /** * delay(ミリ秒)後にイベントを dispatch する。戻り値は uid = X.Timer.add() のタイマーID(数値)。X.Timer.remove(uid) でタイマーを解除して dispatch を中止できる。 - * @this {X.EventDispatcher} - * @param {(number|eventHash|string)=} delay ms 省略した場合は 0 として扱う asyncDispatch( 'myevent' ) -> asyncDispatch( 0, 'myevent' ) - * @param {(eventHash|string|number)=} e イベントを表す数値、文字列、{ type : XXX, ... } なオブジェクト + * kill() 時には内部でまだ呼ばれていないタイマーの X.Timer.remove() が行われる。 + * @example this.asyncDispatch( 'myevent' ); + * // どちらのコードも同じ動作をする。 + * this.asyncDispatch( 0, 'myevent' ); + * @param {number|eventHash|string} delay ms 省略した場合は 0 として扱う asyncDispatch( 'myevent' ) -> asyncDispatch( 0, 'myevent' ) + * @param {eventHash|string|number} e イベントを表す数値、文字列、{ type : XXX, ... } なオブジェクト * @return {number} X.Timer.add() の戻り値 */ asyncDispatch : function( delay, e ){ @@ -235,10 +234,13 @@ X.EventDispatcher = // ------------------------------------------------------------------------- // /** - * 登録されたイベントリスナを呼び出す。イベントリスナの返り値(数値)を OR したものを返す。イベントハッシュでなく、string|number を渡すと内部でイベントハッシュを作る - * @this {X.EventDispatcher} + * 登録されたイベントリスナを呼び出す。イベントリスナの返り値(数値)を OR したものを返す。イベントハッシュでなく、string|number を渡すと内部でイベントハッシュを作る。 + * dispatch のコールバック中で kill() が呼ばれた場合、実際の kill は、dispatch の終わりまで待機する。dispatch がネストする場合は全ての dispatch の完了で kill() する。__ClassBase__ も参照。 + * dispatch のコールバック中で listen() が呼ばれた場合、実際の listen は、dispatch の終わりまで待機する。dispatch がネストする場合は全ての dispatch の完了で listen() する。 + * dispatch のコールバック中で unlisten() が呼ばれた場合、即座に反映され削除されたイベントリスナーは呼ばれない。 + * @alias EventDispatcher.prototype.dispatch + * @param {eventHash|string|number} e * @return {number} X.Callback で定義された数値 - * @param {(eventHash|string|number)} e */ function X_EventDispatcher_dispatch( e ){ var listeners = this[ '_listeners' ], @@ -255,36 +257,30 @@ function X_EventDispatcher_dispatch( e ){ e.target = e.target || this; e.currentTarget = e.currentTarget || this; - if( listeners._dispatching ){ - ++listeners._dispatching; + if( listeners[ X_Listeners_.DISPATCHING ] ){ + ++listeners[ X_Listeners_.DISPATCHING ]; } else { - listeners._dispatching = 1; + listeners[ X_Listeners_.DISPATCHING ] = 1; }; // todo: // type も保存 - listeners._unlistens = listeners._unlistens || {}; - unlistens = listeners._unlistens[ type ]; + listeners[ X_Listeners_.UNLISTENS ] = listeners[ X_Listeners_.UNLISTENS ] || {}; + unlistens = listeners[ X_Listeners_.UNLISTENS ][ type ]; for( i = 0; i < list.length; ++i ){ f = list[ i ]; if( !unlistens ){ - unlistens = listeners._unlistens[ type ]; + unlistens = listeners[ X_Listeners_.UNLISTENS ][ type ]; }; if( unlistens && unlistens.indexOf( f ) !== -1 ) continue; - //if( f !== X.emptyFunction ){ - // if( f.k ){ - r = X_Callback_proxyCallback( f, args || ( args = [ e ] ) ); - // } else { - // r = f.call( this, e ); - // }; - //}; + r = X_Callback_proxyCallback( f, args || ( args = [ e ] ) ); if( f.once || r & X_Callback_UN_LISTEN ){ // dispatch 中に unlisten が作られることがある if( !unlistens ){ - unlistens = listeners._unlistens || ( listeners._unlistens = {} ); + unlistens = listeners[ X_Listeners_.UNLISTENS ] || ( listeners[ X_Listeners_.UNLISTENS ] = {} ); unlistens = unlistens[ type ] || ( unlistens[ type ] = [] ); }; unlistens.indexOf( f ) === -1 && ( unlistens[ unlistens.length ] = f ); @@ -296,12 +292,12 @@ function X_EventDispatcher_dispatch( e ){ ret |= X.Type.isFinite( r ) ? r : 0; }; - if( ( --listeners._dispatching ) === 0 ){ + if( ( --listeners[ X_Listeners_.DISPATCHING ] ) === 0 ){ - delete listeners._dispatching; + delete listeners[ X_Listeners_.DISPATCHING ]; // dispatch 中に listen されたイベントの追加 - if( list = listeners._reserves ){ + if( list = listeners[ X_Listeners_.RESERVES ] ){ for( i = 0, l = list.length; i < l; ++i ){ f = list[ i ]; X_EventDispatcher_once = f[ 4 ]; @@ -312,12 +308,12 @@ function X_EventDispatcher_dispatch( e ){ f.length = 0; }; list.length = 0; - delete listeners._reserves; + delete listeners[ X_Listeners_.RESERVES ]; }; // dispatch 中に unlisten されたイベントの削除 - if( unlistens = listeners._unlistens ){ - delete listeners._unlistens; + if( unlistens = listeners[ X_Listeners_.UNLISTENS ] ){ + delete listeners[ X_Listeners_.UNLISTENS ]; // _unlistens に入っている callbackHash は、lock をクリアしている X_EventDispatcher_unlock = true; @@ -330,17 +326,18 @@ function X_EventDispatcher_dispatch( e ){ list.length = 0; delete unlistens[ type ]; }; - X_EventDispatcher_unlock = false; + X_EventDispatcher_unlock = false; }; if( X_EventDispatcher_LAZY_TIMERS[ X_Timer_currentUID ] === this ){ delete X_EventDispatcher_LAZY_TIMERS[ X_Timer_currentUID ]; }; - if( listeners._killReserved ){ + if( listeners[ X_Listeners_.KILL_RESERVED ] ){ + /* for( timerID in X_EventDispatcher_LAZY_TIMERS ){ if( X_EventDispatcher_LAZY_TIMERS[ timerID ] === this ) return ret; - }; + }; */ this.kill(); }; }; @@ -349,14 +346,36 @@ function X_EventDispatcher_dispatch( e ){ }; /** + * イベントリスナを追加する。同一イベントに対して重複するリスナ(context, function, 引数 array が一致)の追加は無視される。 + * ユーザーが触ることは無いが、システム内部でロックフラグを立てたリスナは、立てられていないフラグとは区別される。 + * この仕組みによってシステムの登録したリスナを、システム外から不用意に削除されることを回避する。 + * @example // 'myEvent' に対して、 this コンテキストを指定して 、コールバック関数を渡す。 + * this.listen( 'myEvent', context, func ); + * // 'myEvent' に対して、 this コンテキストを指定して 、コールバック関数と追加の引数を渡す。 + * args = [ 'arg1', 'arg2', 3 ]; // unlisten( 'myEvent', context, func, args ) で使用するので Array も控えておく。 + * this.listen( 'myEvent', context, func, args ); + * // 'myEvent' に対して、 listener オブジェクトを渡す。listener は handleEvent という関数を持つオブジェクトのこと。 + * listener.handleEvent = function( e ){}; + * this.listen( 'myEvent', listener ); + * // 'myEvent' に対して、 listener オブジェクトと追加の引数を渡す。 + * listener.handleEvent = function( e, arg1, arg2, arg3 ){}; + * this.listen( 'myEvent', listener, [ arg1, arg2, arg3 ] ); + * // 'myEvent' に対して、 function を渡す。 + * this.listen( 'myEvent', onMyEvent ); + * // 'myEvent' に対して、 function と追加の引数を渡す。 + * this.listen( 'myEvent', onMyEvent, args ); + * // 次の二つは同じ動作です。 this コンテキストが与えられなかった場合、コールバックの this は発火元インスタンスになります。 + * this.listen( 'myEvent', this [, func [, args ] ] ); + * this.listen( 'myEvent' [, func [, args ] ] ); + * // 複数のイベントタイプを同時に登録。コールバックは同じ指定が使われる。 + * this.listen( [ 'open', 'close', 'ready' ], onUpdate ); * - * @this {X.EventDispatcher} - * @memberOf X.EventDispatcher.prototype - * @param {(string|number|Array.<(string,number)>)} type - * @param {(listener|function|Array)=} opt_arg1 - * @param {(function|Array=} opt_arg2 - * @param {Array=} opt_arg3 - * @return {X.EventDispatcher} + * @alias EventDispatcher.prototype.listen + * @param {string|number|Array.} type 配列を指定した場合、複数のイベントタイプに対して同じコールバックを登録する。 + * @param {listener|function|Array} [opt_arg1=] + * @param {function|Array} [opt_arg2=] + * @param {Array} [opt_arg3=] コールバック時の引数を配列に入れる。引数がひとつでも配列を使用する。省略した場合引数なし。 + * @return {EventDispatcher} チェインメソッド */ function X_EventDispatcher_listen( type, opt_arg1, opt_arg2, opt_arg3 ){ var listeners = this[ '_listeners' ], @@ -364,9 +383,9 @@ function X_EventDispatcher_listen( type, opt_arg1, opt_arg2, opt_arg3 ){ if( !type ) return this; - if( listeners && listeners._dispatching ){ - if( !listeners._reserves ) listeners._reserves = []; - listeners._reserves[ listeners._reserves.length ] = [ type, opt_arg1, opt_arg2, opt_arg3, X_EventDispatcher_once, X_EventDispatcher_lock ]; + if( listeners && listeners[ X_Listeners_.DISPATCHING ] ){ + if( !listeners[ X_Listeners_.RESERVES ] ) listeners[ X_Listeners_.RESERVES ] = []; + listeners[ X_Listeners_.RESERVES ][ listeners[ X_Listeners_.RESERVES ].length ] = [ type, opt_arg1, opt_arg2, opt_arg3, X_EventDispatcher_once, X_EventDispatcher_lock ]; return this; }; @@ -407,13 +426,13 @@ function X_EventDispatcher_systemListen( that, type, opt_arg1, opt_arg2, opt_arg // TODO this.listen(type) は this リスナの登録なのに、this.unlisten(type)は全てのtypeの削除、と不一致 /** - * - * @this {X.EventDispatcher} - * @return {X.EventDispatcher} - * @param {(string|number|Array.<(string,number)>)=} opt_type - * @param {(listener|function|Array)=} opt_arg1 - * @param {(function|Array=} opt_arg2 - * @param {Array=} opt_arg3 + * イベントリスナの解除を行う。登録時と同じ引数を与える必要がある。kill() ですべてのイベントが解除されるので、途中で解除されるイベント以外は kill() に任せてしまってよい。 + * @alias EventDispatcher.prototype.unlisten + * @return {EventDispatcher} + * @param {string|number|Array.} opt_type + * @param {listener|function|Array} opt_arg1 + * @param {function|Array} opt_arg2 + * @param {Array} opt_arg3 */ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ var listeners = this[ '_listeners' ], @@ -434,7 +453,7 @@ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ // 全て削除 for( opt_type in listeners ){ //if( X_EMPTY_OBJECT[ opt_type ] ) continue; - if( opt_type.charAt( 0 ) === '_' ) continue; + if( opt_type < X_Listeners_.KILL_RESERVED ) continue; list = listeners[ opt_type ]; for( i = list.length; i; ){ this.unlisten( opt_type, list[ --i ] ); // override されていることがあるので、必ず unlisten を使用 @@ -452,12 +471,12 @@ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ }; return this; } else - if( reserves = listeners._reserves ){ + if( reserves = listeners[ X_Listeners_.RESERVES ] ){ for( i = reserves.length; i; ){ f = reserves[ --i ]; if( f[ 0 ] === opt_type && f[ 1 ] === opt_arg1 && f[ 2 ] === opt_arg2 && f[ 3 ] === opt_arg3 && ( !f[ 5 ] || X_EventDispatcher_unlock ) ){ reserves.splice( i, 1 ); - if( !reserves.legth ) delete listeners._reserves; + if( !reserves.legth ) delete listeners[ X_Listeners_.RESERVES ]; return this; }; }; @@ -470,11 +489,11 @@ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ f = ( list = listeners[ opt_type ] )[ i ]; - if( unlistens = listeners._unlistens ){ + if( unlistens = listeners[ X_Listeners_.UNLISTENS ] ){ // _unlistens に入っている callbackHash は、lock のチェックは済んでいる ( unlistens = unlistens[ opt_type ] ) ? ( unlistens[ unlistens.length ] = f ) : - ( listeners._unlistens[ opt_type ] = [ f ] ); + ( listeners[ X_Listeners_.UNLISTENS ][ opt_type ] = [ f ] ); } else { delete f.once; list.splice( i, 1 ); @@ -485,11 +504,11 @@ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ // TODO カウンター empty = true; for( k in listeners ){ - if( k.charAt( 0 ) === '_' ) continue; + if( k < X_Listeners_.KILL_RESERVED ) continue; empty = false; break; }; - if( raw && '' + parseFloat( opt_type ) !== '' + opt_type ){ // 数字イベントの除外 + if( raw && !X_String_isNumberString( opt_type ) ){ // 数字イベントの除外 X_EventDispatcher_removeEvent( this, opt_type, raw, list, !empty ); }; if( empty ) delete this[ '_listeners' ]; @@ -551,7 +570,7 @@ var X_EventDispatcher_actualAddEvent = type === 'animationiteration' || type === 'webkitAnimationIteration' ) ){ raw.addEventListener( type, X_EventDispatcher_iOSTransitionEndDispatch, false ); } else { - f = that[ '_listeners' ]._handleEvent || ( that[ '_listeners' ]._handleEvent = X_Callback_create( that, X_EventDispatcher_actualHandleEvent ) ); + f = that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ] || ( that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ] = X_Callback_create( that, X_EventDispatcher_actualHandleEvent ) ); if( raw.addEventListener ){ raw.addEventListener( type, f, false ); @@ -577,7 +596,7 @@ var X_EventDispatcher_actualAddEvent = break; default : - f = that[ '_listeners' ]._handleEvent || ( that[ '_listeners' ]._handleEvent = X_Callback_create( that, X_EventDispatcher_actualHandleEvent ) ); + f = that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ] || ( that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ] = X_Callback_create( that, X_EventDispatcher_actualHandleEvent ) ); if( raw.attachEvent ){ raw.attachEvent( 'on' + type, f ); @@ -601,14 +620,14 @@ var X_EventDispatcher_actualAddEvent = break; default : - raw[ 'on' + type ] = that[ '_listeners' ]._handleEvent || ( that[ '_listeners' ]._handleEvent = X_Callback_create( that, X_EventDispatcher_actualHandleEvent ) ); + raw[ 'on' + type ] = that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ] || ( that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ] = X_Callback_create( that, X_EventDispatcher_actualHandleEvent ) ); break; }; }); /* * iOS の webkitTransitionEnd が連続して起こる場合、 - * コールバックの(that._handleEvent)クロージャ内の実際のコールバック(X_Callback_actualClosure:obj._)が + * コールバックの(that[ X_Listeners_.ACTUAL_HANDLER ])クロージャ内の実際のコールバック(X_Callback_actualClosure:obj._)が * 参照できていない問題に遭遇、、、iOS3.1.3 & iOS6.1.5 で確認 * animation も怪しい、、、 */ @@ -665,14 +684,14 @@ var X_EventDispatcher_actualRemoveEvent = raw.removeEventListener( type, X_EventDispatcher_iOSTransitionEndDispatch, false ); } else if( raw.addEventListener ){ - raw.removeEventListener( type, that[ '_listeners' ]._handleEvent, false ); + raw.removeEventListener( type, that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ], false ); } else { raw[ 'on' + type ] = null; }; - if( !skip && that[ '_listeners' ]._handleEvent ){ - X_Callback_correct( that[ '_listeners' ]._handleEvent ); - delete that[ '_listeners' ]._handleEvent; + if( !skip && that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ] ){ + X_Callback_correct( that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ] ); + delete that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ]; }; }; }) : @@ -694,15 +713,15 @@ var X_EventDispatcher_actualRemoveEvent = default : if( raw.attachEvent ){ - raw.detachEvent( 'on' + type, that[ '_listeners' ]._handleEvent ); + raw.detachEvent( 'on' + type, that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ] ); } else { raw[ 'on' + type ] = X.emptyFunction; raw[ 'on' + type ] = ''; }; if( !skip ){ - X_Callback_correct( that[ '_listeners' ]._handleEvent ); - delete that[ '_listeners' ]._handleEvent; + X_Callback_correct( that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ] ); + delete that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ]; }; }; }) : @@ -726,13 +745,15 @@ var X_EventDispatcher_actualRemoveEvent = raw[ 'on' + type ] = ''; if( !skip ){ - X_Callback_correct( that[ '_listeners' ]._handleEvent ); - delete that[ '_listeners' ]._handleEvent; + X_Callback_correct( that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ] ); + delete that[ '_listeners' ][ X_Listeners_.ACTUAL_HANDLER ]; }; }; }); +// TODO ブラウザからの呼び出しの最後に登録された関数を呼び出す機能(例えば画面の更新) + // handleEvent を拡張可能にするために、クロージャに移動した // Is this in regard to the Safari 1.x preventDefault bug on click/dblclick? // https://groups.google.com/forum/#!msg/comp.lang.javascript/uYEuCHjHxnw/yKoHtZJPa1QJ @@ -755,7 +776,7 @@ var X_EventDispatcher_actualHandleEvent = return event.returnValue = false; }; }) : - //X_UA_EVENT.W3C & X_UA_EVENT.DOM0 + //X_UA_EVENT.W3C || X_UA_EVENT.DOM0 (function( e ){ var ev = new X.Dom.Event( e, this ), ret = X_Callback_NONE, @@ -768,7 +789,7 @@ var X_EventDispatcher_actualHandleEvent = ret = X.Callback.STOP_PROPAGATION | X.Callback.PREVENT_DEFAULT; } else { for( i = 0, l = ev.length; i < l; ++i ){ - console.log( 'handleEvent ' + ev[ i ].type ); + //console.log( 'handleEvent ' + ev[ i ].type ); ret |= this.dispatch( ev[ i ] ) || 0; }; }; @@ -807,16 +828,16 @@ if( X_UA.WebKit < 525.13 ){ // Safari3- function X_EventDispatcher_toggleAllEvents( that, add ){ var list = that[ '_listeners' ], raw = that._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( that ), - f = add ? X_EventDispatcher_addEvent : X_EventDispatcher_removeEvent, + func = add ? X_EventDispatcher_addEvent : X_EventDispatcher_removeEvent, type; if( !list || !raw ) return; for( type in list ){ //if( X_EMPTY_OBJECT[ type ] ) continue; - if( type.charAt( 0 ) === '_' ) continue; + //if( type < X_Listeners_.KILL_RESERVED ) continue; // 数字イベントの除外 - if( '' + parseFloat( type ) !== type ){ + if( !X_String_isNumberString( type ) ){ // TODO type rename はここ - f( that, type, raw, list[ type ], true ); + func( that, type, raw, list[ type ], true ); }; }; }; diff --git a/0.6.x/js/01_core/14_XTimer.js b/0.6.x/js/01_core/14_XTimer.js index 2954501..7846bf3 100644 --- a/0.6.x/js/01_core/14_XTimer.js +++ b/0.6.x/js/01_core/14_XTimer.js @@ -130,9 +130,9 @@ X.Timer = { if( X_EventDispatcher_LAZY_TIMERS[ uid ] ){ eventDispatcher = X_EventDispatcher_LAZY_TIMERS[ uid ]; delete X_EventDispatcher_LAZY_TIMERS[ uid ]; - + /* listeners = eventDispatcher[ '_listeners' ]; - if( listeners && !listeners._dispatching && listeners._killReserved ){ + if( listeners && !listeners[ X_Listeners_.DISPATCHING ] && listeners[ X_Listeners_.KILL_RESERVED ] ){ for( uid in X_EventDispatcher_LAZY_TIMERS ){ if( X_EventDispatcher_LAZY_TIMERS[ uid ] === eventDispatcher ){ lazy = true; @@ -140,7 +140,7 @@ X.Timer = { }; }; !lazy && eventDispatcher.kill(); - }; + }; */ }; !X_Timer_skipUpdate && ( q.last <= X_Timer_waitTime || l === 1 ) && X_Timer_update(); diff --git a/0.6.x/js/02_dom/02_XNode.js b/0.6.x/js/02_dom/02_XNode.js index cbfcdf6..3557862 100644 --- a/0.6.x/js/02_dom/02_XNode.js +++ b/0.6.x/js/02_dom/02_XNode.js @@ -35,6 +35,7 @@ var GPU_RESERVED : 2 << 21, // 2:GPU予約 GPU_NOW : 2 << 22, // 3:GPU now! GPU_RELEASE_RESERVED : 2 << 23, // 4:GPU解除予約 + GPU_CHILD : 2 << 24, IE4_HAS_TEXTNODE : X_UA.IE4 ? 2 << 21 : 0, IE4_HAS_ELEMENT : X_UA.IE4 ? 2 << 22 : 0, @@ -112,6 +113,7 @@ var length : 1, parent : null, // remove された枝も親子構造は維持している。 _xnodes : null, // Array. + _gpuParent : null, _tag : '', _text : '', @@ -350,6 +352,30 @@ function X_Node_toggleInTreeFlag( xnodes, flag ){ }; }; +function X_Node_toggleInGPUFlag( gpuRoot, xnodes, flag ){ + var i = xnodes.length, xnode; + + if( flag ){ + for( ; i; ){ + xnode = xnodes[ --i ]; + if( !xnode._gpuParent ){ + xnode._flags |= X_Node_State.GPU_CHILD; + xnode._gpuParent = gpuRoot; + xnode._xnodes && X_Node_toggleInTreeFlag( gpuRoot, xnode._xnodes, flag ); + }; + }; + } else { + for( ; i; ){ + xnode = xnodes[ --i ]; + if( xnode._gpuParent === gpuRoot ){ + xnode._flags &= ~X_Node_State.GPU_CHILD; + delete xnode._gpuParent; + xnode._xnodes && X_Node_toggleInTreeFlag( gpuRoot, xnode._xnodes, flag ); + }; + }; + }; +}; + /* -------------------------------------- * Create */ @@ -651,7 +677,7 @@ function X_Node_empty(){ function X_Node_destroy( isChild ){ var xnodes = this._xnodes, i, elm; - if( !this._flags ) return; + if( ( this._flags & X_Node_State.EXIST ) === 0 ) return; elm = this._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ); @@ -664,7 +690,7 @@ function X_Node_destroy( isChild ){ if( this._flags & X_Node_State.IN_TREE ){ !isChild && this.remove(); - delete this._flags; + this._flags &= ~X_Node_State.EXIST; } else { this.parent && this.parent._xnodes.splice( this.parent._xnodes.indexOf( this ), 1 ); elm && !isChild && X_Node__actualRemove( this ); @@ -677,7 +703,7 @@ function X_Node_destroy( isChild ){ function X_Node_onBeforeKill( e ){ var xnodes = this._xnodes, i, elm; - if( !this._flags ) return X.Callback.NONE; + if( ( this._flags & X_Node_State.EXIST ) === 0 ) return X.Callback.NONE; elm = this._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ); elm && this._listeners && this.unlisten(); // イベントの退避 @@ -693,7 +719,7 @@ function X_Node_onBeforeKill( e ){ if( e ){ this.remove(); if( X_Node_reserveRemoval[ X_Node_reserveRemoval.length - 1 ] === this ){ - delete this._flags; + this._flags &= ~X_Node_State.EXIST; return X.Callback.PREVENT_DEFAULT; }; }; @@ -903,11 +929,12 @@ function X_Node_text( text ){ }; return this; }; - if( !text ) return this.empty(); if( ( xnodes = this._xnodes ) && xnodes.length === 1 && !xnodes[ 0 ]._tag ){ xnodes[ 0 ].text( text ); return this; }; + // TODO 一つのtextnode を残すケース 完全に削除したい場合は empty()を使う + if( !text ) return this.empty(); this.empty().createText( text ); return this; }; @@ -1042,7 +1069,7 @@ function X_Node_startUpdate( time ){ xnode = removal[ --i ]; // TODO GPU レイヤーの子の場合、remove をスキップする。 非GPU レイヤーへ apppend される場合、clone する? X_Node__actualRemove( xnode ); - !xnode._flags && xnode.kill(); + ( xnode._flags & X_Node_State.EXIST ) === 0 && xnode.kill(); }; removal.length = 0; }; @@ -1170,12 +1197,13 @@ var X_Node__commitUpdate = if( X_Node_documentFragment ){ //( frg = X_Node_documentFragment ).appendChild( elm ); + // 連続する要素の差し替えの場合に有効 }; if( X_Node_strictElmCreation ){ that._flags &= X_Node_BitMask_RESET_DIRTY; // ie の string から要素を作る場合、ネットワーク系属性は onload イベントなどを拾うために、要素生成->イベント復帰後に適用する - that._newAttrs && ( that._flags |= X_Node_State.DIRTY_ATTR ); // Network 系の属性は遅らせて設定 + that._newAttrs && ( that._flags |= X_Node_State.DIRTY_ATTR ); // _newAttrs には ネットワーク系属性が入っている。Network 系の属性は遅らせて設定 that._flags |= X_Node_State.DIRTY_IE_FILTER;// doc 追加後に filter を指定しないと有効にならない。 } else { elm.UID = that._uid; @@ -1572,7 +1600,7 @@ var X_Node__afterActualCreate = X_Node__afterActualCreate( xnodes[ --i ] ); }; }; - // ネットわーう系属性と filter は要素生成後に適用 + // ネットワーク系属性と filter は要素生成後に適用 if( that._flags & ( X_Node_State.DIRTY_ATTR | X_Node_State.DIRTY_IE_FILTER ) ){ X_Node__updateRawNode( that, that._rawObject || X_Node__ie4getRawNode( that ) ); } else { diff --git a/0.6.x/js/06_net/00_XNet.js b/0.6.x/js/06_net/00_XNet.js index 2a0ad3c..c077326 100644 --- a/0.6.x/js/06_net/00_XNet.js +++ b/0.6.x/js/06_net/00_XNet.js @@ -22,7 +22,7 @@ X.Net = { }, // TODO chashe - // TODO iframe useful or not. + // TODO iframe useful or not. TODO dynamicIframe // TODO file: では http: は使えない jsonp : function( url, useIframe ){ return new X_NET_Queue( X_NET_TYPE_JSONP, url ); diff --git a/0.6.x/js/06_net/01_XNetXHR.js b/0.6.x/js/06_net/01_XNetXHR.js index fb35d5e..6e64e81 100644 --- a/0.6.x/js/06_net/01_XNetXHR.js +++ b/0.6.x/js/06_net/01_XNetXHR.js @@ -30,7 +30,10 @@ itozyun 2014-10-30 20:55:41 basic 認証のかかったhtml を表示して、そのjsが xhr をすると Android1.6 では 401 error が返る。Android 2.3 では解決している。 Android1.6- の XHR で 401 エラーが返った場合は、iframe に xml を表示させてその内容を取ればサーバ側の対応無しでいけるかも? */ -var X_Net_XHR_W3C = ( !X_UA.IE7 || !X_URL_IS_LOCAL ) && window[ 'XMLHttpRequest' ] && new XMLHttpRequest(), +var // Opera7.6+, Safari1.2+, khtml3.?+, Gecko0.9.7+ + // ie7 ではローカルリソースには ActiveX の XHR を使う + X_Net_XHR_W3C = ( !X_UA.IE7 || !X_URL_IS_LOCAL ) && window[ 'XMLHttpRequest' ] && new XMLHttpRequest(), + X_Net_XHR_X_DOMAIN = window[ 'XDomainRequest' ] && new XDomainRequest(), X_Net_XHR_VERSION = 0, X_Net_XHR_ACTIVE_X = !X_UA.IE4 && X_UA.IE < 8 && X_UA.ActiveX && ( new Function( [ @@ -52,13 +55,6 @@ if( X_Net_XHR_ACTIVE_X ){ }; X.Net.XHR = { - // Opera7.6+, Safari1.2+, khtml3.?+, Gecko0.9.7+ - W3C : !!X_Net_XHR_W3C, - - X_DOMAIN : !!X_Net_XHR_X_DOMAIN, - - // ie7 ではローカルリソースには ActiveX の XHR を使う - ACTIVE_X : !!X_Net_XHR_ACTIVE_X, /* * http://hakuhin.jp/as/import.html @@ -72,11 +68,7 @@ X.Net.XHR = { // Progress Events Chrome7, firefox3.5, ie10, opera12, Safari?, Chrome for Android 0.16 PROGRESS : false, // - UL_PROGRESS : false, - - CANCELABLE : false, - - TIMEOUT : false + UL_PROGRESS : false }; @@ -86,8 +78,9 @@ if( X_Net_XHR_W3C || X_Net_XHR_ACTIVE_X ){ new X.EventDispatcher(), { - _rawType : X_EventDispatcher_EVENT_TARGET_TYPE.XHR, - _rawObject : X_Net_XHR_W3C || X_Net_XHR_ACTIVE_X, + '_rawType' : X_EventDispatcher_EVENT_TARGET_TYPE.XHR, + '_rawObject' : X_Net_XHR_W3C || X_Net_XHR_ACTIVE_X, + _isXDR : false, // for ie8 _method : '', @@ -103,7 +96,7 @@ if( X_Net_XHR_W3C || X_Net_XHR_ACTIVE_X ){ method = obj[ 'method' ], url = obj[ 'url' ], async = obj[ 'async' ], - user = obj[ 'user' ], + username = obj[ 'username' ], password = obj[ 'password' ], headers = obj[ 'headers' ] || {}, postbody = obj[ 'postbody' ], @@ -137,7 +130,7 @@ if( X_Net_XHR_W3C || X_Net_XHR_ACTIVE_X ){ }; }; - raw.open( method, url, true ); + raw.open( method, url, true, username, password ); if( raw.responseType !== undefined ){ switch( this._type ){ @@ -338,7 +331,7 @@ if( X_Net_XHR_W3C || X_Net_XHR_ACTIVE_X ){ break; }; - this.asyncDispatch( 32, { type : X.Event.SUCCESS, status : status || 200, data : data } ); + this.asyncDispatch( 32, { type : X.Event.SUCCESS, status : status || 200, data : data } ); } else { live && this.asyncDispatch( 32, { type : X.Event.ERROR, status : raw.status || 0, percent : 100 } ); }; diff --git a/0.6.x/js/06_net/04_XNetImage.js b/0.6.x/js/06_net/04_XNetImage.js index 2a872cb..8cca132 100644 --- a/0.6.x/js/06_net/04_XNetImage.js +++ b/0.6.x/js/06_net/04_XNetImage.js @@ -43,7 +43,6 @@ X_NET_ImageWrapper = X_Class_override( this.abspath = X.URL.toAbsolutePath( data.url ); this.delay = data.delay || 100; this.timeout = data.timeout || 5000; - //this.timerID = X.Timer.add( this.delay, 0, this, this._detect ); this._rawObject.src = this.abspath; -- 2.11.0