2 つめの WebExtension

初めての WebExtension を一通り読んでいる場合、既に Web Extension の書き方を知っていることと思います。この記事では、API の使い方をより詳しく説明するため、前回よりも少し複雑なアドオンを書いてみます。

このアドオンでは Firefox のツールバーにボタンを新しく追加します。このボタンをユーザがクリックすると、動物を選択できるポップアップが表示されます。ユーザが動物を選択すると、Web ページのコンテンツが選択した動物の画像に置き換わります。

これらの機能を以下のように実装していきます。

  • browser action(Firefox のツールバーに表示させるボタン)を定義
    このボタン用に次のものを用意します。
    • "beasts-32.png" というアイコン
    • ボタン押下時に開くポップアップ(HTML / CSS / JavaScript で記述)
  • アドオンのアイコンを定義
    このアイコン(ファイル名: "beasts-48.png")はアドオンマネージャに表示されます。
  • Web ページに読み込ませる content script "beastify.js" を作成
    このスクリプトによって Web ページが実際に変更されます。
  • Web ページを置き換える動物の画像をパッケージ化
    画像を "web-accessible なリソース" とし、web ページから参照できるようにします。

このアドオンは次のような全体構成になっています。

このアドオンはシンプルですが、WebExtensions API の基本的なコンセプトを多く含んでいます。

  • ツールバーにボタンを追加する
  • HTML / CSS / JavaScript を用いてポップアップのパネルを定義する
  • Web ページに content script を差し込む
  • 拡張機能の中において content script と他のスクリプトとを通信させる
  • Web ページで用いるリソースをアドオンにパッケージ化する

ソースコード一式は GitHub で参照できます

このアドオンを作成するには、Firefox 45 以上が必要です。

WebExtension を書く

新しいディレクトリを作成し、そのディレクトリに移動します。

mkdir beastify
cd beastify

manifest.json

それでは、"beastify" ディレクトリ配下に新しいファイル "manifest.json" を作成します。以下の内容を書き込んで保存してください。

{

  "manifest_version": 2,
  "name": "Beastify",
  "version": "1.0",

  "description": "Adds a browser action icon to the toolbar. Click the button to choose a beast. The active tab's body content is then replaced with a picture of the chosen beast. See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Examples#beastify",
  "homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/beastify",
  "icons": {
    "48": "icons/beasts-48.png"
  },

  "permissions": [
    "activeTab"
  ],

  "browser_action": {
    "default_icon": "icons/beasts-32.png",
    "default_title": "Beastify",
    "default_popup": "popup/choose_beast.html"
  },

  "web_accessible_resources": [
    "beasts/frog.jpg",
    "beasts/turtle.jpg",
    "beasts/snake.jpg"
  ]

}
  • 最初の 3 つのキー manifest_versionnameversion は必須であり、アドオンの基本的なメタデータを指定します。
  • description は省略可能ですが、設定しておくことをお勧めします。この値はアドオンマネージャに表示されます。
  • icons は省略可能ですが、 設定しておくことをお勧めします。この値はアドオンのアイコンを指定するものであり、アイコンはアドオンマネージャに表示されます。
  • permissions はアドオンに必要なパーミッションのリストです。ここでは activeTab パーミッション を要請しています。
  • browser_action はツールバーのボタンを指定するものです。ここでは 3 つの情報を指定しています。
    • default_icon ではボタンのアイコンを指定します(必須項目)。
    • default_title ではツールチップの文字列を指定します(省略可)。
    • default_popup ではユーザがボタンをクリックした際に表示されるポップアップを指定します。今回はポップアップを表示させたいので、アドオンに含める HTML ファイルを defualt_popup キーで指定しています。
  • web_accessible_resources は Web ページからアクセスしたいファイルのリストです。このアドオンでは、拡張機能に同梱した画像で Web ページを置き換えるため、画像を Web ページからアクセス可能にする必要があります。

パスはすべて manifest.json 自身からの相対パスで指定することに注意してください。

アイコン

