先取り! Google Chrome Extensions

第3回 Chrome Extensionsの作り方#2

この記事を読むのに必要な時間:およそ 8.5 分

この記事で取り上げているAPIは現在と使い方が異なっていたり,使用できなくなったものを含んでいます。

特にToolstrips APIは最新のChromeでは使用できなくなっています。詳しくは続・先取り! Google Chrome Extensionsをご覧ください。

前回はExtensionsの作り方からドキュメント,開発ツールについて紹介しました。今回は前回作成したSBMカウンタを改良しながら各APIの使い方を見ていきます。

前回の復習とバグフィックス

前回作成したSBMカウンタは,見ているページのURLのソーシャルブックマークサービスでのブックマーク数を表示するExtensionでした。ToolstripsというAPIを使用しましたが,このToolstripの使い方に2つのバグがあったので,まずはこちらの修正を行います。

一つ目のバグは,ウィンドウを2つ以上開いた場合に発生します。Toolstripはウィンドウに対して設置されるので,ウィンドウを複数開けばToolstripも複数開かれることになります。

このとき,Tabs APIのonSelectionChangedイベントは自分のウィンドウ以外でのイベントも受け取ってしまうので,バックグラウンドウィンドウのToolstripも一緒に更新されてしまいます。これを防ぐため,ウィンドウの一致を確認することにします。

onSelectionChangedのバグ修正(windowIdの一致を確認)

chrome.tabs.onSelectionChanged.addListener(function(tabid){
  chrome.tabs.get(tabid, function(tab){
    if (tab.windowId === current_window.id) {
      run_on_tab(tab);
    }
  });
});

続いて,もうひとつのバグはページを読み込んだ際に発生します。Tabs API の,onUpdatedイベントは読み込みの開始(loading)と終了(complete)の2回発生するので,前回のコードでは2回書き換えを行ってしまっていました。よって,読み込み状態がloadingの場合だけ処理を行うように修正します。

onUpdatedのバグ修正(loadingの場合だけ処理)

chrome.tabs.onUpdated.addListener(function(tabid, inf){
  if (inf.status === 'loading') {
    chrome.tabs.getSelected(current_window.id, function(tab){
      if (tab.id === tabid) {
        run_on_tab(tab, true);
      } else {
        run_on_tab(tab, false, true);
      }
    });
  }
});

なお,この2つの修正は前回の記事が公開された時点でパッケージとソースには反映済みとなっています。

Page Actions と Background Pages

続いて,Page Actions と Background Pagesの使い方を見ていきます。Page Actionsはアドレスバー(OmniBox)の中にボタンを表示するAPIで,まずはこのPage Actionsを使用するためにmanifest.jsonにその定義を書きます。対象とするサービスは前回同様で,はてなブックマークとdeliciousです。

Page Actionsの定義

  "page_actions": [
    {
      "id": "hatena",
      "name": "add hatena bookmark",
      "icons": [
        "hatena.favicon.gif"
      ]
    },
    {
      "id": "delicious",
      "name": "add delicious",
      "icons": [
        "delicious.small.gif"
      ]
    }
  ],

idはそのpage_actionsの中でそれぞれがユニークである必要があります。nameはアイコンにマウスオーバーした時などにツールチップとして表示されます(ただし,これを動的に変更することも可能です)⁠iconsはアドレスバー(OmniBox)の中に表示される画像で,複数定義しておくことができ,どの画像を設置するか制御できます。画像が16×16pxよりも大きい場合は自動的にリサイズされます。

続いて,Page Actionを制御するためのBackground Pagesを定義します。Background Pagesは1つの拡張に対して1つだけ持てる,表には現れないページで,バックグラウンドでの処理を一手に引き受けるAPIです。ToolstripsでもPage Actionを制御することは可能ですが,前述した通り複数ウィンドウの制御を考慮しないといけないため,ToolstripsよりBackground PagesのほうがPage Actionsの制御に適しています。

Background Pagesの定義

  "background_page": "background.html",

では,Background PageにPage Actionsの制御用のJavaScriptを記述します。コードはサービスの定義,アクションの登録,アクション時の動作の2つのパートで構成します。

サービスの定義

var PageActionServices = [
   {
      "id":"hatena",
      "title":"add hatena bookmark",
      "url":"http://b.hatena.ne.jp/add?&url=#{encoded_url}&title=#{title}"
   },
   {
      "id":"delicious",
      "title":"add delicious",
      "url":"http://delicious.com/save?v=5&jump=close&url=#{encoded_url}&title=#{title}"
   }
];

このサービスの定義はToolstripsで使用している定義と共有する形にしてもよいのですが,ここでは個別に定義しています。Page Actionsはアドレスバー(OmniBox)の表示領域を狭くするので,実際に使用するかどうか慎重に決める必要があります。

続いて,Page Actionsを各タブに設置する処理を記述します。

enableForTabによるActionの登録

chrome.tabs.onUpdated.addListener(function(tabid, inf){
  if (inf.status !== 'loading') return;
  chrome.tabs.get(tabid, function(tab){
    if (!/^http/.test(tab.url)) return;
    PageActionServices.forEach(function(service){
      var opt = {
        tabId:  tab.id,
        url:    tab.url,
        title:  service.title,
        iconId: 0
      };
      chrome.pageActions.enableForTab(service.id, opt);
    });
  });
});

ここでもTabs APIのonUpdatedイベントでタブを取得し,PageActions APIのenableForTabを呼び出します。enableForTabの第1引数はmanifest.jsonで定義したid,第2引数はタブID,URL,タイトル,アイコンID(manifest.jsonで指定したもの)をもったオブジェクトになります。タイトルとアイコンIDは省略可能です。

これでアドレスバー(OmniBox)へのアイコンの登録ができました。続いて,アイコンをクリックした際のアクションを定義します。

enableForTabによるActionの登録

PageActionServices.forEach(function(service){
  chrome.pageActions[service.id].addListener(function(id, tabinf){
    if (!tabinf){//for Chrom 3
      tabinf = id.data;
      id = id.pageActionId;
    }
    chrome.tabs.get(tabinf.tabId,function(tab){
      var inf = {
        encoded_url:encodeURIComponent(tab.url),
        title:tab.title
      };
      var opt = {
        url: fill(service.url, inf),
        selected: true
      };
      chrome.tabs.update(tab.id,opt);
    });
  });
});
function fill(str, opt){
  function replacer(_, _$){
    return opt[_$] || '';
  }
  return str.replace(/#\{([^}]+)\}/g, replacer);
}

chrome.pageActionsの各IDに対してaddListenerでイベントを登録しています。Chrome 3では1つの引数にデータが入っていましたが,Chrome 4ではリスナー関数は2つの引数をもつように変更されています。そこで,Chrome 3をChrome 4の実装に合わせるための互換コードを入れています。

あとはタブIDからTabオブジェクトを取得し,そのタイトルとURLでブックマークの追加画面へ遷移させています。Page Actions APIの基本的な使い方は以上となります。

著者プロフィール

太田昌吾(おおたしょうご,ハンドルネーム:os0x)

1983年生まれ。JavaScriptをメインに,HTML/CSSにFlashなどのクライアントサイドを得意とするウェブエンジニア。2009年12月より、Google Chrome ExtensionsのAPI Expertとして活動を開始。

URLhttp://d.hatena.ne.jp/os0x/

コメント

コメントの記入