フォーカスと選択

このセクションでは、要素のフォーカスと選択を取り扱う方法について説明します。

フォーカスを得ている要素

「フォーカスを得ている要素」とは、そのとき入力イベントを受け取っている要素のことです。 ウィンドウに 3 つのテキスト入力欄がある場合、そのときフォーカスを得ているテキスト入力欄だけが、利用者によるテキスト入力を受け付けることができます。 1 つのウィンドウについて、1 つの要素だけがフォーカスを得ることが可能です。

利用者は、要素をマウスでクリックするか TAB キーを押すことにより、フォーカスを移動することができます。 TAB キーを押すと、次の要素にフォーカスが移ります。 また、前の要素に戻るには、Shift キーを押しながら TAB キーを押します。

TAB 順序を変更する

tabindex 属性を要素に付加することにより、 TAB キーが押されたときにフォーカスが移る順序 (TAB インデックス) を変更することができます。 この属性には数値を設定する必要があります。 TAB キーが押されたとき、その要素の次に大きい TAB インデックス値を持つ要素にフォーカスが移ります。 つまり、要素にフォーカスを移動したい順に、一連のインデックスを与えていくことによって、任意の順序に変更できます。 とはいっても、たいていの場合、tabindex 属性は設定しないと思います。 その場合は、 TAB キーによって、フォーカスは次に表示されている要素に移ります。 順番を変えたい場合のみ TAB インデックス値を設定すればよいわけです。 以下に例を示します。

var el = env.locale; 例 1 : ソース 表示

<button label="Button 1" tabindex="2"/>
<button label="Button 2" tabindex="1"/>
<button label="Button 3" tabindex="3"/>

フォーカスイベント

focus イベントは、要素がフォーカスを得たことに応じるために利用されます。 blur イベントは、要素がフォーカスを失うことに応じるために利用されます。 要素に onfocusonblur 属性を与えることによって、フォーカス状態の変化に対する反応が可能になります。 これらの属性は、HTML における同名の属性と同様に機能します。 これらのイベントハンドラは、要素のハイライトやステータスバーへのテキストの表示などに利用できると思います。 以下に、focus イベントを処理するために、関数を設定する例を示します。

var el = env.locale; 例 2 : ソース 表示

<script>

function displayFocus(){
  var elem=document.getElementById('sbar');
  elem.setAttribute('value','Enter your phone number.');
}

</script>

<textbox id="tbox1"/>
<textbox id="tbox2" onfocus="displayFocus();"/>
<description id="sbar" value=""/>

この例で focus イベントが発生したとき、displayFocus 関数が呼び出され、 この関数によって、テキストラベルの値が変更されます。 この例を拡張して、blur イベントが発生したときに、テキストを取り除くようにすることも可能です。 focus と blur イベントは、典型的には、利用者が選択した要素に応じてインターフェイスの一部を更新するために使われています。 例えば、利用者によって、フィールドへの数値の入力が行われたときに、合計表示のフィールドを更新したり、入力された値を検証するために focus イベントを使うことができます。 focus や blur イベントの処理中に、アラートダイアログを出してはいけません。 この挙動は、利用者にとってわずらわしいため、ユーザーインターフェイス設計として劣悪です。

DOM 関数の addEventListener を使うことでも、要素にイベントハンドラを動的に追加できます。 この方法は、どんな要素やイベント型に対しても使用できます。 この関数は、3 つの引数、 「イベント型」、「イベントが発生したときに実行される関数」、「イベントを捕捉フェーズで捉えるかどうかを指示する真偽値」、をとります。

フォーカスを得ている要素の取得

現在フォーカスを得ている要素は、ウインドウごとに 1 つだけ存在する、コマンドディスパッチャと呼ばれるオブジェクトに保持されています。 コマンドディスパッチャは、利用者がインターフェイスを利用中にフォーカスを得ている要素を変更しても見失わないように追跡する役割を担っています。 また、コマンドディスパッチャは、それ以外の役割も持っていますが、それについては後のコマンドのセクションで述べます。 今回は、コマンドディスパッチャの機能のうち、フォーカスに関連したものについて見ていくことにします。

