幾つかの要素に、簡単に、イベントや状態の変化に応答してもらいたい場合が数多くあることでしょう。このためには、新しい要素が幾つか使えます。
大きなアプリケーションを作ると、しばしば、重複した機能をもつ要素が幾つかあるということになります。例えば、ツールバー上のボタンは、メニュー項目と機能的に同じという場合があるかもしれません。また、同じことを行なうキーボードショートカットやポップアップメニューがあるかもしれません。
必要なすべてのプロパティーと同様に、個々の場所にコードを追加するのは簡単なことです。しかし、アクションを無効にしたいとすればどうでしょうか。ブラウザー内の Back アクションを無効にしたいとします。メニュー上の Back コマンド、ツールバー上の Back ボタン、キーボードショートカット (例えば Alt+Left) そしてポップアップメニュー上の Back コマンドを無効にする必要があります。これを行なうスクリプトを書くことはできますが、それはまったく退屈なことです。Back アクションがある場所すべてを憶えておかなければならないという欠点もあります。これは、スクリプトすべてを更新しなければならない場合に、新しいスクリプトを追加したいときには、問題になります。単純に Back アクションを無効にし、すべての要素に Back アクションが無効になったことをひとりでに通知できれば、はるかに便利でしょう。
XUL はこのための解決策を提供しています。それは、broadcaster という名前の新しい要素に関連しています。この要素は、Back ボタンの無効状態を保持します。個々の Back アクション要素 (メニュー項目とツールバーのボタン) は、ブロードキャスターを見て、その無効状態が変化すると、それらも変化します。
最も単純なブロードキャスターを下に示します。他の要素から参照できるように、id 属性をいつも使うべきでしょう。
<broadcasterset> <broadcaster id="back_command" disabled="false"/> </broadcasterset> |
これができたら、ブロードキャスターの disabled 属性を変えることができます。ブロードキャスターを見ている要素はすべて、ブロードキャスターの disabled 属性が変更されるといつでも、自動的に更新されます。この結果、これらの要素はひとりでに無効になります。
ブロードキャスターを見ている要素はオブザーバー (observer) と呼ばれます。これらの要素はブロードキャスターの状態を監視 (observe) しているからです。要素をオブザーバーにするには、要素に observes 属性を追加します。例えば、Back ボタンをオブザーバーにするには次のようにします。
<button id="back_button" label="Back" observes="back_command"/> |
observes 属性をボタンに置き、その値を、監視したいブロードキャスターの id の値に設定しました。これによって、Back ボタンは、前に定義した back_command という id をもつブロードキャスターを監視します。
ブロードキャスターの default 属性の値が変化すると、オブザーバーは、自分のもつ default 属性の値を更新します。その結果、ブロードキャスターの状態が変化すると、ボタンは無効になったり、有効になったりします。
別の要素の追加を続けることもできます。要素がどれだけあってもそれらは、一つのブロードキャスターを監視できます。監視させたい要素が一つだけであっても構いませんが、それはたいしたことはしないでしょう。ブロードキャスターを使うのは、プロパティーを監視する複数の要素が必要な場合に限るべきです。以下で、別のオブザーバーを幾つか定義します。
<key id="back_key" modifiers="accel" keycode="VK_LEFT" observes="back_command"/> <menuitem id="back_menuitem" label="Back" observes="back_command"/> |
これで、しなければならないことは、broadcaster 要素の disabled 属性の変更です。これを行なうと、Back ボタン、メニューコマンド、キーボードショートカットはすべて、すぐに無効になります。
これまで、disabled だけを監視してきました。しかし、必要などんな属性でも使うことができます。オブザーバーは、値が変化するといつでも、ブロードキャスターの属性すべてを捉えます。実際には、値が変化したかどうかさえ問題ではありません。前の例は、次のように変更できます。
例 7.6.1
<broadcasterset> <broadcaster id="back_command" label="Back" disabled="false"/> </broadcasterset> <keyset> <key id="back_key" modifiers="accel" key="[" observes="back_command"/> </keyset> <menubar id="back-menubar"> <menu id="back_menu" observes="back_command"/> </menubar> <button id="back_button" observes="back_command"/> |
これで、disabled 属性だけでなく、個々のオブザーバーは、label も捉えます。2 つの属性はブロードキャスターに置かれているからです。その結果、ボタンとメニュー両方のラベルは Back に設定されます。キーの label も変更されますが、その値は何にも使われません。
label 属性がボタンとメニュータイトルに置かれていない点に注意して下さい。これは、それらがブロードキャスターから捉えられるからです。スクリプトを使ってその値を捉える予定がない場合、これは、実際上、入力をほんの少し節約できる以外、大したことはしません。
個々のオブザーバーはブロードキャスターの属性を捉え、それを自分に追加します。属性が既にある場合は、それは上書きされます。例えば、上のボタンに label を追加した場合、そうしなかったのと同じ効果になるでしょう。それは変更されるからです。
ブロードキャスターの属性のどれかの値が変化するといつでも、オブザーバーすべては通知を受け、自分のもっている属性をそれにマッチするように更新します。ブロードキャスターにないオブザーバーの属性は更新されることはありません。id 属性も変わることがない点に注意して下さい。必要なら、自分自身のカスタム属性を使うこともできます。
ブロードキャスターのどの属性を監視するかについてもっと詳しく指定する方法もあります。これには、observes 要素が関係します。これに対応する属性の場合と同様に、こうすることによって、オブザーバーとなる要素の定義ができます。observes 要素は、オブザーバーになる要素の子供にします。例を以下に示します。
<broadcasterset> <broadcaster id="back_command" disabled="false"/> </broadcasterset> <button id="back_button" label="Back"> <observes element="back_command" attribute="disabled"/> </button> |
属性を 2 つ追加しました。最初の element には、監視するブロードキャスターの id を指定します。2 番目の attribute には、監視する属性を指定します。ここでは、その結果、ブロードキャスターの disabled 属性が変化すると、ボタンの状態が変わります。observes 要素は変化しませんが、それが内部にある要素が変化します。この場合は、button です。
attribute の値を変更すると、ブロードキャスターの他の属性を監視できます。
observes 要素に置くことのできるイベントハンドラーは他にもあります。onbroadcast です。見ているブロードキャスターの属性の変化にオブザーバーが気付くと、このイベントハンドラーが呼び出されます。例を下に示します。
例 7.6.2
<broadcasterset>
<broadcaster id="thingy_command" style="color: black"/>
</broadcasterset>
<button label="Test">
<observes element="thingy_command" attribute="style" onbroadcast="alert('Color changed');"/>
</button>
<button label="Observer"
onclick="document.getElementById('thingy_command').setAttribute('style','color: red');"
/>
|
Test というラベルのボタンと Observer というラベルのボタンを作りました。Test ボタンをクリックしても、変わったことは何も起きません。しかし、Observer ボタンをクリックすると、2 つのことが起きます。まず、Test ボタンのテキスト色が赤に変わります。次に、'Color changed' というメッセージをもつアラートボックスが表示されます。
ここで起こったのは、ユーザーが 2 つ目のボタンを押すことにより、そのボタンにある onclick イベントハンドラーが呼び出されたということです。このスクリプトは、ブロードキャスターへの参照を取得し、そのスタイルを変更して color が赤になるようにします。ブロードキャスターは、スタイル変更の影響を受けません。それはスクリーン上に表示されていないからです。しかし、最初のボタンには、スタイルの変更を監視するオブザーバーがあります。observes タグにある element と attribute は、スタイルの変化を検知します。その結果、スタイルが自動的に最初のボタンに適用されたのです。
次に、ブロードキャストが発生したので、イベントハンドラー onbroadcast が呼び出されました。この結果、アラートメッセージが表示されました。broadcaster 要素の属性が変化した場合にだけ、ブロードキャストが行なわれることに注意して下さい。直接ボタンのスタイルを変更しても、ブロードキャストは起こりません。そのため、アラートボックスが表示されることはありません。
最初の button のコードを幾つも複製すると、ボタンそれぞれのためのアラートボックスが表示される結果になってしまいます。これは、ボタンがオブザーバーであり、スタイルが変化するとシグナルを送られるためです。
broadcaster 要素が broadcasterset 要素内に置かれていることに気付いたかもしれません。keyset 要素と同様に、それは要素のコンテナの役割をはたしています。この場合は、ブロードキャスターのためのものです。ブロードキャスターはすべて、ブロードキャスターセット内で宣言するとよいでしょう。そうすると、それらをひとまとめにしておけます。
(進む) 次は、XUL とスクリプトから XPCOM を使う方法を見ることにしましょう。