読者です 読者をやめる 読者になる 読者になる
スポンサーリンク

テキストボックス内のカーソル(キャレット)位置や選択範囲を,JavaScriptで取得・設定する方法

javascript プログラミング


input や textarea などのテキストボックスをフォーカスした際に表示される,「|」の形をしたカーソルの事をキャレットという。

また,Shiftキーを押しながらキャレットを移動させると,文字列が選択状態になる。


キャレットや選択文字列の情報は,JavaScriptで取得・設定できる。


下記は,IEで・・・

  • カーソル(キャレット)の位置を
    • 取得する方法。
    • 設定する方法。つまり,カーソルの移動。
  • 選択状態になった文字列の範囲を
    • 取得する方法。
    • 設定する方法。つまり,指定した範囲を選択する。

のサンプルコード。


また,これらを応用して

  • テキストボックスで,クリックした文字を取得する方法

についても述べる。

なお,Mozilla Firefoxでは下記を使って楽に操作できる。

  • 要素.selectionStart = 開始位置;
  • 要素.selectionEnd = 終了位置;
  • 要素.setSelectionRange( 開始位置, 終了位置 );

Mozillaのサイト:selectionStartプロパティとは
https://developer.mozilla.org/ja/XUL/Property/selectionStart


window.getSelection と document.getSelectionの違い
http://d.hatena.ne.jp/teramako/20080209/p1

もし上と同じことを IE でやろうとすると,日本語圏では情報が極めて手に入りづらい。


(1)IEで,カーソル位置を取得するサンプル

テキストボックス内のカーソルの位置を常にモニタするようなコード。

<input type="text" size=30 id="my_input" value="hogefuga">

<input type="button" onclick="f()" value="キャレットの位置を取得">


<!-- カーソルの位置が,常にここにモニタされます。 -->
<div id="d"></div>


<script language="JavaScript">

function f()
{
	var elem = document.getElementById( "my_input" );
	d.innerHTML = getCaretPositionIE( elem );
}

// 要素内のキャレット位置を取得する関数
function getCaretPositionIE( elem )
{
	elem.focus();

	// ボックスの先頭からキャレットまでのrangeを作って,長さを調査
	var range = document.selection.createRange();
	range.moveStart( "character", - elem.value.length );
	var caret_position = range.text.length;

	return caret_position;
}

// イベント割り当て
my_input.onclick = f;
my_input.onkeyup = f;

</script>

moveStartには,ボックスの末尾からの負の文字数を指定する。


イベント割り当て部分で,fをkeydownにセットしてしまうと「移動前」の位置が出てしまう。
カーソルの「移動後」を捉えるにはkeyupが必要。

(2)IEで,カーソル位置を設定するサンプル

位置のインデックスが0始まりだとして,ボタンクリック時に5文字目にカーソルをセットしてみる。

<input type="text" size=30 id="my_input" value="hogefuga">

<input type="button" onclick="f()" value="キャレットの位置を設定">


<script language="JavaScript">

function f()
{
	var elem = document.getElementById( "my_input" );
	setCaretPositionIE( elem, 5 );
}

// 要素内のキャレット位置を設定する関数
function setCaretPositionIE( elem, caret_position )
{
	var range = elem.createRange();
	range.collapse();

	// rangeの幅を新規設定
	range.moveEnd(   "character", caret_position ); // endを先に
	range.moveStart( "character", caret_position );
	range.select();
}

</script>

moveEndを先に,moveStartをあとで設定すること。

(3)IEで,選択範囲の取得をするサンプル

選択状態になった文字列の

  • 開始位置
  • 終了位置
  • 内容

をアラート表示。

<input type="text" size=30 id="my_input" value="hogefuga">

<input type="button" onclick="f()" value="選択範囲を調査">


<script language="JavaScript">

function f()
{
	var elem = document.getElementById( "my_input" );
	getSelectionIE( elem );
}

// 要素内の選択文字列を調査する関数
function getSelectionIE( elem )
{
	// ページ内で選択中のレンジ
	var selected_range = document.createTextRange();
	if( ! ( selected_range.text.length > 0 ) )
	{
		alert( "選択されていません。" );
		return;
	}

	// 始点を調査
	// ボックスの先頭から,選択範囲の始点までのrangeを作って長さを取得
	var range_start = elem.createRange();
	range_start.setEndPoint( "EndToStart", selected_range );
	var start_point = range_start.text.length;

	// 終点を調査
	// ボックスの先頭から,選択範囲の終点までのrangeを作って長さを取得
	var range_end = elem.createRange();
	range_end.setEndPoint( "EndToEnd", selected_range );
	var end_point = range_end.text.length;

	alert( start_point + "文字目から" + end_point + "文字目まで選択中"  );
	alert( "選択中の文字列は" + elem.value.substring( start_point, end_point ) );

}

