From: itozyun Date: Tue, 2 Jun 2015 11:13:38 +0000 (+0900) Subject: Version 0.6.156, add X.UI.Repeater. X-Git-Url: http://git.osdn.jp/view?p=pettanr%2FclientJs.git;a=commitdiff_plain;h=86c591d2888cf7b24365c1950646fb1f6190efd1 Version 0.6.156, add X.UI.Repeater. --- diff --git a/0.6.x/js/01_core/04_XObject.js b/0.6.x/js/01_core/04_XObject.js index 01a0447..6d9941a 100644 --- a/0.6.x/js/01_core/04_XObject.js +++ b/0.6.x/js/01_core/04_XObject.js @@ -51,14 +51,16 @@ X[ 'Object' ] = { // --- implements ---------------------------------------------------------- // // ------------------------------------------------------------------------- // /** - * 単純なクローンでメンバーをコピーしたオブジェクトを返します。 + * 単純なクローンでメンバーをコピーしたオブジェクトを返します。 k in null でエラーになる Opera7- に対策済。 * @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; + + if( !src || !X_Type_isObject( src ) ) return src; + ret = {}; for( k in src ){ //if( X_EMPTY_OBJECT[ k ] ) continue; @@ -76,7 +78,7 @@ function X_Object_clone( src ){ */ function X_Object_override( target, src ){ var k; - if( !X_Type_isObject( src ) ) return target; + if( !src || !X_Type_isObject( src ) ) return target; for( k in src ){ //if( X_EMPTY_OBJECT[ k ] ) continue; target[ k ] = src[ k ]; @@ -97,6 +99,7 @@ function X_Object_deepCopy( src ){ function X_Object_deepCopy_( src, objSrc, objCopy, n ) { var ret, i, k; + if( !src ){ // 0, "", null, undefined, NaN, false return src; } else @@ -131,6 +134,7 @@ function X_Object_deepCopy_( src, objSrc, objCopy, n ) { function X_Object_cloneArray( ary ){ var ret = [], i = ary.length; + if( !i ) return ret; for( ; i; ){ ret[ --i ] = ary[ i ]; @@ -139,15 +143,15 @@ function X_Object_cloneArray( ary ){ }; /** - * object が空か?調べます。 + * object が空か?調べます。 object でない場合、undefined が返る * @alias X.Object.isEmpty * @param {object} v - * @return {boolean} + * @return {boolean|undefined} */ function X_Object_isEmpty( v ){ - var k; - for( k in v ){ - //if( X_EMPTY_OBJECT[ k ] ) continue; + if( !v ) return; + for( var k in v ){ + //if( X_EMPTY_OBJECT[ _k ] ) continue; return false;//if( v.hasOwnProperty && v.hasOwnProperty( p ) ) return false; ie4 で動かない、、、 }; return true; diff --git a/0.6.x/js/01_core/10_XCallback.js b/0.6.x/js/01_core/10_XCallback.js index 8156687..e427160 100644 --- a/0.6.x/js/01_core/10_XCallback.js +++ b/0.6.x/js/01_core/10_XCallback.js @@ -12,33 +12,33 @@ var X_Closure_COMMAND_DROP = X_Callback_POOL_LIST, - /* @const */ + /** @const */ X_Callback_THIS_FUNC = 1, - /* @const */ + /** @const */ X_Callback_HANDLEEVENT = 2, - /* @const */ + /** @const */ X_Callback_FUNC_ONLY = 3, - /* @const */ + /** @const */ X_Callback_NONE = 0, - /* @const */ + /** @const */ X_Callback_UN_LISTEN = 1, - /* @const */ + /** @const */ X_Callback_STOP_PROPAGATION = 2, - /* @const */ + /** @const */ X_Callback_STOP_NOW = 4 | 2, // 同一階層のリスナーのキャンセル(上位へもキャンセル) - /* @const */ + /** @const */ X_Callback_PREVENT_DEFAULT = 8, // 結果動作のキャンセル, - /* @const */ - X_Callback_MONOPOLY = 16, // move event を独占する - /* @const */ + /** @const */ X_Callback_CAPTURE_POINTER = 16, - /* @const */ + /** @const */ X_Callback_RELEASE_POINTER = 32, - /* @const */ + /** @const */ X_Callback_SYS_CANCEL = 64 | 4 | 2; + + /* * handleEvent という関数のメンバーを持つオブジェクト * @typedef {{ handleEvent : function }} diff --git a/0.6.x/js/01_core/11_XClass.js b/0.6.x/js/01_core/11_XClass.js index cbaeb22..b7c2920 100644 --- a/0.6.x/js/01_core/11_XClass.js +++ b/0.6.x/js/01_core/11_XClass.js @@ -34,7 +34,7 @@ X_Class_CommonMethods = * 全ての動的メンバを削除して、インスタンスを破棄する。
* インスタンスが X.EventDispatcher とそのサブクラスの場合、次の動作をする。 *
    - *
  1. X.Event.BEFORE_KILL_INSTANCE を発火する。戻り値のビットフラグに X_Callback_PREVENT_DEFAULT が立つ場合、破棄をキャンセルし X.Event.KILL_INSTANCE_CANCELED を発火する。 + *
  2. X.Event.BEFORE_KILL_INSTANCE を発火する。戻り値のビットフラグに X_Callback.PREVENT_DEFAULT が立つ場合、破棄をキャンセルし X.Event.KILL_INSTANCE_CANCELED を発火する。 *
  3. 破棄に進む場合は、X.Event.KILL_INSTANCE を発火する。 *
  4. dispatch 中は、インスタンスの全ての dispatch が終了するまで実際の破棄を待つ。 *
  5. 実際の破棄では、インスタンスのメンバの削除に加えて全てのイベントリスナを解除する。 diff --git a/0.6.x/js/01_core/13_XEventDispatcher.js b/0.6.x/js/01_core/13_XEventDispatcher.js index 9fa9c80..01ce6c7 100644 --- a/0.6.x/js/01_core/13_XEventDispatcher.js +++ b/0.6.x/js/01_core/13_XEventDispatcher.js @@ -753,16 +753,16 @@ function X_EventDispatcher_removeEvent( that, type, raw, list, skip ){ var X_EventDispatcher_actualHandleEvent = X_UA_EVENT.IE4 || X_UA_EVENT.IE ? // ie45678 EVENT_IE & EVENT_DOM0 for ie4 (function(){ - var ret; + var e = event, ret; - ret = this[ 'dispatch' ]( new X_DomEvent( event, this, this[ '_rawObject' ] ) ); + ret = this[ 'dispatch' ]( new X_DomEvent( e, this, this[ '_rawObject' ] ) ); if( ret & X_Callback_STOP_PROPAGATION ){ - event.cancelBubble = true; + e.cancelBubble = true; }; if( ret & X_Callback_PREVENT_DEFAULT ){ this[ '_tag' ] === 'A' && this[ '_rawObject' ].blur(); - return event.returnValue = false; + return e.returnValue = false; }; }) : //X_UA_EVENT.W3C || X_UA_EVENT.DOM0 diff --git a/0.6.x/js/01_core/16_XViewPort.js b/0.6.x/js/01_core/16_XViewPort.js index 5a4ad5f..a55a12e 100644 --- a/0.6.x/js/01_core/16_XViewPort.js +++ b/0.6.x/js/01_core/16_XViewPort.js @@ -312,7 +312,7 @@ X[ 'ViewPort' ] = { * @type {Node} */ X[ 'Doc' ][ 'html' ] = html = X_Node_html = elmHtml && new Node( elmHtml )[ 'removeClass' ]( 'js-disabled' )[ 'addClass' ]( X_UA_classNameForHTML ); - html[ '_flags' ] |= X_Node_State.IN_TREE; + html[ '_flags' ] |= X_NodeFlags_IN_TREE; /** * Node( head ) diff --git a/0.6.x/js/02_dom/00_XDoc.js b/0.6.x/js/02_dom/00_XDoc.js index 457bdc1..7232833 100644 --- a/0.6.x/js/02_dom/00_XDoc.js +++ b/0.6.x/js/02_dom/00_XDoc.js @@ -68,10 +68,10 @@ X[ 'Doc' ] = { function X_Doc_create( tag, opt_attrs, opt_css ){ var list, i; switch( X_Node_getType( tag ) ){ - case X_Node_TYPE.STRING : + case X_NodeType_STRING : X_Node_newByTag = true; return new Node( tag, opt_attrs, opt_css ); - case X_Node_TYPE.HTML_STRING : + case X_NodeType_HTML_STRING : list = X_HtmlParser_parse( tag, true ); for( i = list.length; 1 < i; ){ list[ --i ][ 'kill' ](); diff --git a/0.6.x/js/02_dom/02_XNodeFlags.js b/0.6.x/js/02_dom/02_XNodeFlags.js new file mode 100644 index 0000000..2b69e35 --- /dev/null +++ b/0.6.x/js/02_dom/02_XNodeFlags.js @@ -0,0 +1,64 @@ +var X_NodeFlags_DESTROYED = 0x0, + X_NodeFlags_EXIST = 0x1, + X_NodeFlags_IN_TREE = 0x2, // xnode が(仮想)ツリーに追加されている -> 描画の対象 + + X_NodeFlags_STYLE_IS_DISPLAY_NONE = 2 << 1, // display : none + X_NodeFlags_STYLE_IS_INVISIBLE = 2 << 2, // visibility : hidden or opacity : 0 + X_NodeFlags_STYLE_IS_POS_ABSOLUTE = 2 << 3, // position : absolute + X_NodeFlags_STYLE_IS_NO_OVERFLOW = 2 << 4, // overflow : hidden + X_NodeFlags_STYLE_IS_WIDTH_LENGTH = 2 << 5, // width : overflow:hidden,要素無し、または要素が非表示なら、 width() のための commitUpdate が不要 + X_NodeFlags_STYLE_IS_WIDTH_PCT = 2 << 6, // width : width() のための commitUpdate が不要かもしれない。(親で LENGTH が指定されているなら) + X_NodeFlags_STYLE_IS_HEIGHT_LENGTH = 2 << 7, // height : + X_NodeFlags_STYLE_IS_HEIGHT_PCT = 2 << 8, // height : + X_NodeFlags_STYLE_IS_FONT_LENGTH = 2 << 9, // fontSize : + X_NodeFlags_STYLE_IS_FONT_PCT = 2 << 10, // fontSize : + + X_NodeFlags_DIRTY_POSITION = 2 << 11, // 要素位置の変更が起こった。 + X_NodeFlags_DIRTY_CONTENT = 2 << 12, // width, height, x, y textNode の内容 TODO html と排他なので ID と共通でいい + X_NodeFlags_DIRTY_ID = 2 << 12, // width, height, x, y + X_NodeFlags_DIRTY_CLASSNAME = 2 << 13, // X_Node_CSS_getCharSize, width, height, x, y + X_NodeFlags_DIRTY_ATTR = 2 << 14, // X_Node_CSS_getCharSize, width, height, x, y + X_NodeFlags_DIRTY_CSS = 2 << 15, // X_Node_CSS_getCharSize, width, height, x, y + X_NodeFlags_DIRTY_IE_FILTER = X_UA[ 'IE' ] < 10 && X_UA[ 'ActiveX' ] ? 2 << 16 : 0, // + + X_NodeFlags_ACTUAL_LISTENING = 2 << 17, + X_NodeFlags_OLD_ATTRTEXT = 2 << 18, + X_NodeFlags_OLD_CSSTEXT = 2 << 19, + + // filter 要素が親子になると不具合が出るのを検出 + X_NodeFlags_IE_FILTER_NOW = 2 << 20, + + //GPU_WAITING = 2 << 20, // 1:子のGPU解除待 + X_NodeFlags_GPU_RESERVED = 2 << 21, // 2:GPU予約 + X_NodeFlags_GPU_NOW = 2 << 22, // 3:GPU now! + X_NodeFlags_GPU_RELEASE_RESERVED = 2 << 23, // 4:GPU解除予約 + X_NodeFlags_GPU_CHILD = 2 << 24, + + X_NodeFlags_IE4_HAS_TEXTNODE = X_UA[ 'IE4' ] ? 2 << 21 : 0, + X_NodeFlags_IE4_HAS_ELEMENT = X_UA[ 'IE4' ] ? 2 << 22 : 0, + X_NodeFlags_IE4_DIRTY_CHILDREN = X_UA[ 'IE4' ] ? 2 << 23 : 0, + X_NodeFlags_IE4_FIXED = X_UA[ 'IE4' ] ? 2 << 24 : 0, + + X_NodeFlags_IE5_DISPLAY_NONE_FIX = X_UA[ 'IE5' ] && X_UA[ 'ActiveX' ] ? 2 << 24 : 0, + + X_Node_BITMASK_RESET_STYLE = ( ( 2 << 29 ) - 1 + ( 2 << 29 ) ) ^ ( + X_NodeFlags_STYLE_IS_DISPLAY_NONE | + X_NodeFlags_STYLE_IS_INVISIBLE | + X_NodeFlags_STYLE_IS_POS_ABSOLUTE | + X_NodeFlags_STYLE_IS_NO_OVERFLOW | + X_NodeFlags_STYLE_IS_WIDTH_LENGTH | + X_NodeFlags_STYLE_IS_WIDTH_PCT | + X_NodeFlags_STYLE_IS_HEIGHT_LENGTH | + X_NodeFlags_STYLE_IS_HEIGHT_PCT | + X_NodeFlags_STYLE_IS_FONT_LENGTH | + X_NodeFlags_STYLE_IS_FONT_PCT ), + + X_Node_BitMask_IS_DIRTY = X_NodeFlags_DIRTY_POSITION | + X_NodeFlags_DIRTY_CONTENT | X_NodeFlags_DIRTY_ID | X_NodeFlags_DIRTY_CLASSNAME | + X_NodeFlags_DIRTY_ATTR | X_NodeFlags_DIRTY_CSS | X_NodeFlags_DIRTY_IE_FILTER, + + 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_NodeFlags_GPU_RESERVED | X_NodeFlags_GPU_NOW | X_NodeFlags_GPU_RELEASE_RESERVED ), + + X_Node_BitMask_IE4_IS_MIX = X_NodeFlags_IE4_HAS_TEXTNODE | X_NodeFlags_IE4_HAS_ELEMENT; diff --git a/0.6.x/js/02_dom/03_XDomEvent.js b/0.6.x/js/02_dom/03_XDomEvent.js index cba1424..4ab70dd 100644 --- a/0.6.x/js/02_dom/03_XDomEvent.js +++ b/0.6.x/js/02_dom/03_XDomEvent.js @@ -42,6 +42,14 @@ if( !X_UA[ 'IE' ] || 9 <= X_UA[ 'IE' ] ){ this[ 'loaded' ] = e.loaded; this[ 'total' ] = e.total; break; + case 'dragstart' : + case 'dragenter' : + case 'dragover' : + case 'dragleave' : + case 'drop' : + case 'dragend' : + this[ 'dataTransfer' ] = e.dataTransfer; + break; }; //console.log( 'original : ' + originalType + ' > ' + type ); @@ -439,7 +447,7 @@ if( !navigator.pointerEnabled ){ X_Event_Rename[ 'pointercancel' ] = document.documentElement.onmouseleave !== undefined ? 'mouseleave' : 'mouseout';//?? // Opera は ブラウザ設定から右クリックの通知を許可すると mousedown で e.button==2 が返る,キャンセルは可能?? - X_UA[ 'Opera' ] && ( X_Event_Rename[ 'contextmenu' ] = 'mousedown' ); + X_UA[ 'Opera' ] && ( X_Event_Rename[ 'contextmenu' ] = 'mousedown' ); /* * buttons の無いブラウザには mouseup, mousedown を監視して、buttons フラグを更新し続ける diff --git a/0.6.x/js/02_dom/04_XBoxModel.js b/0.6.x/js/02_dom/04_XBoxModel.js index ed00a00..acb0939 100644 --- a/0.6.x/js/02_dom/04_XBoxModel.js +++ b/0.6.x/js/02_dom/04_XBoxModel.js @@ -10,10 +10,6 @@ var X_Node_BoxModel = { // TODO: offsetLeft, offsetTop の基準位置 X_Node_BoxModel_absoluteOffset; - - - - X_ViewPort[ 'listenOnce' ]( X_EVENT_INIT, function(){ var node = X_Node_systemNode; @@ -65,131 +61,114 @@ X_ViewPort[ 'listenOnce' ]( X_EVENT_INIT, function(){ * getBoxObjectFor * getBoundingClientRect */ -Node.prototype[ 'width' ] = function(){ - if( ( this[ '_flags' ] & X_Node_State.IN_TREE ) === 0 || this[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ) return 0; + +function X_Node_BoxModel_mesure( that, name ){ + var flags = that[ '_flags' ], elm; + + if( ( flags & X_NodeFlags_IN_TREE ) === 0 || flags & X_NodeFlags_STYLE_IS_DISPLAY_NONE ) return 0; X_Node_updateTimerID && X_Node_startUpdate(); - if( X_UA_DOM.W3C ){ - // TODO width : length + overflow : hidden ならそれを返す? <- block or inline - return this[ '_rawObject' ] ? this[ '_rawObject' ].offsetWidth : 0; - } else - if( X_UA_DOM.IE4 ){ - return ( this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ).offsetWidth; - } else { - - }; + elm = that[ '_rawObject' ] || X_Node__ie4getRawNode && X_Node__ie4getRawNode( that ); + return elm ? elm[ name ] : 0; }; -Node.prototype[ 'height' ] = function(){ - if( ( this[ '_flags' ] & X_Node_State.IN_TREE ) === 0 || this[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ) return 0; - - X_Node_updateTimerID && X_Node_startUpdate(); +/** + * 要素の幅。elm.offsetWidth + * @alias Node.prototype.width + * @return {number} + * @example node.width(); + */ +function X_Node_width(){ + return X_Node_BoxModel_mesure( this, 'offsetWidth' ); - if( X_UA_DOM.W3C ){ - // this[ 'css' ]( X_Node_CSS_Unit.px, 'height' ); - return this[ '_rawObject' ] ? this[ '_rawObject' ].offsetHeight : 0; - } else - if( X_UA_DOM.IE4 ){ - return ( this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ).offsetHeight; - } else { - - }; + // TODO width : length + overflow : hidden ならそれを返す? <- block or inline + // TODO TextNode どうする? + //if( X_UA_DOM.IE4 ) return elm ? elm.style.pixelWidth : 0; + //return elm ? elm.offsetWidth : 0; }; -Node.prototype[ 'clientWidth' ] = function(){ - if( ( this[ '_flags' ] & X_Node_State.IN_TREE ) === 0 || this[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ) return 0; - - X_Node_updateTimerID && X_Node_startUpdate(); +/** + * 要素の高さ。elm.offsetHeight + * @alias Node.prototype.height + * @return {number} + * @example node.height(); + */ +function X_Node_height(){ + return X_Node_BoxModel_mesure( this, 'offsetHeight' ); - if( X_UA_DOM.W3C ){ - // this[ 'css' ]( X_Node_CSS_Unit.px, 'width' ); - return this[ '_rawObject' ] ? this[ '_rawObject' ].clientWidth : 0; - } else - if( X_UA_DOM.IE4 ){ - return ( this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ).clientWidth; - } else { - - }; + // this[ 'css' ]( X_Node_CSS_Unit.px, 'height' ); + //if( X_UA_DOM.IE4 ) return elm ? elm.style.pixelHeight : 0; + //return elm ? elm.offsetHeight : 0; }; -Node.prototype[ 'clientHeight' ] = function(){ - if( ( this[ '_flags' ] & X_Node_State.IN_TREE ) === 0 || this[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ) return 0; +/** + * 要素のコンテンツ領域の幅。elm.clientWidth + * @alias Node.prototype.clientWidth + * @return {number} + * @example node.clientWidth(); + */ +function X_Node_clientWidth(){ + return X_Node_BoxModel_mesure( this, 'clientWidth' ); - X_Node_updateTimerID && X_Node_startUpdate(); - - if( X_UA_DOM.W3C ){ - // this[ 'css' ]( X_Node_CSS_Unit.px, 'height' ); - return this[ '_rawObject' ] ? this[ '_rawObject' ].clientHeight : 0; - } else - if( X_UA_DOM.IE4 ){ - return ( this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ).clientHeight; - } else { - - }; + // this[ 'css' ]( X_Node_CSS_Unit.px, 'width' ); + //return elm ? elm.clientWidth : 0; }; -Node.prototype[ 'scrollWidth' ] = function(){ - if( ( this[ '_flags' ] & X_Node_State.IN_TREE ) === 0 || this[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ) return 0; - - X_Node_updateTimerID && X_Node_startUpdate(); +/** + * 要素のコンテンツ領域の高さ。elm.clientHeight + * @alias Node.prototype.clientHeight + * @return {number} + * @example node.clientHeight(); + */ +function X_Node_clientHeight(){ + return X_Node_BoxModel_mesure( this, 'clientHeight' ); - if( X_UA_DOM.W3C ){ - // this[ 'css' ]( X_Node_CSS_Unit.px, 'width' ); - return this[ '_rawObject' ] ? this[ '_rawObject' ].scrollWidth : 0; - } else - if( X_UA_DOM.IE4 ){ - return ( this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ).scrollWidth; - } else { - - }; + // this[ 'css' ]( X_Node_CSS_Unit.px, 'height' ); + //return elm ? elm.clientHeight : 0; }; -Node.prototype[ 'scrollHeight' ] = function(){ - if( ( this[ '_flags' ] & X_Node_State.IN_TREE ) === 0 || this[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ) return 0; - - X_Node_updateTimerID && X_Node_startUpdate(); +/** + * 要素のスクロール領域の幅。elm.scrollWidth + * @alias Node.prototype.scrollWidth + * @return {number} + * @example node.scrollWidth(); + */ +function X_Node_scrollWidth(){ + return X_Node_BoxModel_mesure( this, 'scrollWidth' ); - if( X_UA_DOM.W3C ){ - return this[ '_rawObject' ] ? this[ '_rawObject' ].scrollHeight : 0; - } else - if( X_UA_DOM.IE4 ){ - return ( this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ).scrollHeight; - } else { - - }; + // this[ 'css' ]( X_Node_CSS_Unit.px, 'width' ); + //return elm ? elm.scrollWidth : 0; }; -Node.prototype[ 'scrollLeft' ] = function(){ - if( ( this[ '_flags' ] & X_Node_State.IN_TREE ) === 0 || this[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ) return 0; - - X_Node_updateTimerID && X_Node_startUpdate(); +/** + * 要素のスクロール領域の高さ。elm.scrollHeight + * @alias Node.prototype.scrollHeight + * @return {number} + * @example node.scrollHeight(); + */ +function X_Node_scrollHeight(){ + return X_Node_BoxModel_mesure( this, 'scrollHeight' ); +}; - if( X_UA_DOM.W3C ){ - // this[ 'css' ]( X_Node_CSS_Unit.px, 'width' ); - return this[ '_rawObject' ] ? this[ '_rawObject' ].scrollLeft : 0; - } else - if( X_UA_DOM.IE4 ){ - return ( this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ).scrollLeft; - } else { - - }; +/** + * 要素のスクロール位置。elm.scrollLeft + * @alias Node.prototype.scrollLeft + * @return {number} + * @example node.scrollLeft(); + */ +function X_Node_scrollLeft(){ + return X_Node_BoxModel_mesure( this, 'scrollLeft' ); }; -Node.prototype[ 'scrollTop' ] = function(){ - if( ( this[ '_flags' ] & X_Node_State.IN_TREE ) === 0 || this[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ) return 0; - - X_Node_updateTimerID && X_Node_startUpdate(); - - if( X_UA_DOM.W3C ){ - // this[ 'css' ]( X_Node_CSS_Unit.px, 'width' ); - return this[ '_rawObject' ] ? this[ '_rawObject' ].scrollTop : 0; - } else - if( X_UA_DOM.IE4 ){ - return ( this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ).scrollTop; - } else { - - }; +/** + * 要素のスクロール位置。elm.scrollTop + * @alias Node.prototype.scrollTop + * @return {number} + * @example node.scrollTop(); + */ +function X_Node_scrollTop(){ + return X_Node_BoxModel_mesure( this, 'scrollTop' ); }; /* -------------------------------------- @@ -198,61 +177,61 @@ Node.prototype[ 'scrollTop' ] = function(){ * position:absolute の指定で自動で top,left を補う必要あり? -> X.Node.CSS * 親要素 border 外側からの値。 IE, Firefox, Safari, Chrome の offsetLeft/Topでは、border 内側なので補正する。 * transformX, Y は加える? アニメーション中は? + * + * http://www.din.or.jp/~hagi3/JavaScript/JSTips/DHTML/ProbIE5.htm#StyleObject */ -// X_Node_CSS_transform, -Node.prototype[ 'x' ] = function(){ - if( ( this[ '_flags' ] & X_Node_State.IN_TREE ) === 0 || this[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ) return 0; - - X_Node_updateTimerID && X_Node_startUpdate(); +// TODO X_Node_CSS_transform, + +/** + * 要素の親要素に対する位置。offsetLeft + * @alias Node.prototype.x + * @return {number} + * @example node.x(); + */ +function X_Node_x(){ + return X_Node_BoxModel_mesure( this, 'offsetLeft' ); - if( X_UA_DOM.W3C ){ - // this[ 'css' ]( X_Node_CSS_Unit.px, 'left' ); - // this[ 'css' ]( X_Node_CSS_Unit.px, 'translateX' ); - return this[ '_rawObject' ] ? this[ '_rawObject' ].offsetLeft : 0; - } else - if( X_UA_DOM.IE4 ){ - // pixelLeft http://www.din.or.jp/~hagi3/JavaScript/JSTips/DHTML/ProbIE5.htm - return ( this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ).offsetLeft; - } else { - - }; + // this[ 'css' ]( X_Node_CSS_Unit.px, 'left' ); + // this[ 'css' ]( X_Node_CSS_Unit.px, 'translateX' ); + //if( X_UA_DOM.IE4 ) return elm ? elm.style.pixelLeft : 0; + //return elm ? elm.offsetLeft : 0; }; -Node.prototype[ 'y' ] = function(){ - if( ( this[ '_flags' ] & X_Node_State.IN_TREE ) === 0 || this[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ) return 0; - - X_Node_updateTimerID && X_Node_startUpdate(); +/** + * 要素の親要素に対する位置。offsetTop + * @alias Node.prototype.y + * @return {number} + * @example node.y(); + */ +function X_Node_y(){ + return X_Node_BoxModel_mesure( this, 'offsetTop' ); - if( X_UA_DOM.W3C ){ - // this[ 'css' ]( X_Node_CSS_Unit.px, 'top' ); - // this[ 'css' ]( X_Node_CSS_Unit.px, 'transisitonY' ); - return this[ '_rawObject' ] ? this[ '_rawObject' ].offsetTop : 0; - } else - if( X_UA_DOM.IE4 ){ - return ( this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ).offsetTop; - } else { - - }; + // this[ 'css' ]( X_Node_CSS_Unit.px, 'top' ); + // this[ 'css' ]( X_Node_CSS_Unit.px, 'transisitonY' ); + //if( X_UA_DOM.IE4 ) return elm ? elm.style.pixelTop : 0; + //return elm ? elm.offsetTop : 0; }; -Node.prototype[ 'offset' ] = function( /* xnodeParent */ ){ - - if( ( this[ '_flags' ] & X_Node_State.IN_TREE ) === 0 || this[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ) return { x : 0, y : 0 }; +/** + * 要素の親要素に対する位置。 + * @alias Node.prototype.offset + * @return {object} { x: {number}, y : {number} } + * @example node.offset(); + */ +function X_Node_offset( /* xnodeParent */ ){ + var flags = this[ '_flags' ], elm; - if( X.Doc.body === this || X.Doc.html === this ){ + if( ( flags & X_NodeFlags_IN_TREE ) === 0 || flags & X_NodeFlags_STYLE_IS_DISPLAY_NONE ) return { x : 0, y : 0 }; + + if( X_Node_body === this || X_Node_html === this ){ return { x : 0, y : 0 }; }; X_Node_updateTimerID && X_Node_startUpdate(); - if( X_UA_DOM.W3C ){ - return this[ '_rawObject' ] ? X_Node_getPosition( this[ '_rawObject' ] ) : { x : 0, y : 0 }; - } else - if( X_UA_DOM.IE4 ){ - return X_Node_getPosition( this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) ); - } else { - - }; + elm = this[ '_rawObject' ] || X_Node__ie4getRawNode && X_Node__ie4getRawNode( this ); + + return elm ? X_Node_getPosition( elm ) : { x : 0, y : 0 }; }; // エレメントの座標取得 ~スクロール要素~ diff --git a/0.6.x/js/02_dom/05_XNodeAttr.js b/0.6.x/js/02_dom/05_XNodeAttr.js index 9a33207..2bb4817 100644 --- a/0.6.x/js/02_dom/05_XNodeAttr.js +++ b/0.6.x/js/02_dom/05_XNodeAttr.js @@ -86,7 +86,7 @@ function X_Node_Attr_objToAttrText( that, skipNetworkForElmCreation ){ delete that[ '_newAttrs' ]; // このあとで _newAttr にネットワーク系の属性を控える, attrText には加えない } else { - that[ '_flags' ] &= ~X_Node_State.OLD_ATTRTEXT; + that[ '_flags' ] &= ~X_NodeFlags_OLD_ATTRTEXT; // 完全な attrText }; @@ -161,7 +161,7 @@ function X_Node_Attr_objToAttrText( that, skipNetworkForElmCreation ){ * // setter - 2 * node.attr( 'src', url ); */ -Node.prototype[ 'attr' ] = function( nameOrObj /* v */ ){ +function X_Node_attr( nameOrObj /* v */ ){ var attrs = this[ '_attrs' ], newAttrs, f, k, elm, v; if( !this[ '_tag' ] ) return this; @@ -176,8 +176,8 @@ Node.prototype[ 'attr' ] = function( nameOrObj /* v */ ){ }; if( f ){ delete this[ '_attrText' ]; - this[ '_flags' ] |= X_Node_State.DIRTY_ATTR | X_Node_State.OLD_ATTRTEXT; - this[ '_flags' ] & X_Node_State.IN_TREE && X_Node_reserveUpdate(); + this[ '_flags' ] |= X_NodeFlags_DIRTY_ATTR | X_NodeFlags_OLD_ATTRTEXT; + this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); }; return this; } else @@ -185,8 +185,8 @@ Node.prototype[ 'attr' ] = function( nameOrObj /* v */ ){ // setter if( X_Node_Attr_setAttr( this, attrs || ( this[ '_attrs' ] = {} ), this[ '_newAttrs' ] || ( this[ '_newAttrs' ] = {} ), nameOrObj, arguments[ 1 ] ) === true ){ delete this[ '_attrText' ]; - this[ '_flags' ] |= X_Node_State.DIRTY_ATTR | X_Node_State.OLD_ATTRTEXT; - this[ '_flags' ] & X_Node_State.IN_TREE && X_Node_reserveUpdate(); + this[ '_flags' ] |= X_NodeFlags_DIRTY_ATTR | X_NodeFlags_OLD_ATTRTEXT; + this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); }; return this; } else @@ -248,8 +248,8 @@ function X_Node_Attr_setAttr( that, attrs, newAttrs, name, v ){ // TODO unique の check if( v !== that[ '_id' ] ){ that[ '_id' ] = v; - that[ '_flags' ] |= X_Node_State.DIRTY_ID; - that[ '_flags' ] & X_Node_State.IN_TREE && X_Node_reserveUpdate(); + that[ '_flags' ] |= X_NodeFlags_DIRTY_ID; + that[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); }; return; case 'class' : diff --git a/0.6.x/js/02_dom/06_XNodeCSS.js b/0.6.x/js/02_dom/06_XNodeCSS.js index 9a9d85b..9711a5e 100644 --- a/0.6.x/js/02_dom/06_XNodeCSS.js +++ b/0.6.x/js/02_dom/06_XNodeCSS.js @@ -251,7 +251,7 @@ function X_Node_CSS_objToCssText( that, skipFilter ){ n = -1, p, v, specialFix, filterFix; - that[ '_flags' ] &= ~X_Node_State.OLD_CSSTEXT; + that[ '_flags' ] &= ~X_NodeFlags_OLD_CSSTEXT; if( !obj ){ // Opera7.5 未満? delete that[ '_cssText' ]; @@ -416,8 +416,8 @@ function X_Node_CSS_objToIEFilterText( that, opt_css ){ }; function X_Node_CSS_onAfterUpdateForIEFilterFix(){ - if( this[ '_flags' ] & X_Node_State.IN_TREE ){ // 要素があり、要素がツリーに属している - this[ '_flags' ] |= X_Node_State.DIRTY_IE_FILTER; + if( this[ '_flags' ] & X_NodeFlags_IN_TREE ){ // 要素があり、要素がツリーに属している + this[ '_flags' ] |= X_NodeFlags_DIRTY_IE_FILTER; X_Node_reserveUpdate(); }; }; @@ -517,7 +517,7 @@ function X_Node_CSS__splitValueAndUnit( v ){ * // setter - 2 * node.css( 'color', 0x666666 ); */ -Node.prototype[ 'css' ] = function( nameOrObj /* value */ ){ +function X_Node_css( nameOrObj /* value */ ){ var args = arguments, css = this[ '_css' ], p, name, v, plain, camelize, flags; @@ -536,9 +536,9 @@ Node.prototype[ 'css' ] = function( nameOrObj /* value */ ){ if( css[ name ] === v ) continue; flags = X_Node_CSS_setStyle( css, flags, name, v ); }; - flags |= X_Node_State.DIRTY_CSS | X_Node_State.OLD_CSSTEXT; + flags |= X_NodeFlags_DIRTY_CSS | X_NodeFlags_OLD_CSSTEXT; this[ '_flags' ] = flags; - flags & X_Node_State.IN_TREE && X_Node_reserveUpdate(); + flags & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); delete this[ '_cssText' ]; return this; } else @@ -548,8 +548,8 @@ Node.prototype[ 'css' ] = function( nameOrObj /* value */ ){ name = X_Node_CSS_camelize( nameOrObj ); v = args[ 1 ]; if( css[ name ] === v ) return this; - this[ '_flags' ] = X_Node_CSS_setStyle( css, this[ '_flags' ], name, v ) | X_Node_State.DIRTY_CSS | X_Node_State.OLD_CSSTEXT; - this[ '_flags' ] & X_Node_State.IN_TREE && X_Node_reserveUpdate(); + this[ '_flags' ] = X_Node_CSS_setStyle( css, this[ '_flags' ], name, v ) | X_NodeFlags_DIRTY_CSS | X_NodeFlags_OLD_CSSTEXT; + this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); delete this[ '_cssText' ]; return this; }; @@ -563,7 +563,7 @@ Node.prototype[ 'css' ] = function( nameOrObj /* value */ ){ function X_Node_CSS_setStyle( css, flags, name, newValue ){ if( X_Node_CSS_FILTER_FIX_PROPS && X_Node_CSS_FILTER_FIX_PROPS[ name ] ){ - flags |= X_Node_State.DIRTY_IE_FILTER; + flags |= X_NodeFlags_DIRTY_IE_FILTER; }; if( !newValue && newValue !== 0 ){ delete css[ name ]; @@ -574,49 +574,49 @@ function X_Node_CSS_setStyle( css, flags, name, newValue ){ switch( name ){ case 'display' : console.log( newValue ); - newValue === 'none' ? ( flags |= X_Node_State.STYLE_IS_DISPLAY_NONE ) : ( flags &= ~X_Node_State.STYLE_IS_DISPLAY_NONE ); + newValue === 'none' ? ( flags |= X_NodeFlags_STYLE_IS_DISPLAY_NONE ) : ( flags &= ~X_NodeFlags_STYLE_IS_DISPLAY_NONE ); return flags; case 'visibility' : // すでに opacity:0 で invisible - if( flags & X_Node_State.STYLE_IS_INVISIBLE && css[ 'opacity' ] == 0 ) return flags; - newValue === 'hidden' ? ( flags |= X_Node_State.STYLE_IS_INVISIBLE ) : ( flags &= ~X_Node_State.STYLE_IS_INVISIBLE ); + if( flags & X_NodeFlags_STYLE_IS_INVISIBLE && css[ 'opacity' ] == 0 ) return flags; + newValue === 'hidden' ? ( flags |= X_NodeFlags_STYLE_IS_INVISIBLE ) : ( flags &= ~X_NodeFlags_STYLE_IS_INVISIBLE ); return flags; case 'opacity' : // すでに visibility:hidden で invisible - if( flags & X_Node_State.STYLE_IS_INVISIBLE && css[ 'visibility' ] === 'hidden' ) return flags; + if( flags & X_NodeFlags_STYLE_IS_INVISIBLE && css[ 'visibility' ] === 'hidden' ) return flags; newValue == 0 ? // 0 or "0" - ( flags |= X_Node_State.STYLE_IS_INVISIBLE ) : ( flags &= ~X_Node_State.STYLE_IS_INVISIBLE ); + ( flags |= X_NodeFlags_STYLE_IS_INVISIBLE ) : ( flags &= ~X_NodeFlags_STYLE_IS_INVISIBLE ); return flags; case 'overflow' : - newValue === 'hidden' ? ( flags |= X_Node_State.STYLE_IS_NO_OVERFLOW ) : ( flags &= ~X_Node_State.STYLE_IS_NO_OVERFLOW ); + newValue === 'hidden' ? ( flags |= X_NodeFlags_STYLE_IS_NO_OVERFLOW ) : ( flags &= ~X_NodeFlags_STYLE_IS_NO_OVERFLOW ); return flags; case 'position' : - newValue === 'absolute' ? ( flags |= X_Node_State.STYLE_IS_POS_ABSOLUTE ) : ( flags &= ~X_Node_State.STYLE_IS_POS_ABSOLUTE ); + newValue === 'absolute' ? ( flags |= X_NodeFlags_STYLE_IS_POS_ABSOLUTE ) : ( flags &= ~X_NodeFlags_STYLE_IS_POS_ABSOLUTE ); return flags; case 'width' : newValue = X_Node_CSS__splitValueAndUnit( newValue ); if( newValue[ 1 ] !== '%' ){ - flags |= X_Node_State.STYLE_IS_WIDTH_LENGTH; - flags &= ~X_Node_State.STYLE_IS_WIDTH_PCT; + flags |= X_NodeFlags_STYLE_IS_WIDTH_LENGTH; + flags &= ~X_NodeFlags_STYLE_IS_WIDTH_PCT; } else { - flags &= ~X_Node_State.STYLE_IS_WIDTH_LENGTH; - flags |= X_Node_State.STYLE_IS_WIDTH_PCT; + flags &= ~X_NodeFlags_STYLE_IS_WIDTH_LENGTH; + flags |= X_NodeFlags_STYLE_IS_WIDTH_PCT; }; return flags; case 'height' : newValue = X_Node_CSS__splitValueAndUnit( newValue ); if( newValue[ 1 ] !== '%' ){ - flags |= X_Node_State.STYLE_IS_HEIGHT_LENGTH; - flags &= ~X_Node_State.STYLE_IS_HEIGHT_PCT; + flags |= X_NodeFlags_STYLE_IS_HEIGHT_LENGTH; + flags &= ~X_NodeFlags_STYLE_IS_HEIGHT_PCT; } else { - flags &= ~X_Node_State.STYLE_IS_HEIGHT_LENGTH; - flags |= X_Node_State.STYLE_IS_HEIGHT_PCT; + flags &= ~X_NodeFlags_STYLE_IS_HEIGHT_LENGTH; + flags |= X_NodeFlags_STYLE_IS_HEIGHT_PCT; }; return flags; @@ -626,19 +626,29 @@ function X_Node_CSS_setStyle( css, flags, name, newValue ){ return flags; }; -Node.prototype[ 'cssText' ] = function( v ){ +/** + * cssText の getter と setter。setter の場合 css と異なり全ての style が書き変わる。 + * @alias Node.prototype.cssText + * @param {string=} v cssText 文字列名 + * @return {Node|string} getter の場合は cssText 文字列を、setter の場合は自身を返す。(メソッドチェーン) + * @example // getter + * node.cssText(); + * // setter + * node.cssText('color:red;width:20px'); + */ +function X_Node_cssText( v ){ var obj, i, l, attr, name; - if( v === this[ '_cssText' ] && ( this[ '_flags' ] & X_Node_State.OLD_CSSTEXT ) === 0 ){ + if( v === this[ '_cssText' ] && ( this[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT ) === 0 ){ return this; }; if( v === '' ){ delete this[ '_css' ]; delete this[ '_cssText' ]; - this[ '_flags' ] |= X_Node_State.DIRTY_CSS | X_Node_State.DIRTY_IE_FILTER; - this[ '_flags' ] &= ~X_Node_State.OLD_CSSTEXT; - this[ '_flags' ] & X_Node_State.IN_TREE && X_Node_reserveUpdate(); + this[ '_flags' ] |= X_NodeFlags_DIRTY_CSS | X_NodeFlags_DIRTY_IE_FILTER; + this[ '_flags' ] &= ~X_NodeFlags_OLD_CSSTEXT; + this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); return this; } else if( X_Type_isString( v ) ){ @@ -652,7 +662,7 @@ Node.prototype[ 'cssText' ] = function( v ){ return this[ 'css' ]( obj ); }; // getter - this[ '_flags' ] & X_Node_State.OLD_CSSTEXT && X_Node_CSS_objToCssText( this ); + this[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT && X_Node_CSS_objToCssText( this ); return this[ '_cssText' ]; }; diff --git a/0.6.x/js/02_dom/08_XNodeSelector.js b/0.6.x/js/02_dom/08_XNodeSelector.js index 4b735e0..9d33b14 100644 --- a/0.6.x/js/02_dom/08_XNodeSelector.js +++ b/0.6.x/js/02_dom/08_XNodeSelector.js @@ -233,22 +233,24 @@ function X_Node_Selector__parse( query, last ){ * @return {Node|NodeList} */ X[ 'Doc' ][ 'find' ] = X_shortcutFunction = + /** * selector を使って Node, NodeList を取得する - * @alias Node.prototype.find + * @alias NodeList.prototype.find * @function * @param {string} セレクター文字列 * @return {Node|NodeList} */ - Node.prototype[ 'find' ] = + X_NodeList.prototype[ 'find' ] = X_Node_find; + /** * selector を使って Node, NodeList を取得する - * @alias NodeList.prototype.find + * @alias Node.prototype.find * @function * @param {string} セレクター文字列 * @return {Node|NodeList} - */ - X_NodeList.prototype[ 'find' ] = function ( queryString ){ + */ + function X_Node_find( queryString ){ var HTML = X_Node_html, scope = this.constructor === X_NodeList && this.length ? this : [ this.constructor === Node ? this : X_Node_body ], parents = scope, // 探索元の親要素 XNodeList の場合あり diff --git a/0.6.x/js/02_dom/10_XNodeAnime.js b/0.6.x/js/02_dom/10_XNodeAnime.js index 325b955..c83aef5 100644 --- a/0.6.x/js/02_dom/10_XNodeAnime.js +++ b/0.6.x/js/02_dom/10_XNodeAnime.js @@ -99,7 +99,7 @@ var X_Node_ANIMATIONS = [], * @param {number=} wait GPU レイヤーの遅延解除 ms * @return {Node} メソッドチェーン */ -Node.prototype[ 'animate' ] = function( start, dest, duration, easing, wait ){ +function X_Node_animate( start, dest, duration, easing, wait ){ var isNew = !this[ '_anime' ], obj = this[ '_anime' ] || ( this[ '_anime' ] = {} ); @@ -162,7 +162,7 @@ Node.prototype[ 'animate' ] = function( start, dest, duration, easing, wait ){ * @alias Node.prototype.stop * @return {Node} メソッドチェーン */ -Node.prototype[ 'stop' ] = function(){ +function X_Node_stop(){ var obj = this[ '_anime' ]; if( !obj ) return this; @@ -519,21 +519,21 @@ function X_Node_Anime_updatePosition( xnode, x, y, opacity, useGPU ){ if( X_Node_Anime_translateZ ){ if( useGPU ){ - if( xnode[ '_flags' ] & X_Node_State.GPU_RELEASE_RESERVED ){ + if( xnode[ '_flags' ] & X_NodeFlags_GPU_RELEASE_RESERVED ){ xnode[ '_flags' ] &= X_Node_BitMask_RESET_GPU; - xnode[ '_flags' ] |= X_Node_State.GPU_NOW; + xnode[ '_flags' ] |= X_NodeFlags_GPU_NOW; } else - if( xnode[ '_flags' ] & X_Node_State.GPU_NOW ){ + if( xnode[ '_flags' ] & X_NodeFlags_GPU_NOW ){ } else { xnode[ '_flags' ] &= X_Node_BitMask_RESET_GPU; - xnode[ '_flags' ] |= X_Node_State.GPU_RESERVED; + xnode[ '_flags' ] |= X_NodeFlags_GPU_RESERVED; }; } else { - if( xnode[ '_flags' ] & X_Node_State.GPU_NOW ){ + if( xnode[ '_flags' ] & X_NodeFlags_GPU_NOW ){ xnode[ '_flags' ] &= X_Node_BitMask_RESET_GPU; - xnode[ '_flags' ] |= X_Node_State.GPU_RELEASE_RESERVED; + xnode[ '_flags' ] |= X_NodeFlags_GPU_RELEASE_RESERVED; } else - if( xnode[ '_flags' ] & X_Node_State.GPU_RESERVED ){ + if( xnode[ '_flags' ] & X_NodeFlags_GPU_RESERVED ){ xnode[ '_flags' ] &= X_Node_BitMask_RESET_GPU; }; }; diff --git a/0.6.x/js/02_dom/02_XNode.js b/0.6.x/js/02_dom/20_XNode.js similarity index 79% rename from 0.6.x/js/02_dom/02_XNode.js rename to 0.6.x/js/02_dom/20_XNode.js index 185074d..e0aa707 100644 --- a/0.6.x/js/02_dom/02_XNode.js +++ b/0.6.x/js/02_dom/20_XNode.js @@ -1,1947 +1,1893 @@ -var - /** @enum {number} - * @const */ - X_Node_State = { - DESTROYED : 0x0, - EXIST : 0x1, - IN_TREE : 0x2, // xnode が(仮想)ツリーに追加されている -> 描画の対象 - - STYLE_IS_DISPLAY_NONE : 2 << 1, // display : none - 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 : 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 : - STYLE_IS_FONT_LENGTH : 2 << 9, // fontSize : - STYLE_IS_FONT_PCT : 2 << 10, // fontSize : - - DIRTY_POSITION : 2 << 11, // 要素位置の変更が起こった。 - DIRTY_CONTENT : 2 << 12, // width, height, x, y textNode の内容 TODO html と排他なので ID と共通でいい - 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, // - - ACTUAL_LISTENING : 2 << 17, - OLD_ATTRTEXT : 2 << 18, - OLD_CSSTEXT : 2 << 19, - - // filter 要素が親子になると不具合が出るのを検出 - IE_FILTER_NOW : 2 << 20, - - //GPU_WAITING : 2 << 20, // 1:子のGPU解除待 - 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, - 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 << 24 : 0 - }; - -var 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 | - X_Node_State.STYLE_IS_NO_OVERFLOW | - X_Node_State.STYLE_IS_WIDTH_LENGTH | - X_Node_State.STYLE_IS_WIDTH_PCT | - X_Node_State.STYLE_IS_HEIGHT_LENGTH | - X_Node_State.STYLE_IS_HEIGHT_PCT | - 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_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_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, - - /* @enum {number} */ - X_Node_TYPE = { - XNODE : 1, - RAW_HTML : 2, - RAW_TEXT : 3, - HTML_STRING : 4, - STRING : 5, - //DOC_FRAG : 6, - XNODE_LIST : 7, - WINDOW : 8, - DOCUMENT : 9, - IMAGE : 10 - }, - - X_Node_strictElmCreation = !X_UA[ 'MacIE' ] && X_UA[ 'IE' ] <= 8, - - X_Node_documentFragment = document.createDocumentFragment && ( !X_UA[ 'IE' ] || 5.5 <= X_UA[ 'IE' ] ) && document.createDocumentFragment(), - - // 子の生成後に リアル文書 tree に追加する - X_Node_addTreeAfterChildren = !( X_UA[ 'IE' ] < 9 ), - - X_Node_displayNoneFixForIE5 = !!X_Node_State.IE5_DISPLAY_NONE_FIX, - - X_Node_newByTag = false, - - X_Node_newByText = false, - - X_Node_outerXNode = null, - - X_Node_updateTimerID = 0; - -/** - * Node( rawElement | rawTextnode | htmlString | textString ) - * - * @alias X.Node - * @class Node HTMLElement、TextNode をラップし jQuery 風な API で操作できます。 - * @constructs Node - * @extends {EventDispatcher} - */ -var Node = X[ 'Node' ] = X_EventDispatcher[ 'inherits' ]( - 'X.Node', - X_Class.POOL_OBJECT, - - { - /** - * 要素に振られるユニークID - * @type {number} - * @private - * @alias Node.prototype._uid - */ - '_uid' : 0, - - /** - * Node の状態を表すフラグ。 - * @type {number} - * @private - * @alias Node.prototype._flags - */ - '_flags' : X_Node_State.DESTROYED, - - // _rawObject : null, - '_rect' : null, // - - /** - * 最後に計測したフォントサイズを保持している。ツリーが変更されると削除される。 - * @type {number} - * @private - * @alias Node.prototype._fontSize - */ - '_fontSize' : 0, - - /** - * NodeList と動作を一致させるためのプロパティ。常に 1。 - * @type {number} - * @alias Node.prototype.length - */ - length : 1, - - /** - * 親 Node。 - * @type {Node} - * @alias Node.prototype.parent - */ - parent : null, // remove された枝も親子構造は維持している。 - - /** - * 子 Node リスト - * @type {Array} - * @private - * @alias Node.prototype._xnodes - */ - '_xnodes' : null, - - /** - * GPU レイヤーに転送されている場合、その一番親となっている Node。未実装。 - * @type {Node} - * @private - * @alias Node.prototype._gpuParent - */ - '_gpuParent' : null, - - /** - * タグ名。テキストノードの場合は空文字列。 - * @type {string} - * @private - * @alias Node.prototype._tag - */ - '_tag' : '', - - /** - * テキストコンテンツ。テキストノードで使用。 - * @type {string} - * @private - * @alias Node.prototype._text - */ - '_text' : '', - - /** - * id - * @type {string} - * @private - * @alias Node.prototype._id - */ - '_id' : '', - - /** - * クラス名。複数のクラスが設定されている場合、スペース区切り。 - * @type {string} - * @private - * @alias Node.prototype._className - */ - '_className' : '', // - - /** - * 属性。 - * @type {object} - * @private - * @alias Node.prototype._attrs - */ - '_attrs' : null, // see X_Node_Attr - - /** - * まだコミットされていない属性。 - * @type {object} - * @private - * @alias Node.prototype._newAttrs - */ - '_newAttrs' : null, - - /** - * 属性を文字列にしたもの。 color="red" size="8" - * @type {object} - * @private - * @alias Node.prototype._attrText - */ - '_attrText' : '', - - /** - * スタイル。 - * @type {object} - * @private - * @alias Node.prototype._css - */ - '_css' : null, - - /** - * cssText - * @type {string} - * @private - * @alias Node.prototype._cssText - */ - '_cssText' : '', - - /** - * アニメーション用オブジェクト。 - * @type {object} - * @private - * @alias Node.prototype._anime - */ - '_anime' : null, - - /* - * TODO Node の継承ができない! - */ - 'Constructor' : function( v ){ - var uid = X_Node_CHASHE.length, - css, xnodes, xnode, parent; - - if( X_Node_newByTag ){ - X_Node_newByTag = false; - this[ '_tag' ] = v.toUpperCase(); - arguments[ 1 ] && this[ 'attr' ]( arguments[ 1 ] ); - css = arguments[ 2 ]; - css && this[ X_Type_isString( css ) ? 'cssText' : 'css' ]( css ); - } else - if( X_Node_newByText ){ - X_Node_newByText = false; - this[ '_text' ] = v; - } else { - if( 1 < arguments.length ) return new X_NodeList( arguments ); - if( X_Type_isArray( v ) && v.length ) return new X_NodeList( v ); - - switch( X_Node_getType( v ) ){ - case X_Node_TYPE.XNODE : - case X_Node_TYPE.XNODE_LIST : - return v; - - case X_Node_TYPE.RAW_HTML : - if( xnode = X_Node_getXNode( v ) ) return xnode; - // v.parentNode || v.parentElement : dom1 || dom0 - this.parent = ( parent = v.parentNode || v.parentElement ) && parent.tagName /* ie7- */ && X_Node_getXNode( parent ); - this[ '_rawObject' ] = v; - this[ '_tag' ] = v.tagName.toUpperCase(); - this[ '_id' ] = v.id; - this[ '_className' ] = v.className; - - this[ 'cssText' ]( v.style.cssText ); - this[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; // X_Node_State.DIRTY_CSS を落とす - - // TODO attr の回収は不可能、、、? - if( X_UA_DOM.IE4 ){ - v.setAttribute( 'UID', '' + uid ); - } else { - v[ 'UID' ] = uid; - }; - // childNodes... - break; - - case X_Node_TYPE.RAW_TEXT : - if( xnode = X_Node_getXNode( v ) ) return xnode; - this.parent = X_Node_getXNode( v.parentNode ); - this[ '_rawObject' ] = v; - this[ '_text' ] = v.data; - v[ 'UID' ] = uid; - break; - - case X_Node_TYPE.HTML_STRING : - case X_Node_TYPE.STRING : - if( xnodes = X_HtmlParser_parse( v, true ) && 1 < xnodes.length ) return new X_NodeList( xnodes ); - if( xnodes.length ) return xnodes[ 0 ]; - return X_Node_none; - - default : - if( X_Node_none ) return X_Node_none; - this.length = 0; - return; - }; - }; - - if( this.parent && ( this.parent[ '_flags' ] & X_Node_State.IN_TREE ) ){ - this[ '_flags' ] |= X_Node_State.IN_TREE; - }; - this[ '_flags' ] |= X_Node_State.EXIST; - X_Node_CHASHE[ this[ '_uid' ] = uid ] = this; - - X_EventDispatcher_systemListen( this, X_EVENT_BEFORE_KILL_INSTANCE, X_Node_onBeforeKill ); - }, - - // attr - // css, cssText - // find - // animate, stop - - 'create' : X_Node_create, - - 'createAt' : X_Node_createAt, - - 'createText' : X_Node_createText, - - 'createTextAt' : X_Node_createTextAt, - - 'clone' : X_Node_clone, - - 'append' : X_Node_append, - - 'appendAt' : X_Node_appendAt, - - 'appendTo' : X_Node_appendTo, - - 'prev' : X_Node_prev, - - 'next' : X_Node_next, - - 'swap' : X_Node_swap, - - 'remove' : X_Node_remove, - - 'empty' : X_Node_empty, - - 'contains' : X_Node_contains, - - 'getChildAt' : X_Node_getChildAt, - - 'numChildren' : X_Node_numChildren, - - 'firstChild' : X_Node_firstChild, - - 'lastChild' : X_Node_lastChild, - - 'getOrder' : X_Node_getOrder, - - 'className' : X_Node_className, - 'addClass' : X_Node_addClass, - 'removeClass' : X_Node_removeClass, - 'toggleClass' : X_Node_toggleClass, - 'hasClass' : X_Node_hasClass, - - 'html' : X_Node_html, - 'text' : X_Node_text, - 'call' : X_Node_call, - 'each' : X_Node_each - - } -); - -function X_Node_getType( v ){ - if( v === '' ) return X_Node_TYPE.STRING; - if( !v ) return 0; - if( v === window ) return X_Node_TYPE.WINDOW; - if( v === document ) return X_Node_TYPE.DOCUMENT; - if( v.constructor === Node ) return X_Node_TYPE.XNODE; - if( v.constructor === X_NodeList ) return X_Node_TYPE.XNODE_LIST; - if( X_Type_isHTMLElement( v ) ) return X_Node_TYPE.RAW_HTML; - if( v.nodeType === 3 ) return X_Node_TYPE.RAW_TEXT; - if( X_Type_isString( v ) ){ - return '<' === v.charAt( 0 ) && v.charAt( v.length - 1 ) === '>' ? X_Node_TYPE.HTML_STRING : X_Node_TYPE.STRING; - }; - if( v[ 'instanceOf' ] && v[ 'instanceOf' ]( Node ) ) return X_Node_TYPE.XNODE; - return 0; -}; -function X_Node_getXNode( v ){ - var uid, i, chashe, xnode; - switch( X_Node_getType( v ) ){ - case X_Node_TYPE.XNODE : - case X_Node_TYPE.XNODE_LIST : - return v; - case X_Node_TYPE.RAW_HTML : - // fake TextNode too. - if( X_UA_DOM.IE4 ){ - uid = v.getAttribute( 'UID' ); - return uid && X_Node_CHASHE[ uid ]; - }; - return v[ 'UID' ] && X_Node_CHASHE[ v[ 'UID' ] ]; - case X_Node_TYPE.WINDOW : - return X_ViewPort; - case X_Node_TYPE.DOCUMENT : - return X_ViewPort_document; - case X_Node_TYPE.RAW_TEXT : - if( v[ 'UID' ] ) return X_Node_CHASHE[ v[ 'UID' ] ]; - for( chashe = X_Node_CHASHE, i = chashe.length; i; ){ - if( ( xnode = X_Node_CHASHE[ --i ] ) && ( xnode[ '_rawObject' ] === v ) ) return xnode; - }; - }; -}; - -function X_Node_getRoot( xnode ){ - return X_ViewPort_document; - //return X_Node_body[ '_rawObject' ].documentElement ? node : node.ownerDocument || node.document; -}; - // XMLかどうかを判別する -var X_Node_isXmlDocument = - X_UA_DOM.IE4 ? - X_emptyFunction : - (function( root ){ - if( X_Type_isBoolean( root.isXML ) ) return root.isXML; - return root.isXML = root[ '_rawObject' ].createElement( 'p' ).tagName !== root[ '_rawObject' ].createElement( 'P' ).tagName; - }), - X_Node_CHASHE = [], - X_Node_none = X_Node_CHASHE[ 0 ] = Node(), - X_Node_html, // = X_Node_CHASHE[ 1 ] - X_Node_head, // = X_Node_CHASHE[ 2 ] - X_Node_body, // = X_Node_CHASHE[ 3 ] - X_Node_systemNode, // = X_Node_CHASHE[ ? ] - X_Node_fontSizeNode, -/* - * remove : - * X_Node_reserveRemoval = [] に追加。commitUpdate で remove - * add : - * X_Node_reserveRemoval にいたら消す, new_parent[ '_xnodes' ] に挿入 - */ - X_Node_reserveRemoval = []; - - -var X_Node__ie4getRawNode = X_UA_DOM.IE4 && function ( that ){ - return that[ '_rawObject' ] || - ( that[ '_rawObject' ] = document.all[ 'ie4uid' + that[ '_uid' ] ] ) || - ( that[ '_id' ] && ( that[ '_rawObject' ] = document.all[ that[ '_id' ] ] ) ); - }; - - -function X_Node_toggleInTreeFlag( xnodes, flag ){ - var i = xnodes.length, xnode; - for( ; i; ){ - xnode = xnodes[ --i ]; - flag ? ( xnode[ '_flags' ] |= X_Node_State.IN_TREE | X_Node_State.DIRTY_POSITION ) : ( xnode[ '_flags' ] &= ~X_Node_State.IN_TREE & ~X_Node_State.IE5_DISPLAY_NONE_FIX ); - xnode[ '_xnodes' ] && X_Node_toggleInTreeFlag( xnode[ '_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 ); - }; - }; - }; -}; - -/** - * タグ名等を指定して新規に子ノードを作成し、現在のノードに追加する。 - * @alias Node.prototype.create - * @param {string} [tag] タグ名 - * @param {object} [opt_attrs=] 属性 - * @param {object|string} [opt_css=] css - * @return {Node} 新規作成されたノード - * @example var child = parent.create( 'div' ); - */ -function X_Node_create( tag, opt_attrs, opt_css ){ - var xnode; - if( !this[ '_tag' ] ) return; - this[ 'append' ]( xnode = X_Doc_create( tag, opt_attrs, opt_css ) ); - return xnode; -}; -/** - * 挿入位置とタグ名等を指定して新規に子ノードを作成し、現在のノードに挿入する。 - * @alias Node.prototype.createAt - * @param {number} [index] 挿入位置 - * @param {string} [tag] タグ名 - * @param {object} [opt_attrs=] 属性 - * @param {object|string} [opt_css=] css - * @return {Node} 新規作成されたノード - * @example var child = parent.create( 2, 'div' ); - */ -function X_Node_createAt( index, tag, opt_attrs, opt_css ){ - var xnode; - if( !this[ '_tag' ] ) return; - this[ 'appendAt' ]( index, xnode = X_Doc_create( tag, opt_attrs, opt_css ) ); - return xnode; -}; - -/** - * テキストを指定して新規にテキストノードを作成し、現在のノードに挿入する。 - * @alias Node.prototype.createText - * @param {string} [tag] テキスト - * @return {Node} 新規作成されたノード - */ -function X_Node_createText( text ){ - var xnode; - if( !this[ '_tag' ] ) return; - this[ 'append' ]( xnode = X_Doc_createText( text ) ); - return xnode; -}; -/** - * 挿入位置とテキストを指定して新規に子ノードを作成し、現在のノードに挿入する。 - * @alias Node.prototype.createTextAt - * @param {number} [index] 挿入位置 - * @param {string} [tag] テキスト - * @return {Node} 新規作成されたノード - */ -function X_Node_createTextAt( index, text ){ - var xnode; - if( !this[ '_tag' ] ) return; - this[ 'appendAt' ]( index, xnode = X_Doc_createText( text ) ); - return xnode; -}; - -/** - * Node のクローンを作成し返す。id もクローンされる点に注意。イベントリスナはクローンされない。 - * http://d.hatena.ne.jp/think49/20110724/1311472811 - * http://d.hatena.ne.jp/uupaa/20100508/1273299874 - * @alias Node.prototype.clone - * @param {boolean} [opt_clone_children] 子要素のクローンを行うか? - * @return {Node} - */ -function X_Node_clone( opt_clone_children ){ - var xnode, xnodes, i, l; - if( this[ '_tag' ] ){ - X_Node_newByTag = true; - xnode = Node( this[ '_tag' ], X_Object_clone( this[ '_attrs' ] ), X_Object_clone( this[ '_css' ] ) ) - [ 'attr' ]( { 'id' : this[ '_id' ] } ) - [ 'className' ]( this[ '_className' ] ); - if( opt_clone_children && ( xnodes = this[ '_xnodes' ] ) && ( l = xnodes.length ) ){ - for( i = 0; i < l; ++i ){ - xnode[ 'append' ]( xnodes[ i ][ 'clone' ]( true ) ); - }; - }; - return xnode; - }; - X_Node_newByText = true; - return Node( this[ '_text' ] ); -}; - -/** - * ノードを子配列の最後に追加する。文字列が渡された場合、HTMLパーサーによって Node ツリーを作成して追加する。HtmlElement, TextNode の場合は内部使用専用。 - * @alias Node.prototype.append - * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。 - * @return {Node} 自身。チェインメソッド - * @example // - * myNode.append( node ); - * myNode.append( node, '<span>Hello,</span>', 'world.' ); - */ -function X_Node_append( v ){ - var i, l, xnodes, frg; - if( !this[ '_tag' ] ) return; - - if( 1 < ( l = arguments.length ) ){ - for( i = 0; i < l; ++i ){ - this[ 'append' ]( arguments[ i ] ); - }; - return this; - }; - - if( !( xnodes = this[ '_xnodes' ] ) ) this[ '_xnodes' ] = xnodes = []; - - switch( X_Node_getType( v ) ){ - case X_Node_TYPE.RAW_HTML : - case X_Node_TYPE.RAW_TEXT : - v = Node( v ); - break; - case X_Node_TYPE.HTML_STRING : - case X_Node_TYPE.STRING : - return X_Node_append.apply( this, X_HtmlParser_parse( v, true ) ); - case X_Node_TYPE.XNODE : - // 親の xnodes から v を消す - v.parent && v[ 'remove' ](); - // IE4 でテキストノードの追加、FIXED 済でない場合、親に要素の追加を通知 - if( X_UA[ 'IE4' ] && !v[ '_tag' ] && ( this[ '_flags' ] & X_Node_State.IE4_FIXED ) === 0 ) this[ '_flags' ] |= X_Node_State.IE4_DIRTY_CHILDREN; - break; - default : - return this; - }; - - v.parent = this; - xnodes[ xnodes.length ] = v; - if( this[ '_flags' ] & X_Node_State.IN_TREE ){ - v[ '_flags' ] |= X_Node_State.IN_TREE; - v[ '_xnodes' ] && X_Node_toggleInTreeFlag( v[ '_xnodes' ], true ); - X_Node_reserveUpdate(); - }; - return this; -}; - -/** - * ノードを挿入位置に追加する。 - * @alias Node.prototype.appendAt - * @param {number} index 挿入位置 0以上 - * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。 - * @return {Node} 自身。チェインメソッド - * @example myNode.appendAt( 1, node ); - */ -function X_Node_appendAt( start, v ){ - var xnodes, l, i; - - if( !this[ '_tag' ] ) return this; - - l = arguments.length; - if( !( xnodes = this[ '_xnodes' ] ) ) xnodes = this[ '_xnodes' ] = []; - - if( xnodes.length <= start ){ - if( l === 2 ) return this[ 'append' ]( v ); - for( i = 1; i < l; ++i ){ - this[ 'append' ]( arguments[ i ] ); - }; - return this; - }; - if( start < 0 ) start = 0; - if( 2 < l ){ - for( ; l; ){ - this[ 'appendAt' ]( start, arguments[ --l ] ); - }; - return this; - }; - - switch( X_Node_getType( v ) ){ - case X_Node_TYPE.RAW_HTML : - case X_Node_TYPE.RAW_TEXT : - v = Node( v ); - break; - case X_Node_TYPE.HTML_STRING : - case X_Node_TYPE.STRING : - v = X_HtmlParser_parse( v, true ); - for( i = v.length; i; ){ - this[ 'appendAt' ]( start, v[ --i ] ); - }; - return this; - case X_Node_TYPE.XNODE : - // 親の xnodes から v を消す - if( v.parent ){ - if( v.parent === this ){ - i = v[ 'getOrder' ](); - if( i === start ) return this; - if( i < start ) --start; - }; - v[ 'remove' ](); - }; - // IE4 でテキストノードの追加、FIXED 済でない場合、親に要素の追加を通知 - if( X_UA[ 'IE4' ] && !v[ '_tag' ] && ( this[ '_flags' ] & X_Node_State.IE4_FIXED ) === 0 ) this[ '_flags' ] |= X_Node_State.IE4_DIRTY_CHILDREN; - break; - default : - return this; - }; - - v.parent = this; - this[ '_xnodes' ].splice( start, 0, v ); - if( this[ '_flags' ] & X_Node_State.IN_TREE ){ - v[ '_flags' ] |= X_Node_State.IN_TREE; - v[ '_xnodes' ] && X_Node_toggleInTreeFlag( v[ '_xnodes' ], true ); - X_Node_reserveUpdate(); - }; - return this; -}; - -/** - * ノードを親に追加する。戻り値は子ノードなので、続けて操作が出来る。 - * @alias Node.prototype.appendTo - * @param {Node|string|HTMLElement} [parent] HTMLElement は内部のみ。 - * @param {number} [opt_index=-1] 挿入位置。省略した場合は最後に追加する。 - * @return {Node} 自身。チェインメソッド - * @example childNode.appendTo( parentNode, 1 ); - */ -function X_Node_appendTo( parent, opt_index ){ - switch( X_Node_getType( parent ) ){ - case X_Node_TYPE.RAW_HTML : - parent = Node( parent ); - break; - case X_Node_TYPE.HTML_STRING : - parent = X_HtmlParser_parse( parent, true ); - parent = parent[ 0 ] || parent; - case X_Node_TYPE.XNODE : - break; - default : - return this; - }; - X_Type_isFinite( opt_index ) ? parent[ 'appendAt' ]( opt_index, this ) : parent[ 'append' ]( this ); - return this; -}; - - -/** - * ノードの直前の要素を取得。または直前に挿入。挿入する要素が先にいる兄弟でも正しく動作する。 - * @alias Node.prototype.prev - * @param {Node|string|HTMLElement|TextNode} [...v] HTMLElement と TextNode は内部のみ。 - * @return {Node} 自身。チェインメソッド - * @example childNode.prev( prevNode ); - */ -function X_Node_prev( v ){ - var parent = this.parent, xnodes, i, l; - - // getter - if( v === undefined ){ - if( !parent ) return; - xnodes = parent[ '_xnodes' ]; - i = xnodes.indexOf( this ); - return 0 < i ? xnodes[ i - 1 ] : v; - }; - - if( !parent ) return this; - - l = arguments.length; - if( 1 < l ){ - for( i = 0; l; ++i ){ - parent[ 'appendAt' ]( this[ 'getOrder' ]() - i, arguments[ --l ] ); - }; - return this; - }; - parent[ 'appendAt' ]( this[ 'getOrder' ](), v ); - return this; -}; - -/** - * ノードの直後の要素を取得。または直後に挿入。挿入する要素が先にいる兄弟でも正しく動作する。 - * @alias Node.prototype.next - * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。 - * @return {Node} 自身。チェインメソッド - * @example childNode.next( prevNode ); - */ -function X_Node_next( v ){ - var parent = this.parent, xnodes, i, l, start; - - // getter - if( v === undefined ){ - if( !parent ) return; - xnodes = parent[ '_xnodes' ]; - i = xnodes.indexOf( this ); - return ++i < xnodes.length ? xnodes[ i ] : v; - }; - - if( !parent ) return this; - - l = arguments.length; - start = this[ 'getOrder' ]() + 1; - - if( parent[ '_xnodes' ].length <= start ){ - for( i = 0; i < l; ++i ){ - parent[ 'append' ]( arguments[ i ] ); - }; - } else - if( 1 < l ){ - for( ; l; ){ - parent[ 'appendAt' ]( this[ 'getOrder' ]() + 1, arguments[ --l ] ); - }; - } else { - parent[ 'appendAt' ]( start, v ); - }; - return this; -}; - -/** - * 要素の入れ替え。自身は remove() される。 - * @alias Node.prototype.swap - * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。 - * @return {Node} 自身。チェインメソッド - * @example node.swap( newNode ); - */ -function X_Node_swap( v ){ - if( !this.parent ) return this; - return arguments.length === 1 ? this[ 'prev' ]( v )[ 'remove' ]() : X_Node_prev.apply( this, arguments )[ 'remove' ](); -}; - -/** - * 要素を抜く。 - * @alias Node.prototype.remove - * @return {Node} 自身。チェインメソッド - * @example node.remove(); - */ -function X_Node_remove(){ - var parent = this.parent, - elm; - - if( !parent ) return this; - - delete this.parent; - parent[ '_xnodes' ].splice( parent[ '_xnodes' ].indexOf( this ), 1 ); - - if( this[ '_flags' ] & X_Node_State.IN_TREE ){ - this[ '_flags' ] &= ~X_Node_State.IN_TREE & ~X_Node_State.IE5_DISPLAY_NONE_FIX; - this[ '_xnodes' ] && X_Node_toggleInTreeFlag( this[ '_xnodes' ], false ); - - if( X_UA_DOM.IE4 ){ - elm = this[ '_rawObject' ] || X_Node__ie4getRawNode( this ); - if( elm ){ - X_Node_reserveRemoval[ X_Node_reserveRemoval.length ] = this; - X_Node_reserveUpdate(); - } else - if( !this[ '_tag' ] && ( parent[ '_flags' ] & X_Node_State.IE4_FIXED ) === 0 ){ - parent[ '_flags' ] |= X_Node_State.IE4_DIRTY_CHILDREN; - }; - } else { - elm = this[ '_rawObject' ]; - if( elm && elm.parentNode && elm.parentNode.tagName ){ - X_Node_reserveRemoval[ X_Node_reserveRemoval.length ] = this; - X_Node_reserveUpdate(); - }; - }; - }; - return this; -}; - -/** - * 子要素を破棄する。子要素は kill() されます。 - * @alias Node.prototype.empty - * @return {Node} 自身。チェインメソッド - * @example node.empty(); - */ -function X_Node_empty(){ - var xnodes = this[ '_xnodes' ], i; - if( xnodes && ( i = xnodes.length ) ){ - for( ; i; ){ - xnodes[ --i ][ 'kill' ](); - }; - xnodes.length = 0; - }; - return this; -}; - -function X_Node_onBeforeKill( e ){ - var xnodes = this[ '_xnodes' ], i, elm; - - 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' ] && X_EventDispatcher_unlistenAll( this ); // イベントの退避 - - if( xnodes && ( i = xnodes.length ) ){ - for( ; i; ){ - X_Node_onBeforeKill.call( xnodes[ --i ] ); - }; - }; - - delete X_Node_CHASHE[ this[ '_uid' ] ]; - - if( e ){ - this[ 'remove' ](); - if( X_Node_reserveRemoval[ X_Node_reserveRemoval.length - 1 ] === this ){ - this[ '_flags' ] &= ~X_Node_State.EXIST; - return X_Callback_PREVENT_DEFAULT; - }; - }; - return X_Callback_NONE; -}; - - -/** - * 要素を子以下に持つか?調べる。 - * @alias Node.prototype.contains - * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。 - * @return {boolean} - * @example node.contains( testNode ); - */ -function X_Node_contains( v ){ - var elm, type, xnodes, i; - if( !v || !this[ '_tag' ] || this === v ) return false; - // contains ie4+ - if( ( elm = this[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ) ) && document.contains && ( type = X_Node_getType( v ) ) && ( type === X_Node_TYPE.RAW_HTML || type === X_Node_TYPE.RAW_TEXT ) ){ - return elm.contains( v ); - }; - - //if( document.compareDocumentPosition ){ - // - //}; - xnodes = this[ '_xnodes' ]; - if( !xnodes || !xnodes.length ) return false; - if( xnodes.indexOf( v ) !== -1 ) return true; // fast - for( i = xnodes.length; i; ){ - if( xnodes[ --i ][ 'contains' ]( v ) ) return true; - }; - return false; -}; - -/** - * index の子要素を取得する。 - * @alias Node.prototype.getChildAt - * @param {number} index 取得する子ノードの位置。0~ - * @return {Node} 子要素 - * @example child1 = parent.getChildAt(1); - */ -function X_Node_getChildAt( i ){ - var xnodes = this[ '_xnodes' ]; - return xnodes && 0 <= i && i < xnodes.length && xnodes[ i ]; -}; - -/** - * 子要素の数を取得する。 - * @alias Node.prototype.numChildren - * @return {number} 子要素の数。 - * @example n = parent.numChildren(); - */ -function X_Node_numChildren(){ - var xnodes = this[ '_xnodes' ]; - return xnodes ? xnodes.length : 0; -}; - -/** - * 最初の子要素を取得する。 - * @alias Node.prototype.firstChild - * @return {Node} 最初の子要素 - * @example child0 = parent.firstChild(); - */ -function X_Node_firstChild(){ - return this[ '_xnodes' ] && this[ '_xnodes' ][ 0 ]; -}; - -/** - * 最後の子要素を取得する。 - * @alias Node.prototype.lastChild - * @return {Node} 最後の子要素 - * @example lastChild = parent.lastChild(); - */ -function X_Node_lastChild(){ - var xnodes = this[ '_xnodes' ]; - return xnodes && xnodes[ xnodes.length - 1 ]; -}; - -/** - * 要素の index 位置を取得する。 - * @alias Node.prototype.getOrder - * @return {number} index -1 の場合、親を持たない。 - * @example index = node.getOrder(); - */ -function X_Node_getOrder(){ - var parent = this.parent; - return this === X_Node_html ? - 0 : - parent ? - parent[ '_xnodes' ].indexOf( this ) : - -1; -}; - -/** - * className の取得と設定。 - * @alias Node.prototype.className - * @return {string|Node} getter の場合 class 文字列、setter の場合自身。 - * @example // getter - * className = node.className(); - * // setter - * node.className( 'myClass myClass_new' ); - */ -function X_Node_className( v ){ - var node, _, __; - // getter - if( v === undefined ) return this[ '_className' ]; - - // setter - if( this[ '_className' ] === v ) return this; - if( !v || !X_Type_isString( v ) ){ - delete this[ '_className' ]; - } else { - // cleanup - _ = ' '; - __ = ' '; - while( v.indexOf( __ ) !== -1 ){ v = v.split( __ ).join( _ ); }; - v.charAt( 0 ) === _ && ( v = v.substr( 1 ) ); - v.lastIndexOf( _ ) === 0 && ( v = v.substr( 0, v.length - 1 ) ); - - if( this[ '_className' ] === v ) return this; - v ? ( this[ '_className' ] = v ) : delete this[ '_className' ]; - }; - this[ '_flags' ] |= X_Node_State.DIRTY_CLASSNAME; - this[ '_flags' ] & X_Node_State.IN_TREE && X_Node_reserveUpdate(); - return this; -}; - -/** - * className の追加。 - * @alias Node.prototype.addClass - * @param {string} className スペース区切りで複数のクラスを追加できる。 - * @return {Node} 自身。 - * @example node.addClass( 'myClass myClass_new' ); - */ -function X_Node_addClass( v ){ - var names = v.split( ' ' ), - i = names.length, - _class = this[ '_className' ], - name; - v = ''; - for( ; i; ){ - name = names[ --i ]; - if( !name ) continue; - !this[ 'hasClass' ]( name ) && ( v += ( v ? ' ' : '' ) + name ); - }; - return v ? this[ 'className' ]( ( _class ? _class + ' ' : '' ) + v ) : this; -}; - -/** - * className の削除。 - * @alias Node.prototype.removeClass - * @param {string} className スペース区切りで複数のクラスを削除できる。 - * @return {Node} 自身。 - * @example node.removeClass( 'myClass myClass_new' ); - */ -function X_Node_removeClass( v ){ - var _ = ' ', - _class = this[ '_className' ], - names = v.split( _ ), - classNames, i, f, j; - - if( !_class ) return this; - for( classNames = _class.split( _ ), i = classNames.length; i; ){ - _class = classNames[ --i ]; - for( j = names.length; j; ){ - if( _class === names[ --j ] ){ - classNames.splice( i, 1 ); - names.splice( j, 1 ); - f = true; - break; - }; - }; - }; - return f ? this[ 'className' ]( classNames.join( _ ) ) : this; -}; - -/** - * className の更新。 - * @alias Node.prototype.toggleClass - * @param {string} className スペース区切りで複数のクラスを削除できる。 - * @param {boolean} [opt_toggle=] true はクラスの追加。false はクラスの削除。undefined はクラスのトグル。 - * @return {Node} 自身。 - * @example node.toggleClass( 'myClass myClass_new', !!n ); - */ -function X_Node_toggleClass( v, opt_toggle ){ - var names, i, name; - if( opt_toggle !== undefined ){ - return !opt_toggle ? this[ 'removeClass' ]( v ) : this[ 'addClass' ]( v ); - }; - names = v.split( ' ' ); - for( i = names.length; i; ){ - name = names[ --i ]; - this[ 'hasClass' ]( name ) ? this[ 'removeClass' ]( name ) : this[ 'addClass' ]( name ); - }; - return this; -}; - -/** - * className を持つか。 - * @alias Node.prototype.hasClass - * @param {string} className スペース区切りで複数のクラスを削除できる。 - * @return {boolean} - * @example node.hasClass( 'myClass myClass_new' ); - */ -function X_Node_hasClass( v ){ - var _ = ' ', - _class = this[ '_className' ], - i, name; - if( _class === v ) return true; - if( !_class ) return false; - - _class = _ + _class + _; - if( _class.indexOf( _ + v + _ ) !== -1 ) return true; // lucky hit - - for( v = v.split( _ ), i = v.length; i; ){ - name = v[ --i ]; - if( name === '' ) continue; - if( _class.indexOf( _ + name + _ ) === -1 ) return false; - }; - return true; -}; - -/** - * innerHTML 取得・設定。outerHTML が欲しい場合は、xnode.call('outerHTML') とできる。 - * @alias Node.prototype.html - * @param {string} [html=] html文字列 - * @return {string|Node} - * @example node.html( '' ); - */ -function X_Node_html( html ){ - var _ = '', q = '"', xnodes, n, i, l; - // setter - if( html !== undefined ){ // String 以外に Number や false null なども許可 - if( !this[ '_tag' ] ) return this[ 'text' ]( html ); - return html ? this[ 'empty' ]()[ 'append' ].apply( this, X_HtmlParser_parse( html, true ) ) : this[ 'empty' ](); - }; - - // getter - if( !this[ '_tag' ] ){ - return this[ '_text' ]; - }; - - this[ '_flags' ] & X_Node_State.OLD_CSSTEXT && X_Node_CSS_objToCssText( this ); - - html = !X_Node_outerXNode ? [] : [ - '<', this[ '_tag' ], - this[ '_id' ] ? ' id="' + this[ '_id' ] + q : _, - this[ '_className' ] ? ' class="' + this[ '_className' ] + q : _, - this[ '_flags' ] & X_Node_State.OLD_ATTRTEXT ? X_Node_Attr_objToAttrText( this ) : this[ '_attrText' ], - this[ '_cssText' ] ? ' style="' + this[ '_cssText' ] + q : _, - '>' ]; - - n = html.length; - if( ( xnodes = this[ '_xnodes' ] ) && ( l = xnodes.length ) ){ - if( !X_Node_outerXNode ) X_Node_outerXNode = this; - for( i = 0; i < l; ++i ){ - html[ n ] = xnodes[ i ][ 'html' ](); - ++n; - }; - if( X_Node_outerXNode === this ) X_Node_outerXNode = null; - }; - !X_Node_outerXNode || X_Dom_DTD_EMPTY[ this[ '_tag' ] ] || ( html[ n ] = '<\/' + this[ '_tag' ] + '>' ); - return html.join( _ ); -}; - -/* - * null が来たら '', 数値等が来たら文字列化 - */ -/** - * textContent 取得・設定。null が来たら '', 数値等が来たら文字列化 - * @alias Node.prototype.text - * @param {string} [text=] - * @return {string|Node} - * @example node.text( 'Hello, world!' ); - */ -function X_Node_text( text ){ - var xnodes, texts, i, l; - // setter - if( text !== undefined ){ - if( text === null ) text = ''; - text += ''; - - if( !this[ '_tag' ] ){ - if( this[ '_text' ] !== text ){ - text ? ( this[ '_text' ] = text ) : delete this[ '_text' ]; - this[ '_flags' ] |= X_Node_State.DIRTY_CONTENT; - this[ '_flags' ] & X_Node_State.IN_TREE && X_Node_reserveUpdate(); - }; - return this; - }; - 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; - }; - // getter - if( this[ '_tag' ] ){ - if( ( xnodes = this[ '_xnodes' ] ) && ( l = xnodes.length ) ){ - for( texts = [], i = 0; i < l; ++i ){ - texts[ i ] = xnodes[ i ][ 'text' ](); - }; - return texts.join( '' ); - }; - return ''; - }; - return this[ '_text' ]; -}; - -/* - * HTML要素に対して name の関数を実行しその戻り値を返す。関数に渡す引数も任意に設定できる。 - */ -function X_Node_call( name /*, opt_args... */ ){ - var l = arguments.length - 1, - raw, func, args, params, i; - - switch( name ){ - case 'nodeType' : - return this[ '_tag' ] ? 1 : 3; - case 'outerHTML' : - X_Node_outerXNode = X_Node_body; // == true ならなんでもよい。型を合わすために xbody にしている - v = this[ 'html' ](); - X_Node_outerXNode = null; - return v; - case 'treeIsDirty' : - return !!X_Node_updateTimerID; - case 'fontSize' : - return X_Node_CSS_getCharSize( this ); - case 'inGPU' : - return !!( this[ '_flags' ] & ( X_Node_State.GPU_NOW | X_Node_State.GPU_RELEASE_RESERVED ) ); - }; - - X_Node_updateTimerID && X_Node_startUpdate(); - - raw = this[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ); - if( !raw ) return; - - if( name === 'scrollTo' ){ - raw.scrollLeft = arguments[ 1 ] || 0; - raw.scrollTop = arguments[ 2 ] || 0; - return; - }; - - func = raw[ name ]; - if( X_Type_isFunction( func ) ){ - if( l ){ - args = X_Object_cloneArray( arguments ); - args.shift(); - return func.apply( raw, args ); - }; - return raw[ name ](); - } else - if( X_Type_isUnknown( func ) ){ - // typeof func === unknown に対策 - // http://la.ma.la/blog/diary_200509031529.htm - if( l ){ - args = X_Object_cloneArray( arguments ); - args.shift(); - - params = []; - for( i = 0; i < l; ++i ){ - params[ i ] = '_' + i; - }; - params = params.join( ',' ); - return Function( - params, - [ 'return this.', name, '(', params, ')' ].join( '' ) - ).apply( raw, args ); - }; - return raw[ name ](); - }; -}; - -/* - * xnode を this として関数を実行する。 NodeList.each と動作を合わせてあるため関数の戻り値は破棄される。 - * 関数に渡す引数も任意に設定できる。 - */ -function X_Node_each( func /*, opt_args */ ){ - var args; - if( 1 < arguments.length ){ - args = X_Object_cloneArray( arguments ); - args[ 0 ] = 0; - func.apply( this, args ); - } else { - func.call( this, 0 ); - }; - return this; -}; - - -/* -------------------------------------- - * Async commit update - * - * TODO Timer や DOM イベントの呼び出しの最後に、まだ一度も commitUpdate していないなら commitUpdate してしまう。 - */ - -function X_Node_reserveUpdate(){ - if( !X_Node_updateTimerID ) X_Node_updateTimerID = X_Timer_requestFrame( X_Node_startUpdate ); -}; - -var X_Node_updateReservedByReleaseGPU = false; - -function X_Node_startUpdate( time ){ - var removal, i, xnode; - - if( !X_Node_updateTimerID || X_ViewPort_readyState < X_EVENT_INIT ){ - return; - }; - - X_Timer_cancelFrame( X_Node_updateTimerID ); - X_Node_updateTimerID = 0; - - if( time ){ - // X.Timer 経由でないと発火しない このイベントでサイズを取ると無限ループに - X_System[ '_listeners' ] && X_System[ '_listeners' ][ X_EVENT_BEFORE_UPDATE ] && X_System[ 'dispatch' ]( X_EVENT_BEFORE_UPDATE ); - }; - - removal = X_Node_reserveRemoval; - - if( i = removal.length ){ - for( ; i; ){ - xnode = removal[ --i ]; - // TODO GPU レイヤーの子の場合、remove をスキップする。 非GPU レイヤーへ apppend される場合、clone する? - X_Node__actualRemove( xnode ); - ( xnode[ '_flags' ] & X_Node_State.EXIST ) === 0 && xnode[ 'kill' ](); - }; - removal.length = 0; - }; - - if( X_Node_html[ '_flags' ] & X_Node_BitMask_IS_DIRTY ){ - X_Node__commitUpdate( X_Node_html, X_Node_html[ '_rawObject' ].parentNode, null, X_Node_html[ '_flags' ] ); - } else { - X_Node__commitUpdate( X_Node_head, X_Node_head[ '_rawObject' ].parentNode, null, X_Node_head[ '_flags' ] ); - X_Node__commitUpdate( X_Node_body, X_Node_body[ '_rawObject' ].parentNode, null, X_Node_body[ '_flags' ] ); - }; - - if( X_Node_updateReservedByReleaseGPU ){ - X_Node_reserveUpdate(); - X_Node_updateReservedByReleaseGPU = false; - }; - - if( time ){ - // X.Timer 経由でないと発火しない このイベントでサイズを取ると無限ループに - X_System[ '_listeners' ] && X_System[ '_listeners' ][ X_EVENT_UPDATED ] && X_System[ 'dispatch' ]( X_EVENT_UPDATED ); - } else { - X_System[ '_listeners' ] && X_System[ '_listeners' ][ X_EVENT_UPDATED ] && X_System[ 'asyncDispatch' ]( X_EVENT_UPDATED ); - }; - - X_ViewPort[ '_listeners' ] && X_ViewPort[ '_listeners' ][ X_EVENT_AFTER_UPDATE ] && X_ViewPort[ 'asyncDispatch' ]( X_EVENT_AFTER_UPDATE ); -}; - -/* - * 1. GPU_NOW の場合、子の変更は行わない - * 2. GPU解放予約 の場合//、この要素のみ変更を行う。rAF 後にさらに更新するためフラグを立てる。 - * 3. GPU予約 -> GPU - * 4. style="display:none" の場合、これ以下の変更を行わない。 - * 5. ie5 非表示フラグが立っていて、親と自身の class・id によって非表示になっていて、親と自身に変更がない。accumulatedFlags を使用。 - * -> TODO これ TREE の変更を検出できない。 remove したときに 子まで X_Node_State.IE5_DISPLAY_NONE_FIXを落とす。 - * 6. 要素の生成 - * 7. 要素の位置のズレを補正 - * 8. 更新の適用 - * 9. ie5 親及び自身へのクラス・id指定で display:none になるケースがありそれを検出。 - * このままでは、生成と破棄が繰り返されてしまうので親と自身のクラス・idが変わった場合、ツリー位置の変化があった場合に再生する。 - */ -var X_Node__commitUpdate = - X_UA_DOM.W3C ? - ( function( that, parentElement, nextElement, accumulatedFlags ){ - var elm = that[ '_rawObject' ], - created, xnodes, l, next; - - // 1. GPU 一切の更新をスキップ - if( that[ '_flags' ] & X_Node_State.GPU_NOW ){ - console.log( '更新のskip ' + !!( that[ '_flags' ] & X_Node_BitMask_IS_DIRTY ) ); - that[ '_flags' ] & X_Node_BitMask_IS_DIRTY && X_Node__updateRawNode( that, elm ); - return elm; - }; - - // 2. GPU解放予約 - if( that[ '_flags' ] & X_Node_State.GPU_RELEASE_RESERVED ){ - // console.log( 'GPU 解放 ' ); - //X_Node_updateReservedByReleaseGPU = true; - //X_Node__updateRawNode( that, elm ); - that[ '_flags' ] &= X_Node_BitMask_RESET_GPU; - //return elm;// TODO もしかしたらこのタイミングで更新できるかも。 - }; - - // 3. GPU予約 -> GPU - if( that[ '_flags' ] & X_Node_State.GPU_RESERVED ){ - that[ '_flags' ] &= X_Node_BitMask_RESET_GPU; - that[ '_flags' ] |= X_Node_State.GPU_NOW; - }; - - // 4. style="display:none" の場合 - if( that[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ){ - if( X_Node_displayNoneFixForIE5 ){ - // filter の効いている要素を含む要素は display:none が無視される。 - // filter = '' で削除はできるが、再表示時に filter が消える。 -> filter な要素を削除してしまう。 - if( elm && elm.parentNode ){ - X_Node__actualRemove( that ); - }; - return nextElement; - }; - elm && ( elm.style.display = 'none' ); - return ( elm && elm.nextSibling === nextElement ) ? elm : nextElement; - }; - - // 5. ie5 非表示fixフラグ - accumulatedFlags |= that[ '_flags' ]; - - if( that[ '_flags' ] & X_Node_State.IE5_DISPLAY_NONE_FIX ){ - if( accumulatedFlags & ( X_Node_State.DIRTY_POSITION | X_Node_State.DIRTY_ID | X_Node_State.DIRTY_CLASSNAME ) === 0 ){ - return nextElement; - }; - }; - - // 6. 要素の生成 - if( !elm ){ - if( !that[ '_tag' ] ){ - that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; - that[ '_rawObject' ] = elm = document.createTextNode( X_String_chrReferanceTo( that[ '_text' ] ) ); - if( !X_UA[ 'IE' ] ){ - elm[ 'UID' ] = that[ '_uid' ]; - }; - } else - if( X_Node_strictElmCreation ){ - that[ '_flags' ] & X_Node_State.OLD_CSSTEXT && X_Node_CSS_objToCssText( that, true ); // OLD_CSSTEXT ?? - - that[ '_rawObject' ] = elm = - document.createElement( [ - '<', that[ '_tag' ], - ' UID="', that[ '_uid' ], '"', - that[ '_id' ] ? ' id="' + that[ '_id' ] + '"' : '', - that[ '_className' ] ? ' class="' + that[ '_className' ] + '"' : '', - X_Node_Attr_objToAttrText( that, true ), - that[ '_cssText' ] ? ' style="' + that[ '_cssText' ] + '"' : '', - '>' ].join( '' ) ); - } else { - that[ '_rawObject' ] = elm = document.createElement( that[ '_tag' ] ); - }; - - // IE には要素追加のタイミングで起こるメモリリークがありここで追加 - if( !X_Node_addTreeAfterChildren ){ - nextElement ? - parentElement.insertBefore( elm, nextElement ) : - parentElement.appendChild( elm ); - }; - - if( that[ '_tag' ] ){ - 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 ){ - that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; - // ie の string から要素を作る場合、ネットワーク系属性は onload イベントなどを拾うために、要素生成->イベント復帰後に適用する - 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' ]; - that[ '_newAttrs' ] = that[ '_attrs' ]; - that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; - that[ '_flags' ] |= 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; - - // http://outcloud.blogspot.jp/2010/09/iframe.html - // この問題は firefox3.6 で確認 - if( X_UA[ 'Gecko' ] ){ - if( that[ '_tag' ] === 'IFRAME' && ( !that[ '_attrs' ] || !that[ '_attrs' ][ 'src' ] ) ){ - //elm.contentWindow.location.replace = elm.src = 'about:blank'; - that[ 'attr' ]( 'src', 'about:blank' ); - }; - }; - }; - }; - - created = true; - } else - // 7. 要素の位置のズレを補正 - if( elm.parentNode !== parentElement || ( nextElement && elm.nextSibling !== nextElement ) ){ - nextElement ? - parentElement.insertBefore( elm, nextElement ) : - parentElement.appendChild( elm ); - }; - - 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' ]; - X_Node__updateRawNode( that, elm ); - }; - - // 9. ie5 only - // 親及び自身へのクラス・id指定で display : none になるケースがありそれを検出 - // 生成と破棄が繰り返されてしまう、親と自身の id, class が変わった場合だけ再生成。 accumulatedFlags & ( ID | CLASSNAME ) - // currentStyle を観ていたときはエラーで停止する、alert と挟むと正常に動いて支離滅裂 - if( X_Node_displayNoneFixForIE5 && that[ '_tag' ] ){ - if( elm.runtimeStyle.display === 'none' ){ - X_Node__actualRemove( that ); - that[ '_flags' ] |= X_Node_State.IE5_DISPLAY_NONE_FIX; - return nextElement; - } else { - that[ '_flags' ] &= ~X_Node_State.IE5_DISPLAY_NONE_FIX; - }; - }; - - // 10. 子要素の更新。 - if( ( xnodes = that[ '_xnodes' ] ) && ( l = xnodes.length ) ) { - for( ; l; ){ - next = X_Node__commitUpdate( xnodes[ --l ], elm, next, accumulatedFlags ); - }; - }; - - if( created && X_Node_addTreeAfterChildren ){ - nextElement ? - parentElement.insertBefore( elm, nextElement ) : - parentElement.appendChild( elm ); - - if( X_UA[ 'Gecko' ] && that[ '_tag' ] === 'IFRAME' && elm.contentWindow ){ - // tree に追加されるまで contentWindow は存在しない。 - elm.contentWindow.location.replace = elm.src; - }; - }; - - return elm; - }) : - X_UA_DOM.IE4 ? - ( function( that, parentElement, prevElement, accumulatedFlags ){ - var elm = that[ '_rawObject' ] || X_Node__ie4getRawNode( that ), - xnodes, l, i, dirty, mix, html, text, prev; - - if( !that[ '_tag' ] ){ - that[ '_flags' ] & X_Node_State.DIRTY_CONTENT && X_Node__updateRawNode( that, elm ); - return elm; - }; - - // 4. style="display:none" の場合 - if( that[ '_flags' ] & X_Node_State.STYLE_IS_DISPLAY_NONE ){ - if( elm ){ - elm.style.display = 'none'; - if( elm.style.display !== 'none' ){ // ie4 の style は currentStyle 相当らしい、、、? div 以外への display:none が効かないので remove する。 - X_Node__actualRemove( that ); - return prevElement; - }; - }; - return elm || prevElement; - }; - - if( !elm ){ - prevElement ? - prevElement.insertAdjacentHTML( 'AfterEnd', X_Node__actualCreate( that, false ) ) : - parentElement.insertAdjacentHTML( 'AfterBegin', X_Node__actualCreate( that, false ) ); - X_Node__afterActualCreate( that ); - return that[ '_rawObject' ] || X_Node__ie4getRawNode( that ); - }; - - accumulatedFlags |= that[ '_flags' ]; - - xnodes = that[ '_xnodes' ]; - l = xnodes ? xnodes.length : 0; - dirty = !!( that[ '_flags' ] & X_Node_State.IE4_DIRTY_CHILDREN ); - - /* - * HTML の下に TextNode だけ 。MIX_FIXED でない場合、削除、追加 を親に通知 - * HTML の下に HTML だけ - * HTML の下は MIX -> TextNode, html の削除、変更、追加 - * HTML の下は MIX_FIXED -> TextNode を に置き換えてあるのでW3C DON 的に触ることができる - */ - if( dirty ){ - that[ '_flags' ] &= ~X_Node_State.IE4_DIRTY_CHILDREN; - for( i = 0; i < l; ++i ){ - if( xnodes[ i ][ '_tag' ] ){ - that[ '_flags' ] |= X_Node_State.IE4_HAS_ELEMENT; - } else { - that[ '_flags' ] |= X_Node_State.IE4_HAS_TEXTNODE; - }; - if( that[ '_flags' ] & X_Node_BitMask_IE4_IS_MIX === X_Node_BitMask_IE4_IS_MIX ){ - mix = true; - break; - }; - }; - }; - - if( that[ '_flags' ] & X_Node_State.IE4_FIXED || that[ '_flags' ] & X_Node_BitMask_IE4_IS_MIX === X_Node_State.IE4_HAS_ELEMENT ){ - for( i = 0; i < l; ++i ){ - prev = X_Node__commitUpdate( xnodes[ i ], elm, prev, accumulatedFlags ); - }; - } else - if( mix ){ - html = []; - for( i = 0; i < l; ++i ){ - html[ i ] = X_Node__actualCreate( xnodes[ i ], false ); - }; - elm.innerHTML = html.join( '' ); - for( i = 0; i < l; ++i ){ - X_Node__afterActualCreate( xnodes[ i ] ); - }; - that[ '_flags' ] |= X_Node_State.IE4_FIXED; - } else - if( that[ '_flags' ] & X_Node_State.IE4_HAS_TEXTNODE ){ - dirty = dirty || false; - for( i = 0; i < l; ++i ){ - text = xnodes[ i ]; - if( text[ '_flags' ] & X_Node_BitMask_IS_DIRTY ){ - text[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; - dirty = true; - }; - }; - if( dirty ) elm.innerHTML = that[ 'text' ](); - }; - - if( accumulatedFlags & X_Node_BitMask_IS_DIRTY ) delete that[ '_fontSize' ]; - - that[ '_flags' ] &= ~X_Node_State.DIRTY_POSITION; - that[ '_flags' ] & X_Node_BitMask_IS_DIRTY && X_Node__updateRawNode( that, elm ); - return elm; - }) : - (function(){}); - -/* - * GPU レイヤーするブラウザは、子要素から変更を当てていく? <- とりあえず、親要素から。 - */ -var X_Node__updateRawNode = - X_UA_DOM.W3C ? - ( function( that, elm ){ - var attrs, rename, k, v; - - // textNode - if( !that[ '_tag' ] ){ - elm.data = X_String_chrReferanceTo( that[ '_text' ] ); - that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; - return; - }; - // id - if( that[ '_flags' ] & X_Node_State.DIRTY_ID ){ - that[ '_id' ] ? ( elm.id = that[ '_id' ] ) : ( elm.id && elm.removeAttribute( 'id' ) ); - }; - // className - if( that[ '_flags' ] & X_Node_State.DIRTY_CLASSNAME ){ - that[ '_className' ] ? ( elm.className = that[ '_className' ] ) : ( elm.className && elm.removeAttribute( X_UA[ 'IE' ] < 8 ? 'className' : 'class' ) ); // className は ie7- - }; - - // attr - if( that[ '_flags' ] & X_Node_State.DIRTY_ATTR && ( attrs = that[ '_newAttrs' ] || that[ '_attrs' ] ) ){ - rename = X_Node_Attr_renameForDOM; - - for( k in attrs ){ - v = attrs[ k ]; - - switch( that[ '_tag' ] + k ){ - case 'TEXTAREAvalue' : - // IETester 5.5 ではエラーが出なかった.MultipulIE5.5 ではエラーが出たので - if( !X_UA[ 'MacIE' ] && X_UA[ 'IE5x' ] ){ - elm.firstChild ? - ( elm.firstChild.data = v || '' ) : - elm.appendChild( document.createTextNode( v || '' ) ); - continue; - }; - break; - - case 'IFRAMEsrc' : - // http://outcloud.blogspot.jp/2010/09/iframe.html - // この問題は firefox3.6 で確認 - if( X_UA[ 'Gecko' ] && elm.contentWindow ){ - elm.contentWindow.location.replace = elm.src = v || ''; - continue; - }; - break; - - case 'IFRAMEname' : - // http://d.hatena.ne.jp/NeoCat/20080921/1221940658 - // こちらに名前をsetしないとtargetが動作しない - // これってあとから name を変更できないバグでは? itozyun - // if( X_UA[ 'IE' ] ) elm.name = elm.contentWindow.name = v || ''; - }; - - //if( X_EMPTY_OBJECT[ k ] ) continue; - // TODO IE では input, なぜか button, object も type, name の変更が出来ない、同値で置き換えようとしても不可 - v === undefined ? - elm.removeAttribute( rename[ k ] || k ) : - ( elm[ rename[ k ] || k ] = X_Node_Attr_noValue[ k ] ? k : v ); - }; - delete that[ '_newAttrs' ]; - }; - - // style - if( that[ '_flags' ] & X_Node_State.DIRTY_CSS ){ - if( that[ '_flags' ] & X_Node_State.OLD_CSSTEXT ? X_Node_CSS_objToCssText( that ) : that[ '_cssText' ] ){ - X_UA[ 'Opera78' ] || X_UA[ 'NN6' ] ? - elm.setAttribute( 'style', that[ '_cssText' ] ) : // opera8用 - ( elm.style.cssText = that[ '_cssText' ] ); - } else { - elm.style.cssText = ''; // IE5.5以下 Safari3.2 で必要 - elm.removeAttribute( 'style' ); - }; - } else - if( that[ '_flags' ] & X_Node_State.DIRTY_IE_FILTER ){ - v = X_Node_CSS_objToIEFilterText( that ); - if( v ){ - elm.style.filter = v; - that[ '_flags' ] |= X_Node_State.IE_FILTER_NOW; - } else { - elm.style.removeAttribute( 'filter' ); - that[ '_flags' ] &= ~X_Node_State.IE_FILTER_NOW; - }; - }; - - that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; - }) : - X_UA_DOM.IE4 ? - ( function( that, elm ){ - var attrs, rename, k, v; - - // fake textNode - if( !that[ '_tag' ] ){ - elm.innerText = that[ '_text' ]; - that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; - return; - }; - - /* - * http://www.tohoho-web.com/js/element.htm - * title、className、id、lang、language には setAttribute でなく、element.id で直接読み書きできる - */ - // id - if( that[ '_flags' ] & X_Node_State.DIRTY_ID ) elm.setAttribute( 'id', that[ '_id' ] || ( 'ie4uid' + that[ '_uid' ] ) ); - - // className - if( that[ '_flags' ] & X_Node_State.DIRTY_CLASSNAME ){ - that[ '_className' ] ? ( elm.className = that[ '_className' ] ) : elm.removeAttribute( 'class' ); - }; - // style - if( that[ '_flags' ] & X_Node_State.DIRTY_CSS ){ - if( that[ '_flags' ] & X_Node_State.OLD_CSSTEXT ? X_Node_CSS_objToCssText( that ) : that[ '_cssText' ] ){ - elm.style.cssText = that[ '_cssText' ]; - } else { - elm.style.cssText = ''; - elm.removeAttribute( 'style' ); - }; - } else - if( that[ '_flags' ] & X_Node_State.DIRTY_IE_FILTER ){ - v = X_Node_CSS_objToIEFilterText( that ); - if( v ){ - elm.style.filter = v; - that[ '_flags' ] |= X_Node_State.IE_FILTER_NOW; - } else { - elm.style.removeAttribute( 'filter' ); - that[ '_flags' ] &= ~X_Node_State.IE_FILTER_NOW; - }; - }; - - // attr - if( that[ '_flags' ] & X_Node_State.DIRTY_ATTR && ( attrs = that[ '_newAttrs' ] || that[ '_attrs' ] ) ){ - rename = X_Node_Attr_renameForDOM; - for( k in attrs ){ - //if( X_EMPTY_OBJECT[ k ] ) continue; - ( v = attrs[ k ] ) === undefined ? - elm.removeAttribute( rename[ k ] || k ) : - elm.setAttribute( rename[ k ] || k, X_Node_Attr_noValue[ k ] ? k : v ); - }; - delete that[ '_newAttrs' ]; - }; - - that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; - }) : - (function(){}); - -/* -------------------------------------- - * Create - * - * http://d.hatena.ne.jp/uupaa/20080718/1216362040 - * DOM Rangeが使える環境(Firefox2+,Opera9+,Safari3+)なら、innerHTMLいらずで、ガーって書けます。 - * return document.createRange().createContextualFragment("
    "); - * insertAdjacentHTML - * - * ie7 以下では iframe の frameborder や、input name は、createElement 後に setAttribute しても無視される - * - * fragument がある場合 children も足して - * Mozilla: 1.0+, IE: 5.5+, Netscape: 2.0+, Safari: 1.0+, Opera: 7.0+ - * ie6 大丈夫?fragment の場合リークしないか?チェックが必要 - * http://msdn.microsoft.com/ja-jp/library/bb250448%28v=vs.85%29.aspx - * - * document.createElement of ie4 is only for OPTION & IMAGE. - */ -var X_Node__actualCreate = - X_UA_DOM.IE4 && (function( that, isChild ){ - var uid = that[ '_uid' ], - html, xnodes, n, i, l; - - if( !that[ '_tag' ] ){ - html = [ '', that[ '_text' ], '' ];// fake textNode - delete that[ '_rawObject' ]; - } else { - if( !isChild ) X_Node__actualRemove( that, /* true */ false ); - - 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' ] + '"' : '', - X_Node_Attr_objToAttrText( that, true ), - that[ '_cssText' ] ? ' style="' + that[ '_cssText' ] + '"' : '', - '>' ]; - - n = html.length; - if( ( xnodes = that[ '_xnodes' ] ) && ( l = xnodes.length ) ){ - - that[ '_flags' ] &= ~X_Node_State.IE4_DIRTY_CHILDREN; - for( i = 0; i < l; ++i ){ - if( xnodes[ i ][ '_tag' ] ){ - that[ '_flags' ] |= X_Node_State.IE4_HAS_ELEMENT; - } else { - that[ '_flags' ] |= X_Node_State.IE4_HAS_TEXTNODE; - }; - if( that[ '_flags' ] & X_Node_BitMask_IE4_IS_MIX === X_Node_BitMask_IE4_IS_MIX ){ - break; - }; - }; - - if( that[ '_flags' ] & X_Node_BitMask_IE4_IS_MIX === X_Node_State.IE4_HAS_TEXTNODE ){ - // only textnode - html[ n ] = that[ 'text' ](); - ++n; - } else { - for( i = 0; i < l; ++i ){ - html[ n ] = X_Node__actualCreate( xnodes[ i ], true ); - ++n; - }; - that[ '_flags' ] |= X_Node_State.IE4_FIXED; - }; - }; - X_Dom_DTD_EMPTY[ that[ '_tag' ] ] || ( html[ n ] = '<\/' + that[ '_tag' ] + '>' ); - - that[ '_newAttrs' ] && ( that[ '_flags' ] |= X_Node_State.DIRTY_ATTR ); - }; - - return html.join( '' ); - }); - -var X_Node__afterActualCreate = - X_UA_DOM.IE4 && (function( that ){ - var xnodes, i, v; - - if( !that[ '_tag' ] ) return that; - - if( ( xnodes = that[ '_xnodes' ] ) && ( i = xnodes.length ) ){ - for( ; i; ){ - X_Node__afterActualCreate( xnodes[ --i ] ); - }; - }; - // ネットワーク系属性と 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 );// イベントの復帰 - }); - -var X_Node__actualRemove = - X_UA_DOM.W3C ? - // GPUレイヤーにいるうちは remove しない。-> GPU解除してから remove する - // Firefox34 では遭遇せず、Safari で何度かアニメーションしているうちに発生 - ( function( that, isChild ){ - var xnodes = that[ '_xnodes' ], - elm = that[ '_rawObject' ], - child, i, l; - - if( xnodes && ( l = xnodes.length ) ){ - for( i = 0; i < l; ++i ){ - child = xnodes[ i ]; - child[ '_tag' ] && X_Node__actualRemove( child, true ); - }; - }; - - if( !elm ) return; - - 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 でなぜかカラム落ちが発生、、、 - if( X_Node_displayNoneFixForIE5 ){ - if( elm.filters && elm.filters.length ){ - //elm.style.removeAttribute( 'filter' ); - isChild = false; - delete that[ '_rawObject' ]; - // 破棄前にインタラクティブな属性値を控える - 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 = ''; - }; - }; - - if( !X_UA[ 'MacIE' ] ){ - // elm.parentNode.tagName for ie7 - !isChild && elm.parentNode && elm.parentNode.tagName && elm.parentNode.removeChild( elm ); - } else { - !isChild && elm.parentNode && elm.parentNode.tagName && X_TEMP._fixed_remove( elm, that ); - }; - }) : - X_UA_DOM.IE4 ? - ( function( that, isChild ){ - var xnodes = that[ '_xnodes' ], - elm = that[ '_rawObject' ] || X_Node__ie4getRawNode( that ), - i, l, xnode; - if( xnodes && ( l = xnodes.length ) ){ - for( i = 0; i < l; ++i ){ - X_Node__actualRemove( xnodes[ i ], true ); - }; - }; - - if( !elm ) return; - that[ '_listeners' ] && X_EventDispatcher_toggleAllEvents( that, false );// イベントの退避 - - // 破棄前にインタラクティブな属性値を控える - 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 = ''; - delete that[ '_rawObject' ]; - }) : - (function(){}); - -X_ViewPort[ 'listenOnce' ]( X_EVENT_UNLOAD, X_Node__actualRemove, [ X_Node_html, true ] ); - +/** + * Node( rawElement | rawTextnode | htmlString | textString ) + * + * @alias X.Node + * @class Node HTMLElement、TextNode をラップし jQuery 風な API で操作できます。 + * @constructs Node + * @extends {EventDispatcher} + */ +var Node = X[ 'Node' ] = X_EventDispatcher[ 'inherits' ]( + 'X.Node', + X_Class.POOL_OBJECT, + + { + /** + * 要素に振られるユニークID + * @type {number} + * @private + * @alias Node.prototype._uid + */ + '_uid' : 0, + + /** + * Node の状態を表すフラグ。 + * @type {number} + * @private + * @alias Node.prototype._flags + */ + '_flags' : X_NodeFlags_DESTROYED, + + '_rect' : null, // TODO + + /** + * 最後に計測したフォントサイズを保持している。ツリーが変更されると削除される。 + * @type {number} + * @private + * @alias Node.prototype._fontSize + */ + '_fontSize' : 0, + + /** + * NodeList と動作を一致させるためのプロパティ。常に 1。 + * @type {number} + * @const + * @alias Node.prototype.length + */ + length : 1, + + /** + * 親 Node。 + * @type {Node} + * @alias Node.prototype.parent + */ + parent : null, // remove された枝も親子構造は維持している。 + + /** + * 子 Node リスト + * @type {Array} + * @private + * @alias Node.prototype._xnodes + */ + '_xnodes' : null, + + /** + * GPU レイヤーに転送されている場合、その一番親となっている Node。未実装。 + * @type {Node} + * @private + * @alias Node.prototype._gpuParent + */ + '_gpuParent' : null, + + /** + * タグ名。テキストノードの場合は空文字列。 + * @type {string} + * @private + * @alias Node.prototype._tag + */ + '_tag' : '', + + /** + * テキストコンテンツ。テキストノードで使用。 + * @type {string} + * @private + * @alias Node.prototype._text + */ + '_text' : '', + + /** + * id + * @type {string} + * @private + * @alias Node.prototype._id + */ + '_id' : '', + + /** + * クラス名。複数のクラスが設定されている場合、スペース区切り。 + * @type {string} + * @private + * @alias Node.prototype._className + */ + '_className' : '', // + + /** + * 属性。 + * @type {object} + * @private + * @alias Node.prototype._attrs + */ + '_attrs' : null, // see X_Node_Attr + + /** + * まだコミットされていない属性。 + * @type {object} + * @private + * @alias Node.prototype._newAttrs + */ + '_newAttrs' : null, + + /** + * 属性を文字列にしたもの。 color="red" size="8" + * @type {object} + * @private + * @alias Node.prototype._attrText + */ + '_attrText' : '', + + /** + * スタイル。 + * @type {object} + * @private + * @alias Node.prototype._css + */ + '_css' : null, + + /** + * cssText + * @type {string} + * @private + * @alias Node.prototype._cssText + */ + '_cssText' : '', + + /** + * アニメーション用オブジェクト。 + * @type {object} + * @private + * @alias Node.prototype._anime + */ + '_anime' : null, + + /* + * TODO Node の継承ができない! + */ + 'Constructor' : function( v ){ + var uid = X_Node_CHASHE.length, + css, xnodes, xnode, parent; + + if( X_Node_newByTag ){ + X_Node_newByTag = false; + this[ '_tag' ] = v.toUpperCase(); + arguments[ 1 ] && this[ 'attr' ]( arguments[ 1 ] ); + css = arguments[ 2 ]; + css && this[ X_Type_isString( css ) ? 'cssText' : 'css' ]( css ); + } else + if( X_Node_newByText ){ + X_Node_newByText = false; + this[ '_text' ] = v; + } else { + if( 1 < arguments.length ) return new X_NodeList( arguments ); + if( X_Type_isArray( v ) && v.length ) return new X_NodeList( v ); + + switch( X_Node_getType( v ) ){ + case X_NodeType_XNODE : + case X_NodeType_XNODE_LIST : + return v; + + case X_NodeType_RAW_HTML : + if( xnode = X_Node_getXNode( v ) ) return xnode; + // v.parentNode || v.parentElement : dom1 || dom0 + this.parent = ( parent = v.parentNode || v.parentElement ) && parent.tagName /* ie7- */ && X_Node_getXNode( parent ); + this[ '_rawObject' ] = v; + this[ '_tag' ] = v.tagName.toUpperCase(); + this[ '_id' ] = v.id; + this[ '_className' ] = v.className; + + this[ 'cssText' ]( v.style.cssText ); + this[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; // X_NodeFlags_DIRTY_CSS を落とす + + // TODO attr の回収は不可能、、、? + if( X_UA_DOM.IE4 ){ + v.setAttribute( 'UID', '' + uid ); + } else { + v[ 'UID' ] = uid; + }; + // childNodes... + break; + + case X_NodeType_RAW_TEXT : + if( xnode = X_Node_getXNode( v ) ) return xnode; + this.parent = X_Node_getXNode( v.parentNode ); + this[ '_rawObject' ] = v; + this[ '_text' ] = v.data; + v[ 'UID' ] = uid; + break; + + case X_NodeType_HTML_STRING : + case X_NodeType_STRING : + if( xnodes = X_HtmlParser_parse( v, true ) && 1 < xnodes.length ) return new X_NodeList( xnodes ); + if( xnodes.length ) return xnodes[ 0 ]; + return X_Node_none; + + default : + if( X_Node_none ) return X_Node_none; + this.length = 0; + return; + }; + }; + + if( this.parent && ( this.parent[ '_flags' ] & X_NodeFlags_IN_TREE ) ){ + this[ '_flags' ] |= X_NodeFlags_IN_TREE; + }; + this[ '_flags' ] |= X_NodeFlags_EXIST; + X_Node_CHASHE[ this[ '_uid' ] = uid ] = this; + + X_EventDispatcher_systemListen( this, X_EVENT_BEFORE_KILL_INSTANCE, X_Node_onBeforeKill ); + }, + + 'width' : X_Node_width, + 'height' : X_Node_height, + 'clientWidth' : X_Node_clientWidth, + 'clientHeight' : X_Node_clientHeight, + 'scrollWidth' : X_Node_scrollWidth, + 'scrollHeight' : X_Node_scrollHeight, + 'scrollLeft' : X_Node_scrollLeft, + 'scrollTop' : X_Node_scrollTop, + 'x' : X_Node_x, + 'y' : X_Node_y, + 'offset' : X_Node_offset, + + 'attr' : X_Node_attr, + 'css' : X_Node_css, + 'cssText' : X_Node_cssText, + + 'find' : X_Node_find, + + 'animate' : X_Node_animate, + 'stop' : X_Node_stop, + + + 'create' : X_Node_create, + + 'createAt' : X_Node_createAt, + + 'createText' : X_Node_createText, + + 'createTextAt' : X_Node_createTextAt, + + 'clone' : X_Node_clone, + + 'append' : X_Node_append, + + 'appendAt' : X_Node_appendAt, + + 'appendTo' : X_Node_appendTo, + + 'prev' : X_Node_prev, + + 'next' : X_Node_next, + + 'swap' : X_Node_swap, + + 'remove' : X_Node_remove, + + 'empty' : X_Node_empty, + + 'contains' : X_Node_contains, + + 'getChildAt' : X_Node_getChildAt, + + 'numChildren' : X_Node_numChildren, + + 'firstChild' : X_Node_firstChild, + + 'lastChild' : X_Node_lastChild, + + 'getOrder' : X_Node_getOrder, + + 'className' : X_Node_className, + 'addClass' : X_Node_addClass, + 'removeClass' : X_Node_removeClass, + 'toggleClass' : X_Node_toggleClass, + 'hasClass' : X_Node_hasClass, + + 'html' : X_Node_html, + 'text' : X_Node_text, + 'call' : X_Node_call, + 'each' : X_Node_each + + } +); + +var X_NodeType_XNODE = 1, + X_NodeType_RAW_HTML = 2, + X_NodeType_RAW_TEXT = 3, + X_NodeType_HTML_STRING = 4, + X_NodeType_STRING = 5, + //DOC_FRAG = 6, + X_NodeType_XNODE_LIST = 7, + X_NodeType_WINDOW = 8, + X_NodeType_DOCUMENT = 9, + X_NodeType_IMAGE = 10, + + X_Node_strictElmCreation = !X_UA[ 'MacIE' ] && X_UA[ 'IE' ] <= 8, + + X_Node_documentFragment = document.createDocumentFragment && ( !X_UA[ 'IE' ] || 5.5 <= X_UA[ 'IE' ] ) && document.createDocumentFragment(), + + // 子の生成後に リアル文書 tree に追加する + X_Node_addTreeAfterChildren = !( X_UA[ 'IE' ] < 9 ), + + X_Node_displayNoneFixForIE5 = !!X_NodeFlags_IE5_DISPLAY_NONE_FIX, + + X_Node_newByTag = false, + + X_Node_newByText = false, + + X_Node_outerXNode = null, + + X_Node_updateTimerID = 0, + + // XMLかどうかを判別する + X_Node_isXmlDocument = + X_UA_DOM.IE4 ? + X_emptyFunction : + (function( root ){ + if( X_Type_isBoolean( root.isXML ) ) return root.isXML; + return root.isXML = root[ '_rawObject' ].createElement( 'p' ).tagName !== root[ '_rawObject' ].createElement( 'P' ).tagName; + }), + X_Node_CHASHE = [], + X_Node_none = X_Node_CHASHE[ 0 ] = Node(), + X_Node_html, // = + X_Node_head, // = + X_Node_body, // = + X_Node_systemNode, // = X_Node_CHASHE[ ? ] + X_Node_fontSizeNode, +/* + * remove : + * X_Node_reserveRemoval = [] に追加。commitUpdate で remove + * add : + * X_Node_reserveRemoval にいたら消す, new_parent[ '_xnodes' ] に挿入 + */ + X_Node_reserveRemoval = []; + +function X_Node_getType( v ){ + if( v === '' ) return X_NodeType_STRING; + if( !v ) return 0; + if( v === window ) return X_NodeType_WINDOW; + if( v === document ) return X_NodeType_DOCUMENT; + if( v.constructor === Node ) return X_NodeType_XNODE; + if( v.constructor === X_NodeList ) return X_NodeType_XNODE_LIST; + if( X_Type_isHTMLElement( v ) ) return X_NodeType_RAW_HTML; + if( v.nodeType === 3 ) return X_NodeType_RAW_TEXT; + if( X_Type_isString( v ) ){ + return '<' === v.charAt( 0 ) && v.charAt( v.length - 1 ) === '>' ? X_NodeType_HTML_STRING : X_NodeType_STRING; + }; + if( v[ 'instanceOf' ] && v[ 'instanceOf' ]( Node ) ) return X_NodeType_XNODE; + return 0; +}; +function X_Node_getXNode( v ){ + var uid, i, chashe, xnode; + switch( X_Node_getType( v ) ){ + case X_NodeType_XNODE : + case X_NodeType_XNODE_LIST : + return v; + case X_NodeType_RAW_HTML : + // fake TextNode too. + if( X_UA_DOM.IE4 ){ + uid = v.getAttribute( 'UID' ); + return uid && X_Node_CHASHE[ uid ]; + }; + return v[ 'UID' ] && X_Node_CHASHE[ v[ 'UID' ] ]; + case X_NodeType_WINDOW : + return X_ViewPort; + case X_NodeType_DOCUMENT : + return X_ViewPort_document; + case X_NodeType_RAW_TEXT : + if( v[ 'UID' ] ) return X_Node_CHASHE[ v[ 'UID' ] ]; + for( chashe = X_Node_CHASHE, i = chashe.length; i; ){ + if( ( xnode = X_Node_CHASHE[ --i ] ) && ( xnode[ '_rawObject' ] === v ) ) return xnode; + }; + }; +}; + +function X_Node_getRoot( xnode ){ + return X_ViewPort_document; + //return X_Node_body[ '_rawObject' ].documentElement ? node : node.ownerDocument || node.document; +}; + + + +var X_Node__ie4getRawNode = X_UA_DOM.IE4 && function ( that ){ + return that[ '_rawObject' ] || + ( that[ '_rawObject' ] = document.all[ 'ie4uid' + that[ '_uid' ] ] ) || + ( that[ '_id' ] && ( that[ '_rawObject' ] = document.all[ that[ '_id' ] ] ) ); + }; + + +function X_Node_toggleInTreeFlag( xnodes, flag ){ + var i = xnodes.length, xnode; + for( ; i; ){ + xnode = xnodes[ --i ]; + flag ? ( xnode[ '_flags' ] |= X_NodeFlags_IN_TREE | X_NodeFlags_DIRTY_POSITION ) : ( xnode[ '_flags' ] &= ~X_NodeFlags_IN_TREE & ~X_NodeFlags_IE5_DISPLAY_NONE_FIX ); + xnode[ '_xnodes' ] && X_Node_toggleInTreeFlag( xnode[ '_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_NodeFlags_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_NodeFlags_GPU_CHILD; + delete xnode[ '_gpuParent' ]; + xnode[ '_xnodes' ] && X_Node_toggleInTreeFlag( gpuRoot, xnode[ '_xnodes' ], flag ); + }; + }; + }; +}; + +/** + * タグ名等を指定して新規に子ノードを作成し、現在のノードに追加する。 + * @alias Node.prototype.create + * @param {string} [tag] タグ名 + * @param {object} [opt_attrs=] 属性 + * @param {object|string} [opt_css=] css + * @return {Node} 新規作成されたノード + * @example var child = parent.create( 'div' ); + */ +function X_Node_create( tag, opt_attrs, opt_css ){ + var xnode; + if( !this[ '_tag' ] ) return; + this[ 'append' ]( xnode = X_Doc_create( tag, opt_attrs, opt_css ) ); + return xnode; +}; +/** + * 挿入位置とタグ名等を指定して新規に子ノードを作成し、現在のノードに挿入する。 + * @alias Node.prototype.createAt + * @param {number} [index] 挿入位置 + * @param {string} [tag] タグ名 + * @param {object} [opt_attrs=] 属性 + * @param {object|string} [opt_css=] css + * @return {Node} 新規作成されたノード + * @example var child = parent.create( 2, 'div' ); + */ +function X_Node_createAt( index, tag, opt_attrs, opt_css ){ + var xnode; + if( !this[ '_tag' ] ) return; + this[ 'appendAt' ]( index, xnode = X_Doc_create( tag, opt_attrs, opt_css ) ); + return xnode; +}; + +/** + * テキストを指定して新規にテキストノードを作成し、現在のノードに挿入する。 + * @alias Node.prototype.createText + * @param {string} [tag] テキスト + * @return {Node} 新規作成されたノード + */ +function X_Node_createText( text ){ + var xnode; + if( !this[ '_tag' ] ) return; + this[ 'append' ]( xnode = X_Doc_createText( text ) ); + return xnode; +}; +/** + * 挿入位置とテキストを指定して新規に子ノードを作成し、現在のノードに挿入する。 + * @alias Node.prototype.createTextAt + * @param {number} [index] 挿入位置 + * @param {string} [tag] テキスト + * @return {Node} 新規作成されたノード + */ +function X_Node_createTextAt( index, text ){ + var xnode; + if( !this[ '_tag' ] ) return; + this[ 'appendAt' ]( index, xnode = X_Doc_createText( text ) ); + return xnode; +}; + +/** + * Node のクローンを作成し返す。id もクローンされる点に注意。イベントリスナはクローンされない。 + * http://d.hatena.ne.jp/think49/20110724/1311472811 + * http://d.hatena.ne.jp/uupaa/20100508/1273299874 + * @alias Node.prototype.clone + * @param {boolean} [opt_clone_children] 子要素のクローンを行うか? + * @return {Node} + */ +function X_Node_clone( opt_clone_children ){ + var xnode, xnodes, i, l; + if( this[ '_tag' ] ){ + X_Node_newByTag = true; + xnode = Node( this[ '_tag' ], X_Object_clone( this[ '_attrs' ] ), X_Object_clone( this[ '_css' ] ) ) + [ 'attr' ]( { 'id' : this[ '_id' ] } ) + [ 'className' ]( this[ '_className' ] ); + if( opt_clone_children && ( xnodes = this[ '_xnodes' ] ) && ( l = xnodes.length ) ){ + for( i = 0; i < l; ++i ){ + xnode[ 'append' ]( xnodes[ i ][ 'clone' ]( true ) ); + }; + }; + return xnode; + }; + X_Node_newByText = true; + return Node( this[ '_text' ] ); +}; + +/** + * ノードを子配列の最後に追加する。文字列が渡された場合、HTMLパーサーによって Node ツリーを作成して追加する。HtmlElement, TextNode の場合は内部使用専用。 + * @alias Node.prototype.append + * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。 + * @return {Node} 自身。チェインメソッド + * @example // + * myNode.append( node ); + * myNode.append( node, '<span>Hello,</span>', 'world.' ); + */ +function X_Node_append( v ){ + var i, l, xnodes, frg; + if( !this[ '_tag' ] ) return; + + if( 1 < ( l = arguments.length ) ){ + for( i = 0; i < l; ++i ){ + this[ 'append' ]( arguments[ i ] ); + }; + return this; + }; + + if( !( xnodes = this[ '_xnodes' ] ) ) this[ '_xnodes' ] = xnodes = []; + + switch( X_Node_getType( v ) ){ + case X_NodeType_RAW_HTML : + case X_NodeType_RAW_TEXT : + v = Node( v ); + break; + case X_NodeType_HTML_STRING : + case X_NodeType_STRING : + return X_Node_append.apply( this, X_HtmlParser_parse( v, true ) ); + case X_NodeType_XNODE : + // 親の xnodes から v を消す + v.parent && v[ 'remove' ](); + // IE4 でテキストノードの追加、FIXED 済でない場合、親に要素の追加を通知 + if( X_UA[ 'IE4' ] && !v[ '_tag' ] && ( this[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ) this[ '_flags' ] |= X_NodeFlags_IE4_DIRTY_CHILDREN; + break; + default : + return this; + }; + + v.parent = this; + xnodes[ xnodes.length ] = v; + if( this[ '_flags' ] & X_NodeFlags_IN_TREE ){ + v[ '_flags' ] |= X_NodeFlags_IN_TREE; + v[ '_xnodes' ] && X_Node_toggleInTreeFlag( v[ '_xnodes' ], true ); + X_Node_reserveUpdate(); + }; + return this; +}; + +/** + * ノードを挿入位置に追加する。 + * @alias Node.prototype.appendAt + * @param {number} index 挿入位置 0以上 + * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。 + * @return {Node} 自身。チェインメソッド + * @example myNode.appendAt( 1, node ); + */ +function X_Node_appendAt( start, v ){ + var xnodes, l, i; + + if( !this[ '_tag' ] ) return this; + + l = arguments.length; + if( !( xnodes = this[ '_xnodes' ] ) ) xnodes = this[ '_xnodes' ] = []; + + if( xnodes.length <= start ){ + if( l === 2 ) return this[ 'append' ]( v ); + for( i = 1; i < l; ++i ){ + this[ 'append' ]( arguments[ i ] ); + }; + return this; + }; + if( start < 0 ) start = 0; + if( 2 < l ){ + for( ; l; ){ + this[ 'appendAt' ]( start, arguments[ --l ] ); + }; + return this; + }; + + switch( X_Node_getType( v ) ){ + case X_NodeType_RAW_HTML : + case X_NodeType_RAW_TEXT : + v = Node( v ); + break; + case X_NodeType_HTML_STRING : + case X_NodeType_STRING : + v = X_HtmlParser_parse( v, true ); + for( i = v.length; i; ){ + this[ 'appendAt' ]( start, v[ --i ] ); + }; + return this; + case X_NodeType_XNODE : + // 親の xnodes から v を消す + if( v.parent ){ + if( v.parent === this ){ + i = v[ 'getOrder' ](); + if( i === start ) return this; + if( i < start ) --start; + }; + v[ 'remove' ](); + }; + // IE4 でテキストノードの追加、FIXED 済でない場合、親に要素の追加を通知 + if( X_UA[ 'IE4' ] && !v[ '_tag' ] && ( this[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ) this[ '_flags' ] |= X_NodeFlags_IE4_DIRTY_CHILDREN; + break; + default : + return this; + }; + + v.parent = this; + this[ '_xnodes' ].splice( start, 0, v ); + if( this[ '_flags' ] & X_NodeFlags_IN_TREE ){ + v[ '_flags' ] |= X_NodeFlags_IN_TREE; + v[ '_xnodes' ] && X_Node_toggleInTreeFlag( v[ '_xnodes' ], true ); + X_Node_reserveUpdate(); + }; + return this; +}; + +/** + * ノードを親に追加する。戻り値は子ノードなので、続けて操作が出来る。 + * @alias Node.prototype.appendTo + * @param {Node|string|HTMLElement} [parent] HTMLElement は内部のみ。 + * @param {number} [opt_index=-1] 挿入位置。省略した場合は最後に追加する。 + * @return {Node} 自身。チェインメソッド + * @example childNode.appendTo( parentNode, 1 ); + */ +function X_Node_appendTo( parent, opt_index ){ + switch( X_Node_getType( parent ) ){ + case X_NodeType_RAW_HTML : + parent = Node( parent ); + break; + case X_NodeType_HTML_STRING : + parent = X_HtmlParser_parse( parent, true ); + parent = parent[ 0 ] || parent; + case X_NodeType_XNODE : + break; + default : + return this; + }; + X_Type_isFinite( opt_index ) ? parent[ 'appendAt' ]( opt_index, this ) : parent[ 'append' ]( this ); + return this; +}; + + +/** + * ノードの直前の要素を取得。または直前に挿入。挿入する要素が先にいる兄弟でも正しく動作する。 + * @alias Node.prototype.prev + * @param {Node|string|HTMLElement|TextNode} [...v] HTMLElement と TextNode は内部のみ。 + * @return {Node} 自身。チェインメソッド + * @example childNode.prev( prevNode ); + */ +function X_Node_prev( v ){ + var parent = this.parent, xnodes, i, l; + + // getter + if( v === undefined ){ + if( !parent ) return; + xnodes = parent[ '_xnodes' ]; + i = xnodes.indexOf( this ); + return 0 < i ? xnodes[ i - 1 ] : v; + }; + + if( !parent ) return this; + + l = arguments.length; + if( 1 < l ){ + for( i = 0; l; ++i ){ + parent[ 'appendAt' ]( this[ 'getOrder' ]() - i, arguments[ --l ] ); + }; + return this; + }; + parent[ 'appendAt' ]( this[ 'getOrder' ](), v ); + return this; +}; + +/** + * ノードの直後の要素を取得。または直後に挿入。挿入する要素が先にいる兄弟でも正しく動作する。 + * @alias Node.prototype.next + * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。 + * @return {Node} 自身。チェインメソッド + * @example childNode.next( prevNode ); + */ +function X_Node_next( v ){ + var parent = this.parent, xnodes, i, l, start; + + // getter + if( v === undefined ){ + if( !parent ) return; + xnodes = parent[ '_xnodes' ]; + i = xnodes.indexOf( this ); + return ++i < xnodes.length ? xnodes[ i ] : v; + }; + + if( !parent ) return this; + + l = arguments.length; + start = this[ 'getOrder' ]() + 1; + + if( parent[ '_xnodes' ].length <= start ){ + for( i = 0; i < l; ++i ){ + parent[ 'append' ]( arguments[ i ] ); + }; + } else + if( 1 < l ){ + for( ; l; ){ + parent[ 'appendAt' ]( this[ 'getOrder' ]() + 1, arguments[ --l ] ); + }; + } else { + parent[ 'appendAt' ]( start, v ); + }; + return this; +}; + +/** + * 要素の入れ替え。自身は remove() される。 + * @alias Node.prototype.swap + * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。 + * @return {Node} 自身。チェインメソッド + * @example node.swap( newNode ); + */ +function X_Node_swap( v ){ + if( !this.parent ) return this; + return arguments.length === 1 ? this[ 'prev' ]( v )[ 'remove' ]() : X_Node_prev.apply( this, arguments )[ 'remove' ](); +}; + +/** + * 要素を抜く。 + * @alias Node.prototype.remove + * @return {Node} 自身。チェインメソッド + * @example node.remove(); + */ +function X_Node_remove(){ + var parent = this.parent, + elm; + + if( !parent ) return this; + + delete this.parent; + parent[ '_xnodes' ].splice( parent[ '_xnodes' ].indexOf( this ), 1 ); + + if( this[ '_flags' ] & X_NodeFlags_IN_TREE ){ + this[ '_flags' ] &= ~X_NodeFlags_IN_TREE & ~X_NodeFlags_IE5_DISPLAY_NONE_FIX; + this[ '_xnodes' ] && X_Node_toggleInTreeFlag( this[ '_xnodes' ], false ); + + if( X_UA_DOM.IE4 ){ + elm = this[ '_rawObject' ] || X_Node__ie4getRawNode( this ); + if( elm ){ + X_Node_reserveRemoval[ X_Node_reserveRemoval.length ] = this; + X_Node_reserveUpdate(); + } else + if( !this[ '_tag' ] && ( parent[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ){ + parent[ '_flags' ] |= X_NodeFlags_IE4_DIRTY_CHILDREN; + }; + } else { + elm = this[ '_rawObject' ]; + if( elm && elm.parentNode && elm.parentNode.tagName ){ + X_Node_reserveRemoval[ X_Node_reserveRemoval.length ] = this; + X_Node_reserveUpdate(); + }; + }; + }; + return this; +}; + +/** + * 子要素を破棄する。子要素は kill() されます。 + * @alias Node.prototype.empty + * @return {Node} 自身。チェインメソッド + * @example node.empty(); + */ +function X_Node_empty(){ + var xnodes = this[ '_xnodes' ], i; + if( xnodes && ( i = xnodes.length ) ){ + for( ; i; ){ + xnodes[ --i ][ 'kill' ](); + }; + xnodes.length = 0; + }; + return this; +}; + +function X_Node_onBeforeKill( e ){ + var xnodes = this[ '_xnodes' ], i, elm; + + if( ( this[ '_flags' ] & X_NodeFlags_EXIST ) === 0 ) return X_Callback_NONE; + + elm = this[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ); + elm && this[ '_listeners' ] && X_EventDispatcher_unlistenAll( this ); // イベントの退避 + + if( xnodes && ( i = xnodes.length ) ){ + for( ; i; ){ + X_Node_onBeforeKill.call( xnodes[ --i ] ); + }; + }; + + delete X_Node_CHASHE[ this[ '_uid' ] ]; + + if( e ){ + this[ 'remove' ](); + if( X_Node_reserveRemoval[ X_Node_reserveRemoval.length - 1 ] === this ){ + this[ '_flags' ] &= ~X_NodeFlags_EXIST; + return X_Callback_PREVENT_DEFAULT; + }; + }; + return X_Callback_NONE; +}; + + +/** + * 要素を子以下に持つか?調べる。 + * @alias Node.prototype.contains + * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。 + * @return {boolean} + * @example node.contains( testNode ); + */ +function X_Node_contains( v ){ + var elm, type, xnodes, i; + if( !v || !this[ '_tag' ] || this === v ) return false; + // contains ie4+ + if( ( elm = this[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ) ) && document.contains && ( type = X_Node_getType( v ) ) && ( type === X_NodeType_RAW_HTML || type === X_NodeType_RAW_TEXT ) ){ + return elm.contains( v ); + }; + + //if( document.compareDocumentPosition ){ + // + //}; + xnodes = this[ '_xnodes' ]; + if( !xnodes || !xnodes.length ) return false; + if( xnodes.indexOf( v ) !== -1 ) return true; // fast + for( i = xnodes.length; i; ){ + if( xnodes[ --i ][ 'contains' ]( v ) ) return true; + }; + return false; +}; + +/** + * index の子要素を取得する。 + * @alias Node.prototype.getChildAt + * @param {number} index 取得する子ノードの位置。0~ + * @return {Node} 子要素 + * @example child1 = parent.getChildAt(1); + */ +function X_Node_getChildAt( i ){ + var xnodes = this[ '_xnodes' ]; + return xnodes && 0 <= i && i < xnodes.length && xnodes[ i ]; +}; + +/** + * 子要素の数を取得する。 + * @alias Node.prototype.numChildren + * @return {number} 子要素の数。 + * @example n = parent.numChildren(); + */ +function X_Node_numChildren(){ + var xnodes = this[ '_xnodes' ]; + return xnodes ? xnodes.length : 0; +}; + +/** + * 最初の子要素を取得する。 + * @alias Node.prototype.firstChild + * @return {Node} 最初の子要素 + * @example child0 = parent.firstChild(); + */ +function X_Node_firstChild(){ + return this[ '_xnodes' ] && this[ '_xnodes' ][ 0 ]; +}; + +/** + * 最後の子要素を取得する。 + * @alias Node.prototype.lastChild + * @return {Node} 最後の子要素 + * @example lastChild = parent.lastChild(); + */ +function X_Node_lastChild(){ + var xnodes = this[ '_xnodes' ]; + return xnodes && xnodes[ xnodes.length - 1 ]; +}; + +/** + * 要素の index 位置を取得する。 + * @alias Node.prototype.getOrder + * @return {number} index -1 の場合、親を持たない。 + * @example index = node.getOrder(); + */ +function X_Node_getOrder(){ + var parent = this.parent; + return this === X_Node_html ? + 0 : + parent ? + parent[ '_xnodes' ].indexOf( this ) : + -1; +}; + +/** + * className の取得と設定。 + * @alias Node.prototype.className + * @return {string|Node} getter の場合 class 文字列、setter の場合自身。 + * @example // getter + * className = node.className(); + * // setter + * node.className( 'myClass myClass_new' ); + */ +function X_Node_className( v ){ + var node, _, __; + // getter + if( v === undefined ) return this[ '_className' ]; + + // setter + if( this[ '_className' ] === v ) return this; + if( !v || !X_Type_isString( v ) ){ + delete this[ '_className' ]; + } else { + // cleanup + _ = ' '; + __ = ' '; + while( v.indexOf( __ ) !== -1 ){ v = v.split( __ ).join( _ ); }; + v.charAt( 0 ) === _ && ( v = v.substr( 1 ) ); + v.lastIndexOf( _ ) === 0 && ( v = v.substr( 0, v.length - 1 ) ); + + if( this[ '_className' ] === v ) return this; + v ? ( this[ '_className' ] = v ) : delete this[ '_className' ]; + }; + this[ '_flags' ] |= X_NodeFlags_DIRTY_CLASSNAME; + this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); + return this; +}; + +/** + * className の追加。 + * @alias Node.prototype.addClass + * @param {string} className スペース区切りで複数のクラスを追加できる。 + * @return {Node} 自身。 + * @example node.addClass( 'myClass myClass_new' ); + */ +function X_Node_addClass( v ){ + var names = v.split( ' ' ), + i = names.length, + _class = this[ '_className' ], + name; + v = ''; + for( ; i; ){ + name = names[ --i ]; + if( !name ) continue; + !this[ 'hasClass' ]( name ) && ( v += ( v ? ' ' : '' ) + name ); + }; + return v ? this[ 'className' ]( ( _class ? _class + ' ' : '' ) + v ) : this; +}; + +/** + * className の削除。 + * @alias Node.prototype.removeClass + * @param {string} className スペース区切りで複数のクラスを削除できる。 + * @return {Node} 自身。 + * @example node.removeClass( 'myClass myClass_new' ); + */ +function X_Node_removeClass( v ){ + var _ = ' ', + _class = this[ '_className' ], + names = v.split( _ ), + classNames, i, f, j; + + if( !_class ) return this; + for( classNames = _class.split( _ ), i = classNames.length; i; ){ + _class = classNames[ --i ]; + for( j = names.length; j; ){ + if( _class === names[ --j ] ){ + classNames.splice( i, 1 ); + names.splice( j, 1 ); + f = true; + break; + }; + }; + }; + return f ? this[ 'className' ]( classNames.join( _ ) ) : this; +}; + +/** + * className の更新。 + * @alias Node.prototype.toggleClass + * @param {string} className スペース区切りで複数のクラスを削除できる。 + * @param {boolean} [opt_toggle=] true はクラスの追加。false はクラスの削除。undefined はクラスのトグル。 + * @return {Node} 自身。 + * @example node.toggleClass( 'myClass myClass_new', !!n ); + */ +function X_Node_toggleClass( v, opt_toggle ){ + var names, i, name; + if( opt_toggle !== undefined ){ + return !opt_toggle ? this[ 'removeClass' ]( v ) : this[ 'addClass' ]( v ); + }; + names = v.split( ' ' ); + for( i = names.length; i; ){ + name = names[ --i ]; + this[ 'hasClass' ]( name ) ? this[ 'removeClass' ]( name ) : this[ 'addClass' ]( name ); + }; + return this; +}; + +/** + * className を持つか。 + * @alias Node.prototype.hasClass + * @param {string} className スペース区切りで複数のクラスを削除できる。 + * @return {boolean} + * @example node.hasClass( 'myClass myClass_new' ); + */ +function X_Node_hasClass( v ){ + var _ = ' ', + _class = this[ '_className' ], + i, name; + if( _class === v ) return true; + if( !_class ) return false; + + _class = _ + _class + _; + if( _class.indexOf( _ + v + _ ) !== -1 ) return true; // lucky hit + + for( v = v.split( _ ), i = v.length; i; ){ + name = v[ --i ]; + if( name === '' ) continue; + if( _class.indexOf( _ + name + _ ) === -1 ) return false; + }; + return true; +}; + +/** + * innerHTML 取得・設定。outerHTML が欲しい場合は、xnode.call('outerHTML') とできる。 + * @alias Node.prototype.html + * @param {string} [html=] html文字列 + * @return {string|Node} + * @example node.html( '' ); + */ +function X_Node_html( html ){ + var _ = '', q = '"', xnodes, n, i, l; + // setter + if( html !== undefined ){ // String 以外に Number や false null なども許可 + if( !this[ '_tag' ] ) return this[ 'text' ]( html ); + return html ? this[ 'empty' ]()[ 'append' ].apply( this, X_HtmlParser_parse( html, true ) ) : this[ 'empty' ](); + }; + + // getter + if( !this[ '_tag' ] ){ + return this[ '_text' ]; + }; + + this[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT && X_Node_CSS_objToCssText( this ); + + html = !X_Node_outerXNode ? [] : [ + '<', this[ '_tag' ], + this[ '_id' ] ? ' id="' + this[ '_id' ] + q : _, + this[ '_className' ] ? ' class="' + this[ '_className' ] + q : _, + this[ '_flags' ] & X_NodeFlags_OLD_ATTRTEXT ? X_Node_Attr_objToAttrText( this ) : this[ '_attrText' ], + this[ '_cssText' ] ? ' style="' + this[ '_cssText' ] + q : _, + '>' ]; + + n = html.length; + if( ( xnodes = this[ '_xnodes' ] ) && ( l = xnodes.length ) ){ + if( !X_Node_outerXNode ) X_Node_outerXNode = this; + for( i = 0; i < l; ++i ){ + html[ n ] = xnodes[ i ][ 'html' ](); + ++n; + }; + if( X_Node_outerXNode === this ) X_Node_outerXNode = null; + }; + !X_Node_outerXNode || X_Dom_DTD_EMPTY[ this[ '_tag' ] ] || ( html[ n ] = '<\/' + this[ '_tag' ] + '>' ); + return html.join( _ ); +}; + +/* + * null が来たら '', 数値等が来たら文字列化 + */ +/** + * textContent 取得・設定。null が来たら '', 数値等が来たら文字列化 + * @alias Node.prototype.text + * @param {string} [text=] + * @return {string|Node} + * @example node.text( 'Hello, world!' ); + */ +function X_Node_text( text ){ + var xnodes, texts, i, l; + // setter + if( text !== undefined ){ + if( text === null ) text = ''; + text += ''; + + if( !this[ '_tag' ] ){ + if( this[ '_text' ] !== text ){ + text ? ( this[ '_text' ] = text ) : delete this[ '_text' ]; + this[ '_flags' ] |= X_NodeFlags_DIRTY_CONTENT; + this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); + }; + return this; + }; + 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; + }; + // getter + if( this[ '_tag' ] ){ + if( ( xnodes = this[ '_xnodes' ] ) && ( l = xnodes.length ) ){ + for( texts = [], i = 0; i < l; ++i ){ + texts[ i ] = xnodes[ i ][ 'text' ](); + }; + return texts.join( '' ); + }; + return ''; + }; + return this[ '_text' ]; +}; + +/* + * HTML要素に対して name の関数を実行しその戻り値を返す。関数に渡す引数も任意に設定できる。 + */ +function X_Node_call( name /*, opt_args... */ ){ + var l = arguments.length - 1, + raw, func, args, params, i; + + switch( name ){ + case 'nodeType' : + return this[ '_tag' ] ? 1 : 3; + case 'outerHTML' : + X_Node_outerXNode = X_Node_body; // == true ならなんでもよい。型を合わすために xbody にしている + v = this[ 'html' ](); + X_Node_outerXNode = null; + return v; + case 'treeIsDirty' : + return !!X_Node_updateTimerID; + case 'fontSize' : + return X_Node_CSS_getCharSize( this ); + case 'inGPU' : + return !!( this[ '_flags' ] & ( X_NodeFlags_GPU_NOW | X_NodeFlags_GPU_RELEASE_RESERVED ) ); + }; + + X_Node_updateTimerID && X_Node_startUpdate(); + + raw = this[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ); + if( !raw ) return; + + if( name === 'scrollTo' ){ + raw.scrollLeft = arguments[ 1 ] || 0; + raw.scrollTop = arguments[ 2 ] || 0; + return; + }; + + func = raw[ name ]; + if( X_Type_isFunction( func ) ){ + if( l ){ + args = X_Object_cloneArray( arguments ); + args.shift(); + return func.apply( raw, args ); + }; + return raw[ name ](); + } else + if( X_Type_isUnknown( func ) ){ + // typeof func === unknown に対策 + // http://la.ma.la/blog/diary_200509031529.htm + if( l ){ + args = X_Object_cloneArray( arguments ); + args.shift(); + + params = []; + for( i = 0; i < l; ++i ){ + params[ i ] = '_' + i; + }; + params = params.join( ',' ); + return Function( + params, + [ 'return this.', name, '(', params, ')' ].join( '' ) + ).apply( raw, args ); + }; + return raw[ name ](); + }; +}; + +/* + * xnode を this として関数を実行する。 NodeList.each と動作を合わせてあるため関数の戻り値は破棄される。 + * 関数に渡す引数も任意に設定できる。 + */ +function X_Node_each( func /*, opt_args */ ){ + var args; + if( 1 < arguments.length ){ + args = X_Object_cloneArray( arguments ); + args[ 0 ] = 0; + func.apply( this, args ); + } else { + func.call( this, 0 ); + }; + return this; +}; + + +/* -------------------------------------- + * Async commit update + * + * TODO Timer や DOM イベントの呼び出しの最後に、まだ一度も commitUpdate していないなら commitUpdate してしまう。 + */ + +function X_Node_reserveUpdate(){ + if( !X_Node_updateTimerID ) X_Node_updateTimerID = X_Timer_requestFrame( X_Node_startUpdate ); +}; + +var X_Node_updateReservedByReleaseGPU = false; + +function X_Node_startUpdate( time ){ + var removal, i, xnode; + + if( !X_Node_updateTimerID || X_ViewPort_readyState < X_EVENT_INIT ){ + return; + }; + + X_Timer_cancelFrame( X_Node_updateTimerID ); + X_Node_updateTimerID = 0; + + if( time ){ + // X.Timer 経由でないと発火しない このイベントでサイズを取ると無限ループに + X_System[ '_listeners' ] && X_System[ '_listeners' ][ X_EVENT_BEFORE_UPDATE ] && X_System[ 'dispatch' ]( X_EVENT_BEFORE_UPDATE ); + }; + + removal = X_Node_reserveRemoval; + + if( i = removal.length ){ + for( ; i; ){ + xnode = removal[ --i ]; + // TODO GPU レイヤーの子の場合、remove をスキップする。 非GPU レイヤーへ apppend される場合、clone する? + X_Node__actualRemove( xnode ); + ( xnode[ '_flags' ] & X_NodeFlags_EXIST ) === 0 && xnode[ 'kill' ](); + }; + removal.length = 0; + }; + + if( X_Node_html[ '_flags' ] & X_Node_BitMask_IS_DIRTY ){ + X_Node__commitUpdate( X_Node_html, X_Node_html[ '_rawObject' ].parentNode, null, X_Node_html[ '_flags' ] ); + } else { + X_Node__commitUpdate( X_Node_head, X_Node_head[ '_rawObject' ].parentNode, null, X_Node_head[ '_flags' ] ); + X_Node__commitUpdate( X_Node_body, X_Node_body[ '_rawObject' ].parentNode, null, X_Node_body[ '_flags' ] ); + }; + + if( X_Node_updateReservedByReleaseGPU ){ + X_Node_reserveUpdate(); + X_Node_updateReservedByReleaseGPU = false; + }; + + if( time ){ + // X.Timer 経由でないと発火しない このイベントでサイズを取ると無限ループに + X_System[ '_listeners' ] && X_System[ '_listeners' ][ X_EVENT_UPDATED ] && X_System[ 'dispatch' ]( X_EVENT_UPDATED ); + } else { + X_System[ '_listeners' ] && X_System[ '_listeners' ][ X_EVENT_UPDATED ] && X_System[ 'asyncDispatch' ]( X_EVENT_UPDATED ); + }; + + X_ViewPort[ '_listeners' ] && X_ViewPort[ '_listeners' ][ X_EVENT_AFTER_UPDATE ] && X_ViewPort[ 'asyncDispatch' ]( X_EVENT_AFTER_UPDATE ); +}; + +/* + * 1. GPU_NOW の場合、子の変更は行わない + * 2. GPU解放予約 の場合//、この要素のみ変更を行う。rAF 後にさらに更新するためフラグを立てる。 + * 3. GPU予約 -> GPU + * 4. style="display:none" の場合、これ以下の変更を行わない。 + * 5. ie5 非表示フラグが立っていて、親と自身の class・id によって非表示になっていて、親と自身に変更がない。accumulatedFlags を使用。 + * -> TODO これ TREE の変更を検出できない。 remove したときに 子まで X_NodeFlags_IE5_DISPLAY_NONE_FIXを落とす。 + * 6. 要素の生成 + * 7. 要素の位置のズレを補正 + * 8. 更新の適用 + * 9. ie5 親及び自身へのクラス・id指定で display:none になるケースがありそれを検出。 + * このままでは、生成と破棄が繰り返されてしまうので親と自身のクラス・idが変わった場合、ツリー位置の変化があった場合に再生する。 + */ +var X_Node__commitUpdate = + X_UA_DOM.W3C ? + ( function( that, parentElement, nextElement, accumulatedFlags ){ + var elm = that[ '_rawObject' ], + created, xnodes, l, next; + + // 1. GPU 一切の更新をスキップ + if( that[ '_flags' ] & X_NodeFlags_GPU_NOW ){ + console.log( '更新のskip ' + !!( that[ '_flags' ] & X_Node_BitMask_IS_DIRTY ) ); + that[ '_flags' ] & X_Node_BitMask_IS_DIRTY && X_Node__updateRawNode( that, elm ); + return elm; + }; + + // 2. GPU解放予約 + if( that[ '_flags' ] & X_NodeFlags_GPU_RELEASE_RESERVED ){ + // console.log( 'GPU 解放 ' ); + //X_Node_updateReservedByReleaseGPU = true; + //X_Node__updateRawNode( that, elm ); + that[ '_flags' ] &= X_Node_BitMask_RESET_GPU; + //return elm;// TODO もしかしたらこのタイミングで更新できるかも。 + }; + + // 3. GPU予約 -> GPU + if( that[ '_flags' ] & X_NodeFlags_GPU_RESERVED ){ + that[ '_flags' ] &= X_Node_BitMask_RESET_GPU; + that[ '_flags' ] |= X_NodeFlags_GPU_NOW; + }; + + // 4. style="display:none" の場合 + if( that[ '_flags' ] & X_NodeFlags_STYLE_IS_DISPLAY_NONE ){ + if( X_Node_displayNoneFixForIE5 ){ + // filter の効いている要素を含む要素は display:none が無視される。 + // filter = '' で削除はできるが、再表示時に filter が消える。 -> filter な要素を削除してしまう。 + if( elm && elm.parentNode ){ + X_Node__actualRemove( that ); + }; + return nextElement; + }; + elm && ( elm.style.display = 'none' ); + return ( elm && elm.nextSibling === nextElement ) ? elm : nextElement; + }; + + // 5. ie5 非表示fixフラグ + accumulatedFlags |= that[ '_flags' ]; + + if( that[ '_flags' ] & X_NodeFlags_IE5_DISPLAY_NONE_FIX ){ + if( accumulatedFlags & ( X_NodeFlags_DIRTY_POSITION | X_NodeFlags_DIRTY_ID | X_NodeFlags_DIRTY_CLASSNAME ) === 0 ){ + return nextElement; + }; + }; + + // 6. 要素の生成 + if( !elm ){ + if( !that[ '_tag' ] ){ + that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; + that[ '_rawObject' ] = elm = document.createTextNode( X_String_chrReferanceTo( that[ '_text' ] ) ); + if( !X_UA[ 'IE' ] ){ + elm[ 'UID' ] = that[ '_uid' ]; + }; + } else + if( X_Node_strictElmCreation ){ + that[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT && X_Node_CSS_objToCssText( that, true ); // OLD_CSSTEXT ?? + + that[ '_rawObject' ] = elm = + document.createElement( [ + '<', that[ '_tag' ], + ' UID="', that[ '_uid' ], '"', + that[ '_id' ] ? ' id="' + that[ '_id' ] + '"' : '', + that[ '_className' ] ? ' class="' + that[ '_className' ] + '"' : '', + X_Node_Attr_objToAttrText( that, true ), + that[ '_cssText' ] ? ' style="' + that[ '_cssText' ] + '"' : '', + '>' ].join( '' ) ); + } else { + that[ '_rawObject' ] = elm = document.createElement( that[ '_tag' ] ); + }; + + // IE には要素追加のタイミングで起こるメモリリークがありここで追加 + if( !X_Node_addTreeAfterChildren ){ + nextElement ? + parentElement.insertBefore( elm, nextElement ) : + parentElement.appendChild( elm ); + }; + + if( that[ '_tag' ] ){ + X_EventDispatcher_toggleAllEvents( that, true );// イベントの復帰 + that[ '_flags' ] |= X_NodeFlags_ACTUAL_LISTENING; + + 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_NodeFlags_DIRTY_ATTR ); // _newAttrs には ネットワーク系属性が入っている。Network 系の属性は遅らせて設定 + that[ '_flags' ] |= X_NodeFlags_DIRTY_IE_FILTER;// doc 追加後に filter を指定しないと有効にならない。 + } else { + elm[ 'UID' ] = that[ '_uid' ]; + that[ '_newAttrs' ] = that[ '_attrs' ]; + that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; + that[ '_flags' ] |= X_NodeFlags_DIRTY_ID | X_NodeFlags_DIRTY_CLASSNAME | X_NodeFlags_DIRTY_ATTR | X_NodeFlags_DIRTY_CSS | X_NodeFlags_DIRTY_IE_FILTER; + + // http://outcloud.blogspot.jp/2010/09/iframe.html + // この問題は firefox3.6 で確認 + if( X_UA[ 'Gecko' ] ){ + if( that[ '_tag' ] === 'IFRAME' && ( !that[ '_attrs' ] || !that[ '_attrs' ][ 'src' ] ) ){ + //elm.contentWindow.location.replace = elm.src = 'about:blank'; + that[ 'attr' ]( 'src', 'about:blank' ); + }; + }; + }; + }; + + created = true; + } else + // 7. 要素の位置のズレを補正 + if( elm.parentNode !== parentElement || ( nextElement && elm.nextSibling !== nextElement ) ){ + nextElement ? + parentElement.insertBefore( elm, nextElement ) : + parentElement.appendChild( elm ); + }; + + if( that[ '_listeners' ] && ( that[ '_flags' ] & X_NodeFlags_ACTUAL_LISTENING ) === 0 ){ + X_EventDispatcher_toggleAllEvents( that, true );// イベントの退避 + that[ '_flags' ] |= X_NodeFlags_ACTUAL_LISTENING; + }; + + // 8. 更新の適用 + 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 ) + // currentStyle を観ていたときはエラーで停止する、alert と挟むと正常に動いて支離滅裂 + if( X_Node_displayNoneFixForIE5 && that[ '_tag' ] ){ + if( elm.runtimeStyle.display === 'none' ){ + X_Node__actualRemove( that ); + that[ '_flags' ] |= X_NodeFlags_IE5_DISPLAY_NONE_FIX; + return nextElement; + } else { + that[ '_flags' ] &= ~X_NodeFlags_IE5_DISPLAY_NONE_FIX; + }; + }; + + // 10. 子要素の更新。 + if( ( xnodes = that[ '_xnodes' ] ) && ( l = xnodes.length ) ) { + for( ; l; ){ + next = X_Node__commitUpdate( xnodes[ --l ], elm, next, accumulatedFlags ); + }; + }; + + if( created && X_Node_addTreeAfterChildren ){ + nextElement ? + parentElement.insertBefore( elm, nextElement ) : + parentElement.appendChild( elm ); + + if( X_UA[ 'Gecko' ] && that[ '_tag' ] === 'IFRAME' && elm.contentWindow ){ + // tree に追加されるまで contentWindow は存在しない。 + elm.contentWindow.location.replace = elm.src; + }; + }; + + return elm; + }) : + X_UA_DOM.IE4 ? + ( function( that, parentElement, prevElement, accumulatedFlags ){ + var elm = that[ '_rawObject' ] || X_Node__ie4getRawNode( that ), + xnodes, l, i, dirty, mix, html, text, prev; + + if( !that[ '_tag' ] ){ + that[ '_flags' ] & X_NodeFlags_DIRTY_CONTENT && X_Node__updateRawNode( that, elm ); + return elm; + }; + + // 4. style="display:none" の場合 + if( that[ '_flags' ] & X_NodeFlags_STYLE_IS_DISPLAY_NONE ){ + if( elm ){ + elm.style.display = 'none'; + if( elm.style.display !== 'none' ){ // ie4 の style は currentStyle 相当らしい、、、? div 以外への display:none が効かないので remove する。 + X_Node__actualRemove( that ); + return prevElement; + }; + }; + return elm || prevElement; + }; + + if( !elm ){ + prevElement ? + prevElement.insertAdjacentHTML( 'AfterEnd', X_Node__actualCreate( that, false ) ) : + parentElement.insertAdjacentHTML( 'AfterBegin', X_Node__actualCreate( that, false ) ); + X_Node__afterActualCreate( that ); + return that[ '_rawObject' ] || X_Node__ie4getRawNode( that ); + }; + + accumulatedFlags |= that[ '_flags' ]; + + xnodes = that[ '_xnodes' ]; + l = xnodes ? xnodes.length : 0; + dirty = !!( that[ '_flags' ] & X_NodeFlags_IE4_DIRTY_CHILDREN ); + + /* + * HTML の下に TextNode だけ 。MIX_FIXED でない場合、削除、追加 を親に通知 + * HTML の下に HTML だけ + * HTML の下は MIX -> TextNode, html の削除、変更、追加 + * HTML の下は MIX_FIXED -> TextNode を に置き換えてあるのでW3C DON 的に触ることができる + */ + if( dirty ){ + that[ '_flags' ] &= ~X_NodeFlags_IE4_DIRTY_CHILDREN; + for( i = 0; i < l; ++i ){ + if( xnodes[ i ][ '_tag' ] ){ + that[ '_flags' ] |= X_NodeFlags_IE4_HAS_ELEMENT; + } else { + that[ '_flags' ] |= X_NodeFlags_IE4_HAS_TEXTNODE; + }; + if( that[ '_flags' ] & X_Node_BitMask_IE4_IS_MIX === X_Node_BitMask_IE4_IS_MIX ){ + mix = true; + break; + }; + }; + }; + + if( that[ '_flags' ] & X_NodeFlags_IE4_FIXED || that[ '_flags' ] & X_Node_BitMask_IE4_IS_MIX === X_NodeFlags_IE4_HAS_ELEMENT ){ + for( i = 0; i < l; ++i ){ + prev = X_Node__commitUpdate( xnodes[ i ], elm, prev, accumulatedFlags ); + }; + } else + if( mix ){ + html = []; + for( i = 0; i < l; ++i ){ + html[ i ] = X_Node__actualCreate( xnodes[ i ], false ); + }; + elm.innerHTML = html.join( '' ); + for( i = 0; i < l; ++i ){ + X_Node__afterActualCreate( xnodes[ i ] ); + }; + that[ '_flags' ] |= X_NodeFlags_IE4_FIXED; + } else + if( that[ '_flags' ] & X_NodeFlags_IE4_HAS_TEXTNODE ){ + dirty = dirty || false; + for( i = 0; i < l; ++i ){ + text = xnodes[ i ]; + if( text[ '_flags' ] & X_Node_BitMask_IS_DIRTY ){ + text[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; + dirty = true; + }; + }; + if( dirty ) elm.innerHTML = that[ 'text' ](); + }; + + if( accumulatedFlags & X_Node_BitMask_IS_DIRTY ) delete that[ '_fontSize' ]; + + that[ '_flags' ] &= ~X_NodeFlags_DIRTY_POSITION; + that[ '_flags' ] & X_Node_BitMask_IS_DIRTY && X_Node__updateRawNode( that, elm ); + return elm; + }) : + (function(){}); + +/* + * GPU レイヤーするブラウザは、子要素から変更を当てていく? <- とりあえず、親要素から。 + */ +var X_Node__updateRawNode = + X_UA_DOM.W3C ? + ( function( that, elm ){ + var attrs, rename, k, v; + + // textNode + if( !that[ '_tag' ] ){ + elm.data = X_String_chrReferanceTo( that[ '_text' ] ); + that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; + return; + }; + // id + if( that[ '_flags' ] & X_NodeFlags_DIRTY_ID ){ + that[ '_id' ] ? ( elm.id = that[ '_id' ] ) : ( elm.id && elm.removeAttribute( 'id' ) ); + }; + // className + if( that[ '_flags' ] & X_NodeFlags_DIRTY_CLASSNAME ){ + that[ '_className' ] ? ( elm.className = that[ '_className' ] ) : ( elm.className && elm.removeAttribute( X_UA[ 'IE' ] < 8 ? 'className' : 'class' ) ); // className は ie7- + }; + + // attr + if( that[ '_flags' ] & X_NodeFlags_DIRTY_ATTR && ( attrs = that[ '_newAttrs' ] || that[ '_attrs' ] ) ){ + rename = X_Node_Attr_renameForDOM; + + for( k in attrs ){ + v = attrs[ k ]; + + switch( that[ '_tag' ] + k ){ + case 'TEXTAREAvalue' : + // IETester 5.5 ではエラーが出なかった.MultipulIE5.5 ではエラーが出たので + if( !X_UA[ 'MacIE' ] && X_UA[ 'IE5x' ] ){ + elm.firstChild ? + ( elm.firstChild.data = v || '' ) : + elm.appendChild( document.createTextNode( v || '' ) ); + continue; + }; + break; + + case 'IFRAMEsrc' : + // http://outcloud.blogspot.jp/2010/09/iframe.html + // この問題は firefox3.6 で確認 + if( X_UA[ 'Gecko' ] && elm.contentWindow ){ + elm.contentWindow.location.replace = elm.src = v || ''; + continue; + }; + break; + + case 'IFRAMEname' : + // http://d.hatena.ne.jp/NeoCat/20080921/1221940658 + // こちらに名前をsetしないとtargetが動作しない + // これってあとから name を変更できないバグでは? itozyun + // if( X_UA[ 'IE' ] ) elm.name = elm.contentWindow.name = v || ''; + }; + + //if( X_EMPTY_OBJECT[ k ] ) continue; + // TODO IE では input, なぜか button, object も type, name の変更が出来ない、同値で置き換えようとしても不可 + v === undefined ? + elm.removeAttribute( rename[ k ] || k ) : + ( elm[ rename[ k ] || k ] = X_Node_Attr_noValue[ k ] ? k : v ); + }; + delete that[ '_newAttrs' ]; + }; + + // style + if( that[ '_flags' ] & X_NodeFlags_DIRTY_CSS ){ + if( that[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT ? X_Node_CSS_objToCssText( that ) : that[ '_cssText' ] ){ + X_UA[ 'Opera78' ] || X_UA[ 'NN6' ] ? + elm.setAttribute( 'style', that[ '_cssText' ] ) : // opera8用 + ( elm.style.cssText = that[ '_cssText' ] ); + } else { + elm.style.cssText = ''; // IE5.5以下 Safari3.2 で必要 + elm.removeAttribute( 'style' ); + }; + } else + if( that[ '_flags' ] & X_NodeFlags_DIRTY_IE_FILTER ){ + v = X_Node_CSS_objToIEFilterText( that ); + if( v ){ + elm.style.filter = v; + that[ '_flags' ] |= X_NodeFlags_IE_FILTER_NOW; + } else { + elm.style.removeAttribute( 'filter' ); + that[ '_flags' ] &= ~X_NodeFlags_IE_FILTER_NOW; + }; + }; + + that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; + }) : + X_UA_DOM.IE4 ? + ( function( that, elm ){ + var attrs, rename, k, v; + + // fake textNode + if( !that[ '_tag' ] ){ + elm.innerText = that[ '_text' ]; + that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; + return; + }; + + /* + * http://www.tohoho-web.com/js/element.htm + * title、className、id、lang、language には setAttribute でなく、element.id で直接読み書きできる + */ + // id + if( that[ '_flags' ] & X_NodeFlags_DIRTY_ID ) elm.setAttribute( 'id', that[ '_id' ] || ( 'ie4uid' + that[ '_uid' ] ) ); + + // className + if( that[ '_flags' ] & X_NodeFlags_DIRTY_CLASSNAME ){ + that[ '_className' ] ? ( elm.className = that[ '_className' ] ) : elm.removeAttribute( 'class' ); + }; + // style + if( that[ '_flags' ] & X_NodeFlags_DIRTY_CSS ){ + if( that[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT ? X_Node_CSS_objToCssText( that ) : that[ '_cssText' ] ){ + elm.style.cssText = that[ '_cssText' ]; + } else { + elm.style.cssText = ''; + elm.removeAttribute( 'style' ); + }; + } else + if( that[ '_flags' ] & X_NodeFlags_DIRTY_IE_FILTER ){ + v = X_Node_CSS_objToIEFilterText( that ); + if( v ){ + elm.style.filter = v; + that[ '_flags' ] |= X_NodeFlags_IE_FILTER_NOW; + } else { + elm.style.removeAttribute( 'filter' ); + that[ '_flags' ] &= ~X_NodeFlags_IE_FILTER_NOW; + }; + }; + + // attr + if( that[ '_flags' ] & X_NodeFlags_DIRTY_ATTR && ( attrs = that[ '_newAttrs' ] || that[ '_attrs' ] ) ){ + rename = X_Node_Attr_renameForDOM; + for( k in attrs ){ + //if( X_EMPTY_OBJECT[ k ] ) continue; + ( v = attrs[ k ] ) === undefined ? + elm.removeAttribute( rename[ k ] || k ) : + elm.setAttribute( rename[ k ] || k, X_Node_Attr_noValue[ k ] ? k : v ); + }; + delete that[ '_newAttrs' ]; + }; + + that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; + }) : + (function(){}); + +/* -------------------------------------- + * Create + * + * http://d.hatena.ne.jp/uupaa/20080718/1216362040 + * DOM Rangeが使える環境(Firefox2+,Opera9+,Safari3+)なら、innerHTMLいらずで、ガーって書けます。 + * return document.createRange().createContextualFragment("
    "); + * insertAdjacentHTML + * + * ie7 以下では iframe の frameborder や、input name は、createElement 後に setAttribute しても無視される + * + * fragument がある場合 children も足して + * Mozilla: 1.0+, IE: 5.5+, Netscape: 2.0+, Safari: 1.0+, Opera: 7.0+ + * ie6 大丈夫?fragment の場合リークしないか?チェックが必要 + * http://msdn.microsoft.com/ja-jp/library/bb250448%28v=vs.85%29.aspx + * + * document.createElement of ie4 is only for OPTION & IMAGE. + */ +var X_Node__actualCreate = + X_UA_DOM.IE4 && (function( that, isChild ){ + var uid = that[ '_uid' ], + html, xnodes, n, i, l; + + if( !that[ '_tag' ] ){ + html = [ '', that[ '_text' ], '' ];// fake textNode + delete that[ '_rawObject' ]; + } else { + if( !isChild ) X_Node__actualRemove( that, /* true */ false ); + + that[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT && X_Node_CSS_objToCssText( that, true ); + + html = [ + '<', that[ '_tag' ], ' id=', ( that[ '_id' ] || ( 'ie4uid' + uid ) ), ' UID="', uid, '"', + that[ '_className' ] ? ' class="' + that[ '_className' ] + '"' : '', + X_Node_Attr_objToAttrText( that, true ), + that[ '_cssText' ] ? ' style="' + that[ '_cssText' ] + '"' : '', + '>' ]; + + n = html.length; + if( ( xnodes = that[ '_xnodes' ] ) && ( l = xnodes.length ) ){ + + that[ '_flags' ] &= ~X_NodeFlags_IE4_DIRTY_CHILDREN; + for( i = 0; i < l; ++i ){ + if( xnodes[ i ][ '_tag' ] ){ + that[ '_flags' ] |= X_NodeFlags_IE4_HAS_ELEMENT; + } else { + that[ '_flags' ] |= X_NodeFlags_IE4_HAS_TEXTNODE; + }; + if( that[ '_flags' ] & X_Node_BitMask_IE4_IS_MIX === X_Node_BitMask_IE4_IS_MIX ){ + break; + }; + }; + + if( that[ '_flags' ] & X_Node_BitMask_IE4_IS_MIX === X_NodeFlags_IE4_HAS_TEXTNODE ){ + // only textnode + html[ n ] = that[ 'text' ](); + ++n; + } else { + for( i = 0; i < l; ++i ){ + html[ n ] = X_Node__actualCreate( xnodes[ i ], true ); + ++n; + }; + that[ '_flags' ] |= X_NodeFlags_IE4_FIXED; + }; + }; + X_Dom_DTD_EMPTY[ that[ '_tag' ] ] || ( html[ n ] = '<\/' + that[ '_tag' ] + '>' ); + + that[ '_newAttrs' ] && ( that[ '_flags' ] |= X_NodeFlags_DIRTY_ATTR ); + }; + + return html.join( '' ); + }); + +var X_Node__afterActualCreate = + X_UA_DOM.IE4 && (function( that ){ + var xnodes, i, v; + + if( !that[ '_tag' ] ) return that; + + if( ( xnodes = that[ '_xnodes' ] ) && ( i = xnodes.length ) ){ + for( ; i; ){ + X_Node__afterActualCreate( xnodes[ --i ] ); + }; + }; + // ネットワーク系属性と filter は要素生成後に適用 + if( that[ '_flags' ] & ( X_NodeFlags_DIRTY_ATTR | X_NodeFlags_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 );// イベントの復帰 + }); + +var X_Node__actualRemove = + X_UA_DOM.W3C ? + // GPUレイヤーにいるうちは remove しない。-> GPU解除してから remove する + // Firefox34 では遭遇せず、Safari で何度かアニメーションしているうちに発生 + ( function( that, isChild ){ + var xnodes = that[ '_xnodes' ], + elm = that[ '_rawObject' ], + child, i, l; + + if( xnodes && ( l = xnodes.length ) ){ + for( i = 0; i < l; ++i ){ + child = xnodes[ i ]; + child[ '_tag' ] && X_Node__actualRemove( child, true ); + }; + }; + + if( !elm ) return; + + if( that[ '_flags' ] & X_NodeFlags_ACTUAL_LISTENING ){ + that[ '_listeners' ] && X_EventDispatcher_toggleAllEvents( that, false );// イベントの退避 + that[ '_flags' ] &= ~X_NodeFlags_ACTUAL_LISTENING; + }; + + // ie5では filter の効いている要素をremove時に破棄して、再度append 時に新規生成する + // ちなみに elm.filters に触ると ie8 でなぜかカラム落ちが発生、、、 + if( X_Node_displayNoneFixForIE5 ){ + if( elm.filters && elm.filters.length ){ + isChild = false; + delete that[ '_rawObject' ]; + // 破棄前にインタラクティブな属性値を控える + 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.innerHTML = ''; + }; + }; + + if( !X_UA[ 'MacIE' ] ){ + // elm.parentNode.tagName for ie7 + !isChild && elm.parentNode && elm.parentNode.tagName && elm.parentNode.removeChild( elm ); + } else { + !isChild && elm.parentNode && elm.parentNode.tagName && X_TEMP._fixed_remove( elm, that ); + }; + }) : + X_UA_DOM.IE4 ? + ( function( that, isChild ){ + var xnodes = that[ '_xnodes' ], + elm = that[ '_rawObject' ] || X_Node__ie4getRawNode( that ), + i, l, xnode; + if( xnodes && ( l = xnodes.length ) ){ + for( i = 0; i < l; ++i ){ + X_Node__actualRemove( xnodes[ i ], true ); + }; + }; + + if( !elm ) return; + that[ '_listeners' ] && X_EventDispatcher_toggleAllEvents( that, false );// イベントの退避 + + // 破棄前にインタラクティブな属性値を控える + 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 = ''; + delete that[ '_rawObject' ]; + }) : + (function(){}); + +X_ViewPort[ 'listenOnce' ]( X_EVENT_UNLOAD, X_Node__actualRemove, [ X_Node_html, true ] ); + diff --git a/0.6.x/js/02_dom/22_XTreeBuilder.js b/0.6.x/js/02_dom/22_XTreeBuilder.js index 09d371e..7daff08 100644 --- a/0.6.x/js/02_dom/22_XTreeBuilder.js +++ b/0.6.x/js/02_dom/22_XTreeBuilder.js @@ -369,7 +369,7 @@ X_TEMP.bindElementToXnode = if( tag.charAt( 0 ) === '/' ) tag = tag.slice( 1 ); xnode[ '_tag' ] = tag; //}; - xnode[ '_flags' ] |= X_Node_State.IN_TREE; + xnode[ '_flags' ] |= X_NodeFlags_IN_TREE; xnode[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; elm[ 'UID' ] = xnode[ '_uid' ]; current.xtext = null; @@ -417,7 +417,7 @@ X_TEMP.bindElementToXnode = ++current.j; xnode[ '_rawObject' ] = elm; - xnode[ '_flags' ] |= X_Node_State.IN_TREE; + xnode[ '_flags' ] |= X_NodeFlags_IN_TREE; xnode[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; xnode[ '_text' ] = elm.data; // 正確 @@ -455,7 +455,7 @@ X_TEMP.bindElementToXnode = xnode.parent = parent; if( !xnode[ '_tag' ] ){ - xnode[ '_flags' ] |= X_Node_State.IN_TREE; + xnode[ '_flags' ] |= X_NodeFlags_IN_TREE; xnode[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; //alert( X_String_cleanupWhiteSpace( xnode[ '_text' ] ) ); if( !skipCleanup ){ @@ -479,7 +479,7 @@ X_TEMP.bindElementToXnode = }; }; current.xtext = xtext || xnode; - parent[ '_flags' ] |= X_Node_State.IE4_HAS_TEXTNODE; + parent[ '_flags' ] |= X_NodeFlags_IE4_HAS_TEXTNODE; return; }; @@ -499,7 +499,7 @@ X_TEMP.bindElementToXnode = ++current.j; xnode[ '_rawObject' ] = elm; - xnode[ '_flags' ] |= X_Node_State.IN_TREE; + xnode[ '_flags' ] |= X_NodeFlags_IN_TREE; xnode[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY; //xnode[ '_tag' ] = X_Dom_DTD_TAG_FIX[ tag ] || tag; if( X_TEMP._isCleanupTarget( elm ) ){ //!xnode[ 'hasClass' ]( 'skip-cleanup' ) && ( X_Dom_DTD_CLEANUP_TAGS[ tag ] || xnode[ 'hasClass' ]( 'cleanup-target' ) ) ){ @@ -515,7 +515,7 @@ X_TEMP.bindElementToXnode = ( xnode[ '_attrs' ] = { type : 'text' } ) : xnode[ '_attrs' ].type || ( xnode[ '_attrs' ].type = 'text' ) ); - parent[ '_flags' ] |= X_Node_State.IE4_HAS_ELEMENT; + parent[ '_flags' ] |= X_NodeFlags_IE4_HAS_ELEMENT; current.xtext = null; if( tag === 'TEXTAREA' ){ diff --git a/0.6.x/js/06_net/05_XXHRGadget.js b/0.6.x/js/06_net/05_XXHRGadget.js index 28dc843..905e098 100644 --- a/0.6.x/js/06_net/05_XXHRGadget.js +++ b/0.6.x/js/06_net/05_XXHRGadget.js @@ -23,6 +23,7 @@ var X_NET_GIMR_canUse = 5.5 <= X_UA[ 'IE' ] || !X_UA[ 'IE' ], X_NET_GIMR_GADGET_XML_URL = 'http://googledrive.com/host/0B4Y86MXyTfuoVUkwTE54T3V1V1U', + // https://kldleov8fp2dl82hphfmor8riij82tof-a-sites-opensocial.googleusercontent.com/gadgets/ifr X_NET_GIMR_GADGET_URL = 'http://www.ig.gmodules.com/gadgets/ifr?url=' + encodeURIComponent( X_NET_GIMR_GADGET_XML_URL ) + '&nocache=1', X_NET_GIMR_IMAGE_URL = 'img/opacity0.gif', @@ -84,7 +85,7 @@ function X_NET_GIMR_detectImageOverIframe(){ X_NET_GIMR_receivedString = ret.substr( ( n + ':' ).length ); X_NET_GIMR_isReceiveBatches = --n; iwin.location.href = X_NET_GIMR_GADGET_URL + '#_recived_' + X_NET_GIMR_isReceiveBatches; - // TODO speedup + // speedup X_NET_GIMR_timerID = X_Timer_add( 16, 0, X_NET_GIMR_detectImageOverIframe ); return X_Callback_UN_LISTEN; } else { @@ -147,13 +148,19 @@ function X_NET_GIMR_toJSONString( obj ){ X_TEMP.X_Net_GIMR_init = function(){ + // TODO extend NinjaIframe + X_NET_GIMRWrapper = X_Class_override( + X_EventDispatcher(), + X_TEMP.X_Net_GIMR_props + ); -delete X_TEMP.X_Net_GIMR_init; + delete X_TEMP.X_Net_GIMR_init; + delete X_TEMP.X_Net_GIMR_props; + + return X_NET_GIMRWrapper; +}; -// TODO extend NinjaIframe -X_NET_GIMRWrapper = X_Class_override( - X_EventDispatcher(), - { +X_TEMP.X_Net_GIMR_props = { _busy : false, _canceled : false, @@ -236,10 +243,6 @@ X_NET_GIMRWrapper = X_Class_override( this._busy = this._canceled = false; this._onloadCount = 0; } - } -); - -return X_NET_GIMRWrapper; + }; -}; diff --git a/0.6.x/js/06_net/10_XOAuth2.js b/0.6.x/js/06_net/10_XOAuth2.js index 55c40ea..2d5150f 100644 --- a/0.6.x/js/06_net/10_XOAuth2.js +++ b/0.6.x/js/06_net/10_XOAuth2.js @@ -48,19 +48,25 @@ X[ 'OAuth2' ] = X_EventDispatcher[ 'inherits' ]( /** @lends OAuth2.prototype */ { 'Constructor' : function( obj ){ + var expires_at; + obj = X_Object_clone( obj ); X_Pair_create( this, obj ); - if( _getAccessToken( this ) ){ - obj.oauth2State = 4; - this[ 'asyncDispatch' ]( X_EVENT_SUCCESS ); + obj.onAuthError = X_NET_OAUTH2_onXHR401Error; + obj.updateRequest = X_NET_OAUTH2_updateRequest; + + if( _getAccessToken( this ) && ( expires_at = _getAccessTokenExpiry( this ) ) ){ + if( expires_at < X_Timer_now() + 300000 ){ // 寿命が5分を切った + this[ 'refreshToken' ](); + } else { + obj.oauth2State = 4; + this[ 'asyncDispatch' ]( X_EVENT_SUCCESS ); + }; } else { this[ 'asyncDispatch' ]( X_EVENT_NEED_AUTH ); - } - - obj.onAuthError = X_NET_OAUTH2_onXHR401Error; - obj.updateRequest = X_NET_OAUTH2_updateRequest; + }; // TODO canUse // TODO kill の cancel @@ -85,6 +91,8 @@ X[ 'OAuth2' ] = X_EventDispatcher[ 'inherits' ]( * 認可用 window をポップアップする。ポップアップブロックが働かないように必ず pointer event 内で呼ぶこと。 */ 'requestAuth' : function(){ + var url, w, h; + // TODO pointer event 内か?チェック // 二つ以上の popup を作らない if( X_NET_OAUTH2_authorizationWindow ) return; @@ -92,8 +100,12 @@ X[ 'OAuth2' ] = X_EventDispatcher[ 'inherits' ]( if( pair.net || pair.oauth2State ) return; + url = pair[ 'authorizeEndpoint' ]; + w = pair[ 'authorizeWindowWidth' ] || 500; + h = pair[ 'authorizeWindowHeight' ] || 500; + X_NET_OAUTH2_authorizationWindow = window.open( - pair[ 'authorizeEndpoint' ] + '?' + X_URL_objToParam( + url + ( ( url.indexOf( '?' ) !== -1 ) ? '&' : '?' ) + X_URL_objToParam( { 'response_type' : 'code', 'client_id' : pair[ 'clientID' ], @@ -101,10 +113,10 @@ X[ 'OAuth2' ] = X_EventDispatcher[ 'inherits' ]( 'scope' : ( pair[ 'scopes' ] || []).join(' ') } ), 'oauthauthorize', - 'width=' + pair[ 'authorizeWindowWidth' ] - + ',height=' + pair[ 'authorizeWindowHeight' ] - + ',left=' + (screen.width - pair[ 'authorizeWindowWidth' ] ) / 2 - + ',top=' + (screen.height - pair[ 'authorizeWindowHeight' ] ) / 2 + 'width=' + w + + ',height=' + h + + ',left=' + ( screen.width - w ) / 2 + + ',top=' + ( screen.height - h ) / 2 + ',menubar=no,toolbar=no'); X_NET_OAUTH2_authorizationTimerID = X_Timer_add( 333, 0, this, X_Net_OAuth2_detectAuthPopup ); @@ -139,13 +151,9 @@ X[ 'OAuth2' ] = X_EventDispatcher[ 'inherits' ]( * アクセストークンのリフレッシュ。 */ 'refreshToken' : function(){ - /* TODO 自動リフレッシュ - * var expires_at = this._getAccessTokenExpiry(); - if (expires_at && Date.now() + millis > expires_at) - this._refreshAccessToken({replay: false}); - */ - - pair = X_Pair_get( this ); + // TODO 自動リフレッシュ + + var pair = X_Pair_get( this ); if( pair.net ) return; @@ -327,7 +335,7 @@ function X_NET_OAUTH2_updateRequest( oauth2, request ){ function _getAccessToken( that ){ return updateLocalStorage( '', that, 'accessToken' ); } function _getRefreshToken( that){ return updateLocalStorage( '', that, 'refreshToken' ); } -function _getAccessTokenExpiry( that ){ return updateLocalStorage( '', that, 'tokenExpiry' ); } +function _getAccessTokenExpiry( that ){ return parseInt( updateLocalStorage( '', that, 'tokenExpiry' ) ) || 0; } function _getAuthMechanism( that ){ // TODO use gadget | flash ... // IE's XDomainRequest doesn't support sending headers, so don't try. diff --git a/0.6.x/js/07_audio/02_XHTMLAudio.js b/0.6.x/js/07_audio/02_XHTMLAudio.js index a87c67c..3e84d3d 100644 --- a/0.6.x/js/07_audio/02_XHTMLAudio.js +++ b/0.6.x/js/07_audio/02_XHTMLAudio.js @@ -41,6 +41,8 @@ if( X_Audio_constructor && !X_Audio_HTMLAudioWrapper_badOperaAndroid ){ //引数なしで new Audio() とすると、Operaでエラーになるそうなので注意。 X_Audio_rawAudio = new X_Audio_constructor( '' ); + // https://html5experts.jp/miyuki-baba/3766/ + // Chrome for Android31 で HE-AAC が低速再生されるバグ if( X_Audio_rawAudio.canPlayType ){ X_Audio_codecs = { 'mp3' : X_Audio_rawAudio.canPlayType('audio/mpeg'), diff --git a/0.6.x/js/20_ui/02_XUI_Attr.js b/0.6.x/js/20_ui/02_XUI_Attr.js index ff7356e..5a0bd47 100644 --- a/0.6.x/js/20_ui/02_XUI_Attr.js +++ b/0.6.x/js/20_ui/02_XUI_Attr.js @@ -21,7 +21,8 @@ var XUI_Attr_AUTO = 1/0,//Number.POSITIVE_INFINITY, COMBI : 1024, QUARTET : 2048, DEFAULT_ONLY : 4096, - INIT_ONLY : 8192 + INIT_ONLY : 8192, + OBJECT : 32768 }, XUI_Attr_Option = { BORDER_STYLE : 'none,hidden,dotted,dashed,solid,double,groove,ridge,inset,outset', @@ -66,6 +67,8 @@ var XUI_Attr_AUTO = 1/0,//Number.POSITIVE_INFINITY, pointerDownClass : [ null, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.DEFAULT_ONLY | XUI_Attr_Type.STRING ], invalidLayoutColor: [ null, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.DEFAULT_ONLY | XUI_Attr_Type.COLOR ], + dataFeild : [ null, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.DEFAULT_ONLY | XUI_Attr_Type.STRING ], + role : [ 1, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.INIT_ONLY | XUI_Attr_Type.LIST, 'none,chrome' ], selectable : [ false, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.INIT_ONLY | XUI_Attr_Type.BOOLEAN ], @@ -193,6 +196,7 @@ XUI_Attr_copy( XUI_AttrClass.prototype, XUI_Attr_Support ); function XUI_Attr_preset( baseKlass, opt_supports, opt_attrs ){ var klass = baseKlass.inherits(), proto = klass.prototype, + supports = proto.usableAttrs || opt_supports, p; // 属性プリセット @@ -202,7 +206,7 @@ function XUI_Attr_preset( baseKlass, opt_supports, opt_attrs ){ XUI_attrClassProto = proto; for( p in opt_attrs ){ if( X_EMPTY_OBJECT[ p ] ) continue; - opt_supports[ p ] && XUI_AbstractUINode.prototype.setAttr( p, opt_supports[ p ], opt_attrs[ p ] ); + supports[ p ] && XUI_AbstractUINode.prototype.setAttr( p, supports[ p ], opt_attrs[ p ] ); }; XUI_attrClassProto = null; return klass; diff --git a/0.6.x/js/20_ui/06_AbstractUINode.js b/0.6.x/js/20_ui/06_AbstractUINode.js index b2dfe24..4ca1595 100644 --- a/0.6.x/js/20_ui/06_AbstractUINode.js +++ b/0.6.x/js/20_ui/06_AbstractUINode.js @@ -1,3 +1,4 @@ +// TODO -> Node[ 'inherits' ] var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( 'X.UI._AbstractUINode', X_Class.ABSTRACT, @@ -12,7 +13,7 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( parentData : null, xnode : null, - supportAttrs : XUI_Attr_Support, + usableAttrs : XUI_Attr_Support, attrClass : XUI_AttrClass, attrObject : null, unverifiedAttrs : null, @@ -30,14 +31,12 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( boxX : 0, boxY : 0, - scrollWidth : 0, // remove? - scrollHeight : 0, // remove? boxWidth : XUI_Attr_AUTO, - minBoxWidth : 0, - maxBoxWidth : XUI_Attr_AUTO, + boxWidthMin : 0, + boxWidthMax : XUI_Attr_AUTO, boxHeight : XUI_Attr_AUTO, - minBoxHeight : 0, - maxBoxHeight : XUI_Attr_AUTO, + boxHeightMin : 0, + boxHeightMax : XUI_Attr_AUTO, contentL : 0, contentT : 0, contentR : 0, @@ -49,13 +48,13 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( boxSizingOffsetLR : 0, boxSizingOffsetTB : 0, contentWidth : XUI_Attr_AUTO, - minContentWidth : 0, - maxContentWidth : XUI_Attr_AUTO, - lastContentWidth : -1, + contentWidthMin : 0, + contentWidthMax : XUI_Attr_AUTO, + contentWidthLast : -1, contentHeight : XUI_Attr_AUTO, - minContentHeight : 0, - maxContentHeight : XUI_Attr_AUTO, - lastContentHeight : -1, + contentHeightMin : 0, + contentHeightMax : XUI_Attr_AUTO, + contentHeightLast : -1, constraintW : false, constraintH : false, @@ -72,7 +71,6 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( this.rootData = rootData; this.parent = parent; this.parentData = parentData; - //this.xnode = X_Doc_create( 'div' ); this.phase = 1; this[ 'dispatch' ]( XUI_Event.INIT ); @@ -281,7 +279,7 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( getAttr : function( name ){ var attrs = this.attrObject || this.attrClass.prototype || XUI_AttrClass, - support = this.supportAttrs[ name ], + support = this.usableAttrs[ name ], v, type, list; if( !support ) return; @@ -358,7 +356,7 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( updateLayout : function(){ var x = this.boxX + ( this.parentData ? this.parentData.paddingL : 0 ), y = this.boxY + ( this.parentData ? this.parentData.paddingT : 0 ), - w = X_UA[ 'IE5x' ] ? this.boxWidth : this.contentWidth, + w = X_UA[ 'IE5x' ] ? this.boxWidth : this.contentWidth, // IE6 の互換モードも h = X_UA[ 'IE5x' ] ? this.boxHeight : this.contentHeight; this.xnode @@ -366,7 +364,7 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( [ 'css' ]( 'top', y ? y + 'em' : 0 ) // 親の padding 分ずらす [ 'css' ]( 'width', this.noWidth ? 'auto' : w ? w + 'em' : 0 ) [ 'css' ]( 'height', this.noHeight ? 'auto' : h ? h + 'em' : 0 ) - [ 'css' ]( 'padding', XUI_AbstractUINode_createCssText( this, 'padding' ) ) + [ 'css' ]( 'padding', XUI_AbstractUINode_createCssText( this, 'padding' ) ) // TODO 不要? その分 w, h に足す [ 'css' ]( 'borderWidth', XUI_AbstractUINode_createCssText( this, 'borderWidth' ) ); }, @@ -412,17 +410,17 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( this.contentWidth = contentW + boxMinus; this.boxWidth = this.contentWidth + this.contentL + this.contentR; this.boxSizingOffsetLR = boxMinus; - delete this.minContentWidth; - delete this.maxContentWidth; - delete this.minBoxWidth; - delete this.maxBoxWidth; + delete this.contentWidthMin; + delete this.contentWidthMax; + delete this.boxWidthMin; + delete this.boxWidthMax; } else { - this.minContentWidth = XUI_AbstractUINode_ceil( XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.minWidth.No ], allowedW ) + boxMinus ); - this.maxContentWidth = XUI_AbstractUINode_ceil( XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.maxWidth.No ], allowedW ) + boxMinus ); - this.minBoxWidth = this.minContentWidth + this.contentL + this.contentR; - this.maxBoxWidth = this.maxContentWidth + this.contentL + this.contentR; - this.contentWidth = this.minContentWidth; - this.boxWidth = this.minBoxWidth; + this.contentWidthMin = XUI_AbstractUINode_ceil( XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.minWidth.No ], allowedW ) + boxMinus ); + this.contentWidthMax = XUI_AbstractUINode_ceil( XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.maxWidth.No ], allowedW ) + boxMinus ); + this.boxWidthMin = this.contentWidthMin + this.contentL + this.contentR; + this.boxWidthMax = this.contentWidthMax + this.contentL + this.contentR; + this.contentWidth = this.contentWidthMin; + this.boxWidth = this.boxWidthMin; this.boxSizingOffsetLR = boxMinus; }; @@ -453,38 +451,34 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( this.contentHeight = contentH + boxMinus; this.boxHeight = this.contentHeight + this.contentT + this.contentB; // padding-box の場合 border だけ足される this.boxSizingOffsetTB = boxMinus; - delete this.minContentHeight; - delete this.maxContentHeight; - delete this.minBoxHeight; - delete this.maxBoxHeight; + delete this.contentHeightMin; + delete this.contentHeightMax; + delete this.boxHeightMin; + delete this.boxHeightMax; } else { - this.minContentHeight = XUI_AbstractUINode_ceil( XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.minHeight.No ], allowedH ) + boxMinus ); - this.maxContentHeight = XUI_AbstractUINode_ceil( XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.maxHeight.No ], allowedH ) + boxMinus ); - this.minBoxHeight = this.minContentHeight + this.contentT + this.contentB; - this.maxBoxHeight = this.maxContentHeight + this.contentT + this.contentB; - this.contentHeight = this.minContentHeight; - this.boxHeight = this.minBoxHeight; + this.contentHeightMin = XUI_AbstractUINode_ceil( XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.minHeight.No ], allowedH ) + boxMinus ); + this.contentHeightMax = XUI_AbstractUINode_ceil( XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.maxHeight.No ], allowedH ) + boxMinus ); + this.boxHeightMin = this.contentHeightMin + this.contentT + this.contentB; + this.boxHeightMax = this.contentHeightMax + this.contentT + this.contentB; + this.contentHeight = this.contentHeightMin; + this.boxHeight = this.boxHeightMin; this.boxSizingOffsetTB = boxMinus; }; + // x if( this.parentData && this.parentData.layout.overrideAttrsForChild.left ){ - if( this.constraintW ){ - this.boxX = ( boxL || boxL === 0 ) ? boxL : XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.left.No ], allowedW ); - } else - if( attrs[ XUI_Attr_Support.right.No ] === null ){ + if( this.constraintW || attrs[ XUI_Attr_Support.right.No ] === null ){ this.boxX = ( boxL || boxL === 0 ) ? boxL : XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.left.No ], allowedW ); } else { - this.boxX = alllowW - this.boxWidth - ( ( boxR || boxR === 0 ) ? boxR : XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.right.No ], allowedW ) ); + this.boxX = allowedW - this.boxWidth - ( ( boxR || boxR === 0 ) ? boxR : XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.right.No ], allowedW ) ); }; } else { delete this.boxX; }; + // y if( this.parentData && this.parentData.layout.overrideAttrsForChild.top ){ - if( this.constraintH ){ - this.boxY = ( boxT || boxT === 0 ) ? boxT : XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.top.No ], allowedH ); - } else - if( attrs[ XUI_Attr_Support.bottom.No ] === null ){ + if( this.constraintH || attrs[ XUI_Attr_Support.bottom.No ] === null ){ this.boxY = ( boxT || boxT === 0 ) ? boxT : XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.top.No ], allowedH ); } else { this.boxY = allowedH - this.boxHeight - ( ( boxB || boxB === 0 ) ? boxB : XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.bottom.No ], allowedH ) ); @@ -499,7 +493,6 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( */ mesure : function(){ var dirty = this.dirty, - //sup = X_UA[ 'Gecko' ] || ( X_UA[ 'Safari' ] && X_UA[ 'Windows' ] ) ? .01251 : 0, w, _w, h, xnode; if( dirty === XUI_Dirty.CLEAN ){ @@ -512,12 +505,12 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( case XUI_Dirty.CONTENT : // コンテンツが変更された case XUI_Dirty.FONT : // フォントサイズが変更された - delete this.lastContentWidth; - delete this.lastContentHeight; + delete this.contentWidthLast; + delete this.contentHeightLast; case XUI_Dirty.LAYOUT : // レイアウトの再計算が必要 - default : // TODO レイアウト崩れに対処 パフォーマンス悪い! + default : // TODO レイアウト指定が不正な場合 bgcolor を変更、これ以下のレイアウトの中止 w = this.contentWidth; h = this.contentHeight; @@ -546,13 +539,13 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( w = _w = XUI_AbstractUINode_ceil( xnode[ 'css' ]( 'width', 'auto' )[ 'clientWidth' ]() / X_Node_CSS_getCharSize( xnode ) ); - if( this.maxContentWidth < w - this.boxSizingOffsetLR ){ + if( this.contentWidthMax < w - this.boxSizingOffsetLR ){ this.noWidth = false; - w = this.maxContentWidth + this.boxSizingOffsetLR; + w = this.contentWidthMax + this.boxSizingOffsetLR; }; - if( w - this.boxSizingOffsetLR < this.minContentWidth ){ + if( w - this.boxSizingOffsetLR < this.contentWidthMin ){ this.noWidth = false; - w = this.minContentWidth + this.boxSizingOffsetLR; + w = this.contentWidthMin + this.boxSizingOffsetLR; }; if( h === XUI_Attr_AUTO ){ @@ -561,42 +554,42 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( w !== _w && xnode[ 'css' ]( 'width', 'auto' ); }; - this.lastContentWidth = this.contentWidth = w; + this.contentWidthLast = this.contentWidth = w; } else if( h === XUI_Attr_AUTO ){ - if( w !== this.lastContentWidth ){ + if( w !== this.contentWidthLast ){ xnode[ 'css' ]( 'width', w + 'em' ); - this.lastContentWidth = w; + this.contentWidthLast = w; // ie8 clientHeight, ff scrollHeight & clientHeight h = XUI_AbstractUINode_ceil( xnode[ 'css' ]( 'height', 'auto' )[ 'scrollHeight' ]() / X_Node_CSS_getCharSize( xnode ) ); } else { - h = this.lastContentHeight === -1 ? + h = this.contentHeightLast === -1 ? XUI_AbstractUINode_ceil( xnode[ 'css' ]( 'height', 'auto' )[ 'scrollHeight' ]() / X_Node_CSS_getCharSize( xnode ) ) : - this.lastContentHeight; + this.contentHeightLast; }; } else if( dirty !== XUI_Dirty.LAYOUT ){ - this.contentWidth = this.lastContentWidth = w; + this.contentWidth = this.contentWidthLast = w; h = XUI_AbstractUINode_ceil( xnode[ 'css' ]( 'height', 'auto' )[ 'scrollHeight' ]() / X_Node_CSS_getCharSize( xnode ) ); }; - if( this.maxContentHeight < h - this.boxSizingOffsetTB ){ + if( this.contentHeightMax < h - this.boxSizingOffsetTB ){ this.noHeight = false; - h = this.maxContentHeight + this.boxSizingOffsetTB; + h = this.contentHeightMax + this.boxSizingOffsetTB; }; - if( h - this.boxSizingOffsetTB < this.minContentHeight ){ + if( h - this.boxSizingOffsetTB < this.contentHeightMin ){ this.noHeight = false; - h = this.minContentHeight + this.boxSizingOffsetTB; + h = this.contentHeightMin + this.boxSizingOffsetTB; }; - this.contentHeight = this.lastContentHeight = h; + this.contentHeight = this.contentHeightLast = h; } else { // コンテンツを持たないため基本のサイズは0 - if( w === XUI_Attr_AUTO ) this.contentWidth = w = 0 < this.minContentWidth ? this.minContentWidth : 0; - if( h === XUI_Attr_AUTO ) this.contentHeight = h = 0 < this.minContentHeight ? this.minContentHeight : 0; + if( w === XUI_Attr_AUTO ) this.contentWidth = w = 0 < this.contentWidthMin ? this.contentWidthMin : 0; + if( h === XUI_Attr_AUTO ) this.contentHeight = h = 0 < this.contentHeightMin ? this.contentHeightMin : 0; this.noWidth = this.noHeight = false; }; @@ -636,8 +629,8 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( if( !this.constraintW ){ contentW += contentPlus; - min = this.minBoxWidth = XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.minWidth.No ], contentW ); - max = this.maxBoxWidth = XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.maxWidth.No ], contentW ); + min = this.boxWidthMin = XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.minWidth.No ], contentW ); + max = this.boxWidthMax = XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.maxWidth.No ], contentW ); if( contentW < min && contentPlus < min ){ this.contentWidth = min - contentPlus; } else @@ -668,8 +661,8 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( }; if( !this.constraintH ){ contentH += contentPlus; - min = this.minBoxHeight = XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.minHeight.No ], contentH ); - max = this.maxBoxHeight = XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.maxHeight.No ], contentH ); + min = this.boxHeightMin = XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.minHeight.No ], contentH ); + max = this.boxHeightMax = XUI_AbstractUINode_calcValue( attrs[ XUI_Attr_Support.maxHeight.No ], contentH ); if( contentH < min && contentPlus < min ){ this.contentHeight = min - contentPlus; } else @@ -685,6 +678,7 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( }; }, + // TODO fontsize が変わることもある capcher : function( x, y ){ if( this.pointerDisabled ) return false; @@ -703,6 +697,7 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( */ listen : function( type, arg1, arg2, arg3 ){ var root, events, counter, f; + if( XUI_Event._START_POINTER <= type && type <= XUI_Event._END_POINTER ){ if( this.phase < 3 ){ if( !( events = this.reserveEvents ) ) this.reserveEvents = events = []; @@ -727,6 +722,7 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( }; }; }; + arg1 && arg1.kind ? ( f = arg1 ) : ( f = X_Callback_classifyCallbackArgs( arg1, arg2, arg3 ) ); if( !f.kind ){ return X_EventDispatcher_listen.call( this, type, this.User, f ); @@ -788,6 +784,11 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( this.rootData.monopolyNodeData = null; if( xve._START_BUBLEUP < type && this.parentData && !( ret & X_Callback_STOP_PROPAGATION ) && !( ret & X_Callback_STOP_NOW ) ) return this.parentData[ 'dispatch' ]( e ); return ret; + }, + + setItemData : function(){ + // this[ 'dispatch' ]( UI_Event.ITEMDATA_CHANGED ); + // itemData.listen( X_Event_CHANGED ) -> this[ 'dispatch' ]( UI_Event.ITEMDATA_UPDATED ); } } @@ -795,7 +796,7 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( function XUI_AbstractUINode_createCssText( that, name ){ var attrs = that.attrObject || that.attrClass.prototype || XUI_AttrClass, - def = that.supportAttrs[ name ], + def = that.usableAttrs[ name ], no = def.No, v = attrs[ def.No ], type = def[ 3 ], @@ -920,7 +921,7 @@ X.UI.AbstractUINode = X_Class_create( if( layout && !layout[ k ] ){ continue; }; - if( def = p.supportAttrs[ k ] ){ + if( def = p.usableAttrs[ k ] ){ p.setAttr( k, def, nameOrObject[ k ] ); }; }; @@ -937,7 +938,7 @@ X.UI.AbstractUINode = X_Class_create( }; // getter if( attrs = ( p.attrObject || p.attrClass.prototype || XUI_AttrClass ) ){ - def = p.supportAttrs[ nameOrObject ]; + def = p.usableAttrs[ nameOrObject ]; return def && attrs[ def.No ]; }; return v; @@ -1004,6 +1005,74 @@ X.UI.AbstractUINode = X_Class_create( getHeight : function(){ // dirty の場合、rootData.calculate return X_Pair_get( this ).boxHeight; + }, + + /* + * Repeater に於いて、繰り返されるアイテムの元(itemRenderer)からの複製に使用 + */ + clone : function( opt_cloneListener ){ + var newNode = this.constructor(), + newPair = X_Pair_get( newNode ), + pair = X_Pair_get( this ), + attr, listeners, type, list, i, l; + + // handleEvent 等の拡張されたオブジェクトもコピーする! + for( k in this ){ + if( this[ k ] !== newNode[ k ] && !newNode[ k ] ) newNode[ k ] = this[ k ]; + }; + + // User.UINODE な値は pair にコピーされているのでこれをコピー + for( k in pair ){ + if( pair[ k ] !== newPair[ k ] && !newPair[ k ] ) newPair[ k ] = pair[ k ]; + }; + + // attr もコピー + if( pair.attrObject ){ + attr = pair.attrClass(); + for( k in pair.attrObject ){ + if( pair.attrObject[ k ] !== attr[ k ] ) attr[ k ] = pair.attrObject[ k ]; + }; + newPair.attrObject = attr; + }; + + // listener もコピーする! + if( opt_cloneListener && ( listeners = pair[ '_listeners' ] ) ){ + for( type in listeners ){ + list = listeners[ type ]; + for( i = 0, l = list.length; i < l; ++i ){ + f = list[ i ]; + switch( f.kind ){ + case X_Callback_THIS_FUNC : + if( f.lock ){ + X_EventDispatcher_systemListen( newNode, type, f.context === this ? newNode : f.context, f.func, f.supplement ); + } else { + newNode[ f.once ? 'listenOnce' : 'listen' ]( type, f.context === this ? newNode : f.context, f.func, f.supplement ); + }; + break; + case X_Callback_HANDLEEVENT : + if( f.lock ){ + X_EventDispatcher_systemListen( newNode, type, f.context === this ? newNode : f.context, f.supplement ); + } else { + newNode[ f.once ? 'listenOnce' : 'listen' ]( type, f.context === this ? newNode : f.context, f.supplement ); + }; + break; + /* + case X_Callback_FUNC_ONLY : + if( f.lock ){ + X_EventDispatcher_systemListen( newNode, type, f.func, f.supplement ); + } else { + newNode[ f.once ? 'listenOnce' : 'listen' ]( type, f.func, f.supplement ); + }; + break; + default : + newNode[ 'listen' ]( type, f ); + break; */ + }; + }; + }; + }; + + return newNode; } } ); diff --git a/0.6.x/js/20_ui/08_Box.js b/0.6.x/js/20_ui/08_Box.js index b5de649..3fb51e4 100644 --- a/0.6.x/js/20_ui/08_Box.js +++ b/0.6.x/js/20_ui/08_Box.js @@ -24,7 +24,10 @@ var XUI_Layout_Canvas = X[ 'UI' ][ 'Layout' ][ 'Canvas' ] = XUI_createLayout( { data.preMesure( w, h ); - if( isNeedsDetection && ( data.boxWidth === XUI_Attr_AUTO || data.boxHeight === XUI_Attr_AUTO ) ) return false; + console.log( w + ' > ' + data.boxWidth ); + + // data.boxWidth と data.boxHeight のどちらかでも Infinity + if( isNeedsDetection && data.boxWidth + data.boxHeight === XUI_Attr_AUTO ) return false; _x = data.contentL; _y = data.contentT; @@ -39,7 +42,7 @@ var XUI_Layout_Canvas = X[ 'UI' ][ 'Layout' ][ 'Canvas' ] = XUI_createLayout( { }; } else if( data.contentHeight === XUI_Attr_AUTO ){ - data.contentHeight = data.minContentHeight !== XUI_Attr_AUTO ? data.minContentHeight : 0; + data.contentHeight = data.contentHeightMin !== XUI_Attr_AUTO ? data.contentHeightMin : 0; }; data.postMesure(); @@ -57,7 +60,7 @@ var XUI_Box = XUI_AbstractUINode.inherits( 'X.UI._Box', X_Class.NONE, { - supportAttrs : XUI_Attr_createAttrDef( XUI_AbstractUINode.prototype.supportAttrs, XUI_Layout_Canvas.overrideAttrsForSelf ), + usableAttrs : XUI_Attr_createAttrDef( XUI_AbstractUINode.prototype.usableAttrs, XUI_Layout_Canvas.overrideAttrsForSelf ), layout : null, uinodes : null, @@ -72,9 +75,9 @@ var XUI_Box = XUI_AbstractUINode.inherits( Constructor : function( user, layout, args ){ var i = 0, - l = args.length || 1, + l = args && args.length, j = -1, - uinodes, arg, _data, attrs, support, p; + uinodes, arg, _data, attrs, attrDef, p; //if( !args.length ) args = [ args ]; @@ -84,10 +87,11 @@ var XUI_Box = XUI_AbstractUINode.inherits( this.User = user; + // TODO デフォルトの attr 指定の中から XNODE に指定するものを集めて適用。 this.xnode = X_Doc_create( 'div' ); // すでに定義されていればそちらを採用 - // supportAttrs や attrClass が、layout を元に上書きされているため + // usableAttrs や attrClass が、layout を元に上書きされているため this.layout = this.layout || layout; for( ; i < l; ++i ){ @@ -100,12 +104,6 @@ var XUI_Box = XUI_AbstractUINode.inherits( //throw new Error( 'インスタンスはすでに親に追加されています ' + arg ); }; } else - if( arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( Node ) ){ - //this.layout = arg; - } else - if( arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( XUI_LayoutBase ) ){ - //this.layout = arg; - } else if( X_Type_isObject( arg ) ){ if( attrs ){ attrs = X_Class_override( attrs, arg ); @@ -119,7 +117,7 @@ var XUI_Box = XUI_AbstractUINode.inherits( for( p in attrs ){ if( X_EMPTY_OBJECT[ p ] ) continue; - ( support = this.supportAttrs[ p ] ) && this.setAttr( p, support, attrs[ p ] ); + ( attrDef = this.usableAttrs[ p ] ) && this.setAttr( p, attrDef, attrs[ p ] ); }; }, /* Rellay */ @@ -130,7 +128,6 @@ var XUI_Box = XUI_AbstractUINode.inherits( this.rootData = rootData; this.parent = parent; this.parentData = parentData; - //this.xnode = X_Doc_create( 'div' ); if( i ){ for( ; i; ){ @@ -234,14 +231,13 @@ var XUI_Box = XUI_AbstractUINode.inherits( _p1 = p1 && data.phase < 1; _p2 = p2 && data.phase < 2; _p1 && data.initialize( this.root, this.rootData, this.User, this ); - if( index <= num ){ - // _p2 && this.xnode.insertBefore( data.xnode, uinodes[ index + i ].xnode ); + if( index < num ){ _p2 && uinodes[ index + i ].xnode[ 'prev' ]( data.xnode ); _p2 && data.addToParent( this.xnode ); uinodes.splice( index + i, 0, data ); } else { _p2 && data.addToParent( this.xnode ); - uinodes[ uinodes.length ] = data; + uinodes[ uinodes.length ] = data; }; p3 && data.phase < 3 && data.creationComplete(); }; @@ -310,17 +306,19 @@ X.UI.Box = X.UI.AbstractUINode.inherits( X_Pair_create( this, XUI_Box( this, XUI_Layout_Canvas, arguments ) ); }, - add : function( node /* , node, node ... */ ){ - X_Pair_get( this ).addAt( this.numNodes() + 1, Array.prototype.slice.call( arguments ) ); + add : function( /* node, node, node ... */ ){ + X_Pair_get( this ).addAt( this.numNodes() + 1, X_Object_cloneArray( arguments ) ); return this; }, - addAt : function( index, node /* , node, node ... */ ){ + addAt : function( index /* , node , node, node ... */ ){ + var nodes; if( index < 0 ) index = 0; - X_Pair_get( this ).addAt( arguments[ 0 ], Array.prototype.slice.call( arguments, 1 ) ); + nodes = X_Object_cloneArray( arguments ); + X_Pair_get( this ).addAt( nodes.shift(), nodes ); return this; }, - remove : function( node /* , node, node ... */ ){ - X_Pair_get( this )[ 'remove' ]( Array.prototype.slice.call( arguments ) ); + remove : function( /* node, node, node ... */ ){ + X_Pair_get( this )[ 'remove' ]( X_Object_cloneArray( arguments ) ); return this; }, removeAt : function( from, length ){ @@ -353,6 +351,20 @@ X.UI.Box = X.UI.AbstractUINode.inherits( numNodes : function(){ var uinodes = X_Pair_get( this ).uinodes; return uinodes && uinodes.length || 0; + }, + + clone : function( opt_cloneListener ){ + var clone = XUI_AbstractUINode.prototype.clone.call( this, opt_cloneListener ), + uinodes = X_Pair_get( this ).uinodes, + i = 0, + l = uinodes && uinodes.length, + copies = []; + + for( ; i < l; ++i ){ + copies[ i ] = uinodes[ i ].clone( opt_cloneListener ); + }; + + return l ? clone.add.apply( clone, copies ) : clone; } } ); @@ -396,20 +408,20 @@ X.UI.Box.presets = function(){ /* * スーパークラスの属性定義リストをレイアウトの持つ属性定義で上書きした新しい属性定義リストを作る。 */ - supports = XUI_Attr_createAttrDef( privateKlass.prototype.supportAttrs, layout.overrideAttrsForSelf ); + supports = XUI_Attr_createAttrDef( privateKlass.prototype.usableAttrs, layout.overrideAttrsForSelf ); klass = this.inherits( privateKlass ); - privateKlass.prototype.supportAttrs = supports; + privateKlass.prototype.usableAttrs = supports; privateKlass.prototype.attrClass = XUI_Attr_preset( privateKlass.prototype.attrClass, supports, attrs ); } else { - supports = XUI_Attr_createAttrDef( shadow.prototype.supportAttrs, layout.overrideAttrsForSelf ); + supports = XUI_Attr_createAttrDef( shadow.prototype.usableAttrs, layout.overrideAttrsForSelf ); klass = this.inherits( boxName, shadow.inherits( { layout : layout, - supportAttrs : supports, + usableAttrs : supports, attrClass : XUI_Attr_preset( shadow.prototype.attrClass, supports, attrs ) } ) diff --git a/0.6.x/js/20_ui/11_VBox.js b/0.6.x/js/20_ui/11_VBox.js index 9c81e5a..f11c592 100644 --- a/0.6.x/js/20_ui/11_VBox.js +++ b/0.6.x/js/20_ui/11_VBox.js @@ -39,9 +39,9 @@ var XUI_Layout_Vertical = X[ 'UI' ][ 'Layout' ][ 'Vertical' ] = XUI_createLayout autoW = contentW === XUI_Attr_AUTO; autoH = contentH === XUI_Attr_AUTO; detectionPhase = autoW || autoH; - gapY = XUI_AbstractUINode_calcValue( attrs[ data.supportAttrs.gapY.No ], contentH ); - childW = XUI_AbstractUINode_calcValue( attrs[ data.supportAttrs.childWidth.No ], contentW ); - childH = XUI_AbstractUINode_calcValue( attrs[ data.supportAttrs.childHeight.No ], contentH ); + gapY = XUI_AbstractUINode_calcValue( attrs[ data.usableAttrs.gapY.No ], contentH ); + childW = XUI_AbstractUINode_calcValue( attrs[ data.usableAttrs.childWidth.No ], contentW ); + childH = XUI_AbstractUINode_calcValue( attrs[ data.usableAttrs.childHeight.No ], contentH ); _x = data.contentL; _y = 0; //data.contentT; @@ -54,13 +54,13 @@ var XUI_Layout_Vertical = X[ 'UI' ][ 'Layout' ][ 'Vertical' ] = XUI_createLayout node.calculate( detectionPhase, 0, _y, contentW, childH ); _y += node.boxHeight + gapY; //console.dir( node ); - // 概算のみ + // 概算のみ, 子要素の最大幅を調べる _w if( autoW ){ if( node.boxWidth !== XUI_Attr_AUTO ){ w = node.boxWidth; } else - if( node.minBoxWidth !== XUI_Attr_AUTO ){ - w = node.minBoxWidth; + if( node.boxWidthMin !== XUI_Attr_AUTO ){ + w = node.boxWidthMin; minFlag = true; } else { w = 0; @@ -70,7 +70,7 @@ var XUI_Layout_Vertical = X[ 'UI' ][ 'Layout' ][ 'Vertical' ] = XUI_createLayout }; _y -= gapY; } else { - _y = data.minContentHeight !== XUI_Attr_AUTO ? data.minContentHeight : 0; + _y = data.contentHeightMin !== XUI_Attr_AUTO ? data.contentHeightMin : 0; }; if( detectionPhase ){ @@ -103,12 +103,12 @@ X.UI.VBox = X.UI.Box.inherits( var supports; if( !XUI_VBox ){ - supports = XUI_Attr_createAttrDef( XUI_Box.prototype.supportAttrs, XUI_Layout_Vertical.overrideAttrsForSelf ); + supports = XUI_Attr_createAttrDef( XUI_Box.prototype.usableAttrs, XUI_Layout_Vertical.overrideAttrsForSelf ); XUI_VBox = XUI_Box.inherits( { layout : XUI_Layout_Vertical, - supportAttrs : supports, + usableAttrs : supports, attrClass : XUI_Attr_preset( XUI_Box.prototype.attrClass, supports, { gapY : '0.2em', childWidth : '100%' diff --git a/0.6.x/js/20_ui/12_HBox.js b/0.6.x/js/20_ui/12_HBox.js index 8429a4d..6639a7c 100644 --- a/0.6.x/js/20_ui/12_HBox.js +++ b/0.6.x/js/20_ui/12_HBox.js @@ -34,9 +34,9 @@ var XUI_Layout_Horizontal = X[ 'UI' ][ 'Layout' ][ 'Horizontal' ] = XUI_createLa autoW = contentW === XUI_Attr_AUTO; autoH = contentH === XUI_Attr_AUTO; detectionPhase = autoW || autoH; - gapX = XUI_AbstractUINode_calcValue( attrs[ data.supportAttrs.gapX.No ], contentW ); - childW = XUI_AbstractUINode_calcValue( attrs[ data.supportAttrs.childWidth.No ], contentW ); - childH = XUI_AbstractUINode_calcValue( attrs[ data.supportAttrs.childHeight.No ], contentH ); + gapX = XUI_AbstractUINode_calcValue( attrs[ data.usableAttrs.gapX.No ], contentW ); + childW = XUI_AbstractUINode_calcValue( attrs[ data.usableAttrs.childWidth.No ], contentW ); + childH = XUI_AbstractUINode_calcValue( attrs[ data.usableAttrs.childHeight.No ], contentH ); _x = 0; //data.contentL; _y = 0; //data.contentT; @@ -52,8 +52,8 @@ var XUI_Layout_Horizontal = X[ 'UI' ][ 'Layout' ][ 'Horizontal' ] = XUI_createLa if( node.boxHeight !== XUI_Attr_AUTO ){ h = node.boxHeight; } else - if( node.minBoxHeight !== XUI_Attr_AUTO ){ - h = node.minBoxHeight; + if( node.boxHeightMin !== XUI_Attr_AUTO ){ + h = node.boxHeightMin; minFlag = true; } else { h = 0; @@ -63,7 +63,7 @@ var XUI_Layout_Horizontal = X[ 'UI' ][ 'Layout' ][ 'Horizontal' ] = XUI_createLa }; _x -= gapX; } else { - _h = data.minContentHeight !== XUI_Attr_AUTO ? data.minContentHeight : 0; + _h = data.contentHeightMin !== XUI_Attr_AUTO ? data.contentHeightMin : 0; }; if( detectionPhase ){ @@ -105,13 +105,13 @@ X.UI.HBox = X.UI.Box.inherits( var supports; if( !XUI_HBox ){ - supports = XUI_Attr_createAttrDef( XUI_Box.prototype.supportAttrs, XUI_Layout_Horizontal.overrideAttrsForSelf ); + supports = XUI_Attr_createAttrDef( XUI_Box.prototype.usableAttrs, XUI_Layout_Horizontal.overrideAttrsForSelf ); XUI_HBox = XUI_Box.inherits( { - layout : XUI_Layout_Horizontal, - supportAttrs : supports, - attrClass : XUI_Attr_preset( XUI_Box.prototype.attrClass, supports, { + layout : XUI_Layout_Horizontal, + usableAttrs : supports, + attrClass : XUI_Attr_preset( XUI_Box.prototype.attrClass, supports, { gapX : '0.2em' } ) } diff --git a/0.6.x/js/20_ui/13_TileBox.js b/0.6.x/js/20_ui/13_TileBox.js index 06c2a6d..a01198e 100644 --- a/0.6.x/js/20_ui/13_TileBox.js +++ b/0.6.x/js/20_ui/13_TileBox.js @@ -35,18 +35,18 @@ var XUI_Layout_Tile = X[ 'UI' ][ 'Layout' ][ 'Tile' ] = XUI_createLayout( { _x = data.contentL; _y = data.contentT; _w = data.contentWidth; - gapX = XUI_AbstractUINode_calcValue( attrs[ data.supportAttrs.gapX.No ], contentW ); - gapY = XUI_AbstractUINode_calcValue( attrs[ data.supportAttrs.gapY.No ], contentH ); - childW = XUI_AbstractUINode_calcValue( attrs[ data.supportAttrs.childWidth.No ], contentW ); - childH = XUI_AbstractUINode_calcValue( attrs[ data.supportAttrs.childHeight.No ], contentH ); + gapX = XUI_AbstractUINode_calcValue( attrs[ data.usableAttrs.gapX.No ], contentW ); + gapY = XUI_AbstractUINode_calcValue( attrs[ data.usableAttrs.gapY.No ], contentH ); + childW = XUI_AbstractUINode_calcValue( attrs[ data.usableAttrs.childWidth.No ], contentW ); + childH = XUI_AbstractUINode_calcValue( attrs[ data.usableAttrs.childHeight.No ], contentH ); numH = XUI_Attr_FLOOR( ( _w + gapX ) / ( childW + gapX ) ); numV = l % numH ? XUI_Attr_FLOOR( l / numH ) + 1 : l / numH; _h = _y + data.contentB + ( childH + gapY ) * numH - gapY; - startX = attrs[ data.supportAttrs.hCenter.No ] ? + startX = attrs[ data.usableAttrs.hCenter.No ] ? ( _w - ( childW + gapX ) * numH - gapX ) / 2 : _x; __x = startX; - __y = attrs[ data.supportAttrs.vCenter.No ] && _h <= h ? + __y = attrs[ data.usableAttrs.vCenter.No ] && _h <= h ? ( h - _h ) / 2 + _y : _y; for( i = 0; i < l; ++i ){ @@ -65,7 +65,7 @@ var XUI_Layout_Tile = X[ 'UI' ][ 'Layout' ][ 'Tile' ] = XUI_createLayout( { } else if( data.contentHeight === XUI_Attr_AUTO ){ - data.contentHeight = data.minContentHeight !== XUI_Attr_AUTO ? data.minContentHeight : 0; + data.contentHeight = data.contentHeightMin !== XUI_Attr_AUTO ? data.contentHeightMin : 0; }; data.postMesure(); @@ -98,12 +98,12 @@ X.UI.TileBox = X.UI.Box.inherits( var supports; if( !XUI_TileBox ){ - supports = XUI_Attr_createAttrDef( XUI_Box.prototype.supportAttrs, XUI_Layout_Tile.overrideAttrsForSelf ); + supports = XUI_Attr_createAttrDef( XUI_Box.prototype.usableAttrs, XUI_Layout_Tile.overrideAttrsForSelf ); XUI_TileBox = XUI_Box.inherits( { layout : XUI_Layout_Tile, - supportAttrs : supports, + usableAttrs : supports, attrClass : XUI_Attr_preset( XUI_Box.prototype.attrClass, supports, { gapX : '0.2em', gapY : '0.2em', diff --git a/0.6.x/js/20_ui/14_ChromeBox.js b/0.6.x/js/20_ui/14_ChromeBox.js index 82b387b..7053192 100644 --- a/0.6.x/js/20_ui/14_ChromeBox.js +++ b/0.6.x/js/20_ui/14_ChromeBox.js @@ -51,16 +51,19 @@ X.UI.ChromeBox = X.UI.Box.inherits( Constructor : function(){ X_Pair_create( this, XUI_ChromeBox( this, XUI_Layout_Canvas, arguments ) ); }, - add : function( node /* , node, node ... */ ){ - X_Pair_get( this ).containerNode.addAt( this.numNodes(), Array.prototype.slice.call( arguments ) ); + add : function( /* node, node, node ... */ ){ + X_Pair_get( this ).containerNode.addAt( this.numNodes(), X_Object_cloneArray( arguments ) ); return this; }, - addAt : function( index, node /* , node, node ... */ ){ - X_Pair_get( this ).containerNode.addAt( index, Array.prototype.slice.call( arguments, 1 ) ); + addAt : function( index /* , node, node, node ... */ ){ + var nodes; + if( index < 0 ) index = 0; + nodes = X_Object_cloneArray( arguments ); + X_Pair_get( this ).containerNode.addAt( nodes.shift(), nodes ); return this; }, remove : function( node /* , node, node ... */ ){ - X_Pair_get( this ).containerNode[ 'remove' ]( arguments ); + X_Pair_get( this ).containerNode.remove( arguments ); return this; }, removeAt : function( from, length ){ @@ -76,26 +79,11 @@ X.UI.ChromeBox = X.UI.Box.inherits( getLastChild : function(){ return X_Pair_get( this ).containerNode.User.getLastChild(); }, - getNodeByUID : function( uid ){ - return X_Pair_get( this ).containerNode.User.getNodeByUID(); - }, getNodeAt : function( index ){ return X_Pair_get( this ).containerNode.User.getNodeAt( index ); }, numNodes : function(){ return X_Pair_get( this ).containerNode.User.numNodes(); - }, - getContainerNode : function(){ - return X_Pair_get( this ).containerNode.User; - }, - getChromeNodeAt : function( index ){ - if( index < 0 ) return null; - var nodes = X_Pair_get( this ).chromeNodes; - return nodes ? nodes[ index ].User || null : null; - }, - numChromeNodes : function(){ - var nodes = X_Pair_get( this ).chromeNodes; - return nodes ? nodes.length : 0; } } ); \ No newline at end of file diff --git a/0.6.x/js/20_ui/15_ScrollBox.js b/0.6.x/js/20_ui/15_ScrollBox.js index 73f62b6..47915ff 100644 --- a/0.6.x/js/20_ui/15_ScrollBox.js +++ b/0.6.x/js/20_ui/15_ScrollBox.js @@ -1,32 +1,5 @@ -function X_UI_ScrollBox_momentum( current, start, time, lowerMargin, wrapperSize, deceleration ){ - var distance = current - start, - speed = Math.abs( distance ) / time, - destination, - duration; - - deceleration = deceleration === undefined ? 0.0006 : deceleration; - - destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); - duration = speed / deceleration; - - if( destination < lowerMargin ){ - destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; - distance = Math.abs( destination - current ); - duration = distance / speed; - } else - if ( destination > 0 ) { - destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; - distance = Math.abs( current ) + destination; - duration = distance / speed; - }; - - return { - destination : Math.round( destination ), - duration : duration - }; -}; var X_UI_ScrollBox_SUPPORT_ATTRS = { // スクロール開始するために必要な移動距離、縦か横、どちらか制限する場合、より重要 @@ -35,7 +8,7 @@ var X_UI_ScrollBox_SUPPORT_ATTRS = { scrollYEnabled : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], scrollEnabled : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], bounceEnabled : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], - bounceTime : [ 600, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.TIME ], + bounceTime : [ 300, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.TIME ], useWheel : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], useKey : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], hasScrollShadow : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ], @@ -46,6 +19,8 @@ var XUI_ScrollBox = XUI_ChromeBox.inherits( '_ScrollBox', X_Class.NONE, { + layout : XUI_Layout_Canvas, + directionLockThreshold : 10, scrollXEnabled : true, scrollYEnabled : true, @@ -58,8 +33,6 @@ var XUI_ScrollBox = XUI_ChromeBox.inherits( hasScrollShadow : true, scrollShadowColor : '#000', - supportAttrs : XUI_Attr_createAttrDef( XUI_Attr_Support, X_UI_ScrollBox_SUPPORT_ATTRS ), - scrolling : false, initiated : '', @@ -172,12 +145,12 @@ function X_UI_ScrollBox_onLayoutBefore( e ){ function X_UI_ScrollBox_onLayoutComplete( e ){ // scroll の停止、GPU の解除 var font = this.fontSize = this.xnodeSlider.call( 'fontSize' ); - - this.scrollXMax = ( this.boxWidth - this._containerNode.boxWidth ) * font; - this.scrollYMax = ( this.boxHeight - this._containerNode.boxHeight ) * font; - this.hasHScroll = this.scrollXEnabled && this.scrollXMax < 0; - this.hasVScroll = this.scrollYEnabled && this.scrollYMax < 0; + this.scrollXMax = ( this.boxWidth - this._containerNode.boxWidth ) * font | 0; + this.scrollYMax = ( this.boxHeight - this._containerNode.boxHeight ) * font | 0; + + this.hasHScroll = this.scrollXEnabled && ( this.scrollXMax < -1 ); // < 0 だと + this.hasVScroll = this.scrollYEnabled && ( this.scrollYMax < -1 ); if( !this.hasHScroll ){ this.scrollXMax = 0; @@ -508,12 +481,48 @@ function X_UI_ScrollBox_onAnimeEnd( e ){ return X_Callback_NONE; }; +function X_UI_ScrollBox_momentum( current, start, time, lowerMargin, wrapperSize, deceleration ){ + var distance = current - start, + speed = Math.abs( distance ) / time, + destination, + duration; + + deceleration = deceleration === undefined ? 0.0006 : deceleration; + + destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); + duration = speed / deceleration; + + if( destination < lowerMargin ){ + destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; + distance = Math.abs( destination - current ); + duration = distance / speed; + } else + if ( destination > 0 ) { + destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; + distance = Math.abs( current ) + destination; + duration = distance / speed; + }; + + return { + destination : Math.round( destination ), + duration : duration + }; +}; + // TODO Box の継承に! X.UI.ScrollBox = X.UI.ChromeBox.inherits( 'ScrollBox', X_Class.NONE, { Constructor : function(){ + var supports, slider; + + if( XUI_ScrollBox.prototype.usableAttrs === XUI_ChromeBox.prototype.usableAttrs ){ + XUI_ScrollBox.prototype.usableAttrs = supports = XUI_Attr_createAttrDef( XUI_Attr_Support, X_UI_ScrollBox_SUPPORT_ATTRS ); + + XUI_ScrollBox.prototype.attrClass = XUI_Attr_preset( XUI_Box.prototype.attrClass, supports, { width : '100%', height : '100%', bgColor : 0x111111 } ); + }; + var args = [ XUI_Layout_Vertical, { @@ -526,18 +535,19 @@ X.UI.ScrollBox = X.UI.ChromeBox.inherits( } ], i = arguments.length, - arg, layout, attr; + arg, attr; for( ; i; ){ arg = arguments[ --i ]; if( arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( XUI_LayoutBase ) ){ - layout = arg; + args[ 0 ] = arg; } else if( arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( X.UI.AbstractUINode ) ){ args[ args.length ] = arg; } else if( X_Type_isObject( arg ) ){ - attr = arg; + args[ args.length ] = attr = arg; + slider = attr.scrollSlider; }; }; @@ -545,18 +555,14 @@ X.UI.ScrollBox = X.UI.ChromeBox.inherits( this, XUI_ScrollBox( this, - XUI_Layout_Canvas, + null, [ - { - width : '100%', - height : '100%' - }, - X.UI.VBox.apply( 0, args ) + slider || X.UI.VBox.apply( 0, args ) ] ) ); - attr && this.attr( attr ); + //attr && this.attr( attr ); }, scrollX : function(){ diff --git a/0.6.x/js/20_ui/16_Repeater.js b/0.6.x/js/20_ui/16_Repeater.js new file mode 100644 index 0000000..3f980f8 --- /dev/null +++ b/0.6.x/js/20_ui/16_Repeater.js @@ -0,0 +1,218 @@ +var X_UI_Repeater_SUPPORT_ATTRS = { + dataSource : [ null, XUI_Dirty.LAYOUT, XUI_Attr_USER.UINODE, XUI_Attr_Type.OBJECT ], + itemRenderer : [ null, XUI_Dirty.LAYOUT, XUI_Attr_USER.UINODE, XUI_Attr_Type.OBJECT ] +}; + +var XUI_Repeater = XUI_Box.inherits( + '_Repeater', + X_Class.NONE, + { + layout : XUI_Layout_Vertical, + + dataSource : null, // Array., Array. + + itemRenderer : null, + + + startIndex : 0, + startRenderIndex : 0, + numItemsParPage : 0, + numItems : 0, + + Constructor : function( user, dataSource, itemRenderer, attr ){ + this.Super( user, null, [ attr ] ); + this.dataSource = dataSource; + this.itemRenderer = itemRenderer; + }, + + /* + * ここに来るのは、初描画とリサイズ + */ + calculate : function( isNeedsDetection, x, y, allowedW, allowedH ){ + var dataSource = this[ 'dataSource' ]; + + if( allowedW + allowedH === XUI_Attr_AUTO ) return false; + + this.scrollPortWidth = allowedW; + this.scrollPortHeight = allowedH; + + this.preMesure( allowedW, allowedH ); + + if( dataSource && dataSource.length ){ + this.updateItemRenderer( this.contentWidth, allowedH ); + } else + if( this.contentHeight === XUI_Attr_AUTO ){ + this.contentHeight = this.contentHeightMin !== XUI_Attr_AUTO ? this.contentHeightMin : 0; + }; + + this.postMesure(); + + if( !isNeedsDetection ){ + this.boxX += x; + this.boxY += y; + }; + return true; + }, + + handleEvent : function( e ){ + var scrollBox, scrollY, dataSource, offsetY, startIndex, maxIndex, offset, uinodes; + + switch( e.type ){ + case XUI_Event.SCROLL_END : + scrollBox = this.parentData; + scrollY = scrollBox.scrollY; + dataSource = this[ 'dataSource' ]; + uinodes = this.uinodes; + // transition Y を 0 付近に。 + offsetY = scrollY % this.itemHeightLast; + scrollBox.scrollTo( 0, offsetY, 0, '', 0 ); // anime無し + // startIndex の計算 + startIndex = scrollY / this.itemHeightLast | 0; + maxIndex = dataSource.length <= this.numItems ? 0 : dataSource.length - this.numItems; + startIndex = + startIndex < 0 ? 0 : + maxIndex < startIndex ? maxIndex : startIndex; + // アイテムの座標の修正とレンジ外のアイテムを配列内で再配置 + offset = startIndex - this.startIndex; // visible な stratIndex renderStartIndex + + if( 0 < offset ){ + this.addAt( last, uinodes.splice( 0, offset ) ); + } else + if( offset < 0 ){ + this.addAt( 0, uinodes.splice( uinodes.length - offset ) ); + }; + // 再配置されたアイテムにitemData のセット + this.updateItemRenderer( this.contentWidth, this.scrollPortHeight ); + break; + }; + }, + + updateItemRenderer : function( _w, _h ){ + var uinodes = this.uinodes || ( this.uinodes = [] ), + attrs = this.attrObject || this.attrClass.prototype, + gapY = XUI_AbstractUINode_calcValue( attrs[ this.usableAttrs.gapY.No ], _w ), + dataSource = this[ 'dataSource' ], + render = this[ 'itemRenderer' ], + l = dataSource.length, + start = this.startIndex - ( this.numItems - this.numItemsParPage ) / 2 | 0, + itemH = this.itemHeightLast, + i, node, data, _y = 0, last, n; + + i = start = start < 0 ? 0 : start; + + for( ; i < l; ++i ){ + if( !( node = uinodes[ i ] ) ){ + node = render.clone( true ); + this.addAt( i, [ node ] ); + data = X_Pair_get( node ); + // init -> addToParent -> creationComplete + }; + data.setItemData( dataSource[ i ] ); + + data.calculate( false, 0, _y, _w, _h ); + _y += ( itemH || data.boxHeight ) + gapY; + + // 一番最初のループ。ここでページあたりのアイテム数を計算 + if( !itemH && i === start ){ + itemH = _y - gapY; + this.itemHeightLast = itemH * X_ViewPort_baseFontSize, + // scroller の miniHeight は(例えば)親の高さの300% そこにいくつのアイテムを並べることが出来るか?端数切り上げ + this.numItemsParPage = _h / itemH + 0.999 | 0; + n = this.numItems = ( _h * 3 ) / itemH + 0.999 | 0; // TODO boxHeight + last = i + n; + // データの最後まで、または、開始位置から 3ページ分を生成する + l = last < l ? last : l; + }; + }; + + for( l = uinodes.length; i < l; ++i ){ + // uinodes[ i ] hide + }; + + // TODO contentHeight は attr を無視する -> 未表示領域につくるアイテム数 GPU の有無で変わる + this.contentHeight = _y - gapY; + }, + + onPropertyChange : function( name, newValue ){ + var uinodes, i, l, uinode, dataList, from; + + switch( name ){ + case 'itemRenderer' : + for( uinodes = this.uinodes, i = uinodes && uinodes.length; i; ){ + uinodes[ --i ][ 'kill' ](); + }; + + case 'dataSource' : + if( uinodes = this.uinodes ){ + i = uinodes.length; + l = this[ 'dataSource' ].length; + while( l < i ){ + uinodes[ --i ][ 'kill' ](); + uinodes.length = i; + }; + }; + + + break; + }; + } + } +); + +X.UI.Repeater = X.UI.Box.inherits( + 'Repeater', + X_Class.NONE, + { + Constructor : function( dataSource, itemRenderer ){ + var supports; + + if( XUI_Repeater.prototype.usableAttrs === XUI_Box.prototype.usableAttrs ){ + XUI_Repeater.prototype.usableAttrs = supports = XUI_Attr_createAttrDef( XUI_Attr_Support, XUI_Layout_Vertical.overrideAttrsForSelf ); + + XUI_Repeater.prototype.attrClass = XUI_Attr_preset( XUI_Box.prototype.attrClass, supports ); + }; + + // dataProvider + // itemBase parent に追加されている uinode は不可 + // minHeight=300% height=auto + X_Pair_create( this, + XUI_Repeater( + this, + dataSource, itemRenderer, + { + name : 'ScrollBox-Scroller', + role : 'container', + width : 'auto', + minWidth : '100%', + height : 'auto', + minHeight : '100%' + })); + }, + + getItemDataAt : function(){ + + }, + + add : function( /* node, node, node ... */ ){ + }, + addAt : function( index /* , node , node, node ... */ ){ + }, + remove : function( /* node, node, node ... */ ){ + }, + removeAt : function( from, length ){ + }, + getNodesByClass : function( klass ){ + }, + getFirstChild : function(){ + }, + getLastChild : function(){ + }, + getNodeAt : function( index ){ + }, + numNodes : function(){ + var uinodes = X_Pair_get( this ).uinodes; + return uinodes && uinodes.length || 0; + } + + } +); diff --git a/0.6.x/js/20_ui/17_List.js b/0.6.x/js/20_ui/17_List.js new file mode 100644 index 0000000..5112b46 --- /dev/null +++ b/0.6.x/js/20_ui/17_List.js @@ -0,0 +1,20 @@ + +X.UI.List = X.UI.ScrollBox.inherits( + 'Repeater', + X_Class.NONE, + { + Constructor : function( dataSource, itemRenderer ){ + + this.Super( + { + borderColor : 0x252527, + borderWidth : [ 0.15, 0, 0 ], + height : 'auto', + bgColor : 0x444643, + gapY : 0.1, + scrollSlider : X.UI.Repeater.apply( 0, [ dataSource, itemRenderer ] ) + } + ); + } + } +); diff --git a/0.6.x/js/20_ui/17_Text.js b/0.6.x/js/20_ui/17_Text.js index b589337..34820f1 100644 --- a/0.6.x/js/20_ui/17_Text.js +++ b/0.6.x/js/20_ui/17_Text.js @@ -2,7 +2,7 @@ var XUI_Text = XUI_AbstractUINode.inherits( '_Text', X_Class.NONE, { - content : null, + content : '', Constructor : function( user, content ){ if( !( user[ 'instanceOf' ]( X.UI.Text ) ) ){ @@ -13,9 +13,16 @@ var XUI_Text = XUI_AbstractUINode.inherits( if( X_Type_isString( content ) && content ){ this.content = content; + }; + }, + + creationComplete : function(){ + if( X_Type_isString( this.content ) && this.content ){ this.xnode[ 'text' ]( this.content ); this.dirty = XUI_Dirty.CONTENT; }; + + XUI_AbstractUINode.prototype.creationComplete.apply( this, arguments ); } } ); diff --git a/0.6.x/js/20_ui/20_PageRoot.js b/0.6.x/js/20_ui/20_PageRoot.js index fdcec3a..e4d2ab4 100644 --- a/0.6.x/js/20_ui/20_PageRoot.js +++ b/0.6.x/js/20_ui/20_PageRoot.js @@ -180,7 +180,7 @@ function XUI_PageRoot_onViewUpdate( e ){ }; //var XUI_PageRoot; - +// TODO singleton X.UI.PageRoot = X.UI.Box.inherits( 'PageRoot', X_Class.NONE, @@ -189,10 +189,10 @@ X.UI.PageRoot = X.UI.Box.inherits( var supports; //if( !XUI_PageRoot ){ - supports = XUI_Attr_createAttrDef( XUI_Box.prototype.supportAttrs, XUI_Layout_Canvas.overrideAttrsForSelf ); + supports = XUI_Attr_createAttrDef( XUI_Box.prototype.usableAttrs, XUI_Layout_Canvas.overrideAttrsForSelf ); XUI_PageRoot.prototype.layout = XUI_Layout_Canvas; - XUI_PageRoot.prototype.supportAttrs = supports; + XUI_PageRoot.prototype.usableAttrs = supports; XUI_PageRoot.prototype.attrClass = XUI_Attr_preset( XUI_Box.prototype.attrClass, supports, { width : '100%', height : '100%' diff --git a/0.6.x/js/import.js b/0.6.x/js/import.js index e260590..c26df4c 100644 --- a/0.6.x/js/import.js +++ b/0.6.x/js/import.js @@ -29,7 +29,7 @@ document.write( [ 'js/02_dom/00_XDoc.js', 'js/02_dom/01_XDTD.js', - 'js/02_dom/02_XNode.js', + 'js/02_dom/02_XNodeFlags.js', 'js/02_dom/03_XDomEvent.js', 'js/02_dom/04_XBoxModel.js', 'js/02_dom/05_XNodeAttr.js', @@ -38,6 +38,7 @@ document.write( [ 'js/02_dom/08_XNodeSelector.js', 'js/02_dom/09_XHTMLParser.js', 'js/02_dom/10_XNodeAnime.js', + 'js/02_dom/20_XNode.js', 'js/02_dom/22_XTreeBuilder.js', 'js/03_plugin/00_XPlugin.js',