OSDN Git Service

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