OSDN Git Service

Version 0.6.185, fix X.AudioSprite & X_Node_onKill.
[pettanr/clientJs.git] / 0.6.x / js / 01_core / 13_XClass.js
index ebe050b..bf86574 100644 (file)
@@ -24,8 +24,9 @@ var
        X_Class_CALL_SUPER_STACK   = [],\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
-               // Opera Mobile 12.10 Android11 IS01 でクラスのメンバが欠落する問題に遭遇。__proto__ を辞めると動作,,,\r
+       X_Class_SEAL_KILLING       = [],\r
 \r
 X_Class_CommonMethods =\r
 /** @lends __ClassBase__.prototype */\r
@@ -34,41 +35,76 @@ X_Class_CommonMethods =
         * 全ての動的メンバを削除して、インスタンスを破棄する。<br>\r
         * インスタンスが X.EventDispatcher とそのサブクラスの場合、次の動作をする。\r
         * <ol>\r
-        * <li>X.Event.BEFORE_KILL_INSTANCE を発火する。戻り値のビットフラグに X_Callback.PREVENT_DEFAULT が立つ場合、破棄をキャンセルし X.Event.KILL_INSTANCE_CANCELED を発火する。\r
+        * <li>X.Event.BEFORE_KILL_INSTANCE を発火する。戻り値のビットフラグに X_Callback.PREVENT_DEFAULT が立つ場合、破棄をキャンセルし X.Event.KILL_INSTANCE_CANCELED を発火する。この間に kill() が呼ばれても無視される。\r
         * <li>破棄に進む場合は、X.Event.KILL_INSTANCE を発火する。\r
         * <li>dispatch 中は、インスタンスの全ての dispatch が終了するまで実際の破棄を待つ。\r
         * <li>実際の破棄では、インスタンスのメンバの削除に加えて全てのイベントリスナを解除する。\r
         */\r
        // TODO kill したインスタンスのイベントが残っていないか?これは開発用のみ\r
        'kill' : function(){\r
-               var def, listeners, p;\r
+               var listeners, flag, p, timers, def;\r
                \r
-               // TODO kill 中の kill の呼び出しを防ぐ, 破棄済のインスタンスへの kill\r
+               // TODO 破棄済のインスタンスへの kill\r
                \r
                if( this[ 'instanceOf' ]( X_EventDispatcher ) ){\r
 \r
-                       if( this[ 'dispatch' ]( X_EVENT_BEFORE_KILL_INSTANCE ) & X_Callback_PREVENT_DEFAULT ){\r
-                               this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE_CANCELED );\r
-                               return;\r
-                       };\r
-                       \r
                        listeners = this[ '_listeners' ];\r
-                       \r
-                       if( listeners && listeners[ X_LISTENERS_DISPATCHING ] ){\r
-                               listeners[ X_LISTENERS_KILL_RESERVED ] = true;\r
-                               return;\r
+\r
+                       // SEAL のタイミングは、イベント中なので listeners が存在する\r
+                       if( listeners && X_Class_SEAL_KILLING.length && X_Class_SEAL_KILLING.indexOf( this ) !== -1 ) return;\r
+\r
+                       // listeners がない場合、イベントの登録がないため、BEFORE_KILL_INSTANCE は呼ばれない。\r
+                       // KILL_RESERVED == true の場合、BEFORE_KILL_INSTANCE は呼ばれない。\r
+                       if( listeners && !listeners[ X_LISTENERS_KILL_RESERVED ] && listeners[ X_EVENT_BEFORE_KILL_INSTANCE ] ){\r
+                               X_Class_SEAL_KILLING[ X_Class_SEAL_KILLING.length ] = this;\r
+                               \r
+                               if( this[ 'dispatch' ]( X_EVENT_BEFORE_KILL_INSTANCE ) & X_CALLBACK_PREVENT_DEFAULT ){\r
+                                       this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE_CANCELED );\r
+                                       // BEFORE_KILL_INSTANCE, KILL_INSTANCE_CANCELED 内で kill() しても PREVENT_DEFAULT の場合はこれを無視する。\r
+                                       flag = true;\r
+                               };\r
+                               \r
+                               X_Class_SEAL_KILLING.length === 1 ?\r
+                                       ( X_Class_SEAL_KILLING.length = 0 ) :\r
+                                       X_Class_SEAL_KILLING.splice( X_Class_SEAL_KILLING.indexOf( this ), 1 );\r
+\r
+                               if( flag ) return;\r
+                       };\r
+\r
+                       if( listeners = this[ '_listeners' ] ){// unlisten 等で listeners が破棄されている場合があるので取り直し。\r
+                               if( listeners[ X_LISTENERS_DISPATCHING ] ){\r
+                                       listeners[ X_LISTENERS_KILL_RESERVED ] = true;\r
+                                       return;\r
+                               };\r
+                               \r
+                               if( listeners[ X_EVENT_KILL_INSTANCE ] ){\r
+                                       X_Class_SEAL_KILLING[ X_Class_SEAL_KILLING.length ] = this;\r
+\r
+                                       listeners[ X_LISTENERS_KILL_RESERVED ] = false;                                 \r
+                                       this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE );\r
+                                       \r
+                                       X_Class_SEAL_KILLING.length === 1 ?\r
+                                               ( X_Class_SEAL_KILLING.length = 0 ) :\r
+                                               X_Class_SEAL_KILLING.splice( X_Class_SEAL_KILLING.indexOf( this ), 1 );\r
+                               };\r
+                               \r
+                               X_EventDispatcher_unlistenAll( this );\r
                        };\r
 \r