ウインドウのコマンドディスパッチャは、文書オブジェクトの commandDispatcher プロパティから取得できます。 また、フォーカスを得ている要素は、コマンドディスパッチャの focusedElement プロパティから取得できます。 以下にその例を示します。

var el = env.locale; 例 3 : ソース 表示

<window id="focus-example" title="Focus Example"
        onload="init();"
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<script>
function init(){
  addEventListener("focus",setFocusedElement,true);
}

function setFocusedElement(){
  var focused = document.commandDispatcher.focusedElement;
  document.getElementById("focused").value = focused.tagName;
}
</script>

<hbox>
  <label control="username" value="User Name:"/>
  <textbox id="username"/>
</hbox>

<button label="Hello"/>
<checkbox label="Remember This Decision"/>

<label id="focused" value="-No focus-"/>

</window>

この例では、フォーカスイベントハンドラをウインドウに設定しています。 捕捉フェーズ用のイベントハンドラを利用したいので、addEventListener メソッドを使う必要があります。 このメソッドによって、ウインドウに setFocusedElement メソッドを呼び出す、捕捉イベントハンドラを登録しています。 setFocusedElement メソッドは、フォーカスを得ている要素をコマンドディスパッチャから取得して、タグ名表示用ラベルの値として、その要素のタグ名を設定します。 これらによって、フォーカスを得た要素が変更されるごとに、ラベルにはその要素のタグ名が表示されることになります。

注意点がいくつかあります。

  • まず、 テキスト入力欄にフォーカスを与えたとき、タグ名の表示は「html:input」になり、期待される「textbox」にはなりません。これは、 XUL のテキスト入力欄が、HTML の input ウィジェットを使用して実装されており、フォーカスイベントは実装元の要素の方が受け取ることになるためです。
  • 次に、テキスト入力欄のラベルをクリックすると、フォーカスはテキスト入力欄に移ります。これは、ラベルにテキスト入力欄の id を指す control 属性が与えられているためです。
  • 最後に、タグ名を表示するラベルには control 属性が設定されていないため、クリックしても、フォーカスを得ている要素は変更されません。フォーカスは、フォーカス可能な要素のみが取得できます。

ラベルをフォーカス可能にする

カスタム要素の作成を行おうとしたときに、その要素がフォーカス可能か否かを変更する必要があるかもしれません。 そのためには、特殊なスタイルプロパティ -moz-user-focus を利用します。 このプロパティは、要素がフォーカス可能かどうかを制御します。 これにより、以下に例を示すように、ラベルをフォーカス可能にすることもできます。

var el = env.locale; 例 4 : ソース 表示

<label id="focused" style="-moz-user-focus: normal;"
          onkeypress="alert('Label Focused');" value="Focus Me"/>

この例では、フォーカス可能にするために、スタイルプロパティに normal を設定しています。 また、これを ignore に設定した場合、その要素はフォーカス不能になります。 ただし、この挙動を要素を無効化するために利用すべきではありません。 そのためには、要素を無効化するために設計されている disabled 属性か、プロパティの方を利用すべきです。 上の例のラベルがフォーカスを得ると、キー入力に反応できるようになります。 当然ですが、通常、ラベルはフォーカスを得ることを期待されていないため、ラベルがフォーカスを得ても、それを示すような表示は行いません。

スクリプトからフォーカスを制御する

スクリプトを使用して、フォーカスを別の要素に移動する方法はいくつかあります。 最も単純な方法はフォーカスを与えたい XUL 要素に対して、focus メソッドを呼び出すことです。 または、blur メソッドを使用して、要素からフォーカスを外すことも可能です。 以下に例を示します。

var el = env.locale; 例 5 : ソース 表示

<textbox id="addr"/>

<button label="Focus" oncommand="document.getElementById('addr').focus()"/>

もしくは、コマンドディスパッチャの、advanceFocusrewindFocus メソッドを利用することもできます。 これらのメソッドは、それぞれ、規定の順序に従って、フォーカスを次の要素あるいは前の要素へと移動します。

テキスト入力欄 (textbox) には、フォーカスを得ている間、それを示すために専用の属性 focused が追加されます。 この属性の有無をチェックすることにより、スクリプトあるいはスタイルシートから要素がフォーカスを得ているかどうかを知ることができます。 テキスト入力欄がフォーカスを得ているときは、値として true をとり、 テキスト入力欄がフォーカスを得ていないときは、この属性は存在しません。

