株式会社クリアコード/下田 洋志 SHIMODA Hiroshi
http://www.clear-code.com/

拡張機能の開発の仕方を学ぶ前に,まずは拡張機能を作るための基盤となる技術の「XUL(XML-based User-interfaceLanguage)」について学びましょう.

はじめに

XULの概要

XULは,MozillaブラウザのGUI記述言語として開発された,XMLベースの言語の一種です.XUL以前にも,HTMLとスクリプト言語の組み合わせによってアプリケーションのGUIを開発する試みは古くからあり,XULはその発展形と言えます(▽注1).Webページがプラットフォームの違いに関係なく表示されるのと同じように,XULで記述されたアプリケーションも,Firefox が動作する環境ならどこでも同じように動作します.

HTMLは元々Webページという文書を記述するための言語なので,アプリケーションを記述するには機能が貧弱なのは否めません.その点,XULは本格的なUI記述用言語なので,特にスクリプトを駆使しなくても,タグを書くだけで高機能なUI部品を挿入することができます.

なお,W3Cなどの標準化団体によって仕様が策定されている言語と異なり,XULには現在,明確な仕様書がありません(▽注2).本章では,Firefox 3で盛り込まれることが予定されている機能にも一部触れながら,基本的にはFirefox 2での実装に基づいて解説を行います.

また,本章では各要素の説明に際して,ソースコードを例示しながら解説を行っています.実際にソースコードを手元で入力してFirefoxに読み込ませ,挙動や表示を確認してみてください.ソースコードは次のURLからダウンロードできます.

http://piro.sakura.ne.jp/xul/doc/200704softwaredesign/samples.zip

XULの表示方法

XULはFirefoxやThunderbirdなどのMozillaアプリケーションや拡張機能の開発に用いられる場合がほとんどですが,FirefoxやGecko エンジンを使用したその他のWebブラウザでは,Web上のコンテンツにおいてもXULを使うことができます(▽注3).例えば本章のサンプルコードを実際に試してみるには,内容をテキストファイルに保存して拡張子を「.xul」に変更し,Firefox のブラウザウィンドウにドラッグ&ドロップしてください.

FirefoxのGUIを表示せずに特定のXULファイルの内容のみを読み込ませたい場合,Firefoxの起動オプションで「-chrome "ファイルのURL"」と指定して起動します.

また,リスト1のように,XULのウィンドウ内でのみ利用できるwindow.openDialogメソッドを使う方法もあります.拡張機能において別のウィンドウを開く場合にはこちらの方法を使います.

リスト1:FirefoxのGUIが無いウィンドウを開く例
window.openDialog('another.xul', '_blank','chrome,all,dialog=no');

XMLアプリケーションとしてのXUL

リスト2はXULで記述したGUIの定義ファイル(以下,XUL文書)の例です.XULは基本的にはwindow要素をルート要素として,名前空間URIには「http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul」を指定します.文字エンコーディングをUTF-8にする場合は,エンコーディング指定やXML宣言を省略できます.本章で紹介しているコードの例を試す場合も,こちらに内容を記述してください.

リスト2:XUL文書の基本形
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="chrome://global/skin/"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    <!-- ここに内容を置く-->
</window>

XUL文書もXML文書なので,XHTML,SVG,MathMLなどの要素を埋め込んだり,外部エンティティ参照を利用してXUL文書の内容をモジュール化したり,DOMやXLink,XSLTなどのXML関連技術と組み合わせたりと,さまざまな応用が可能です.

Firefoxや拡張機能の国際化においても,こういったXMLの機能が活用されています.

スタイルシートの読み込み

XULでは要素の細かい外観はCSSで指定します.XULもXMLの一種なので,スタイルシートの読み込みにはxml-stylesheet処理命令を使うことになります.

リスト2においても,2行目の記述によってテーマの標準的なスタイル指定を読み込むようにしてあります.「chrome://global/skin/」という内部の特殊なスタイルシートを参照することで,ラベルやボタンなどの文字の大きさ,ウィンドウの背景色などを現在Firefoxで選択されているテーマに合わせることができます.これ以外にも,自分で定義したスタイルシートを読み込ませることも可能です.

XULのボックスモデル

XULでは,原則としてすべてのUI部品を縦横2種類のボックスの組み合わせで配置します.要素の配置には,リスト3のように,要素を横(水平)方向に並べるためのhbox(horizontal box)要素と,縦(垂直)方向に並べるためのvbox(vertical box)要素を使います.Firefoxに読み込ませると,図1のように表示されます.

リスト3:縦横のボックスの例
<label value="水平配置"/>
<hbox>
    <button label="horizontal1"/>
    <button label="horizontal2"/>