+                       if( this[ 'instanceOf' ]( Node ) ){\r
+                               // console.log( 'KILL : ' + this.call( 'outerHTML' ) );\r
+                               X_Node_onKill( this );\r
+                       };\r
+\r
+                       timers = X_EventDispatcher_LAZY_TIMERS;\r
+\r
                        // asyncDispatch の削除\r
-                       for( p in X_EventDispatcher_LAZY_TIMERS ){\r
-                               if( X_EventDispatcher_LAZY_TIMERS[ p ] === this ){\r
+                       for( p in timers ){\r
+                               if( timers[ p ] === this ){\r
                                         // delete X_EventDispatcher_LAZY_TIMERS[ p ]; コレ不要\r
                                        X_Timer_remove( p );\r
                                };\r
                        };\r
-                       \r
-                       this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE );\r
-                       listeners && X_EventDispatcher_unlistenAll( this );\r
                };\r
                \r
                X_Object_clear( this );\r
@@ -94,12 +130,13 @@ X_Class_CommonMethods =
        'Super' : function( var_args ){\r
                var sClass = this,\r
                        i      = X_Class_CALLING_SUPER.indexOf( sClass ),\r
-                       n      = -1,\r
                        l, sList, def, sConst, 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
                } else {\r
                        sList = X_Class_CALL_SUPER_STACK[ i ];\r
                };\r
@@ -108,8 +145,9 @@ X_Class_CommonMethods =
                        def    = X_Class_getClassDef( sClass );\r
                        sClass = def.SuperClass;\r
                        sConst = def.SuperConstructor;\r
-                       if( sConst && sList[ ++n ] !== sConst ){\r
-                               sList[ n ] = sConst;\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
@@ -168,7 +206,7 @@ X_Class_CommonMethods =
                                                case 4 :\r
                                                        return sFunc.call( this, args[ 1 ], args[ 2 ], args[ 3 ] );\r
                                                default :\r
-                                                       args = X_Object_cloneArray( args );\r
+                                                       args = X_Array_copy( args );\r
                                                        args.shift();\r
                                                        return sFunc.apply( this, args );\r
                                        };\r
@@ -200,7 +238,7 @@ X_Class_CommonMethods =
 // --- interface ----------------------------------------------------------- //\r
 // ------------------------------------------------------------------------- //\r
 \r
-/*\r
+/**\r
  * @enum {number}\r
  * @const\r
  */\r
@@ -300,7 +338,7 @@ X[ 'Class' ] = /** @lends X.Class */ {
         * );\r
         */\r
        function X_Class_create( /* displayName, classSetting, privateClass, props */ ){\r
-               var args        = X_Object_cloneArray( arguments ),\r
+               var args        = X_Array_copy( arguments ),\r
                        displayName = args[ 0 ],\r
                        classSetting,\r
                        opt_pool, opt_abstract, opt_final,\r
@@ -346,7 +384,7 @@ X[ 'Class' ] = /** @lends X.Class */ {
                        classDef.Constructor = props[ 'Constructor' ];\r
                };\r
 \r
-               klass  = X_Callback_actualClosure( cbHash ); // TODO callbackHash を class定義の置き場所にしてしまう!なるほど…\r
+               klass  = X_Closure_actualClosure( cbHash ); // TODO callbackHash を class定義の置き場所にしてしまう!なるほど…\r
                cbHash.klass = klass;\r
                klass[ 'superClassOf' ] = X_Class_superClassOf;\r
                klass[ 'subClassOf' ]   = X_Class_subClassOf;\r
@@ -370,7 +408,7 @@ X[ 'Class' ] = /** @lends X.Class */ {
                klass[ 'name' ] = displayName;\r
                \r
                if( opt_abstract ){\r
-                       classDef.Abstract = true;\r
+                       classDef.isAbstract = true;\r
                } else\r
                if( opt_pool ){\r
                        classDef.pool = [];\r
@@ -462,12 +500,11 @@ function X_Class_subClassOf( klass ){
  * @example var SubClass = SuperClass.inherits( 'Sub', X_Class.FINAL, { ... } );\r
  * @param {string} [displayName] クラスの名前\r
  * @param {number} [classSetting=0] X_Class.POOL_OBJECT | X_Class.FINAL など\r
- * @param {__ClassBase__=} [privateClass] このクラスとペアで動作するシャドウクラス\r
  * @param {object} [props={}] このクラスのメンバと関数。コンストラクタは Constructor と書くこと\r
  * @return {__ClassBase__}\r
  */\r
-function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
-       var args        = X_Object_cloneArray( arguments ),\r
+function X_Class_inherits( /* displayName, classSetting, props */ ){\r
+       var args        = X_Array_copy( arguments ),\r
                params      = [],\r
                Super       = this,\r
                superDef    = X_Class_getClassDef( Super ),\r
@@ -534,7 +571,7 @@ function X_Class_actualConstructor( f, args ){
                def      = f.classDef,\r
                instance, obj;\r
 \r
-       if( def.Abstract ){\r
+       if( def.isAbstract ){\r
                X.Logger.critical( 'AbstractClass!' );\r
                return;\r
        };\r
@@ -544,9 +581,14 @@ 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
+               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
@@ -556,6 +598,7 @@ function X_Class_actualConstructor( f, args ){
                instance[ 'kill' ]();\r
                return obj;\r
        };\r
+       \r
        return instance;\r
 };\r
 \r