【jQuery】『wrapAll()』の怪動作の検証

【怪動作】
包む側の要素にテキストノードのfirstChildが含まれていると、
包まれる側の要素が表示されません。


【実例】


■ ごく一般的な『wrapAll()』の使用例です。

jQuery:
var $hoge = $('<p>hoge1</p>');
$hoge.wrapAll($('<div />'));

HTML:
<div>
<p>hoge1</p>
</div>



CSS:
div{
background:#fee;
border : 2px solid #f88;
margin : 0.5em;
padding : 0.5em;
}
p{
background: #ccc;
border : 1px solid #666;
padding : 0.5em;
}





■ 包む側に、テキストノードのfirstChildが含まれている場合です。

jQuery:
var $hoge = $('<p>hoge2</p>');
$hoge.wrapAll($('<div><!-- firstChild→ -->fuga2</div>'));

HTML:
//<p>タグが消えた…!
<div>fuga2</div>





■ テキストノードが存在しても、firstChildでなければ問題ありません。

jQuery:
var $hoge = $('<p>hoge3</p>');
$hoge.wrapAll($('<div><!-- firstChild→ --><div />fuga3</div>'));

HTML:
<div>
<div>
<p>hoge3</p>
</div>
fuga3
</div>




【原因】

jquery-1.3.2.js (219行目〜238行目):
wrapAll: function( html ) {
if ( this[0] ) {
// The elements to wrap the target around
var wrap = jQuery( html, this[0].ownerDocument ).clone();

if ( this[0].parentNode )
wrap.insertBefore( this[0] );

wrap.map(function(){
var elem = this;

while ( elem.firstChild )
//テキストノードであってもノーチェックで
//リターンされ、『append()』が呼び出される
elem = elem.firstChild;

return elem;
}).append(this);
}

return this;
},

jquery-1.3.2.js (252行目〜257行目):
append: function() {
return this.domManip(arguments, true, function(elem){
//要素ノード以外は無視されて、appendされない!
if (this.nodeType == 1)
this.appendChild( elem );
});
},

(参考: nodeTypeについて)
◆DOM Samples /Core Node/nodeType - [JavaScript]All About
http://allabout.co.jp/internet/javascript/closeup/CU20040307/


【感想】
ノーチェックで『elem = elem.firstChild;』としている箇所の前に、
『if(elem.firstChild.nodeType != 1) break;』のような、
テキストノードの場合はループを終了する処理を挿入すれば
解決するのではとも思います。


が、そもそも『wrapAll()』は包むためのメソッドなのですから、
ある要素を複雑な構成の要素に所属させたいのなら、
『wrap()』系ではなく『append()』を使うべきなんでしょうね。