このセクションでは、共通するコンテントを分離するために利用可能なオーバーレイについて説明します。
オーバーレイを使う
通常、ウィンドウを 1 つしか使わないような単純なアプリケーションは、 XUL ファイルが 1 つと、スクリプトファイル、スタイルシート、DTD ファイルが それぞれ1 つ、後はいくつかの画像ファイルから構成されるのが一般的だと思います。 また、もう少し複雑なアプリケーションでは、いくつか関連するダイアログを持っていて、 これらのダイアログは独立した XUL ファイルに保存されることになるはずです。 さらに、もっと複雑なアプリケーションの場合は、多数のウィンドウやダイアログが含まれることになります。
いくつかのウィンドウを持つアプリケーションには、それぞれのウィンドウ間で共通する要素やユーザインターフェイスの部品が多数存在しているはずです。 例えば、Mozilla スイートでは、(ブラウザやメールといった) 各コンポーネントで、いくつかの共通する要素を共有しています。 具体的には、ツールやヘルプといった、いくつかのメニューや、サイドバーが類似していますし、 各ウィンドウは、いくつかの共通するグローバルなキーボードショートカットを共有しています。
こういった場合に、類似した要素や機能を、必要なファイルでそれぞれ再実装していくのも、1 つの方法ではあると思います。 しかしながら、その方法をとると、何か変更を行おうとするときには、多くの場所を修正しなければならなくなり、メンテナンスが困難になってしまいます。 このため、共通する要素は分離して、ウィンドウ間で共有するようなメカニズムを使う方が、より優れた方法になるはずです。 この方法は、オーバーレイを利用すれば可能になります。
オーバーレイの内部には、そのオーバーレイを利用する全てのウィンドウで共有する要素を置くことになります。 これらの要素は、各ウィンドウに対して、その id を元に決定された場所に追加されます。
例えば、いくつかのウィンドウで共有するヘルプメニューを作りたいとします。 このヘルプメニューは、オーバーレイの方に置くことになりますが、記述は通常と同じ XUL を使用して行います。 このメニューには、識別のために id 属性を与えておく必要があります。 そして、各ウィンドウでは、この後に説明するディレクティブ (directive) を使ってオーバーレイのインポートを行います。 ウィンドウにオーバーレイで定義されたヘルプメニューを配置するために必要なことは、 メニュー要素を 1 つ追加して、その id 属性にオーバーレイに設定したものと同じ値を設定することだけです。 なお、このメニューは、子要素としてオーバーレイに置かれたものを利用するため、XUL 側に子要素を置く必要はありません。
オーバーレイを利用するウィンドウを開いたときに、ウィンドウとオーバーレイの両方に同じ id をもつ要素がある場合、1 つに結合されます。 マッチしたオーバーレイ側の要素の子要素は、ウィンドウ側の要素の子要素の後ろに追加されることになります。 また、オーバーレイ側の要素に設定された属性は、ウィンドウ側の要素に適用されることになります。 これらについては、後で詳細に説明します。
ファイル検索ダイアログの例
それでは、ファイル検索ダイアログにヘルプメニューのオーバーレイをインポートしてみましょう。 オーバーレイをウィンドウにインポートするために使用する構文 (ディレクティブ) は以下のようになりますので、これを XUL ファイルの先頭付近に追加してください。
<?xul-overlay href="chrome://findfile/content/helpoverlay.xul"?>
この行はファイルの先頭近くのどこか、通常は DTD を宣言するすぐ前に追加します。 上記の例では、ウィンドウは <tt>helpoverlay.xul</tt> ファイルに保存されたオーバーレイをインポートします。
オーバーレイ自体は XUL ファイルで、
要素が overlay
要素に代わって置かれますが、それ以外は通常の XUL ファイルとほとんど同じです。 オーバーレイ自身が、スタイルシートや DTD、スクリプトを持つことも可能ですし、 オーバーレイを他のオーバーレイからインポートしても構いません。window
単純なオーバーレイの例
以下の例は、オーバーレイとして記述された簡単なヘルプメニューを示しています。
例 1 : ソース
<?xml version="1.0"?>
<!DOCTYPE overlay SYSTEM "chrome://findfile/locale/findfile.dtd">
<overlay id="toverlay"
xmlns="https://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<menu id="help-menu">
<menupopup id="help-popup">
<menuitem id="help-contents" label="&contentsCmd.label;"
accesskey="&contentsCmd.accesskey;"/>
<menuitem id="help-index" label="&indexCmd.label;"
accesskey="&indexCmd.accesskey;"/>
<menuitem id="help-about" label="&aboutCmd.label;"
accesskey="&aboutCmd.accesskey;"/>
</menupopup>
</menu>
</overlay>
要素が、オーバーレイのコンテントを囲んでいます。 名前空間は、XUL ウィンドウのファイルと同じものを使用します。 オーバーレイの内部では、3 つの項目からなるメニューが 1 つ定義されています。 このメニューの overlay
id
は help-menu
で、 これは、ウィンドウの、同じ id 値を持つ類似の要素に、そのコンテントが追加されるということを意味しています。 また、ウィンドウ側に該当する要素がない場合は、オーバーレイの該当部分は無視されます。 オーバーレイには、必要ならばいくつでも要素を含めることが可能です。 なお、オーバーレイは DTD ファイルも読み込む必要があることに注意してください。 この例では、メインウィンドウと同じ DTD ファイルを使用していますが、 通常はオーバーレイごとに別の DTD ファイルを作るようにします。
次に、オーバーレイに作成したヘルプメニューを、ファイル検索ダイアログのウィンドウに追加する必要があります。 このために必要なのは、適切な場所に、同じ id をもつ menu
要素を加えることだけです。 この例の場合は、Edit メニューのすぐ後に置くのが良さそうです。
<menu id="edit-menu" label="Edit" accesskey="e">
<menupopup id="edit-popup">
<menuitem label="&cutCmd.label;" accesskey="&cutCmd.accesskey;"
key="cut_cmd"/>
<menuitem label="©Cmd.label;" accesskey="©Cmd.accesskey;"
key="copy_cmd"/>
<menuitem label="&pasteCmd.label;" accesskey="&pasteCmd.accesskey;"
key="paste_cmd" disabled="true"/>
</menupopup>
</menu>
<menu id="help-menu" label="&helpCmd.label;"
accesskey="&helpCmd.accesskey;"/>
</menubar>
このヘルプメニューの要素にはコンテントとして何も置かれていません。 このメニューの項目は、オーバーレイ側の要素と id がマッチするため、オーバーレイから取られることになるためです。 このオーバーレイは別のウィンドウからもインポートできるため、 このヘルプメニューのコンテントの定義はオーバーレイ 一個所にあるだけで構いません。 また、DTD ファイルにも、数行の追加を行っておく必要があります。
<!ENTITY helpCmd.label "Help">
<!ENTITY helpCmd.accesskey "h">
<!ENTITY contentsCmd.label "Contents">
<!ENTITY indexCmd.label "Index">
<!ENTITY aboutCmd.label "About...">
<!ENTITY contentsCmd.accesskey "c">
<!ENTITY indexCmd.accesskey "i">
<!ENTITY aboutCmd.accesskey "a">
<!ENTITY findfilehelpCmd.label "Find files help">
<!ENTITY findfilehelpCmd.accesskey "f">
上記の最後の 2 つの実体は、この後の説明で使用することになります。
オーバーレイに設定した属性は、各ウィンドウの要素に継承されます。 これを利用して、ウィンドウ側に記述するコード量をさらに減らすために、 ヘルプメニューの属性 (例では label
と accesskey
) をオーバーレイ側に移すことが可能です。 なお、オーバーレイとウィンドウの両方に同名の属性を指定した場合、 その要素が持つ値は、オーバーレイの値で上書きされることになります。
それでは、この方法でヘルプメニューを変更してみましょう。
findfile.xul:
<menu id="help-menu"/>
helpoverlay.xul:
<menu id="help-menu" label="&helpCmd.label;"
accesskey="&helpCmd.accesskey;">
重複コンテントの処理
XUL ウィンドウとオーバーレイの両方にコンテントがあるときには、 ウィンドウのコンテントはそのまま使用され、オーバーレイのコンテントがその後に追加されます。 以下の例は、この挙動を示しています。
stopandgo.xul: <?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?> <window title="Stop and Go" id="test-window" xmlns="https://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <?xul-overlay href="chrome://findfile/content/toverlay.xul"?> <box id="singlebox"> <button id="gobutton" label="Go"/> <button id="stopbutton" label="Stop"/> </box> </window> toverlay.xul: <?xml version="1.0"?> <overlay id="toverlay" xmlns="https://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <box id="singlebox"> <button id="backbutton" label="Back"/> <button id="forwardbutton" label="Forward"/> </box> </overlay>
この例では、singlebox
で識別されるボックスは、それ自身がコンテントを持っています。 さらに、要素がオーバーレイと結合されたことにより、オーバーレイの 2 つのボタンがボックスの末尾に追加されています。
ファイル検索ダイアログの例
このテクニックは、ファイル検索ダイアログにも使用できます。
findfile.xul:
<menu id="help-menu">
<menupopup id="help-popup">
<menuitem id="help-findfiles"
label="&findfilehelpCmd.label;"
accesskey="&findfilehelpCmd.accesskey;"/>
</menupopup>
</menu>
</menubar>
この
要素の menupopup
id
属性もオーバーレイのものとマッチします。 このため、両方のメニュー項目が 1 つのポップアップにマージされています。 このように、オーバーレイでは、他の要素の内側にある項目であっても、同じ id 属性を持っていればマージされることになります。
オーバーレイされた要素の配置
先述の例では、オーバーレイのメニュー項目をメニューの末尾に追加しましたが、 今度はこれをメニューの先頭に置く必要があるとしましょう。 XUL では、オーバーレイされた要素の配置のための仕組みを提供しており、 これを利用すれば単に先頭に置くだけでなく、 いくつかの項目は先頭に置き、残りを最後 (あるいは、その間の任意の場所) に置くといったことも可能になります。 つまり、これを利用することで、メニューやツールバーなどのウィジェットを、正確に必要な場所にオーバーレイすることが可能になります。
このためには、メニュー項目に対して
属性を使用します。 その項目は、この属性で指定した id を持つ要素の直前に挿入されることになります。 また、insertbefore
属性を使用すれば、指定の要素の直後に項目を挿入することも可能です。 なお、これらの属性は、直接指定されている要素だけに効果があります。 つまり、ある要素に insertafter
を指定しても、その後の要素は末尾に追加されることになります。 このため、その後の要素も全て前に表示させたい場合には、該当する全ての要素に insertbefore
を置く必要があります。insertbefore
また、特定のインデックスの位置を指定したい場合には、
属性を使用することが可能です。 このとき、最初のインデックスは 1 になります。position
それでは、先述の例の「Contents」項目と「Index」項目を、「Find files help」項目の前に表示するように変更し、「About」項目は最後に表示したままにしてみましょう。 このためには、メニューの「Contents」項目と「Index」項目の両方に
属性を追加します。 なお、完全に指定するべく、「About」メニュー項目に insertbefore
を追加しても構いませんが、 オーバーレイの項目は、デフォルトで末尾に表示されため必須ではありません。insertafter
先述のヘルプメニューの例では、ウィンドウ側のメニュー項目の id には help-findfiles
を設定しています。 このため、
属性には、この id と同じ値を設定する必要があります。 以下の例は、このための変更点を示しています。insertbefore
<menupopup id="help-popup"> <menuitem id="help-contents" label="Contents" insertbefore="help-findfiles"/> <menuitem id="help-index" label="Index" insertbefore="help-findfiles"/> <menuitem id="help-about" label="About..."/> </menupopup>
以下は (ファイル検索ダイアログなどの) ヘルプオーバーレイを使ったウィンドウを開いた場合に起こることを順に列挙していきます。
- オーバーレイに直接置かれている全ての項目、 つまり
要素の全ての子要素に対して、ベースとなるウィンドウに、同じ id の要素が存在するかが調べられます。 存在しない場合は、オーバーレイの要素は無視されます。 この例の場合は、overlay
help-menu
とhelp-popup
という id を持った要素が見つかることになります。 - 存在した場合は、オーバーレイの要素の属性が見つけられた要素にコピーされます。
- オーバーレイ側の要素の子要素はベースとなるウィンドウの要素の子要素として挿入されます。 この例の場合は、個々のメニュー項目が挿入されることになります。
- オーバーレイの要素に
属性があれば、その要素は、属性の値にマッチする id を持ったベースウィンドウの要素の直後に追加されます。insertafter
- オーバーレイの要素に
属性があれば、その要素は、属性の値にマッチする id をもつベースウィンドウの要素の直前に追加されます。insertbefore
- オーバーレイの要素に
属性があれば、その要素は、その属性で 1 から始まるインデックスによって指定された位置に追加されます。position
- それ以外の場合は、オーバーレイの要素は、最後の子要素として追加されます。
- オーバーレイの要素に
実際には、
と insertbefore
の値には、カンマで区切ったリストを指定することも可能です。 この場合は、リスト中の id のうちで、ウィンドウで最初に見つかったものが位置を決めるために使用されることになります。insertafter
ここまでのファイル検索ダイアログの例 : ソース
次のセクションでは、オーバーレイを異なるパッケージのウィンドウに適用する方法について見ていきます。