OSDN Git Service

Version 0.6.18, rewrite for async DOM update.
[pettanr/clientJs.git] / 0.6.x / js / dom / 11_XDomNode.js
1 \r
2 X.Dom.Dirty = {\r
3         CLEAN            :  0,\r
4         TREE             :  1, // width, height, x, y\r
5         CONTENT          :  2,  // width, height, x, y textNode の内容\r
6         CLASSNAME        :  4, // _getCharSize, width, height, x, y\r
7         CSS              :  8, // _getCharSize, width, height, x, y\r
8         ATTR             : 16,  // _getCharSize, width, height, x, y\r
9         IE4_TEXTNODE_FIX : 32\r
10 };\r
11 \r
12 /*\r
13  * Node( rawElement | rawTextnode | htmlString | textString )\r
14  */\r
15 //;(function( window, document, undeifned ){\r
16 X.Dom.Node = X.EventDispatcher.inherits(\r
17         'XDomNode',\r
18         X.Class.POOL_OBJECT,\r
19         {\r
20                 _uid       : 0,\r
21                 _state     : 0,\r
22                 _destroyed : false,\r
23                 _dirty     : 0,         \r
24                 \r
25                 _rawNode   : null,\r
26                 _root      : null,              \r
27                 parent     : null,\r
28                 _xnodes    : null,\r
29         \r
30                 _xnodeType : 0,\r
31                 _tag       : null,\r
32                 _text      : null,\r
33                 _id        : null,\r
34                 _className : '',\r
35 \r
36                 _attrs     : null, // X.Dom.Attr\r
37                 _newAttrs  : null,\r
38                 _attrText  : '',\r
39                 \r
40                 _css       : null, // X.Dom.Style\r
41                 _cssText   : '',\r
42                 \r
43                 Constructor : function( v ){\r
44                         var css, xnodes, xnode, parent, uid = Node._chashe.length;\r
45                         \r
46                         if( Node._newByTag ){\r
47                                 Node._newByTag  = false;\r
48                                 this._tag       = v;\r
49                                 this._xnodeType = 1;\r
50                                 arguments[ 1 ] && this.attr( arguments[ 1 ] );\r
51                                 css = arguments[ 2 ];\r
52                                 css && this[ X.Type.isString( css ) ? 'cssText' : 'css' ]( css );\r
53                         } else\r
54                         if( Node._newByText ){\r
55                                 Node._newByText = false;\r
56                                 this._text      = v;\r
57                                 this._xnodeType = 3;\r
58                                 this._charCode  = '';\r
59                                 for( v = 0; v < this._text.length; ++v ){\r
60                                         this._charCode += this._text.charCodeAt( v ) + ',';\r
61                                 };\r
62                         } else {\r
63                                 if( 1 < arguments.length ) return new X.Dom.NodeList( arguments );\r
64                                 if( X.Type.isArray( v ) && v.length ) return new X.Dom.NodeList( v );\r
65                                 if( !this || this.append !== Node.prototype.append ) return new Node( v );\r
66                 \r
67                                 switch( Node._getType( v ) ){\r
68                                         case Node.IS_XNODE :\r
69                                         case Node.IS_XNODE_LIST :\r
70                                                 return v;\r
71                                         case Node.IS_RAW_HTML :\r
72                                                 if( xnode = Node._getXNode( v ) ) return xnode;\r
73                                                 // v.parentNode || v.parentElement : dom1 || dom0\r
74                                                 this.parent     = v !== document.body && ( parent = v.parentNode || v.parentElement ) && parent.tagName /* ie7- */ && Node._getXNode( parent );\r
75                                                 this._state     = this.parent ? Node.STATE_STAGED : Node.STATE_NO_PARENT;\r
76                                                 this._rawNode   = v;\r
77                                                 this._xnodeType = 1;\r
78                                                 this._tag       = v.tagName;\r
79                                                 this._id        = v.id;\r
80                                                 this._className = v.className;\r
81                                                 this.cssText( v.style.cssText );\r
82                                                 // attr\r
83                                                 \r
84                                                 if( X.UA.IE && X.UA.IE < 5 ){\r
85                                                         v.setAttribute( 'UID', '' + uid );\r
86                                                 } else {\r
87                                                         v.UID = uid;\r
88                                                 };\r
89                                                 // childNodes...\r
90                                                 break;\r
91                                         case Node.IS_RAW_TEXT :\r
92                                                 if( xnode = Node._getXNode( v ) ) return xnode;\r
93                                                 this.parent     = Node._getXNode( v.parentNode );\r
94                                                 this._state     = this.parent ? Node.STATE_STAGED : Node.STATE_NO_PARENT;\r
95                                                 this._rawNode   = v;\r
96                                                 this._xnodeType = 3;\r
97                                                 this._text      = v.data;\r
98                                                 v.UID = uid;\r
99                                                 break;\r
100                                         case Node.IS_HTML_STRING :\r
101                                         case Node.IS_STRING :\r
102                                                 if( xnodes = X.Dom.parse( v, true ) && 1 < xnodes.length ) return new X.Dom.NodeList( xnodes );\r
103                                                 if( xnodes.length ) return xnodes[ 0 ];\r
104                                                 return Node.none;\r
105                                         case Node.IS_IMAGE :\r
106                                                 v.UID = uid;\r
107                                         case Node.IS_WINDOW :\r
108                                         case Node.IS_DOCUMENT :\r
109                                                 this._rawNode   = v;\r
110                                                 this._xnodeType = 2;\r
111                                                 this._state     = Node.STATE_STAGED;\r
112                                                 break;\r
113                                         default :\r
114                                                 if( Node.none ) return Node.none;\r
115                                                 return;\r
116                                 };\r
117                         };\r
118                         \r
119                         Node._chashe[ this._uid = uid ] = this;\r
120                 }\r
121         }\r
122 );\r
123 \r
124 var Node = X._shortcut = X.Dom.Node;\r
125 \r
126 Node.IS_XNODE       = 1;\r
127 Node.IS_RAW_HTML    = 2;\r
128 Node.IS_RAW_TEXT    = 3;\r
129 Node.IS_HTML_STRING = 4;\r
130 Node.IS_STRING      = 5;\r
131 //Node.IS_DOC_FRAG    = 6;\r
132 Node.IS_XNODE_LIST  = 7;\r
133 Node.IS_WINDOW      = 8;\r
134 Node.IS_DOCUMENT    = 9;\r
135 Node.IS_IMAGE       = 10;\r
136 \r
137 \r
138 Node.STATE_NO_RAW    = 0; // new Node されたばかり\r
139 Node.STATE_NO_PARENT = 1; // exist node._rawNode\r
140 //Node.STATE_DIRTY     = 2;\r
141 Node.STATE_STAGED    = 2; // exist _rawNode.parentNode\r
142 Node.STATE_DESTROYED = 3;\r
143 \r
144 Node._useDocumentFragment = document.createDocumentFragment && ( !X.UA.IE || 6 <= X.UA.IE ) && document.createDocumentFragment();\r
145 \r
146 Node._getType = function( v ){\r
147         if( v === '' ) return Node.IS_STRING;\r
148         if( !v ) return 0;\r
149         if( v === window ) return Node.IS_WINDOW;\r
150         if( v === document ) return Node.IS_DOCUMENT;\r
151         if( v.constructor === window.Image ) return Node.IS_IMAGE;\r
152         if( v.constructor === Node ) return Node.IS_XNODE;\r
153         if( v.constructor === X.Dom.NodeList ) return Node.IS_XNODE_LIST;\r
154         if( v.tagName ) return Node.IS_RAW_HTML;\r
155         if( v.nodeType === 3 ) return Node.IS_RAW_TEXT;\r
156         if( typeof v === 'string' ){\r
157                 return '<' === v.charAt( 0 ) && v.charAt( v.length - 1 ) === '>' ? Node.IS_HTML_STRING : Node.IS_STRING;\r
158         };\r
159         //if( v.nodeType === 11 ) return Node.IS_DOC_FRAG;\r
160         return 0;\r
161 };\r
162 Node._getXNode = function( node ){\r
163         var uid;\r
164         switch( Node._getType( node ) ){\r
165                 case Node.IS_XNODE :\r
166                 case Node.IS_XNODE_LIST :\r
167                         return node;\r
168                 case Node.IS_RAW_HTML :\r
169                 case Node.IS_RAW_TEXT :\r
170                 case Node.IS_IMAGE :\r
171                         if( X.UA.IE && X.UA.IE < 5 ){\r
172                                 uid = node.getAttribute( 'UID' );\r
173                                 return uid && Node._chashe[ uid ];\r
174                         };\r
175                         return node.UID && Node._chashe[ node.UID ];\r
176                 case Node.IS_WINDOW :\r
177                         return Node._window;\r
178                 case Node.IS_DOCUMENT :\r
179                         return Node._document;\r
180         };\r
181 };\r
182 \r
183 \r
184 Node.create = function( tag, opt_attr, opt_css ){\r
185         Node._newByTag = true;\r
186         return new Node( tag, opt_attr, opt_css );\r
187 };\r
188 Node.createText = function( text ){\r
189         Node._newByText = true;\r
190         return new Node( text );\r
191 };\r
192 \r
193 \r
194 Node.getRoot = function( xnode ){\r
195         return Node._document;\r
196         //return xnode.root._rawNode.documentElement ? node : node.ownerDocument || node.document;\r
197 };\r
198         // XMLかどうかを判別する\r
199 Node.isXmlDocument =\r
200         X.UA.IE && X.UA.IE < 5 ?\r
201                 X.emptyFunction :\r
202                 (function( root ){\r
203                         return root._rawNode.createElement( 'p' ).tagName !== root._rawNode.createElement( 'P' ).tagName;\r
204                 });\r
205 \r
206 Node._chashe     = [];\r
207 Node.none        = Node._chashe[ 0 ] = new Node();\r
208 Node._window     = new Node( window ); // Node._chashe[ 1 ]\r
209 Node._document   = new Node( document ); // Node._chashe[ 2 ]\r
210 Node._html       = null; // Node._chashe[ 3 ]\r
211 Node.root        = null;// = Node._chashe[ 4 ] body\r
212 Node._systemNode = null;// = Node._chashe[ ? ]\r
213 \r
214 Node._reserveRemoval = [];\r
215 \r
216 if( !document.getElementById && document.all ){\r
217         Node.prototype._ie4getRawNode = function(){\r
218                 var elm, uid;\r
219                 if( elm = this._rawNode ) return elm;\r
220                 if( this._id && ( elm = this._rawNode = document.all[ this._id ] ) ){\r
221                         return elm;\r
222                 };\r
223                 if( elm = this._rawNode = document.all[ 'ie4uid' + this._uid ] ){\r
224                         if( this._id ) elm.setAttribute( 'id', this._id );\r
225                         return elm;\r
226                 };\r
227         };\r
228 };\r
229 \r
230 \r
231 /* --------------------------------------\r
232  *  Create\r
233  */\r
234 Node.prototype.create = function( tag, opt_attrs, opt_css ){\r
235         var xnode;\r
236         if( this._xnodeType !== 1 ) return;\r
237         if( !this._xnodes ) this._xnodes = [];\r
238         \r
239         Node._newByTag = true;\r
240         xnode = new Node( tag, opt_attrs, opt_css );\r
241         xnode.parent = this;\r
242         \r
243         this._reserveUpdate();\r
244         this._xnodes[ this._xnodes.length ] = xnode;\r
245         return xnode;\r
246 };\r
247 \r
248 /* --------------------------------------\r
249  *  CreateText\r
250  */\r
251 Node.prototype.createText = function( text ){\r
252         var xnode;\r
253         if( this._xnodeType !== 1 ) return;\r
254         if( !this._xnodes ) this._xnodes = [];\r
255         \r
256         Node._newByText = true;\r
257         xnode = new Node( text );\r
258         xnode.parent = this;\r
259         \r
260         this._reserveUpdate();\r
261         this._xnodes[ this._xnodes.length ] = xnode;\r
262         return xnode;\r
263 };\r
264 \r
265 /* --------------------------------------\r
266  *  Clone\r
267  * http://d.hatena.ne.jp/think49/20110724/1311472811\r
268  * http://d.hatena.ne.jp/uupaa/20100508/1273299874\r
269  */\r
270 Node.prototype.clone = function( opt_clone_children ){\r
271         var xnode, xnodes, i, l;\r
272         switch( this._xnodeType ){\r
273                 case 1 :\r
274                         Node._newByTag = true;\r
275                         xnode = new Node( this._tag, X.cloneObject( this._attrs ), X.cloneObject( this._css ) );\r
276                         xnode.className( this._className );\r
277                         if( opt_clone_children && ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){\r
278                                 for( i = 0; i < l; ++i ){\r
279                                         xnode.append( xnodes[ i ].clone( true ) );\r
280                                 };\r
281                         };\r
282                         return xnode;\r
283                 case 3 :\r
284                         Node._newByText = true;\r
285                         xnode = new Node( this._text );\r
286                         return xnode;\r
287                 \r
288                 //case 0 :\r
289                 //case 2 :\r
290         };\r
291         return this;\r
292 };\r
293 \r
294 /* --------------------------------------\r
295  *  Add\r
296  * Node\r
297  * HtmlElement の場合は内部使用専用 そのため event の破棄等しない\r
298  */\r
299 Node.prototype.append = function( v ){\r
300         var i, l, xnodes, frg;\r
301         if( this._xnodeType !== 1 ) return;\r
302         \r
303         if( 1 < ( l = arguments.length ) ){\r
304                 for( i = 0; i < l; ++i ){\r
305                         this.append( arguments[ i ] );\r
306                 };\r
307                 return this;\r
308         };\r
309         \r
310         if( !( xnodes = this._xnodes ) ) this._xnodes = xnodes = [];\r
311         \r
312         switch( Node._getType( v ) ){\r
313                 case Node.IS_RAW_HTML :\r
314                 case Node.IS_RAW_TEXT :\r
315                         v = new Node( v );\r
316                         break;\r
317                 case Node.IS_HTML_STRING :\r
318                 case Node.IS_STRING :\r
319                         return this.append( X.Dom.parse( v, true ) );\r
320                 case Node.IS_XNODE :\r
321                         if( v._xnodeType !== 1 && v._xnodeType !== 3 ) return this;\r
322                         // 親の xnodes から v を消す\r
323                         if( v.parent ){\r
324                                 v.parent._xnodes.splice( v.parent._xnodes.indexOf( v ), 1 );\r
325                                 // ie4\r
326                                 !document.getElementById && document.all && v.remove();\r
327                         } else\r
328                         if( ( i = Node._reserveRemoval.indexOf( v ) ) !== -1 ){\r
329                                 if( v._destroyed ) alert( 'xnode already destroyed!' );\r
330                                 Node._reserveRemoval.splice( i, 1 );\r
331                         };\r
332                 default :\r
333                         return this;\r
334         };\r
335 \r
336         this._reserveUpdate();\r
337         v.parent = this;\r
338         v._state = Node.STATE_NO_PARENT;\r
339         xnodes[ xnodes.length ] = v;\r
340         return this;\r
341 };\r
342 \r
343 \r
344 Node.prototype.appendAt = function( start, v ){\r
345         var xnodes, l, i;\r
346         \r
347         if( this._xnodeType !== 1 ) return this;\r
348         \r
349         if( !( xnodes = this._xnodes ) ) xnodes = this._xnodes = [];\r
350         \r
351         l = arguments.length;\r
352         if( xnodes.length <= start ){\r
353                 if( l === 2 ) return this.append( v );\r
354                 v = [];\r
355                 for( ; 1 < l; ){\r
356                         v[ l - 2 ] = arguments[ --l ];\r
357                 };\r
358                 return this.append.apply( this, v );\r
359         };\r
360         if( start < 0 ) start = 0;\r
361         if( 2 < l ){\r
362                 for( ; l; ){\r
363                         this.appendAt( start, arguments[ --l ] );\r
364                 };\r
365                 return this;\r
366         };\r
367 \r
368         switch( Node._getType( v ) ){\r
369                 case Node.IS_RAW_HTML :\r
370                 case Node.IS_RAW_TEXT :\r
371                         v = new Node( v );\r
372                         break;\r
373                 case Node.IS_HTML_STRING :\r
374                 case Node.IS_STRING :\r
375                         v = X.Dom.parse( v, true );\r
376                         for( i = v.length; i; ){\r
377                                 this.appendAt( start, v[ --i ] );\r
378                         };\r
379                         return this;\r
380                 case Node.IS_XNODE :\r
381                         if( v._xnodeType !== 1 && v._xnodeType !== 3 ) return this;\r
382                         // 親の xnodes から v を消す\r
383                         if( v.parent ){\r
384                                 v.parent._xnodes.splice( v.parent._xnodes.indexOf( v ), 1 );\r
385                                 // ie4\r
386                                 !document.getElementById && document.all && v.remove();\r
387                         } else\r
388                         if( ( i = Node._reserveRemoval.indexOf( v ) ) !== -1 ){\r
389                                 if( v._destroyed ) alert( 'xnode already destroyed!' );\r
390                                 Node._reserveRemoval.splice( i, 1 );\r
391                         };\r
392                         break;\r
393                 default :\r
394                         return this;\r
395         };\r
396 \r
397         this._reserveUpdate();\r
398         v.parent = this;\r
399         v._state = Node.STATE_NO_PARENT;\r
400         this._xnodes.splice( start, 0, v );\r
401         return this;\r
402 };\r
403 \r
404 Node.prototype.appendTo = function( parent, opt_index ){\r
405         if( parent.constructor === Node ){\r
406                 opt_index === undefined ? parent.append( this ) : parent.appendAt( opt_index, this );\r
407         } else {\r
408                 opt_index === undefined ? new Node( parent ).append( this ) : new Node( parent ).appendAt( opt_index, this );\r
409         };\r
410         return this;\r
411 };\r
412 \r
413 Node.prototype.appendToRoot = function( opt_index ){\r
414         opt_index === undefined ? Node.root.append( this ) : Node.root.appendAt( opt_index, this );\r
415         return this;\r
416 };\r
417 \r
418 /* --------------------------------------\r
419  *  Before , After, Replace\r
420  */\r
421 Node.prototype.before = function( v ){\r
422         var parent, l;\r
423         if( this._xnodeType !== 1 || !( parent = this.parent ) ) return this;\r
424         l = arguments.length;\r
425         if( 1 < l ){\r
426                 v = [ this.getOrder() ];\r
427                 for( ; l; ){\r
428                         v[ l ] = arguments[ --l ];\r
429                 };\r
430                 parent.appendAt.apply( parent, v );\r
431                 return this;\r
432         };\r
433         parent.appendAt( this.getOrder(), v );\r
434         return this;\r
435 };\r
436 \r
437 Node.prototype.after = function( v ){\r
438         var parent, l;\r
439         if( this._xnodeType !== 1 || !( parent = this.parent ) ) return this;\r
440         l = arguments.length;\r
441         if( 1 < l ){\r
442                 v = [ this.getOrder() + 1 ];\r
443                 for( ; l; ){\r
444                         v[ l ] = arguments[ --l ];\r
445                 };\r
446                 parent.appendAt.apply( parent, v );\r
447                 return this;\r
448         };\r
449         parent.appendAt( this.getOrder() + 1, v );\r
450         return this;\r
451 };\r
452 \r
453 Node.prototype.replace = function( v ){\r
454         if( !this.parent ) return this;\r
455         return arguments.length === 1 ? this.before( v ).remove() : this.before.apply( this, arguments ).remove();\r
456 };\r
457 \r
458 /* --------------------------------------\r
459  *  Remove\r
460  */\r
461 Node.prototype.remove = function(){\r
462         var parent = this.parent;\r
463                 \r
464         if( !parent ) return this;\r
465 \r
466         this._state = Node.STATE_NO_PARENT;\r
467         parent._xnodes.splice( parent._xnodes.indexOf( this ), 1 );\r
468         Node._reserveRemoval[ Node._reserveRemoval.length ] = this;\r
469         parent._reserveUpdate();\r
470         delete this.parent;\r
471         return this;\r
472 };\r
473 \r
474 Node.prototype.empty = function(){\r
475         var xnodes = this._xnodes, child, i, l;\r
476         if( xnodes && ( l = xnodes.length ) ){\r
477                 for( i = 0; i < l; ++i ){\r
478                         xnodes[ i ].destroy();\r
479                 };\r
480                 xnodes.length = 0;\r
481         };\r
482         return this;\r
483 };\r
484 \r
485 /* --------------------------------------\r
486  *  destory\r
487  */\r
488 Node.prototype.destroy = function( isChild ){\r
489         var xnodes = this._xnodes, i;\r
490         \r
491         if( this._destroyed ) return;\r
492         \r
493         if( xnodes && ( i = xnodes.length ) ){\r
494                 for( ; i; ){\r
495                         xnodes[ --i ].destroy( true );\r
496                 };\r
497                 xnodes.length = 0;\r
498         };\r
499         this.unlisten(); // イベントの退避\r
500 \r
501         delete Node._chashe[ this._uid ];\r
502         \r
503         if( this._rawNode && this._rawNode.parentNode && this._rawNode.parentNode.tagName ){\r
504                 this.remove();\r
505                 this._state = Node.STATE_DESTROYED;\r
506                 this._destroyed = true; // state                \r
507         } else {\r
508                 this.parent._xnodes.splice( this.parent._xnodes.indexOf( this ), 1 );\r
509                 !isChild && this._actualRemove();\r
510                 this.kill();\r
511         };\r
512 };\r
513 \r
514 \r
515 \r
516 /* --------------------------------------\r
517  *  contains\r
518  */\r
519 Node.prototype.contains = function( v ){\r
520         var node, xnodes, i;\r
521         if( !v || !this.parent || this._xnodeType !== -1 ) return false;\r
522         // contains ie4+\r
523         if( document.contains ){\r
524                 node = this._ie4getRawNode ? this._ie4getRawNode() : this._rawNode;\r
525                 switch( Node._getType( v ) ){\r
526                         case Node.IS_RAW_HTML :\r
527                         case Node.IS_RAW_TEXT :\r
528                                 return node.contains( v );\r
529                         case Node.IS_XNODE :\r
530                                 if( v.parent === this ) return true;\r
531                                 v = v._ie4getRawNode ? v._ie4getRawNode() : v._rawNode;\r
532                                 if( node && v ) return node.contains( v );\r
533                                 break;\r
534                         default :\r
535                                 return false;\r
536                 };              \r
537         };\r
538         //if( document.compareDocumentPosition ){\r
539         //      \r
540         //};\r
541         xnodes = this._xnodes;\r
542         if( xnodes.indexOf( v ) !== -1 ) return true;\r
543         if( ( node = this._rawNode ) && node === v.parentNode ) return false;\r
544         for( i = xnodes.length; i; ){\r
545                 if( xnodes[ --i ].contains( v ) ) return true;\r
546         };\r
547         return false;\r
548 };\r
549 \r
550 /* --------------------------------------\r
551  *  getChild\r
552  */\r
553 Node.prototype.getChildAt = function( index ){\r
554         var xnodes = this._xnodes;\r
555         if( this._xnodeType !== 1 || index < 0 || !xnodes || xnodes.length <= index ) return; //?\r
556         return xnodes[ index ];\r
557 };\r
558 \r
559 \r
560 /* --------------------------------------\r
561  *  prevNode, nextNode, firstChild, lastChild\r
562  */\r
563 \r
564 Node.prototype.prevNode = function(){\r
565         var parent = this.parent, xnodes, index;\r
566         if( !parent ) return;\r
567         xnodes = parent._xnodes;\r
568         index = xnodes.indexOf( this );\r
569         if( 0 < index ) return xnodes[ index - 1 ];\r
570 };\r
571 Node.prototype.nextNode = function(){\r
572         var parent = this.parent, xnodes, index;\r
573         if( !parent ) return;\r
574         xnodes = parent._xnodes;\r
575         index  = xnodes.indexOf( this );\r
576         if( index + 1 < xnodes.length ) return xnodes[ index + 1 ];\r
577 };\r
578 Node.prototype.firstChild = function(){\r
579         return this.getChildAt( 0 );\r
580 };\r
581 Node.prototype.lastChild = function(){\r
582         return this.getChildAt( this._xnodes.length - 1 );\r
583 };\r
584 \r
585 /* --------------------------------------\r
586  *  getOrder\r
587  */\r
588 Node.prototype.getOrder = function(){\r
589         var parent = this.parent;\r
590         if( !parent ) return -1;\r
591         return parent._xnodes.indexOf( this );\r
592 };\r
593 \r
594 /* --------------------------------------\r
595  *  className, addClass, removeClass, hasClass\r
596  */\r
597 Node.prototype.className = function( v ){\r
598         var node;\r
599         // getter\r
600         if( v === undefined ) return this._className;\r
601         // setter\r
602         if( this._className === v ) return this;\r
603         if( !v || typeof v !== 'string' ){\r
604                 delete this._className;\r
605         } else {\r
606                 this._className = v;    \r
607         };\r
608         this._dirty |= X.Dom.Dirty.CLASSNAME;\r
609         return this;\r
610 };\r
611 Node.prototype.addClass = function( v ){\r
612         var names = v.split( ' ' ),\r
613                 i     = names.length,\r
614                 name;\r
615         v = '';\r
616         for( ; i; ){\r
617                 name = names[ --i ];\r
618                 if( !name ) continue;\r
619                 !this.hasClass( name ) && ( v += ( v ? ' ' : '' ) + name );\r
620         };\r
621         return v ? his.className( this._className + ( this._className ? ' ' : '' ) + v ) : this;\r
622 };\r
623 Node.prototype.removeClass = function( v ){\r
624         var _          = ' ',\r
625                 className  = this._className,\r
626                 names      = v.split( ' ' ),\r
627                 classNames, i, f;\r
628         if( !className ) return this;\r
629         for( classNames = className.split( _ ), i = classNames.length; i; ){\r
630                 className = classNames[ --i ];\r
631                 for( j = names.length; j; ){\r
632                         if( className === names[ --j ] ){\r
633                                 classNames.splice( i, 1 );\r
634                                 names.splice( j, 1 );\r
635                                 f = true;\r
636                                 break;\r
637                         };\r
638                 };\r
639         };\r
640         return f ? this.className( classNames.join( ' ' ) ) : this;\r
641 };\r
642 Node.prototype.toggleClass = function( v ){\r
643 \r
644 };\r
645 Node.prototype.hasClass = function( v ){\r
646         var _ = ' ',\r
647                 className = this._className,\r
648                 i, name;\r
649         if( className === v ) return true;\r
650         if( !className ) return false;\r
651         \r
652         className = _ + className + _;\r
653         if( className.indexOf( _ + v + _ ) !== -1 ) return true; // lucky hit\r
654         \r
655         for( v = v.split( _ ), i = v.length; i; ){\r
656                 name = v[ --i ];\r
657                 if( name === '' ) continue;\r
658                 if( className.indexOf( _ + name + _ ) === -1 ) return false;\r
659         };\r
660         return true;\r
661 };\r
662 \r
663 /* --------------------------------------\r
664  *  html, text\r
665  */\r
666 Node.prototype.html = function( html, opt_wrap ){\r
667         var xnodes, n, i, l;\r
668         // setter\r
669         if( html ){\r
670                 if( this._xnodeType === 3 ){\r
671                         if( this._text !== html ){\r
672                                 this._text = html;\r
673                                 this.parent && this._reserveUpdate();\r
674                                 this._dirty |= X.Dom.Dirty.CONTENT;\r
675                         };\r
676                         return this;\r
677                 };\r
678                 return this.empty().append.apply( this, X.Dom.parse( html, true ) );\r
679         };\r
680         // getter\r
681         if( this._xnodeType === 3 ){\r
682                 return this._text;\r
683         };\r
684         \r
685         if( this._dirty & X.Dom.Dirty.CSS && !( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){\r
686                 delete this._cssText;\r
687         };\r
688         html = !opt_wrap ? [] : [\r
689                 '<', this._tag,\r
690                 this._id ? ' id=' + this._id : '',\r
691                 this._className ? ' class="' + this._className + '"' : '',\r
692                 this._attrText || ( this._attrText = X.Dom.Attr.objToAttrText( this._attrs ) ),\r
693                 this._cssText ? ' style="' + this._cssText + '"' : '',\r
694         '>' ];\r
695         \r
696         n = html.length;\r
697         if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){\r
698                 for( i = 0; i < l; ++i ){\r
699                         html[ n ] = xnodes[ i ].html( undefined, true );\r
700                         ++n;\r
701                 };\r
702         };\r
703         !opt_wrap || X.Dom.DTD.EMPTY[ this._tag.toLowerCase() ] || ( html[ n ] = '<\/' + this._tag + '>' );\r
704 \r
705         return html.join( '' );\r
706 };\r
707 \r
708 Node.prototype.text = function( text ){\r
709         var xnodes, n, i;\r
710         // setter\r
711         if( text ){\r
712                 if( this._xnodeType === 3 ){\r
713                         if( this._text !== text ){\r
714                                 this._text = text;\r
715                                 this.parent && this._reserveUpdate();\r
716                                 this._dirty |= X.Dom.Dirty.CONTENT;\r
717                         };\r
718                         return this;\r
719                 };\r
720                 this.empty().createText( text );\r
721                 return this;    \r
722         };\r
723         // getter\r
724         if( this._xnodeType === 1 ){\r
725                 if( ( xnodes = this._xnodes ) && ( i = xnodes.length ) ){\r
726                         for( text = [], n = -1; i; ){\r
727                                 text[ ++n ] = xnodes[ --i ].text();\r
728                         };\r
729                         return text.join( '' );\r
730                 };\r
731                 return '';\r
732         };\r
733         return this._text;\r
734 };\r
735 \r
736 /* --------------------------------------\r
737  *  Async commit update\r
738  * \r
739  * state:\r
740  *  0 : no_rawnode\r
741  *  1 : not_added\r
742  *  3 : dirty\r
743  *  4 : clean\r
744  * \r
745  * remove :\r
746  * root._reserveRemoval = [] に追加。commitUpdate で remove して state は not_added\r
747  * add :\r
748  * root._reserveRemoval にいたら消す, new_parent._xnodes に挿入 steta は not_added にして commitUpdate を待つ\r
749  */\r
750         \r
751 Node.prototype._reserveUpdate = function( child ){\r
752         var root = Node.root;\r
753         //if( !root ) return;\r
754         //child && ( child._dirty = true );\r
755         if( root && !root._updateReserved ) root._updateReserved = X.Timer.requestFrame( root, root._startUpdate );\r
756 };\r
757 \r
758 Node.prototype._startUpdate = function(){\r
759         var removal, i, xnode, tmp;\r
760         \r
761         if( this._updateReserved ){\r
762                 //X.Timer.cancelFrame( this._updateReserved );\r
763                 delete this._updateReserved;\r
764         } else {\r
765                 return;\r
766         };\r
767 \r
768         removal = Node._reserveRemoval;\r
769         i       = removal.length;\r
770         \r
771         tmp = this._rawNode.style.visibility;\r
772         //this._rawNode.style.visibility = 'hidden';\r
773         \r
774         for( ; i; ){\r
775                 xnode = removal[ --i ];\r
776                 xnode._actualRemove();\r
777                 xnode._destroyed && xnode.kill();\r
778         };\r
779         this._commitUpdate();\r
780         \r
781         //this._rawNode.style.visibility = tmp;\r
782 };\r
783 \r
784 Node.prototype._commitUpdate =\r
785         document.getElementById ?\r
786                 ( function( parentElement, nextElement ){\r
787                         var elm = this._rawNode,\r
788                                 xnodes, l, i, next, k, v;\r
789 \r
790                         if( !elm ){\r
791                                 nextElement ?\r
792                                         parentElement.insertBefore( this._actualCreate(), nextElement ) :\r
793                                         parentElement.appendChild( this._actualCreate() );\r
794                                 this._afterActualCreate();\r
795                                 return this._rawNode;\r
796                         } else          \r
797                         if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){\r
798                                 for( ; l; ){\r
799                                         next = xnodes[ --l ]._commitUpdate( elm, next );\r
800                                 };\r
801                         };\r
802 \r
803                         // textNode\r
804                         if( this._dirty & X.Dom.Dirty.CONTENT ) elm.data = X.Dom.chrReferanceTo( this._text );\r
805                         // className\r
806                         if( this._dirty & X.Dom.Dirty.CLASSNAME ) elm.className = this._className;\r
807                         // style\r
808                         if( this._dirty & X.Dom.Dirty.CSS ){\r
809                                 if( this._cssText || ( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){\r
810                                         elm.style.cssText = this._cssText;\r
811                                 } else {\r
812                                         elm.removeAttribute( 'style' );\r
813                                         delete this._cssText;\r
814                                 };\r
815                         };\r
816                         // attr\r
817                         if( this._newAttrs ){\r
818                                 for( k in this._newAttrs ){\r
819                                         ( v = this._newAttrs[ k ] ) === undefined ?\r
820                                                 elm.removeAttribute( k ) :\r
821                                                 ( elm[ k ] = v );\r
822                                 };\r
823                                 delete this._newAttrs;\r
824                         };\r
825                         \r
826                         delete this._dirty;\r
827                         \r
828                         return elm;\r
829                 }) :\r
830         document.all ? \r
831                 ( function( parentElement, prevElement ){\r
832                         var elm    = this._rawNode || this._ie4getRawNode(),\r
833                                 xnodes = this._xnodes,\r
834                                 l      = xnodes && xnodes.length,\r
835                                 i, html, elm, child, prev, k, v;\r
836 \r
837                         if( !elm ){\r
838                                 prevElement ?\r
839                                         prevElement.insertAdjacentText( 'AfterEnd', this._actualCreate() ) :\r
840                                         parentElement.insertAdjacentText( 'BeforeEnd', this._actualCreate() );\r
841                                 this._afterActualCreate();\r
842                                 return this._rawNode || this._ie4getRawNode();\r
843                         } else\r
844                         if( this._dirty | X.Dom.Dirty.IE4_TEXTNODE_FIX ){\r
845                                 html = [];\r
846                                 for( i = 0; i < l; ++i ){\r
847                                         html[ i ] = xnodes[ i ]._actualCreate();\r
848                                 };\r
849                                 elm.innerHTML = html.join( '' );\r
850                                 for( i = 0; i < l; ++i ){\r
851                                         xnodes[ i ]._afterActualCreate();\r
852                                 };\r
853                         } else                  \r
854                         if( l ){\r
855                                 for( i = 0; i < l; ++i ){\r
856                                         prev = xnodes[ i ]._commitUpdate( elm, prev );\r
857                                 };\r
858                         };\r
859 \r
860                         // fake textNode\r
861                         if( this._dirty & X.Dom.Dirty.CONTENT ) elm.innerHTML = this._text;\r
862                         // className\r
863                         if( this._dirty & X.Dom.Dirty.CLASSNAME ) elm.className = this._className;\r
864                         // style\r
865                         if( this._dirty & X.Dom.Dirty.CSS ){\r
866                                 if( this._cssText || ( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){\r
867                                         elm.style.cssText = this._cssText;\r
868                                 } else {\r
869                                         elm.removeAttribute( 'style' );\r
870                                         delete this._cssText;\r
871                                 };\r
872                         };\r
873                         // attr\r
874                         if( this._newAttrs ){\r
875                                 for( k in this._newAttrs ){\r
876                                         ( v = this._newAttrs[ k ] ) === undefined ?\r
877                                                 elm.removeAttribute( k ) :\r
878                                                 elm.setAttribute( k, v );\r
879                                 };\r
880                                 delete this._newAttrs;\r
881                         };\r
882                         \r
883                         delete this._dirty;\r
884                         \r
885                         return elm;\r
886                 }) :\r
887                 (function(){});\r
888 \r
889 /* --------------------------------------\r
890  *  Create\r
891  * \r
892  * http://d.hatena.ne.jp/uupaa/20080718/1216362040\r
893  * DOM Rangeが使える環境(Firefox2+,Opera9+,Safari3+)なら、innerHTMLいらずで、ガーって書けます。\r
894  * return document.createRange().createContextualFragment("<div><select><option></option></select></div>");\r
895  * insertAdjacentHTML\r
896  * \r
897  * ie7 以下では iframe の frameborder や、input name は、createElement 後に aetAttribute しても無視される\r
898  * \r
899  * fragument がある場合 children も足して\r
900  * Mozilla: 1.0+, IE: 6.0+, Netscape: 2.0+, Safari: 1.0+, Opera: 7.0+\r
901  * ie6 大丈夫?fragment の場合リークしないか?チェックが必要\r
902  * http://msdn.microsoft.com/ja-jp/library/bb250448%28v=vs.85%29.aspx\r
903  * \r
904  * document.createElement of ie4 is only for OPTION & IMAGE.\r
905  */\r
906 Node.prototype._actualCreate =\r
907         document.getElementById ? (function( isChild ){\r
908                 var elm = this._rawNode,\r
909                         xnodes, frg, i, l;\r
910                 \r
911                 if( this._xnodeType === 3 ){\r
912                         return elm || ( this._rawNode = document.createTextNode( X.Dom.chrReferanceTo( this._text ) ) );\r
913                 };\r
914                 \r
915                 if( !elm ){\r
916                         if( this._dirty & X.Dom.Dirty.CSS && !( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){\r
917                                 delete this._cssText;\r
918                         };\r
919                         this._isNew = true;\r
920                         this._rawNode = elm =\r
921                                 X.UA.IE ?\r
922                                         document.createElement( [\r
923                                                 '<', this._tag,\r
924                                                         ' UID="', this._uid, '"',\r
925                                                         this._id ? ' id="' + this._id + '"' : '',\r
926                                                         this._className ? ' class="' + this._className + '"' : '',\r
927                                                         this._attrText || ( this._attrText = X.Dom.Attr.objToAttrText( this._attrs ) ),\r
928                                                         this._cssText ? ' style="' + this._cssText + '"' : '',\r
929                                                 '>' ].join( '' ) ):\r
930                                         document.createElement( this._tag );\r
931                 };\r
932                 if( Node._useDocumentFragment ){\r
933                         if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){\r
934                                 !isChild && ( frg = Node._useDocumentFragment ).appendChild( elm );\r
935                                 for( i = 0; i < l; ++i ){\r
936                                         elm.appendChild( xnodes[ i ]._actualCreate( true ) );\r
937                                 };\r
938                                 return frg || elm;\r
939                         };\r
940                 };\r
941                 \r
942                 return elm;\r
943         }) :\r
944         document.all ? (function(){\r
945                 var uid = this._uid,\r
946                         html, xnodes, n, i, l;\r
947                 \r
948                 if( this._xnodeType === 3 ){\r
949                         html = [ '<font id=ie4uid', uid, ' UID=', uid, '>', this._text, '</font>' ];// fake textNode\r
950                 } else {\r
951                         if( this._dirty & X.Dom.Dirty.CSS && !( this._cssText = X.Dom.Style.objToCssText( this._css ) ) ){\r
952                                 delete this._cssText;\r
953                         };\r
954                         html = [\r
955                                 '<', this._tag, ' id=', ( this._id || ( 'ie4uid' + uid ) ), ' UID=', uid,\r
956                                 this._className ? ' class="' + this._className + '"' : '',\r
957                                 this._attrText || ( this._attrText = X.Dom.Attr.objToAttrText( this._attrs ) ),\r
958                                 this._cssText ? ' style="' + this._cssText + '"' : '',\r
959                         '>' ];\r
960                         \r
961                         n = html.length;\r
962                         if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){\r
963                                 for( i = 0; i < l; ++i ){\r
964                                         html[ n ] = xnodes[ i ]._actualCreate();\r
965                                         ++n;\r
966                                 };\r
967                         };\r
968                         X.Dom.DTD.EMPTY[ this._tag.toLowerCase() ] || ( html[ n ] = '<\/' + this._tag + '>' );\r
969                         \r
970                         delete this._newAttrs;\r
971                 };\r
972                 delete this._dirty;\r
973                 delete this._rawNode;\r
974                 \r
975                 return html.join( '' );\r
976         }) :\r
977         (function(){});\r
978 \r
979 Node.prototype._afterActualCreate =\r
980         document.getElementById ? (function(){\r
981                 var xnodes, l, elm, attrs, k, i;\r
982                 \r
983                 this.state  = Node.STATE_STAGED;\r
984                 delete this._dirty;\r
985                 if( this._xnodeType === 3 ){\r
986                         //elm.UID = this._uid;\r
987                         return this;\r
988                 };\r
989                 delete this._newAttrs;\r
990                         \r
991                 xnodes = this._xnodes;\r
992                 l      = xnodes && xnodes.length;\r
993                 elm    = this._rawNode;\r
994                 \r
995                 if( this._isNew ){\r
996                         if( !Node._useDocumentFragment && l ){// docFrg が使えない場合、doc 追加後に子を追加\r
997                                 for( i = 0; i < l; ++i ){\r
998                                         elm.appendChild( xnodes[ i ]._actualCreate( true ) );\r
999                                 };\r
1000                         };\r
1001                         if( !X.UA.IE ){\r
1002                                 elm.UID = this._uid;\r
1003                                 if( this._id ) elm.id = this._id;\r
1004                                 if( this._className ) elm.className = this._className;\r
1005                                 if( attrs = this._attrs ){\r
1006                                         for( k in attrs ){\r
1007                                                 elm[ k ] = attrs[ k ];\r
1008                                         };\r
1009                                 };\r
1010                                 elm.style.cssText = this._cssText;\r
1011                         };\r
1012                         this._restoreEvent();// イベントの復帰\r
1013                         delete this._isNew;\r
1014                 };\r
1015                 if( l ){\r
1016                         for( i = 0; i < l; ++i ){\r
1017                                 xnodes[ i ]._afterActualCreate();\r
1018                         };\r
1019                 };\r
1020                 return this;\r
1021         }) :\r
1022         document.all ? (function(){\r
1023                 var xnodes, i;\r
1024                 this.state = Node.STATE_STAGED;\r
1025                 \r
1026                 if( this._xnodeType !== 1 ) return this;\r
1027                 \r
1028                 if( ( xnodes = this._xnodes ) && ( i = xnodes.length ) ){\r
1029                         for( ; i; ){\r
1030                                 xnodes[ --i ]._afterActualCreate();\r
1031                         };\r
1032                 };\r
1033                 return this._restoreEvent();// イベントの復帰\r
1034         }) :\r
1035         (function(){});\r
1036         \r
1037 Node.prototype._actualRemove =\r
1038         document.getElementById ?\r
1039                 ( function( isChild ){\r
1040                         var xnodes = this._xnodes,\r
1041                                 elm    = this._rawNode,\r
1042                                 child, i, l;\r
1043                         if( xnodes && ( l = xnodes.length ) ){\r
1044                                 for( i = 0; i < l; ++i ){\r
1045                                         child = xnodes[ i ];\r
1046                                         child._xnodeType === 1 && child._actualRemove( true );\r
1047                                 };\r
1048                         };\r
1049                         if( !elm ) return;\r
1050                         this._xnodeType === 1 && this._migrateEvent();// イベントの退避\r
1051                         // elm.parentNode.tagName check tagName is for ie7\r
1052                         !isChild && elm.parentNode && elm.parentNode.tagName && elm.parentNode.removeChild( elm );\r
1053                 }) :\r
1054         document.all ? \r
1055                 ( function( isChild ){\r
1056                         var xnodes = this._xnodes,\r
1057                                 elm    = this._rawNode || this._ie4getRawNode(),\r
1058                                 i, l, xnode;\r
1059                         if( xnodes && ( l = xnodes.length ) ){\r
1060                                 for( i = 0; i < l; ++i ){\r
1061                                         xnodes[ i ]._actualRemove( true );\r
1062                                 };\r
1063                         };\r
1064                         if( !elm ) return;\r
1065                         this._xnodeType === 1 && this._migrateEvent();// イベントの退避\r
1066                         delete this._rawNode;\r
1067                         elm.removeAttribute( 'id', '' );\r
1068                         document.all[ 'ie4uid' + this._uid ] = null;\r
1069                         if( !isChild ) elm.outerHTML = '';\r
1070                 }) :\r
1071                 (function(){});\r
1072         \r
1073         \r
1074 //})( window, document );\r
1075 \r
1076 \r