フォーカスを、現在フォーカスを得ている場所から、ブラウザが次に移動させるはずの場所に移動させたいと考えているとします。 利用者は、このために、通常 TAB キーを押します。 スクリプトから実行する場合、どこからでも参照可能な、XUL ブラウザの文書オブジェクトを使用して、簡単に行うことが可能です。

      document.commandDispatcher.advanceFocus();

実際には、commandDispatcher は、単純に nsIDOMXULCommandDispatcher インターフェイスを実装しています。 なお、このインターフェイスでは、これ以外にも便利なメソッドをいくつか提供しています。

プラットフォーム固有の挙動

Mac OS X
Mac OS X には「Full Keyboard Access」(FKA) と呼ばれる設定があります。 XUL が、この設定の影響を強く受けることに注意してください。 具体的には、FKA の設定が「off」である場合、テキスト入力欄とリスト、及びツリーだけが、キーボードから (コードから focus() を呼び出すように) フォーカスを与えることが可能であることを意味しています。

テキストへの変更に対する処理

利用者が、テキスト入力欄の値を変更したことを検出するために、2 つのイベントを利用することができます。 当然ですが、これらのイベントは、テキスト入力欄がフォーカスを得ている場合のみ送信されます。

  • input イベントは、テキストがフィールド内で編集されるごとに発生します。つまり、このイベントの前後では、フィールドの値に差異があります。値の変更の監視には、キーイベントではなく、このイベントを利用する方が良いと思います。なぜなら、シフトキーなど、いくつかの値を変更しないキー操作や、テキスト入力欄に、上限まで文字が入力された以降に、文字キーが押された場合には、input イベントは発生しないからです。
  • change イベントは、フィールドへの変更が加えられたときに発生するという点では、input イベントと同じですが、このイベントは、テキスト入力欄がフォーカスを失うとき、つまり一連の変更が完了した場合にのみ、発生する点が異なります。

テキスト選択

テキスト入力欄の処理では、入力されたテキスト全部ではなく、利用者が選択した部分のみを取り出したいときがあります。 あるいは、選択されている領域を変更したい場合もあるかもしれません。

XUL のテキスト入力欄は、選択部分の読み出しや選択領域の変更をサポートしています。 最も単純なものは、テキスト入力欄が持っている、全てのテキストの選択です。 これは textbox オブジェクトの、select メソッドを利用することで可能です。

tbox.select();

また、一部のみを選択させたい場合もあると思います。 そのためには、setSelectionRange 関数を利用します。 この関数は、2 つの引数、選択範囲の先頭の文字の位置と、末尾の直後の文字の位置をとります。 位置は 0 を基点に数えます。すなわち、最初の文字が 0 、2 番目が 1 といった具合に数えていきます。

tbox.setSelectionRange(4,8);

この例では、表示されている 5 番目から 8 番目の文字を選択します。 もしフィールド内に 6 文字しか入力されていない場合、 5 番目と 6 番目の文字のみが選択されます。このときエラーは発生しません。

2つの引数に同じ値を与えた場合、選択範囲の先頭と末尾は同じ位置を指すことになり、 その場合は、結果としてテキスト入力欄のカーソル位置だけが変更されます。 以下の例を使用して、カーソルをテキストの先頭に移動させることができます。

tbox.setSelectionRange(0,0);

また、選択されている範囲は、selectionStartselectionEnd プロパティから取得できます。 これらのプロパティは、それぞれ選択範囲の先頭位置と末尾位置に設定されます。 両方とも同じ値に設定されている場合は、テキストが選択されていないことを示しています。 このとき、値としては現在のカーソル位置が設定されています。 これらのプロパティを利用して、先頭と末尾の位置が得られれば、テキスト全体から該当する部分を substring で取り出すことが可能です。

なお、テキスト入力欄全体の内容は、value プロパティによって、取得および設定することが可能です。

このとき、テキスト入力欄にある全文字数は、 textLength プロパティから取得することが可能です。

次のセクションでは、コマンドの使い方について見ていきます。

ドキュメントのタグと貢献者

 このページの貢献者: ethertank, Morishoji, Mgjbot
 最終更新者: ethertank,