レベル: 中級 Uche Ogbuji (uche@ogbuji.net), Partner, Zepheira, LLC
2007年 10月 16日 XUL を利用すると、クロスプラットフォームのブラウザー拡張機能や、さらにはスタンドアロンのアプリケーションでさえ、驚くほど容易に作成することができます。この記事では Mozilla ブラウザーの拡張機能を作成する方法を学びます。これらの拡張機能はユーザーのブラウザー自体に組み込まれるため、組み込みのスクリプト言語や CGI など他のツールの機能を超えるほど強力で柔軟です。
Mozilla の XUL (XML User Interface Language) は、スタンドアロンのアプリケーションやブラウザー拡張機能を開発するための多用途の言語です。このシリーズの第 1 回では XUL 拡張機能のための基本的なビルディング・ブロックを紹介しました。今回の記事では、これらのビルディング・ブロックをクロスプラットフォームの Firefox 拡張機能として組み立てるための方法を説明します。第 1 回の記事のコードは限定的なものでしたが、それはブラウザーでの XUL ファイルに対するセキュリティー障壁が高かったためです。拡張機能の場合には、そうした制限はずっと少なくなっています。そこで今回は、前回のコードに欠けていた機能もいくつか提供することにします。
拡張機能の基本的な構造
最初のステップは、前回の記事の場合と同じように、XUL を使った拡張機能と、サポート・ファイルを作成することです。Firefox の他のアドオンをインストールしたことのある人は、アドオンが .xpi というファイル拡張子を持つパッケージとして提供されていることに気付いているかもしれません。.xpi は XPI (XUL's Cross-Platform Install) パッケージ・フォーマット (「zippy」と発音します (訳注: 英語圏の人は「ジッピィ」と発音するようですが、日本では「エックスピーアイ」とそのまま読んだりもします)) を意味します。XPI はバンドルという、特定のレイアウト・ファイルとマニフェスト・ファイルを持つ .zip ファイルを定義します。これは、Java の JAR フォーマットと似ています (JAR も .zip されたコンテンツ・ファイルとマニフェスト・ファイルが組み合わされています)。リスト 1 は、前回の記事で XUL と JavaScript、そして CSS を使って用意した、拡張機能のための .zip ファイルのディレクトリーです。
リスト 1. Firefox 拡張機能の XPI バンドルに対する .zip ファイルのディレクトリー
Archive: /Users/uche/stats.xpi
Length Method Size Ratio Date Time CRC-32 Name
-------- ------ ------- ----- ---- ---- ------ ----
0 Stored 0 0% 10-08-07 23:10 00000000 chrome/
0 Stored 0 0% 10-08-07 23:10 00000000 chrome/content/
271 Defl:N 184 32% 10-09-07 00:13 44bb6d65 chrome/content/overlay.js
464 Defl:N 284 39% 10-09-07 00:13 1d873c24 chrome/content/overlay.xul
909 Defl:N 366 60% 10-09-07 00:13 67869f05 chrome/content/stats.js
1581 Defl:N 544 66% 10-09-07 00:13 49def584 chrome/content/stats.xul
0 Stored 0 0% 10-08-07 23:10 00000000 chrome/skin/
230 Defl:N 147 36% 10-09-07 00:13 a732aecb chrome/skin/stats.css
181 Defl:N 105 42% 10-09-07 00:13 f7317c0a chrome.manifest
0 Stored 0 0% 10-08-07 23:10 00000000 defaults/
0 Stored 0 0% 10-08-07 23:10 00000000 defaults/preferences/
948 Defl:N 440 54% 10-09-07 00:13 50ee7971 install.rdf
0 Stored 0 0% 10-08-07 23:10 00000000 locale/
0 Stored 0 0% 10-08-07 23:10 00000000 locale/en-US/
43 Stored 43 0% 10-09-07 00:13 d9c38400 locale/en-US/overlay.dtd
-------- ------- --- -------
4627 2113 54% 15 files
|
ファイルの配置によく注意してください。拡張機能を作成する際には、ファイルの配置の問題が最も面倒なのです。この中に、前回の記事で説明しなかった新しいファイルがいくつかあることに気付くと思います。これらについて、次のセクションで説明します。
XUL オーバーレイ
前回の記事では、新しい XUL ウィンドウはスタンドアロンでした。しかし今度は拡張機能としてバンドルされているので、これを何らかの方法で Firefox から呼び出す必要があります。通常、このためにはブラウザーのユーザー・インターフェースを細工し、拡張機能を呼び出せる手段をユーザーに対して提供する必要があります。XUL では、次のようにオーバーレイと呼ばれるものを使ってユーザー・インターフェースを容易に拡張することができます。リスト 2 (overlay.xul) は、stats ビューアー・ウィンドウを起動するためのメニュー項目を追加するオーバーレイです。
リスト 2 (overlay.xul). メニュー項目を追加するための XUL オーバーレイ
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://stats/skin/overlay.css" type="text/css"?>
<!DOCTYPE overlay SYSTEM "chrome://stats/locale/overlay.dtd">
<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="stats-overlay">
<script src="overlay.js"/>
<menupopup id="menu_ToolsPopup">
<menuitem id="stats" label="&statsmenuitemname;"
oncommand="Stats.onMenuItemCommand(event);"/>
</menupopup>
</overlay>
|
chrome の URL については後のセクションでさらに説明します。DTD をロードするために使われている文書型宣言に注目してください。DTD はローカライズする必要のあるすべてのストリング (基本的に、ユーザーに表示されるすべての自然言語ストリング) を含んでいます。次のセクションでは、Mozilla の chrome アプリケーションでの、このスマートなローカライゼーション (l10n) の方法について、もう少し詳しく説明します。オーバーレイの XUL の中では、メニューの追加を指定しています。外側の要素は、Firefox の既存のターゲット・メニュー項目を ID で指定しています (menu_ToolsPopup は「ツール」のメニューです)。デフォルトで、新しい項目は最後のメニュー項目として追加されます。新しいメニュー項目 (stats) は、ユーザーに表示されるラベルとして、(先ほど触れた DTD の実体として提供される) ローカライズされたストリングを使います。oncommand 属性は重要です。この属性によって、ユーザーがメニュー項目を選択したときに何が起こるかが決まるからです。指定されている JavaScript 関数は、別のスクリプト・ファイル overlay.js で提供されます (リスト 3)。
リスト 3 (overlay.js). 追加されたメニュー項目のアクションを記述するスクリプト
var Stats = {
onLoad: function() {
//You can place set-up code for the extension here
},
onMenuItemCommand: function() {
window.open("chrome://stats/content/stats.xul", "", "chrome, resizable=yes");
}
};
window.addEventListener("load", function(e) { Stats.onLoad(e); }, false);
|
このスクリプトの大部分は、すべての機能をラップする Stats という 1 つの構造を定義しています。この構造の中に、任意のグローバル変数も置きたいものです。そうすれば、グローバルな名前空間 (外部構造そのものの名前) で使う名前は 1 つですみ、この拡張機能のフットプリントを減らすことができます。また、そうすることは、他の拡張機能が使用するオブジェクト名との衝突や、さらにはコンテンツのスクリプトが使用するオブジェクト名との衝突を避けるために、適切な振る舞いをするすべての拡張機能が標準的に行っていることでもあります。ラップされたオブジェクトへのアクセス方法は、リスト 2 の JavaScript のスニペット、つまりリスト 3 の 2 番目の構造項目にアクセスする Stats.onMenuItemCommand(event) で既に見ました。ここでは完全にするために Stats.onLoad 関数も含めましたが、この拡張機能では実際には使っていません。この関数を使えば、任意の拡張機能の初期化コードを実行することができます。このスクリプトの最後の行は、chrome のロードが完了すると即座に Stats.onLoad 関数が実行されるように設定しています。Stats.onMenuItemCommand 関数は単純に、前回の記事の XUL サンプル・アプレットを持つウィンドウを起動します。2 番目の属性はウィンドウ ID ですが、ここでは使っていません。3 番目の属性はフラグのリスト、chrome であり、新しいウィンドウが独自の chrome を持つこと、そしてこの新しいウィンドウをブラウザーの chrome 内で開いてはならないことを示しています (つまり例えば、新しいウィンドウは Firefox のメニューやツールバー、ステータス・バー、タブなどを継承しません)。resizable=yes は、ユーザーがウィンドウのサイズを変更できるようにします。
chrome のリソース
皆さんは、この拡張機能のためのファイルが次々に増えていることに既に気付いたかもしれません。XPI で重要なことは、バンドルの中のファイルを見つけることです。そこで、マニフェスト・ファイル、chrome.manifest が登場します (リスト 4)。
リスト 4. Stats 拡張機能のための chrome のマニフェスト・ファイル
content stats chrome/content/
overlay chrome://browser/content/browser.xul chrome://stats/content/overlay.xul
locale stats en-US locale/en-US/
skin stats classic/1.0 chrome/skin/
|
最初の行からは、メインのコンテンツ (XUL ファイルやスクリプトなど) がある場所がわかります。この行は stats エイリアスを使って、バンドルの中にある「chrome/content/」フォルダーを参照します。つまり、例えば chrome の URL として chrome://stats/content/stats.xul を使ったとすると、stats エイリアスをマッピングし、「chrome/content/」フォルダー内で「stats.xul」ファイルを探すことで、この URL を解決します。2 行目は、ブラウザーのメインの chrome のオーバーレイを、overlay.xul (リスト 2) を使って設定します。3 行目は、自然言語のストリングを含む DTD の場所を設定することでローカライゼーションをサポートします。この例にはアメリカ英語のストリングしかありませんが、それらをフランス語に翻訳して fr-FR フォルダーに置いたり、ドイツ語に翻訳して de-DE フォルダーを使ったり、ということもできます。ブラウザーは、ユーザーが設定した言語のプリファレンスに対応する言語を自動的に使用します。最後の行は、ブラウザーの標準の chrome と組み合わされる CSS ファイルの場所を設定します。
インストーラーの設定
XPI でもう 1 つ重要な情報が、install.rdf (リスト 5) です。これは拡張機能をインストールするための命令を含んでいます。
リスト 5 (install.rdf). Stats 拡張機能のためのインストール・パラメーター
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<!-- Required Items -->
<em:id>xulapp@example.com</em:id>
<em:name>Stats viewer</em:name>
<em:version>1.0</em:version>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>1.5</em:minVersion>
<em:maxVersion>2.0.0.*</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Optional Items -->
<em:creator>Uche Ogbuji</em:creator>
<em:description>
Opens a window in which you can view simple stats about Web pages
</em:description>
<em:homepageURL>http://www.ibm.com/developerworks/web/</em:homepageURL>
</Description>
</RDF>
|
この大部分は自明なので詳細は省略しますが、1 点だけ、ここで使用している em:targetApplication 要素が Firefox のバージョンとして 1.5 より上で 2.0.1 より下を指定していることには注意してください。長い em:id ストリングは Firefox 自体のアプリケーション UUID です。
前回の記事のサンプル・ファイルは、単純にリスト 1 に示す場所に置けるはずです。ただし 1 つだけ例外として、「stats.xul」の CSS リンクを調整する必要があります (前回の記事では「stats.css」が同じディレクトリーにあるものとしていました)。ここではその代わりに chrome リンク chrome://stats/skin/stats.css を使用します。
拡張機能の機能を完成させる
繰り返しますが、前回はセキュリティーの制約から XUL ファイル stats.js のいくつかの機能を無効にする必要がありました。今度はこのファイルを拡張機能としてパッケージ化したので、これまで欠けていたものを元通り入れることができます。リスト 6 は更新された stats.js です。この stats.js は、この拡張機能に期待されているカウント動作を、実際にその通り行います。
リスト 6. Stats ビューアー・ウィンドウのための JavaScript が完成
//Invoked in response to a click on the "Go!" button
function change_url(event)
{
//Variables for convenient access to specific elements in the XUL
var urlbox = document.getElementById("url");
var contentview = document.getElementById("contentview");
var wordcountbox = document.getElementById("wordcount");
var charcountbox = document.getElementById("charcount");
var elemcountbox = document.getElementById("elemcount");
alert(urlbox.value);
contentview.contentDocument.location.href = urlbox.value;
//Use Firefox XPath to get the raw text of the document
var doctext = contentview.contentDocument.evaluate(
"string(.)", document, null, XPathResult.STRING_TYPE, null).stringValue;
var wordcount = doctext.split(" ").length()
alert(wordcount);
wordcountbox.value = String(wordcount);
charcountbox.value = String(doctext.length());
//Use Firefox XPath to count elements in the document
var elemcount = contentview.contentDocument.evaluate(
"count(//*)", document, null, XPathResult.NUMBER_TYPE, null).numberValue;
elemcountbox.value = String(elemcount);
}
|
ここでは、ユーザーが contentview の中にロードした Web ページに対して、2 つの Xpath 式を使っています。最初の式 string(.) では、(ストリングの長さから) 文字カウントを取得し、(ストリングを空白で分割し、その結果をカウントすることで) 単語カウントを取得します。2 番目の式 //* では要素の数を取得します。次に、これらの値を使って該当するテキスト・ボックスを更新します。
まとめ
Firefox の拡張機能の作成は面倒ですが、幸い Firefox のコミュニティーには既に数多くの拡張機能が作成されており、それらがさまざまな面で役立ちます。「囲み記事」には、そのいくつかを挙げてあります。この 2 回シリーズの記事では、少し注意深く行えば Firefox の拡張機能を作成できること、またその知識を活用することで、完全なアプリケーションにするために明らかに必要と思われる部分を容易に開発できることを学びました。XUL と JavaScript、そして Mozilla プラットフォーム全体には驚くほどの能力があります。そして、単なる古典的な Web ブラウザー以上のものをターゲットにすることができます。通常は、音楽管理アプリケーションの Songbird やソーシャル Web ブラウザーの Flock など、Mozilla の (そして一般的には XUL ベースの) アプリケーションに Firefox の拡張機能を適用する作業は、それほど難しくはないのです。
参考文献 学ぶために
議論するために
著者について  | 
|  | Uche Ogbuji は、次世代の Web 技術を専門にソリューションを提供する会社、 Zepheira, LLC のパートナーです。Ogbuji 氏は、XML と RDF、そしてナレッジ管理アプリケーションのためのソープン・ソース・プラットフォーム 4Suite の中心開発者であり、Versa RDF 問い合わせ言語の中心開発者でもあります。彼はナイジェリア出身のコンピューター・エンジニア兼ライターであり、アメリカのコロラド州のボールダーに住み、業務を行っています。彼について詳しくは、彼のブログ Copia をご覧ください。 |
記事の評価
|