アドオンにはアイコンを用意すると良いでしょう。このアイコンは、アドオンマネージャでアドオンのリスト横に表示されます(アドオンマネージャは "about:addons" の URL から確認できます)。 今回の manifest.json では "icons/beasts-48.png" を用意していると宣言しています。

まずは "beastify" ディレクトリの下に "icons" ディレクトリを作成します。次に、アイコンを "border-48.png" という名前で "icons" ディレクトリ内に保存します。必要であれば サンプルで使用しているアイコン を利用しても構いません(このアイコンは Aha-Soft’s Free Retina iconset から引用したものであり、該当する ライセンス の下で使用しています)。

ここでアイコンを自分で用意する場合は 48x48 ピクセルのサイズにする必要があります。高解像度のディスプレイには 96x96 ピクセルのアイコンを表示させたい場合は、manifest.json の icons オブジェクトに 96 というプロパティで設定してください。

"icons": {
  "48": "icons/beasts-48.png",
  "96": "icons/beasts-96.png"
}

ツールバーのボタン

ツールバーのボタンにもアイコンが必要です。 今回の manifest.json では "icons/beasts-32.png" を用意していると宣言しています。

アイコンを "beasts-32.png" という名前で "icons" ディレクトリ内に保存します。必要であれば サンプルで使用しているアイコン を利用しても構いません(このアイコンは IconBeast Lite のアイコン集 から引用したものであり、該当する ライセンス の下で使用しています)。

ポップアップを使わない場合、ユーザがボタンをクリックした際にはクリックイベントがアドオンに向けて送出されます。ポップアップを使う場合にクリックイベントは送出されず、代わりにポップアップが開きます。今回はポップアップが必要なので、次の項で作成しましょう。

ポップアップ

今回のポップアップでは、ユーザが 3 つの動物から 1 つ選択できる機能を持つこととします。

アドオンのルートディレクトリ配下に "popup" というディレクトリを新しく作成します。ここにはポップアップ用のコードを保管します。ポップアップは次の 3 ファイルから構成されます。

  • choose_beast.html パネルのコンテンツを定義する
  • choose_beast.css コンテンツのスタイルを指定する
  • choose_beast.js アクティブなタブで content script を実行し、ユーザの選択を処理する

choose_beast.html

HTML ファイルは次のようになります。

<!DOCTYPE html>

<html>
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="choose_beast.css"/>
  </head>

  <body>
    <div class="beast">Frog</div>
    <div class="beast">Turtle</div>
    <div class="beast">Snake</div>

    <script src="choose_beast.js"></script>
  </body>

</html>

単にここでは動物ごとに要素を与えています。通常の Web ページと同じように CSS と JS ファイルを読み込んでいることに注意してください。

choose_beast.css

この CSS ではポップアップのサイズを固定し、3 つの選択肢がポップアップを埋めるようにし、基本的なスタイリングを施しています。

html, body {
  width: 100px;
}

.beast {
  margin: 3% auto;
  padding: 4px;
  text-align: center;
  font-size: 1.5em;
  background-color: #E5F2F2;
  cursor: pointer;
}

.beast:hover {
  background-color: #CFF2F2;
}

choose_beast.js

ポップアップ用の JavaScript ではクリックイベントをリッスンします。3 つの動物のどれかがクリックされた場合、アクティブなタブに content script を差し込みます。content script が読み込まれると、動物の選択のメッセージを送ります:

/*
動物の名前を受け取り、対応する画像の URL を返す
*/
function beastNameToURL(beastName) {
  switch (beastName) {
    case "Frog":
      return chrome.extension.getURL("beasts/frog.jpg");
    case "Snake":
      return chrome.extension.getURL("beasts/snake.jpg");
    case "Turtle":
      return chrome.extension.getURL("beasts/turtle.jpg");
  }
}