</hbox>
<label value="垂直配置"/>
<vbox>
    <button label="vertical1"/>
    <button label="vertical2"/>
</vbox>
<label value="併用"/>
<hbox>
    <button label="mixed1"/>
    <vbox>
        <button label="mixed2"/>
        <button label="mixed3"/>
    </vbox>
    <button label="mixed4"/>
</hbox>
図1:リスト3の表示結果
[図1]
orient

ボックスの内容が縦横どちらに並ぶかは,初期状態では要素によって異なります.orient属性を使うと,この配置方向を明示的に指定・変更することができます.「horizontal」で内容が横に,「vertical」で縦に並ぶようになります.

alignとpack

align属性とpack属性は,どちらもボックス内の要素の配置を指定するものです.それぞれstart(上または左),center(中央),end(下または右),stretch(一番大きな幅・高さの要素に合わせて他の要素を伸縮)のうちいずれかを設定できます.

align属性はorient属性の指定の軸に直交する方向の配置を,pack属性はorient属性の指定の軸に沿った方向の配置を決定します.図2はどちらも「align="center" pack="start"」の状態ですが,alignとpackの指定が同じでも,それぞれの作用する方向はorientの値によって変わります.

この他にも,HTMLでのtable要素を用いたようなレイアウトを実現するgrid要素や,要素を重ね合わせてレイアウトするstack要素などもあります.XULでは,これらのボックスを使って各種のウィジェット(GUI部品)を配置していくことで,複雑なインターフェースを構築することができます.

共通属性

個別のGUI部品について紹介する前に,すべての要素で利用できる共通の属性の中でも,特に頻出するものを紹介します.

idとclass

idとclassは,XHTMLの同名の属性と同様の働きをする属性です.idで一意な名前を定義したり,classで要素を分類したりすることで,CSSやJavaScriptなどからその要素を簡単に参照できます.また,他の要素からidを参照することで初めて機能を発揮する特殊な要素もあります.

図2:alignとpackの意味はorientに応じて入れ替わる
[図2]

なお,これらの属性の初期値は,alignがstretch,packがstartです.先ほどの図1において一番下の行の左右のボタンが縦に大きく広がっているのも,中央の縦に並んだ2つのボタンの高さに合わせて左右のボタンの高さが調節されているからです.

flex

通常,要素の高さや幅は固定されています.ウィンドウの幅や高さいっぱいに要素を広げて表示するには,flex属性を指定します.

flex属性は親要素のorient属性で示される配置方向に対する伸縮率を正の整数で指定するもので,「flex="1"」と記述することで,要素がその方向いっぱいに広がります.「flex="1"」を指定された要素が2つ以上並んだ場合,それぞれの大きさは等分になるように調整されます.特定の要素だけを大きめに表示させたい場合,「flex="2"」などのように異なる値を指定します.例えばリスト4のような場合,2つ目のラベルは1つ目のラベルに対して2倍の大きさで表示されることになります(図3).

リスト4:flex属性による伸縮
<hbox>
    <label value="label1" flex="1" style="border: 1px solid;"/>
    <label value="label2" flex="2" style="border: 1px solid;"/>
</hbox>
図3:リスト4の表示結果
[図3]
ordinal

XULのボックス内では,要素は基本的に,ソース内に記述されたとおりの順番(上から下,左から右)で表示されます.ordinal属性を使うと,この配置順を入れ替えることができます.ordinal属性はボックスの配置順を正の整数で指定するもので,例えばリスト5のような場合,3つのボタンは実際には「button3」「button2」「button1」の順に表示されます(図4).

リスト5:ordinal属性で順番を入れ換える例
<vbox>
    <button label="button1" ordinal="3"/>
    <button label="button2" ordinal="2"/>
    <button label="button3" ordinal="1"/>
</vbox>
図4:リスト5の表示結果
[図4]

ordinal属性に同じ値を指定された要素が複数ある場合は,同じ値を持った要素同士がソース中での登場順に並ぶことになります.なお,ordinal属性の初期値は「1」です.

ボックスの大きさ

XUL要素の大きさを明示的に指定するには,リスト6のようにwidth属性とheight属性を使います.また,flex属性によって伸縮できるようにした場合の最小サイズを設定するためのminwidthとminheight,最大サイズを設定するmaxwidthとmaxheightも利用できます.いずれも単位はピクセルです.

また,リスト7のようにstyle属性を使ってインラインでCSSのスタイル指定を埋め込めば,ピクセル以外の単位でも要素の大きさを指定できます.

リスト6:サイズを指定したボタン
<button label="Button" width="200" height="100"/>
リスト7:CSSの記法でサイズを指定したボタン
<button label="Button" style="min-width: 10em;"/>
hiddenとcollapsed

