X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2Fdom%2F11_XDomNode.js;h=74841844dc38e9eee2f105787d9db8ae28264d9f;hb=fb2a4b2dace3975474be1daa56659a861bbcbfbe;hp=667a1db385d060671aef1ff8164355104d13aab8;hpb=2cfc1f1dd997da0e5d24dea5d56dc7609f3326e6;p=pettanr%2FclientJs.git diff --git a/0.6.x/js/dom/11_XDomNode.js b/0.6.x/js/dom/11_XDomNode.js index 667a1db..7484184 100644 --- a/0.6.x/js/dom/11_XDomNode.js +++ b/0.6.x/js/dom/11_XDomNode.js @@ -1,27 +1,54 @@ - X.Dom.Dirty = { CLEAN : 0, - TREE : 1, // width, height, x, y - CONTENT : 2, // width, height, x, y textNode の内容 - CLASSNAME : 4, // _getCharSize, width, height, x, y - CSS : 8, // _getCharSize, width, height, x, y - ATTR : 16, // _getCharSize, width, height, x, y - IE4_TEXTNODE_FIX : 32 + 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 ) */ -//;(function( window, document, undeifned ){ + X.Dom.Node = X.EventDispatcher.inherits( 'XDomNode', X.Class.POOL_OBJECT, { _uid : 0, - _destroyed : false, - _dirty : 0, + _state : 0, + _dirty : 0, + + _isNew : false, _rawNode : null, + _rect : null, // + _root : null, // xnode が文書ツリーに属しているか?はこれを見る parent : null, // remove された枝も親子構造は維持している。 _xnodes : null, @@ -34,10 +61,12 @@ X.Dom.Node = X.EventDispatcher.inherits( _attrs : null, // X.Dom.Attr _newAttrs : null, - _attrText : '', + _attrText : '', // X.Dom.Attr.objToAttrText が必要な場合は false が入っている _css : null, // X.Dom.Style - _cssText : ' ', + _cssText : null, + + _fontSize : 0, _anime : null, @@ -46,16 +75,18 @@ X.Dom.Node = X.EventDispatcher.inherits( if( Node._newByTag ){ Node._newByTag = false; - this._tag = v; + this._tag = v.toUpperCase(); this._xnodeType = 1; + this._state = X.Dom.State.DISPLAY_INLINE; // todo arguments[ 1 ] && this.attr( arguments[ 1 ] ); - css = arguments[ 2 ]; + 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 ); @@ -72,15 +103,15 @@ X.Dom.Node = X.EventDispatcher.inherits( this._root = this.parent ? this.parent._root : null; this._rawNode = v; this._xnodeType = 1; - this._tag = v.tagName; + 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 &= ~X.Dom.Dirty.CSS; this._dirty = 0; // attr の回収は不可能、、、 - if( X.UA.IE && X.UA.IE < 5 ){ + if( X.Dom.DOM_IE4 ){ v.setAttribute( 'UID', '' + uid ); } else { v.UID = uid; @@ -93,6 +124,7 @@ X.Dom.Node = X.EventDispatcher.inherits( 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; @@ -102,11 +134,18 @@ X.Dom.Node = X.EventDispatcher.inherits( if( xnodes.length ) return xnodes[ 0 ]; return Node.none; case Node.IS_IMAGE : - v.UID = uid; + 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; @@ -132,14 +171,17 @@ Node.IS_WINDOW = 8; Node.IS_DOCUMENT = 9; Node.IS_IMAGE = 10; -Node._useDocumentFragment = document.createDocumentFragment && ( !X.UA.IE || 6 <= X.UA.IE ) && document.createDocumentFragment(); - 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; @@ -159,7 +201,7 @@ Node._getXNode = function( v ){ case Node.IS_RAW_HTML : case Node.IS_IMAGE : // fake TextNode too. - if( X.UA.IE && X.UA.IE < 5 ){ + if( X.Dom.DOM_IE4 ){ uid = v.getAttribute( 'UID' ); return uid && Node._chashe[ uid ]; }; @@ -169,6 +211,7 @@ Node._getXNode = function( v ){ 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; }; @@ -176,9 +219,19 @@ Node._getXNode = function( v ){ }; -Node.create = function( tag, opt_attr, opt_css ){ - Node._newByTag = true; - return new Node( tag, opt_attr, opt_css ); +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; @@ -188,14 +241,15 @@ Node.createText = function( text ){ Node.getRoot = function( xnode ){ return Node._document; - //return xnode.root._rawNode.documentElement ? node : node.ownerDocument || node.document; + //return xNode._body._rawNode.documentElement ? node : node.ownerDocument || node.document; }; // XMLかどうかを判別する Node.isXmlDocument = - X.UA.IE && X.UA.IE < 5 ? + X.Dom.DOM_IE4 ? X.emptyFunction : (function( root ){ - return root._rawNode.createElement( 'p' ).tagName !== root._rawNode.createElement( 'P' ).tagName; + if( X.Type.isBoolean( root.isXML ) ) return root.isXML; + return root.isXML = root._rawNode.createElement( 'p' ).tagName !== root._rawNode.createElement( 'P' ).tagName; }); Node._chashe = []; @@ -203,12 +257,12 @@ 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.root = null;// = Node._chashe[ 4 ] body +Node._body = null;// = Node._chashe[ 4 ] body Node._systemNode = null;// = Node._chashe[ ? ] Node._reserveRemoval = []; -if( !document.getElementById && document.all ){ +if( X.Dom.DOM_IE4 ){ Node.prototype._ie4getRawNode = function(){ var elm = this._rawNode; return elm || @@ -226,14 +280,16 @@ Node.prototype.create = function( tag, opt_attrs, opt_css ){ if( this._xnodeType !== 1 ) return; if( !this._xnodes ) this._xnodes = []; - Node._newByTag = true; - xnode = new Node( tag, opt_attrs, opt_css ); - xnode.parent = this; + xnode = Node.create( tag, opt_attrs, opt_css ); - this._root && this._reserveUpdate(); + 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 @@ -251,6 +307,9 @@ Node.prototype.createText = function( text ){ this._xnodes[ this._xnodes.length ] = xnode; return xnode; }; +Node.prototype.createTextAt = function( index, text ){ + // TODO +}; /* -------------------------------------- * Clone @@ -307,24 +366,24 @@ Node.prototype.append = function( v ){ break; case Node.IS_HTML_STRING : case Node.IS_STRING : - return this.append( X.Dom.parse( v, true ) ); + 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( document.getElementById ){ - v.parent._xnodes.splice( v.parent._xnodes.indexOf( v ), 1 ); - } else - if( document.all ){ + //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 { - }; - } else - if( ( i = Node._reserveRemoval.indexOf( v ) ) !== -1 ){ - if( v._destroyed ) alert( 'xnode already destroyed!' ); - Node._reserveRemoval.splice( i, 1 ); - }; + //}; + };// else + //if( ( i = Node._reserveRemoval.indexOf( v ) ) !== -1 ){ + // if( !this._state ) alert( 'xnode already destroyed!' ); + // Node._reserveRemoval.splice( i, 1 ); + //}; break; default : return this; @@ -342,16 +401,15 @@ Node.prototype.appendAt = function( start, v ){ if( this._xnodeType !== 1 ) return this; + l = arguments.length; if( !( xnodes = this._xnodes ) ) xnodes = this._xnodes = []; - l = arguments.length; if( xnodes.length <= start ){ if( l === 2 ) return this.append( v ); - v = []; - for( ; 1 < l; ){ - v[ l - 2 ] = arguments[ --l ]; + for( i = 1; i < l; ++i ){ + this.append( arguments[ i ] ); }; - return this.append.apply( this, v ); + return this; }; if( start < 0 ) start = 0; if( 2 < l ){ @@ -377,19 +435,19 @@ Node.prototype.appendAt = function( start, v ){ if( v._xnodeType !== 1 && v._xnodeType !== 3 ) return this; // 親の xnodes から v を消す if( v.parent ){ - if( document.getElementById ){ - v.parent._xnodes.splice( v.parent._xnodes.indexOf( v ), 1 ); - } else - if( document.all ){ + //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 { - }; - } else - if( ( i = Node._reserveRemoval.indexOf( v ) ) !== -1 ){ - if( v._destroyed ) alert( 'xnode already destroyed!' ); - Node._reserveRemoval.splice( i, 1 ); - }; + //}; + };// else + //if( ( i = Node._reserveRemoval.indexOf( v ) ) !== -1 ){ + // if( !this._state ) alert( 'xnode already destroyed!' ); + // Node._reserveRemoval.splice( i, 1 ); + //}; break; default : return this; @@ -402,53 +460,87 @@ Node.prototype.appendAt = function( start, v ){ }; Node.prototype.appendTo = function( parent, opt_index ){ - if( parent.constructor === Node ){ - opt_index === undefined ? parent.append( this ) : parent.appendAt( opt_index, this ); - } else { - opt_index === undefined ? new Node( parent ).append( this ) : new Node( parent ).appendAt( opt_index, this ); + 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.root.append( this ) : Node.root.appendAt( opt_index, this ); + opt_index === undefined ? Node._body.append( this ) : Node._body.appendAt( opt_index, this ); return this; }; /* -------------------------------------- * Before , After, Replace */ -Node.prototype.before = function( v ){ - var parent, l; - if( !( parent = this.parent ) ){ - return this; +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 ){ - v = [ this.getOrder() ]; for( ; l; ){ - v[ l ] = arguments[ --l ]; + parent.appendAt( start, arguments[ --l ] ); }; - parent.appendAt.apply( parent, v ); return this; }; - parent.appendAt( this.getOrder(), v ); + parent.appendAt( start, v ); return this; }; -Node.prototype.after = function( v ){ - var parent, l; - if( !( parent = this.parent ) ) 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 ){ - v = [ this.getOrder() + 1 ]; for( ; l; ){ - v[ l ] = arguments[ --l ]; + parent.appendAt( start, arguments[ --l ] ); }; - parent.appendAt.apply( parent, v ); return this; }; - parent.appendAt( this.getOrder() + 1, v ); + parent.appendAt( start, v ); return this; }; @@ -462,23 +554,24 @@ Node.prototype.replace = function( v ){ */ 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; - parent._reserveUpdate(); + this._reserveUpdate(); }; delete this.parent; + delete this._root; return this; }; Node.prototype.empty = function(){ - var xnodes = this._xnodes, child, i, l; - if( xnodes && ( l = xnodes.length ) ){ - for( i = 0; i < l; ++i ){ - xnodes[ i ].destroy(); + var xnodes = this._xnodes, i; + if( xnodes && ( i = xnodes.length ) ){ + for( ; i; ){ + xnodes[ --i ].destroy(); }; xnodes.length = 0; }; @@ -488,27 +581,30 @@ Node.prototype.empty = function(){ /* -------------------------------------- * destory */ +Node._destroyChildFlag = false; // TODO + Node.prototype.destroy = function( isChild ){ - var xnodes = this._xnodes, i; + var xnodes = this._xnodes, i, elm; - if( this._destroyed ) return; + if( !this._state ) return; + + elm = this._rawNode || this._ie4getRawNode && this._ie4getRawNode(); if( xnodes && ( i = xnodes.length ) ){ - for( ; i; ){ - xnodes[ --i ].destroy( true ); - }; - xnodes.length = 0; + //for( ; i; ){ + // xnodes[ --i ].destroy( true ); + //}; }; - this.unlisten(); // イベントの退避 + elm && this._listeners && this.unlisten(); // イベントの退避 delete Node._chashe[ this._uid ]; + delete this._state; - if( this._root ){//this._rawNode && this._rawNode.parentNode && this._rawNode.parentNode.tagName ){ - this.remove(); - this._destroyed = true; // state + if( this._root ){ + !isChild && this.remove(); } else { this.parent && this.parent._xnodes.splice( this.parent._xnodes.indexOf( this ), 1 ); - !isChild && this._actualRemove(); + elm && !isChild && this._actualRemove(); this.kill(); }; }; @@ -522,7 +618,7 @@ 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() ) && document.contains && ( type = Node._getType( v ) ) && ( type === Node.IS_RAW_HTML || type === Node.IS_RAW_TEXT ) ){ + 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 ){ @@ -547,23 +643,8 @@ Node.prototype.getChildAt = function( i ){ /* -------------------------------------- - * prevNode, nextNode, firstChild, lastChild + * firstChild, lastChild */ - -Node.prototype.prevNode = function(){ - var parent = this.parent, xnodes, index; - if( !parent ) return; - xnodes = parent._xnodes; - index = xnodes.indexOf( this ); - if( 0 < index ) return xnodes[ index - 1 ]; -}; -Node.prototype.nextNode = function(){ - var parent = this.parent, xnodes, index; - if( !parent ) return; - xnodes = parent._xnodes; - index = xnodes.indexOf( this ); - if( index + 1 < xnodes.length ) return xnodes[ index + 1 ]; -}; Node.prototype.firstChild = function(){ return this.getChildAt( 0 ); }; @@ -584,15 +665,24 @@ Node.prototype.getOrder = function(){ * className, addClass, removeClass, hasClass */ Node.prototype.className = function( v ){ - var node; + 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 { - this._className = v; + // 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(); @@ -608,12 +698,12 @@ Node.prototype.addClass = function( v ){ if( !name ) continue; !this.hasClass( name ) && ( v += ( v ? ' ' : '' ) + name ); }; - return v ? his.className( this._className + ( this._className ? ' ' : '' ) + v ) : this; + return v ? this.className( this._className + ( this._className ? ' ' : '' ) + v ) : this; }; Node.prototype.removeClass = function( v ){ var _ = ' ', className = this._className, - names = v.split( ' ' ), + names = v.split( _ ), classNames, i, f, j; if( !className ) return this; for( classNames = className.split( _ ), i = classNames.length; i; ){ @@ -627,10 +717,19 @@ Node.prototype.removeClass = function( v ){ }; }; }; - return f ? this.className( classNames.join( ' ' ) ) : this; + return f ? this.className( classNames.join( _ ) ) : this; }; -Node.prototype.toggleClass = function( v ){ - +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 _ = ' ', @@ -653,20 +752,17 @@ Node.prototype.hasClass = function( v ){ /* -------------------------------------- * html, text */ -Node.prototype.html = function( html, opt_outer ){ - var xnodes, n, i, l; + +Node._outerFlag = null; + +Node.prototype.html = function( html ){ + var _ = '', q = '"', xnodes, n, i, l; // setter - if( html ){ - if( this._xnodeType === 3 ){ - if( this._text !== html ){ - this._text = html; - this._root && this._reserveUpdate(); - this._dirty |= X.Dom.Dirty.CONTENT; - }; - return this; - }; - return this.empty().append.apply( this, X.Dom.parse( html, true ) ); + 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; @@ -675,60 +771,73 @@ Node.prototype.html = function( html, opt_outer ){ if( this._dirty & X.Dom.Dirty.CSS && !( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){ delete this._cssText; }; - html = !opt_outer ? [] : [ + html = !Node._outerFlag ? [] : [ '<', this._tag, - this._id ? ' id=' + this._id : '', - this._className ? ' class="' + this._className + '"' : '', - this._attrText || ( this._attrText = X.Dom.Attr.objToAttrText( this._attrs ) ), - this._cssText !== ' ' ? ' style="' + this._cssText + '"' : '', + 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( undefined, true ); + html[ n ] = xnodes[ i ].html(); ++n; }; + if( Node._outerFlag === this ) Node._outerFlag = null; }; - !opt_outer || X.Dom.DTD.EMPTY[ this._tag.toLowerCase() ] || ( html[ n ] = '<\/' + this._tag + '>' ); - - return html.join( '' ); + !Node._outerFlag || X.Dom.DTD.EMPTY[ this._tag ] || ( html[ n ] = '<\/' + this._tag + '>' ); + return html.join( _ ); }; Node.prototype.text = function( text ){ - var xnodes, n, i; + var xnodes, texts, i, l; // setter - if( text ){ + if( X.Type.isString( text ) ){ if( this._xnodeType === 3 ){ if( this._text !== text ){ - 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; + return this; }; // getter if( this._xnodeType === 1 ){ - if( ( xnodes = this._xnodes ) && ( i = xnodes.length ) ){ - for( text = [], n = -1; i; ){ - text[ ++n ] = xnodes[ --i ].text(); + if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){ + for( texts = [], i = 0; i < l; ++i ){ + texts[ i ] = xnodes[ i ].text(); }; - return text.join( '' ); + 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 : not_added + * 1 : no_parent + * 2 : no_root * 3 : dirty * 4 : clean * @@ -739,88 +848,98 @@ Node.prototype.text = function( text ){ */ Node.prototype._reserveUpdate = function(){ - var root = Node.root; + 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 ); + //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; - i = removal.length; tmp = this._rawNode.style.visibility; //this._rawNode.style.visibility = 'hidden'; - - for( ; i; ){ - xnode = removal[ --i ]; - xnode._actualRemove(); - xnode._destroyed && xnode.kill(); + + //console.log( '_actualRemove().' ); + + if( i = removal.length ){ + for( ; i; ){ + xnode = removal[ --i ]; + xnode._actualRemove(); + !this._state && xnode.kill(); + }; + removal.length = 0; }; - this._commitUpdate(); + + //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 = - document.getElementById ? + X.Dom.DOM_W3C ? ( function( parentElement, nextElement ){ var elm = this._rawNode, - xnodes, l, i, next, k, v; + 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 ) ){ + 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 ) ){ - for( ; l; ){ - next = xnodes[ --l ]._commitUpdate( elm, next ); - }; + } 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 ); + }; + //}; }; - // textNode - if( this._dirty & X.Dom.Dirty.CONTENT ) elm.data = X.Dom.chrReferanceTo( this._text ); - // className - if( this._dirty & X.Dom.Dirty.CLASSNAME ) elm.className = this._className; - // style - if( this._dirty & X.Dom.Dirty.CSS ){ - if( this._cssText !== ' ' || ( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){ - elm.style.cssText = this._cssText; - } else { - elm.removeAttribute( 'style' ); - delete this._cssText; - }; + delete this._fontSize; + this._dirty && this._updateRawNode( elm ); + if( this._state & X.Dom.State.IE5_DISPLAY_NONE_FIX ){ + return nextElement; }; - // attr - if( this._newAttrs ){ - for( k in this._newAttrs ){ - ( v = this._newAttrs[ k ] ) === undefined ? - elm.removeAttribute( k ) : - ( elm[ k ] = v ); - }; - delete this._newAttrs; - }; - - delete this._dirty; - return elm; }) : - document.all ? + X.Dom.DOM_IE4 ? ( function( parentElement, prevElement ){ var elm = this._rawNode || this._ie4getRawNode(), - xnodes = this._xnodes, - l = xnodes && xnodes.length || 0, - i, html, elm, child, prev, attrs, k, v; + xnodes, l, i, html, text, prev; if( !elm ){ prevElement ? @@ -828,8 +947,12 @@ Node.prototype._commitUpdate = parentElement.insertAdjacentHTML( 'AfterBegin', this._actualCreate() ); this._afterActualCreate(); return this._rawNode || this._ie4getRawNode(); - } else - if( this._dirty & X.Dom.Dirty.IE4_TEXTNODE_FIX ){ + }; + + 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(); @@ -838,40 +961,143 @@ Node.prototype._commitUpdate = for( i = 0; i < l; ++i ){ xnodes[ i ]._afterActualCreate(); }; - } else + 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.innerHTML = this._text; + 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 ) elm.className = this._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 !== ' ' || ( this._cssText = X.Dom.Style.objToCssText( this._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( attrs = this._newAttrs ){ + 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( k ) : - elm.setAttribute( k, v ); - delete attrs[ k ]; + elm.removeAttribute( rename[ k ] || k ) : + elm.setAttribute( rename[ k ] || k, v ); // TODO X.Dom.Attr.noValue }; delete this._newAttrs; }; delete this._dirty; - - return elm; }) : (function(){}); @@ -883,22 +1109,24 @@ Node.prototype._commitUpdate = * return document.createRange().createContextualFragment("
"); * insertAdjacentHTML * - * ie7 以下では iframe の frameborder や、input name は、createElement 後に aetAttribute しても無視される + * ie7 以下では iframe の frameborder や、input name は、createElement 後に setAttribute しても無視される * * fragument がある場合 children も足して - * Mozilla: 1.0+, IE: 6.0+, Netscape: 2.0+, Safari: 1.0+, Opera: 7.0+ + * 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 = - document.getElementById ? (function( isChild ){ + X.Dom.DOM_W3C ? (function( isChild ){ var elm = this._rawNode, xnodes, frg, i, l; if( this._xnodeType === 3 ){ - return elm || ( this._rawNode = document.createTextNode( X.Dom.chrReferanceTo( this._text ) ) ); + if( elm ) return elm; + delete this._dirty; + return this._rawNode = document.createTextNode( X.Dom.chrReferanceTo( this._text ) ); }; if( !elm ){ @@ -907,20 +1135,20 @@ Node.prototype._actualCreate = }; this._isNew = true; this._rawNode = elm = - X.UA.IE && X.UA.IE < 9 ? + X.Dom._strictElmCreation ? document.createElement( [ '<', this._tag, ' UID="', this._uid, '"', this._id ? ' id="' + this._id + '"' : '', this._className ? ' class="' + this._className + '"' : '', - this._attrText || ( this._attrText = X.Dom.Attr.objToAttrText( this._attrs ) ), - this._cssText !== ' ' ? ' style="' + this._cssText + '"' : '', - '>' ].join( '' ) ): + this._attrText === false ? ( this._attrText = X.Dom.Attr.objToAttrText( this._attrs ) ) : this._attrText, + this._cssText ? ' style="' + this._cssText + '"' : '', + '>' ].join( '' ) ) : document.createElement( this._tag ); }; - if( Node._useDocumentFragment ){ + if( X.Dom._useDocumentFragment ){ if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){ - !isChild && ( frg = Node._useDocumentFragment ).appendChild( elm ); + !isChild && ( frg = X.Dom._useDocumentFragment ).appendChild( elm ); for( i = 0; i < l; ++i ){ elm.appendChild( xnodes[ i ]._actualCreate( true ) ); }; @@ -930,94 +1158,98 @@ Node.prototype._actualCreate = return elm; }) : - document.all ? (function(){ + X.Dom.DOM_IE4 ? (function( isChild ){ var uid = this._uid, html, xnodes, n, i, l; if( this._xnodeType === 3 ){ - html = [ '', this._text, '' ];// fake textNode + 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._tag, ' id=', ( this._id || ( 'ie4uid' + uid ) ), ' UID="', uid, '"', this._className ? ' class="' + this._className + '"' : '', - this._attrText || ( this._attrText = X.Dom.Attr.objToAttrText( this._attrs ) ), - this._cssText !== ' ' ? ' style="' + this._cssText + '"' : '', + 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 - // ONLY_TEXTNODE - }; - for( i = 0; i < l; ++i ){ - html[ n ] = xnodes[ i ]._actualCreate(); + 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.toLowerCase() ] || ( html[ n ] = '<\/' + this._tag + '>' ); + X.Dom.DTD.EMPTY[ this._tag ] || ( html[ n ] = '<\/' + this._tag + '>' ); delete this._newAttrs; }; - delete this._dirty; - delete this._rawNode; return html.join( '' ); }) : (function(){}); Node.prototype._afterActualCreate = - document.getElementById ? (function(){ - var xnodes, l, elm, attrs, k, i; - + X.Dom.DOM_W3C ? (function(){ + var elm = this._rawNode, xnodes, l, attrs, k, i; + this._root = this.parent._root; - delete this._dirty; if( this._xnodeType === 3 ){ - //elm.UID = this._uid; + this._dirty && this._updateRawNode( elm ); return this; }; - delete this._newAttrs; xnodes = this._xnodes; l = xnodes && xnodes.length; - elm = this._rawNode; if( this._isNew ){ - if( !Node._useDocumentFragment && l ){// docFrg が使えない場合、doc 追加後に子を追加 + if( !X.Dom._useDocumentFragment && l ){// docFrg が使えない場合、doc 追加後に子を追加 for( i = 0; i < l; ++i ){ elm.appendChild( xnodes[ i ]._actualCreate( true ) ); }; }; - if( !X.UA.IE || 8 < X.UA.IE ){ + if( !X.Dom._strictElmCreation ){ elm.UID = this._uid; - if( this._id ) elm.id = this._id; - if( this._className ) elm.className = this._className; - if( attrs = this._attrs ){ - for( k in attrs ){ - elm[ k ] = attrs[ k ]; - }; - }; - if( this._cssText !== ' ' ) elm.style.cssText = this._cssText; + 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; }; - this._restoreEvent();// イベントの復帰 + delete this._isNew; + } else { + this._dirty && this._updateRawNode( elm ); }; + if( l ){ for( i = 0; i < l; ++i ){ xnodes[ i ]._afterActualCreate(); }; }; - return this; + // src の onload があるので先ではないか? + // ie の str から要素を作る場合、srcだけ イベント設定後ではないか? + this._restoreEvent();// イベントの復帰 }) : - document.all ? (function(){ + X.Dom.DOM_IE4 ? (function(){ var xnodes, i; - this._root = this.parent && this.parent._root; + this._root = this.parent._root; if( this._xnodeType !== 1 ) return this; @@ -1026,12 +1258,17 @@ Node.prototype._afterActualCreate = xnodes[ --i ]._afterActualCreate(); }; }; - return this._restoreEvent();// イベントの復帰 + // 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 = - document.getElementById ? + X.Dom.DOM_W3C ? ( function( isChild ){ var xnodes = this._xnodes, elm = this._rawNode, @@ -1042,13 +1279,17 @@ Node.prototype._actualRemove = child._xnodeType === 1 && child._actualRemove( true ); }; }; - delete this._root; + if( !elm ) return; this._xnodeType === 1 && this._migrateEvent();// イベントの退避 - // elm.parentNode.tagName check tagName is for ie7 - !isChild && elm.parentNode && elm.parentNode.tagName && elm.parentNode.removeChild( elm ); + // 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 ); + }; }) : - document.all ? + X.Dom.DOM_IE4 ? ( function( isChild ){ var xnodes = this._xnodes, elm = this._rawNode || this._ie4getRawNode(), @@ -1058,17 +1299,19 @@ Node.prototype._actualRemove = xnodes[ i ]._actualRemove( true ); }; }; - delete this._root; + if( !elm ) return; this._xnodeType === 1 && this._migrateEvent();// イベントの退避 - delete this._rawNode; - elm.removeAttribute( 'id', '' ); // ? - document.all[ 'ie4uid' + this._uid ] = null; // ? + + 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(){}); - - -//})( window, document ); +console.log( 'X.Dom.Node' );