OSDN Git Service

bug fixes superCall, merge X.UI.Gesture to X.UI.AbstructUINode.
[pettanr/clientJs.git] / 0.6.x / js / 01_core / 13_XClass.js
index f5cdc03..072bc2c 100644 (file)
@@ -20,12 +20,13 @@ var
 \r
        X_Class_CLASS_LIST         = [],\r
        X_Class_DEF_LIST           = [],\r
-       X_Class_CALLING_SUPER      = [],\r
-       X_Class_CALL_SUPER_STACK   = [],\r
+       X_Class_SUPER_CALLER       = [],\r
+       X_Class_SUPER_STACKS       = [],\r
        X_Class_traits             = null,\r
        X_Class_useObjectCreate    = false, // !!Object.create, http://jsperf.com/prototype-vs-object-create-perf\r
        // Opera Mobile 12.10 Android11 IS01 でクラスのメンバが欠落する問題に遭遇。__proto__ を辞めると動作,,,\r
        X_Class_use_proto_         = !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] && !!X_emptyFunction.prototype.__proto__,\r
+       X_Class_constructorFix     = X_UA[ 'AOSP' ] < 3 || X_UA[ 'iOS' ] < 5,\r
        X_Class_SEAL_KILLING       = [],\r
 \r
 X_Class_CommonMethods =\r
