レベル: 中級 Uche Ogbuji (uche@ogbuji.net), Partner, Zepheira, LLC
2007年 10月 02日 Web ブラウザーに組み込まれた機能を超える拡張機能を作成しましょう。Mozilla プロジェクトの XUL エンジンは、Mozilla ブラウザーの拡張やスタンドアロンのアプリケーション作成に使用できるユーザー・インターフェース言語です。XUL を使うことで、驚くほど容易にクロスプラットフォームのブラウザー拡張機能を作成することができます。この 2 回シリーズの記事では、その方法について説明します。
Mozilla のプロジェクト・チームは非常に初期の頃に、コアの開発を C++ で標準化すること、ただしクロスプラットフォームでコア機能と拡張機能を共有するためのコンポーネント・システムであるXPCOM (Cross Platform Component Object Model) を作成することを決定しました。またこのチームは、そうしたコンポーネント用のユーザー・インターフェースの設計を、XUL (XML User Interface Language、ズール (zool) と発音します) という、プラットフォームに依存しない言語で行うための方法も開発しました。XUL に XML が使われていることに特別な意味はありません。彼らは、(その気になれば) まったく新しい構文を作り出すこともできたのです。XUL は、単なるもう 1 つのプログラミング言語と考えればよいのであり、たまたま基本的な構文用に XML を使っているにすぎません。XUL は、実際に ECMAScript (JavaScript の実装で最もよく知られています) や DOM、CSS など既存の Web 技術を利用しているため、Web 開発者にとっては非常に学びやすいはずです。その兄弟分である、もう一方の言語 XBL (eXtensible Bindings Language) は、XUL 要素の動的な振る舞いをコントロールするために使われます。XUL と XBL は非常に強力であり、完全なブラウザーや、あるいはブラウザー以外にも Mozilla のコンポーネントをベースにするクロスプラットフォームの完全なアプリケーションを開発することができます。しかし大部分の開発者は、XUL をもっと控え目に、既存のブラウザーや他のアプリケーションのユーザー・インターフェースの拡張や操作のために使っています (XUL はそうした使い方ができるように注意深く設計されています)。ブラウザーの拡張機能を開発しているほとんどのケースで、このような XUL の使い方をしています。そして、Mozilla ブラウザーの大部分の拡張機能にとって最も魅力的な対象は、Mozilla で最も人気のスタンドアロンのブラウザーである Firefox です。Firefox は XUL と JavaScript で作成されています。これは XUL の強力さを示していますが、Firefox は XUL を使った拡張機能に対しても非常にオープンです。
この記事では、ユーザー・インターフェース機能を持つほとんどの拡張機能を作成する上で必要な基本部分 (XUL、CSS、JavaScript、そして DOM) を併せて使用しますが、XUL の入門記事ではありません。XUL の基礎を説明した資料については「参考文献」のリンクを参照してください。この記事では、XUL の基本概念を理解しているという前提で、その実際の使い方に焦点を絞ります。またここでは、JavaScript と DOM、そして CSS の基本的な知識を持ち合わせていることも前提としています。
XUL による直接的な方法
XUL の素晴らしいことの 1 つは、Mozilla ブラウザーが XUL の大部分を他の Web コンテンツと同様に扱うことです。これはつまり、アプリケーションや完全な拡張機能を適切にパッケージ化することを心配する前に、開発フェーズの間にさまざまなことを素早く試し、デプロイできるということです。そうした迅速なデプロイメントに利用できる便利なツールはいくつかあります。Ted Mielczarek による Extension Developer's Extension (「参考文献」を参照) には、XUL をオンラインで編集、プレビューできる Live XUL Editor など、便利なツールが数多く含まれています。また彼の Web サイトでは、それとほとんど同じことができる、非常に単純な XUL のページを提供しています (Web からロードされたすべての XUL に適用される、いくつかのセキュリティー制限が解除されています)。ただし私としては、通常は XUL の開発サイクルをもっと直接的な方法で行う方が好きです。つまり適切なテキスト・エディター (特に、XML をオーサリングする際の苦痛をいくらか緩和する機能を提供するもの) で編集し、その後で単純に Firefox のタブに XUL ファイルを直接ロードするのです。そして何らかの微調整や修正をするために再度編集し、そのファイルのためのページをリロードします。リスト 1 (stats.xul) は単純な XUL の例ですが、XUL の強力さをいくつか示しています。この例では、URL の入力とそれに対応する Web ページの表示を 1 つのパネルで行うことができ、また別のパネルでは、そのページに関するいくつかの簡単な統計を見ることができます。
リスト 1 (stats.xul). 単純な XUL の例
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="statswindow" title="View Web page stats">
<vbox flex="1">
<hbox id="toppanel">
<label value="Enter a URL:"/>
<textbox id="url" flex="1" value="http://www.ibm.com/developerworks/web"/>
<button label="Go!"/>
</hbox>
<description value="Current page:"/>
<hbox flex="1">
<iframe id="contentview" src="http://www.ibm.com/developerworks/web" flex="2"/>
<vbox>
<groupbox>
<caption label="Stats"/>
<grid flex="1">
<columns>
<column flex="1"/>
<column flex="1"/>
</columns>
<rows>
<row>
<label value="Word count"/>
<textbox class="count" id="wordcount" value="N/A" readonly="true"/>
</row>
<row>
<label value="Character count"/>
<textbox class="count" id="charcount" value="N/A" readonly="true"/>
</row>
<row>
<label value="Element count"/>
<textbox class="count" id="elemcount" value="N/A" readonly="true"/>
</row>
</rows>
</grid>
</groupbox>
<spacer flex="1"/>
</vbox>
</hbox>
</vbox>
</window>
|
chrome://global/skin/ スタイルシート宣言によって、ブラウザーは chrome パッケージのデフォルトの global.css を使います (global.css は、Firefox に組み込みのルック・アンド・フィールか、あるいはスキンがインストールされている場合には何らかのバリエーションを表します)。window には一連のネストしたボックスを使ってコンテンツを配置していますが、ここでは表示に凝りすぎないようにし (これに関しては次のセクションで説明します)、ほとんど UI 要素の論理的なグループ分けのみに集中しています。iframe 要素は同じ名前の HTML 要素と似ていますが、対象となる Web ページを描画するためのコンテンツ・フレームを作成します。コンテンツ・フレームのデフォルトは http://www.ibm.com/developerworks/web であり、これは url textbox の中に置かれる値でもあります。この 2 つの値は、デフォルトのビューをユーザーにとって意味のあるものにするために一致させてあるにすぎず、この段階では 2 つの値を結びつけるものは何もありません (これについては後のセクションで説明します)。groupbox は stats のエントリーを整理するために便利です (stats の各エントリーは読み取り専用のテキスト・ボックスであり、今の段階ではデフォルトでダミーの値になっています)。この結果表示されるのは単純で静的なウィンドウですが、それでも iframe の強力さのおかげで素晴らしい結果を示します。これを「stats.xul」というファイルに保存し、それを任意の Mozilla ブラウザー・ウィンドウにロードします。そのためには、Firefox で、URL 欄に「file:」として指定するかメニューから「ファイルを開く」を使います。そうすると図 1 のようなものが表示されるはずです。
図 1. リスト 1 をロードした、Firefox ブラウザーのウィンドウ
表示のスタイルを追加する
XUL を使っても多少は UI 要素の位置決め操作を行えますが、ほとんどの場合、ウィンドウをどう表示するかの詳細はスタイルシートの問題であり、スタイルシートに任せた方が適切です。XUL に CSS を使うことで、HTML 用の CSS や他の XML でおなじみの通常のプロパティー (色、フォント、空白、およびサイズ) をコントロールすることができます。リスト 2 (stats.css) は、リスト 1 の表示を微調整するための宣言をいくつか示しています。
リスト2 (stats.css). リスト 1 に適用される CSS
window {
font-family: arial, "lucida console", sans-serif;
}
description {
padding: 5px;
color: blue;
}
#toppanel {
padding: 5px;
}
#contentview {
padding: 5px;
border: thin solid black;
}
.count {
width: 5em;
}
|
これを見ると、ID やクラス、要素などのセレクターを使ってリスト 1 の各部分と突き合わせるルールがあることがわかります。このスタイルシートを適用するためには、XUL ファイルの先頭に、さらに宣言を追加します。これをリスト 3 に示します。リスト 3 は、新しい CSS 宣言を追加して更新した後の XUL ファイルの最初の 4 行のみを示してあります。
リスト 3. スタイルシート宣言を追加して更新したリスト 1 の最初の数行
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="stats.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
chrome://global/skin/ の宣言を削除しなかったことに注意してください。ほとんどの場合には、こうしておく必要があります。そうするとブラウザーは、このグローバルなスキンを、指定した特定のスタイルシートと組み合わせてくれます。図 2 は、スタイルシートを持ち、Firefox にロードされた、更新された XUL ウィンドウを示しています。
図 2. CSS を使った XUL ウィンドウを持つ Firefox ブラウザー
スクリプトを使って仕上げる
このデモ用の XUL アプリケーション開発の最後のステップは、コントロールを使えるようにすることです。そのためには、コントロール要素を動作にバインドします。XUL には兄弟分の言語である XBL があります。XBL を使うと、このバインディングの大部分を宣言を使って行うことができ、必要なスクリプトの量を減らすことができます。しかしこの記事では、JavaScript 関数を参照するイベント属性を使ってバインディングを行います。
リスト 4 (stats-styled-scripted.xul). リスト 1 を CSS とスクリプト宣言、そしてスクリプト・フック属性を使って更新したもの
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="stats.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="statswindow" title="View Web page stats">
<script type="application/x-javascript" src="stats.js"/>
<vbox flex="1">
<hbox>
<label value="Enter a URL:"/>
<textbox id="url" flex="1" value="http://www.ibm.com/developerworks/web"/>
<button label="Go!" oncommand="change_url(event)"/>
</hbox>
<description value="Current page:"/>
<hbox flex="1">
<iframe id="contentview" src="http://www.ibm.com/developerworks/web" flex="2"/>
<vbox>
<groupbox>
<caption label="Stats"/>
<grid flex="1">
<columns>
<column flex="1"/>
<column flex="1"/>
</columns>
<rows>
<row>
<label value="Word count"/>
<textbox class="count" id="wordcount" value="N/A" readonly="true"/>
</row>
<row>
<label value="Character count"/>
<textbox class="count" id="charcount" value="N/A" readonly="true"/>
</row>
<row>
<label value="Element count"/>
<textbox class="count" id="elemcount" value="N/A" readonly="true"/>
</row>
</rows>
</grid>
</groupbox>
<spacer flex="1"/>
</vbox>
</hbox>
</vbox>
</window>
|
window の中に追加された script 要素と、「Go!」ボタンに追加された属性 oncommand="change_url(event)" に注目してください。リスト 5 は、参照されている JavaScript ファイル「stats.js」です。
リスト 5 (stats.js). 「Go!」ボタンを処理するための 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");
//Setting this attribute, happens to change the visible contents of the panel
contentview.setAttribute("src", urlbox.value);
//Fake up the update code for now, to allow running in Firefox
wordcountbox.previousSibling.value += " (fake)";
wordcountbox.value = "1000";
charcountbox.previousSibling.value += " (fake)";
charcountbox.value = "100";
elemcountbox.previousSibling.value += " (fake)";
elemcountbox.value = "10";
}
|
リスト 4 は、関数 change_url を「Go!」ボタンのクリックにバインドします。この関数はクリックのイベントの詳細を受信しますが、この場合にはそれを使っていません。グローバルな document オブジェクトを利用すると、DOM を使ってさまざまな XUL 要素にアクセスすることができます (この場合には固有 ID で要素を見つけるために getElementById を使っています)。XUL 要素は当然 XML 属性を持っていますが、オブジェクトのプロパティーも持っています。属性とプロパティーは、たとえ名前が似ている場合でも、照会される際や操作される際の動作が異なることがあります。例えばここでは、URL のテキスト・ボックスの中のテキストを、urlbox.getAttribute("value") ではなく urlbox.value のようなコードを使って取得しています。後者は、そのページがロードされてからユーザーが何を入力したかにかかわらず、必ずそのテキスト・ボックスの元々の内容 ("http://www.ibm.com/developerworks/web") を読み取ります。同様に、そうしたテキスト・ボックスの中に表示される内容を更新したい場合には、コードを urlbox.setAttribute("value", newvalue) ではなく、urlbox.value = newvalue と記述します。この原則は、この関数の最後にあるカウント用テキスト・ボックスを更新するコードで使われています。こうしたニュアンスは、XUL の参照資料にすべて説明されています。何らかの XUL 要素を使用する際には、その要素に関する説明を注意深く読む必要があります
セキュリティーの壁
属性とプロパティーの扱い方の違いに関する注意事項は、contentview.setAttribute("src", urlbox.value); の行にも当てはまります。新しい URL のコンテンツを表示するための、もっと適切な方法は、contentview.contentDocument.location.href = urlbox.value; かもしれません。しかし、この行には問題があります。Firefox には XUL 文書に対して厳密なセキュリティー・モデルがあります。これはつまり、contentview.contentDocument などの慎重な扱いが必要なオブジェクト属性にアクセスしようとすると、JavaScript が例外をスローするということを意味します。このエラーを見るためには Error Console ウィンドウを使う必要がありますが、使ったとしても、このエラーは「Error: uncaught exception: Permission denied to create wrapper for object of class UnnamedClass (エラー: キャッチされなかった例外: UnnamedClass クラスのオブジェクトに対するラッパーの作成が許可されませんでした)」のような曖昧で汎用のものでしかないかもしれません。これは XUL を直接的な方法で実験する際の大きな問題です。次回の記事では、この記事で紹介したそのままの内容を Firefox の適切な拡張機能に変える方法を説明します。そこでは、適当な Chrome Registration によってセキュリティーの制限を回避します。現状では、このコードは XUL でスクリプトを作成する際の基本的な設定を示すために、contentview (目に見える結果を表示してくれます) の属性のうち、制限されていない src 属性を変更し、そしてカウント用テキスト・ボックスに対してダミーの変更を行っています。
まとめ
この記事では、Web 開発の基本的なビルディング・ブロックと XUL とを自然に混在させられることを説明しました。XUL には豊富な UI 要素があり、それぞれの要素が豊富な属性とプロパティーを持っているため、それらを組み合わせることでアプリケーションや拡張機能を構築するための機能豊富なツールボックスを作ることができます。ブラウザーに直接 XUL をロードすれば、XUL アプリケーションのプロトタイピングやストーリーボード作成を手軽に素早く行うことができますが、スクリプトを使って何かを操作し始めると、予測しなかった困難に突き当たる可能性があります。幸いなことに、Mozilla の開発者達が作成したスタンドアロンのツールである、XULRunner というオプションがあります。XULRunner は、ブラウザーの外で XUL ファイルを実行できるため、厳しいセキュリティー・モデルを回避することができます。XULRunner は開発者が使用するツールであり、実際に使うのは (特に一部のプラットフォームでは) 苦労しますが、XUL プロジェクトの開発や XUL をデプロイするための重要な選択肢です。次回の記事では、低くなったセキュリティー障壁を利用してスクリプトを更新し、今回の記事で取り上げた各部分を Firefox の拡張機能としてパッケージ化する方法について説明します。
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | 
|  | Uche Ogbuji は、次世代の Web 技術を専門にソリューションを提供する会社、 Zepheira, LLC のパートナーです。Ogbuji 氏は、XML と RDF、そしてナレッジ管理アプリケーションのためのソープン・ソース・プラットフォーム 4Suite の中心開発者であり、Versa RDF 問い合わせ言語の中心開発者でもあります。彼はナイジェリア出身のコンピューター・エンジニア兼ライターであり、アメリカのコロラド州のボールダーに住み、業務を行っています。彼について詳しくは、彼のブログ Copia をご覧ください。 |
記事の評価
|