八章第二回 Rangeの機能
このページの最終更新日:
前回は、Rangeの作り方を解説しました。今回は、Rangeを使ってできることを解説します。
deleteContents
まず、Rangeが持つdeleteContentsというメソッドを解説します。これは、Rangeの示す範囲にあるものを残さず削除するというものです。引数も戻り値もありません。例えば、
- BBB
- ←開始点
- CCC
- DDD
- ←終了点
- EEE
というRangeがあったとき、deleteContentsをすると
- BBB
- ←開始点
- ←終了点
- EEE
という状態になります。間の部分が見事に消えました。このとき、開始点と終了点の間がすべてなくなったので、当然このRangeの開始点と終了点は同じに(つぶれた状態に)なります。
また、今回の場合点がノードとノードの間だったので簡単ですが、テキストの途中の場合でも同じです。
- BBB
- #text
"aaa|bbb"
←|が開始点
- #text
- DDD
- #text
"ccccc|dd"
←|が終了点
という範囲の場合、deleteContentsは
- BBB
- #text
"aaa"
- #text
- #text
"dd"
という結果になります。
cloneContents
さて、今度はcloneContentsというメソッドがあります。これは、選択部分をまるまるコピーしてその部分だけ得るというメソッドです。戻り値で結果が得られます。例えば、
- ←開始点
- BBB
- CCC
- DDD
- ←終了点
- EEE
というRangeでcloneContentsした場合、
- BBB
- CCC
- DDD
という部分を取得できます。メソッドの名前の通りあくまで「クローン」なので、選択されているほうには変化はありません。
もちろん、テキストでもOKです。例えば、
- BBB
- #text
"aaa|bbb"
- #text
- DDD
- #text
"ccccc|dd"
の場合は、
- BBB
- #text
"bbb"
- #text
- DDD
- #text
"ccccc"
というものを取得できます。どうしてこうなったのか分かりにくければ、タグで表わしてみるといいかもしれません。
<AAA><BBB>aaabbb</BBB><DDD />cccccdd</AAA>
というようになっていて、強調部分が選択範囲です。これを抜き出すと
bbb</BBB><DDD />ccccc
となります。ここで、BBB要素は終了タグのみがあって開始タグが無いので補います。そこで、
<BBB>bbb</BBB><DDD />ccccc
のようにうまいこと補います。こうすると、上の木構造の図と同じになりました。
さて、今回抜き出した部分はよく見ると親がありませんね。実は、ここで以前紹介したDocumentFragmentが出てきます。つまり、
- BBB
- #text
"bbb"
- #text
- DDD
- #text
"ccccc"
ということです。cloneContentsの戻り値はDocumentFragmentだったのです。
extractContents
さて、次に解説するextractContentsは、上の2つを合わせたようなメソッドです。どういうことかというと、このメソッドは、そのRangeの範囲の部分を抜き出して、それを返すというものです。抜き出すとは、つまり木構造から除去するということです。これは、deleteContentsと同じですね。そして、その部分を戻り値として得ることが同時にできるのです。つまり、cloneContentsをしたときと同じ戻り値を得ることができます。使うときに使えば結構便利かもしれません。
compareBoundaryPoints
今度は、compareBoundaryPointsを解説します。これはRangeのメソッドの中でも利便性が高いもので、2つのRangeの位置を比較するというものです。位置の比較といえば、以前に紹介したcompareDocumentPositionが思い出されますね。使用できる局面も似ています。使い方はこうです。
range.compareBoundaryPoints(how, sourceRange)
引数が2つありますね。range
とsourceRange
の2つが、比較するRangeです。さて、もう一つあるhowという引数は定数です。これは、比較の仕方を表すものです。
先にメソッドの返り値を説明します。このメソッドは「sourceRangeから見たrangeの位置」を、-1,0,1のいずれかの数で返します。rangeがsourceRangeより前なら-1、位置が同じなら0、後なら1が返ります。
さて、定数の説明ですが、定数は4種類あります。
というのも、二つのRangeを比較するさい、基準にする点を「開始点」にする方法と「終了点」にする方法の二種類あります。そこで、これをどうするかを定数で決めるのです。
- START_TO_START
- 開始点どうしを比べます。
- START_TO_END
- sourceRangeの開始点と、rangeの終了点を比べます。
- END_TO_START
- sourceRangeの終了点と、rangeの開始点を比べます。
- END_TO_END
- 終了点どうしを比べます。
これらの定数は、Rangeオブジェクトのプロパティとして使用できます。つまり、Range.START_TO_START
のように使います。どちらがどちらなのかとても分かりにくいので注意しましょう。
例えば、
range : |------|
abcdefghijklmnopqrstuvwxyz
sourceRange: |-------|
というように、rangeがsourceRangeより完全に前にあるのを判定するには、どうすればいいでしょうか。これは、次のようにすればよいです。
range.compareBoundaryPoints(Range.START_TO_END,sourceRange) <= 0
というようにします。
これは、定数がSTART_TO_ENDなので
range : |------| ←rangeの終了点
abcdefghijklmnopqrstuvwxyz
sourceRange: |-------|
sourceRangeの開始点↑
の2つを比べます。rangeの終了点がsourceRangeの開始点からみて前にあればいいので、-1ということになります。ただし、ここでは<= 0
としています。これは、0(位置が同じ)の場合にも、完全に前にあると見なしているためです。そう見なしたくなければ、-1のみで判定するのがよいでしょう。
また、比較が2回以上必要な場合もあります。例えば、
range : |---------------|
abcdefghijklmnopqrstuvwxyz
sourceRange: |-------|
のように、sourceRangeがrangeに完全に囲まれている場合を判定したい場合は、「rangeの開始点がsourceRangeの開始点より前」「rangeの終了点がsourceRangeの終了点より後」という2つの条件を満たす必要があります。これは以前紹介した>論理積演算子の&&
で可能ですね。
range.compareBoundaryPoints(Range.START_TO_START, sourceRange) <= 0 && range.compareBoundaryPoints(Range.END_TO_END, sourceRange) >= 0
というようになります。そのほか、自分で必要に応じてやってみましょう。
insertNode
さて、まだまだ解説します。次はinsertNodeです。これは、ノードを引数にとり、そのRangeの開始点の位置にノードを挿入するということです。例えば、
|-----|
abcdefghijklmn
というRangeがあり、この開始点に<AAA>123</AAA>
というノードを追加したとき、結果は
a<AAA>123</AAA>bcdefghijklmn
となります。
これはこのようにタグで見ると単純な動作ですが、木構造で見ると
- #text
"abcdefghijklmn"
が
- #text
"a"
- AAA
- #text
"123"
- #text
- #text
"abcdefghijklmn"
となり、もとのテキストノードが2つに分断されています。これは自力でやろうとすると多少面倒ですよね。Rangeを使って簡単にできるというのは、なかなかいい点です。
ただし、このメソッドはRangeの表す範囲が関係なく開始点だけが関わっているので、Rangeのメソッドとしてはちょっと特殊です。
cloneRange
cloneRangeは、その名の通りRangeを複製するメソッドです。返り値は新しくできたRangeで、引数はありません。複製なので、新しいRangeの開始点・終了点はもとのRangeと同じになります。
toString
toStringは、Rangeの範囲を全てテキストにして返すメソッドです。引数はありません。
|---------|
abcde<em>fghij</em>klmn
というRangeならば、返り値は"bcdefgh"ということになります。textContentの場合と同様、タグは無視されてテキストノードの値のみ集められます。