JavaScript Rangeの使い方
Rev.19を表示中。最新版はこちら。
Rangeオブジェクトに関するメモ。1.SelectionとRangeの関係
Selectionはカーソルの選択領域を示す。Rangeは1つの連続した選択領域を表しSelectionに格納されている。通常はSelectionの中にはRangeは1つだけ存在する。分断された領域が複数選択されている場合は、Selectionは複数のRangeを持つ(以下参照)。
Selectionの中に複数のRangeが含まれるケース
Linux版FireFoxだと、designMode = "On"の時に図1のようにセルを選択できる。このような場合、選択した各々のセルが1つのRegionとなり、Selectionに3つのRangeが含まれることになる。このような選択はIEやWindows版FireFoxではできなかった。この他に複数のRangeを持つ選択方法にどのようなものがあるかは不明。
図1 複数Range存在するケース
2.現在の選択範囲の取得の仕方(Mozilla系)
2.1 Selectionの取得
まずはSelectionを取得する。var selection = window.getSelection();
2.2 Rangeの取得
Selection内の最初のRangeを取得するには以下のようにする。var range = selection.getRangeAt(0);
Rangeの数はrangeCountプロパティで取得可能。
selection.rangeCount;
2.3 Rangeの取り扱い
Rangeから具体的な選択範囲を取得するには表1に示すプロパティを使う。表1 Rangeオブジェクトのよく使うプロパティ
プロパティ | 意味 |
---|---|
startContainer | 選択開始位置のDOM Node |
startOffset | 選択開始位置のstartContainer内でのオフセット |
endContainer | 選択終了位置のDOM Node |
endOffset | 選択終了位置のendContainer内でのオフセット |
文字を選択した時に表1のプロパティがどのように変化するかを表示するサンプル。
http://www.bit-hive.com/~tomita/RangeDump/
JavaScriptのソースはhttp://www.bit-hive.com/~tomita/RangeDump/range.js
3. 現在の選択範囲の取得の仕方(IEの場合)
3.1 Rangeの取得
IEの場合Selectionはdocument内に既にあるので以下のようにして取得できる。var range = document.selection.createRange();
3.2 Rangeの取り扱い
IEではMozilla系のようにstartContainerなどのプロパティは存在しない。IEのRangeオブジェクトの仕様はこちらを参照。textプロパティで選択範囲の文字列を取得したり、pasteHTML()メソッドで選択範囲にHTMLを貼り付けたりできる。
4. サンプルコード
実際にRangeオブジェクトを使ったサンプル。このサンプルはIFRAME内の選択領域にHTMLオブジェクトを挿入するコードを以下に示す。
IEではcreateRange()でRangeオブジェクトを取ってしまえば、pasteHTML()で張りつけることができる。Mozilla系では選択範囲のDOMオブジェクトを操作する必要がある。
IE用コード
function insertHTMLforIE(html)
{
// iframeのdocument,windowを取得
var win = frames['frame'].window;
var doc = frames['frame'].document;
win.focus();
range = doc.selection.createRange();
try {
range.pasteHTML(html);
} catch (e) {
alert(e);
}
}
Mozilla系用のコード
function insertHTMLForMozilla(html)
{
// iframeのdocumentとwindowを取得
var win = document.getElementById('frame').contentWindow;
var doc = document.getElementById('frame').contentDocument;
var fragment = doc.createDocumentFragment();
var div = doc.createElement("div");
div.innerHTML = html;
// div配下のNodeをfragmentに移動
while (div.firstChild) {
fragment.appendChild(div.firstChild);
}
var selection = win.getSelection();
range = selection.getRangeAt(0);
// 選択範囲の削除
range.deleteContents();
var container = range.startContainer;
var offset = range.startOffset;
switch (container.nodeType) {
case 1:
// Element node
container.insertBefore(fragment,
container.childNodes[offset]);
break;
case 3:
// Text node
var node = container.splitText(offset);
node.parentNode.insertBefore(fragment, node);
break;
}
}
実働サンプル:
http://www.bit-hive.com/~tomita/RangeInsert/
JavaScriptのソース:
http://www.bit-hive.com/~tomita/RangeInsert/insert.js