/*
ポップアップのクリックイベントをリッスンする。

動物以外がクリックされた場合は最初で return する。

そうでない場合、クリックされたノードの textContent から動物の名前を取得する。

アクティブなタブに content script "beastify.js" を差し込む。

続いて、アクティブなタブへの参照を取得し、"beastify.js" にメッセージを送信する。
このメッセージには、選択された動物に対応する画像の URL を含んでいる。
*/
document.addEventListener("click", function(e) {
  if (!e.target.classList.contains("beast")) {
    return;
  }

  var chosenBeast = e.target.textContent;
  var chosenBeastURL = beastNameToURL(chosenBeast);

  chrome.tabs.executeScript(null, {
    file: "/content_scripts/beastify.js"
  });

  chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    chrome.tabs.sendMessage(tabs[0].id, {beastURL: chosenBeastURL});
  });

});

ここでは 3 つの WebExtension API メソッドを使用しています。

  • chrome.tabs.executeScript では "content_scripts/beastify.js" にある content script をアクティブなタブに差し込んでいます。
  • chrome.tabs.query ではアクティブなタブを取得しています。
  • chrome.tabs.sendMessage ではアクティブなタブの content script にメッセージを送信しています。このメッセージには、選択された動物に対応する画像の URL が含まれています。

content script

アドオンのルートディレクトリ配下に "content_scripts" というディレクトリを新しく作成します。続いてそこに "beastify.js" という名前のファイルを作成し、下記のスクリプトを記述します。

/*
beastify():
* document.body に含まれるノードをすべて削除し、
* 選択された動物を挿入し、
* 自分自身をリスナから削除する 
*/
function beastify(request, sender, sendResponse) {
  removeEverything();
  insertBeast(request.beastURL);
  chrome.runtime.onMessage.removeListener(beastify);
}

/*
document.body に含まれるノードをすべて削除する
*/
function removeEverything() {
  while (document.body.firstChild) {
    document.body.firstChild.remove();
  }
}

/*
動物の画像の URL を受け取り、画像を指す IMG 要素の作成・スタイル適用を行い、
作成したノードをドキュメント内に挿入する
*/
function insertBeast(beastURL) {
  var beastImage = document.createElement("img");
  beastImage.setAttribute("src", beastURL);
  beastImage.setAttribute("style", "width: 100vw");
  beastImage.setAttribute("style", "height: 100vh");
  document.body.appendChild(beastImage);
}

/*
アドオンからのメッセージを受信するリスナに beastify() を指定する
*/
chrome.runtime.onMessage.addListener(beastify);

この content script では、アドオンからの(つまり、先ほどの "choose_beast.js" からの)メッセージを受信するリスナ関数を追加しています。このリスナでは次の処理を行います。

  • document.body 内の要素をすべて削除する
  • 与えられた URL を指す <img> 要素を作り、DOM に挿入する
  • メッセージリスナを削除する

動物

最後に、動物の画像を用意しておく必要があります。

アドオンのルートディレクトリ配下に   "beasts" という名前のディレクトリを新しく作成し、その中に 3 つの画像を適切な名前で保存します。画像は GitHub リポジトリ から、またはここからでも取得できます。

動かしてみよう

正しいファイルが正しい場所にあるかどうか、もう一度確認してください。

beastify/

    beasts/
        frog.jpg
        snake.jpg
        turtle.jpg

    content_scripts/
        beastify.js

    icons/
        beasts-32.png
        beasts-48.png

    popup/
        choose_beast.css
        choose_beast.html
        choose_beast.js

    manifest.json

Firefox 45 以降では、WebExtensions をディスクから一時的にインストールできるようになりました。

Firefox で "about:debugging" を開き、"一時的なアドオンを読み込む" をクリックし、自分で作成した manifest.json ファイルを選択してください。アドオンのアイコンが Firefox のツールバーに表示されているはずです。

適当な Web ページを開き、アドオンのアイコンをクリックし、動物を選択してください。すると Web ページが動物の画像に置き換わるはずです。

ドキュメントのタグと貢献者

 このページの貢献者: mtwwstj9, hashedhyphen, teoli, Uemmra3
 最終更新者: mtwwstj9,