</script>
  1. 選択範囲のレンジ
  2. 選択範囲の始点までのレンジ
  3. 選択範囲の終点までのレンジ

という3つを作成して算出している。

※参考:http://d.hatena.ne.jp/brazil/20061021/1161377936

(4)IEで,選択範囲を設定するサンプル

<input type="text" size=30 id="my_input" value="hogefuga">

<input type="button" onclick="f()" value="選択">


<script language="JavaScript">

function f()
{
	var elem = document.getElementById( "my_input" );
	setSelectionIE( elem, 1, 3 ); // ogが選択される
}

// 要素内の文字列を選択状態にする関数
// start, end : 選択したい文字列の開始地点と終了地点。(先頭からの文字数)
function setSelectionIE( elem, start, end )
{
	// 終了地点を,末尾から数えた負の文字数に変換
	var end_new = - ( elem.value.length - end );

	// 範囲生成
	var range = elem.createTextRange();
	range.moveStart( "character", start   ); // 先頭から数えた開始地点
	range.moveEnd(   "character", end_new ); // 末尾から数えた開始地点

	// 選択
	range.select();
}

</script>

(5)IEで,クリックした文字を取得

ここまでのrangeの使い方を踏まえて,「テキストボックス内の文字列をクリックした時に,ちょうどクリックした所にある文字を取得」というのをやってみよう。

<input type="text" size=30 id="my_input" value="hogefugahigehage">

<!-- クリックした文字がここに表示されます。 -->
<div id="d"></div>


<script language="JavaScript">

function f()
{
	// イベント情報を取得
	var evt = arguments[0] || window.event;
	var elem = evt.srcElement;
	var clicked_pos = evt.offsetX;

	// 現在表示中の文字列を保管
	var original_txt = elem.value;

	// 表示文字列を1文字ずつ増やしながら,
	// その文字列の幅とクリック位置を比較する。
	var clicked_index = -1;
	for( var i = 1, len = original_txt.length; i <= len; i ++ )
	{
		// 先頭から i 文字だけを表示
		var sub_txt = original_txt.substring( 0, i );
		elem.value = sub_txt;

		// その幅を取得
		var range = elem.createTextRange();
		var txt_max_pos = range.boundingWidth;

		// クリックしたときの位置が内包されているか?
		if( clicked_pos <= txt_max_pos )
		{
			clicked_index = i - 1;
			break;
		}

	}

	// 表示文字列を復元
	elem.value = original_txt;

	// クリックした文字を返す
	if( clicked_index >= 0 )
	{
		var clicked_char = original_txt.charAt( clicked_index );
		d.innerHTML = clicked_index + "文字目の" + clicked_char + "をクリックしました。";
	}


}

// イベント割り当て
my_input.onclick = f;

</script>


アルゴリズムは,ソースコード中にコメントで示した通り。

画面上に実際に表示されている文字列をじかに変えてしまい,いろいろ長さを変えながらクリック位置を模索していく,というかなりトリッキーな方法。


こんな不思議な方法,実際に利用されるのだろうか?と思うかもしれないが,本当に利用されているのである。

jQueryで時刻を入力するためのプラグイン,「jQuery Time Entry」の中の「_doDblClick()」関数中のコードを見てみてほしい。

テキストボックス中のクリック位置によって,時・分のターゲットを切り替えている。

jQuery Time Entry
http://keith-wood.name/timeEntry.html

補足点

以上は,input要素で利用できるコード。


textareaの場合は,エラーなくカーソル位置を取得するコードが下記に紹介されている。

IEが \r\n を自動でトリムしてしまったかどうかを検出すればよい。

How do I get the current position of the cursor in a TEXTAREA using Javascript?
http://www.dedestruct.com/2008/03/22/howto-cross-browser-cursor-position-in-textareas/

※ http://d.hatena.ne.jp/authorNari/20070819/1187493863 にも関連情報がある。




また,クロスブラウザなコードを書くためには,下記サイトのrange関連の関数一覧対応表を参考に。

選択範囲の取得について調べた
http://d.hatena.ne.jp/dayflower/20080423/1208941641

Rangeオブジェクトが何者なのかについては,下記で基礎的な事がよくまとまっている。

JavaScript Rangeの使い方
http://wiki.bit-hive.com/tomizoo/pg/JavaScript%20Range%A4%CE%BB%C8%A4%A4%CA%FD



関連する記事:

JavaScriptの動かないコード (中級編) テーブルに行追加できない - 主に言語とシステム開発に関して
http://d.hatena.ne.jp/language_and_engineering/20080914/1221348848


JavaScriptで,文字列を反復する / 逆順に並び替える方法 - 主に言語とシステム開発に関して
http://d.hatena.ne.jp/language_and_engineering/20080924/1222174957


alert() と書くために,わざわざ行頭に戻らなくてもすむ方法 - 主に言語とシステム開発に関して
http://d.hatena.ne.jp/language_and_engineering/20100829/p1