続いては、XBL で定義された要素にカスタムプロパティを追加する方法を見ていきます。
XBL インタフェース
JavaScript と DOM は、要素のプロパティを取得または設定するためのアクセス手段を提供しています。 XBL を利用すれば、作成した要素に独自のプロパティを定義することが可能です。 または、処理を呼び出すためのメソッドを追加することもできます。 これらを行っておけば、後は (getElementById
のような関数を使って) 要素への参照の取得を行うだけで、 追加したプロパティの取得や設定、または追加したメソッドの呼び出しが可能になります。
追加できる項目には 3 種類あります。
- フィールド (field) は、単純な値を保持するのに使います。
- プロパティ (property) も、値を保持するのに使いますが、値の取得や変更を行うときに、コードが実行される場合があります。
- メソッド (method) は、実行可能な関数です。
これらの 3 つは、すべて
要素の子要素として置かれた binding
要素の中に定義することになります。 implementation
要素の中では、 implementation
、field
、property
の各要素を必要に応じて個別に定義していきます。 このための一般的な構文を以下に示します。method
<binding id="element-name"> <content> -- content goes here -- </content> <implementation> <field name="field-name-1"/> <field name="field-name-2"/> <field name="field-name-3"/> <property name="property-name-1"/> <property name="property-name-2"/> <property name="property-name-3"/> . . . <method name="method-name-1"> -- method content goes here -- </method> . . . </implementation> </binding>
フィールド
個々のフィールドは、
要素を使って定義します。 しばしば、フィールドは field
label
や disabled
のような、 要素に置かれた属性と対応していますが、そうしなければならないという訳ではありません。
要素の field
name
属性は、フィールドの名前を指示するために使用します。 この名前を使用して、スクリプトからフィールドの値の取得と設定を行うことができます。 以下の例では、乱数を生成して保存するためのボタンを作成しています。 このボタンの number
プロパティからは、(値を変更しない限り) 何回取得しても同じ値が取り出されることになります。 この例では、処理のほとんどを、 oncommand
ハンドラで行っています。 これを XBL に移す方法については、もう少し後で見ることにします。
XUL: <box id="random-box" class="randomizer"/> <button label="Generate" oncommand="document.getElementById('random-box').number=Math.random();"/> <button label="Show" oncommand="alert(document.getElementById('random-box').number)"/> XBL: <binding id="randomizer"> <implementation> <field name="number"/> </implementation> </binding>
このバインディングの中では、乱数を保存するための number
フィールドが定義されています。 このフィールドの値の設定と取得は、XUL の方に追加した 2 つのボタンを使って行ないます。 そのための構文は、HTML 要素のプロパティの取得や設定を行うためのものによく似ています。 なお、この例では、表示するべきコンテントが XUL ボックスの中にも、対応する XBL の定義の中にも置かれていませんが、そのことはまったく問題ではありません。
といっても、この例のフィールドにはデフォルト値が設定されていないので、 この例には修正するべき点が 1 つもないという訳ではありません。 デフォルト値を設定するためには、
タグの内側にコンテントとして、デフォルト値として設定したい値を置きます。 以下に例を示します。field
<field name="number"> 25 </field>
これによって、number
フィールドのデフォルト値として 25 が設定されます。 さらに、値を置く代わりに
タグの中に、デフォルト値を求めるためのスクリプトを置くことも可能です。 この方法は、デフォルト値を計算する必要がある場合に必要になるはずです。 例えば、以下のフィールドは、現在時刻と同じ値がデフォルト値になります。field
<field name="currentTime"> new Date().getTime(); </field>
プロパティ
プロパティにデータを設定する際、値として正しいかを確認したいことはしばしばあると思います。 または、参照されるたびに動的に値を計算したい場合もあるかもしれません。 例えば、現在時刻を保持するプロパティが必要だとすると、その値は必要になるたびに生成したいはずです。 このような場合には、
タグではなく field
タグを使う必要があります。 property
property
タグを使う場合も、前述の field
タグの場合と、構文自体は似ていますが、機能が追加されています。
onget 属性と onset 属性
プロパティでは、onget
と onset
属性によって、値の取得または変更する場合にコードを実行させることが可能になります。 これらの属性は、
要素に追加し、その値にはプロパティ値の取得、または設定を行なうためのスクリプトを設定します。property
例えば、現在時刻を計算するためのスクリプトを onget
に設定するとします。 この onget
のスクリプトは、他のスクリプトがプロパティ値にアクセスするたびに、その値を取得するため呼び出されることになり、 このスクリプトは、そのプロパティの値となるべき値を返す必要があります。
また、onset
ハンドラも似ていますが、こちらはスクリプトからプロパティに新しい値を設定しようとする場合に呼び出されることになります。 ここに設定するスクリプトは、値をどこかに保存するか、あるいは値が正しいかを確認するためのものになるはずです。 例えば、プロパティによっては、数値だけを保存できるようにしたい場合があると思いますが、 このようなプロパティに英字のテキストの設定を行おうとした場合は、失敗する必要があるはずです。
<property name="size" onget="return 77;" onset="alert('Changed to:'+val);"/>
このプロパティを取得すると、常に 77 を返します。 また、設定した場合には、値がプロパティに設定されたことを示すアラートが表示されます。 onset
ハンドラが呼び出されるときには、特別な変数 val
によって、プロパティに設定するべき値が渡されます。 ハンドラのスクリプトでは、これを利用して値が正しいかの確認や保存処理を行うことが可能です。 なお、onset
ハンドラは、実際に設定された新しい値を返す必要があります。
続いては、スクリプトで「よくあるコード」が実行されたとき、 どのように処理されていくのかを見ていくことにします。
まず、「banana」と「orange」という名前の 2 つの要素があり、 それぞれには、「size」という名前のカスタムプロパティがあるとします。 このときに、以下のスクリプトを実行します。
banana.size = orange.size;
- orange の size プロパティを取得するために、orange の
onget
スクリプトが呼び出されます。呼び出されたスクリプトは値を計算して返します。 - banana の size プロパティの
onset
ハンドラが呼び出されます。onset
のスクリプトではval
変数を通して orange のonget
スクリプトが返した値を受け取り、それを banana の size プロパティに必要な手順に従って設定します。
フィールドとは異なり、プロパティは値を保持しないことに注意してください。 onset
ハンドラのないプロパティに値を設定しようとした場合は、エラーになります。 このため、しばしばプロパティの実際の値を保持するために、内部的に別のフィールドを利用します。 また、プロパティを XBL で定義された要素の属性に一致させる方法も、よく利用されます。 以下の例は、プロパティを要素の属性と対応させる方法を示しています。
<property name="size" onget="return this.getAttribute('size');" onset="this.setAttribute('size',val);" />
この例で作成したプロパティの値を、スクリプトから取得しようとするたびに、その要素の同じ名前の属性が取得されます。 また、設定しようとするときには、その値は要素の属性に設定されます。 こうしておけば、プロパティと属性のどちらから取得、または変更しても、同じ値になるため便利です。
getter 要素と setter 要素
また、onget
属性と onset
属性に設定するスクリプトが長い場合には、別の構文を利用することも可能です。 具体的には、onget
属性は、
という名前の子要素として置き換えることができ、 getter
onset
属性は、
要素で置き換えることが可能です。 以下に例を示します。setter
<property name="number"> <getter> return this.getAttribute('number'); </getter> <setter> var v = parseInt(val,10); if (!isNaN(v)) { this.setAttribute('number',''+v); } </setter> </property>
この例のプロパティでは、整数値だけを保持することが可能です。 それ以外の文字が入力された場合は取り除かれます。 また、入力が数値でない場合には、値は変更されません。 これらの処理は、
要素の中に置かれたコードで行っています。 なお、このプロパティの実際の値は、要素の setter
number
属性に保存されることになります。
プロパティ値の取得や設定を行なうハンドラを作成するためには、どちらの構文を利用しても構いません。
readonly 属性
タグや field
タグに property
readonly
属性を追加して true
に設定することにより、 フィールドやプロパティを読み取り専用にすることが可能です。 このとき、読み取り専用になっているプロパティに値を設定しようとしても失敗します。
次のセクションでは、XBL で定義された要素にメソッドを追加する方法を見ていきます。