要素の表示・非表示を切り替えるには,hidden属性もしくはcollapsed属性を使用します.

「hidden="true"」と指定すると,その要素は非表示になります.これはCSSで「display: none」と指定した場合と同じ効果です.コンテキストメニューの表示されていない項目のように,「存在していない・隠された」状態を表すにはこちらを使います.

「collapsed="true"」と指定した場合,要素の幅も高さも0の状態になりますが,要素自体は存在するものとして扱われます.こちらはCSSで「visibility: collapse」と指定した場合と同じになります.使っていないときのサイドバーのように,「折りたたまれた」状態を表したい場合はこちらを使います

disabled

すべての要素で利用できるわけではありませんが,ユーザの操 作を受け付ける要素では,入力を一時的に無効にするための disabled属性が利用できます.「disabled="true"」と指定された 要素は多くの場合,半透明や薄いグレーなどで表示されます.

なお,hidden,collapsed,disabledのような真偽値型の属性は,XULにおいては「disabled="false"」のようにfalseを値として指定すると,意図しない動作になることがあります.これは一部のスクリプトやCSSの指定において,属性に何か値が指定されていれば無条件でtrueと見なすように記述されている場合があるためです.たとえばDOMの機能で属性の値を変更する場合には,
「setAttribute('disabled', false)」ではなく,
「removeAttribute('disabled')」と記述したほうが良いでしょう.

tooltiptext

要素の上で簡単な説明をツールチップ形式で表示させたい場合は,tooltiptext属性を使います.この属性に文字列を指定すると,値がツールチップの内容として表示されます.

persist

XUL要素の状態がユーザの操作によって変更された後,その状態を記憶・保持させておく簡易的な方法として,persist属性があります.persist属性に,値を保存しておきたい属性の名前を半角スペースで区切って列挙すると,そのXUL文書を次に読み込むとき,保存されていた値が自動的に復元されます(▽注4).4章で紹介する設定システムや,複雑なスクリプトを使わない簡易的な状態保持用に利用できます.

なお,persist属性で他の属性の状態を記憶させるには,その要素に何らかのidが指定されている必要があります.

コラム

属性での指定をCSSで代替する

Geckoレンダリングエンジンでは,まだW3Cの勧告になっていない仕様の先行実装やXUL用の専用プロパティとして,接頭辞に「-moz-」が付いた独自拡張のCSSプロパティをいくつか利用できます.それらの中には表Aのように,XULの共通属性に対応するプロパティがあります.XULの共通属性の働きは,実際にはこれらのCSSプロパティによって実現されています.

これらのプロパティに指定する値は,XUL属性の場合と同じで整数値またはキーワードです.通常のXULを使った開発でこれらのプロパティを使うことはあまりお勧めできませんが,userChrome.cssでこれらを利用すれば,スクリプトに頼らずにFirefoxのUIをカスタマイズする役に立てることができます.たとえば,リストAの内容をuserChrome.cssという名前でユーザプロファイルフォルダのchromeフォルダ内に保存すると,タブバーをコンテンツエリアの下に移動できます.

表A:XULの属性に対応する独自拡張CSSプロパティ
XUL属性CSSプロパティ記述例
orient-moz-box-orient-moz-box-orient: vertical;
align-moz-box-align-moz-box-align: start;
pack-moz-box-pack-moz-box-pack: stretch;
flex-moz-box-flex-moz-box-flex: 1;
ordinal-moz-box-ordinal-group-moz-box-ordinal-group:
リストA:タブを下に移動するユーザースタイルシートの例
tabbrowser .tabbrowser-strip {
  -moz-box-ordinal-group: 2;
}
tabbrowser tabpanels {
  -moz-box-ordinal-group: 1;
}

XULで利用できるウィジェット

その他のXUL の機能

△注1同様のアプローチとして,Windows Vistaから採用されたXAMLや,Adobe Flash用のFlexなどがあります.
△注2XUL 1.0(https://developer.mozilla.org/ja/XUL)という仕様書としてのドキュメントは存在しますが,2001年の時点での実装や構想に基づく記述なの で,現在のXULとは異なる部分が多々あります.XUL の最新の仕様については,MDC内のリファレンス(https://developer.mozilla.org/ja/XUL_Reference)や Mozilla Wiki内のXULのページ(https://wiki.mozilla.org/XUL)などを参照してください.
△注3例として,Amazonでの買い物を支援する「Mozilla Amazon Browser」(http://www.faser.net/mab/chrome/content/mab.xul)や,筆者が開発・公開しているプレゼンツールの「高橋メソッド in XUL」(http://piro.sakura.ne.jp/xul/applications/takahashi-r/)などがあります.
△注4これらの値はユーザプロファイル内のlocalstore.rdfというファイルに保存されます.