2 X.Dom._useBuilder = true;
\r
4 X.Dom._isCleanupTarget = function( elm ){
\r
5 var cname = ' ' + elm.className + ' ',
\r
6 tag = ( elm.tagName || '' ).toUpperCase();
\r
7 return cname.indexOf( ' skip-cleanup ' ) === -1 &&
\r
8 ( X.Dom.cleanupTagNames[ tag ] || cname.indexOf( ' cleanup-target ' ) !== -1 );
\r
13 X.Dom._fixed_remove = function( node, xnode ){
\r
14 var parent = node.parentNode, l;
\r
16 node.nodeType !== 3 && alert( node.nodeType + '\n' + ( node.outerHTML || node.data ) );
\r
17 if( node.nodeType === 1 ){
\r
18 //node.outerHTML = '';
\r
19 parent && parent.removeChild( node );
\r
21 if( node.nodeType === 3 ){
\r
23 l = X.Dom._removalTextNodes.length;
\r
25 //!l && X.Timer.once( 0, X.Dom._timer_remove );
\r
26 //X.Dom._removalTextNodes[ l ] = node;
\r
29 // str[str.length] = p;
\r
31 //alert( str.join( ',' ) + parent.innerHTML );
\r
32 //node.nodeValue = '';
\r
33 //parent.replaceChild( document.createElement( 'span' ), node );
\r
35 //var f = document.createDocumentFragment();
\r
36 //f.appendChild( e = document.createElement( 'span' ) );
\r
37 //f.replaceChild( node, e );
\r
38 //e.appendChild( f );
\r
39 //parent.appendChild( e = document.createElement( 'span' ) );
\r
40 //e.appendChild( node );
\r
41 //parent.removeChild( e );
\r
42 //node.parentNode = null;
\r
43 //document.body.appendChild( node );
\r
44 //parent.replaceChild( document.createComment( '' ), node );
\r
45 document.body.appendChild( node );
\r
47 if( parent.parentNode !== document.body ){
\r
48 var clone = parent.cloneNode( true );
\r
49 for( var i = 0, l = parent.childNodes.length; i < l; ++i ){
\r
50 if( parent.childNodes[ i ] !== node ){
\r
51 clone.removeChild( clone.childNodes[ i ] );
\r
54 //parent.parentNode.insertBefore( clone, parent );
\r
55 //parent.parentNode.removeChild( parent );
\r
56 parent.parentNode.insertBefore( clone, parent );
\r
57 parent.style.display = 'none';
\r
59 xnode.parent.parent._rawNode = clone;
\r
66 //if( !node.ownerDocument ) alert( 'no owner' );
\r
72 X.Dom._removalTextNodes = [];
\r
74 X.Dom._timer_remove = function(){
\r
75 var nodes = X.Dom._removalTextNodes,
\r
77 while( i < 5 && nodes.length ){
\r
78 node = nodes.shift();
\r
79 if( node.parentNode ){
\r
80 //node.parentNode.removeChild( node );
\r
85 //nodes.length && X.Timer.once( 1000, X.Dom._timer_remove );
\r
91 X.Dom._fixed_remove = function( node ){
\r
92 if( node.nodeType === 1 || node.nodeType === 3 ){
\r
93 node.parentNode && node.parentNode.removeChild( node );
\r
100 /* --------------------------------------
\r
101 * 通常のwebページに対して使用する場合、dom ready で dom tree を写し取るために使う.
\r
102 * 完全にワンページアプリで<body/>が空な場合、このコードはビルドに含める必要はない
\r
104 * TODO (注4) IE6 の空白に関する“癖”について
\r
105 * http://kojs.sukobuto.com/docs/visible-binding
\r
106 * IE6 には、「空の span エレメントに続く空白は無視される」という謎な癖があります。
\r
108 X.Dom.listenOnce( X.Dom.Event.DOM_PRE_INIT,
\r
113 copy, i, l, node, html,
\r
116 // textarea の内容を控えて、消す。xnode tree 構築後に復帰。でないと、html パースでこける
\r
117 //X.UA.MacIE && alert( body.innerHTML );
\r
119 (function/*cleanUpTree*/( elm, skip, head ){
\r
120 var nodes = X.copyArray( elm.childNodes ),
\r
123 node, tag, textNode, content;
\r
124 for( ; i < l; ++i ){
\r
126 switch( node.nodeType ){
\r
128 tag = node.tagName.toUpperCase();
\r
129 if( X.Dom.moveToHead[ tag ] ){
\r
130 head = head || document.getElementsByTagName( 'head' )[ 0 ];
\r
131 head.appendChild( node );
\r
134 if( X.Dom._isCleanupTarget( node ) ){
\r
135 elm.removeChild( node );
\r
138 // pre タグ以下はスペースの置換は行わない
\r
139 node.childNodes && node.childNodes.length && /*cleanUpTree*/arguments.callee( node, skip || X.Dom.skipCleanupTagNames[ tag ], head );
\r
144 content = skip ? node.data : X.Dom.cleanupWhiteSpace( node.data );
\r
145 //console.log( 'Delete space ' + node.data.length + ' => ' + content.length );
\r
146 if( !textNode && content !== ' ' && content.length ){
\r
147 node.data = content;
\r
152 textNode.data += content; // 直前が TextNode の場合 一本化して削除
\r
154 // ブロック要素直下のスペースだけは削除??
\r
156 //console.log( 'Remove type: ' + node.nodeType + ' value: ' + node.nodeValue );
\r
157 if( !X.UA.Opera7 /*&& !X.UA.MacIE */ ){
\r
158 elm.removeChild( node );
\r
160 X.Dom._fixed_remove( node );
\r
165 })( X.UA.MacIE ? ( copy = body.cloneNode( true ) ) : body );
\r
168 document.write( html = copy.innerHTML );
\r
172 html = body.innerHTML.split( X.Dom.CRLF ).join( '' ); // 不要な改行が入る
\r
174 html = body.innerHTML;
\r
177 // Nokia s60 Safari
\r
178 if( html === 'fastinnerhtml!' ){
\r
180 for( i = 0, l = body.childNodes.length; i < l; ++i ){
\r
181 node = body.childNodes[ i ];
\r
182 html += ( node.outerHTML || node.data );
\r
187 body.appendChild( elmProgress = document.createElement( 'div' ) );
\r
188 elmProgress.style.cssText = 'position:absolute;top:0;left:0;z-index:9999;width:0;height:0.5em;background:#00f;overflow:hidden;';
\r
189 elmProgress.setAttribute( 'style', 'position:absolute;top:0;left:0;z-index:9999;width:0;height:0.5em;background:#00f;overflow:hidden;' );
\r
191 X.Dom.asyncParse( html, true )
\r
192 .listen( X.Event.PROGRESS,
\r
194 elmProgress.style.width = ( e.progress * 100 | 0 ) + '%';
\r
197 .listenOnce( X.Event.SUCCESS, function( e ){
\r
198 var xnodes = Node.root._xnodes = [], t;
\r
199 xnodes.push.apply( xnodes, e.xnodes );
\r
200 elmProgress.style.width = '100%';
\r
202 X.Dom._asyncCreateTree( Node.root, body.childNodes, elmProgress );
\r
210 elmProgress = '_xdom_builder_progress',
\r
214 * http://support.microsoft.com/kb/812417/ja
\r
215 * PRB: outerHTML の HTML 要素のプロパティは、既定の属性は表示されません。
\r
217 * body.innerHTML でなく、 body.outerHTML にはできなかった、、、
\r
219 html = body.innerHTML;
\r
220 body.insertAdjacentHTML( 'BeforeEnd', '<div id="' + elmProgress + '" style="position:absolute;top:0;left:0;z-index:9999;width:0;height:0.5em;background:#00f;overflow:hidden;"></div>' );
\r
221 elmProgress = document.all[ elmProgress ];
\r
223 X.Dom.asyncParse( html, true )
\r
224 .listen( X.Event.PROGRESS,
\r
226 elmProgress.style.width = ( e.progress * 100 | 0 ) + '%';
\r
229 .listenOnce( X.Event.SUCCESS,
\r
231 var xnodes = Node.root._xnodes = [], t;
\r
232 xnodes.push.apply( xnodes, e.xnodes );
\r
233 elmProgress.style.width = '100%';
\r
235 X.Dom._asyncCreateTree( Node.root, body.childNodes || body.children, elmProgress );
\r
243 X.Dom._asyncCreateTree = function ( parent, elems, elmProgress, async ){
\r
244 var xnodes = async ? 0 : X.copyArray( parent._xnodes ),
\r
245 l = async ? 0 : xnodes.length,
\r
246 stack = async ? async.stack : [],
\r
247 done = async ? async.done : 0,
\r
248 startTime = X.getTime(),
\r
249 current = async ? async.current : {
\r
254 elems : X.copyArray( elems ),
\r
260 //alert( 'X.Dom._asyncCreateTree' );
\r
261 while( current || ( current = stack.pop() ) ){
\r
265 parent = current.me;
\r
266 xnodes = current.xnodes;
\r
267 while( xnode = xnodes[ i ] ){
\r
269 dive = X.Dom._bindElementToXnode( parent, xnode, current );
\r
275 stack[ stack.length ] = current;
\r
281 xnodes = dive.xnodes;
\r
285 if( startTime + 16 <= X.getTime() ){
\r
288 async.current = i < l && current;
\r
291 //alert( 'koko?' );
\r
292 X.Timer.once( 0, X.Dom._asyncCreateTree, [ null, null, elmProgress, async || { stack : stack, current : i < l && current, done : done } ] );
\r
294 elmProgress.style.width = ( ( 1 - done / Node._chashe.length ) * 100 | 0 ) + '%';
\r
302 X.Dom.asyncDispatch( 0, { type : X.Dom.Event.DOM_BUILDER_COMPLETE } );
\r
303 elmProgress.parentNode ? elmProgress.parentNode.removeChild( elmProgress ) : ( elmProgress.outerHTML = '' );
\r
304 delete X.Dom._asyncCreateTree;
\r
305 delete X.Dom._bindElementToXnode;
\r
308 X.Dom._bindElementToXnode =
\r
310 (function( parent, xnode, current ){
\r
311 var elems = current.elems,
\r
314 xtext = current.xtext,
\r
315 skipCleanup = current.skipCleanup,
\r
316 inPreTag = current.inPreTag,
\r
319 xnode.parent = parent;
\r
321 for( ; current.j < m; ++current.j ){
\r
322 elm = elems[ current.j ];
\r
323 tag = elm.tagName && elm.tagName.toUpperCase();
\r
324 if( ( elm.nodeType !== 1 && elm.nodeType !== 3 ) || tag === '!' || ( tag && tag.charAt( 0 ) === '/' ) ){
\r
325 if( !X.UA.Opera7 && !X.UA.MacIE ){
\r
326 elm.parentNode.removeChild( elm );
\r
328 X.Dom._fixed_remove( elm );
\r
333 if( xnode._xnodeType === 1 ){
\r
334 if( elm.nodeType === 3 ){
\r
335 if( !( text = elm.data ) || ( text = X.Dom.cleanupWhiteSpace( text ) ) === ' ' ){
\r
336 //alert( text.charCodeAt( 0 ) );
\r
337 if( !X.UA.Opera7 && !X.UA.MacIE ){
\r
338 elm.parentNode.removeChild( elm );
\r
340 X.Dom._fixed_remove( elm );
\r
344 alert( '1:[' +parent._tag + '>' +xnode._tag + '] !== ' + elm.nodeType + '\n' + ( elm.data ) );
\r
346 if( X.Dom.moveToHead[ tag ] ){
\r
350 if( xnode._tag !== tag ){
\r
351 alert( '2:[' +parent._tag + '>' +xnode._tag + ' len:' + (xnode._xnodes ? xnode._xnodes.length : '' ) + '] !== ' + tag + ' ' + (elm.childNodes ? elm.childNodes.length : '' ) + '\n' + elm.outerHTML );
\r
353 xnode._rawNode = elm;
\r
354 //if( ( doc = elm.ownerDocument || elm.document ) && ( doc.createElement( 'p' ).tagName === doc.createElement( 'P' ).tagName ) ){
\r
355 if( tag.charAt( 0 ) === '/' ) tag = tag.slice( 1 );
\r
358 xnode._root = parent._root;
\r
359 elm.UID = xnode._uid;
\r
361 if( tag === 'TEXTAREA' ){
\r
362 xnode.attr( 'value', xnode.html() ).empty();
\r
363 current.xtext = null;
\r
365 if( X.Dom._isCleanupTarget( elm ) ){// !xnode.hasClass( 'skip-cleanup' ) && ( X.Dom.cleanupTagNames[ tag ] || xnode.hasClass( 'cleanup-target' ) ) ){ // ie で body 内の script が2度よばれるのに対処
\r
366 //alert( '[' +parent._tag + '>' + xnode._tag + '] remove ... ' );
\r
369 if( elm.childNodes && elm.childNodes.length ){
\r
370 //alert( '[' +parent._tag + '>' + xnode._tag + ' ' + (xnode._xnodes ? xnode._xnodes.length : '' ) + '] === ' + tag + ' ' + (elm.childNodes ? elm.childNodes.length : '' ) + ' Hit\n' + elm.outerHTML );
\r
371 current.xtext = null;
\r
376 xnodes : X.copyArray( xnode._xnodes ),
\r
380 l : xnode._xnodes.length,
\r
381 elems : X.copyArray( elm.childNodes ),
\r
383 skipCleanup : skipCleanup || X.Dom.skipCleanupTagNames[ tag ]
\r
391 if( elm.nodeType !== 3 ){
\r
392 if( !( text = xnode._text ) || ( text = X.Dom.cleanupWhiteSpace( text ) ) === ' ' ){
\r
393 console.log( '[' +parent._tag + '> UID:' + xnode._uid + ' len:' + xnode._text.length + ' code : ' + xnode._text.charCodeAt( 0 ) + ',' + xnode._text.charCodeAt( 1 ) + '] destroyed.' );
\r
397 alert( parent._tag + ' > ' + '"' + xnode._text + '" !== ' + tag + '\n' +
\r
398 'prev : ' + ( xnode.prevNode() && xnode.prevNode().html() ) + '\n' +
\r
399 'next : ' + ( xnode.nextNode() && xnode.nextNode().html() ) + '\n' +
\r
400 'html : ' + elm.outerHTML );
\r
405 xnode._rawNode = elm;
\r
406 xnode._text = elm.data; // 正確
\r
407 xnode._root = parent._root;
\r
408 if( !skipCleanup ){
\r
409 if( !( text = xnode._text ) || ( text = X.Dom.cleanupWhiteSpace( text ) ) === ' ' ){
\r
410 console.log( '[' +parent._tag + '>' + xnode._uid + '] destroy ... ' );
\r
414 xtext.text( xtext._text + text );
\r
415 console.log( '[' +parent._tag + '>' + xnode._uid + '] xtext,destroy ... ' );
\r
418 //alert( parent._tag + '>' + '"' + text + '"\n' + elm.data );
\r
419 xnode.text( text );
\r
423 xtext.text( xtext._text + xnode._text );
\r
424 console.log( '[' +parent._tag + '>' + xnode._uid + '] xtext,destroy ... ' );
\r
427 current.xtext = xtext || xnode;
\r
431 (function ( parent, xnode, current ){
\r
432 var elems = current.elems,
\r
435 xtext = current.xtext,
\r
436 skipCleanup = current.skipCleanup,
\r
439 xnode.parent = parent;
\r
441 if( xnode._xnodeType === 3 ){
\r
442 //alert( X.Dom.cleanupWhiteSpace( xnode._text ) );
\r
443 if( !skipCleanup ){
\r
444 if( !( text = xnode._text ) || ( text = X.Dom.cleanupWhiteSpace( text ) ) === ' ' ){
\r
448 //alert( 'xtext ' + text.charCodeAt( 0 ) + ' : ' + text.length );
\r
449 xtext.text( xtext._text + text );
\r
452 //alert( 'xnode ' + text.charCodeAt( 0 ) + ' : ' + text.length );
\r
453 xnode.text( text );
\r
457 //alert( 'skip ' + text.charCodeAt( 0 ) + ' : ' + text.length );
\r
458 xtext.text( xtext._text + xnode._text );
\r
462 current.xtext = xtext || xnode;
\r
466 if( xnode._xnodeType !== 1 ){
\r
467 //alert( xnode._xnodeType )
\r
471 for( ; j < m; ++j, ++current.j ){
\r
475 * 未知のタグについては、閉じタグも含めてタグ名扱いになる
\r
477 if( tag === '!' || tag.charAt( 0 ) === '/' ){
\r
478 //alert( '## ' + tag );
\r
481 if( xnode._tag !== tag ){
\r
482 alert( xnode._tag + ' ' + ' !== ' + tag + '\nxnode.html():' + xnode.attr('cite') + '\nelm.outerHTML:' + elm.outerHTML );
\r
486 xnode._rawNode = elm;
\r
487 xnode._root = parent._root;
\r
488 //xnode._tag = X.Dom.DTD.TAG_FIX[ tag ] || tag;
\r
489 if( X.Dom._isCleanupTarget( elm ) ){ //!xnode.hasClass( 'skip-cleanup' ) && ( X.Dom.cleanupTagNames[ tag ] || xnode.hasClass( 'cleanup-target' ) ) ){
\r
494 !xnode._id && elm.setAttribute( 'id', 'ie4uid' + xnode._uid );
\r
495 elm.setAttribute( 'UID', xnode._uid );
\r
497 tag === 'INPUT' && (
\r
499 ( xnode._attrs = { type : 'text' } ) :
\r
500 xnode._attrs.type || ( xnode._attrs.type = 'text' )
\r
503 current.xtext = null;
\r
505 if( tag === 'TEXTAREA' ){
\r
506 xnode.attr( 'value', xnode.html() ).empty();
\r
508 if( xnode._xnodes && xnode._xnodes.length ){
\r
511 xnodes : X.copyArray( xnode._xnodes ),
\r
515 l : xnode._xnodes.length,
\r
516 elems : X.copyArray( elm.children ),
\r
518 skipCleanup : skipCleanup || X.Dom.skipCleanupTagNames[ tag ]
\r
525 if( !xnode._rawNode ){
\r
526 alert( xnode._tag + ' ' + xnode._id + ' !== none...' );
\r
530 ( current.flag & 6 ) && ( parent._dirty |= X.Dom.Dirty.IE4_TEXTNODE_FIX );
\r
533 console.log( 'X.Dom.Builder' );
\r
534 console.log( 'bootTime : ' + ( X.getTime() - X.bootTime ) );