Mozilla extension とは、Mozilla ブラウザにインストールできる、 追加の機能を提供するものです。 (例えば Linky は、 ドキュメント中・選択範囲中の複数のリンクを一度に開く項目をコンテキストメニューに追加します) 。 このチュートリアルでは、現在の Mozilla のソースコードの状態 (最新のコードがコンパイルに成功し、テストを通ったかどうか) を示すアイコンをステータスバーに表示する Mozilla extension を作る過程を見ていきます。この extension は、 コードの状態を取得するために、ソースコードの状態を追跡する mozilla.org のウェブツールである Tinderbox にアクセスします。
このチュートリアルを修了すれば、 どのように Mozilla のユーザインターフェイス (UI) が構築されているのか、 どうやって拡張したい UI のソースコードを見つけるか、 インストールされている Mozilla に変更を加える前の準備、 Web ページを読み込み解析する Mozilla のネットワークライブラリを JavaScript から使う方法、 他のユーザが使えるように Mozilla extension をパッケージ化するための動的 overlay の使い方に関する基礎知識が得られるでしょう。
このチュートリアルを修了するには、次に挙げるプログラムが必要です。
前提知識として、 HTML のようなタグベースの言語に加え、基本的な JavaScript 、CSS 、 DOM についても理解しているべきです。 また、このチュートリアルの過程では Mozilla を何度もインストールすることになるので、 インストーラを手元に置いておくと便利でしょう。
もし今すでに Mozilla を使っているのなら、 このチュートリアルのデモ用の Mozilla を、 今インストールされているのとは別の場所にもうひとつインストールするべきです。 このチュートリアルでは、インストールした Mozilla を使えなくしてしまうかもしれない方法を紹介します。 このチュートリアルで普段使っている Mozilla を変更しないでください!
Tinderbox は Mozilla のソースコードの状態を追跡するウェブツールです。 これは Mozilla のビルドとテストを連続して行い、 結果をサーバに渡すクライアントマシンと、 その結果をウェブページで見られるようにするサーバから構成されています。 このツールによって、コンパイルや実行ができなくなるような (あるいは、妥協できるパフォーマンスやフットプリント (訳注:割り当てられた後、 解放されないメモリ領域の大きさのこと) が得られなくなるような) コードへの変更はすぐに mozilla.org に通知され、 問題を解決したり変更を元に戻したりしてもらうようにすることができます。
Mozilla エンジニアたちは、コードを変更する前に定期的に Tinderbox をチェックします。コードベースが壊れている間は、 コードベースへの変更が禁止されているためです。 Mozilla 保安官(コードを監視し、 破損箇所を修復してくれるエンジニアを探す交代制の役職) は、もっと定期的に Tinderbox をチェックしています。Tinderbox のページや Tinderbox サイドバーを開くのが難しいという事はありませんが、 ウェブページを開く、サイドバーを切り替える、 あるいはサイドバー自体を開くということすらなしに、 Tinderbox がチェックできたら便利になるでしょう。
様々な tinderbox クライアントマシンが様々な種類のビルド (各種のプラットフォーム向け) を行っていますが、ほとんどの人は、 失敗したクライアントがないかどうかしか気にしません。 まずビルドの失敗、次にテストの失敗をチェックすることで、 失敗したクライアントがあるかどうかを確実にユーザに示す事ができます。 もしビルドに失敗しているクライアントがあれば、 赤いアイコンを表示することにします。 全てのクライアントがビルドに成功していても、 テストに失敗したクライアントがあれば、 それを知らせるオレンジ色のアイコンを表示することにします。 全てのクライアントがビルドに成功し、 テストにも成功したと報告した場合に限り、 コードが全て良好である事を知らせる緑色のアイコンを表示することにします。
Mozilla の UI は、 XUL (後述), XBL (他のチュートリアルのトピック), JavaScript, CSS, そしてイメージファイルで構成されています。 XUL, XBL, JavaScript, CSS はテキスト形式のファイルで、 テキストエディタがあれば編集できます。 イメージファイルは GIF か JPG か PNG フォーマットのファイルで、 編集するには画像編集プログラムが必要です。
次に、 UI を構成するファイルは JAR アーカイブにまとめられます。 これはただの ZIP ファイルの拡張子を変えたもので、 "manifest" というファイルを含んでいます。これは、 アーカイブの内容について書いてある特別なフォーマットのファイルで、 Mozilla はこのファイルを読んで行うべき処理を決定します。
JAR アーカイブはバイナリファイルですが、Mozilla の UI はマシンコードにコンパイルされるわけではありません。Mozilla は、 起動する度にその UI をアーカイブ中のファイルからビルドします。 そのため、アーカイブ中のファイルを変更してアプリを再起動するだけで、 変更点の確認ができます。このため、Mozilla の UI はコンパイルベースのアプリケーションより修正が簡単になっています。
Mozilla の UI ファイルは通常 JAR アーカイブに格納されていますが、 代わりにアーカイブされていない形の UI ファイルを使うこともできます。 これは、コードを修正する前にアーカイブからファイルを取り出したり、 修正した後にアーカイブへファイルを追加したりする必要がないので、 extension の開発者にとってとても有効な手段です。 最初に一回だけアーカイブを解凍する必要がありますが、 それだけで後は好きなだけ変更ができます。
Mozilla を修正可能にするには、まず最初に unzip ユーティリティを使って アーカイブから UI ファイルを取り出します。 次に Mozilla の UI ファイルのレジストリを修正し、 オリジナルの JAR アーカイブの代わりに、 取り出したファイルを使うように設定します。 もし以下の説明でうまく動かない場合は、 Patch Maker を試してください。 このツールは、アーカイブからファイルを取り出し、 Mozilla のレジストリを書き換えるパッチを作ってくれます。
アーカイブは Mozilla がインストールされているディレクトリの chrome サブディレクトリに格納されています。 unzip ユーティリティを使って、ディレクトリにある .jar 拡張子のファイルを全て解凍しましょう。 .jar ファイルが配置されているのと同じディレクトリ (chrome ディレクトリ) に解凍したか確かめてください。 bash ライクなシェルがある Unix ライクな OS では、 chrome ディレクトリで次のコマンドを実行すれば、この作業は完了します。
for file in *.jar; do unzip $file; done
DOS のようなシェルを持つ OS では、次のコマンドを実行すれば作業完了です。
for %f in (*.jar); do unzip %f
(訳者注:上記のコマンドを実行すると、 replace (ファイル名)? [y]es, [n]o, [A]ll, [N]one, [r]ename: というプロンプトが何度か出ますが、全て A と答えてください) そのディレクトリにあるプラットフォーム固有のファイル -- en-mac.jar, en-unix.jar, そして en-win.jar -- については、 使っているプラットフォームに対応した物だけ解凍してください。 (訳者注:上記のコマンドを実行した場合は、 自分の使っているプラットフォームに対応した .jar ファイルをもう一度解凍して、ファイルを上書き (プロンプトに A と答える) してください)
ファイルを解凍したら、オリジナルの JAR アーカイブの代わりに 解凍されたファイルを使うように Mozilla chrome レジストリを修正します。 chrome レジストリとは、主要な Mozilla コンポーネントとその UI ファイルが chrome ディレクトリのどこに配置されているかが書かれているファイルです。 これは chrome ディレクトリの chrome.rdf と installed-chrome.txt のどちらか (または両方) にあたります。
このレジストリには、JAR アーカイブ内のディレクトリを指す jar:resource:/chrome/SOMETHING.jar!/SOMETHING-ELSE... という形の URL がいくつも含まれています。この URL が解凍したファイルを指すように、まず先頭の "Jar:" を取り除き、 次に真ん中ぐらいの "SOMETHING.jar!" という部分を取り除きます。 もし Perl が使えるなら、次のコマンドで行う事ができます。
perl -pi.orig -e "s/(jar:)|(\/[^.\/]+\.jar!)//g" chrome.rdf installed-chrome.txt
例えば、jar:resource:/chrome/comm.jar!/content/necko/ という URL は resource:/chrome/content/necko/ に変更されます。
ここまできたら、修正した Mozilla を起動してみましょう。 元々入っている Mozilla ではなく、新しくインストールして修正した Mozilla を起動していること、 もし Windows を使っていて "quick lanuch" 機能を有効にしているのなら "quick launch" を終了させたことを確認してください。 Mozilla が立ち上がり、普通のウェブブラウザウインドウが出てきたなら、 Mozilla を修正できるようになりました!
これで改造できる Mozilla が出来たので、 次は改造するファイルを探しましょう。Mozilla の UI は、三つのレイヤー 「構造」、「スタイル」、「ふるまい」に分かれています。 構造レイヤーは部品 (メニュー、ボタンなど) とそれらの UI 上での相対位置を定義します。スタイルレイヤーは部品の見え方 (サイズ、色、スタイルなど) やそれらの全体的な位置 (アライメント (訳注: 右寄せや中央寄せなどを定義する事) ) を決定します。 ふるまいレイヤーは、部品がどのように動作するか、 ユーザが部品をどう使うことができるかを指定します。
(注意: これらのレイヤーは完全に排他的ではではありません。例えば、 位置の情報は構造レイヤーとスタイルレイヤーの両方で指定できますし、 「ふるまい」の一部はスタイルレイヤーで定義できます。)
それでは、三つの UI レイヤーにコードを加えて行きましょう。 まずは構造レイヤーから始めます。構造レイヤーは XUL ファイルで構成されています。XUL は XML-based User Interface Language の略で ("Zool"(ズール)と発音します)、 アプリケーションのインターフェイスを記述するために設計された、 XML ベースの言語です。これは一般的なウィジェット (メニュー、ボタン、ツールバーなど) と、多くの洗練されたウィジェット (ツリー、ブラウザ、カラーピッカー) を含んでいます。
Mozilla のウィンドウやダイアログボックスでは、一つのウィンドウが一つの XUL ファイルで定義されています (overlay の仕組みを利用して、 他のウィンドウから一部を提供してもらう事もあります) 。tinderbox の状態を示すアイコンを Mozilla に加えるには、 まずはブラウザウィンドウの構造が一体どの XUL ファイルで定義されているのか探す必要があります。
ウィンドウに対応する XUL ファイルを見つけるには、 DOM Inspector を使うのが最もよい方法です。DOM Inspector は Mozilla に付属のツールで、 ウェブページおよび XUL ウィンドウの DOM を調べる事ができます。 DOM Inspector を起動するには、 "Tools" メニューから "Web Development" サブメニューを選択し、 "DOM Inspector" を選択します。 DOM Inspector が別ウィンドウで開きます。
DOM Inspector ウィンドウで、 File メニューから Inspect a Window サブメニューを選択し、 Mozilla ブラウザウィンドウのアイテム (ブラウザが現在開いているページの名前がつけられています) を選択します。DOM Inspector には Mozilla ブラウザのウィンドウを定義している XUL ファイルの URL, ここでは chrome://navigator/content/navigator.xul が表示されます。
chrome URL は、Mozilla をインストールしたディレクトリの chrome サブディレクトリの中のファイルを参照するために Mozilla 内部で 使われている URL のことです。Chrome URL には path 部がありますが、その path は必ずしもディレクトリ階層そのものを 示しているわけではありません。この場合、 chrome URL は mozilla-installation-directory/chrome/content/navigator/navigator.xul を示しています。
書き換えるべきファイルが分かったので、 次はそのファイルから書き換えるべきコードを見つけます。 これも DOM Inspector で簡単にできます。 DOM Inspector の左側の "Document - DOM Nodes" ペインが、 ブラウザウィンドウの XUL ファイルのツリー構造を表示しています。 ツリーのノードを選択すると、ブラウザウィンドウの対応する部分の周りで、 赤いボーダーが数秒間点滅します。
下にスクロールしして、ツリーの statusbar ノードを選択します。 ブラウザウィンドウの下のステータスバーの周りが赤く点滅するのに注目してください。 DOM Inspector の statusbar ノードの隣のプラス記号をクリックし、 出てきた statusbarpanel ノードを一つずつ選択していきます。 ステータスバーの別々の箇所が赤く点滅するのに注目してください。
navigator.xul ファイルをテキストエディタで開き、statusbar 要素を検索してください。 我々が作る extension の UI を追加するのはその中です。
今回の extension の UI はステータスバー上のアイコンです。 この UI を実装するために、 statusbarpanel 要素を navigator.xul ファイルの statusbar 要素に追加します。
<statusbar id="status-bar" class="chromeclass-status"
ondragdrop="nsDragAndDrop.drop(event, contentAreaDNDObserver);">
<statusbarpanel id="component-bar"/>
<statusbarpanel id="statusbar-display"
label="&statusText.label;" flex="1"/>
<statusbarpanel class="statusbarpanel-progress">
<progressmeter class="progressmeter-statusbar"
id="statusbar-icon" mode="normal" value="0"/>
</statusbarpanel>
<statusbarpanel class="statusbarpanel-iconic"
id="tinderbox-status" status="none"/>
<statusbarpanel class="statusbarpanel-iconic" id="offline-status"/>
<statusbarpanel class="statusbarpanel-iconic" id="security-button"
onclick="BrowserPageInfo(null, 'securityTab')"/>
</statusbar>
statusbar XUL 要素は、 アプリケーションの状態を表示するステータスバーを定義しています。 これにはテキストメッセージ (例えば、 Mozilla でドキュメントをロードし終えた時に表示される "Done" (訳注: 日本語パックでは"完了")) や、グラフィカルなメッセージ (例えば、 Mozilla で表示しているドキュメントが SSL で暗号化されているかどうかを示す鍵のアイコン) を含める事ができます。
ステータスバーは statusbarpanel XUL 要素で定義される複数のパネルから構成されています。 各ステータスバーパネルは別々の情報を表示します。 グラフィカルパネル (我々が作っている、アイコンを表示するようなもの) には statusbar-iconic class が追加されます。これで、 CSS スタイルシートで要素の見た目が定義されるようになります。
status 属性は、XUL の statusbarpanel 要素の定義にはありませんが、この extension では現在の tinderbox の状態を保持するのに使います。 tinderbox のステータスをサーバから取得する毎に status 属性の値を更新します。また、status の値に対応するアイコンが表示されるように CSS ルールを定義します。 全ての XUL 要素は、 XUL レンダリングエンジンが認識するもの以外に、 追加の属性を持つことができます。エンジンは追加された属性を無視するので、 属性を追加することで問題が起こったり、 (CSS で明示的に指定する場合を除き) GUI 部品を表示する方法が変更されたりすることはありません。
では、CSS を使って表示するアイコンを定義しましょう。まずは tinderbox の状態 (none, success, test failed, and busted) を示すアイコンを作成し、 tinderbox の状態に対応するアイコンを表示する CSS のルールを作ります。
statusbarpanel#tinderbox-status { list-style-image: url("chrome://navigator/content/tb-nostatus.png"); } statusbarpanel#tinderbox-status[status="success"] { list-style-image: url("chrome://navigator/content/tb-success.png"); } statusbarpanel#tinderbox-status[status="testfailed"] { list-style-image: url("chrome://navigator/content/tb-testfailed.png"); } statusbarpanel#tinderbox-status[status="busted"] { list-style-image: url("chrome://navigator/content/tb-busted.png"); }
Mozilla は外観を管理するスタイルシートの組み合わせを複数持つ事ができますが、 それらの既存のスタイルシートの組み合わせ全てにいちいちルールを追加するのは面倒です (そして、新しいスタイルシートがインストールされた時にこの extension が (訳注: 上書きされて?) 壊れてしまうことも避けなければなりません) 。 そのために、このスタイルシートを "tinderstatus.css" という名前で navigator.xul と同じディレクトリに配置し、navigator.xul の先頭の global stylesheet の参照のすぐ下で "tinderstatus.css" を参照するようにします。
<?xml-stylesheet href="chrome://navigator/skin/" type="text/css"?>
<?xml-stylesheet
href="chrome://navigator/content/tinderstatus.css"
type="text/css"?>
我々のステータスパネル の status 属性に値が設定されたときに表示される画像を、 CSS ルールの "list-style-image" プロパティを使って定義します。 tinderbox の状態一つ毎にルールを作ります。
四つの状態を示すアイコンを作るか、次のアイコンを使ってください。 no status, success, test failed, busted.
もし今 Mozilla を再起動したら、 "no status" アイコンが ブラウザのステータスバーに表示されているでしょう。 (訳者注:Mozilla を一旦終了した後、プロファイルディレクトリの "XUL.mfl"(Windows), "XUL FastLoad File"(Mac), "XUL.mfasl"(Unix) を削除する必要があるかもしれません)
これで我々の Mozilla extension ができましたが、 このままではまだ動きません。 動くようにするには、 tinderbox の状態に合わせて extension の status 属性を変更する JavaScript のコードが必要です。まず最初に、 tinderbox server から現在の tinderbox の状態を取得する関数を書きます。
var gXMLHttpRequest; function loadTinderboxStatus() { gXMLHttpRequest = new XMLHttpRequest(); gXMLHttpRequest.onload = updateTinderboxStatus; gXMLHttpRequest.open("GET", "http://tinderbox.mozilla.org/SeaMonkey/panel.html"); gXMLHttpRequest.send(null); }
XMLHttpRequest は HTTP を介してドキュメントを取得するための Mozilla の インターフェイスです。これは XML コンテンツを取得し、解析して DOM に変換するように設計されています。XML 以外のコンテンツも (解析はしませんが) ちゃんと取得できます。今回は、現在の tinderbox の状態の概要を含む HTML ファイルを取得するのに使います。その HTML ファイルは tinderbox server がビルドを終える度に更新されています。 そのファイルには、アクティブな tinderbox クライアントのリストと、 最新のビルドの結果が示されています。
今回のようなシンプルな場合なら、XMLHttpRequest を使うのは簡単です。 new で XMLHttpRequest のインスタンスを生成し、 インスタンスの onload プロパティに updateTinderboxStatus() をセット (この関数はドキュメントの読み込みが終わった時に実行したい関数です) し、 インスタンスの open メソッドを、発行したい HTTP リクエストのタイプと、取得するドキュメントの URL を引数に指定して呼び、 最後に実際にリクエストを送る send メソッドを呼び出します。 (訳注: updateTinderboxStatus() 関数は次の Step で作成します)
XMLHttpRequest は与えられた URL にあるドキュメントを取得し、 取得し終わると updateTinderboxStatus() を呼びます。
XMLHttpRequest のインスタンスをグローバル変数として定義したのに注意してください。 これは updateTinderboxStatus() がこの関数と同様に このインスタンスを参照する必要があるけれど、この関数が直接に updateTinderboxStatus() を呼ぶのではないので、 この関数から updateTinderboxStatus() へ XMLHttpRequest のインスタンスを渡す事ができないためです。
loadTinderboxStatus() を動作させるには、対応する updateTinderboxStatus() 関数を定義しなければなりません。
function updateTinderboxStatus() { var icon = document.getElementById('tinderbox-status'); if (gXMLHttpRequest.responseText.match("EE0000")) icon.setAttribute("status", "busted"); else if (gXMLHttpRequest.responseText.match("FFAA00")) icon.setAttribute("status", "testfailed"); else if (gXMLHttpRequest.responseText.match("11DD11")) icon.setAttribute("status", "success"); else icon.setAttribute("status", ""); }
updateTinderboxStatus() では、我々の extension の UI を表す statusbarpanel 要素への参照を取得し、 次に、取得した HTML ドキュメント (XMLHttpRequest インスタンスの responseText プロパティに入っています) に検索をかけます。 赤 (RGBコード "EE0000" で表される) が含まれていれば、それは tinderbox クライアントが Mozilla のビルドに失敗した事を示しています。 オレンジ色 ("FFAA00") が含まれていれば、それは tinderbox クライアントが Mozilla のビルドには成功したが、 そのビルドがテストには失敗した事を示しています。 緑色 ("11DD11") が含まれていれば、それはクライアントが Mozilla のビルドにもテストにも成功した事を示しています。 updateTinderboxStatus() 関数は、 ドキュメント中に色を見つけたら、対応する値をパネルの status 属性にセットします。 その結果、前に定義した CSS ルールによって、アイコンが tinderbox の状態に対応するものに切り替えられます。 我々の条件文は成功の判定よりも先に、悪い結果 (bustage (訳注:ビルド失敗), テスト失敗) の判定をしているため、 成功のステータスよりも失敗のステータスが優先して表示されます。 (訳者注:もしそうでないと、「一つでも成功しているビルドがあれば、 成功のステータスが表示される」ことになってしまいます)
これで tinderbox のステータスを取得してアイコンを更新するコードができたので、 それを定期的に実行するようにしましょう。
function loadTinderboxStatus() { gXMLHttpRequest = new XMLHttpRequest(); gXMLHttpRequest.onload = updateTinderboxStatus; gXMLHttpRequest.open("GET", "http://tinderbox.mozilla.org/SeaMonkey/panel.html"); gXMLHttpRequest.send(null); window.setTimeout(loadTinderboxStatus, 60000); } window.setTimeout(loadTinderboxStatus, 1000);
window.setTimeout は、指定された関数を一定時間後に実行させます。 これを loadTinderboxStatus 関数の中で使い、loadTinderboxStatus 関数を スタートアップの一秒後 (1,000 ミリ秒) とその後一分毎 (60,000 ミリ秒) に実行するようにします。 これで、ユーザは tinderbox server に負荷をあまりかけず、 かつ Mozilla がリクエストのせいで遅くならずに、 比較的多く tinderbox の更新ができるようになります。
我々のコードはこれで動くようになりましたが、Mozilla はこのコードについて何も知りません。この機能を有効にするには、 Step 5 で我々の CSS のコードへの参照を navigator.xul に追加したのと同様に、 navigator.xul に我々の JavaScript のコードの参照を加えます。 tinderstatus.js という名前の JavaScript のコードを navigator.xul と同じディレクトリに置き、 navigator.xul の他の JavaScript script を参照している所に tinderstatus.js も参照させるようにします。
...
<!-- Navigator -->
<script type="application/x-javascript"
src="chrome://navigator/content/browser.js"/>
<script type="application/x-javascript"
src="chrome://navigator/content/navigator.js"/>
<script type="application/x-javascript"
src="chrome://navigator/content/navigatorDD.js"/>
<script type="application/x-javascript"
src="chrome://navigator/content/sessionHistoryUI.js"/>
<script type="application/x-javascript"
src="chrome://navigator/content/tinderstatus.js"/>
<!-- hook for stringbundle overlays -->
...
この変更を行い、 Mozilla を再起動すれば、 Tinderbox status パネルに 現在の tinderbox の状態が表示されるはずです。 Tinderbox に行き、 パネルがアクティブな tinderdox クライアントの現在の状態のうち最悪のものを表示しているか確かめてください。
これで tinderbox のステータスを表示する Mozilla extension が完成しました。 次はこれを他のユーザに配布できるようにします。 やり方としては、Mozilla のコードに統合する方法 (この場合、 我々の作ったものは extension ではなく、デフォルトの Mozilla 配布物の一部になります) と、 extension を Mozilla から実行可能なインストーラパッケージにして、 ユーザが extension を使用中の Mozilla に追加するようにする方法があります。
ほとんどの extension はインストーラパッケージとして配布されているので、 我々も同様にしましょう。なお、 extension を Mozilla のコードベースに統合する方法はこのチュートリアルの範疇ではありませんが、 mozilla.org の hacking documentation に多くの情報があります。
Mozilla のインストーラーパッケージは XPIs ("zippies" (ジッピーズ) と発音します) と呼ばれます。これはクロスプラットフォームインストーラー (cross-platform installer) の略です。パッケージはただの ZIP アーカイブで、インストールされるファイルに加えて、 インストールを実行する JavaScript スクリプトと、chrome レジストリ用の、インストールされるコンポーネントについて記述した RDF ファイルを含んでいます。
この extension は、インストールすると Mozilla 中のファイルを変更します。 動的 XUL overlay を使って extension の内容をインストール済みの Mozilla に書き加えるようにするためには、extension をパッケージ化する前に、変更部分を別のファイルに分ける必要があります。
XUL overlay は XUL ファイルの一種で、 他の XUL ファイルに挿入されるべき要素を含んでいます。 挿入は、挿入先の XUL ファイルがアプリケーションの UI へレンダリングされる時に行なわれます。 静的 overlay では、 XUL ファイルの先頭に記述された XUL ファイルへの参照によって挿入が行なわれます (stylesheet や JavaScript スクリプトと同様です)。 動的 overlay では、 chrome レジストリに XUL ファイルへの参照を追加することで挿入が行なわれます。
コードの可読性、保守性、拡張性を高めるために、overlay を使って巨大な XUL ファイルをいくつかのファイルへ分割することができます。 (一つのファイルがアプリケーションウィンドウ全体の構造を記述し、 それ以外がウィンドウの特定の部分を実装する) 。 動的 overlay は、変更したい XUL ファイル自体に変更を加えずに、 その XUL ファイルを変更したのと同じ効果を得るためにも使われます。 この機能は extension をインストールするときに使われます。 では、まず始めにファイルを静的 overlay にし、次にそれを動的 overlay に していきましょう。
ファイルを静的 overlay にするには、navigator.xul と同じディレクトリに tinderstatusOverlay.xul というファイルを作り、navigator.xul に追加していたコードを全てそこに移します。
<?xml version="1.0"?> <?xml-stylesheet href="chrome://navigator/content/tinderstatus.css" type="text/css"?> <overlay id="tinderstatusOverlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/x-javascript" src="chrome://navigator/content/tinderstatus.js" /> <statusbar id="status-bar"> <statusbarpanel class="statusbarpanel-iconic" id="tinderbox-status" insertbefore="offline-status" status="none"/> </statusbar> </overlay>
tinderstatusOverlay.xul は、そのファイルが XML であることを示す XML 宣言から始まります (全ての XUL ファイルは XML 宣言を含む必要があります) 。 次の行は、以前 navigator.xul に追加した stylesheet への参照です。 次は XUL の overlay 要素です。この要素は XUL overlay ファイルのトップレベル要素で、これによりファイルが overlay であることが分かります。 その中身は前に navigator.xul に追加したスクリプトへの参照です。 その次には statusbarpanel 要素を含む statusbar 要素があります。
この overlay の中の statusbar 要素の id 属性の値は、 navigator.xul の statusbar 要素の id 属性と同じです。 navigator.xul がレンダリングされてブラウザの UI になるとき、 overlay ファイルの statusbar 要素の全ての属性と子要素が UI の DOM に追加されます。 これにより、overlay ファイルで定義した要素が、あたかも navigator.xul で定義されているかのような UI が表示されます。
statusbarpanel 要素に属性 insertbefore を追加したのに注意してください。この属性では、 statusbar の中の、我々の要素の次に現れる statusbarpanel 要素を指定しています。これにより、我々の要素が statusbar の中でどの要素の前にくるかという、他の statusbarpanel に対する相対的な位置を指定する事ができます。
insertbefore を省略すると、要素は statusbar の 最後に追加され、通常は resizer grippy (訳注: ウィンドウ右下の、ウィンドウのサイズを変えるのに使う部分) の前に来るでしょう。 また、insertbefore の代わりに insertafter を使えば、他の要素の後ろに要素を配置する事もできます。
我々が navigator.xul に対して行った変更の代わりにこの overlay を使うには、今までの変更を元に戻し、 overlay への参照を navigator.xul の先頭に追加します。
... <?xml-stylesheet href="chrome://navigator/skin/" type="text/css"?> <?xml-stylesheet href="chrome://navigator/content/tinderstatus.css" type="text/css"?> <?xul-overlay href="chrome://navigator/content/navigatorOverlay.xul"?> <?xul-overlay href="chrome://navigator/content/navExtraOverlay.xul"?> <?xul-overlay href="chrome://navigator/content/linkToolbarOverlay.xul"?> <?xul-overlay href="chrome://navigator/content/tinderstatusOverlay.xul"?> <?xul-overlay href="chrome://communicator/content/contentAreaContextOverlay.xul"?> <?xul-overlay href="chrome://communicator/content/sidebar/sidebarOverlay.xul"?> <?xul-overlay href="chrome://communicator/content/communicatorOverlay.xul"?> <?xul-overlay href="chrome://communicator/content/bookmarks/bookmarksOverlay.xul"?> ... <!-- Navigator --> <script type="application/x-javascript" src="chrome://navigator/content/browser.js"/> <script type="application/x-javascript" src="chrome://navigator/content/navigator.js"/> <script type="application/x-javascript" src="chrome://navigator/content/navigatorDD.js"/> <script type="application/x-javascript" src="chrome://navigator/content/sessionHistoryUI.js"/> <script type="application/x-javascript" src="chrome://navigator/content/tinderstatus.js"/> <!-- hook for stringbundle overlays --> ... <statusbar id="status-bar" class="chromeclass-status" ondragdrop="nsDragAndDrop.drop(event, contentAreaDNDObserver);"> <statusbarpanel id="component-bar"/> <statusbarpanel id="statusbar-display" label="&statusText.label;" flex="1"/> <statusbarpanel class="statusbarpanel-progress"> <progressmeter class="progressmeter-statusbar" id="statusbar-icon" mode="normal" value="0"/> </statusbarpanel> <statusbarpanel class="statusbarpanel-iconic" id="tinderbox-status" status="none"/> <statusbarpanel class="statusbarpanel-iconic" id="offline-status"/> <statusbarpanel class="statusbarpanel-iconic" id="security-button" onclick="BrowserPageInfo(null, 'securityTab')"/> </statusbar> ...
これで静的な overlay ができました。次に XPI パッケージを作成します。 XPI パッケージによって、 extension は動的 overlay として Mozilla にインストールされます。 XPI は UI レイヤーを別々に切り分ける事ができるように設計されています。 まず、 XPI に含めるファイルを入れるディレクトリを作ります。 次に、ファイル中の URL を変更して、XPI を使ってインストールしたときにファイルが置かれる場所を指すようにします。 次に、 tinderstatus コンポーネントについて記述した contents.rdf と、 インストールを実行する install.js スクリプトを作成します。 最後に、構成ファイルを zip アーカイブへ圧縮します。
まず、適当な場所に tinderstatus-installer ディレクトリを作成します。次に tinderstatus サブディレクトリをその中に作成し、さらにその中に content サブ-サブディレクトリを作成してください。作成したら、次のファイルを content ディレクトリにコピーしてください。
tinderstatusOverlay.xul tinderstatus.js tinderstatus.css tb-busted.png tb-nostatus.png tb-success.png tb-testfailed.png
これらは XPI に入れるファイルです。 次に、コピーした tinderstatusOverlay.xul 中の URL を、XPI を使ってインストールしたときにファイルが置かれる場所を指すように変更します。
<?xml version="1.0"?> <?xml-stylesheet href="chrome://tinderstatus/content/tinderstatus.css" type="text/css"?> <overlay id="tinderstatusOverlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/x-javascript" src="chrome://tinderstatus/content/tinderstatus.js" /> <statusbar id="status-bar"> <statusbarpanel class="statusbarpanel-iconic" id="tinderbox-status" insertbefore="offline-status" status="none"/> </statusbar> </overlay>
tinderstatus.css も同様に URL を変更します。
statusbarpanel#tinderbox-status { list-style-image: url("chrome://tinderstatus/content/tb-nostatus.png"); } statusbarpanel#tinderbox-status[status="success"] { list-style-image: url("chrome://tinderstatus/content/tb-success.png"); } statusbarpanel#tinderbox-status[status="testfailed"] { list-style-image: url("chrome://tinderstatus/content/tb-testfailed.png"); } statusbarpanel#tinderbox-status[status="busted"] { list-style-image: url("chrome://tinderstatus/content/tb-busted.png"); }
次に、二つのファイルを作成します。 一つは contents.rdf という名前で、 インストールするコンポーネントの情報が記述されており、 chrome レジストリにインストールされます。 もう一つは install.js という名前で、 コンポーネントをインストールするためのコードです。 contents.rdf は content ディレクトリに入れます。
<?xml version="1.0"?> <RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:chrome="http://www.mozilla.org/rdf/chrome#"> <RDF:Seq about="urn:mozilla:package:root"> <RDF:li resource="urn:mozilla:package:tinderstatus"/> </RDF:Seq> <RDF:Description about="urn:mozilla:package:tinderstatus" chrome:displayName="Mozilla Tinderstatus Extension" chrome:author="Myk Melez" chrome:name="tinderstatus" chrome:extension="true" chrome:description="Displays tinderbox status for the Mozilla codebase."> </RDF:Description> <RDF:Seq about="urn:mozilla:overlays"> <RDF:li resource="chrome://navigator/content/navigator.xul"/> </RDF:Seq> <RDF:Seq about="chrome://navigator/content/navigator.xul"> <RDF:li>chrome://tinderstatus/content/tinderstatusOverlay.xul</RDF:li> </RDF:Seq> </RDF:RDF>
install.js は tinderstatus-installer ディレクトリに入れます。
initInstall( "Mozilla Tinderstatus Extension", "/mozdev/tinderstatus", "0.1"); var installDir = getFolder("Chrome","tinderstatus"); setPackageFolder(installDir); addDirectory("tinderstatus"); registerChrome( CONTENT | DELAYED_CHROME, getFolder(installDir, "content")); var result = performInstall(); if ( result != SUCCESS ) cancelInstall(result);
全てのファイルの配置が終わったら、tinderstatus-installer ディレクトリで zip を使い、install.js と tinderstatus/ ディレクトリの内容を全て含んだ ZIP アーカイブを作り、その名前を tinderstatus.xpi にします。 アーカイブのトップレベルにファイルとディレクトリがあることを確かめてください。
これで実際に動作する Mozilla extension のインストーラが出来上がりました! テストをするには、新しく Mozilla をインストールし、その Mozilla から XPI ファイルを読み込ませて extension をインストールしてください (ウェブからロードさせても、 "file:///" URL を使ってローカルのハードディスクからロードしても動作するでしょう) 。 Mozilla は自動的にファイルがインストーラであるかどうか判断し、 インストーラであると判断されれば、 ソフトウェアをインストールするかどうか尋ねるでしょう。 extension をインストールしたら、 Mozilla を再起動し、 動作するか確認しましょう。
もしあなたがこのチュートリアルに従って作ったインストーラが動かなければ、 こちらの動作するバージョン を問題を見つけ出す参考にしてください。
このチュートリアル・課題の発展としては:
chrome://navigator/content/navigator.xul
を
chrome://browser/content/browser.xul
に変更する必要があります。
もしこのドキュメントに間違いを見つけたり、最新の情報や追加情報を寄与したいのであれば、 ぜひ Myk Melez へコンタクトを取ってください。 (訳注: この翻訳に関しては翻訳者までお願いします)