OSDN Git Service

d526b36209f56a85c84d38ce45225b29e8fefd84
[pettanr/clientJs.git] / 0.6.x / js / 02_dom / 02_XNode.js
1 var \r
2         \r
3         X_Node_State = {\r
4                 DESTROYED              : 0x0,\r
5                 EXIST                  : 0x1,\r
6                 IN_TREE                : 0x2, // xnode が(仮想)ツリーに追加されている -> 描画の対象\r
7                 \r
8                 ELM_NEED_INIT          : 2 <<  1,\r
9                 \r
10                 STYLE_IS_DISPLAY_NONE  : 2 <<  2, // display    : none          \r
11                 STYLE_IS_INVISIBLE     : 2 <<  3, // visibility : hidden or opacity : 0\r
12                 STYLE_IS_POS_ABSOLUTE  : 2 <<  4, // position   : absolute\r
13                 STYLE_IS_NO_OVERFLOW   : 2 <<  5, // overflow   : hidden\r
14                 STYLE_IS_WIDTH_LENGTH  : 2 <<  6, // width  : width() のための commitUpdate が不要\r
15                 STYLE_IS_WIDTH_PCT     : 2 <<  7, // width  : width() のための commitUpdate が不要かもしれない。(親で LENGTH が指定されているなら)\r
16                 STYLE_IS_HEIGHT_LENGTH : 2 <<  8, // height :\r
17                 STYLE_IS_HEIGHT_PCT    : 2 <<  9, // height :\r
18                 STYLE_IS_FONT_LENGTH   : 2 << 10, // fontSize :\r
19                 STYLE_IS_FONT_PCT      : 2 << 11, // fontSize :\r
20 \r
21                 //DIRTY_CHILD            : 2 << 18, // 使っていない\r
22                 DIRTY_CONTENT          : 2 << 12, // width, height, x, y textNode の内容 TODO html と排他なので ID と共通でいい\r
23                 DIRTY_ID               : 2 << 13, // width, height, x, y\r
24                 DIRTY_CLASSNAME        : 2 << 14, // X_Node_CSS_getCharSize, width, height, x, y\r
25                 DIRTY_ATTR             : 2 << 15, // X_Node_CSS_getCharSize, width, height, x, y\r
26                 DIRTY_CSS              : 2 << 16, // X_Node_CSS_getCharSize, width, height, x, y\r
27                 DIRTY_IE_FILTER        : X_UA.IE < 10 && X_UA.ActiveX ? 2 << 17 : 0, // \r
28 \r
29                 OLD_ATTRTEXT           : 2 << 18,\r
30                 OLD_CSSTEXT            : 2 << 19,\r
31 \r
32                 GPU_WAITING            : 2 << 20,                     // 1:子のGPU解除待\r
33                 GPU_RESERVED           : 2 << 21,                     // 2:GPU予約\r
34                 GPU_NOW                : 2 << 20 | 2 << 21,           // 3:GPU now!()\r
35                 GPU_RELEASE_RESERVED   : 2 << 20 | 2 << 21 | 2 << 22, // 4:GPU解除予約\r
36                 \r
37                 /* 子要素は一つのテキストノード */\r
38                 IE4_ONLY_TEXT          : 2 << 23,\r
39                 /* 子要素に html要素とテキストノードが混在する */\r
40                 IE4_TEXTNODE_FIX       : 2 << 24,\r
41                 IE4_TEXTNODE_EXIST     : 2 << 25\r
42         },\r
43 \r
44         X_Node_BITMASK_RESET_STYLE = ( ( 2 << 29 ) - 1 + ( 2 << 29 ) ) ^ (\r
45                 X_Node_State.STYLE_IS_DISPLAY_NONE |\r
46                 X_Node_State.STYLE_IS_INVISIBLE |\r
47                 X_Node_State.STYLE_IS_POS_ABSOLUTE |\r
48                 X_Node_State.STYLE_IS_NO_OVERFLOW |\r
49                 X_Node_State.STYLE_IS_WIDTH_LENGTH |\r
50                 X_Node_State.STYLE_IS_WIDTH_PCT |\r
51                 X_Node_State.STYLE_IS_HEIGHT_LENGTH |\r
52                 X_Node_State.STYLE_IS_HEIGHT_PCT |\r
53                 X_Node_State.STYLE_IS_FONT_LENGTH |\r
54                 X_Node_State.STYLE_IS_FONT_PCT ),\r
55 \r
56         X_Node_BitMask_IS_DIRTY = \r
57                 X_Node_State.DIRTY_CHILD | X_Node_State.DIRTY_CONTENT | X_Node_State.DIRTY_ID | X_Node_State.DIRTY_CLASSNAME |\r
58                 X_Node_State.DIRTY_ATTR | X_Node_State.DIRTY_CSS | X_Node_State.DIRTY_IE_FILTER,\r
59 \r
60         X_Node_BitMask_RESET_DIRTY = ( ( 2 << 29 ) - 1 + ( 2 << 29 ) ) ^ X_Node_BitMask_IS_DIRTY,\r
61         \r
62         X_Node_TYPE = {\r
63                 XNODE       : 1,\r
64                 RAW_HTML    : 2,\r
65                 RAW_TEXT    : 3,\r
66                 HTML_STRING : 4,\r
67                 STRING      : 5,\r
68                 //DOC_FRAG    : 6,\r
69                 XNODE_LIST  : 7,\r
70                 WINDOW      : 8,\r
71                 DOCUMENT    : 9,\r
72                 IMAGE       : 10\r
73         },\r
74         \r
75         X_Node_strictElmCreation = !X_UA.MacIE && X_UA.IE5678,// && !X_UA.MacIE;\r
76         \r
77         X_Node_useDocumentFragment = document.createDocumentFragment && ( !X_UA.IE || 5.5 <= X_UA.IE ) && document.createDocumentFragment(),\r
78         \r
79         X_Node_displayNoneFixForIE5 = X_UA.IE5 && X_UA.ActiveX,\r
80         \r
81         X_Node_newByTag      = false,\r
82         \r
83         X_Node_newByText     = false,\r
84         \r
85         X_Node_outerXNode    = null,\r
86         \r
87         X_Node_updateTimerID = 0,\r
88 /*\r
89  * Node( rawElement | rawTextnode | htmlString | textString )\r
90  */     \r
91         Node = X.Node = X.EventDispatcher.inherits(\r
92         'XDomNode',\r
93         X.Class.POOL_OBJECT, // X.Class.FINAL\r
94         {\r
95                 _uid       : 0,\r
96                 _flags     : X_Node_State.DESTROYED,\r
97 \r
98                 _rawObject : null,\r
99                 _rect      : null, // \r
100                 _fontSize  : 0,\r
101                 \r
102                 parent     : null, // remove された枝も親子構造は維持している。\r
103                 _xnodes    : null, // Array.<Node>\r
104 \r
105                 _tag       : '',\r
106                 _text      : '',\r
107                 _id        : '',\r
108                 _className : '',\r
109 \r
110                 _attrs     : null, // see X_Node_Attr\r
111                 _newAttrs  : null,\r
112                 _attrText  : '',\r
113                 \r
114                 _css       : null, // see X_Node_CSS\r
115                 _cssText   : '',\r
116                 \r
117                 _anime     : null, // Hash see X_Node_Anime\r
118                 \r
119         /*\r
120          * TODO Node の継承ができない!\r
121          */\r
122                 Constructor : function( v ){\r
123                         var css, xnodes, xnode, parent, uid = X_Node_CHASHE.length;\r
124                         \r
125                         if( X_Node_newByTag ){\r
126                                 X_Node_newByTag = false;\r
127                                 this._tag       = v.toUpperCase();\r
128                                 this._flags    |= X_Node_State.EXIST;\r
129                                 arguments[ 1 ] && this.attr( arguments[ 1 ] );\r
130                                 css = arguments[ 2 ];\r
131                                 css && this[ X.Type.isString( css ) ? 'cssText' : 'css' ]( css );\r
132                         } else\r
133                         if( X_Node_newByText ){\r
134                                 X_Node_newByText = false;\r
135                                 this._text       = v;\r
136                                 this._flags     |= X_Node_State.EXIST;\r
137                         } else {\r
138                                 if( 1 < arguments.length ) return new X_NodeList( arguments );\r
139                                 if( X.Type.isArray( v ) && v.length ) return new X_NodeList( v );\r
140 \r
141                                 switch( X_Node_getType( v ) ){\r
142                                         case X_Node_TYPE.XNODE :\r
143                                         case X_Node_TYPE.XNODE_LIST :\r
144                                                 return v;\r
145 \r
146                                         case X_Node_TYPE.RAW_HTML :\r
147                                                 if( xnode = X_Node_getXNode( v ) ) return xnode;\r
148                                                 // v.parentNode || v.parentElement : dom1 || dom0\r
149                                                 this.parent     = ( parent = v.parentNode || v.parentElement ) && parent.tagName /* ie7- */ && X_Node_getXNode( parent );\r
150                                                 if( this.parent && ( this.parent._flags & X_Node_State.IN_TREE ) ){\r
151                                                         this._flags |= X_Node_State.IN_TREE;\r
152                                                 };\r
153                                                 this._rawObject = v;\r
154                                                 this._flags    |= X_Node_State.EXIST;\r
155                                                 this._tag       = v.tagName.toUpperCase();\r
156                                                 this._id        = v.id;\r
157                                                 this._className = v.className;\r
158                                                 \r
159                                                 this.cssText( v.style.cssText );\r
160                                                 this._flags &= X_Node_BitMask_RESET_DIRTY; // X_Node_State.DIRTY_CSS を落とす\r
161                                                 \r
162                                                 // TODO attr の回収は不可能、、、\r
163                                                 if( X_UA_DOM.IE4 ){\r
164                                                         v.setAttribute( 'UID', '' + uid );\r
165                                                 } else {\r
166                                                         v.UID = uid;\r
167                                                 };\r
168                                                 // childNodes...\r
169                                                 break;\r
170 \r
171                                         case X_Node_TYPE.RAW_TEXT :\r
172                                                 if( xnode = X_Node_getXNode( v ) ) return xnode;\r
173                                                 this.parent     = X_Node_getXNode( v.parentNode );\r
174                                                 if( this.parent && ( this.parent._flags & X_Node_State.IN_TREE ) ){\r
175                                                         this._flags |= X_Node_State.IN_TREE;\r
176                                                 };\r
177                                                 this._rawObject = v;\r
178                                                 this._flags    |= X_Node_State.EXIST;\r
179                                                 this._text      = v.data;\r
180                                                 v.UID = uid;\r
181                                                 break;\r
182 \r
183                                         case X_Node_TYPE.HTML_STRING :\r
184                                         case X_Node_TYPE.STRING :\r
185                                                 if( xnodes = X_HtmlParser_parse( v, true ) && 1 < xnodes.length ) return new X_NodeList( xnodes );\r
186                                                 if( xnodes.length ) return xnodes[ 0 ];\r
187                                                 return X_Node_none;\r
188 \r
189                                         default :\r
190                                                 if( X_Node_none ) return X_Node_none;\r
191                                                 return;\r
192                                 };\r
193                         };\r
194                         \r
195                         X_Node_CHASHE[ this._uid = uid ] = this;\r
196                 },\r
197                 \r
198                 // attr\r
199                 // css, cssText\r
200                 // find\r
201                 // animate, stop\r
202                 \r
203                 create         : X_Node_create,\r
204                 \r
205                 createAt       : X_Node_createAt,\r
206                 \r
207                 createText     : X_Node_createText,\r
208                 \r
209                 createTextAt   : X_Node_createTextAt,\r
210                 \r
211                 clone          : X_Node_clone,\r
212                 \r
213                 append         : X_Node_append,\r
214                 \r
215                 appendAt       : X_Node_appendAt,\r
216                 \r
217                 appendTo       : X_Node_appendTo,\r
218                 \r
219                 appendToRoot   : X_Node_appendToRoot,\r
220                 \r
221                 before         : X_Node_before, // remove\r
222                 \r
223                 prevNode       : X_Node_before, // -> prev\r
224                 \r
225                 after          : X_Node_after, // remove\r
226                 \r
227                 nextNode       : X_Node_after, // -> next\r
228                 \r
229                 replace        : X_Node_replace, // remove\r
230                 \r
231                 swap           : X_Node_replace,\r
232                 \r
233                 remove         : X_Node_remove,\r
234                 \r
235                 empty          : X_Node_empty,\r
236                 \r
237                 destroy        : X_Node_destroy, // -> kill && kill event\r
238                 \r
239                 contains       : X_Node_contains,\r
240                 \r
241                 getChildAt     : X_Node_getChildAt,\r
242                 \r
243                 numChildren    : X_Node_length,\r
244                 \r
245                 firstChild     : X_Node_firstChild,\r
246                 \r
247                 lastChild      : X_Node_lastChild,\r
248                 \r
249                 getOrder       : X_Node_getOrder,\r
250                 \r
251                 className      : X_Node_className,\r
252                 addClass       : X_Node_addClass,\r
253                 removeClass    : X_Node_removeClass,\r
254                 toggleClass    : X_Node_toggleClass,\r
255                 hasClass       : X_Node_hasClass,\r
256                 \r
257                 html           : X_Node_html,\r
258                 text           : X_Node_text,\r
259                 call           : X_Node_call,\r
260                 each           : X_Node_each\r
261                 \r
262         }\r
263 );\r
264 \r
265 function X_Node_getType( v ){\r
266         if( v === '' ) return X_Node_TYPE.STRING;\r
267         if( !v ) return 0;\r
268         if( v === window ) return X_Node_TYPE.WINDOW;\r
269         if( v === document ) return X_Node_TYPE.DOCUMENT;\r
270         if( v.constructor === Node ) return X_Node_TYPE.XNODE;\r
271         if( v.constructor === X_NodeList ) return X_Node_TYPE.XNODE_LIST;\r
272         if( X.Type.isHTMLElement( v ) ) return X_Node_TYPE.RAW_HTML;\r
273         if( v.nodeType === 3 ) return X_Node_TYPE.RAW_TEXT;\r
274         if( X.Type.isString( v ) ){\r
275                 return '<' === v.charAt( 0 ) && v.charAt( v.length - 1 ) === '>' ? X_Node_TYPE.HTML_STRING : X_Node_TYPE.STRING;\r
276         };\r
277         return 0;\r
278 };\r
279 function X_Node_getXNode( v ){\r
280         var uid, i, chashe, xnode;\r
281         switch( X_Node_getType( v ) ){\r
282                 case X_Node_TYPE.XNODE :\r
283                 case X_Node_TYPE.XNODE_LIST :\r
284                         return v;\r
285                 case X_Node_TYPE.RAW_HTML :\r
286                         // fake TextNode too.\r
287                         if( X_UA_DOM.IE4 ){\r
288                                 uid = v.getAttribute( 'UID' );\r
289                                 return uid && X_Node_CHASHE[ uid ];\r
290                         };\r
291                         return v.UID && X_Node_CHASHE[ v.UID ];\r
292                 case X_Node_TYPE.WINDOW :\r
293                         return X_ViewPort;\r
294                 case X_Node_TYPE.DOCUMENT :\r
295                         return X_ViewPort_document;\r
296                 case X_Node_TYPE.RAW_TEXT :\r
297                         if( v.UID ) return X_Node_CHASHE[ v.UID ];\r
298                         for( chashe = X_Node_CHASHE, i = chashe.length; i; ){\r
299                                 if( ( xnode = X_Node_CHASHE[ --i ] ) && ( xnode._rawObject === v ) ) return xnode;\r
300                         };\r
301         };\r
302 };\r
303 \r
304 function X_Node_getRoot( xnode ){\r
305         return X_ViewPort_document;\r
306         //return X_Node_body._rawObject.documentElement ? node : node.ownerDocument || node.document;\r
307 };\r
308         // XMLかどうかを判別する\r
309 var X_Node_isXmlDocument =\r
310                 X_UA_DOM.IE4 ?\r
311                         X.emptyFunction :\r
312                         (function( root ){\r
313                                 if( X.Type.isBoolean( root.isXML ) ) return root.isXML;\r
314                                 return root.isXML = root._rawObject.createElement( 'p' ).tagName !== root._rawObject.createElement( 'P' ).tagName;\r
315                         }),\r
316         X_Node_CHASHE     = [],\r
317         X_Node_none  = X_Node_CHASHE[ 0 ] = new Node(),\r
318         X_Node_html, // = X_Node_CHASHE[ 1 ] <html>\r
319         X_Node_head, // = X_Node_CHASHE[ 2 ] <head>\r
320         X_Node_body, // = X_Node_CHASHE[ 3 ] <body>\r
321         X_Node_systemNode, // = X_Node_CHASHE[ ? ]\r
322         X_Node_fontSizeNode,\r
323 /*\r
324  * remove :\r
325  *  X_Node_reserveRemoval = [] に追加。commitUpdate で remove\r
326  * add :\r
327  *  X_Node_reserveRemoval にいたら消す, new_parent._xnodes に挿入\r
328  */\r
329         X_Node_reserveRemoval = [];\r
330 \r
331 \r
332 var X_Node__ie4getRawNode = X_UA_DOM.IE4 && function ( that ){\r
333                 var elm = that._rawObject;\r
334                 return elm ||\r
335                         ( ( elm = document.all[ 'ie4uid' + that._uid ] ) && ( that._rawObject = elm ) ) ||\r
336                         ( that._id && ( elm = document.all[ that._id ] ) ) && ( that._rawObject = elm );\r
337         };\r
338 \r
339 \r
340 function X_Node_toggleInTreeFlag( xnodes, flag ){\r
341         var i = xnodes.length, xnode;\r
342         for( ; i; ){\r
343                 xnode = xnodes[ --i ];\r
344                 flag ? ( xnode._flags |= X_Node_State.IN_TREE ) : ( xnode._flags &= ~X_Node_State.IN_TREE );\r
345                 xnode._xnodes && X_Node_toggleInTreeFlag( xnode._xnodes, flag );\r
346         };\r
347 };\r
348 \r
349 /* --------------------------------------\r
350  *  Create\r
351  */\r
352 function X_Node_create( tag, opt_attrs, opt_css ){\r
353         var xnode;\r
354         if( !this._tag ) return;\r
355         if( !this._xnodes ) this._xnodes = [];\r
356         \r
357         xnode = X_Doc_create( tag, opt_attrs, opt_css );\r
358         \r
359         xnode.parent = this;\r
360         this._xnodes[ this._xnodes.length ] = xnode;\r
361         if( this._flags & X_Node_State.IN_TREE ){\r
362                 xnode._flags |= X_Node_State.IN_TREE;\r
363                 xnode._xnodes && X_Node_toggleInTreeFlag( xnode._xnodes, true );\r
364                 X_Node_reserveUpdate();\r
365         };\r
366         return xnode;\r
367 };\r
368 function X_Node_createAt( index, tag, opt_attrs, opt_css ){\r
369         var xnode = X_Doc_create( tag, opt_attrs, opt_css );\r
370         this.appendAt( index, xnode );\r
371         return xnode;\r
372 };\r
373 \r
374 /* --------------------------------------\r
375  *  CreateText\r
376  */\r
377 function X_Node_createText( text ){\r
378         var xnode;\r
379         if( !this._tag ) return;\r
380         if( !this._xnodes ) this._xnodes = [];\r
381         \r
382         X_Node_newByText = true;\r
383         xnode = new Node( text );\r
384         xnode.parent = this;\r
385         this._xnodes[ this._xnodes.length ] = xnode;\r
386         \r
387         if( this._flags & X_Node_State.IN_TREE ){\r
388                 xnode._flags |= X_Node_State.IN_TREE;\r
389                 xnode._xnodes && X_Node_toggleInTreeFlag( xnode._xnodes, true );\r
390                 X_Node_reserveUpdate();\r
391         };\r
392         return xnode;\r
393 };\r
394 function X_Node_createTextAt( index, text ){\r
395         var xtext = X_Doc_createText( text );\r
396         this.appendAt( index, xtext );\r
397         return xtext;\r
398 };\r
399 \r
400 /* --------------------------------------\r
401  *  Clone\r
402  * http://d.hatena.ne.jp/think49/20110724/1311472811\r
403  * http://d.hatena.ne.jp/uupaa/20100508/1273299874\r
404  */\r
405 function X_Node_clone( opt_clone_children ){\r
406         var xnode, xnodes, i, l;\r
407         if( this._tag ){\r
408                 X_Node_newByTag = true;\r
409                 xnode = new Node( this._tag, X_Object_clone( this._attrs ), X_Object_clone( this._css ) )\r
410                         .attr( { 'id' : this._id } )\r
411                         .className( this._className );\r
412                 if( opt_clone_children && ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){\r
413                         for( i = 0; i < l; ++i ){\r
414                                 xnode.append( xnodes[ i ].clone( true ) );\r
415                         };\r
416                 };\r
417                 return xnode;           \r
418         };\r
419         X_Node_newByText = true;\r
420         return new Node( this._text );\r
421 };\r
422 \r
423 /* --------------------------------------\r
424  *  Add\r
425  * Node\r
426  * HtmlElement の場合は内部使用専用 そのため event の破棄等しない\r
427  */\r
428 function X_Node_append( v ){\r
429         var i, l, xnodes, frg;\r
430         if( !this._tag ) return;\r
431         \r
432         if( 1 < ( l = arguments.length ) ){\r
433                 for( i = 0; i < l; ++i ){\r
434                         this.append( arguments[ i ] );\r
435                 };\r
436                 return this;\r
437         };\r
438         \r
439         if( !( xnodes = this._xnodes ) ) this._xnodes = xnodes = [];\r
440         \r
441         switch( X_Node_getType( v ) ){\r
442                 case X_Node_TYPE.RAW_HTML :\r
443                 case X_Node_TYPE.RAW_TEXT :\r
444                         v = new Node( v );\r
445                         break;\r
446                 case X_Node_TYPE.HTML_STRING :\r
447                 case X_Node_TYPE.STRING :\r
448                         return this.append.apply( this, X_HtmlParser_parse( v, true ) );\r
449                 case X_Node_TYPE.XNODE :\r
450                         // 親の xnodes から v を消す\r
451                         if( v.parent ){\r
452                                 v.remove();\r
453                         };\r
454                         break;\r
455                 default :\r
456                         return this;\r
457         };\r
458 \r
459         v.parent = this;\r
460         xnodes[ xnodes.length ] = v;\r
461         if( this._flags & X_Node_State.IN_TREE ){\r
462                 v._flags |= X_Node_State.IN_TREE;\r
463                 v._xnodes && X_Node_toggleInTreeFlag( v._xnodes, true );\r
464                 X_Node_reserveUpdate();\r
465         };\r
466         return this;\r
467 };\r
468 \r
469 \r
470 function X_Node_appendAt( start, v ){\r
471         var xnodes, l, i;\r
472         \r
473         if( !this._tag ) return this;\r
474         \r
475         l = arguments.length;\r
476         if( !( xnodes = this._xnodes ) ) xnodes = this._xnodes = [];\r
477         \r
478         if( xnodes.length <= start ){\r
479                 if( l === 2 ) return this.append( v );\r
480                 for( i = 1; i < l; ++i ){\r
481                         this.append( arguments[ i ] );\r
482                 };\r
483                 return this;\r
484         };\r
485         if( start < 0 ) start = 0;\r
486         if( 2 < l ){\r
487                 for( ; l; ){\r
488                         this.appendAt( start, arguments[ --l ] );\r
489                 };\r
490                 return this;\r
491         };\r
492 \r
493         switch( X_Node_getType( v ) ){\r
494                 case X_Node_TYPE.RAW_HTML :\r
495                 case X_Node_TYPE.RAW_TEXT :\r
496                         v = new Node( v );\r
497                         break;\r
498                 case X_Node_TYPE.HTML_STRING :\r
499                 case X_Node_TYPE.STRING :\r
500                         v = X_HtmlParser_parse( v, true );\r
501                         for( i = v.length; i; ){\r
502                                 this.appendAt( start, v[ --i ] );\r
503                         };\r
504                         return this;\r
505                 case X_Node_TYPE.XNODE :\r
506                         // 親の xnodes から v を消す\r
507                         if( v.parent ){\r
508                                 v.remove();\r
509                         };\r
510                         break;\r
511                 default :\r
512                         return this;\r
513         };\r
514 \r
515         v.parent = this;\r
516         this._xnodes.splice( start, 0, v );\r
517         if( this._flags & X_Node_State.IN_TREE ){\r
518                 v._flags |= X_Node_State.IN_TREE;\r
519                 v._xnodes && X_Node_toggleInTreeFlag( v._xnodes, true );\r
520                 X_Node_reserveUpdate();\r
521         };\r
522         return this;\r
523 };\r
524 \r
525 function X_Node_appendTo( parent, opt_index ){\r
526         switch( X_Node_getType( parent ) ){\r
527                 case X_Node_TYPE.RAW_HTML :\r
528                         parent = new Node( parent );\r
529                         break;\r
530                 case X_Node_TYPE.HTML_STRING :\r
531                         parent = X_HtmlParser_parse( parent, true );\r
532                         parent = parent[ 0 ] || parent;\r
533                 case X_Node_TYPE.XNODE :\r
534                         break;\r
535                 default :\r
536                         return this;\r
537         };\r
538         opt_index === undefined ? parent.append( this ) : parent.appendAt( opt_index, this );\r
539         return this;\r
540 };\r
541 \r
542 function X_Node_appendToRoot( opt_index ){\r
543         opt_index === undefined ? X_Node_body.append( this ) : X_Node_body.appendAt( opt_index, this );\r
544         return this;\r
545 };\r
546 \r
547 /* --------------------------------------\r
548  *  Before , After, Replace\r
549  */\r
550 function X_Node_before( v ){\r
551         var parent = this.parent, xnodes, i, l, start;\r
552         \r
553         // getter\r
554         if( v === undefined ){\r
555                 if( !parent ) return;\r
556                 xnodes = parent._xnodes;\r
557                 i      = xnodes.indexOf( this );\r
558                 return 0 < i ? xnodes[ i - 1 ] : v;\r
559         };\r
560         \r
561         if( !parent ) return this;\r
562         \r
563         l = arguments.length;\r
564         start = this.getOrder();\r
565         if( 1 < l ){\r
566                 for( ; l; ){\r
567                         parent.appendAt( start, arguments[ --l ] );\r
568                 };\r
569                 return this;\r
570         };\r
571         parent.appendAt( start, v );\r
572         return this;\r
573 };\r
574 \r
575 function X_Node_after( v ){\r
576         var parent = this.parent, xnodes, i, l, start;\r
577         \r
578         // getter\r
579         if( v === undefined ){\r
580                 if( !parent ) return;\r
581                 xnodes = parent._xnodes;\r
582                 i      = xnodes.indexOf( this );\r
583                 return ++i < xnodes.length ? xnodes[ i ] : v;\r
584         };\r
585         \r
586         if( !parent ) return this;\r
587         \r
588         l = arguments.length;\r
589         start = this.getOrder() + 1;\r
590         if( parent._xnodes.length <= start ){\r
591                 if( 1 < l ){\r
592                         for( i = 0; i < l; ++i ){\r
593                                 parent.append( arguments[ i ] );\r
594                         };\r
595                         return this;\r
596                 };\r
597                 parent.append( v );\r
598                 return this;\r
599         };\r
600         if( 1 < l ){\r
601                 for( ; l; ){\r
602                         parent.appendAt( start, arguments[ --l ] );\r
603                 };\r
604                 return this;\r
605         };\r
606         parent.appendAt( start, v );\r
607         return this;\r
608 };\r
609 \r
610 function X_Node_replace( v ){\r
611         if( !this.parent ) return this;\r
612         return arguments.length === 1 ? this.before( v ).remove() : this.before.apply( this, arguments ).remove();\r
613 };\r
614 \r
615 /* --------------------------------------\r
616  *  Remove\r
617  */\r
618 function X_Node_remove(){\r
619         var parent = this.parent;\r
620         \r
621         if( !parent ) return this;\r
622 \r
623         delete this.parent;\r
624         parent._xnodes.splice( parent._xnodes.indexOf( this ), 1 );\r
625         if( this._flags & X_Node_State.IN_TREE ){\r
626                 this._flags ^= X_Node_State.IN_TREE;\r
627                 this._xnodes && X_Node_toggleInTreeFlag( this._xnodes, false );\r
628                 \r
629                 X_Node_reserveRemoval[ X_Node_reserveRemoval.length ] = this;\r
630                 X_Node_reserveUpdate();\r
631         };\r
632         return this;\r
633 };\r
634 \r
635 function X_Node_empty(){\r
636         var xnodes = this._xnodes, i;\r
637         if( xnodes && ( i = xnodes.length ) ){\r
638                 for( ; i; ){\r
639                         xnodes[ --i ].destroy();\r
640                 };\r
641                 xnodes.length = 0;\r
642         };\r
643         return this;\r
644 };\r
645 \r
646 /* --------------------------------------\r
647  *  TODO destory -> kill\r
648  */\r
649 \r
650 function X_Node_destroy( isChild ){\r
651         var xnodes = this._xnodes, i, elm;\r
652         \r
653         if( !this._flags ) return;\r
654         \r
655         elm = this._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this );\r
656         \r
657         if( xnodes && ( i = xnodes.length ) ){\r
658                 //for( ; i; ){\r
659                 //      xnodes[ --i ].destroy( true );\r
660                 //};\r
661         };\r
662         elm && this._listeners && this.unlisten(); // イベントの退避\r
663 \r
664         delete X_Node_CHASHE[ this._uid ];\r
665         delete this._flags;\r
666         \r
667         if( this._flags & X_Node_State.IN_TREE ){\r
668                 !isChild && this.remove();\r
669         } else {\r
670                 this.parent && this.parent._xnodes.splice( this.parent._xnodes.indexOf( this ), 1 );\r
671                 elm && !isChild && X_Node__actualRemove( this );\r
672                 this.kill();\r
673         };\r
674 };\r
675 \r
676 function X_Node_onKill( e ){\r
677         var elm = this._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this );\r
678         \r
679         delete X_Node_CHASHE[ this._uid ];\r
680         delete this._flags;\r
681         \r
682         if( this._flags & X_Node_State.IN_TREE ){\r
683                 this.remove();\r
684         } else {\r
685                 this.parent && this.parent._xnodes.splice( this.parent._xnodes.indexOf( this ), 1 );\r
686                 elm && X_Node__actualRemove( this );\r
687         };\r
688 };\r
689 \r
690 \r
691 /* --------------------------------------\r
692  *  contains\r
693  */\r
694 function X_Node_contains( v ){\r
695         var elm, type, xnodes, i;\r
696         if( !v || !this._tag || this === v ) return false;\r
697         // contains ie4+\r
698         if( ( elm = this._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ) ) && document.contains && ( type = X_Node_getType( v ) ) && ( type === X_Node_TYPE.RAW_HTML || type === X_Node_TYPE.RAW_TEXT ) ){\r
699                 return elm.contains( v );       \r
700         };\r
701         //if( document.compareDocumentPosition ){\r
702         //      \r
703         //};\r
704         xnodes = this._xnodes;\r
705         if( !xnodes || !xnodes.length ) return false;\r
706         if( xnodes.indexOf( v ) !== -1 ) return true; // fast\r
707         if( elm === v.parentNode ) return true;\r
708         for( i = xnodes.length; i; ){\r
709                 if( xnodes[ --i ].contains( v ) ) return true;\r
710         };\r
711         return false;\r
712 };\r
713 \r
714 /* --------------------------------------\r
715  *  getChild\r
716  */\r
717 function X_Node_getChildAt( i ){\r
718         var xnodes = this._xnodes;\r
719         return xnodes && 0 <= i && i < xnodes.length && xnodes[ i ];\r
720 };\r
721 \r
722 function X_Node_length(){\r
723         var xnodes = this._xnodes;\r
724         return xnodes ? xnodes.length : 0;\r
725 };\r
726 \r
727 /* --------------------------------------\r
728  *  firstChild, lastChild\r
729  */\r
730 function X_Node_firstChild(){\r
731         return this.getChildAt( 0 );\r
732 };\r
733 function X_Node_lastChild(){\r
734         return this.getChildAt( this._xnodes.length - 1 );\r
735 };\r
736 \r
737 /* --------------------------------------\r
738  *  getOrder\r
739  */\r
740 function X_Node_getOrder(){\r
741         var parent = this.parent;\r
742         if( !parent ) return -1;\r
743         return parent._xnodes.indexOf( this );\r
744 };\r
745 \r
746 /* --------------------------------------\r
747  *  className, addClass, removeClass, hasClass\r
748  */\r
749 function X_Node_className( v ){\r
750         var node, _, __;\r
751         // getter\r
752         if( v === undefined ) return this._className;\r
753         \r
754         // setter\r
755         if( this._className === v ) return this;\r
756         if( !v || typeof v !== 'string' ){\r
757                 delete this._className;\r
758         } else {\r
759                 // cleanup\r
760                 _  = ' ';\r
761                 __ = '  ';\r
762                 while( v.indexOf( __ ) !== -1 ){ v = v.split( __ ).join( _ ); };\r
763                 v.charAt( 0 ) === _ && ( v = v.substr( 1 ) );\r
764                 v.lastIndexOf( _ ) === 0 && ( v = v.substr( 0, v.length - 1 ) );\r
765                 \r
766                 if( this._className === v ) return this;\r
767                 v ? ( this._className = v ) : delete this._className;\r
768         };\r
769         this._flags |= X_Node_State.DIRTY_CLASSNAME;\r
770         this._flags & X_Node_State.IN_TREE && X_Node_reserveUpdate();\r
771         return this;\r
772 };\r
773 function X_Node_addClass( v ){\r
774         var names = v.split( ' ' ),\r
775                 i     = names.length,\r
776                 name;\r
777         v = '';\r
778         for( ; i; ){\r
779                 name = names[ --i ];\r
780                 if( !name ) continue;\r
781                 !this.hasClass( name ) && ( v += ( v ? ' ' : '' ) + name );\r
782         };\r
783         return v ? this.className( this._className + ( this._className ? ' ' : '' ) + v ) : this;\r
784 };\r
785 function X_Node_removeClass( v ){\r
786         var _          = ' ',\r
787                 className  = this._className,\r
788                 names      = v.split( _ ),\r
789                 classNames, i, f, j;\r
790         if( !className ) return this;\r
791         for( classNames = className.split( _ ), i = classNames.length; i; ){\r
792                 className = classNames[ --i ];\r
793                 for( j = names.length; j; ){\r
794                         if( className === names[ --j ] ){\r
795                                 classNames.splice( i, 1 );\r
796                                 names.splice( j, 1 );\r
797                                 f = true;\r
798                                 break;\r
799                         };\r
800                 };\r
801         };\r
802         return f ? this.className( classNames.join( _ ) ) : this;\r
803 };\r
804 function X_Node_toggleClass( v, opt_toggle ){\r
805         var names, i, name;\r
806         if( opt_toggle !== undefined ){\r
807                 return !!opt_toggle ? this.addClass( v ) : this.removeClass( v );       \r
808         };\r
809         names = v.split( ' ' );\r
810         for( i = names.length; i; ){\r
811                 name = names[ --i ];\r
812                 this.hasClass( name ) ? this.removeClass( name ) : this.addClass( name );\r
813         };\r
814         return this;\r
815 };\r
816 function X_Node_hasClass( v ){\r
817         var _ = ' ',\r
818                 className = this._className,\r
819                 i, name;\r
820         if( className === v ) return true;\r
821         if( !className ) return false;\r
822         \r
823         className = _ + className + _;\r
824         if( className.indexOf( _ + v + _ ) !== -1 ) return true; // lucky hit\r
825         \r
826         for( v = v.split( _ ), i = v.length; i; ){\r
827                 name = v[ --i ];\r
828                 if( name === '' ) continue;\r
829                 if( className.indexOf( _ + name + _ ) === -1 ) return false;\r
830         };\r
831         return true;\r
832 };\r
833 \r
834 /* --------------------------------------\r
835  *  html, text\r
836  * \r
837  * outerHTML が欲しい場合は、xnode.attr('outerHTML') とできる。\r
838  */\r
839 function X_Node_html( html ){\r
840         var _ = '', q = '"', xnodes, n, i, l;\r
841         // setter\r
842         if( html !== undefined ){ // String 以外に Number や false null なども許可\r
843                 if( !this._tag ) return this.text( html );\r
844                 return html ? this.empty().append.apply( this, X_HtmlParser_parse( html, true ) ) : this.empty();\r
845         };\r
846         \r
847         // getter\r
848         if( !this._tag ){\r
849                 return this._text;\r
850         };\r
851         \r
852         this._flags & X_Node_State.OLD_CSSTEXT && X_Node_CSS_objToCssText( this );\r
853 \r
854         html = !X_Node_outerXNode ? [] : [\r
855                 '<', this._tag,\r
856                 this._id ? ' id="' + this._id + q : _,\r
857                 this._className ? ' class="' + this._className + q : _,\r
858                 this._flags & X_Node_State.OLD_ATTRTEXT ? X_Node_Attr_objToAttrText( this ) : this._attrText,\r
859                 this._cssText ? ' style="' + this._cssText + q : _,\r
860         '>' ];\r
861         \r
862         n = html.length;\r
863         if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){\r
864                 if( !X_Node_outerXNode ) X_Node_outerXNode = this;\r
865                 for( i = 0; i < l; ++i ){\r
866                         html[ n ] = xnodes[ i ].html();\r
867                         ++n;\r
868                 };\r
869                 if( X_Node_outerXNode === this ) X_Node_outerXNode = null;\r
870         };\r
871         !X_Node_outerXNode || X_Dom_DTD_EMPTY[ this._tag ] || ( html[ n ] = '<\/' + this._tag + '>' );\r
872         return html.join( _ );\r
873 };\r
874 \r
875 /*\r
876  * null が来たら '', 数値等が来たら文字烈化\r
877  */\r
878 function X_Node_text( text ){\r
879         var xnodes, texts, i, l;\r
880         // setter\r
881         if( text !== undefined ){\r
882                 if( text === null ) text = '';\r
883                 text += '';\r
884                 \r
885                 if( !this._tag ){\r
886                         if( this._text !== text ){\r
887                                 text ? ( this._text = text ) : delete this.text;\r
888                                 this._flags |= X_Node_State.DIRTY_CONTENT;                              \r
889                                 this._flags & X_Node_State.IN_TREE && X_Node_reserveUpdate();\r
890                         };\r
891                         return this;\r
892                 };\r
893                 if( !text ) return this.empty();\r
894                 if( ( xnodes = this._xnodes ) && xnodes.length === 1 && !xnodes[ 0 ]._tag ){\r
895                         xnodes[ 0 ].text( text );\r
896                         return this;\r
897                 };\r
898                 this.empty().createText( text );\r
899                 return this;\r
900         };\r
901         // getter\r
902         if( this._tag ){\r
903                 if( ( xnodes = this._xnodes ) && ( l = xnodes.length ) ){\r
904                         for( texts = [], i = 0; i < l; ++i ){\r
905                                 texts[ i ] = xnodes[ i ].text();\r
906                         };\r
907                         return texts.join( '' );\r
908                 };\r
909                 return '';\r
910         };\r
911         return this._text;\r
912 };\r
913 \r
914 /*\r
915  * HTML要素に対して name の関数を実行しその戻り値を返す。関数に渡す引数も任意に設定できる。\r
916  */\r
917 function X_Node_call( name /*, opt_args... */ ){\r
918         var l = arguments.length - 1,\r
919                 raw, func, args, params, i;\r
920                 \r
921         X_Node_updateTimerID && X_Node_startUpdate();\r
922         \r
923         switch( name ){\r
924                 case 'nodeType' :\r
925                         return this._tag ? 1 : 3;\r
926                 case 'text' :\r
927                         return this.text();\r
928                 case 'html' :\r
929                 case 'innerHTML' :\r
930                         return this.html();\r
931                 case 'outerHTML' :\r
932                         X_Node_outerXNode = this;\r
933                         v = this.html();\r
934                         X_Node_outerXNode = null;\r
935                         return v;\r
936         };\r
937         \r
938         raw  = this._rawObject || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this );\r
939         if( !raw ) return;\r
940         \r
941         func = raw[ name ];\r
942         if( X.Type.isFunction( func ) ){\r
943                 if( l ){\r
944                         args = X_Object_cloneArray( arguments );\r
945                         args.shift();\r
946                         return func.apply( raw, args );\r
947                 };\r
948                 return raw[ name ]();           \r
949         } else\r
950         if( X.Type.isUnknown( func ) ){\r
951                 // typeof func === unknown に対策\r
952                 // http://la.ma.la/blog/diary_200509031529.htm          \r
953                 if( l ){\r
954                         args = X_Object_cloneArray( arguments );\r
955                         args.shift();\r
956                         \r
957                 params = [];\r
958                 for( i = 0; i < l; ++i ){\r
959                         params[ i ] = '_' + i;\r
960                 };\r
961                 params = params.join( ',' );\r
962                 return Function(\r
963                         params,\r
964                     [ 'return this.', name, '(', params, ')' ].join( '' )\r
965                 ).apply( raw, args );\r
966                 };\r
967                 return raw[ name ]();\r
968         };\r
969 };\r
970 \r
971 /*\r
972  * xnode を this として関数を実行する。 NodeList.each と動作を合わせてあるため関数の戻り値は破棄される。\r
973  * 関数に渡す引数も任意に設定できる。\r
974  */\r
975 function X_Node_each( func /*, opt_args */ ){\r
976         var args;\r
977         if( 1 < arguments.length ){\r
978                 args = X_Object_cloneArray( arguments );\r
979                 args[ 0 ] = 0;          \r
980                 func.apply( this, args );\r
981         } else {\r
982                 func.call( this, 0 );\r
983         };\r
984         return this;\r
985 };\r
986 \r
987 \r
988 /* --------------------------------------\r
989  *  Async commit update\r
990  * \r
991  * TODO Timer や DOM イベントの呼び出しの最後に、まだ一度も commitUpdate していないなら commitUpdate してしまう。\r
992  */\r
993         \r
994 function X_Node_reserveUpdate(){\r
995         if( !X_Node_updateTimerID ) X_Node_updateTimerID = X.Timer.requestFrame( X_Node_startUpdate );\r
996 };\r
997 \r
998 function X_Node_startUpdate( time ){\r
999         var removal, i, xnode;\r
1000         \r
1001         if( !X_Node_updateTimerID || X_ViewPort_readyState < X_TEMP.SYSTEM_EVENT_INIT ){\r
1002                 return;\r
1003         };\r
1004 \r
1005         X.Timer.cancelFrame( X_Node_updateTimerID );\r
1006         X_Node_updateTimerID = 0;\r
1007 \r
1008         if( time ){\r
1009                 // X.Timer 経由でないと発火しない このイベントでサイズを取ると無限ループに\r
1010                 X_System._listeners && X_System._listeners[ X.Event.BEFORE_UPDATE ] && X_System.dispatch( X.Event.BEFORE_UPDATE );\r
1011         };\r
1012 \r
1013         removal = X_Node_reserveRemoval;\r
1014 \r
1015         if( i = removal.length ){\r
1016                 for( ; i; ){\r
1017                         xnode = removal[ --i ];\r
1018                         X_Node__actualRemove( xnode );\r
1019                         !X_Node_body._flags && xnode.kill();\r
1020                 };\r
1021                 removal.length = 0;\r
1022         };\r
1023         \r
1024         if( X_Node_html._flags & X_Node_BitMask_IS_DIRTY ){\r
1025                 X_Node__commitUpdate( X_Node_html );\r
1026         } else {\r
1027                 X_Node__commitUpdate( X_Node_head );\r
1028                 X_Node__commitUpdate( X_Node_body );\r
1029         };\r
1030         \r
1031         if( time ){\r
1032                 // X.Timer 経由でないと発火しない このイベントでサイズを取ると無限ループに\r
1033                 X_System._listeners && X_System._listeners[ X.Event.UPDATED ] && X_System.dispatch( X.Event.UPDATED );  \r
1034         };\r
1035         \r
1036         X_ViewPort._listeners && X_ViewPort._listeners[ X.Event.AFTER_UPDATE ] && X_ViewPort.asyncDispatch( X.Event.AFTER_UPDATE );\r
1037 };\r
1038 \r
1039 var X_Node__commitUpdate =\r
1040         X_UA_DOM.W3C ?\r
1041                 ( function( that, parentElement, nextElement ){\r
1042                         var elm = that._rawObject,\r
1043                                 xnodes, l, i, frg, next, k, v;\r
1044 \r
1045                         if( X_Node_displayNoneFixForIE5 && that._flags & X_Node_State.STYLE_IS_DISPLAY_NONE ){\r
1046                                 // filter の効いている要素だけdisplay:none が無視される模様。filter を切ればよい?\r
1047                                 // 親が、display:none の場合は?\r
1048                                 elm && elm.parentNode && X_Node__actualRemove( that );\r
1049                                 return nextElement;\r
1050                         };\r
1051 \r
1052                         if( !elm || ( parentElement && elm.parentNode !== parentElement ) || ( nextElement && elm.nextSibling !== nextElement ) ){\r
1053                                 nextElement ?\r
1054                                         parentElement.insertBefore( X_Node__actualCreate( that ), nextElement ) :\r
1055                                         parentElement.appendChild( X_Node__actualCreate( that ) );\r
1056                                 X_Node__afterActualCreate( that );\r
1057 \r
1058                                 return elm || that._rawObject;\r
1059                         } else\r
1060                         if( ( xnodes = that._xnodes ) && ( l = xnodes.length ) ) {\r
1061                                 for( ; l; ){\r
1062                                         next = X_Node__commitUpdate( xnodes[ --l ], elm, next );\r
1063                                 };\r
1064                         };\r
1065 \r
1066                         delete that._fontSize;\r
1067 \r
1068                         if( that._flags & X_Node_BitMask_IS_DIRTY ){\r
1069                                 X_Node__updateRawNode( that, elm );\r
1070                         } else\r
1071                         if( that._tag && X_Node_displayNoneFixForIE5 && elm.currentStyle.display === 'none' ){\r
1072                                 // TODO 親要素への変更で display:none が変わる場合もあるのでここで調べる\r
1073                         };\r
1074                         \r
1075                         if( X_Node_displayNoneFixForIE5 && that._flags & X_Node_State.STYLE_IS_DISPLAY_NONE ){\r
1076                                 return nextElement;\r
1077                         };\r
1078                         return elm;\r
1079                 }) :\r
1080         X_UA_DOM.IE4 ? \r
1081                 ( function( that, parentElement, prevElement ){\r
1082                         var elm    = that._rawObject || X_Node__ie4getRawNode( that ),\r
1083                                 xnodes, l, i, html, text, prev;\r
1084 \r
1085                         if( !elm ){\r
1086                                 prevElement ?\r
1087                                         prevElement.insertAdjacentHTML( 'AfterEnd', X_Node__actualCreate( that ) ) :\r
1088                                         parentElement.insertAdjacentHTML( 'AfterBegin', X_Node__actualCreate( that ) );\r
1089                                 X_Node__afterActualCreate( that );\r
1090                                 return that._rawObject || X_Node__ie4getRawNode( that );\r
1091                         };\r
1092                         \r
1093                         xnodes = that._xnodes;\r
1094                         l      = xnodes ? xnodes.length : 0;\r
1095                         \r
1096                         if( ( that._flags & X_Node_State.IE4_ONLY_TEXT && ( l !== 1 || xnodes[ 0 ]._tag ) ) || that._flags & X_Node_State.IE4_TEXTNODE_FIX ){\r
1097                                 html = [];\r
1098                                 for( i = 0; i < l; ++i ){\r
1099                                         html[ i ] = X_Node__actualCreate( xnodes[ i ] );\r
1100                                 };\r
1101                                 elm.innerHTML = html.join( '' );\r
1102                                 for( i = 0; i < l; ++i ){\r
1103                                         X_Node__afterActualCreate( xnodes[ i ] );\r
1104                                 };\r
1105                                 that._flags &= ~X_Node_State.IE4_TEXTNODE_FIX;\r
1106                                 that._flags &= ~X_Node_State.IE4_ONLY_TEXT;\r
1107                         } else\r
1108                         // TODO textNode だけが 2つ以上ある場合\r
1109                         if( that._flags & X_Node_State.IE4_ONLY_TEXT ){\r
1110                                 text = xnodes[ 0 ];\r
1111                                 if( text._flags & X_Node_State.DIRTY_CONTENT || ( text._flags & X_Node_State.IE4_TEXTNODE_EXIST ) === 0 ){\r
1112                                         elm.innerHTML = text._text;\r
1113                                         text._flags  &= X_Node_BitMask_RESET_DIRTY;\r
1114                                         /* if( taht._flags & X_Node_State.IN_TREE ) */ text._flags |= X_Node_State.IE4_TEXTNODE_EXIST;\r
1115                                 };\r
1116                         } else\r
1117                         if( l ){\r
1118                                 for( i = 0; i < l; ++i ){\r
1119                                         prev = X_Node__commitUpdate( xnodes[ i ], elm, prev );\r
1120                                 };\r
1121                         };\r
1122                         \r
1123                         delete that._fontSize;\r
1124                         that._flags & X_Node_BitMask_IS_DIRTY && X_Node__updateRawNode( that, elm );\r
1125                         return elm;\r
1126                 }) :\r
1127                 (function(){});\r
1128 \r
1129 /*\r
1130  * TODO IE5 は filter-fix があるため、親から変更を適用し、自信の display:none を調べる\r
1131  * GPU レイヤーするブラウザは、子要素から変更を当てていく?\r
1132  */\r
1133 var X_Node__updateRawNode =\r
1134         X_UA_DOM.W3C ?\r
1135                 ( function( that, elm ){\r
1136                         var attrs, rename, k, v;\r
1137 \r
1138                         // textNode\r
1139                         if( !that._tag ){\r
1140                                 elm.data = X_String_chrReferanceTo( that._text );\r
1141                                 that._flags &= X_Node_BitMask_RESET_DIRTY;\r
1142                                 return;\r
1143                         };\r
1144                         // id\r
1145                         if( that._flags & X_Node_State.DIRTY_ID ){\r
1146                                 that._id ? ( elm.id = that._id ) : ( elm.id && elm.removeAttribute( 'id' ) );           \r
1147                         };\r
1148                         // className\r
1149                         if( that._flags & X_Node_State.DIRTY_CLASSNAME ){\r
1150                                 that._className ? ( elm.className = that._className ) : ( elm.className && elm.removeAttribute( X_UA.IE5678 ? 'className' : 'class' ) ); // className は ie7-?                         \r
1151                         };\r
1152                         \r
1153                         // ie5 only\r
1154                         // TODO 親へのクラス・id指定で display : none になるケースもある\r
1155                         if( X_Node_displayNoneFixForIE5 && elm.currentStyle.display === 'none' ){\r
1156                                 X_Node__actualRemove( that );\r
1157                                 that._flags |= X_Node_State.STYLE_IS_DISPLAY_NONE;\r
1158                                 return;\r
1159                         };                      \r
1160                         \r
1161                         if( that._flags & X_Node_State.DIRTY_IE_FILTER ){\r
1162                                 elm.style.filter = X_Node_CSS_objToIEFilterText( that );;\r
1163                         };\r
1164                         \r
1165                         // attr\r
1166                         // TODO display:none の場合、更新をスキップ\r
1167                         if( that._flags & X_Node_State.DIRTY_ATTR && ( attrs = that._newAttrs || that._attrs ) ){\r
1168                                 rename = X_Node_Attr_renameForDOM;\r
1169                                 \r
1170                                 // IETester 5.5 ではエラーが出なかった.MultipulIE5.5 ではエラーが出たので\r
1171                                 if( !X_UA.MacIE && X_UA.IE5x && that._tag === 'TEXTAREA' && ( ( v = attrs[ 'value' ] ) || X_Object_inObject( 'value', attrs ) ) ){\r
1172                                         delete attrs[ 'value' ];\r
1173                                         elm.firstChild ?\r
1174                                                 ( elm.firstChild.data = v || '' ) :\r
1175                                                 elm.appendChild( document.createTextNode( v || '' ) );\r
1176                                 };\r
1177                                 // http://outcloud.blogspot.jp/2010/09/iframe.html\r
1178                                 // この問題は firefox3.6 で確認\r
1179                                 if( X_UA.Gecko && that._tag === 'IFRAME' && ( ( v = attrs[ 'src' ] ) || X_Object_inObject( 'src', attrs ) ) ){\r
1180                                         elm.contentWindow.location.replace = elm.src = v || '';\r
1181                                         delete attrs[ 'src' ];\r
1182                                 };\r
1183                                                 \r
1184                                 for( k in attrs ){\r
1185                                         //if( X_EMPTY_OBJECT[ k ] ) continue;\r
1186                                         // TODO IE では input, なぜか button, object も type の変更が出来ない、同値で置き換えようとしても不可\r
1187                                         ( v = attrs[ k ] ) === undefined ?\r
1188                                                 elm.removeAttribute( rename[ k ] || k ) :\r
1189                                                 ( elm[ rename[ k ] || k ] = X_Node_Attr_noValue[ k ] ? k : v );\r
1190                                 };\r
1191                                 delete that._newAttrs;\r
1192                         };\r
1193                         \r
1194                         // style\r
1195                         // TODO display:none の場合、更新をスキップ\r
1196                         if( that._flags & X_Node_State.DIRTY_CSS ){\r
1197                                 if( that._flags & X_Node_State.OLD_CSSTEXT ? X_Node_CSS_objToCssText( that ) : that._cssText ){\r
1198                                         X_UA.Opera78 || X_UA.NN6 ?\r
1199                                                 elm.setAttribute( 'style', that._cssText ) : // opera8用\r
1200                                                 ( elm.style.cssText = that._cssText );\r
1201                                 } else {\r
1202                                         elm.style.cssText = ''; // IE5.5以下 Safari3.2 で必要\r
1203                                         elm.removeAttribute( 'style' );\r
1204                                         delete that._cssText;\r
1205                                 };\r
1206                         };\r
1207                         \r
1208                         that._flags &= X_Node_BitMask_RESET_DIRTY;\r
1209                 }) :\r
1210         X_UA_DOM.IE4 ? \r
1211                 ( function( that, elm ){\r
1212                         var attrs, rename, k, v;\r
1213 \r
1214                         // fake textNode\r
1215                         if( !that._tag ){\r
1216                                 elm.innerText = that._text;\r
1217                                 that._flags &= X_Node_BitMask_RESET_DIRTY;\r
1218                                 return;\r
1219                         };\r
1220                         \r
1221                 /*\r
1222                  * http://www.tohoho-web.com/js/element.htm\r
1223                  * title、className、id、lang、language には setAttribute でなく、element.id で直接読み書きできる\r
1224                  */     \r
1225                         // id\r
1226                         if( that._flags & X_Node_State.DIRTY_ID ) elm.setAttribute( 'id', that._id || ( 'ie4uid' + xnode._uid ) );\r
1227 \r
1228                         // className\r
1229                         if( that._flags & X_Node_State.DIRTY_CLASSNAME ){\r
1230                                 that._className ? ( elm.className = that._className ) : elm.removeAttribute( 'class' );\r
1231                         };\r
1232                         // style\r
1233                         if( that._flags & X_Node_State.DIRTY_CSS ){\r
1234                                 if( that._flags & X_Node_State.OLD_CSSTEXT ? X_Node_CSS_objToCssText( that ) : that._cssText ){\r
1235                                         elm.style.cssText = that._cssText;\r
1236                                 } else {\r
1237                                         elm.style.cssText = '';\r
1238                                         elm.removeAttribute( 'style' );\r
1239                                         delete that._cssText;\r
1240                                 };\r
1241                         };\r
1242                         \r
1243                         if( that._flags & X_Node_State.DIRTY_IE_FILTER ){\r
1244                                 that._rawObject.style.filter = X_Node_CSS_objToIEFilterText( that );;\r
1245                         };\r
1246                         \r
1247                         // attr\r
1248                         if( that._flags & X_Node_State.DIRTY_ATTR && ( attrs = that._newAttrs || that._attrs ) ){\r
1249                                 rename = X_Node_Attr_renameForDOM;\r
1250                                 for( k in attrs ){\r
1251                                         //if( X_EMPTY_OBJECT[ k ] ) continue;\r
1252                                         ( v = attrs[ k ] ) === undefined ?\r
1253                                                 elm.removeAttribute( rename[ k ] || k ) :\r
1254                                                 elm.setAttribute( rename[ k ] || k, X_Node_Attr_noValue[ k ] ? k : v );\r
1255                                 };\r
1256                                 delete that._newAttrs;\r
1257                         };\r
1258 \r
1259                         that._flags &= X_Node_BitMask_RESET_DIRTY;\r
1260                 }) :\r
1261                 (function(){});\r
1262 \r
1263 /* --------------------------------------\r
1264  *  Create\r
1265  * \r
1266  * http://d.hatena.ne.jp/uupaa/20080718/1216362040\r
1267  * DOM Rangeが使える環境(Firefox2+,Opera9+,Safari3+)なら、innerHTMLいらずで、ガーって書けます。\r
1268  * return document.createRange().createContextualFragment("<div><select><option></option></select></div>");\r
1269  * insertAdjacentHTML\r
1270  * \r
1271  * ie7 以下では iframe の frameborder や、input name は、createElement 後に setAttribute しても無視される\r
1272  * \r
1273  * fragument がある場合 children も足して\r
1274  * Mozilla: 1.0+, IE: 5.5+, Netscape: 2.0+, Safari: 1.0+, Opera: 7.0+\r
1275  * ie6 大丈夫?fragment の場合リークしないか?チェックが必要\r
1276  * http://msdn.microsoft.com/ja-jp/library/bb250448%28v=vs.85%29.aspx\r
1277  * \r
1278  * document.createElement of ie4 is only for OPTION & IMAGE.\r
1279  */\r
1280 var X_Node__actualCreate =\r
1281         X_UA_DOM.W3C ? (function( that, isChild ){\r
1282                 var elm = that._rawObject,\r
1283                         xnodes, frg, i, l;\r
1284                 \r
1285                 if( !that._tag ){\r
1286                         if( elm ) return elm;\r
1287                         that._flags &= X_Node_BitMask_RESET_DIRTY;\r
1288                         return that._rawObject = document.createTextNode( X_String_chrReferanceTo( that._text ) );\r
1289                 };\r
1290                 \r
1291                 if( !elm ){\r
1292                         that._flags & X_Node_State.DIRTY_CSS && X_Node_CSS_objToCssText( that );\r
1293 \r
1294                         that._flags |= X_Node_State.ELM_NEED_INIT;\r
1295                         that._rawObject = elm =\r
1296                                 X_Node_strictElmCreation ?\r
1297                                         document.createElement( [\r
1298                                                 '<', that._tag,\r
1299                                                         ' UID="', that._uid, '"',\r
1300                                                         that._id ? ' id="' + that._id + '"' : '',\r
1301                                                         that._className ? ' class="' + that._className + '"' : '',\r
1302                                                         that._flags & X_Node_State.OLD_ATTRTEXT ? X_Node_Attr_objToAttrText( that ) : that._attrText,\r
1303                                                         that._cssText ? ' style="' + that._cssText + '"' : '',\r
1304                                                 '>' ].join( '' ) ) :\r
1305                                         document.createElement( that._tag );\r
1306                                 \r
1307                                         \r
1308         console.log( '##' + that._attrText + '##' );\r
1309                 };\r
1310                 if( X_Node_useDocumentFragment ){\r
1311                         if( ( xnodes = that._xnodes ) && ( l = xnodes.length ) ){\r
1312                                 !isChild && ( frg = X_Node_useDocumentFragment ).appendChild( elm );\r
1313                                 for( i = 0; i < l; ++i ){\r
1314                                         elm.appendChild( X_Node__actualCreate( xnodes[ i ], true ) );\r
1315                                 };\r
1316                                 return frg || elm;\r
1317                         };\r
1318                 };\r
1319                 \r
1320                 return elm;\r
1321         }) :\r
1322         X_UA_DOM.IE4 ? (function( that, isChild ){\r
1323                 var uid = that._uid,\r
1324                         html, xnodes, n, i, l;\r
1325                 \r
1326                 if( !that._tag ){\r
1327                         html = [ '<FONT id=ie4uid', uid, ' UID="', uid, '">', that._text, '</FONT>' ];// fake textNode\r
1328                         delete that._rawObject;\r
1329                 } else {\r
1330                         if( that._rawObject && !isChild ) X_Node__actualRemove( that, true );\r
1331                         \r
1332                         that._flags & X_Node_State.DIRTY_CSS && X_Node_CSS_objToCssText( that );\r
1333                         \r
1334                         html = [\r
1335                                 '<', that._tag, ' id=', ( that._id || ( 'ie4uid' + uid ) ), ' UID="', uid, '"',\r
1336                                 that._className ? ' class="' + that._className + '"' : '',\r
1337                                 that._flags & X_Node_State.OLD_ATTRTEXT ? X_Node_Attr_objToAttrText( that ) : that._attrText,\r
1338                                 that._cssText ? ' style="' + that._cssText + '"' : '',\r
1339                         '>' ];\r
1340                         \r
1341                         n = html.length;\r
1342                         if( ( xnodes = that._xnodes ) && ( l = xnodes.length ) ){\r
1343                                 if( l === 1 && !xnodes[ 0 ]._tag ){\r
1344                                         // only textnode\r
1345                                         html[ n ] = xnodes[ 0 ]._text;\r
1346                                         ++n;\r
1347                                         that._flags |= X_Node_State.IE4_ONLY_TEXT;\r
1348                                 } else {\r
1349                                         for( i = 0; i < l; ++i ){\r
1350                                                 html[ n ] = X_Node__actualCreate( xnodes[ i ], true );\r
1351                                                 ++n;\r
1352                                         };                                      \r
1353                                 };\r
1354                         };\r
1355                         X_Dom_DTD_EMPTY[ that._tag ] || ( html[ n ] = '<\/' + that._tag + '>' );\r
1356                         \r
1357                         delete that._newAttrs;\r
1358                 };\r
1359                 \r
1360                 return html.join( '' );\r
1361         }) :\r
1362         (function(){});\r
1363 \r
1364 var X_Node__afterActualCreate =\r
1365         X_UA_DOM.W3C ? (function( that ){\r
1366                 var elm = that._rawObject, xnodes, l, i;\r
1367                 \r
1368                 if( !that._tag ){\r
1369                         that._flags & X_Node_BitMask_IS_DIRTY && X_Node__updateRawNode( that, elm );\r
1370                         return that;\r
1371                 };\r
1372                         \r
1373                 xnodes = that._xnodes;\r
1374                 l      = xnodes && xnodes.length;\r
1375                 \r
1376                 if( that._flags & X_Node_State.ELM_NEED_INIT ){\r
1377                         if( !X_Node_useDocumentFragment ){// docFrg が使えない場合、doc 追加後に子を追加\r
1378                                 for( i = 0; i < l; ++i ){\r
1379                                         elm.appendChild( X_Node__actualCreate( xnodes[ i ], true ) );\r
1380                                         X_Node__afterActualCreate( xnodes[ i ] );\r
1381                                 };\r
1382                         } else {\r
1383                                 for( i = 0; i < l; ++i ){\r
1384                                         X_Node__afterActualCreate( xnodes[ i ] );\r
1385                                 };\r
1386                         };\r
1387                         \r
1388                         if( X_Node_strictElmCreation ){\r
1389                                 if( that._flags & X_Node_State.DIRTY_IE_FILTER ){\r
1390                                         elm.style.filter = X_Node_CSS_objToIEFilterText( that );;\r
1391                                 };\r
1392                                 that._flags &= X_Node_BitMask_RESET_DIRTY;\r
1393                         } else {\r
1394                                 elm.UID = that._uid;\r
1395                                 that._newAttrs = that._attrs;\r
1396                                 that._flags |= X_Node_State.DIRTY_ID | X_Node_State.DIRTY_CLASSNAME | X_Node_State.DIRTY_ATTR | X_Node_State.DIRTY_CSS | X_Node_State.DIRTY_IE_FILTER;\r
1397                                 X_Node__updateRawNode( that, elm );\r
1398                                 \r
1399                                 // http://outcloud.blogspot.jp/2010/09/iframe.html\r
1400                                 // この問題は firefox3.6 で確認\r
1401                                 if( X_UA.Gecko && that._tag === 'IFRAME' ){\r
1402                                         if( !that._attrs[ 'src' ] ){\r
1403                                                 elm.contentWindow.location.replace = elm.src = 'about:blank'; \r
1404                                         };\r
1405                                 };\r
1406                         };\r
1407                         \r
1408                         that._flags ^= X_Node_State.ELM_NEED_INIT;\r
1409                 } else {\r
1410                         \r
1411                         for( i = 0; i < l; ++i ){\r
1412                                 X_Node__afterActualCreate( xnodes[ i ] );\r
1413                         };\r
1414                         // 親要素の updateRawNode 前に子要素の updateRawNode を行う\r
1415                         // 親要素が GPU レイヤーに転送されるケースがあるので、先に子要素の変更を済ませる\r
1416                         that._flags & X_Node_BitMask_IS_DIRTY && X_Node__updateRawNode( that, elm );\r
1417                 };      \r
1418 \r
1419                 // src の onload があるので先ではないか?\r
1420                 // TODO ie の str から要素を作る場合、srcだけ イベント設定後ではないか?\r
1421                 X_EventDispatcher_toggleAllEvents( that, true );// イベントの復帰\r
1422         }) :\r
1423         X_UA_DOM.IE4 ? (function( that ){\r
1424                 var xnodes, i;\r
1425                 that._flags |= X_Node_State.IE4_TEXTNODE_EXIST;\r
1426                 \r
1427                 if( !that._tag ) return that;\r
1428                 \r
1429                 if( ( xnodes = that._xnodes ) && ( i = xnodes.length ) ){\r
1430                         for( ; i; ){\r
1431                                 X_Node__afterActualCreate( xnodes[ --i ] );\r
1432                         };\r
1433                 };\r
1434                 if( that._flags & X_Node_State.DIRTY_IE_FILTER ){\r
1435                         X_Node__ie4getRawNode( that ).style.filter = X_Node_CSS_objToIEFilterText( that );;\r
1436                 };\r
1437                 that._flags &= X_Node_BitMask_RESET_DIRTY;\r
1438                 X_EventDispatcher_toggleAllEvents( that, true );// イベントの復帰\r
1439         }) :\r
1440         (function(){});\r
1441 \r
1442 var X_Node__actualRemove =\r
1443         X_UA_DOM.W3C ?\r
1444                 // GPUレイヤーにいるうちは remove しない。-> GPU解除してから remove する\r
1445                 // Firefox34 では遭遇せず、Safari で何度かアニメーションしているうちに発生\r
1446                 ( function( that, isChild ){\r
1447                         var xnodes = that._xnodes,\r
1448                                 elm    = that._rawObject,\r
1449                                 child, i, l;\r
1450                         if( xnodes && ( l = xnodes.length ) ){\r
1451                                 for( i = 0; i < l; ++i ){\r
1452                                         child = xnodes[ i ];\r
1453                                         child._tag && X_Node__actualRemove( child, true );\r
1454                                 };\r
1455                         };\r
1456 \r
1457                         if( !elm ) return;\r
1458                         that._listeners && X_EventDispatcher_toggleAllEvents( that, false );// イベントの退避\r
1459                         if( !X_UA.MacIE ){\r
1460                                 // elm.parentNode.tagName for ie7\r
1461                                 !isChild && elm.parentNode && elm.parentNode.tagName && elm.parentNode.removeChild( elm );\r
1462                         } else {\r
1463                                 !isChild && elm.parentNode && elm.parentNode.tagName && X_TEMP._fixed_remove( elm, that );\r
1464                         };\r
1465                 }) :\r
1466         X_UA_DOM.IE4 ?\r
1467                 ( function( that, isChild ){\r
1468                         var xnodes = that._xnodes,\r
1469                                 elm    = that._rawObject || X_Node__ie4getRawNode( that ),\r
1470                                 i, l, xnode;\r
1471                         if( xnodes && ( l = xnodes.length ) ){\r
1472                                 for( i = 0; i < l; ++i ){\r
1473                                         X_Node__actualRemove( xnodes[ i ], true );\r
1474                                 };\r
1475                         };\r
1476 \r
1477                         if( !elm ) return;\r
1478                         that._listeners && X_EventDispatcher_toggleAllEvents( that, false );// イベントの退避\r
1479                         \r
1480                         if( X_Node_Attr_HAS_VALUE[ that._tag ] && ( !that._newAttrs || !X_Object_inObject( 'value', that._newAttrs ) ) ){\r
1481                                 that._attrs.value = elm.value;\r
1482                         };\r
1483                         elm.removeAttribute( 'id' ); // ?\r
1484                         //document.all[ that._id || ( 'ie4uid' + that._uid ) ] = null; // MacIE5 でエラー\r
1485                         if( !isChild ) elm.outerHTML = '';\r
1486                         delete that._rawObject;\r
1487                 }) :\r
1488                 (function(){});\r
1489 \r
1490 X_ViewPort.listenOnce( X.Event.UNLOAD, X_Node__actualRemove, [ X_Node_html, true ] );\r
1491 \r