このセクションでは、XBL の例を説明します。
XBL 要素の完全な例を作ることにしましょう。これは、一度に一つずつ表示されるオブジェクトのデック (deck) を保存するウィジェットです。下部にあるナビゲーションボタンによって、ユーザーは、オブジェクトをたどることができます。ボタンの間にあるテキストウィジェットは現在のページを表示します。このページには何でも置くことができますが、イメージセットに使うと役立つかもしれません。これは、スライドショー要素と呼ぶことにします。
まず、XBL 内容にどんな要素が必要かを決めることにしましょう。ページがめくれるようにしたいので、ページの内容を保持するには deck 要素が最適です。ページの内容は XBL ではなく XUL ファイルで指定しますが、それはデック内に追加する必要があります。children タグを使わなければなりません。下部には、前のページに戻るためのボタンと現在のページ数を表示するテキストウィジェット、次のページに進むボタンが必要です。
例 11.9.1
<binding id="slideshow">
<content>
<xul:vbox flex="1">
<xul:deck index="0" flex="1">
<children/>
</xul:deck>
<xul:hbox>
<xul:button xbl:inherits="label=previoustext"/>
<xul:description flex="1"/>
<xul:button xbl:inherits="label=nexttext"/>
</xul:hbox>
</xul:vbox>
</content>
</binding>
|
このバインディングは、スライドショーの構造を作ります。flex 属性を要素の幾つかに追加し、正しく伸縮するようにします。2 つのボタンの label 属性は、それが結び付けられた要素から値を継承します。ここでは、2 つのカスタム属性 previoustext と nexttext を継承しています。これによって、ボタンのラベルの変更が簡単になります。XBL が結び付けられている要素の子供は、deck 内部に置きます。
以下の XUL ファイルは、下のイメージにある結果になります。
<box class="slideshow" previoustext="Previous" nexttext="Next" flex="1"> <button label="Button 1"/> <button label="Button 2"/> <button label="Button 3"/> </box> |
要素は定義された通りに置かれています。最初のボタン 'Button 1' は、デックの最初のページとして使われています。description ウィジェットは表示されていません。そのための value が指定されていないからです。値を設定することもできますが、そうする代わりに、これは後で計算することにしましょう。
次に、現在のページを保持するプロパティーを追加します。このカスタムプロパティーを取得する場合、現在表示されているページの番号を保持するデックの index 属性の値を検索する必要があります。同様に、このプロパティーを設定する場合、デックの index 属性を変更する必要があります。更に、どのページが現在表示されているのかを示すため、テキストウィジェットを更新する必要があります。
<property name="page"
onget="return parseInt(document.getAnonymousNodes(this)[0].childNodes[0].getAttribute('index'));"
onset="return setPage(val);"/>
|
'page' プロパティーは、無名配列の最初の要素を見ることによって、その値を取得します。これは水平方向のボックスを返します。そのため、デックを取得するには、ボックスの最初の子供ノードを取得する必要があります。ここでは、無名配列は使用しません。デックはボックスから見ると無名ではないからです。最後に、index 属性を取得し、それを返します。'page' を設定するには、後で定義する 'setPage' を呼び出します。プロパティーのデフォルト値は指定しません。それはデックの値を取得するだけだからです。
onclick ハンドラーは、ボタンが押されたときページが変更されるようにするため、Previous と Next ボタンに追加する必要があります。便利なことに、たった今追加したカスタム 'page' プロパティーを使ってページを変更することができます。
<xul:button xbl:inherits="label=previoustext"
onclick="parentNode.parentNode.parentNode.page--;"/>
<xul:text flex="1"/>
<xul:button xbl:inherits="label=nexttext"
onclick="parentNode.parentNode.parentNode.page++;"/>
|
'page' プロパティーは、外側の XUL 要素だけにあるので、そこに行くには parentNode プロパティーを使う必要があります。最初の parentNode はボタンの親を返します。これは水平方向のボックスです。その 2 番目の親は垂直方向のボックスです。最後の親は外側のボックスになります。'page' プロパティーは加減算されます。これを行なうには、まずその値を取得するため onget スクリプトを呼び出し、値に 1 足すか引くかして、値を設定するため onset ハンドラーを呼び出します。
'setPage' メソッドを定義しましょう。これはパラメータを一つ取ります。page に設定するページ番号です。ページが範囲外ではないことを確かめ、デックの index とテキストウィジェットの label 属性を変更する必要があります。
<method name="setPage">
<parameter name="newidx"/>
<body>
<![CDATA[
var thedeck=document.getAnonymousNodes(this)[0].childNodes[0];
var totalpages=childNodes.length;
if (newidx<=0) return 0;
if (newidx>totalpages) return totalpages;
thedeck.setAttribute("index",newidx);
document.getAnonymousNodes(this)[0].childNodes[1].childNodes[1]
.setAttribute("value",newidx+" of "+totalpages);
return newidx;
]]>
</body>
</method>
|
この関数は 'setPage' という名前で、'newidx' というパラメータを取ります。メソッドの本体は '<![CDATA[' and ']]>' 内にあります。これは、その中にあるテキストすべてをエスケープするため、XML ファイルすべてで使われる一般的なメカニズムです。こうすれば、内部にある小なり記号と大なり記号すべてをエスケープする必要がありません。
コードを部分ごとに細分化して見ていくことにしましょう。
var thedeck=document.getAnonymousNodes(this)[0].childNodes[0];無名内容配列の最初の要素を取得する。これは垂直方向のボックスである。次に、その最初の子供を取得する。これはデック要素である。
var totalpages=childNodes.length;結び付けられたボックスがもつ子供の数を取得する。これは存在するページの総数である。
if (newidx<=0) return 0;新しいインデックスが最初のページより前になったら、ページは変更せず 0 を返す。ページは、最初のページより前のものに変更すべきではない。
if (newidx>totalpages) return totalpages;新しいインデックスが最後のページより後になったら、ページは変更せず最後のページのインデックスを返す。ページは、最後のページより後のものに変更すべきではない。
thedeck.setAttribute("index",newidx);
デックの index 属性を変更する。これによって、リクエストされたページが表示される。
document.getAnonymousNodes(this)[0].childNodes[1].childNodes[1].setAttribute("value",newidx+" of "+totalpages);
この行は、現在のページインデックスを表示するテキストウィジェットを変更する。テキストウィジェットは、無名内容 (垂直方向のボックス) の最初の要素、それの 2 番目の子供 (水平方向のボックス)、そしてそのボックスの 2 番目の要素を取得することによって検索できる。value 属性は、'1 of 3' やそれに似たものに変更される。
ただ一つ残っている問題は、テキストウィジェットにはデフォルトで何も設定されていないということです。最終結果を以下のイメージで示します。
追加機能を加えることもできます。キーボードショートカットが Previous と Next ボタンに使えるでしょう (例えば、バックスペースとスペースバー)。最初のページと最後のページに行くために First と Last ボタンを追加することもできるでしょう。テキストウィジェットをフィールドに変更して、ユーザーが行きたいページを入力するようにすることもできます。あるいは、ポップアップを追加して、メニューからページの選択ができるようにすることもできるでしょう。CSS を使ってデックの周囲に境界を付けることもできます。そうすれば、見栄えが少しよくなるでしょう。
最終コードは次の通りです。
例 11.9.2
<binding id="slideshow">
<content>
<xul:vbox flex="1">
<xul:deck index="1" flex="1">
<children/>
</xul:deck>
<xul:hbox>
<xul:button xbl:inherits="label=previoustext"
onclick="parentNode.parentNode.parentNode.page--;"/>
<xul:text flex="1"/>
<xul:button xbl:inherits="label=nexttext"
onclick="parentNode.parentNode.parentNode.page++;"/>
</xul:hbox>
</xul:vbox>
</content>
<implementation>
<property name="page"
onget="return parseInt(document.getAnonymousNodes(this)[0].childNodes[0].getAttribute('index'));"
onset="return setPage(val);"/>
<method name="setPage">
<parameter name="newidx"/>
<body>
<![CDATA[
var thedeck=document.getAnonymousNodes(this)[0].childNodes[0];
var totalpages=childNodes.length;
if (newidx<=0) return 0;
if (newidx>totalpages) return totalpages;
thedeck.setAttribute("index",newidx);
document.getAnonymousNodes(this)[0].childNodes[1].childNodes[1]
.setAttribute("value",newidx+" of "+totalpages);
return newidx;
]]>
</body>
</method>
</implementation>
</binding>
|
(進む) 次は、ウィンドウの追加的な機能を幾つか見ることにしましょう。