DOMレンジの内容の操作
レンジを選択すると、内部的にドキュメントフラグメントノードが作成され、そこに選択内のすべてのノードがアタッチされます。ただし、この処理が行われる前に、選択内容が整形式であることが要求されます。
先ほどの例に示したように、この方法では、途中に</b>終了タグを含んでいる、「Hello」の1つ目の「l」から「World」の「o」までの範囲を選択することができます(図4を参照)。このような選択は、『Professional JavaScript for Web Developers』(Nicholas C. Zakas 著、Wrox Pr Inc.、2005年4月)で説明されている通常のDOMメソッドでは不可能です。

レンジを使ったときにこの制限を回避できるのは、レンジでは欠けている開始タグと終了タグが認識されるからです。前述の例では、選択内に<b>開始タグが足りないと判断されたため、レンジによって開始タグが動的に追加され、さらに「He」を閉じるための</b>終了タグが新たに追加されます。これにより、DOMは次のようになります。
<p><b>He</b><b>llo</b> World</p>
このレンジに含まれるドキュメントフラグメントは図5のようになります。

このドキュメントフラグメントが作成されると、レンジの内容をさまざまなメソッドで操作できるようになります。
最もわかりやすく使いやすいのはdeleteContents()メソッドでしょう。このメソッドでは、レンジの内容をドキュメントから削除します。前述の例でレンジに対してdeleteContents()を呼び出すと、ページ内のHTMLは次のようになります。
<p><b>He</b>rld</p>
ドキュメントフラグメント全体が削除されるので、そのままだと</b>タグが足りなくなりますが、レンジによって</b>タグが補われるため、ドキュメントは整形式に保たれます。
extractContents()メソッドはdeleteContents()によく似ています。このメソッドでは、選択範囲をドキュメントから削除し、その範囲のドキュメントフラグメントを戻り値として返します。これにより、そのレンジの内容を他の場所に挿入することが可能になります。
var oP1 = document.getElementById("p1"); var oHello = oP1.firstChild.firstChild; var oWorld = oP1.lastChild; var oRange = document.createRange(); oRange.setStart(oHello, 2); oRange.setEnd(oWorld, 3); var oFragment = oRange.extractContents(); document.body.appendChild(oFragment);
この例では、ドキュメントフラグメントを抽出した後、ドキュメントの<body/>要素の末尾に追加しています((ドキュメントフラグメントをappendChild()に渡したときは、そのフラグメント自身ではなく、フラグメントの子だけが追加されるので注意してください)。この例を実行すると、ページの先頭には<b>He</b>rldが、ページの末尾には<b>llo</b> Woが配置されます。
また、cloneContents()メソッドを使用すると、ドキュメントフラグメントをその場に残したまま、そのフラグメントのコピーを作成して、ドキュメントの他の場所に挿入することができます。
var oP1 = document.getElementById("p1"); var oHello = oP1.firstChild.firstChild; var oWorld = oP1.lastChild; var oRange = document.createRange(); oRange.setStart(oHello, 2); oRange.setEnd(oWorld, 3); var oFragment = oRange.cloneContents(); document.body.appendChild(oFragment);
このメソッドはextractContents()によく似ています(どちらもレンジのドキュメントフラグメントを返します)。この例を実行すると、ページの末尾に<b>llo</> Woが追加され、元のHTMLコードはそのまま残ります。
DOMレンジの内容の挿入
前述の3つのメソッドでは、それぞれ異なる方法でレンジの情報を削除またはコピーしました。また別のメソッドを使用して、レンジに内容を追加することもできます。
insertNode()メソッドでは、選択レンジの先頭にノードを挿入できます。たとえば、前のセクションで定義したレンジに次のHTMLコードを挿入することを考えてみましょう。
<span style="color: red">Inserted text</span>
この処理は次のコードで実現できます。
var oP1 = document.getElementById("p1"); var oHello = oP1.firstChild.firstChild; var oWorld = oP1.lastChild; var oRange = document.createRange(); var oSpan = document.createElement("span"); oSpan.style.color = "red"; oSpan.appendChild(document.createTextNode("Inserted text")); oRange.setStart(oHello, 2); oRange.setEnd(oWorld, 3); oRange.insertNode(oSpan);
このJavaScriptを実行すると、次のHTMLコードが生成されます。
<p id="p1"><b>He<span style="color: red">Inserted text</span>llo</b> World</p>
レンジ選択の前半部分である「Hello」の「llo」の直前に<span/>が挿入されていることに注目してください。また、元のHTMLで<b/>要素が追加も削除もされていないことに注意してください。これは、前のセクションで紹介したメソッドを使用していないからです。このテクニックは、役に立つ情報をページに挿入するときなどに利用できます(たとえば、新規ウィンドウで開くリンクを示すアイコンなど)。
レンジに内容を挿入するだけでなく、surroundContents()メソッドを使用して、レンジを囲むように内容を挿入することもできます。このメソッドは、レンジの内容を囲むノードを引数として受け取ります。内部的には、次のような処理が行われます。
- レンジの内容が抽出されます(extractContents()と同様)。
- 元のドキュメント内で、レンジが置かれていた位置に指定のノードが挿入されます。
- ドキュメントフラグメントの内容が指定のノードに追加されます。
この機能は、Webページ内の特定の単語を強調表示するときなどに役立ちます。次に例を示します。
var oP1 = document.getElementById("p1"); var oHello = oP1.firstChild.firstChild; var oWorld = oP1.lastChild; var oRange = document.createRange(); var oSpan = document.createElement("span"); oSpan.style.backgroundColor = "yellow"; oRange.setStart(oHello, 2); oRange.setEnd(oWorld, 3); oRange.surroundContents(oSpan);
このコードを実行すると、選択レンジの背景が黄色で強調表示されます。
