uhyohyo.net

JavaScript初級者から中級者になろう

八章第二回 Rangeの機能

このページの最終更新日:

前回は、Rangeの作り方を解説しました。今回は、Rangeを使ってできることを解説します。

deleteContents

まず、Rangeが持つdeleteContentsというメソッドを解説します。これは、Rangeの示す範囲にあるものを残さず削除するというものです。引数も戻り値もありません。例えば、

AAA
  • BBB
    • ←開始点
    • CCC
  • DDD
  • ←終了点
  • EEE

というRangeがあったとき、deleteContentsをすると

AAA
  • BBB
  • ←開始点
  • ←終了点
  • EEE

という状態になります。間の部分が見事に消えました。このとき、開始点と終了点の間がすべてなくなったので、当然このRangeの開始点と終了点は同じに(つぶれた状態に)なります。

また、今回の場合点がノードとノードの間だったので簡単ですが、テキストの途中の場合でも同じです。

AAA
  • BBB
    • #text "aaa|bbb" ←|が開始点
  • DDD
  • #text "ccccc|dd" ←|が終了点

という範囲の場合、deleteContentsは

AAA
  • BBB
    • #text "aaa"
  • #text "dd"

という結果になります。

cloneContents

さて、今度はcloneContentsというメソッドがあります。これは、選択部分をまるまるコピーしてその部分だけ得るというメソッドです。戻り値で結果が得られます。例えば、

AAA
  • ←開始点
  • BBB
    • CCC
  • DDD
  • ←終了点
  • EEE

というRangeでcloneContentsした場合、

  • BBB
    • CCC
  • DDD

という部分を取得できます。メソッドの名前の通りあくまで「クローン」なので、選択されているほうには変化はありません

もちろん、テキストでもOKです。例えば、

AAA
  • BBB
    • #text "aaa|bbb"
  • DDD
  • #text "ccccc|dd"

の場合は、

  • BBB
    • #text "bbb"
  • DDD
  • #text "ccccc"

というものを取得できます。どうしてこうなったのか分かりにくければ、タグで表わしてみるといいかもしれません。

<AAA><BBB>aaabbb</BBB><DDD />cccccdd</AAA>

というようになっていて、強調部分が選択範囲です。これを抜き出すと

bbb</BBB><DDD />ccccc

となります。ここで、BBB要素は終了タグのみがあって開始タグが無いので補います。そこで、

<BBB>bbb</BBB><DDD />ccccc

のようにうまいこと補います。こうすると、上の木構造の図と同じになりました。

さて、今回抜き出した部分はよく見ると親がありませんね。実は、ここで以前紹介したDocumentFragmentが出てきます。つまり、

DocumentFragment
  • BBB
    • #text "bbb"
  • DDD
  • #text "ccccc"

ということです。cloneContentsの戻り値はDocumentFragmentだったのです。

extractContents

さて、次に解説するextractContentsは、上の2つを合わせたようなメソッドです。どういうことかというと、このメソッドは、そのRangeの範囲の部分を抜き出して、それを返すというものです。抜き出すとは、つまり木構造から除去するということです。これは、deleteContentsと同じですね。そして、その部分を戻り値として得ることが同時にできるのです。つまり、cloneContentsをしたときと同じ戻り値を得ることができます。使うときに使えば結構便利かもしれません。

compareBoundaryPoints

今度は、compareBoundaryPointsを解説します。これはRangeのメソッドの中でも利便性が高いもので、2つのRangeの位置を比較するというものです。位置の比較といえば、以前に紹介したcompareDocumentPositionが思い出されますね。使用できる局面も似ています。使い方はこうです。

range.compareBoundaryPoints(how, sourceRange)

引数が2つありますね。rangesourceRangeの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 "abcdefghijklmn"

となり、もとのテキストノードが2つに分断されています。これは自力でやろうとすると多少面倒ですよね。Rangeを使って簡単にできるというのは、なかなかいい点です。

ただし、このメソッドはRangeの表す範囲が関係なく開始点だけが関わっているので、Rangeのメソッドとしてはちょっと特殊です。

cloneRange

cloneRangeは、その名の通りRangeを複製するメソッドです。返り値は新しくできたRangeで、引数はありません。複製なので、新しいRangeの開始点・終了点はもとのRangeと同じになります。

toString

toStringは、Rangeの範囲を全てテキストにして返すメソッドです。引数はありません。

|---------|
abcde<em>fghij</em>klmn

というRangeならば、返り値は"bcdefgh"ということになります。textContentの場合と同様、タグは無視されてテキストノードの値のみ集められます。