Hatena::Groupjavascript

JavaScriptで遊ぶよ

 | 

2009-02-23

createContextualFragmentの前にやっておくこと

09:13

何度使ってもなかなか覚えられないのでメモ。

javascript:(function(){
var s='<div>hoge</div>';
var range = document.createRange();
var df = range.createContextualFragment(s);
document.body.appendChild(df);
})()

一見大丈夫そうだけど、Firefox でしか意図した通りに動いてくれない。

Safari では、range.createContextualFragment(s) のところで

Error: NOT_SUPPORTED_ERR: DOM Exception 9

というエラーが出る。

Opera では、

<body><div>hoge</div></body>

というノードが挿入されてしまう。この理由は、document.createRange() した瞬間には Range の始点が HTMLDocument になるため (以下のブックマークレットで試すと Firefox、Safari、Opera のどれも HTMLDocument が得られる)、div 要素を作成しようとしたとき本来無くてはならないはずの body タグを補完するため。(contextual な実装)

javascript:alert(document.createRange().startContainer);

そういうわけで、range の始点として body の中のどこかを指定してやる必要がある。

javascript:(function(){
var s='<div>hoge</div>';
var range=document.createRange();
range.selectNodeContents(document.body); /*この一行が大事!*/
var df=range.createContextualFragment(s);
document.body.appendChild(df);
})()

こうすることによって、Safari でも先のエラーが出なくなり、挿入されるノードも3ブラウザで等しくなる。

Safari のエラーの原因は不明。


参考

os0xos0x2009/02/24 20:18AutoPagerize では、document.implementation.createHTMLDocument or document.implementation.createDocument で Document を作って、その Document をXPath関数に渡しています。この方法は一応各ブラウザ共通で使えて、id関数などが元の Document と作った Document で別々の結果になるというメリットがあります。
Safari で div に入れているのは、 createHTMLDocument を使うと Safari が高確率で落ちるという致命的なバグのためです。 div に入れると、元の Document にくっつける形になるので、id関数が使えなくなります…

edvakfedvakf2009/02/25 03:11createHTMLDocument で Safari でも動きました。ちょうど oAutoPagerize のその部分が面倒くさそうで見なかったことにしていたところでした。

http://javascript.g.hatena.ne.jp/edvakf/20090224/1235462786
このテストページでは Safari は落ちないっぽいので、何か条件があるんでしょうかね。

トラックバック - http://javascript.g.hatena.ne.jp/edvakf/20090223
 |