From: itozyun Date: Thu, 19 Feb 2015 05:06:43 +0000 (+0900) Subject: Version 0.6.131, cleanup X.EventDispatcher. X-Git-Url: http://git.osdn.jp/view?p=pettanr%2FclientJs.git;a=commitdiff_plain;h=321cf844195090369e92f5d0c67dcd360eaa6fdd Version 0.6.131, cleanup X.EventDispatcher. --- diff --git a/0.6.x/js/01_core/11_XClass.js b/0.6.x/js/01_core/11_XClass.js index 1280d1a..248b5bd 100644 --- a/0.6.x/js/01_core/11_XClass.js +++ b/0.6.x/js/01_core/11_XClass.js @@ -54,11 +54,10 @@ X_Class_CommonProps = // X.Event.KILL_INSTANCE_CANCELED は kill() がキャンセルされた場合に発行。また dispatchループ中にkill()が呼ばれると一旦キャンセルされ発行。 // (flagを立ててdispatchの終わりにkillする) if( this.instanceOf( X.EventDispatcher ) ){ - //console.log( 'this.instanceOf( X.EventDispatcher )! ' + this._dispatching ); if( !def.isPrivate ){ - if( this._dispatching ){ + if( this[ '_listeners' ] && this[ '_listeners' ]._dispatching ){ this.dispatch( X.Event.BEFORE_KILL_INSTANCE ); - this._killReserved = true; + this[ '_listeners' ]._killReserved = true; this.dispatch( X.Event.KILL_INSTANCE_CANCELED ); return; } else @@ -86,8 +85,8 @@ X_Class_CommonProps = if( i !== -1 ){ data = X_Class_getPrivate( instance ); X_Class_killPrivateFlag = true; - if( data._dispatching && data.instanceOf( X.EventDispatcher ) ){ - data._killReserved = true; + if( data[ '_listeners' ] && data[ '_listeners' ]._dispatching && data.instanceOf( X.EventDispatcher ) ){ + data[ '_listeners' ]._killReserved = true; } else { data.kill(); }; diff --git a/0.6.x/js/01_core/13_XEventDispatcher.js b/0.6.x/js/01_core/13_XEventDispatcher.js index 25c2d11..36a11fb 100644 --- a/0.6.x/js/01_core/13_XEventDispatcher.js +++ b/0.6.x/js/01_core/13_XEventDispatcher.js @@ -29,7 +29,33 @@ var X_EventDispatcher_once = false, X_EventDispatcher_unlock = false, X_EventDispatcher_needsIndex = false, - X_EventDispatcher_safariPreventDefault = false; // Safari3- + X_EventDispatcher_safariPreventDefault = false, // Safari3- + + X_EventDispatcher_EVENT_TARGET_TYPE = { + OTHER : 0, + XHR : 1, + SILVER_LIGHT : 2 + }, + + 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 ----------------------------------------------------------- // @@ -61,14 +87,19 @@ X.EventDispatcher = /** @lends X.EventDispatcher.prototype */ { - - - // TODO _rawObjectType EventTarget, XHR, Silverlight, ... + /** + * OTHER(Node,window,document,Image,Audio), XHR, Silverlight + * @private + * @type {number} + */ + '_rawType' : X_EventDispatcher_EVENT_TARGET_TYPE.OTHER, + /** * イベントリスナをイベント名(string)や数値(1~,フレームワーク内で定義)をキーとするArrayで記憶します。 * Arrayには、{k:種類,x:コンテキスト(thisObject),f:関数,s:サプリメントする引数の配列} というハッシュ、または関数が蓄えられています。 + * * @private - * @type {Object.<(number|string), Array.<(callbackHash|function)>>} + * @type {X_EventDispatcher_listeners} */ '_listeners' : null, @@ -76,62 +107,15 @@ X.EventDispatcher = * _rawObject には HTMLElement, window, document, XHR といったイベントターゲットオブジェクトを設定します。 * _rawObject が設定されていると listen(), unlisten() 時に addEventListener(DOM Level2) や detachEvent(ie5~8), on~(DOM0) 等を操作します。 * _rawObject は最初の listen() 前に設定しておかないと addEventListener 等が意図したように行われません。 - * X.Node では非同期に HTMLElement を生成していて、要素生成以前に listen, unlisten を呼び出すことができます。これは適宜に X_EventDispatcher_toggleAllEvents を呼んで解決しているためです。 + * X.Node では非同期に HTMLElement を生成していますが、要素生成以前に listen, unlisten を呼び出すことができます。これは適宜に X_EventDispatcher_toggleAllEvents を呼んで解決しているためです。 * @private * @type {Object} */ '_rawObject' : null, - - /** - * _rawObject がある場合、イベントターゲットオブジェクトに対して addEventListener, attachEvent, onXX 時に実際に渡される関数。 - * イベントタイプが変わっても、単一の オブジェクトを使いまわす。(但し例外は、IE8以下の XHR|MSXML に対して。)最初の listen で生成されて、最後の unlisten で削除される。 - * @private - * @type {X.Callback} - */ - '_handleEvent' : null, - - /** - * dispatch 中に dispatch が呼ばれた際に、そのネストの深さを保存する。 - * dispatch() 終了時に _dispatching が 0 の場合に、現在のインスタンスの dispatch がすべて終わったことになる。 - * @private - * @type {number} - */ - '_dispatching' : 0, // dispatch 中の unlisten で使用 - - /** - * dispatch 中に listen が呼ばれた場合に、配列のindexがずれることを避けるため、一旦保持する。 - * _dispatching が 0 のときに _reserves を使って listen() を呼び出す。 - * @private - * @type {Object.<(number|string), Array.<(X.Callback|function)>>} - */ - '_reserves' : null, - - /** - * dispatch 中に unlisten が呼ばれた場合に、配列のindexがずれることを避けるため、一旦保持する。 - * _dispatching が 0 のときに _unlistens を使って unlisten() を呼び出す。 - * @private - * @type {Object.<(number|string), Array.<(X.Callback|function)>>} - */ - '_unlistens' : null, - - /** - * dispatch 中に kill が呼ばれた場合に、X.EventDispatcher インスタンスの削除を dispatch 後にずらすために立てるフラグ。 - * @private - * @type {boolean} - */ - '_killReserved' : false, - - /** - * asyncDispatch 中に kill が呼ばれた場合に、X.EventDispatcher インスタンスの削除を最後のタイマーの発火後にずらすために立てるフラグ。 - * TODO asyncDispatch の解除はどうする? - * @private - * @type {boolean} - */ - '_lastLazyID' : false, /** * X.EventDispatcher のコンストラクタの実体。 - * @@@constructs + * @constructs * @this {X.EventDispatcher} * @param {object=} opt_rawObject */ @@ -196,30 +180,31 @@ X.EventDispatcher = * @param {Array=} opt_arg3 */ listening : function( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ - var list = this._listeners, - unlistens, i, f, hash; + var listeners = this[ '_listeners' ], + lock = X_EventDispatcher_lock || X_EventDispatcher_unlock, + list, cbHash, unlistens, i, f; - if( opt_type === undefined ) return !!list; - if( !list || !( list = list[ opt_type ] ) ) return false; + if( opt_type === undefined ) return !!listeners; + if( !listeners || !( list = listeners[ opt_type ] ) ) return false; if( opt_arg1 === undefined ) return true; if( opt_arg1.k ){ - hash = opt_arg1; + cbHash = opt_arg1; } else { - hash = X_Callback_classifyCallbackArgs( opt_arg1, opt_arg2, opt_arg3, this ); + cbHash = X_Callback_classifyCallbackArgs( opt_arg1, opt_arg2, opt_arg3, this ); }; - if( ( unlistens = this._unlistens ) && ( unlistens = unlistens[ opt_type ] ) ){ + if( ( unlistens = listeners._unlistens ) && ( unlistens = unlistens[ opt_type ] ) ){ for( i = unlistens.length; i; ){ f = unlistens[ --i ]; - if( f === hash || ( f.x === hash.x && f.f === hash.f && f.s === hash.s ) ) return false; + if( f === cbHash || ( f.x === cbHash.x && f.f === cbHash.f && f.s === cbHash.s && f.lock === lock ) ) return false; }; }; for( i = list.length; i; ){ f = list[ --i ]; - if( f === hash || ( f.x === hash.x && f.f === hash.f && f.s === hash.s ) ){ + if( f === cbHash || ( f.x === cbHash.x && f.f === cbHash.f && f.s === cbHash.s && f.lock === lock ) ){ // index を要求された場合、lock されていない、または unlock なら index を返す - return X_EventDispatcher_needsIndex ? ( X_EventDispatcher_unlock || !f.lock ? i : false ) : true; + return X_EventDispatcher_needsIndex ? i : true; }; }; return false; @@ -233,11 +218,14 @@ X.EventDispatcher = * @return {number} X.Timer.add() の戻り値 */ asyncDispatch : function( delay, e ){ + var timerID; if( delay && e === undefined ){ e = delay; delay = 0; }; - return this[ '_lastLazyID' ] = X.Timer.add( delay, 1, this, X_EventDispatcher_dispatch, [ e ] ); + timerID = X.Timer.add( delay, 1, this, X_EventDispatcher_dispatch, [ e ] ); + X_EventDispatcher_LAZY_TIMERS[ timerID ] = this; + return timerID; } } ); @@ -253,12 +241,12 @@ X.EventDispatcher = * @param {(eventHash|string|number)} e */ function X_EventDispatcher_dispatch( e ){ - var list = this[ '_listeners' ], - ret = X_Callback_NONE, - type = e[ 'type' ], - unlistens, i, l, args, f, r, sysOnly; + var listeners = this[ '_listeners' ], + ret = X_Callback_NONE, + type = e[ 'type' ], + list, unlistens, i, l, args, f, r, sysOnly, timerID; - if( !list || !( list = list[ type || e ] ) ) return ret; + if( !listeners || !( list = listeners[ type || e ] ) ) return ret; // 数値, 文字が渡された場合 if( !type ){ @@ -267,17 +255,21 @@ function X_EventDispatcher_dispatch( e ){ e.target = e.target || this; e.currentTarget = e.currentTarget || this; - ++this._dispatching; + if( listeners._dispatching ){ + ++listeners._dispatching; + } else { + listeners._dispatching = 1; + }; // todo: // type も保存 - this._unlistens = this._unlistens || {}; - unlistens = this._unlistens[ type ]; + listeners._unlistens = listeners._unlistens || {}; + unlistens = listeners._unlistens[ type ]; for( i = 0; i < list.length; ++i ){ f = list[ i ]; if( !unlistens ){ - unlistens = this._unlistens[ type ]; + unlistens = listeners._unlistens[ type ]; }; if( unlistens && unlistens.indexOf( f ) !== -1 ) continue; @@ -292,7 +284,7 @@ function X_EventDispatcher_dispatch( e ){ if( f.once || r & X_Callback_UN_LISTEN ){ // dispatch 中に unlisten が作られることがある if( !unlistens ){ - unlistens = this._unlistens || ( this._unlistens = {} ); + unlistens = listeners._unlistens || ( listeners._unlistens = {} ); unlistens = unlistens[ type ] || ( unlistens[ type ] = [] ); }; unlistens.indexOf( f ) === -1 && ( unlistens[ unlistens.length ] = f ); @@ -304,33 +296,12 @@ function X_EventDispatcher_dispatch( e ){ ret |= X.Type.isFinite( r ) ? r : 0; }; - if( ( --this._dispatching ) === 0 ){ - - if( this[ '_lastLazyID' ] && X_Timer_currentUID === this[ '_lastLazyID' ] ){ - delete this[ '_lastLazyID' ]; - }; - - // dispatch 中に unlisten された要素の削除 - unlistens = this._unlistens; - delete this._dispatching; - delete this._unlistens; - // _unlistens に入っている callbackHash は、lock をクリアしている - X_EventDispatcher_unlock = true; - for( type in unlistens ){ - //if( X_EMPTY_OBJECT[ type ] ) continue; - list = unlistens[ type ]; - for( i = list.length; i; ){ - this.unlisten( type, list[ --i ] ); - }; - list.length = 0; - delete unlistens[ type ]; - }; - X_EventDispatcher_unlock = false; + if( ( --listeners._dispatching ) === 0 ){ + + delete listeners._dispatching; - if( this._killReserved ){ - this.kill(); - } else - if( list = this._reserves ){ + // dispatch 中に listen されたイベントの追加 + if( list = listeners._reserves ){ for( i = 0, l = list.length; i < l; ++i ){ f = list[ i ]; X_EventDispatcher_once = f[ 4 ]; @@ -341,7 +312,36 @@ function X_EventDispatcher_dispatch( e ){ f.length = 0; }; list.length = 0; - delete this._reserves; + delete listeners._reserves; + }; + + // dispatch 中に unlisten されたイベントの削除 + if( unlistens = listeners._unlistens ){ + delete listeners._unlistens; + + // _unlistens に入っている callbackHash は、lock をクリアしている + X_EventDispatcher_unlock = true; + for( type in unlistens ){ + //if( X_EMPTY_OBJECT[ type ] ) continue; + list = unlistens[ type ]; + for( i = list.length; i; ){ + this.unlisten( type, list[ --i ] ); + }; + list.length = 0; + delete unlistens[ type ]; + }; + X_EventDispatcher_unlock = false; + }; + + if( X_EventDispatcher_LAZY_TIMERS[ X_Timer_currentUID ] === this ){ + delete X_EventDispatcher_LAZY_TIMERS[ X_Timer_currentUID ]; + }; + + if( listeners._killReserved ){ + for( timerID in X_EventDispatcher_LAZY_TIMERS ){ + if( X_EventDispatcher_LAZY_TIMERS[ timerID ] === this ) return ret; + }; + this.kill(); }; }; @@ -359,14 +359,14 @@ function X_EventDispatcher_dispatch( e ){ * @return {X.EventDispatcher} */ function X_EventDispatcher_listen( type, opt_arg1, opt_arg2, opt_arg3 ){ - var list = this._listeners, - i, raw, add, f; + var listeners = this[ '_listeners' ], + i, raw, add, list, f; if( !type ) return this; - if( this._dispatching ){ - if( !this._reserves ) this._reserves = []; - this._reserves[ this._reserves.length ] = [ type, opt_arg1, opt_arg2, opt_arg3, X_EventDispatcher_once, X_EventDispatcher_lock ]; + 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 ]; return this; }; @@ -378,12 +378,12 @@ function X_EventDispatcher_listen( type, opt_arg1, opt_arg2, opt_arg3 ){ }; raw = this._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ); - add = raw && ( !list || !list[ type ] ) && X.Type.isString( type ); - + add = raw && ( !listeners || !listeners[ type ] ) && X.Type.isString( type ); + if( this.listening( type, opt_arg1 || this, opt_arg2, opt_arg3 ) ) return this; - if( !list ) list = this._listeners = {}; - if( !( list = list[ type ] ) ) list = this._listeners[ type ] = []; + if( !listeners ) listeners = this[ '_listeners' ] = {}; + list = listeners[ type ] || ( listeners[ type ] = [] ); add && X_EventDispatcher_addEvent( this, type, raw, list ); @@ -416,9 +416,9 @@ function X_EventDispatcher_systemListen( that, type, opt_arg1, opt_arg2, opt_arg * @param {Array=} opt_arg3 */ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ - var list = this._listeners, - _list, reserves, unlistens, i, f, raw, empty; - if( !list ) return this; + var listeners = this[ '_listeners' ], + list, reserves, unlistens, i, f, raw, k, empty; + if( !listeners ) return this; if( X.Type.isArray( opt_type ) ){ for( i = opt_type.length; i; ){ @@ -432,11 +432,12 @@ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ if( opt_type === undefined ){ // 全て削除 - for( opt_type in list ){ + for( opt_type in listeners ){ //if( X_EMPTY_OBJECT[ opt_type ] ) continue; - _list = list[ opt_type ]; - for( i = _list.length; i; ){ - this.unlisten( opt_type, _list[ --i ] ); // override されていることがあるので、必ず unlisten を使用 + if( opt_type.charAt( 0 ) === '_' ) continue; + list = listeners[ opt_type ]; + for( i = list.length; i; ){ + this.unlisten( opt_type, list[ --i ] ); // override されていることがあるので、必ず unlisten を使用 }; // this.unlisten( opt_type ); これは無茶! }; @@ -444,19 +445,19 @@ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ } else if( opt_arg1 === undefined ){ // 同一タイプを全て削除 - if( _list = list[ opt_type ] ){ - for( i = _list.length; i; ){ - this.unlisten( opt_type, _list[ --i ] ); // override されていることがあるので、必ず unlisten を使用 + if( list = listeners[ opt_type ] ){ + for( i = list.length; i; ){ + this.unlisten( opt_type, list[ --i ] ); // override されていることがあるので、必ず unlisten を使用 }; }; return this; } else - if( reserves = this._reserves ){ + if( reserves = 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 ){ + 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 this._reserves; + if( !reserves.legth ) delete listeners._reserves; return this; }; }; @@ -467,22 +468,31 @@ function X_EventDispatcher_unlisten( opt_type, opt_arg1, opt_arg2, opt_arg3 ){ X_EventDispatcher_needsIndex = false; if( i === false ) return this; - f = ( _list = list[ opt_type ] )[ i ]; - // _unlistens に入っている callbackHash は、lock をクリアしている - if( unlistens = this._unlistens ){ + f = ( list = listeners[ opt_type ] )[ i ]; + + if( unlistens = listeners._unlistens ){ + // _unlistens に入っている callbackHash は、lock のチェックは済んでいる ( unlistens = unlistens[ opt_type ] ) ? ( unlistens[ unlistens.length ] = f ) : - ( this._unlistens[ opt_type ] = [ f ] ); + ( listeners._unlistens[ opt_type ] = [ f ] ); } else { delete f.once; - _list.splice( i, 1 ); - if( !_list.length ){ + list.splice( i, 1 ); + if( !list.length ){ raw = this._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ); - delete list[ opt_type ]; - if( empty = X_Object_isEmpty( list ) ) delete this._listeners; + delete listeners[ opt_type ]; + //empty = X_Object_isEmpty( listeners ); + // TODO カウンター + empty = true; + for( k in listeners ){ + if( k.charAt( 0 ) === '_' ) continue; + empty = false; + break; + }; if( raw && '' + parseFloat( opt_type ) !== '' + opt_type ){ // 数字イベントの除外 - X_EventDispatcher_removeEvent( this, opt_type, raw, _list, !empty ); + X_EventDispatcher_removeEvent( this, opt_type, raw, list, !empty ); }; + if( empty ) delete this[ '_listeners' ]; }; }; return this; @@ -515,66 +525,84 @@ var X_EventDispatcher_actualAddEvent = // Days on the Moon DOM Events とブラウザの実装 // http://nanto.asablo.jp/blog/2007/03/23/1339502 // Safari 2 では関数オブジェクトしか EventListener として使えませんが、Safari のナイトリービルドでは handleEvent メソッドを持つオブジェクトも EventListener として使えるようです。 - X_UA_EVENT.W3C /* && ( X_UA.WebKit < 525.13 || X_UA.Opera7 || X_UA.NetFront < 4 ) */ ? // Safari3- + X_UA_EVENT.W3C ? (function( that, type, raw, list ){ - if( that._isXHR && X_UA.Opera < 12 ){ - // Opera11- の XHR は event オブジェクトが返らないため, eventType 毎に callback を指定する addEventListener もない - raw[ 'on' + type ] = X_Callback_create( that, X_EventDispatcher_dispatch, [ type ] ); - } else - if( that._isSilverlight ){ - list.slcallback = X_Callback_create( that, X_EventDispatcher_sliverLightDispatch, [ type ] ); - list.sltoken = raw.AddEventListener( type, list.slcallback ); - } else - // iOS と MacOSX Iron36 で発生。連続してアニメーションが起こると、クロージャの束縛された obj へのアクセスに失敗する。Win では起きない? - // むしろ、MacOSX のブラウザ全般で起こる?? - if( ( X_UA.WebKit || X_UA.Blink ) && - ( type === 'webkitTransitionEnd' || type === 'transitionend' || - type === 'animationend' || type === 'webkitAnimationEnd' || - type === 'animationstart' || type === 'webkitAnimationStart' || - type === 'animationiteration' || type === 'webkitAnimationIteration' ) ){ - raw.addEventListener( type, X_EventDispatcher_iOSTransitionEndDispatch, false ); - } else { - console.log( 'event > ' + type ); - that._handleEvent || ( that._handleEvent = X_Callback_create( that, X_EventDispatcher_actualHandleEvent ) ); + var f; + switch( that[ '_rawType' ] ){ + case X_EventDispatcher_EVENT_TARGET_TYPE.SILVER_LIGHT : + list.slcallback = X_Callback_create( that, X_EventDispatcher_sliverLightDispatch, [ type ] ); + list.sltoken = raw.AddEventListener( type, list.slcallback ); + break; + + case X_EventDispatcher_EVENT_TARGET_TYPE.XHR : + if( X_UA.Opera < 12 ){ + // Opera11- の XHR は event オブジェクトが返らないため, eventType 毎に callback を指定する addEventListener もない + raw[ 'on' + type ] = X_Callback_create( that, X_EventDispatcher_dispatch, [ type ] ); + break; + }; - if( raw.addEventListener ){ - raw.addEventListener( type, that._handleEvent, false ); - } else { - // Safari は Image, Opera7 は window - raw[ 'on' + type ] = that._handleEvent; - }; + default : + // iOS と MacOSX Iron36 で発生。連続してアニメーションが起こると、クロージャの束縛された obj へのアクセスに失敗する。Win では起きない? + // むしろ、MacOSX のブラウザ全般で起こる?? + if( ( X_UA.WebKit || X_UA.Blink ) && + ( type === 'webkitTransitionEnd' || type === 'transitionend' || + type === 'animationend' || type === 'webkitAnimationEnd' || + type === 'animationstart' || type === 'webkitAnimationStart' || + 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 ) ); + + if( raw.addEventListener ){ + raw.addEventListener( type, f, false ); + } else { + // Safari は Image, Opera7 は window + raw[ 'on' + type ] = f; + }; + }; }; }) : X_UA_EVENT.IE ? (function( that, type, raw, list ){ - if( that._isXHR ){ - // ie8- の XHR は window.event が更新されないため, eventType 毎に callback を指定する - raw[ 'on' + type ] = X_Callback_create( that, X_EventDispatcher_dispatch, [ type ] ); - } else - if( that._isSilverlight ){ - list.slcallback = X_Callback_create( that, X_EventDispatcher_sliverLightDispatch, [ type ] ); - list.sltoken = raw.AddEventListener( type, list.slcallback ); - } else { - that._handleEvent || ( that._handleEvent = X_Callback_create( that, X_EventDispatcher_actualHandleEvent ) ); + var f; + switch( that[ '_rawType' ] ){ + case X_EventDispatcher_EVENT_TARGET_TYPE.SILVER_LIGHT : + list.slcallback = X_Callback_create( that, X_EventDispatcher_sliverLightDispatch, [ type ] ); + list.sltoken = raw.AddEventListener( type, list.slcallback ); + break; - if( raw.attachEvent ){ - raw.attachEvent( 'on' + type, that._handleEvent ); - } else { - raw[ 'on' + type ] = that._handleEvent; - }; + case X_EventDispatcher_EVENT_TARGET_TYPE.XHR : + // ie8- の XHR は window.event が更新されないため, eventType 毎に callback を指定する + raw[ 'on' + type ] = X_Callback_create( that, X_EventDispatcher_dispatch, [ type ] ); + break; + + default : + f = that[ '_listeners' ]._handleEvent || ( that[ '_listeners' ]._handleEvent = X_Callback_create( that, X_EventDispatcher_actualHandleEvent ) ); + + if( raw.attachEvent ){ + raw.attachEvent( 'on' + type, f ); + } else { + raw[ 'on' + type ] = f; + }; + break; }; }) : (function( that, type, raw, list ){ - if( that._isXHR ){ - // ie4 mobile は XHR をサポート! - raw[ 'on' + type ] = X_Callback_create( that, X_EventDispatcher_dispatch, [ type ] ); - } else - if( that._isSilverlight ){ - // DOM0 で Silverlight ってあるの? - list.slcallback = X_Callback_create( that, X_EventDispatcher_sliverLightDispatch, [ type ] ); - list.sltoken = raw.AddEventListener( type, list.slcallback ); - } else { - raw[ 'on' + type ] = that._handleEvent || ( that._handleEvent = X_Callback_create( that, X_EventDispatcher_actualHandleEvent ) ); + switch( that[ '_rawType' ] ){ + case X_EventDispatcher_EVENT_TARGET_TYPE.SILVER_LIGHT : + // DOM0 で Silverlight ってあるの -> ie4 mobile? + list.slcallback = X_Callback_create( that, X_EventDispatcher_sliverLightDispatch, [ type ] ); + list.sltoken = raw.AddEventListener( type, list.slcallback ); + break; + + case X_EventDispatcher_EVENT_TARGET_TYPE.XHR : + // ie4 mobile は XHR をサポート! + raw[ 'on' + type ] = X_Callback_create( that, X_EventDispatcher_dispatch, [ type ] ); + break; + + default : + raw[ 'on' + type ] = that[ '_listeners' ]._handleEvent || ( that[ '_listeners' ]._handleEvent = X_Callback_create( that, X_EventDispatcher_actualHandleEvent ) ); + break; }; }); @@ -610,82 +638,97 @@ function X_EventDispatcher_removeEvent( that, type, raw, list, skip ){ }; var X_EventDispatcher_actualRemoveEvent = - X_UA_EVENT.W3C /*&& ( X_UA.WebKit < 525.13 || X_UA.Opera7 || X_UA.NetFront < 4 )*/ ? // Safari3- + X_UA_EVENT.W3C ? (function( that, type, raw, list, skip ){ - if( that._isXHR && X_UA.Opera < 12 ){ - X_Callback_correct( raw[ 'on' + type ] ); - raw[ 'on' + type ] = ''; - } else - if( that._isSilverlight ){ - raw.RemoveEventListener( type, list.sltoken ); // token - X_Callback_correct( list.slcallback ); - delete list.sltoken; - delete list.slcallback; - } else - if( ( X_UA.WebKit || X_UA.Blink ) && - ( type === 'webkitTransitionEnd' || type === 'transitionend' || - type === 'animationend' || type === 'webkitAnimationEnd' || - type === 'animationstart' || type === 'webkitAnimationStart' || - type === 'animationiteration' || type === 'webkitAnimationIteration' ) ){ - raw.removeEventListener( type, X_EventDispatcher_iOSTransitionEndDispatch, false ); - } else { - - if( raw.addEventListener ){ - raw.removeEventListener( type, that._handleEvent, false ); - } else { - raw[ 'on' + type ] = null; - }; - if( !skip ){ - X_Callback_correct( that._handleEvent ); - delete that._handleEvent; - }; + switch( that[ '_rawType' ] ){ + case X_EventDispatcher_EVENT_TARGET_TYPE.SILVER_LIGHT : + raw.RemoveEventListener( type, list.sltoken ); // token + X_Callback_correct( list.slcallback ); + delete list.sltoken; + delete list.slcallback; + break; + + case X_EventDispatcher_EVENT_TARGET_TYPE.XHR : + if( X_UA.Opera < 12 ){ + // Opera11- の XHR は event オブジェクトが返らないため, eventType 毎に callback を指定する addEventListener もない + X_Callback_correct( raw[ 'on' + type ] ); + raw[ 'on' + type ] = ''; + break; + }; + + default : + if( ( X_UA.WebKit || X_UA.Blink ) && + ( type === 'webkitTransitionEnd' || type === 'transitionend' || + type === 'animationend' || type === 'webkitAnimationEnd' || + type === 'animationstart' || type === 'webkitAnimationStart' || + type === 'animationiteration' || type === 'webkitAnimationIteration' ) ){ + raw.removeEventListener( type, X_EventDispatcher_iOSTransitionEndDispatch, false ); + } else + if( raw.addEventListener ){ + raw.removeEventListener( type, that[ '_listeners' ]._handleEvent, false ); + } else { + raw[ 'on' + type ] = null; + }; + + if( !skip && that[ '_listeners' ]._handleEvent ){ + X_Callback_correct( that[ '_listeners' ]._handleEvent ); + delete that[ '_listeners' ]._handleEvent; + }; }; }) : X_UA_EVENT.IE ? (function( that, type, raw, list, skip ){ - if( that._isXHR ){ - X_Callback_correct( raw[ 'on' + type ] ); - raw[ 'on' + type ] = X.emptyFunction; - raw[ 'on' + type ] = ''; - } else - if( that._isSilverlight ){ - raw.RemoveEventListener( type, list.sltoken ); // token - X_Callback_correct( list.slcallback ); - delete list.sltoken; - delete list.slcallback; - } else { - if( raw.attachEvent ){ - raw.detachEvent( 'on' + type, that._handleEvent ); - } else { + switch( that[ '_rawType' ] ){ + case X_EventDispatcher_EVENT_TARGET_TYPE.SILVER_LIGHT : + raw.RemoveEventListener( type, list.sltoken ); // token + X_Callback_correct( list.slcallback ); + delete list.sltoken; + delete list.slcallback; + break; + + case X_EventDispatcher_EVENT_TARGET_TYPE.XHR : + X_Callback_correct( raw[ 'on' + type ] ); raw[ 'on' + type ] = X.emptyFunction; raw[ 'on' + type ] = ''; - }; - - if( !skip ){ - X_Callback_correct( that._handleEvent ); - delete that._handleEvent; - }; + break; + + default : + if( raw.attachEvent ){ + raw.detachEvent( 'on' + type, that[ '_listeners' ]._handleEvent ); + } else { + raw[ 'on' + type ] = X.emptyFunction; + raw[ 'on' + type ] = ''; + }; + + if( !skip ){ + X_Callback_correct( that[ '_listeners' ]._handleEvent ); + delete that[ '_listeners' ]._handleEvent; + }; }; }) : (function( that, type, raw, list, skip ){ - if( that._isXHR ){ - X_Callback_correct( raw[ 'on' + type ] ); - raw[ 'on' + type ] = X.emptyFunction; - raw[ 'on' + type ] = ''; - } else - if( that._isSilverlight ){ - raw.RemoveEventListener( type, list.sltoken ); // token - X_Callback_correct( list.slcallback ); - delete list.sltoken; - delete list.slcallback; - } else { - raw[ 'on' + type ] = X.emptyFunction; - raw[ 'on' + type ] = ''; + switch( that[ '_rawType' ] ){ + case X_EventDispatcher_EVENT_TARGET_TYPE.SILVER_LIGHT : + raw.RemoveEventListener( type, list.sltoken ); // token + X_Callback_correct( list.slcallback ); + delete list.sltoken; + delete list.slcallback; + break; - if( !skip ){ - X_Callback_correct( that._handleEvent ); - delete that._handleEvent; - }; + case X_EventDispatcher_EVENT_TARGET_TYPE.XHR : + X_Callback_correct( raw[ 'on' + type ] ); + raw[ 'on' + type ] = X.emptyFunction; + raw[ 'on' + type ] = ''; + break; + + default : + raw[ 'on' + type ] = X.emptyFunction; + raw[ 'on' + type ] = ''; + + if( !skip ){ + X_Callback_correct( that[ '_listeners' ]._handleEvent ); + delete that[ '_listeners' ]._handleEvent; + }; }; }); @@ -762,13 +805,14 @@ if( X_UA.WebKit < 525.13 ){ // Safari3- // イベントの退避、dom が画面から抜かれる場合に実施しておく // 退避したイベントの復帰 function X_EventDispatcher_toggleAllEvents( that, add ){ - var list = that._listeners, + var list = that[ '_listeners' ], raw = that._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( that ), f = 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( '' + parseFloat( type ) !== type ){ // TODO type rename はここ diff --git a/0.6.x/js/01_core/14_XTimer.js b/0.6.x/js/01_core/14_XTimer.js index 9dbfe40..2954501 100644 --- a/0.6.x/js/01_core/14_XTimer.js +++ b/0.6.x/js/01_core/14_XTimer.js @@ -114,7 +114,7 @@ X.Timer = { var list = X_Timer_TICKET_LIST, i = list.length, l = i, - f, q; + f, q, eventDispatcher, lazy, listeners; // fire 中の cancel if( X_Timer_busyTimeout ){ if( !X_Timer_removal ) X_Timer_removal = {}; @@ -123,6 +123,26 @@ X.Timer = { for( ; i; ){ if( ( q = list[ --i ] ).uid === uid ){ list.splice( i, 1 ); + + /* + * lazyDispatch 中の EventDispatcher の有無を調べる + */ + 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 ){ + for( uid in X_EventDispatcher_LAZY_TIMERS ){ + if( X_EventDispatcher_LAZY_TIMERS[ uid ] === eventDispatcher ){ + lazy = true; + break; + }; + }; + !lazy && eventDispatcher.kill(); + }; + }; + !X_Timer_skipUpdate && ( q.last <= X_Timer_waitTime || l === 1 ) && X_Timer_update(); break; }; diff --git a/0.6.x/js/02_dom/02_XNode.js b/0.6.x/js/02_dom/02_XNode.js index 26060f5..cbfcdf6 100644 --- a/0.6.x/js/02_dom/02_XNode.js +++ b/0.6.x/js/02_dom/02_XNode.js @@ -9,7 +9,7 @@ var STYLE_IS_INVISIBLE : 2 << 2, // visibility : hidden or opacity : 0 STYLE_IS_POS_ABSOLUTE : 2 << 3, // position : absolute STYLE_IS_NO_OVERFLOW : 2 << 4, // overflow : hidden - STYLE_IS_WIDTH_LENGTH : 2 << 5, // width : width() のための commitUpdate が不要 + STYLE_IS_WIDTH_LENGTH : 2 << 5, // width : overflow:hidden,要素無し、または要素が非表示なら、 width() のための commitUpdate が不要 STYLE_IS_WIDTH_PCT : 2 << 6, // width : width() のための commitUpdate が不要かもしれない。(親で LENGTH が指定されているなら) STYLE_IS_HEIGHT_LENGTH : 2 << 7, // height : STYLE_IS_HEIGHT_PCT : 2 << 8, // height : @@ -18,34 +18,33 @@ var DIRTY_POSITION : 2 << 11, // 要素位置の変更が起こった。 DIRTY_CONTENT : 2 << 12, // width, height, x, y textNode の内容 TODO html と排他なので ID と共通でいい - DIRTY_ID : 2 << 13, // width, height, x, y - DIRTY_CLASSNAME : 2 << 14, // X_Node_CSS_getCharSize, width, height, x, y - DIRTY_ATTR : 2 << 15, // X_Node_CSS_getCharSize, width, height, x, y - DIRTY_CSS : 2 << 16, // X_Node_CSS_getCharSize, width, height, x, y - DIRTY_IE_FILTER : X_UA.IE < 10 && X_UA.ActiveX ? 2 << 17 : 0, // + DIRTY_ID : 2 << 12, // width, height, x, y + DIRTY_CLASSNAME : 2 << 13, // X_Node_CSS_getCharSize, width, height, x, y + DIRTY_ATTR : 2 << 14, // X_Node_CSS_getCharSize, width, height, x, y + DIRTY_CSS : 2 << 15, // X_Node_CSS_getCharSize, width, height, x, y + DIRTY_IE_FILTER : X_UA.IE < 10 && X_UA.ActiveX ? 2 << 16 : 0, // - - ELM_NEED_INIT : 2 << 18, - OLD_ATTRTEXT : 2 << 19, - OLD_CSSTEXT : 2 << 20, + ACTUAL_LISTENING : 2 << 17, + OLD_ATTRTEXT : 2 << 18, + OLD_CSSTEXT : 2 << 19, // filter 要素が親子になると不具合が出るのを検出 - IE_FILTER_NOW : 2 << 21, + IE_FILTER_NOW : 2 << 20, //GPU_WAITING : 2 << 20, // 1:子のGPU解除待 - GPU_RESERVED : 2 << 22, // 2:GPU予約 - GPU_NOW : 2 << 23, // 3:GPU now! - GPU_RELEASE_RESERVED : 2 << 24, // 4:GPU解除予約 + GPU_RESERVED : 2 << 21, // 2:GPU予約 + GPU_NOW : 2 << 22, // 3:GPU now! + GPU_RELEASE_RESERVED : 2 << 23, // 4:GPU解除予約 - IE4_HAS_TEXTNODE : X_UA.IE4 ? 2 << 22 : 0, - IE4_HAS_ELEMENT : X_UA.IE4 ? 2 << 23 : 0, - IE4_DIRTY_CHILDREN : X_UA.IE4 ? 2 << 24 : 0, - IE4_FIXED : X_UA.IE4 ? 2 << 25 : 0, + IE4_HAS_TEXTNODE : X_UA.IE4 ? 2 << 21 : 0, + IE4_HAS_ELEMENT : X_UA.IE4 ? 2 << 22 : 0, + IE4_DIRTY_CHILDREN : X_UA.IE4 ? 2 << 23 : 0, + IE4_FIXED : X_UA.IE4 ? 2 << 24 : 0, - IE5_DISPLAY_NONE_FIX : X_UA.IE5 && X_UA.ActiveX ? 2 << 25 : 0 + IE5_DISPLAY_NONE_FIX : X_UA.IE5 && X_UA.ActiveX ? 2 << 24 : 0 }, - X_Node_BITMASK_RESET_STYLE = ( ( 2 << 29 ) - 1 + ( 2 << 29 ) ) ^ ( + X_Node_BITMASK_RESET_STYLE = ( ( 2 << 29 ) - 1 + ( 2 << 29 ) ) ^ ( X_Node_State.STYLE_IS_DISPLAY_NONE | X_Node_State.STYLE_IS_INVISIBLE | X_Node_State.STYLE_IS_POS_ABSOLUTE | @@ -57,15 +56,15 @@ var X_Node_State.STYLE_IS_FONT_LENGTH | X_Node_State.STYLE_IS_FONT_PCT ), - X_Node_BitMask_IS_DIRTY = X_Node_State.DIRTY_POSITION | + X_Node_BitMask_IS_DIRTY = X_Node_State.DIRTY_POSITION | X_Node_State.DIRTY_CONTENT | X_Node_State.DIRTY_ID | X_Node_State.DIRTY_CLASSNAME | X_Node_State.DIRTY_ATTR | X_Node_State.DIRTY_CSS | X_Node_State.DIRTY_IE_FILTER, - X_Node_BitMask_RESET_DIRTY = ( ( 2 << 29 ) - 1 + ( 2 << 29 ) ) ^ X_Node_BitMask_IS_DIRTY, + X_Node_BitMask_RESET_DIRTY = ( ( 2 << 29 ) - 1 + ( 2 << 29 ) ) ^ X_Node_BitMask_IS_DIRTY, - X_Node_BitMask_RESET_GPU = ( ( 2 << 29 ) - 1 + ( 2 << 29 ) ) ^ ( X_Node_State.GPU_RESERVED | X_Node_State.GPU_NOW | X_Node_State.GPU_RELEASE_RESERVED ), + X_Node_BitMask_RESET_GPU = ( ( 2 << 29 ) - 1 + ( 2 << 29 ) ) ^ ( X_Node_State.GPU_RESERVED | X_Node_State.GPU_NOW | X_Node_State.GPU_RELEASE_RESERVED ), - X_Node_BitMask_IE4_IS_MIX = X_Node_State.IE4_HAS_TEXTNODE | X_Node_State.IE4_HAS_ELEMENT, + X_Node_BitMask_IE4_IS_MIX = X_Node_State.IE4_HAS_TEXTNODE | X_Node_State.IE4_HAS_ELEMENT, X_Node_TYPE = { XNODE : 1, @@ -106,7 +105,7 @@ var _uid : 0, _flags : X_Node_State.DESTROYED, - _rawObject : null, + // _rawObject : null, _rect : null, // _fontSize : 0, @@ -224,7 +223,7 @@ var appendTo : X_Node_appendTo, - appendToRoot : X_Node_appendToRoot, + appendToRoot : X_Node_appendToRoot, // remove before : X_Node_before, // remove @@ -676,27 +675,29 @@ function X_Node_destroy( isChild ){ }; function X_Node_onBeforeKill( e ){ - var xnodes = this._xnodes, - elm = this._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ), - i; - - if( !this._flags ) return; + var xnodes = this._xnodes, i, elm; - delete X_Node_CHASHE[ this._uid ]; + if( !this._flags ) return X.Callback.NONE; + elm = this._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ); + elm && this._listeners && this.unlisten(); // イベントの退避 + if( xnodes && ( i = xnodes.length ) ){ for( ; i; ){ X_Node_onBeforeKill.call( xnodes[ --i ] ); }; }; - e && this.remove(); - elm && this._listeners && this.unlisten(); // イベントの退避 - - if( e && elm && elm.parentNode && elm.parentNode.tagName ){ - delete this._flags; - return X.Callback.PREVENT_DEFAULT; + delete X_Node_CHASHE[ this._uid ]; + + if( e ){ + this.remove(); + if( X_Node_reserveRemoval[ X_Node_reserveRemoval.length - 1 ] === this ){ + delete this._flags; + return X.Callback.PREVENT_DEFAULT; + }; }; + return X.Callback.NONE; }; @@ -1039,6 +1040,7 @@ function X_Node_startUpdate( time ){ if( i = removal.length ){ for( ; i; ){ xnode = removal[ --i ]; + // TODO GPU レイヤーの子の場合、remove をスキップする。 非GPU レイヤーへ apppend される場合、clone する? X_Node__actualRemove( xnode ); !xnode._flags && xnode.kill(); }; @@ -1066,8 +1068,8 @@ function X_Node_startUpdate( time ){ }; /* - * 1. GPU_NOW の場合、これ以下の一切の更新を行わない - * 2. GPU解放予約 の場合、この要素のみ変更を行う。rAF 後にさらに更新するためフラグを立てる。 + * 1. GPU_NOW の場合、子の変更は行わない + * 2. GPU解放予約 の場合//、この要素のみ変更を行う。rAF 後にさらに更新するためフラグを立てる。 * 3. GPU予約 -> GPU * 4. style="display:none" の場合、これ以下の変更を行わない。 * 5. ie5 非表示フラグが立っていて、親と自身の class・id によって非表示になっていて、親と自身に変更がない。accumulatedFlags を使用。 @@ -1118,7 +1120,7 @@ var X_Node__commitUpdate = return nextElement; }; elm && ( elm.style.display = 'none' ); - return elm.nextSibling === nextElement ? elm : nextElement; + return ( elm && elm.nextSibling === nextElement ) ? elm : nextElement; }; // 5. ie5 非表示fixフラグ @@ -1140,7 +1142,7 @@ var X_Node__commitUpdate = }; } else if( X_Node_strictElmCreation ){ - that._flags & X_Node_State.DIRTY_CSS && X_Node_CSS_objToCssText( that, true ); + that._flags & X_Node_State.OLD_CSSTEXT && X_Node_CSS_objToCssText( that, true ); // OLD_CSSTEXT ?? that._rawObject = elm = document.createElement( [ @@ -1148,9 +1150,9 @@ var X_Node__commitUpdate = ' UID="', that._uid, '"', that._id ? ' id="' + that._id + '"' : '', that._className ? ' class="' + that._className + '"' : '', - that._flags & X_Node_State.OLD_ATTRTEXT ? X_Node_Attr_objToAttrText( that ) : that._attrText, + X_Node_Attr_objToAttrText( that, true ), that._cssText ? ' style="' + that._cssText + '"' : '', - '>' ].join( '' ) ); + '>' ].join( '' ) ); } else { that._rawObject = elm = document.createElement( that._tag ); }; @@ -1163,18 +1165,17 @@ var X_Node__commitUpdate = }; if( that._tag ){ - // src の onload があるので先ではないか? - // TODO ie の str から要素を作る場合、srcだけ イベント設定後ではないか? X_EventDispatcher_toggleAllEvents( that, true );// イベントの復帰 + that._flags |= X_Node_State.ACTUAL_LISTENING; if( X_Node_documentFragment ){ //( frg = X_Node_documentFragment ).appendChild( elm ); }; if( X_Node_strictElmCreation ){ - // TODO src 等の設定 - delete that._newAttrs; that._flags &= X_Node_BitMask_RESET_DIRTY; + // ie の string から要素を作る場合、ネットワーク系属性は onload イベントなどを拾うために、要素生成->イベント復帰後に適用する + that._newAttrs && ( that._flags |= X_Node_State.DIRTY_ATTR ); // Network 系の属性は遅らせて設定 that._flags |= X_Node_State.DIRTY_IE_FILTER;// doc 追加後に filter を指定しないと有効にならない。 } else { elm.UID = that._uid; @@ -1185,7 +1186,7 @@ var X_Node__commitUpdate = // http://outcloud.blogspot.jp/2010/09/iframe.html // この問題は firefox3.6 で確認 if( X_UA.Gecko ){ - if( that._tag === 'IFRAME' && !that._attrs[ 'src' ] ){ + if( that._tag === 'IFRAME' && ( !that._attrs || !that._attrs[ 'src' ] ) ){ //elm.contentWindow.location.replace = elm.src = 'about:blank'; that.attr( 'src', 'about:blank' ); }; @@ -1200,19 +1201,19 @@ var X_Node__commitUpdate = nextElement ? parentElement.insertBefore( elm, nextElement ) : parentElement.appendChild( elm ); - - if( X_Node_displayNoneFixForIE5 ) that._flags |= X_Node_State.DIRTY_POSITION; }; - that._flags & X_Node_State.DIRTY_POSITION && X_EventDispatcher_toggleAllEvents( that, true );// イベントの復帰 - that._flags &= ~X_Node_State.DIRTY_POSITION; + if( that._listeners && ( that._flags & X_Node_State.ACTUAL_LISTENING ) === 0 ){ + X_EventDispatcher_toggleAllEvents( that, true );// イベントの退避 + that._flags |= X_Node_State.ACTUAL_LISTENING; + }; // 8. 更新の適用 - if( accumulatedFlags & X_Node_BitMask_IS_DIRTY ) delete that._fontSize; - - that._flags & X_Node_BitMask_IS_DIRTY && X_Node__updateRawNode( that, elm ); - - + if( accumulatedFlags & X_Node_BitMask_IS_DIRTY ){ + delete that._fontSize; + X_Node__updateRawNode( that, elm ); + }; + // 9. ie5 only // 親及び自身へのクラス・id指定で display : none になるケースがありそれを検出 // 生成と破棄が繰り返されてしまう、親と自身の id, class が変わった場合だけ再生成。 accumulatedFlags & ( ID | CLASSNAME ) @@ -1266,7 +1267,7 @@ var X_Node__commitUpdate = return prevElement; }; }; - return elm || nextElement; + return elm || prevElement; }; if( !elm ){ @@ -1341,7 +1342,6 @@ var X_Node__commitUpdate = (function(){}); /* - * TODO IE5 は filter-fix があるため、親から変更を適用し、自信の display:none を調べる * GPU レイヤーするブラウザは、子要素から変更を当てていく? <- とりあえず、親要素から。 */ var X_Node__updateRawNode = @@ -1416,7 +1416,6 @@ var X_Node__updateRawNode = } else { elm.style.cssText = ''; // IE5.5以下 Safari3.2 で必要 elm.removeAttribute( 'style' ); - delete that._cssText; }; } else if( that._flags & X_Node_State.DIRTY_IE_FILTER ){ @@ -1461,7 +1460,6 @@ var X_Node__updateRawNode = } else { elm.style.cssText = ''; elm.removeAttribute( 'style' ); - delete that._cssText; }; } else if( that._flags & X_Node_State.DIRTY_IE_FILTER ){ @@ -1519,12 +1517,12 @@ var X_Node__actualCreate = } else { if( !isChild ) X_Node__actualRemove( that, /* true */ false ); - that._flags & X_Node_State.DIRTY_CSS && X_Node_CSS_objToCssText( that, true ); + that._flags & X_Node_State.OLD_CSSTEXT && X_Node_CSS_objToCssText( that, true ); html = [ '<', that._tag, ' id=', ( that._id || ( 'ie4uid' + uid ) ), ' UID="', uid, '"', that._className ? ' class="' + that._className + '"' : '', - that._flags & X_Node_State.OLD_ATTRTEXT ? X_Node_Attr_objToAttrText( that ) : that._attrText, + X_Node_Attr_objToAttrText( that, true ), that._cssText ? ' style="' + that._cssText + '"' : '', '>' ]; @@ -1557,7 +1555,7 @@ var X_Node__actualCreate = }; X_Dom_DTD_EMPTY[ that._tag ] || ( html[ n ] = '<\/' + that._tag + '>' ); - delete that._newAttrs; + that._newAttrs && ( that._flags |= X_Node_State.DIRTY_ATTR ); }; return html.join( '' ); @@ -1574,8 +1572,12 @@ var X_Node__afterActualCreate = X_Node__afterActualCreate( xnodes[ --i ] ); }; }; - that._flags & X_Node_State.DIRTY_IE_FILTER && X_Node__updateRawNode( that, that._rawObject || X_Node__ie4getRawNode( that ) ); - that._flags &= X_Node_BitMask_RESET_DIRTY; + // ネットわーう系属性と 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 { + that._flags &= X_Node_BitMask_RESET_DIRTY; + }; X_EventDispatcher_toggleAllEvents( that, true );// イベントの復帰 }); @@ -1597,7 +1599,10 @@ var X_Node__actualRemove = if( !elm ) return; - that._listeners && X_EventDispatcher_toggleAllEvents( that, false );// イベントの退避 + if( that._flags & X_Node_State.ACTUAL_LISTENING ){ + that._listeners && X_EventDispatcher_toggleAllEvents( that, false );// イベントの退避 + that._flags &= ~X_Node_State.ACTUAL_LISTENING; + }; // ie5では filter の効いている要素をremove時に破棄して、再度append 時に新規生成する // ちなみに elm.filters に触ると ie8 でなぜかカラム落ちが発生、、、 @@ -1606,10 +1611,23 @@ var X_Node__actualRemove = //elm.style.removeAttribute( 'filter' ); isChild = false; delete that._rawObject; - // 破棄前に value を控える TODO checked, selected も! + // 破棄前にインタラクティブな属性値を控える if( X_Node_Attr_HAS_VALUE[ that._tag ] && ( !that._newAttrs || !X_Object_inObject( 'value', that._newAttrs ) ) ){ + if( !that._attrs ) that._attrs = {}; that._attrs.value = elm.value; }; + if( that._tag === 'OPTION' && ( !that._newAttrs || !X_Object_inObject( 'selected', that._newAttrs ) ) ){ + if( !that._attrs ) that._attrs = {}; + that._attrs.selected = elm.selected; + }; + if( that._tag === 'SELECT' && ( !that._newAttrs || !X_Object_inObject( 'selectedIndex', that._newAttrs ) ) ){ + if( !that._attrs ) that._attrs = {}; + that._attrs.selectedIndex = elm.selectedIndex; + }; + if( that._tag === 'INPUT' && that._attr && ( that._attr.type === 'checkbox' || that._attr.type === 'radio' ) && ( !that._newAttrs || !X_Object_inObject( 'checked', that._newAttrs ) ) ){ + that._attrs.checked = elm.checked; + }; + // 子要素への参照を外す elm.innerHTML = ''; }; }; @@ -1635,10 +1653,24 @@ var X_Node__actualRemove = if( !elm ) return; that._listeners && X_EventDispatcher_toggleAllEvents( that, false );// イベントの退避 - // 破棄前に value を控える TODO checked, selected も! + // 破棄前にインタラクティブな属性値を控える if( X_Node_Attr_HAS_VALUE[ that._tag ] && ( !that._newAttrs || !X_Object_inObject( 'value', that._newAttrs ) ) ){ + if( !that._attrs ) that._attrs = {}; that._attrs.value = elm.value; }; + if( that._tag === 'OPTION' && ( !that._newAttrs || !X_Object_inObject( 'selected', that._newAttrs ) ) ){ + if( !that._attrs ) that._attrs = {}; + that._attrs.selected = elm.selected; + }; + if( that._tag === 'SELECT' && ( !that._newAttrs || !X_Object_inObject( 'selectedIndex', that._newAttrs ) ) ){ + if( !that._attrs ) that._attrs = {}; + that._attrs.selectedIndex = elm.selectedIndex; + }; + if( that._tag === 'INPUT' && that._attr && ( that._attr.type === 'checkbox' || that._attr.type === 'radio' ) && ( !that._newAttrs || !X_Object_inObject( 'checked', that._newAttrs ) ) ){ + if( !that._attrs ) that._attrs = {}; + that._attrs.checked = elm.checked; + }; + elm.removeAttribute( 'id' ); // ? //document.all[ that._id || ( 'ie4uid' + that._uid ) ] = null; // MacIE5 でエラー if( !isChild ) elm.outerHTML = ''; diff --git a/0.6.x/js/02_dom/05_XNodeAttr.js b/0.6.x/js/02_dom/05_XNodeAttr.js index cd9a1ff..cd04236 100644 --- a/0.6.x/js/02_dom/05_XNodeAttr.js +++ b/0.6.x/js/02_dom/05_XNodeAttr.js @@ -61,57 +61,77 @@ X_Node_Attr_STATIC_VALUE_TYPES = { checkbox : true }, +// 自由な内容が入るため、参照文字への変換が必要 +X_Node_Attr_toChrReferance = { + value : true, + title : true, + alt : true +}, + X_Node_Attr_renameForTag = {}; // http://nanto.asablo.jp/blog/2005/10/29/123294 // checked -> defaultChecked // 動的に生成した input 要素を文書ツリーに挿入する前に設定した checked 属性は反映されず、defaultChecked だと反映される // ロードイベントを拾うために、要素生成時にネットワーク関連の属性を設定しない。 // -> src (img, iframe, ), link の href, -function X_Node_Attr_objToAttrText( that, skipNetwork, escape ){ // TODO value の escape " -> " + // +function X_Node_Attr_objToAttrText( that, skipNetworkForElmCreation ){ var obj = that._attrs, noValue = X_Node_Attr_noValue, attrs = [ '' ], // 先頭にスペース plain = X_EMPTY_OBJECT, - n = 0, k, hasNetwork; - - that._flags &= ~X_Node_State.OLD_ATTRTEXT; + n = 0, k, check; + if( skipNetworkForElmCreation ){ + delete that._newAttrs; + // このあとで _newAttr にネットワーク系の属性を控える, attrText には加えない + } else { + that._flags &= ~X_Node_State.OLD_ATTRTEXT; + // 完全な attrText + }; + if( !obj ){ // Opera7 delete that._attrText; return ''; }; + for( k in obj ){ if( plain[ k ] ) continue; - if( skipNetwork ){ - switch( k ){ - case 'value' : - if( that._tag === 'LINK' && that._attr && that._attr.name === 'movie' ){ - hasNetwork = true; - continue; - }; - break; + if( skipNetworkForElmCreation ){ + check = false; + switch( that._tag + k ){ + case 'PARAMvalue' : + check = obj[ 'name' ] !== 'movie'; + case 'INPUTsrc' : + check = check || ( obj[ 'type' ] !== 'image' ); + case 'LINKhref' : + check = check || ( obj[ 'rel' ] !== 'stylesheet' ); - case 'src' : - hasNetwork = true; + if( !check ) break; + + case 'IMGsrc' : + case 'IFRAMEsrc' : + case 'FRAMEsrc' : + case 'SCRIPTsrc' : + case 'EMBEDsrc' : + case 'OBJECTdata' : + case 'BGSOUNDsrc' : + case 'APPLETcode' : + //case 'AUDIOsrc' : + //case 'VIDEOsrc' : + if( !that._newAttrs ) that._newAttrs = {}; + that._newAttrs[ k ] = obj[ k ]; continue; - - case 'href' : - if( that._tag === 'LINK' ){ - hasNetwork = true; - continue; - }; }; }; attrs[ ++n ] = noValue[ k ] ? k : [ k, '="', - k === 'value' ? X_String_toChrReferance( obj[ k ] ) : obj[ k ], + X_Node_Attr_toChrReferance[ k ] ? X_String_toChrReferance( obj[ k ] ) : obj[ k ], '"' ].join( '' ); }; - //if( hasNetwork ) that._flags |= X_Node_State.IE_NETWORK_ATTR - if( 0 < n ){ return that._attrText = attrs.join( ' ' ); }; diff --git a/0.6.x/js/02_dom/06_XNodeCSS.js b/0.6.x/js/02_dom/06_XNodeCSS.js index 1445907..a452ca6 100644 --- a/0.6.x/js/02_dom/06_XNodeCSS.js +++ b/0.6.x/js/02_dom/06_XNodeCSS.js @@ -285,6 +285,7 @@ function X_Node_CSS_objToCssText( that, skipFilter ){ }; if( 0 <= n ){ + // cssText には完全なものを控えるが、戻すのは filter を抜いたもの that._cssText = css.join( ';' ); if( skipFilter ){ --css.length; @@ -522,7 +523,7 @@ Node.prototype.css = function( nameOrObj /* orUnitID, valuOrUnitOrName */ ){ if( css[ name ] === v ) continue; flags = X_Node_CSS_setStyle( css, flags, name, v ); }; - this._flags = flags | X_Node_State.DIRTY_CSS | X_Node_State.OLD_CSSTEXT; + this._flags |= X_Node_State.DIRTY_CSS | X_Node_State.OLD_CSSTEXT; this._flags & X_Node_State.IN_TREE && X_Node_reserveUpdate(); delete this._cssText; return this; diff --git a/0.6.x/js/02_dom/10_XNodeAnime.js b/0.6.x/js/02_dom/10_XNodeAnime.js index 140f78a..1d7a23e 100644 --- a/0.6.x/js/02_dom/10_XNodeAnime.js +++ b/0.6.x/js/02_dom/10_XNodeAnime.js @@ -472,24 +472,26 @@ function X_Node_Anime_updatePosition( xnode, x, y, opacity, useGPU ){ }); }; - if( useGPU ){ - if( xnode._flags & X_Node_State.GPU_RELEASE_RESERVED ){ - xnode._flags &= X_Node_BitMask_RESET_GPU; - xnode._flags |= X_Node_State.GPU_NOW; - } else - if( xnode._flags & X_Node_State.GPU_NOW ){ + if( X_Node_Anime_translateZ ){ + if( useGPU ){ + if( xnode._flags & X_Node_State.GPU_RELEASE_RESERVED ){ + xnode._flags &= X_Node_BitMask_RESET_GPU; + xnode._flags |= X_Node_State.GPU_NOW; + } else + if( xnode._flags & X_Node_State.GPU_NOW ){ + } else { + xnode._flags &= X_Node_BitMask_RESET_GPU; + xnode._flags |= X_Node_State.GPU_RESERVED; + }; } else { - xnode._flags &= X_Node_BitMask_RESET_GPU; - xnode._flags |= X_Node_State.GPU_RESERVED; - }; - } else { - if( xnode._flags & X_Node_State.GPU_NOW ){ - xnode._flags &= X_Node_BitMask_RESET_GPU; - xnode._flags |= X_Node_State.GPU_RELEASE_RESERVED; - } else - if( xnode._flags & X_Node_State.GPU_RESERVED ){ - xnode._flags &= X_Node_BitMask_RESET_GPU; - }; + if( xnode._flags & X_Node_State.GPU_NOW ){ + xnode._flags &= X_Node_BitMask_RESET_GPU; + xnode._flags |= X_Node_State.GPU_RELEASE_RESERVED; + } else + if( xnode._flags & X_Node_State.GPU_RESERVED ){ + xnode._flags &= X_Node_BitMask_RESET_GPU; + }; + }; }; }; diff --git a/0.6.x/js/06_net/01_XNetXHR.js b/0.6.x/js/06_net/01_XNetXHR.js index 71d4770..fb35d5e 100644 --- a/0.6.x/js/06_net/01_XNetXHR.js +++ b/0.6.x/js/06_net/01_XNetXHR.js @@ -85,9 +85,9 @@ if( X_Net_XHR_W3C || X_Net_XHR_ACTIVE_X ){ X_NET_XHRWrapper = X_Class_override( new X.EventDispatcher(), { - + + _rawType : X_EventDispatcher_EVENT_TARGET_TYPE.XHR, _rawObject : X_Net_XHR_W3C || X_Net_XHR_ACTIVE_X, - _isXHR : true, // X.EventDispatcher で使用 for ie8- _isXDR : false, // for ie8 _method : '', diff --git a/0.6.x/js/07_audio/03_XSilverlightAudio.js b/0.6.x/js/07_audio/03_XSilverlightAudio.js index e64f3da..9a792fd 100644 --- a/0.6.x/js/07_audio/03_XSilverlightAudio.js +++ b/0.6.x/js/07_audio/03_XSilverlightAudio.js @@ -22,7 +22,7 @@ if( X.Pulgin.SilverlightEnabled ){ 'X.AV.SilverlightAudioWrapper', X.Class.POOL_OBJECT, { - _isSilverlight : true, // for X.EventDispatcher.listen + '_rawType' : X_EventDispatcher_EVENT_TARGET_TYPE.SILVER_LIGHT, proxy : null, startTime : 0,