Thunderbird の拡張機能(アドオン)を作ってみた

Firefox 3ではじめる拡張機能開発:特集|gihyo.jp … 技術評論社 が非常に面白いので
自分も拡張機能を作ってみることにした。ただし、あえて Thunderbird で。

今回作るアプリ - SubjectHelper

http://japan.cnet.com/blog/0040/2008/01/17/entry_25004191/ を実践するための拡張機能を開発する。
メール作成画面の件名にボタンを追加して、そこから「要返信」とか「参考」とかを
件名に挿入できるようにするだけ。ショボいって言うなー><


SubjectHelper の動作イメージ

準備

ポインタファイル(subjecthelper@mallowlabs.s206.xrea.com)の作成

C:\Documents and Settings\Owner\Application Data\Thunderbird\Profiles\{#ID}\extensions
の下にポインタファイルを作成する。
Thunderbird は上記のディレクトリの下にディレクトリがあれば中身を拡張機能だと認識し、
ファイルがあればファイルに書かれたパスを拡張機能だと認識するらしい。


subjecthelper@mallowlabs.s206.xrea.com

C:\Thunderbird\SubjectHelper
DOM Inspector のインストール

XUL アプリの拡張機能の開発には DOM Inspector が必須。
ないと話にならないのでインストールしておく。
http://developer.mozilla.org/ja/docs/DOM_Inspector

アプリケーション開発

インストールマニフェスト(install.rdf)の作成

C:\Thunderbird\SubjectHelper 以下に install.rdf を作成する。
このファイルは、拡張機能に必ず含まれており、拡張機能の情報を含む。


install.rdf

<?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">
    <em:id>subjecthelper@mallowlabs.s206.xrea.com</em:id>
    <em:type>2</em:type>
    <em:name>Subject Helper</em:name>
    <em:version>0.1</em:version>
    <em:description>Helps to input mail subject.</em:description>
    <em:creator>mallowlabs</em:creator>
    <em:homepageURL>mallowlabs.s206.xrea.com/subjecthelper</em:homepageURL>
    <em:targetApplication>
      <!-- Thunderbird -->
      <Description>
        <em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
        <em:minVersion>2.0b1</em:minVersion>
        <em:maxVersion>2.0.0.*</em:maxVersion>
      </Description>
    </em:targetApplication>
  </Description>

</RDF>

注意するべき点が2点ある。

  1. /Description/em:id は先ほどのポインタファイルの名前と必ず一致するようにする。
  2. /Description/em:targetApplication/Description/em:id の値は Thunderbird の値。Firefox の場合は別の GUID を指定する。


この時点で Thunderbird を起動し、アドオンの一覧を見ると
作成したアプリケーションがインストールされているのがわかる。
install.rdf を編集したときには、ポインタファイルをどこかにコピーし、
アドオンをアンインストールしてから再びポインタファイルを設置しなければ
ならないことに注意する。

クロムマニフェスト(chrome.manifest)の編集

アドオンのインストールをすると chrome.manifest というファイルができているので
このファイルを以下のように編集する。


chrome.manifest

content  subjecthelper  content/
overlay  chrome://messenger/content/messengercompose/messengercompose.xul  chrome://subjecthelper/content/overlay.xul

1行目でパッケージを登録している。
2行目でメール作成画面に対してクロスパッケージオーバレイの宣言をしている。
詳しくは元記事を参照。

XUL ドキュメントを書く

拡張機能開発の肝はオーバレイである。
XUL アプリの GUIXML で書かれており、
拡張はその XML にオーバーレイする XML を記述することで行う。
XML の中でも id がつく要素が拡張ポイントになっている。

content/overlay.xul

<?xml version="1.0"?>
<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <textbox id="msgSubject">
    <button popup="_child" type="menu" id="subject-helper-button"
     style="-moz-binding: url('chrome://subjecthelper/content/subjectHelper.xml#subjectHelper');">
      <menupopup>
        <script><![CDATA[
        function subjectHelperCommand(event) {
            var msgSubject = document.getElementById("msgSubject");
            msgSubject.value = event.label + ":" + msgSubject.value;
            msgSubject.focus();
            gContentChanged = true;
            SetComposeWindowTitle();
        }
        ]]></script>
        <menuitem label="回答" accesskey="R" oncommand="subjectHelperCommand(this);"/>
        <menuitem label="返不要" accesskey="U" oncommand="subjectHelperCommand(this);"/>
        <menuitem label="送付" accesskey="T" oncommand="subjectHelperCommand(this);"/>
        <menuitem label="質問" accesskey="Q" oncommand="subjectHelperCommand(this);"/>
        <menuitem label="保存" accesskey="S" oncommand="subjectHelperCommand(this);"/>
        <menuitem label="参考" accesskey="F" oncommand="subjectHelperCommand(this);"/>
        <menuitem label="案内" accesskey="I" oncommand="subjectHelperCommand(this);"/>
        <menuitem label="要返信" accesskey="N" oncommand="subjectHelperCommand(this);"/>
        <menuitem label="草案" accesskey="D" oncommand="subjectHelperCommand(this);"/>
        <menuitem label="迄" accesskey="L" oncommand="subjectHelperCommand(this);"/>
      </menupopup>
    </button>
  </textbox>
</overlay>

2行目の overlay 要素は固定。いわゆるおまじない。
3行目の texbox 要素がオーバーレイする GUI 部品を指定している。
メール作成画面の id が msgSubject である textbox、
つまり件名の入力ボックスにオーバーレイをするという意味である。
# このオーバーレイしたい部品の id を調べるのに DOM Inspector を使う。


件名の入力ボックスの下に button 要素を追加している。
style の -moz-binding については後述。
type 属性に menu を指定するとボタンがクリックされたときに
popup 属性で指定された メニューを表示できる。
popup 属性に _child を指定すると button 要素の子要素にある
menupopup 要素のメニューを表示できる。
menuitem 要素がひとつの項目をあらわし、クリックされると JavaScript で記述された
コード(ここでは subjectHelperCommand 関数)がキックされる。
subjectHelperCommand はメニューのラベルを取得して、
件名の入力ボックスに取得した値を挿入する。
スクリプトの最後の2行は,メール作成画面に件名が変更されたことを通知する処理である。

-moz-binding を使う

先ほど説明を省略した -moz-binding は -moz-binding - CSS: カスケーディングスタイルシート | MDN で解説されている。
正直なところよくわかっていないが
例えば OK ボタンと Cancel ボタンを持つ GUI 部品に名前をつけて
あとからそれを使うことができるような仕組みらしい。


今回は button だけど 表示はアイコンのみという
GUI 部品を実現するために使用している。


content/subjectHelper.xml

<?xml version="1.0"?>
<bindings id="subjectHelperBindings"
   xmlns="http://www.mozilla.org/xbl"
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
   xmlns:xbl="http://www.mozilla.org/xbl">

  <binding id="subjectHelper">
    <resources>
      <stylesheet src="chrome://subjecthelper/content/subjectHelper.css"/>
    </resources>
    <content popup="_child">
      <children/>
      <xul:stack flex="1">
        <xul:hbox align="center">
          <xul:image class="subject-helper-button-image" xbl:inherits="src"/>
        </xul:hbox>
        <xul:hbox align="center">
          <xul:image class="subject-helper-button-dropmarker"/>
        </xul:hbox>
      </xul:stack>
    </content>  
  </binding>

</bindings>

xul:image 要素の1つ目はスクリーンショットの電球のアイコン。
xul:image 要素の2つ目はスクリーンショットの下向き黒三角のアイコンである。
細かなスタイルは stylesheet 要素で指定した CSS で記述する。


content/subjectHelper.css

#subject-helper-button  {
  margin-top: 0px;
  margin-bottom: 0px;
  -moz-margin-start: 0px;
  -moz-margin-end: 2px;
  cursor: default;
}
.subject-helper-button-image {
  margin: 0px;
  list-style-image: url("chrome://subjecthelper/content/img/icon.png");
}
.subject-helper-button-dropmarker {
  -moz-margin-start: 7px;
  margin-top: 5px;
  list-style-image: url("chrome://messenger/skin/icons/search-arrow.gif");
}


content/img/icon.png
サイズが 12 x 12 のアイコンを置く。


ここまでで Thunderbird を再起動すると
拡張が動作しているのがわかる。

完成

しちゃった。


リリースパッケージを作るには
install.rdf/chrome.manifest/content を zip で固めて
拡張子を xpi に変更するだけでいい。

所感

XUL アプリの拡張は install.rdf/chrome.manifest の書き方と
XUL のオーバーレイの感覚がわかれば結構書けちゃう感じ。
もちろん XPCOM がまったくわかってないのでちゃんとしたアプリは書けないけど
少なくとも拡張機能を作っている気分は味わえるのでなんとなく楽しい。

2008.09.05 追記

githubソースコード置いた。MIT ライセンスで。

git://github.com/mallowlabs/thunderbird-subject-helper.git

バイナリはこちらから

http://github.com/mallowlabs/thunderbird-subject-helper/tree/master%2Frelease%2Fsubject-helper.xpi?raw=true