スキップしてメイン コンテンツに移動

pettanRのテキストレンジAPI

マークアップを更新し、誤った説明と表記のブレを修正しました。TODO を追記しています。(2021/05/05)

はじめに

W3C Range と IE 独自の先行実装 TextRange をラップしています。リッチテキストエディタ的なものを実装しながら必要なAPIを追加しています。

用語

テキスト編集要素
<textarea>typetext, search, url, telephone, password<input> 要素。
W3C レンジと Mozilla セレクション
Firefox, Webkit がサポートする。IE は9以降でサポート。
IE 独自レンジ
IE4~IE10までサポートした。テキスト編集要素のテキスト(value)に対しても矩形の測定などができて高性能。
ページ座標
ドキュメントの上端左を (0,0) とする座標系。

BODYBUTTONTEXTAREA の各エレメント、および text タイプを持った INPUT エレメントでのみ TextRange オブジェクトが作成できる。

使用技術とブラウザのサポート

ブラウザSelection APIHTMLInputElement.setSelectionRange()IE 独自レンジ
IE9+9+4~10
Opera9+ (*1)8+8 beta2(*2)~10.5
Firefox2+1.0
Safari2+2.0.3+ または 1.3.2+
  1. /*для цитаты*/d.onmouseup=function(){if(self.opera)str=d.getSelection();}
    //--for selection capture in old Opera (>7,<8) only
    • Added support for document.selection and document.getSelection in form input fields.
    • Added support for TextRange with methods collapse, move, moveStart, and moveEnd, required by Google Suggest.

概要

注意事項、レンジオブジェクトのライフサイクル

レンジオブジェクトが内部で持つ値は createRange() 時点でのスナップショットであり、DOM ツリーを変更すると不正な値になります。DOM ツリーを変更した後は createRange() を取り直します。最適化する場合はソースを確認してね。

レンジオブジェクトのタイプ毎の公開メソッド

メソッドレンジのタイプ
選択範囲indexn行目最後からn行目ページ座標ページ座標の行
xnode.createRangeIE 独自レンジが無い場合に制限があり *1IE 独自レンジが無い場合テキスト編集要素についてはレンジを作ることができない
range.getOffset
range.getRectIE 独自レンジが無い場合、テキスト編集要素についてはメソッドが居ない *1
range.move
range.select〇 *2
range.textテキスト編集要素でない場合、メソッドが居ない
  1. IE 独自レンジが無い場合、テキスト編集要素のコンテンツに対して座標系の操作が行えません。このため、行の取得、座標の文字を取得もできません。
  2. iOS11.2 でも選択範囲を js から変更できないcontentEditable を true にすれば良い という書き込みがある。またおいおい。

レンジの作成

選択範囲から作成

現在の選択範囲からレンジを作ります。テキスト編集要素の場合、要素にフォーカスが無いとレンジは作られません。

選択範囲から xnode がはみ出す場合、truncate オプションに true を与えると xnode の範囲に切り詰めたレンジにします。true 以外の場合、レンジは作られません。

var range = xnode.createRange("selection", true);
xnode.createRange("selection" [, truncate=false])
引数名値または型ノート
rangeType"selection"現在の選択範囲からレンジを作ります。
truncatebooleanレンジが xnode からはみ出している場合の処理を決めます。true の場合 xnode の範囲にレンジを切り詰めます。falseではレンジは作成されません。
戻り値レンジ | nullxnodeの範囲にレンジが無い場合、テキストエリアでフォーカスが無い場合 null が返る。

開始位置と終了位置から作成

from が要素の文字数を超えた場合、最後の文字の後ろに幅0のレンジが作られます。

var range = xnode.createRange("index", 0, 5);
xnode.createRange("index", from [, to])
引数名値または型ノート
rangeType"index"開始位置と終了位置からレンジを作ります。
fromNumber0以上。テキストの文字数を超えた場合は text.length が入る。
toNumberテキストの文字数を超えた場合は text.length が入る。省略した場合、from と同じ値。
戻り値レンジ

TODO

テキストの文字数を超えた場合は null を返すのは?検討する。(2021/05/05)

