前回のセクションの Hello World の例では、最も一般的なツールメニューへの追加 (推奨) とメインメニューバーへの追加 (非推奨) の 2 通りの方法でメニューを追加しました。このセクションでは、さらに専門的なメニューとその扱い方を見ていきます。
新しいメニューの追加
私たちはすでにオーバーレイでメニューを追加する方法を説明しているので、サブメニューを入れ子にする方法のイメージが掴めるでしょう。しかし、ユーザを混乱させないように、すべてのオプションをメニューに含めるようなことは避けなければなりません。
あなたの拡張機能が新しい XUL ウィンドウを必要とする場合は、menubar 要素で、それらのウィンドウにメニューを追加できます。menubar 要素は、Mac OS X 以外のシステム上ではもう一つのツールバーとして扱われるため、toolbox 要素の子要素にしなければなりません。これらのシステムでは、ツールバーをカスタマイズして、ツールバーコントロールをメニューバー上に移動することができます。
Mac OS X は、他のシステムとかなり異なる方法でメニューを扱います。あなたの拡張機能がメニューを別の方法で追加する場合は、Mac OS X 上でテストし、すべて適切に動作することを確認してください。
toolbox は、XUL ドキュメントの先頭に記述されなければなりません。コードは次のようになります:
<toolbox>
<menubar id="xulschoolhello-menubar">
<menu id="xulschoolhello-greeting-menu" label="&xulschoolhello.greeting.label;">
<menupopup>
<menuitem label="&xulschoolhello.greet.short.label;"
oncommand="XULSchoolChrome.GreetingDialog.greetingShort(event);" />
<menuitem label="&xulschoolhello.greet.medium.label;"
oncommand="XULSchoolChrome.GreetingDialog.greetingMedium(event);" />
<menuitem label="&xulschoolhello.greet.long.label;"
oncommand="XULSchoolChrome.GreetingDialog.greetingLong(event);" />
<menuseparator />
<menuitem label="&xulschoolhello.greet.custom.label;"
oncommand="XULSchoolChrome.GreetingDialog.greetingCustom(event);" />
</menupopup>
</menu>
</menubar>
</toolbox>
このコードは、簡単な menu を表示し、3 種類の異なる挨拶のオプションと menuseparator を持ち、最後にカスタムの挨拶のオプションがあります。セパレータは、異なる種類の menuitem 要素を分ける水平線として表示され、メニューアイテムを整えるために使用されます。
menubar は、一つ以上の menu 要素を保持できます。メニューは、menupopup 要素をコンテナにする必要があり、その子要素に menuitem 要素や menuseparator 要素だけでなく、メニューを入れ子にするための menu 要素を持つことができます:
<toolbox>
<menubar id="xulschoolhello-menubar">
<menu id="xulschoolhello-greeting-menu" label="&xulschoolhello.greeting.label;">
<menupopup>
<menu id="xulschoolhello-greeting-sizes-menu" label="&xulschoolhello.greetingSizes.label;">
<menupopup>
<menuitem label="&xulschoolhello.greet.short.label;"
oncommand="XULSchoolChrome.GreetingDialog.greetingShort(event);" />
<menuitem label="&xulschoolhello.greet.medium.label;"
oncommand="XULSchoolChrome.GreetingDialog.greetingMedium(event);" />
<menuitem label="&xulschoolhello.greet.long.label;"
oncommand="XULSchoolChrome.GreetingDialog.greetingLong(event);" />
</menupopup>
</menu>
<menuitem label="&xulschoolhello.greet.custom.label;"
oncommand="XULSchoolChrome.GreetingDialog.greetingCustom(event);" />
</menupopup>
</menu>
</menubar>
</toolbox>
上記の例では、3 個の挨拶アイテムをサブメニューにグループ化しました。分かりづらいかもしれませんが、メニューを 2 個だけに減らし、そのうちの片方は 3 個のアイテムをサブメニューにしています。
メニューを動的に生成することもできます。menupopup 要素を XUL ドキュメントに直接置く代わりに、popup が表示される時に発生する onpopupshowing イベントを利用して子要素を生成してください。
メニューに表示するアイテムが無いときは、Firefox の標準に従ってください。無効化された "(空)" ラベルのアイテムを表示します。
メニューの生成に時間がかかるときは、何かを表示するまで Firefox (またはユーザ) を待たせてはいけません。非同期でコンテンツを生成していることをユーザに知らせるため、読み込み中のインジケータ画像 (chrome://global/skin/icons/loading_16.png を参照) を表示するとよいでしょう。このチュートリアルでは、いくつかの非同期のテクニックを扱います。
既存のメニューへの要素の追加
前回のセクションで説明したとおり、拡張機能のメニューのオーバーレイを適用する場所は ツール メニュー内が最適です。ここは、あなたの拡張機能のメニューを置く分かりやすい場所が、他に無い場合に使用するとよいでしょう。ツールメニューにオーバーレイを適用する場合のコードは、次のようになります。
<menupopup id="menu_ToolsPopup">
<menu id="
xulschoolhello-hello-menu" label="&xulschoolhello.hello.label;"
accesskey="&xulschoolhello.helloMenu.accesskey;"
insertafter="javascriptConsole,devToolsSeparator">
<menupopup>
<!-- ここにメニュー項目を -->
</menupopup>
</menu>
</menupopup>
次は、いくつかの特殊なメニューアイテムを見ていきましょう。
メニューの種類
チェックボックスメニュー
ユーザがメニューでオプションの有効化と無効化を切り替えられるようにするため、menuitem 要素を "チェック可能" にし、メニューアイテムに直接チェックを入れたり外したりできます。このために、type と checked の 2 個の属性が用意されています。type 属性の値は "checkbox" に設定してください。デフォルトでチェックが入った状態にするには、checked 属性の値を "true" に設定してください。
アイテムのチェック状態は、ユーザがメニューアイテムをクリックすると切り替わります。チェックボックスメニューの例は、Firefox のメインメニューの [表示] > [ステータスバー] を見てください。
ラジオメニュー
menuitem 要素の集合の中で一度に一つのアイテムにチェックを入れたいときは、type 属性の値を "radio" に設定します。また、ラジオグループの中でアイテムを特定できるようにするために、name 属性を使用します。
<menupopup oncommand="XULSchoolChrome.HW.GreetingDialog.greeting(event);">
<menuitem type="radio" name="xulschoolhello-greeting-radio"
label="&xulschoolhello.greet.short.label;" checked="true" />
<menuitem type="radio" name="xulschoolhello-greeting-radio"
label="&xulschoolhello.greet.medium.label;" />
<menuitem type="radio" name="xulschoolhello-greeting-radio"
label="&xulschoolhello.greet.long.label;" />
</menupopup>
これは、挨拶メニューの変更バージョンです。3 つの選択肢からラジオメニューで選べるようになりました。最初のアイテムにはデフォルトでチェックが入ります。また、menupopup にセットされた oncommand 属性によってコードの重複を避け、3 個のアイテムから同じ関数を呼ぶように変更しています。
ラジオメニューのもう一つの例は、[表示] > [サイドバー] メニューです。サイドバーをいくつかの選択肢の中から選ぶと、一度に一つだけ表示されます。
画像付きメニュー
menu や menuitem にアイコンを追加するには、その class 属性に "menu-iconic" または "menuitem-iconic" を設定し、image 属性または list-style-image CSS プロパティを設定します。メニューアイコンの大きさは、一般的に 16px × 16px です。
Mac OS X 上のメニュー
先にも述べたように、Mac OS X 上のメニューは他のシステムと異なります。Mac のメニューは、オペレーティングシステムによってコントロールされる単一のメニューバーに統合されているため、他のシステムのように Firefox から全体をコントロールできるメニューとは対称的です。また、Mac OS X のメニューには標準が定められており、他のシステムでは使用されないアイテムが配置されています。以下は、Mac 上のメニューを扱うときに陥りがちな既知の問題のリストです。
- [Firefox について]、[環境設定]、[終了] の各メニューアイテムは、"Firefox" メニュー下に配置され、他のシステムと異なる場所になります。これらのアイテムは DOM を通してアクセスできますが、その親メニューへは簡単にアクセスできません。
- 特にルートメニュー (ファイル、編集、表示、他) のアイテムに対してアイテムの追加、削除、有効化、無効化を動的に行うとバグに陥ります。このような動作は、あなたの拡張機能で正しく動作するように、慎重にテストしてください。
- メニューアイテムの画像は正しく表示されません。代わりに、画像の一部分のみが表示されます。これは、リモート画像を使用すると起こるようです。
- メニューアイテムは、メニューを開いている間は動的に更新されません。例えば、現在時刻を表示し、毎秒更新される menuitem を作成した場合、他のシステムではメニューを開いたままでも表示が更新されますが、Mac OS 上では更新されません。