@@ -128,54 +129,83 @@ X_Class_CommonMethods =
         */\r
        // TODO 現在 new しているインスタンスを保持してチェックする\r
        'Super' : function( var_args ){\r
-               var sClass = this,\r
-                       i      = X_Class_CALLING_SUPER.indexOf( sClass ),\r
-                       l, sList, def, sConst, ret;\r
+               var me     = this,\r
+                       sClass = me,\r
+                       i      = X_Class_SUPER_CALLER.indexOf( me ),\r
+                       stack, t, def, ret;\r
        \r
                if( i === -1 ){\r
-                       X_Class_CALLING_SUPER[ l = X_Class_CALLING_SUPER.length ] = sClass;\r
-                       X_Class_CALL_SUPER_STACK[ l ] = sList = [];\r
-                       def = X_Class_getClassDef( sClass );\r
-                       if( !def.Constructor ) sClass = def.SuperClass;// 現在のクラスがコンストラクタを持たない場合 SuperConstructor を new で呼んでいるため再び呼ばないようにする\r
+                       X_Class_SUPER_CALLER[ i = X_Class_SUPER_CALLER.length ] = me;\r
+                       X_Class_SUPER_STACKS[ i ] = stack = 0;\r
                } else {\r
-                       sList = X_Class_CALL_SUPER_STACK[ i ];\r
+                       stack = X_Class_SUPER_STACKS[ i ];\r
                };\r
                \r
+               t = stack;\r
+               \r
+        while( t ){\r
+               sClass = X_Class_getClassDef( sClass ).SuperClass;\r
+            --t;\r
+        };\r
+               \r
                while( sClass ){\r
+                       ++t;\r
+                       sClass = X_Class_getClassDef( sClass ).SuperClass;\r
+                       if( !sClass ) break;\r
                        def    = X_Class_getClassDef( sClass );\r
-                       sClass = def.SuperClass;\r
-                       sConst = def.SuperConstructor;\r
-                       if( !sConst ) break;\r
-                       if( sList.indexOf( sConst ) === -1 ){\r
-                               sList[ sList.length ] = sConst;\r
-                               ret = sConst.apply( this, arguments );\r
-                               --sList.length;\r
-                               if( !sList.length ){\r
-                                       X_Class_CALLING_SUPER.splice( i, 1 );\r
-                                       X_Class_CALL_SUPER_STACK.splice( i, 1 );\r
-                               };\r
-                               return ret;\r
+                       \r
+                       if( def.Constructor ){\r
+                               X_Class_SUPER_STACKS[ i ] += t;\r
+                               ret = def.Constructor.apply( me, arguments );\r
+                               break;\r
                        };\r
                };\r
-               console.log( 'スーパークラスのコンストラクタが見つかりません' );\r
+               \r
+               if( X_Class_SUPER_STACKS[ i ] === stack ) console.log( 'スーパークラス、またはスーパークラスのコンストラクタは存在しません' );\r
+               \r
+               if( stack === 0 ){\r
+                       X_Class_SUPER_CALLER.splice( i, 1 );\r
+                       X_Class_SUPER_STACKS.splice( i, 1 );\r
+               } else {\r
+                       X_Class_SUPER_STACKS[ i ] = stack;\r
+               };\r
+               return ret || me;\r
        },\r
 \r
        /**\r
         * func について、親クラスで設定されている同名の関数メンバーを呼び出す。<br>\r
-        * 第一引数に関数を指定し、2つ以上の異なる名前で同じ関数がメンバーがいた場合、動作が不確実になります。<br>\r
+        * 第一引数にオーバーライド済の自身の(自身から参照できる)関数を指定します。内部では関数名を調べた上で prototype チェーンをゴリゴリ辿る、特別なことはしていません。\r
+        * superCall がネストする場合、arguments.callee でないと正しく現在階層を取得して親関数を知ることができない\r
+        * 次の理由によって、関数名で辿ることはやめました\r
+        * <ol>\r
+        * <li>closur compiler でメソッド名が変更される\r
+        * <li>superCall 内からさらに superCall が呼ばれた場合に、起点となる関数を特定できない\r
+        * </ol>\r
+        * 次の場合、意図した動作が得られません\r
+        * <ol>\r
+        * <li>2つ以上の異なる名前で同じ関数がメンバーがいた場合<br>\r
+        * <li>または、サブクラスのメンバーにスーパークラスと同じ関数が出現する\r
+        * <li>superCall 以外の手段で親関数を呼び、そのなかで superCall を読んだ\r
+        * </ol>\r
+        * 通常の X.Class.create の書き方ではこのような状況は起きませんが、js はなんでもできるので\r
         * 参考:<a href="http://qiita.com/no22@github/items/d3bead2acbb7ff1fb86b" target="_blank">ES5なJavascriptでモダンなクラス的継承&スーパー呼び出し </a>\r
-        * @param funcNameOrFunc {Function|string} スーパークラスの関数名 または、オーバーライド済の自身の関数。\r
+        * @param myFunc {Function|string} オーバーライド済の自身の(自身から参照できる)関数。\r
         * @param var_args {...*} オーバーライド元関数に渡す任意の数の引数\r
         * @example return this.superCall( arguments.callee, param0, param1, ... );\r
         * @return {*} オーバーライド元の関数を呼び出した戻り値。\r
         */\r
-       'superCall' : function( funcNameOrFunc, var_args ){\r
-               var sClass = this,\r
+       'superCall' : function( myFunc, var_args ){\r
+               var me     = this,\r
+                       sClass = me.constructor,\r
+                       proto  = sClass.prototype,\r
+                       i      = X_Class_SUPER_CALLER.indexOf( me ),\r
+                       l, d, ret,\r
                        args   = arguments,\r
-                       name, p, sFunc, hit = false;\r
-               if( X_Type_isFunction( funcNameOrFunc ) ){\r
-                       for( p in this.constructor.prototype ){\r
-                               if( this.constructor.prototype[ p ] === funcNameOrFunc ){\r
+                       name, p, sFunc;\r
+\r
+               if( X_Type_isFunction( myFunc ) ){\r
+                       for( p in proto ){\r
+                               if( proto[ p ] === myFunc ){\r
                                        name = p;\r
                                        break;\r
                                };\r
@@ -184,41 +214,70 @@ X_Class_CommonMethods =
                } else {\r
                        return;\r
                };\r
-               \r
-               if( X_EMPTY_OBJECT[ name ] ) return;\r
-               \r
-               while( sClass ){\r
-                       def    = X_Class_getClassDef( sClass );\r
-                       sClass = def.SuperClass;\r
-                       sFunc  = sClass.prototype[ name ];\r
-                       if( sFunc === funcNameOrFunc ){\r
-                               hit = true; // 現在の関数にヒット\r
-                       } else\r
-                       if( hit && X_Object_inObject( name, this ) ){\r
-                               if( X_Type_isFunction( sFunc ) ){\r
-                                       switch( args.length ){\r
-                                               case 1 :\r
-                                                       return sFunc.call( this );\r
-                                               case 2 :\r
-                                                       return sFunc.call( this, args[ 1 ] );\r
-                                               case 3 :\r
-                                                       return sFunc.call( this, args[ 1 ], args[ 2 ] );\r
-                                               case 4 :\r
-                                                       return sFunc.call( this, args[ 1 ], args[ 2 ], args[ 3 ] );\r
-                                               default :\r
-                                                       args = X_Array_copy( args );\r
-                                                       args.shift();\r
-                                                       return sFunc.apply( this, args );\r
+                       \r
+               if( i === -1 ){\r
+                       X_Class_SUPER_CALLER[ i = X_Class_SUPER_CALLER.length ] = me;\r
+                       X_Class_SUPER_STACKS[ i ] = stack = 0;\r
+               } else {\r
+                       stack = X_Class_SUPER_STACKS[ i ];\r
+               };\r
+\r
+               t = stack;\r
+\r
+        while( t ){\r
+               sClass = X_Class_getClassDef( sClass ).SuperClass;\r
+            --t;\r
+        };\r
+        \r
+        if( sClass ){\r
+               myFunc = sClass.prototype[ name ];\r
+\r
+                       while( sClass ){\r
+                               ++t;\r
+                               sClass = X_Class_getClassDef( sClass ).SuperClass;      \r
+                               sFunc  = sClass.prototype[ name ];\r
+                               \r
+                               if( sFunc !== myFunc /* X_Object_own( name, sClass.prototype ) */ ){\r
+                                       // this の関数と異なり、値が設定されていたら、今は手を抜いて undef か?見ている、正しくは hasOwnProperty\r
+                                       if( X_Type_isFunction( sFunc ) ){\r
+                                               X_Class_SUPER_STACKS[ i ] += t;\r
+                                               switch( args.length ){\r
+                                                       case 0 :\r
+                                                               ret = sFunc.call( me );\r
+                                                               break;\r
+                                                       case 1 :\r
+                                                               ret = sFunc.call( me, args[ 0 ] );\r
+                                                               break;\r
+                                                       case 2 :\r
+                                                               ret = sFunc.call( me, args[ 0 ], args[ 1 ] );\r
+                                                               break;\r
+                                                       case 3 :\r
+                                                               ret = sFunc.call( me, args[ 0 ], args[ 1 ], args[ 2 ] );\r
+                                                               break;\r
+                                                       default :\r
+                                                               args = X_Array_copy( args );\r
+                                                               args.shift();\r
+                                                               ret = sFunc.apply( me, args );\r
+                                                               break;                                                  \r
+                                               };\r
                                        };\r
+                                       break;\r
                                };\r
-                               break;\r
                        };\r
                };\r
+\r
+               if( stack === 0 ){\r
+                       X_Class_SUPER_CALLER.splice( i, 1 );\r
+                       X_Class_SUPER_STACKS.splice( i, 1 );\r
+               } else {\r
+                       X_Class_SUPER_STACKS[ i ] = stack;\r
+               };\r
+               return ret;\r
        },\r
        \r
        /**\r
         * インスタンスのクラスか?またはスーパークラスか?調べる。<br>\r
-        * instanceof 構文をサポートしない環境(IE4,Mac IE5)を想定する場合、必ずこのメソッドを使用すること。<br>\r
+        * instanceof 構文をサポートしない環境(IE5以下)を想定する場合、必ずこのメソッドを使用すること。<br>\r
         * クラスのインスタンスか?だけ調べたい場合は this.constructor === klass が高速。\r
         * @param klass {__ClassBase__} クラス定義\r
         * @return {boolean}\r
@@ -429,16 +488,13 @@ X[ 'Class' ] = /** @lends X.Class */ {
 \r
 \r
 function X_Class_getClass( instance ){\r
-       var cList    = X_Class_CLASS_LIST,\r
-               i        = cList.length,\r
-               klass;\r
-       for( ; i; ){\r
-               klass = cList[ --i ];\r
-               if( instance.constructor === klass ) return klass;\r
-       };\r
+       var cList = X_Class_CLASS_LIST, i;\r
+       \r
+       if( ( i = cList.indexOf( instance.constructor ) ) !== -1 ) return cList[ i ];\r
        if( cList.indexOf( instance ) !== -1 ) return instance;\r
 };\r
 \r
+// TODO def = klass( X_Closure_COMMAND_BACK )\r
 function X_Class_getClassDef( KlassOrInstance ){\r
        var i = X_Class_CLASS_LIST.indexOf( KlassOrInstance );\r
        if( i === -1 ) i = X_Class_CLASS_LIST.indexOf( X_Class_getClass( KlassOrInstance ) );\r
@@ -556,8 +612,8 @@ function X_Class_inherits( /* displayName, classSetting, props */ ){
        def    = X_Class_getClassDef( klass );\r
        // 継承用プロパティを控える\r
        def.SuperClass       = Super;\r
-       def.SuperProto       = Super.prototype;\r
-       def.SuperConstructor = superDef.Constructor || superDef.SuperConstructor;\r
+       //def.SuperProto       = Super.prototype;\r
+       //def.SuperConstructor = superDef.Constructor || superDef.SuperConstructor;\r
        \r
        return klass;\r
 };\r
@@ -581,18 +637,17 @@ function X_Class_actualConstructor( f, args ){
                                X_Class_useObjectCreate ?\r
                                        Object.create( klass.prototype ) :\r
                                        new klass( X_Closure_COMMAND_DROP );\r
-       \r
+\r
        def.live && def.live.push( instance );\r
 \r
-       if( ( X_UA[ 'AOSP' ] < 3 || X_UA[ 'iOS' ] < 5 ) && instance.constructor !== klass ){\r
+       if( X_Class_constructorFix && instance.constructor !== klass ){\r
                console.log( '------- constructor の不一致!' ); // Android2.3.7\r
                instance.constructor = klass;\r
        };\r
 \r
        obj = def.Constructor ?\r
                        def.Constructor.apply( instance, args ) :\r
-               def.SuperConstructor &&\r
-                       def.SuperConstructor.apply( instance, args );\r
+                       instance[ 'Super' ].apply( instance, args );\r
 \r
        if( obj !== instance && ( X_Type_isObject( obj ) || X_Type_isFunction( obj ) ) ){ // Class\r
                instance[ 'kill' ]();\r