OSDN Git Service

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