Firefox3.1β1 をインストールしてみたけれど createContextualFragment が
2008-10-21 追記 この日記は、こんな流れで修正やら追記がされてます。
uupaa.js(ver0.6)では、HTML文字列をノード化するために、
uu.node.insert = function(html, context) { var node = document.createRange().createContextualFragment(html); var rv = node.firstChild; context.appendChild(node); return rv; } uu.log(uu.node.insert("<span>UU.LAST_CHILD</span>"));
とかやってるのですが、このコードが Firefox3.1β1 だとうまく動きません。
rv の中身を見てみると、
- Firefox3.0.3 は ElementArray@1[(ELEMENT_NODE)/span[1]] - Firefox3.1β1 は ElementArray@2[(TEXT_NODE)[" "], (ELEMENT_NODE)/span[1]]
が返ってきてます(表示はuupaa.jsのインスペクタのもの)
むぅ
なんか余計なテキストノードが挟まってますね。
そういえば、Opera9.2x の createContextualFragment もダメなんだよなぁ。
Safari3(WebKit)にも createContextualFragment があるけど、Firefox3と挙動が違うためつかえないんだよなぁ(オンザフライでノードが作れない)。
createContextualFragment がこちらの期待通りに動くのは、Firefox3.0ぐらいなもんです。
DOMで標準化(文書化)されてないAPIって、大抵はこんな感じです。
「APIが実装されている」と「クロスブラウザで使える」は、別の話なんですよね。
テストケースをだれかが公表しないかぎり、この手の混乱がずっと続くわけです。
当面は
Firefox3.1 でも 旧来の方式(プレースホルダ)で実体化。
uu.node.substance = function(html) { // createContextualFragment が使えない環境(Safar3, Firefox2, IE等)では、 // <div></div>をプレースホルダとしてノードを生成し、中身だけを切り抜いて返す var rv, e = _doc.body.appendChild(_doc.createElement("div")); // placeholder e.innerHTML = html; rv = uu.node.cutdown(e); uu.node.remove(e); // remove placeholder return rv; }
2008-10-21 21:05 追記
http://developer.mozilla.org/en/DOM/range.createContextualFragment に記載されているコードを試してみました。
ページを表示するとbody要素に<div>I am a div node</div>が追加されます。
Showボタンをクリックすると、ライブなHTML(JavaScriptで加工した後のHTML)が表示されるようになってます。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>createContextualFragment test</title> <script src="createContextualFragment.js"></script> </head> <body><input type="button" value="Show" onclick="show()" /></body> </html>
// createContextualFragment.js function boot() { var rv = insert("<div>I am a div node</div>"); alert(rv); } function insert(tagString) { var range = document.createRange(); //range.selectNode(document.getElementsByTagName("div").item(0)); ここを修正 range.selectNode(document.getElementsByTagName("body")[0]); var documentFragment = range.createContextualFragment(tagString); var rv = documentFragment.firstChild; // ここを追加 document.body.appendChild(documentFragment) return rv; // ここも追加 } function show() { if (/Gecko\//.test(navigator.userAgent)) { // for Firefox2+ add outerHTML prop. HTMLElement.prototype.__defineGetter__("outerHTML", function() { var r = document.createRange(), tub = document.createElement("div"); r.selectNode(this); tub.appendChild(r.cloneContents()); return tub.innerHTML; }); } var d = window.open().document; d.write("<xmp>" + document.body.outerHTML + "</xmp>"); d.close(); } window.onload = boot;
結果
Browser | alert(rv) |
Firefox3.1β1 | HTMLDivElement |
Firefox3.0.3 | HTMLDivElement |
Firefox2.0.0.7 | HTMLDivElement |
Safari3.1.1 | HTMLDivElement |
Chrome | HTMLDivElement |
Opera9.27 | HTMLDivElement |
Opera9.61 | HTMLBodyElement |
IE8 | not impl |
Showボタンを押すと、こんな感じのHTMLになります。
Firefox3.1β1, Firefox3.0.3, Firefox2.0.0.7 <body><input value="Show" onclick="show()" type="button"><div>I am a div node</div></body>
Safari3.1.1, Chrome <body><input type="button" value="Show" onclick="show()"> <div>I am a div node</div></body>
Opera9.27 <BODY><INPUT type="button" value="Show" onclick="show()"> <DIV>I am a div node</DIV>
Opera9.61 <BODY><INPUT type="button" value="Show" onclick="show()"> <BODY><DIV>I am a div node</DIV></BODY></BODY>
どうやら、
var node = document.createRange().createContextualFragment(html);
といったコードで、Nodeを作成できたのはFirefox3.0のみで、むしろ少数派の挙動だったようです。
逆の可能性について思慮が不足してました。(ありがとうid:javascripterさん)