X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2F01_dom%2F11_XDomNode.js;fp=0.6.x%2Fjs%2F01_dom%2F11_XDomNode.js;h=e92d637f4f0dfe79a4899b4e8d81192847709bd4;hb=27420d0fbdf56a5cda68f5b10de6565de8a5c010;hp=0000000000000000000000000000000000000000;hpb=fb2a4b2dace3975474be1daa56659a861bbcbfbe;p=pettanr%2FclientJs.git diff --git a/0.6.x/js/01_dom/11_XDomNode.js b/0.6.x/js/01_dom/11_XDomNode.js new file mode 100644 index 0000000..e92d637 --- /dev/null +++ b/0.6.x/js/01_dom/11_XDomNode.js @@ -0,0 +1,1317 @@ +X.Dom.Dirty = { + CLEAN : 0, + CHILD_IS_DIRTY : 1, + ID : 2, // width, height, x, y + CONTENT : 4, // width, height, x, y textNode の内容 + CLASSNAME : 8, // _getCharSize, width, height, x, y + ATTR : 16, // _getCharSize, width, height, x, y + CSS : 32, // _getCharSize, width, height, x, y + IE_FILTER : X.UA.IE && X.UA.IE < 9 && !X.UA.MacIE ? 64 : 0, + UNKNOWN_TAG_FIX : 128, + IE4_TEXTNODE_FIX : 256 +}; + +X.Dom.State = { + DESTROYED : 0, + EXIST : 1, + BELONG_TREE : 2, + DISPLAY_NONE : 4, + DISPLAY_BLOCK : 8, + DISPLAY_INLINE : 16, + POSITION_ABSOLUTE : 32, + OVERFLOW_HIDDEN : 64, + HAS_WIDTH_LENGTH : 128, + HAS_WIDTH_PERCENT : 256, + HAS_HEIGHT_LENGTH : 512, + HAS_HEIGHT_PERCENT : 1024, + IE4_ONLY_TEXT : 2048, + IE5_DISPLAY_NONE_FIX : !X.UA.MacIE && 5 <= X.UA.IE && X.UA.IE < 5.5 ? 4096 : 0 // filterがかかっていると不可? MacIE5.2- は ? +}; + +X.Dom._strictElmCreation = !X.UA.MacIE && X.UA.IE5678;// && !X.UA.MacIE; + +X.Dom._useDocumentFragment = document.createDocumentFragment && ( !X.UA.IE || 5.5 <= X.UA.IE ) && document.createDocumentFragment(); + +/* + * Node( rawElement | rawTextnode | htmlString | textString ) + */ + +X.Dom.Node = X.EventDispatcher.inherits( + 'XDomNode', + X.Class.POOL_OBJECT, + { + _uid : 0, + _state : 0, + _dirty : 0, + + _isNew : false, + + _rawNode : null, + _rect : null, // + + _root : null, // xnode が文書ツリーに属しているか?はこれを見る + parent : null, // remove された枝も親子構造は維持している。 + _xnodes : null, + + _xnodeType : 0, + _tag : null, + _text : null, + _id : null, + _className : '', + + _attrs : null, // X.Dom.Attr + _newAttrs : null, + _attrText : '', // X.Dom.Attr.objToAttrText が必要な場合は false が入っている + + _css : null, // X.Dom.Style + _cssText : null, + + _fontSize : 0, + + _anime : null, + + Constructor : function( v ){ + var css, xnodes, xnode, parent, uid = Node._chashe.length; + + if( Node._newByTag ){ + Node._newByTag = false; + this._tag = v.toUpperCase(); + this._xnodeType = 1; + this._state = X.Dom.State.DISPLAY_INLINE; // todo + arguments[ 1 ] && this.attr( arguments[ 1 ] ); + css = arguments[ 2 ] || arguments[ 1 ]; + css && this[ X.Type.isString( css ) ? 'cssText' : 'css' ]( css ); + } else + if( Node._newByText ){ + Node._newByText = false; + this._text = v; + this._xnodeType = 3; + this._state = X.Dom.State.DISPLAY_INLINE; + } else { + if( 1 < arguments.length ) return new X.Dom.NodeList( arguments ); + if( X.Type.isArray( v ) && v.length ) return new X.Dom.NodeList( v ); + if( !this || this.append !== Node.prototype.append ) return new Node( v ); + + switch( Node._getType( v ) ){ + case Node.IS_XNODE : + case Node.IS_XNODE_LIST : + return v; + case Node.IS_RAW_HTML : + if( xnode = Node._getXNode( v ) ) return xnode; + // v.parentNode || v.parentElement : dom1 || dom0 + this.parent = ( parent = v.parentNode || v.parentElement ) && parent.tagName /* ie7- */ && Node._getXNode( parent ); + this._root = this.parent ? this.parent._root : null; + this._rawNode = v; + this._xnodeType = 1; + this._state = X.Dom.State.DISPLAY_BLOCK; // todo + this._tag = v.tagName.toUpperCase(); + this._id = v.id; + this._className = v.className; + this.cssText( v.style.cssText ); + // X.Dom.Dirty.CSS を落とす + this._dirty = 0; + // attr の回収は不可能、、、 + if( X.Dom.DOM_IE4 ){ + v.setAttribute( 'UID', '' + uid ); + } else { + v.UID = uid; + }; + // childNodes... + break; + case Node.IS_RAW_TEXT : + if( xnode = Node._getXNode( v ) ) return xnode; + this.parent = Node._getXNode( v.parentNode ); + this._root = this.parent ? this.parent._root : null; + this._rawNode = v; + this._xnodeType = 3; + this._state = X.Dom.State.DISPLAY_INLINE; + this._text = v.data; + v.UID = uid; + break; + case Node.IS_HTML_STRING : + case Node.IS_STRING : + if( xnodes = X.Dom.parse( v, true ) && 1 < xnodes.length ) return new X.Dom.NodeList( xnodes ); + if( xnodes.length ) return xnodes[ 0 ]; + return Node.none; + case Node.IS_IMAGE : + if( xnode = Node._getXNode( v ) ) return xnode; + this._rawNode = v; + this._xnodeType = 4; + v.UID = uid; + this._state = X.Dom.State.EXIST; + break; + case Node.IS_WINDOW : + case Node.IS_DOCUMENT : + if( xnode = Node._getXNode( v ) ) return xnode; + this._rawNode = v; + this._xnodeType = 2; + this._state = X.Dom.State.DISPLAY_BLOCK; + break; + default : + if( Node.none ) return Node.none; + return; + }; + }; + + Node._chashe[ this._uid = uid ] = this; + } + } +); + +var Node = X.Dom.Node; + +Node.IS_XNODE = 1; +Node.IS_RAW_HTML = 2; +Node.IS_RAW_TEXT = 3; +Node.IS_HTML_STRING = 4; +Node.IS_STRING = 5; +//Node.IS_DOC_FRAG = 6; +Node.IS_XNODE_LIST = 7; +Node.IS_WINDOW = 8; +Node.IS_DOCUMENT = 9; +Node.IS_IMAGE = 10; + +Node._getType = function( v ){ + if( v === '' ) return Node.IS_STRING; + if( !v ) return 0; + if( v === window ) return Node.IS_WINDOW; + if( v === document ) return Node.IS_DOCUMENT; + if( v.constructor === window.Image ) return Node.IS_IMAGE; + if( X.UA.WebKit < 525.13 ){ // Safari3- + if( v.src !== undefined && v.onload !== undefined && X.Type.isNumber( v.height ) && X.Type.isNumber( v.width ) && X.Type.isBoolean( v.complete ) ){ + return Node.IS_IMAGE; + }; + }; + if( v.constructor === Node ) return Node.IS_XNODE; + if( v.constructor === X.Dom.NodeList ) return Node.IS_XNODE_LIST; + if( v.tagName ) return Node.IS_RAW_HTML; + if( v.nodeType === 3 ) return Node.IS_RAW_TEXT; + if( typeof v === 'string' ){ + return '<' === v.charAt( 0 ) && v.charAt( v.length - 1 ) === '>' ? Node.IS_HTML_STRING : Node.IS_STRING; + }; + //if( v.nodeType === 11 ) return Node.IS_DOC_FRAG; + return 0; +}; +Node._getXNode = function( v ){ + var uid, i, chashe, xnode; + switch( Node._getType( v ) ){ + case Node.IS_XNODE : + case Node.IS_XNODE_LIST : + return v; + case Node.IS_RAW_HTML : + case Node.IS_IMAGE : + // fake TextNode too. + if( X.Dom.DOM_IE4 ){ + uid = v.getAttribute( 'UID' ); + return uid && Node._chashe[ uid ]; + }; + return v.UID && Node._chashe[ v.UID ]; + case Node.IS_WINDOW : + return Node._window; + case Node.IS_DOCUMENT : + return Node._document; + case Node.IS_RAW_TEXT : + if( v.UID ) return Node._chashe[ v.UID ]; + for( chashe = Node._chashe, i = chashe.length; i; ){ + if( ( xnode = Node._chashe[ --i ] ) && ( xnode._rawNode === v ) ) return xnode; + }; + }; +}; + + +Node.create = function( tag, opt_attrs, opt_css ){ + var list, i; + switch( Node._getType( tag ) ){ + case Node.IS_STRING : + Node._newByTag = true; + return new Node( tag, opt_attrs, opt_css ); + case Node.IS_HTML_STRING : + list = X.Dom.parse( tag, true ); + for( i = list.length; 1 < i; ){ + list[ --i ].destroy(); + }; + return list[ 0 ]; + }; +}; +Node.createText = function( text ){ + Node._newByText = true; + return new Node( text ); +}; + + +Node.getRoot = function( xnode ){ + return Node._document; + //return xNode._body._rawNode.documentElement ? node : node.ownerDocument || node.document; +}; + // XMLかどうかを判別する +Node.isXmlDocument = + X.Dom.DOM_IE4 ? + X.emptyFunction : + (function( root ){ + if( X.Type.isBoolean( root.isXML ) ) return root.isXML; + return root.isXML = root._rawNode.createElement( 'p' ).tagName !== root._rawNode.createElement( 'P' ).tagName; + }); + +Node._chashe = []; +Node.none = Node._chashe[ 0 ] = new Node(); +Node._window = new Node( window ); // Node._chashe[ 1 ] +Node._document = new Node( document ); // Node._chashe[ 2 ] +Node._html = null; // Node._chashe[ 3 ] +Node._body = null;// = Node._chashe[ 4 ] body +Node._systemNode = null;// = Node._chashe[ ? ] + +Node._reserveRemoval = []; + +if( X.Dom.DOM_IE4 ){ + Node.prototype._ie4getRawNode = function(){ + var elm = this._rawNode; + return elm || + ( ( elm = document.all[ 'ie4uid' + this._uid ] ) && ( this._rawNode = elm ) ) || + ( this._id && ( elm = document.all[ this._id ] ) ) && ( this._rawNode = elm ); + }; +}; + + +/* -------------------------------------- + * Create + */ +Node.prototype.create = function( tag, opt_attrs, opt_css ){ + var xnode; + if( this._xnodeType !== 1 ) return; + if( !this._xnodes ) this._xnodes = []; + + xnode = Node.create( tag, opt_attrs, opt_css ); + + xnode.parent = this; + this._xnodes[ this._xnodes.length ] = xnode; + this._root && this._reserveUpdate(); + return xnode; +}; +Node.prototype.createAt = function( index, tag, opt_attrs, opt_css ){ + // TODO +}; + +/* -------------------------------------- + * CreateText + */ +Node.prototype.createText = function( text ){ + var xnode; + if( this._xnodeType !== 1 ) return; + if( !this._xnodes ) this._xnodes = []; + + Node._newByText = true; + xnode = new Node( text ); + xnode.parent = this; + + this._root && this._reserveUpdate(); + this._xnodes[ this._xnodes.length ] = xnode; + return xnode; +}; +Node.prototype.createTextAt = function( index, text ){ + // TODO +}; + +/* -------------------------------------- + * Clone + * http://d.hatena.ne.jp/think49/20110724/1311472811 + * http://d.hatena.ne.jp/uupaa/20100508/1273299874 + */ +Node.prototype.clone = function( opt_clone_children ){ + var xnode, xnodes, i, l; + switch( this._xnodeType ){ + case 1 : + Node._newByTag = true; + xnode = new Node( this._tag, X.cloneObject( this._attrs ), X.cloneObject( 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; + case 3 : + Node._newByText = true; + xnode = new Node( this._text ); + return xnode; + + //case 0 : + //case 2 : + }; + return this; +}; + +/* -------------------------------------- + * Add + * Node + * HtmlElement の場合は内部使用専用 そのため event の破棄等しない + */ +Node.prototype.append = function( v ){ + var i, l, xnodes, frg; + if( this._xnodeType !== 1 ) 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( Node._getType( v ) ){ + case Node.IS_RAW_HTML : + case Node.IS_RAW_TEXT : + v = new Node( v ); + break; + case Node.IS_HTML_STRING : + case Node.IS_STRING : + return this.append.apply( this, X.Dom.parse( v, true ) ); + case Node.IS_XNODE : + if( v._xnodeType !== 1 && v._xnodeType !== 3 ) return this; + // 親の xnodes から v を消す + if( v.parent ){ + //if( X.Dom.DOM_W3C ){ + // v.parent._xnodes.splice( v.parent._xnodes.indexOf( v ), 1 ); + //} else + //if( X.Dom.DOM_IE4 ){ + v.remove(); + //} else { + + //}; + };// else + //if( ( i = Node._reserveRemoval.indexOf( v ) ) !== -1 ){ + // if( !this._state ) alert( 'xnode already destroyed!' ); + // Node._reserveRemoval.splice( i, 1 ); + //}; + break; + default : + return this; + }; + + v.parent = this; + xnodes[ xnodes.length ] = v; + this._root && this._reserveUpdate(); + return this; +}; + + +Node.prototype.appendAt = function( start, v ){ + var xnodes, l, i; + + if( this._xnodeType !== 1 ) 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( Node._getType( v ) ){ + case Node.IS_RAW_HTML : + case Node.IS_RAW_TEXT : + v = new Node( v ); + break; + case Node.IS_HTML_STRING : + case Node.IS_STRING : + v = X.Dom.parse( v, true ); + for( i = v.length; i; ){ + this.appendAt( start, v[ --i ] ); + }; + return this; + case Node.IS_XNODE : + if( v._xnodeType !== 1 && v._xnodeType !== 3 ) return this; + // 親の xnodes から v を消す + if( v.parent ){ + //if( X.Dom.DOM_W3C ){ + // v.parent._xnodes.splice( v.parent._xnodes.indexOf( v ), 1 ); + //} else + //if( X.Dom.DOM_IE4 ){ + v.remove(); + //} else { + + //}; + };// else + //if( ( i = Node._reserveRemoval.indexOf( v ) ) !== -1 ){ + // if( !this._state ) alert( 'xnode already destroyed!' ); + // Node._reserveRemoval.splice( i, 1 ); + //}; + break; + default : + return this; + }; + + v.parent = this; + this._xnodes.splice( start, 0, v ); + this._root && this._reserveUpdate(); + return this; +}; + +Node.prototype.appendTo = function( parent, opt_index ){ + switch( Node._getType( parent ) ){ + case Node.IS_RAW_HTML : + parent = new Node( parent ); + break; + case Node.IS_HTML_STRING : + parent = X.Dom.parse( parent, true ); + parent = parent[ 0 ] || parent; + case Node.IS_XNODE : + break; + default : + return this; + }; + opt_index === undefined ? parent.append( this ) : parent.appendAt( opt_index, this ); + return this; +}; + +Node.prototype.appendToRoot = function( opt_index ){ + opt_index === undefined ? Node._body.append( this ) : Node._body.appendAt( opt_index, this ); + return this; +}; + +/* -------------------------------------- + * Before , After, Replace + */ +Node.prototype.before = Node.prototype.prevNode = function( v ){ + var parent = this.parent, xnodes, i, l, start; + + // 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; + start = this.getOrder(); + if( 1 < l ){ + for( ; l; ){ + parent.appendAt( start, arguments[ --l ] ); + }; + return this; + }; + parent.appendAt( start, v ); + return this; +}; + +Node.prototype.after = Node.prototype.nextNode = function( 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 ){ + if( 1 < l ){ + for( i = 0; i < l; ++i ){ + parent.append( arguments[ i ] ); + }; + return this; + }; + parent.append( v ); + return this; + }; + if( 1 < l ){ + for( ; l; ){ + parent.appendAt( start, arguments[ --l ] ); + }; + return this; + }; + parent.appendAt( start, v ); + return this; +}; + +Node.prototype.replace = function( v ){ + if( !this.parent ) return this; + return arguments.length === 1 ? this.before( v ).remove() : this.before.apply( this, arguments ).remove(); +}; + +/* -------------------------------------- + * Remove + */ +Node.prototype.remove = function(){ + var parent = this.parent; + + if( !parent ) return this; + + parent._xnodes.splice( parent._xnodes.indexOf( this ), 1 ); + if( this._root ){ + Node._reserveRemoval[ Node._reserveRemoval.length ] = this; + this._reserveUpdate(); + }; + delete this.parent; + delete this._root; + return this; +}; + +Node.prototype.empty = function(){ + var xnodes = this._xnodes, i; + if( xnodes && ( i = xnodes.length ) ){ + for( ; i; ){ + xnodes[ --i ].destroy(); + }; + xnodes.length = 0; + }; + return this; +}; + +/* -------------------------------------- + * destory + */ +Node._destroyChildFlag = false; // TODO + +Node.prototype.destroy = function( isChild ){ + var xnodes = this._xnodes, i, elm; + + if( !this._state ) return; + + elm = this._rawNode || this._ie4getRawNode && this._ie4getRawNode(); + + if( xnodes && ( i = xnodes.length ) ){ + //for( ; i; ){ + // xnodes[ --i ].destroy( true ); + //}; + }; + elm && this._listeners && this.unlisten(); // イベントの退避 + + delete Node._chashe[ this._uid ]; + delete this._state; + + if( this._root ){ + !isChild && this.remove(); + } else { + this.parent && this.parent._xnodes.splice( this.parent._xnodes.indexOf( this ), 1 ); + elm && !isChild && this._actualRemove(); + this.kill(); + }; +}; + + + +/* -------------------------------------- + * contains + */ +Node.prototype.contains = function( v ){ + var elm, type, xnodes, i; + if( !v || this._xnodeType !== 1 ) return false; + // contains ie4+ + if( ( elm = this._rawNode || this._ie4getRawNode && this._ie4getRawNode() ) && document.contains && ( type = Node._getType( v ) ) && ( type === Node.IS_RAW_HTML || type === Node.IS_RAW_TEXT ) ){ + return elm.contains( v ); + }; + //if( document.compareDocumentPosition ){ + // + //}; + xnodes = this._xnodes; + if( xnodes.indexOf( v ) !== -1 ) return true; + if( elm === v.parentNode ) return false; + for( i = xnodes.length; i; ){ + if( xnodes[ --i ].contains( v ) ) return true; + }; + return false; +}; + +/* -------------------------------------- + * getChild + */ +Node.prototype.getChildAt = function( i ){ + var xnodes = this._xnodeType === 1 && this._xnodes; + return xnodes && 0 <= i && i < xnodes.length && xnodes[ i ]; +}; + + +/* -------------------------------------- + * firstChild, lastChild + */ +Node.prototype.firstChild = function(){ + return this.getChildAt( 0 ); +}; +Node.prototype.lastChild = function(){ + return this.getChildAt( this._xnodes.length - 1 ); +}; + +/* -------------------------------------- + * getOrder + */ +Node.prototype.getOrder = function(){ + var parent = this.parent; + if( !parent ) return -1; + return parent._xnodes.indexOf( this ); +}; + +/* -------------------------------------- + * className, addClass, removeClass, hasClass + */ +Node.prototype.className = function( v ){ + var node, _, __; + // getter + if( v === undefined ) return this._className; + + // setter + if( this._className === v ) return this; + if( !v || typeof v !== 'string' ){ + 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._dirty |= X.Dom.Dirty.CLASSNAME; + this._root && this._reserveUpdate(); + return this; +}; +Node.prototype.addClass = function( v ){ + var names = v.split( ' ' ), + i = names.length, + name; + v = ''; + for( ; i; ){ + name = names[ --i ]; + if( !name ) continue; + !this.hasClass( name ) && ( v += ( v ? ' ' : '' ) + name ); + }; + return v ? this.className( this._className + ( this._className ? ' ' : '' ) + v ) : this; +}; +Node.prototype.removeClass = function( v ){ + var _ = ' ', + className = this._className, + names = v.split( _ ), + classNames, i, f, j; + if( !className ) return this; + for( classNames = className.split( _ ), i = classNames.length; i; ){ + className = classNames[ --i ]; + for( j = names.length; j; ){ + if( className === names[ --j ] ){ + classNames.splice( i, 1 ); + names.splice( j, 1 ); + f = true; + break; + }; + }; + }; + return f ? this.className( classNames.join( _ ) ) : this; +}; +Node.prototype.toggleClass = function( v, opt_toggle ){ + var names, i, name; + if( opt_toggle !== undefined ){ + return !!opt_toggle ? this.addClass( v ) : this.removeClass( v ); + }; + names = v.split( ' ' ); + for( i = names.length; i; ){ + name = names[ --i ]; + this.hassClass( name ) ? this.removeClass( name ) : this.addClass( name ); + }; + return this; +}; +Node.prototype.hasClass = function( v ){ + var _ = ' ', + className = this._className, + i, name; + if( className === v ) return true; + if( !className ) return false; + + className = _ + className + _; + if( className.indexOf( _ + v + _ ) !== -1 ) return true; // lucky hit + + for( v = v.split( _ ), i = v.length; i; ){ + name = v[ --i ]; + if( name === '' ) continue; + if( className.indexOf( _ + name + _ ) === -1 ) return false; + }; + return true; +}; + +/* -------------------------------------- + * html, text + */ + +Node._outerFlag = null; + +Node.prototype.html = function( html ){ + var _ = '', q = '"', xnodes, n, i, l; + // setter + if( X.Type.isString( html ) ){ + if( this._xnodeType === 3 ) return this.text( html ); + return html ? this.empty().append.apply( this, X.Dom.parse( html, true ) ) : this.empty(); + }; + + // getter + if( this._xnodeType === 3 ){ + return this._text; + }; + + if( this._dirty & X.Dom.Dirty.CSS && !( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){ + delete this._cssText; + }; + html = !Node._outerFlag ? [] : [ + '<', this._tag, + this._id ? ' id="' + this._id + q : _, + this._className ? ' class="' + this._className + q : _, + this._attrText === false ? ( this._attrText = X.Dom.Attr.objToAttrText( this._attrs ) ) : this._attrText, + this._cssText ? ' style="' + this._cssText + q : _, + '>' ]; + + n = html.length; + if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){ + if( !Node._outerFlag ) Node._outerFlag = this; + for( i = 0; i < l; ++i ){ + html[ n ] = xnodes[ i ].html(); + ++n; + }; + if( Node._outerFlag === this ) Node._outerFlag = null; + }; + !Node._outerFlag || X.Dom.DTD.EMPTY[ this._tag ] || ( html[ n ] = '<\/' + this._tag + '>' ); + return html.join( _ ); +}; + +Node.prototype.text = function( text ){ + var xnodes, texts, i, l; + // setter + if( text !== undefined ){ + if( this._xnodeType === 3 ){ + if( this._text !== text ){ + text ? ( this._text = text ) : delete this.text; + this._root && this._reserveUpdate(); + this._dirty |= X.Dom.Dirty.CONTENT; + }; + return this; + }; + if( !text ) return this.empty(); + if( ( xnodes = this._xnodes ) && xnodes.length === 1 && xnodes[ 0 ]._xnodeType === 3 ){ + xnodes[ 0 ].text( text ); + return this; + }; + this.empty().createText( text ); + return this; + }; + // getter + if( this._xnodeType === 1 ){ + 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; +}; + +Node.prototype.each = function( func ){ + func.call( this, 0 ); + return this; +}; + + +/* -------------------------------------- + * Async commit update + * + * state: + * 0 : no_rawnode + * 1 : no_parent + * 2 : no_root + * 3 : dirty + * 4 : clean + * + * remove : + * root._reserveRemoval = [] に追加。commitUpdate で remove して state は not_added + * add : + * root._reserveRemoval にいたら消す, new_parent._xnodes に挿入 steta は not_added にして commitUpdate を待つ + */ + +Node.prototype._reserveUpdate = function(){ + var root = Node._body; + if( root && !root._updateTimerID ) root._updateTimerID = X.Timer.requestFrame( root, root._startUpdate ); +}; + +Node.prototype._startUpdate = function(){ + var removal, i, xnode, tmp; + if( X.Dom.readyState < X.Dom.Event.DOM_INIT ){ + return; + }; + if( this._updateTimerID ){ + //X.Timer.cancelFrame( this._updateTimerID ); // fire 中の cancel が動かない、、、 + this._updateTimerID = 0; + } else { + return; + }; + // このイベントでサイズを取ると無限ループに + // X.Dom._listeners && X.Dom._listeners[ X.Dom.Event.BEFORE_UPDATE ] && X.Dom.dispatch( { type : X.Dom.Event.BEFORE_UPDATE } ); + + removal = Node._reserveRemoval; + + tmp = this._rawNode.style.visibility; + //this._rawNode.style.visibility = 'hidden'; + + //console.log( '_actualRemove().' ); + + if( i = removal.length ){ + for( ; i; ){ + xnode = removal[ --i ]; + xnode._actualRemove(); + !this._state && xnode.kill(); + }; + removal.length = 0; + }; + + //console.log( 'start _startUpdate().' ); + + Node._html._dirty ? Node._html._commitUpdate() : this._commitUpdate(); + + //console.log( 'end of _startUpdate().' ); + + X.Dom._listeners && X.Dom._listeners[ X.Dom.Event.AFTER_UPDATE ] && X.Dom.asyncDispatch( 0, { type : X.Dom.Event.AFTER_UPDATE } ); + //this._rawNode.style.visibility = tmp; +}; + +Node.prototype._commitUpdate = + X.Dom.DOM_W3C ? + ( function( parentElement, nextElement ){ + var elm = this._rawNode, + xnodes, l, i, frg, next, k, v; + + if( this._state & X.Dom.State.IE5_DISPLAY_NONE_FIX ){ + //alert( this._tag + ' ' + !!elm ); + elm && elm.parentNode && this._actualRemove(); + return nextElement; + }; + + if( !elm || ( parentElement && elm.parentNode !== parentElement ) || ( nextElement && elm.nextSibling !== nextElement ) ){ + nextElement ? + parentElement.insertBefore( this._actualCreate(), nextElement ) : + parentElement.appendChild( this._actualCreate() ); + this._afterActualCreate(); + + return elm || this._rawNode; + } else + if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ) { + + /*if( elm.childNodes.length !== l && ( frg = X.Dom._useDocumentFragment ) ){ + for( i = 0; i < l; ++i ){ + frg.appendChild( xnodes[ i ]._actualCreate( true ) ); + }; + elm.appendChild( frg ); + for( i = 0; i < l; ++i ){ + xnodes[ i ]._afterActualCreate( true ); + }; + } else {*/ + for( ; l; ){ + next = xnodes[ --l ]._commitUpdate( elm, next ); + }; + //}; + }; + + delete this._fontSize; + this._dirty && this._updateRawNode( elm ); + if( this._state & X.Dom.State.IE5_DISPLAY_NONE_FIX ){ + return nextElement; + }; + return elm; + }) : + X.Dom.DOM_IE4 ? + ( function( parentElement, prevElement ){ + var elm = this._rawNode || this._ie4getRawNode(), + xnodes, l, i, html, text, prev; + + if( !elm ){ + prevElement ? + prevElement.insertAdjacentHTML( 'AfterEnd', this._actualCreate() ) : + parentElement.insertAdjacentHTML( 'AfterBegin', this._actualCreate() ); + this._afterActualCreate(); + return this._rawNode || this._ie4getRawNode(); + }; + + xnodes = this._xnodes; + l = xnodes ? xnodes.length : 0; + + if( this._dirty & X.Dom.Dirty.IE4_TEXTNODE_FIX || ( this._state & X.Dom.State.IE4_ONLY_TEXT && ( l !== 1 || xnodes[ 0 ]._xnodeType !== 3 ) ) ){ // 1 < l && elm.children.length === 0 + html = []; + for( i = 0; i < l; ++i ){ + html[ i ] = xnodes[ i ]._actualCreate(); + }; + elm.innerHTML = html.join( '' ); + for( i = 0; i < l; ++i ){ + xnodes[ i ]._afterActualCreate(); + }; + this._state &= ~X.Dom.State.IE4_ONLY_TEXT; + } else + if( this._state & X.Dom.State.IE4_ONLY_TEXT ){ // textNode が swap した場合の検出は、_root で行う + text = xnodes[ 0 ]; + if( text._dirty || !text._root ){ + elm.innerHTML = text._text; + delete text._dirty; + text._root = this._root; + }; + } else + if( l ){ + for( i = 0; i < l; ++i ){ + prev = xnodes[ i ]._commitUpdate( elm, prev ); + }; + }; + + delete this._fontSize; + this._dirty && this._updateRawNode( elm ); + return elm; + }) : + (function(){}); + +Node.prototype._updateRawNode = + X.Dom.DOM_W3C ? + ( function( elm ){ + var attrs, rename, k, v; + + // textNode + if( this._dirty & X.Dom.Dirty.CONTENT ){ + elm.data = X.Dom.chrReferanceTo( this._text ); + delete this._dirty; + return; + }; + // id + if( this._dirty & X.Dom.Dirty.ID ){ + this._id ? ( elm.id = this._id ) : ( elm.id && elm.removeAttribute( 'id' ) ); + }; + // className + if( this._dirty & X.Dom.Dirty.CLASSNAME ){ + this._className ? ( elm.className = this._className ) : ( elm.className && elm.removeAttribute( X.UA.IE ? 'className' : 'class' ) ); + + // ie5 only + if( X.Dom.State.IE5_DISPLAY_NONE_FIX && elm.currentStyle.display === 'none' ){ + this._actualRemove(); + this._state |= X.Dom.State.IE5_DISPLAY_NONE_FIX; + return; + }; + }; + // style + if( this._dirty & X.Dom.Dirty.CSS ){ + if( this._cssText !== null || ( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){ + X.UA.Opera78 || X.UA.NN6 ? + elm.setAttribute( 'style', this._cssText ) : // opera8用 + ( elm.style.cssText = this._cssText ); + } else { + elm.style.cssText = ''; // IE5.5以下 Safari3.2 で必要 + elm.removeAttribute( 'style' ); + delete this._cssText; + }; + }; + + if( this._dirty & X.Dom.Dirty.IE_FILTER ){ + elm.style.filter = X.Dom.Style.SPECIAL_FIX( this._css ); + }; + + // attr + if( this._dirty & X.Dom.Dirty.ATTR && ( attrs = this._newAttrs || this._attrs ) ){ + rename = X.Dom.Attr.renameForDOM; + for( k in attrs ){ + if( !X.UA.MacIE && 5 <= X.UA.IE && X.UA.IE < 6 ){ // IETester 5.5 ではエラーが出なかった.MultipulIE5.5 ではエラーが出たので + if( this._tag === 'TEXTAREA' && k === 'value' ){ + elm.firstChild ? + ( elm.firstChild.data = attrs[ k ] ) : + elm.appendChild( document.createTextNode( attrs[ k ] ) ); + continue; + }; + }; + k = + ( v = attrs[ k ] ) === undefined ? + elm.removeAttribute( rename[ k ] || k ) : + ( elm[ rename[ k ] || k ] = X.Dom.Attr.noValue[ k ] ? k : v ); + + }; + delete this._newAttrs; + }; + + delete this._dirty; + }) : + X.Dom.DOM_IE4 ? + ( function( elm ){ + var attrs, rename, k, v; + + // fake textNode + if( this._dirty & X.Dom.Dirty.CONTENT ){ + elm.innerText = this._text; + delete this._dirty; + return; + }; + + /* + * http://www.tohoho-web.com/js/element.htm + * title、className、id、lang、language には setAttribute でなく、element.id で直接読み書きできる + */ + // id + if( this._dirty & X.Dom.Dirty.CONTENT ) elm.setAttribute( 'id', this._id || ( 'ie4uid' + xnode._uid ) ); + + // className + if( this._dirty & X.Dom.Dirty.CLASSNAME ){ + this._className ? ( elm.className = this._className ) : elm.removeAttribute( 'class' ); + }; + // style + if( this._dirty & X.Dom.Dirty.CSS ){ + if( this._cssText !== null || ( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){ + elm.style.cssText = this._cssText; + } else { + elm.style.cssText = ''; + elm.removeAttribute( 'style' ); + delete this._cssText; + }; + }; + + if( this._dirty & X.Dom.Dirty.IE_FILTER ){ + this._rawNode.style.filter = X.Dom.Style.SPECIAL_FIX( this._css ); + }; + + // attr + if( this._dirty & X.Dom.Dirty.ATTR && ( attrs = this._newAttrs || this._attrs ) ){ + rename = X.Dom.Attr.renameForDOM; + for( k in attrs ){ + ( v = attrs[ k ] ) === undefined ? + elm.removeAttribute( rename[ k ] || k ) : + elm.setAttribute( rename[ k ] || k, v ); // TODO X.Dom.Attr.noValue + }; + delete this._newAttrs; + }; + + delete this._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. + */ +Node.prototype._actualCreate = + X.Dom.DOM_W3C ? (function( isChild ){ + var elm = this._rawNode, + xnodes, frg, i, l; + + if( this._xnodeType === 3 ){ + if( elm ) return elm; + delete this._dirty; + return this._rawNode = document.createTextNode( X.Dom.chrReferanceTo( this._text ) ); + }; + + if( !elm ){ + if( this._dirty & X.Dom.Dirty.CSS && !( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){ + delete this._cssText; + }; + this._isNew = true; + this._rawNode = elm = + X.Dom._strictElmCreation ? + document.createElement( [ + '<', this._tag, + ' UID="', this._uid, '"', + this._id ? ' id="' + this._id + '"' : '', + this._className ? ' class="' + this._className + '"' : '', + this._attrText === false ? ( this._attrText = X.Dom.Attr.objToAttrText( this._attrs ) ) : this._attrText, + this._cssText ? ' style="' + this._cssText + '"' : '', + '>' ].join( '' ) ) : + document.createElement( this._tag ); + }; + if( X.Dom._useDocumentFragment ){ + if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){ + !isChild && ( frg = X.Dom._useDocumentFragment ).appendChild( elm ); + for( i = 0; i < l; ++i ){ + elm.appendChild( xnodes[ i ]._actualCreate( true ) ); + }; + return frg || elm; + }; + }; + + return elm; + }) : + X.Dom.DOM_IE4 ? (function( isChild ){ + var uid = this._uid, + html, xnodes, n, i, l; + + if( this._xnodeType === 3 ){ + html = [ '', this._text, '' ];// fake textNode + delete this._rawNode; + } else { + if( this._rawNode && !isChild ) this._actualRemove( true ); + + if( this._dirty & X.Dom.Dirty.CSS && !( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){ + delete this._cssText; + }; + + html = [ + '<', this._tag, ' id=', ( this._id || ( 'ie4uid' + uid ) ), ' UID="', uid, '"', + this._className ? ' class="' + this._className + '"' : '', + this._attrText === false ? ( this._attrText = X.Dom.Attr.objToAttrText( this._attrs ) ) : this._attrText, + this._cssText ? ' style="' + this._cssText + '"' : '', + '>' ]; + + n = html.length; + if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){ + if( l === 1 && xnodes[ 0 ]._xnodeType === 3 ){ + // only textnode + html[ n ] = xnodes[ 0 ]._text; + ++n; + this._state |= X.Dom.State.IE4_ONLY_TEXT; + } else { + for( i = 0; i < l; ++i ){ + html[ n ] = xnodes[ i ]._actualCreate( true ); + ++n; + }; + }; + }; + X.Dom.DTD.EMPTY[ this._tag ] || ( html[ n ] = '<\/' + this._tag + '>' ); + + delete this._newAttrs; + }; + + return html.join( '' ); + }) : + (function(){}); + +Node.prototype._afterActualCreate = + X.Dom.DOM_W3C ? (function(){ + var elm = this._rawNode, xnodes, l, attrs, k, i; + + this._root = this.parent._root; + + if( this._xnodeType === 3 ){ + this._dirty && this._updateRawNode( elm ); + return this; + }; + + xnodes = this._xnodes; + l = xnodes && xnodes.length; + + if( this._isNew ){ + if( !X.Dom._useDocumentFragment && l ){// docFrg が使えない場合、doc 追加後に子を追加 + for( i = 0; i < l; ++i ){ + elm.appendChild( xnodes[ i ]._actualCreate( true ) ); + }; + }; + if( !X.Dom._strictElmCreation ){ + elm.UID = this._uid; + this._newAttrs = this._attrs; + this._dirty = X.Dom.Dirty.ID | X.Dom.Dirty.CLASSNAME | X.Dom.Dirty.CSS | X.Dom.Dirty.ATTR | X.Dom.Dirty.IE_FILTER; + this._updateRawNode( elm ); + } else + if( this._dirty & X.Dom.Dirty.IE_FILTER ){ + elm.style.filter = X.Dom.Style.SPECIAL_FIX( this._css ); + delete this._dirty; + }; + + delete this._isNew; + } else { + this._dirty && this._updateRawNode( elm ); + }; + + if( l ){ + for( i = 0; i < l; ++i ){ + xnodes[ i ]._afterActualCreate(); + }; + }; + // src の onload があるので先ではないか? + // ie の str から要素を作る場合、srcだけ イベント設定後ではないか? + this._restoreEvent();// イベントの復帰 + }) : + X.Dom.DOM_IE4 ? (function(){ + var xnodes, i; + this._root = this.parent._root; + + if( this._xnodeType !== 1 ) return this; + + if( ( xnodes = this._xnodes ) && ( i = xnodes.length ) ){ + for( ; i; ){ + xnodes[ --i ]._afterActualCreate(); + }; + }; + // textarea への value の適用はここで + if( this._dirty & X.Dom.Dirty.IE_FILTER ){ + this._ie4getRawNode().style.filter = X.Dom.Style.SPECIAL_FIX( this._css ); + }; + delete this._dirty; + this._restoreEvent();// イベントの復帰 + }) : + (function(){}); + +Node.prototype._actualRemove = + X.Dom.DOM_W3C ? + ( function( isChild ){ + var xnodes = this._xnodes, + elm = this._rawNode, + child, i, l; + if( xnodes && ( l = xnodes.length ) ){ + for( i = 0; i < l; ++i ){ + child = xnodes[ i ]; + child._xnodeType === 1 && child._actualRemove( true ); + }; + }; + + if( !elm ) return; + this._xnodeType === 1 && this._migrateEvent();// イベントの退避 + // elm.parentNode.tagName for ie7 + if( !X.UA.MacIE ){ + !isChild && elm.parentNode && elm.parentNode.tagName && elm.parentNode.removeChild( elm ); + } else { + !isChild && elm.parentNode && elm.parentNode.tagName && X.Dom._fixed_remove( elm, this ); + }; + }) : + X.Dom.DOM_IE4 ? + ( function( isChild ){ + var xnodes = this._xnodes, + elm = this._rawNode || this._ie4getRawNode(), + i, l, xnode; + if( xnodes && ( l = xnodes.length ) ){ + for( i = 0; i < l; ++i ){ + xnodes[ i ]._actualRemove( true ); + }; + }; + + if( !elm ) return; + this._xnodeType === 1 && this._migrateEvent();// イベントの退避 + + if( X.Dom.Attr.HAS_VALUE[ this._tag ] && ( !this._newAttrs || !X.inObject( 'value', this._newAttrs ) ) ){ + this._attrs.value = elm.value; + }; + elm.removeAttribute( 'id' ); // ? + document.all[ this._id || ( 'ie4uid' + this._uid ) ] = null; // MacIE5 でエラー + if( !isChild ) elm.outerHTML = ''; + delete this._rawNode; + }) : + (function(){}); + +console.log( 'X.Dom.Node' ); +