マウスイベント等のページ座標から作成

var range = xnode.createRange("point", e.pageX, e.pageY);
xnode.createRange("point", pageX, pageY)
引数名値または型ノート
rangeType"point"ページ座標からレンジを作ります。
pageXNumberページ座標の x
pageYNumberページ座標の y
戻り値レンジ | null座標の位置に文字が無い場合、null が返ります。

開始行と終了行から行レンジを作成

var range = xnode.createRange("line-index", 0);
xnode.createRange("line-index", lineFrom [, lineTo])
引数名値または型ノート
rangeType"line-index"開始行と終了行から行レンジを作ります。
lineFromNumber0以上。開始行。
lineToNumber省略した場合、lineFrom と同じ値。
戻り値レンジ | nulllineFrom が xnode の行数を超える場合、null が返ります。

最終行からのindexから行レンジを作成

var range = xnode.createRange("line-last", 0);
xnode.createRange("line-last", lastLineFrom [, lastLineTo])
引数名値または型ノート
rangeType"line-last"最終行からのindexから行レンジを作ります。
lastLineFromNumber0以上。
lastLineToNumber省略した場合、lastLineFrom と同じ値。
戻り値レンジ | nulllastLineFrom が xnode の行数を超える場合、null が返ります。

マウスイベント等のページ座標から行レンジを作成

var range = xnode.createRange("line-point", e.pageX, e.pageY);
xnode.createRange("line-point", pageX, pageY)
引数名値または型ノート
rangeType"line-point"
pageXNumber
pageYNumber
戻り値レンジ | null座標の位置に文字が無い場合、null が返ります。

レンジのメソッド

レンジの開始位置、終了位置の取得

xnode のコンテンツの中で、レンジの開始 index と終了 index を返します。

range.getOffset()
引数名値または型ノート
無し
戻り値{ from : Number, to : Number }

レンジのページ座標と幅と高さを取得

テキスト編集要素であり、ブラウザが IE TextRange をサポートしない場合、getRect は range に居ません。

range.getRect()
引数名値または型ノート
無し
戻り値{ x : Number, y : Number, width : Number, height : Number }ページ座標です。

レンジの移動

レンジを移動します。負の値を指定した場合、現在の各位置に加算します。

range.move( from [, to] )
引数名値または型ノート
fromNumber負の値を指定した場合、現在の開始位置に加算した位置に移動します。開始位置は0以下にはなりません。
toNumber負の値を指定した場合、現在の修了位置に加算した位置に移動します。修了位置は xnode からはみ出すことはありません。
戻り値レンジチェインメソッド用に自信を返します。

TODO

相対位置用のメソッドを追加して、正数と負数どちらにもレンジを移動できるようにする。(2021/05/05)

レンジを選択する

レンジを選択状態にします。以前の選択範囲は解除される点に注意します。createRange("selection") で作ったレンジにはこのメソッドが提供されません。

range.select()
引数名値または型ノート
無し
戻り値レンジチェインメソッド用に自信を返します。

レンジのテキストを取得、またはテキスト挿入ないし置換

レンジのテキストを取得または選択範囲へテキストを挿入または置換します。テキスト編集要素の場合だけこのメソッドが提供されます。

挿入した場合、レンジの開始位置・終了位置は挿入したテキストの最後に移動します。

置換した場合、レンジの終了位置は置換したテキストの最後に移動します。

range.text([text])
引数名値または型ノート
textString選択範囲がこのテキストで置換されます。
戻り値String | レンジ

参考情報

Linux 版 FireFoxだと、designMode = "On" の時に図1のようにセルを選択できる。このような場合、選択した各々のセルが1つの Region となり、Selection に3つの Range が含まれることになる。

DOM 標準には document.caretRangeFromPoint というメソッドがあり、座標から collapsed range を得ることができる。ただし WebKit しか実装してないらしい。

http://www.w3.org/TR/cssom-view/#dom-documentview-caretrangefrompoint

Firefox はマウスイベントの rangeParentrangeOffset というガラパゴスプロパティがある。