このセクションでは、ボックスオブジェクトについて説明します。 このオブジェクトは、XUL ボックスの表示とレイアウトに関する情報、 言い換えれば XUL のレイアウトに関するいくつかの詳細な情報を保持しています。
Mozilla のレイアウト処理
Mozilla は、対象をコンテントツリーとレイアウトツリーの 2 つのツリーに分けて処理します。 コンテントツリーは、ソースコードで見つかった内容をノードとして保持するツリーです。 レイアウトツリーは、それとは別のノードからなるツリーで、そのノードは個々の表示可能なコンポーネントに対応しています。 レイアウトツリーは、表示が期待されているものをノードとするような構造を保持しています。 このため、コンテントツリーとレイアウトツリーのノードが 1 対 1 に対応しているとは限りません。 一部のコンテントノードに対しては、複数のレイアウトオブジェクトが存在することがあります。 例えば、段落の場合、レイアウトオブジェクトは、含まれる個々の行ごとに存在することになります。 逆に、一部のコンテントノードには、レイアウトオブジェクトが全く存在しません。 例えば、
要素は、いかなる場合でも表示されることはないので、レイアウトオブジェクトは存在しません。 同様に、key
によって隠されている要素についても、レイアウトオブジェクトは存在しません。
一般に DOM は、文書の内容、あるいは構造に関係する情報の取得と変更についてのみ用いられます。 このため、与えられた要素から、どのような種類のコンテントツリーのノードが作成されるかは、比較的簡単に決定されます。 例えば、XUL 要素は、XULElement 型のコンテントノードを持つことになります。
一方、どのレイアウトオブジェクトが作成されるかは、より複雑な手法で決定されます。 このために、「タグ名」「要素の属性」「数々の CSS プロパティ」「周囲の要素とレイアウトオブジェクト」「要素に結びつけられた XBL (XBL については後のセクションで記述します) 」といった様々な情報が、組み合わされて利用されます。 要素に対してスタイルを変更していなければ、通常、ほとんどの XUL 要素は、ボックスレイアウトオブジェクトあるいはその派生型を利用します。 すべての XUL 要素はボックスの一種であること、つまりボックスは表示されるすべての XUL 要素の基本であることを思い出してください。 なお、ボックスには、個々の XUL 要素の種類に応じて特化された 25 以上の派生型があります。 これらの派生型の中でも、スタック (
) やリストボックス (stack
) などは、基本的なボックスよりも複雑なレイアウトを行うために必要になりますが、 ボタンなどそれ以外のものは、独自のマウスとキーイベントの処理を追加するためのみに利用されています。listbox
単に CSS の display
プロパティが別のものに変更されるだけでも、要素に結びつけられたレイアウトオブジェクトは取り除かれて、代わりに全く異なる種類のオブジェクトが作成されることがあります。 例えば、ボタン要素の display
プロパティの値を、デフォルトの -moz-box
から、HTML のブロック要素で使用される block
に変更した場合、ボタンのレイアウトオブジェクトは削除され、代わりにブロックオブジェクトが作成されることになります。 また、これに従って要素の外観と機能も変更されます。
XUL アプリケーションを開発するためだけであれば、レイアウトオブジェクトの構築方法について詳細を知る必要はありませんが、 少なくとも、上で述べた XUL レイアウトについての知識は、さらに高度な XUL 開発のために、非常に役に立つと思います。
ボックスオブジェクト
レイアウトオブジェクトは、XUL のレイアウトコンポーネントが内部的に使用するものなので、 開発者が操作を行うためにアクセスすることはできません。 しかしながら、XUL ではその代わりにレイアウトを操作するためのヘルパーオブジェクトを提供しています。 これらはボックスオブジェクトと呼ばれており、レイアウトに関係する情報にアクセスすることを可能にします。 また、その名が示しているように、全てのボックスを基本とする要素で利用することが可能です。
ボックスオブジェクトにはいくつかの派生型がありますが、普段はそのうちの 1 組だけが利用されます。 それ以外のものは、全て特定の要素とともに利用されることが前提になっています。 このため、いくつか関数は持っているものの、直接要素にマップされたメソッドの方が簡単にアクセスできるため、ボックスオブジェクトの方は利用されません。 しかしながら、基本ボックスオブジェクト、あるいは (派生型が実装する) BoxObject インターフェイスには、XUL で開発する上で非常に有用なプロパティがいくつかあります。
この基本ボックスオブジェクトには、2 つの便利な機能があります。 1 つめは、XUL 要素が表示されている位置とサイズを取得する機能で、 2 つめは、ボックスの中に表示される要素の並び順序を調べる機能になります。 なお、この順番は、要素が DOM に格納されている順番とは異なる場合があります。
要素の位置とサイズを取得する
ボックスオブジェクトには、要素の位置とサイズを知るための 4 つのプロパティ x
、y
、width
、height
があります。 x
と y
は、ウインドウ内に置かれた文書の左上隅 (ウインドウの枠とタイトルバーを除いたところ) からの相対的な画素数による座標を表します。 width
と height
プロパティも、単位は画素数で CSS の padding
と border
を、(もしあれば) 含めた上での要素の幅と高さを返します。
これらの値は、常にそのときの表示位置と表示サイズになるため、要素の移動やリサイズを行った場合、それに応じて変更されます。 例えば、伸縮可能な要素のサイズを変更した場合、ボックスオブジェクトの寸法もそれに伴って更新されます。 この挙動は、以下の例で確認できます。
var el = env.locale; 例 1 : ソース 表示
<button label="Click Me" oncommand="alert('The width is ' + this.boxObject.width);"/>
普通は、要素自身が内容に合わせて適切なサイズを定めるため、あまり利用しませんが、 要素に対して width
と height
属性を設定することで、個別に幅と高さを指定することが可能です。 これらの属性は、デフォルトのサイズを指定されたサイズで上書きするため、 要素を特定のサイズで表示させたいのであれば、 属性に対応する、width
と height
プロパティを利用して、 いつでも要素の寸法を調整することができます。 明示的にサイズを設定した要素に対してこれらのプロパティの値を取得した場合、設定されているサイズが戻ります。 width
または height
属性 (またはプロパティ) が設定されていない場合は、空文字列が戻ることに注意してください。 これは、これらのプロパティから、そのときのサイズを取得することはできないということを意味しています。 そのときのサイズが必要な場合は、ボックスオブジェクトのプロパティを利用しなければなりません。
少しばかり混乱させたかもしれませんが、要約すると、要素の width と height プロパティが XUL で設定されたサイズを返すのに対して、ボックスオブジェクトの width と height プロパティは現在の表示サイズを返すということになります。
隠された要素と折り畳まれた要素
属性を指定すると、要素は表示されないように隠されます。 表示がされないために、ボックスオブジェクトの位置とサイズを表す 4 つのプロパティの値は、すべて 0 になります。 要素が隠されると、表示から取り除かれてレイアウトオブジェクトも削除されます。 どこにも表示されていないので位置もサイズも持っていません。
また、
属性を指定した場合は、要素は表示されないように折り畳まれます。 この属性も利用者に対しては、要素の表示という点で collapsed
と同じ効果を与えますが、 内部的には、要素のサイズが 0 に変更されるだけで、要素自体は画面に残り、レイアウトオブジェクトも完全に保持されます。 まとめると、
によって隠されても、
によって折畳まれても、要素の幅と高さは 0 になります。 また、隠されている要素の位置 x と y は 0 である一方、折り畳まれている要素では、ウインドウ内の位置が維持されます。collapsed
と
の状態の取得と設定は、対応するプロパティを利用することで可能です。 以下に例を示します。collapsed
var el = env.locale; 例 2 : ソース 表示
<script> function showPositionAndSize() { var labelbox = document.getElementById('thelabel').boxObject; alert("Position is (" + labelbox.x + "," + labelbox.y + ") and size is (" + labelbox.width + "," + labelbox.height + ")"); } </script> <button label="Hide" oncommand="document.getElementById('thelabel').hidden = true;"/> <button label="Show" oncommand="document.getElementById('thelabel').hidden = false;"/> <button label="Collapse" oncommand="document.getElementById('thelabel').collapsed = true;"/> <button label="Uncollapse" oncommand="document.getElementById('thelabel').collapsed = false;"/> <button label="Show Position/Size" oncommand="showPositionAndSize();"/> <label id="thelabel" value="I am a label"/>
この例で、ラベルを隠して、かつ折り畳んだ場合、隠されたものとして扱われることに注意してください。 といっても、この場合も折り畳み状態が解除されたわけではないので、ラベルを再び表示させるためには、隠した状態と折り畳んだ状態の両方を解除する必要があります。
XUL 要素の並び方
ボックスオブジェクトは、要素の表示上の並び順を特定するために利用できます。 この並び順は、ソース内での順序と異なっている可能性があります。 childNodes
、firstChild
、nextSibling
といった DOM プロパティが、文書ツリー内での要素のナビゲーションに利用できることを思い出してください。 ボックスオブジェクトでも、同じような処理が可能ですが、要素は表示上の並びに従って取得されます。
ボックスオブジェクトには、このためにプロパティとして firstChild
、lastChild
、nextSibling
、previousSibling
、parentBox
が用意されています。 これらは、それぞれの名前が示すままの機能を持ち、戻り値として要素を返します。 例えば、firstChild
プロパティは、ボックス内の最初の位置に表示されている子要素を返します。 なお、ボックスには DOM の childNodes
プロパティに対応するものが存在しません。 このため、同様の処理を行うには、nextSibling
、あるいは previousSibling
プロパティを利用して、隣接ノードを取得していくことで次の処理対象を選択していく必要があります。
ボックスオブジェクトのナビゲーションでは、 によって隠された要素が除外される点が、DOM ツリーのナビゲーションとは異なっています。 つまり、6 つの子要素を持つボックスで、最初の 2 つが隠されていた場合、
firstChild
プロパティは 3 番目の要素を返します。 一方、collapsed
によって折り畳まれた要素は、サイズは 0 であるものの、依然として表示はされているため、ボックスオブジェクトのナビゲーションにも含まれることになります。 例えば、以下のボックスでは、「Button 2」は隠されているため、「Button 1」の隣接要素は「Button 3」になります。 また、「Button 4」は折り畳まれているだけなので、「Button 3」の隣接要素は、「Button 4」になります。
var el = env.locale; 例 3 : ソース 表示
<hbox> <button label="Button 1" oncommand="alert('Next is: ' + this.boxObject.nextSibling.label);"/> <button label="Button 2" hidden="true"/> <button label="Button 3" oncommand="alert('Next is: ' + this.boxObject.nextSibling.label);"/> <button label="Button 4" collapsed="true"/> </hbox>
ボックスの並び制御属性
XUL ボックスがウインドウ上で配置されるとき、子要素はいくつかのプロパティ、 具体的には、縦か横かを示すための「方向 (orientation) 」「並びグループ (ordinal group)」正順か逆順かを示す「順序 (direction) 」を元にして並べられます。
orient 属性
通常、方向は
属性により変更されます。 また、状況に応じて対応する CSS プロパティ orient
-moz-box-orient
を代わりに利用することも可能です。 この属性については、以前のボックスについてのセクションで説明されています。
ordinal 属性
属性は、要素の並びグループの指定に利用します。 これは、CSS プロパティ ordinal
-moz-box-ordinal-group
を利用することでも指定可能です。
ordinal
によって、より小さな並びに設定された要素は、より大きな並びに設定された要素よりも、ボックス内で前に配置されます。 例えば、ordinal
が 2 の要素は、ordinal
が 3 以上の要素より前に位置し、ordinal
1 の要素の後に位置することになります。 ordinal
のデフォルト値は 1 です。 このため、要素の並び順を変えたい場合、たくさんの要素の ordinal
を変更する必要があるときがしばしばあると思います。
通常は、要素の並び順を変えたい場合、単にソース内に記述する順番を変えれば済むため、 ordinal
で要素の並びを調整することは、あまり一般的なことではありません。 しかし、この操作は DOM を変更せずに、後から項目の並び替えを行うために利用できます。 以下に例を示します。
var el = env.locale; 例 4 : ソース 表示
<hbox> <button label="One" oncommand="this.ordinal++;"/> <button label="Two" oncommand="this.ordinal++;"/> <button label="Three" oncommand="this.ordinal++;"/> </hbox>
最初に、ボタン「One」を押した場合、ordinal
が 1 から 2 に加算されます。 他のボタンの ordinal
は 1 のままなので、ボタン「One」は最後に表示されるようになります。 次に、ボタン「Two」を押すと、 ordinal
が 1 増えて、ボタンは行末へ移動します。 これは、ordinal
が同じ項目は、ソース内と同じ順序で表示されるためです。 更にもう一度、ボタン「One」を押すと、ordinal
が 3 に増えて、末尾に移動します。 最後に、ボタン「Three」を押すと、ordinal
は 2 に増え、他の 2 つのボタンの間に表示されます。
dir 属性
ボックスの並び制御属性の最後は
属性で、対応する CSS プロパティは dir
-moz-box-direction
になります。 この値が reverse
に設定されると、ボックス内のすべての子要素は逆順に並んで表示されます。 つまり、水平ボックスでは右から左へ、垂直ボックスでは下から上へ要素が配置されていくことになります。 以下に例を示します。
var el = env.locale; 例 5 : ソース 表示
<hbox dir="reverse"> <button label="Left"/> <button label="Center"/> <button label="Right"/> </hbox>
ボックスオブジェクトの並び順によるノードのナビゲーションでは、
によって調整された順番で要素が返されます。 このため、要素の ordinal
を変更した場合は、ボックス内の並び順も変更されます。 一方、ordinal
によって順序を逆にしたとしても、ボックス内の並び順は変更されません。dir
次のセクションでは、 XUL とスクリプトから XPCOM オブジェクトを利用する方法について見ていきます。