gihyo.jp/dev/serial/01/chrome-web-store/0006">前回はWebアプリの設定と保存を通して、Options PageとWeb Storageについて詳細を解説しました。今回は引き続きOdometerに機能を追加する形で、Context MenusとOmniboxについて解説していきたいと思います。
検索ボックスとコンテキストメニューの拡張
これまでは、Odometerを使うためにWebアプリを起動して画面から住所を検索し、目的地を入力していました。わざわざWebアプリを起動しなくても、もっと素早く住所を検索したいとか、ほかのWebサイトにある住所を直接検索したいといった要望があるかもしれません。これらを実現するための仕組みとして、Chromeの検索ボックス(アドレスバー)を拡張するOmniboxやWebサイト内でのコンテキストメニュー(右クリックメニュー)を拡張するContext Menusがあります。今回はこの2つを使って、検索ボックスとコンテキストメニューから素早くOdometerを呼び出し、住所検索を行えるように修正します。
Webアプリの構成
今回は、Webアプリを構成するファイルに追加はありません。odometer.jsとbackground.js、そしてmanifest.jsonを変更して機能を追加しています。
検索ボックスを拡張するための指定として、新たに "omnibox" という項目を追加しています。その中の "keyword" は、検索ボックスからOdometerを呼び出すためのトリガーとなる最初のキーワードを指定します。ここでは "Odometer" を指定していますが、大文字と小文字は区別しません。詳細は後述します。
コンテキストメニューを拡張するためには、"permissons"に "contextMenus" を追加します。また、検索ボックスやコンテキストメニューからOdometerを呼び出すために "tabs" も合わせて追加しています。
Omnibox
Omniboxは、Chromeの検索ボックス(アドレスバー)を拡張するための仕組みです。みなさん普段はこの検索ボックスを使ってGoogleなどで検索をしているかと思います。Omniboxでは、この検索ボックスからキーワードを検索エンジンではなくWebアプリへ渡すことができるようになります。また、キーワードを入力する際のサジェストなどもカスタマイズすることができます。
Omniboxの使い方
先に実際のOmniboxの使い方を説明しましょう。検索ボックスには、検索エンジンによる検索のほかに、お気に入りや履歴などからもサジェストが表示されます。その中でWebアプリのアイコンが付いたサジェストが、そのWebアプリを呼び出すためのものになっています。
検索ボックスにマニフェストファイルで指定したキーワードを入力する
Webアプリのアイコンが表示されたサジェストを選択する
エンターキーで入力完了とWebアプリの呼び出し
続けてWebアプリに渡すキーワードを入力
OmniboxからのWebアプリの呼び出し
今回は、マニフェストファイルで指定した"Odometer"という文字列を検索ボックスに入力すると、その後に続くキーワードをパラメーターとしてOdometerを呼び出すことになります。パラメーターを住所としてOdometerで検索するようにしてみましょう。検索ボックスの設定は非常に簡単で、各種イベントを登録するだけです。ここでは、background.js内でchrome.omnibox.onInputEnteredイベントを登録しています。
onInputEnteredイベントは、検索ボックスでキーワードを入力し、エンターキーを押した際のイベントになります。このイベントには入力されたキーワードを引数に持つコールバックを指定します。入力されたキーワードをsearchOnAppメソッドで検索して表示しています。searchOnAppメソッドは今回作成したもので、Odometerが既に起動していればそのタブで検索を行い、まだ起動していなければ新たにOdometerを起動してから検索を行っています。Omniboxとは直接関係はありませんが詳しくみていきましょう。
selectOrCreateTab メソッドでOdometerのタブを選択、もしくは作成をします。chrome.tabs.getAllInWindowメソッドを使って指定のURLを持つタブが存在するかチェックし、既に存在する場合chrome.tabs.updateメソッドを使ってそのタブを選択しています。chrome.tabs.updateメソッドはURLだけでなく、その他のステータスを変更する場合にも利用することができます。Odometerのタブが存在しなければchrome.tabs.createメソッドを使ってタブを作成しています。
Odometerで検索するには、chrome.extension.getViewsメソッドを使ってタブのWindowオブジェクトを取得し、グローバルに定義されているsearchByTextメソッド呼び出しています。ポイントは、新たに作成したタブのstatusをチェックし、"loading"となっていた場合はすぐには検索を実行せず、対象のWindowオブジェクトへsearchText変数を定義していることです。表示側はsearchText変数が定義されていれば準備ができ次第、検索を実行します。若干スマートではないかもしれませんが、とりあえず今回はこの方法で実装しました。
Omniboxのサジェスト
今回は利用していませんが、Omniboxのサジェストの設定方法についても説明します。デフォルトのサジェストを設定するには、chrome.omnibox.setDefaultSuggestionメソッドを使います。また.キーワード入力中のサジェストはchrome.omnibox.onInputChangedイベントのコールバックの中で設定します。サジェストは、contentとdescriptionを持つオブジェクトで構成されます。contentは実際にサジェストするキーワードで、descriptionは検索ボックスに候補として表示される内容になります。サンプルを以下に示します。
表1 chrome.omnibox
メソッド/プロパティ | 説明 |
setDefaultSuggestion(suggest) | デフォルトのサジェストを設定する |
表2 chrome.omnibox(イベント)
イベント | 説明 |
onInputCancelled | キーワードの入力がキャンセルイベント |
onInputChanged | キーワードの入力変更イベント
コールバックにキーワードとサジェストを引数に持つ。function(text, suggest){…} |
onInputEntered | キーワードの入力完了イベント
コールバックにキーワードを引数に持つ。function(text){…} |
onInputStarted | キーワードの入力開始イベント |
Context Menus
Context Menusは、Chromeのコンテキストメニュー(右クリックメニュー)を拡張するための仕組みです。通常であれば、コンテキストメニューにはフォーカスした対象に合わせたメニューが表示されています。例えばテキストを選択している場合であれば、「コピー」や「Googleで検索」、「要素を検証」などのメニューが表示されています。Context Menusでは、これらのメニューに加えてWebアプリ独自のメニューを追加します。
メニューの作成
今回は、選択したテキストを「住所検索」するメニューを追加します。メニューを作成するには、chrome.contextMenus.createメソッドを利用します。引数にとるオブジェクトでメニューの内容を細かく指定していきます。メニューがクリックされた場合のコールバックもこのオブジェクトのonclickプロパティに登録します。
titleでメニューの表示名を設定し、contextsでフォーカスした対象がどういったものの場合にメニューを表示するかどうかを設定します。ここでは、テキストを選択している場合に表示される"selection"を指定しています。contextsにはそのほかにもリンク要素に対して表示される"link"や画像に対して表示される"image"などがあります。contextsの設定によってonclick時のコールバックに返されるオブジェクトの内容が変わります。contextsが"selection"の場合、selectionTextプロパティから選択したテキストを取得することができます。
さまざまなメニューと階層化
単なるラベルのメニュー以外にも、チェックボックスやラジオボタン、セパレーターなどを作成することができます。また、chrome.contextMenus.createメソッドの戻り値であるメニューIDを使って階層化することもできます。以下にサンプルコードを示します。
表3 chrome.contextMenus
メソッド/プロパティ | 説明 |
create(createProperties, callback) | メニューを作成する |
remove(menuItemId, callback) | メニューを削除する |
removeAll(callback) | メニューをすべて削除する |
update(id, updateProperties, callback) | メニューを更新する |
表4 createProperties/updateProperties
メソッド/プロパティ | 説明 |
type | メニューのタイプ
normal: ラベル(デフォルト)
checkbox: チェックボックス
radio: ラジオボタン
separator: セパレーター |
title | メニューの表示名
|
checked | typeがcheckboxまたはradioの場合のチェック状態 |
contexts | メニューを表示するフォーカスの対象を配列で指定する
all: すべて
page: ページ(デフォルト)
frame: iframe内
selection: テキスト選択
link: リンク
editable: 入力可能フォーム
image: 画像
video: 動画
audio: 音声 |
onclick | クリック時のコールバック
function(info, tab){…}
infoは、下記のOnClickDataを参照 |
documentUrlPatterns | メニューを表示するURLパターン |
targetUrlPatterns | contextsがimage、video、audioの場合にメニューを表示する対象のURLパターン |
表5 OnClickData
メソッド/プロパティ | 説明 |
menuItemId | メニューID |
parentMenuItemId | 親メニューID |
mediaType | メディアタイプ
contexts: image/video/audio |
linkUrl | リンクURL
contexts: link |
srcUrl | ソースURL
contexts: image/video/audio |
pageUrl | ページURL
contexts: page |
frameUrl | フレームURL
contexts: frame |
selectionText | 選択テキスト
contexts: selection |
editable | 編集可能かどうか
contexts: editable |
※:contextsは同時に複数マッチする場合があります。
まとめ
これで、Odometerを検索ボックスやコンテキストメニューから呼び出すことができるようになりました。検索ボックスやコンテキストメニューは、単にWebアプリを呼び出す導線というだけでなく、インターフェースとしてさまざまなことに応用できるので、是非とも何か面白い使い方を考えてみてください。
今回は、OmniboxとContext Menusの詳細を解説しました。次回も引き続きさまざまなAPIを解説していきたいと思います。