Context Menus と Omnibox を使って API の無い Web アプリの検索を実行する。

Chrome Extensions を作ろう

ちょっと社内の機能発表の用にネタアプリでも作ろうと思ったのが発端。うちは社長から営業、管理に至るまで Google Chrome が大好きで(弊社サービスは Chrome は公式にはサポートしていないが、社内ユーザーが多すぎて渋々対応している。。まあ特に何もしなくてもいい良い子なのでいいのですが)、せっかくだから弊社サービスの検索機能を Chrome から呼び出せるようにしてやろうと考えた訳です。

API が無いや。。

まあ弊社サービスはまだ Web API が無い状態で Chrome から何かしようにも REST APi 叩いて〜みたいなカッチョいい事はできないわけです。
つまり Web の画面を使って何かするしかない。しかも、本番サービスで使えるようにしたいので余計な穴(クエリ引数を処理するとか)は一切開ける訳にもいかず最初から茨の道に見えました。

検索文字列を取得する

このあたりは Context Menus も Omnibox も楽勝で取得できる。

以下では manifest.json への記述は省略してるので注意してください。

Context Menus の場合

今回は選択中のテキストで検索するっていう機能に絞ります。
以下の background.html に書いておけばOK。

var id = chrome.contextMenus.create({"title" : "コンテキストメニューに出したいタイトル", "contexts": ["selection"], "onclick": genericOnClick});

function genericOnClick(info, tab) {
  console.log(info.selectionText); // 選択中にコンテキストメニューを呼び出した際の文字列が取得できる
}

実はコンテキストメニューのタイトルに選択中のテキストを表示したかったんですが、方法が分かりませんでした。現状はできなさそうに見えます。

Context Menus - Google Chrome Extensions

Omnibox の場合

もっと簡単になります。

chrome.omnibox.onInputEntered.addListener(function(text) {
  console.log(text); // manifest.json で設定したキーワードで検索した場合の文字列が取得できる
});

Omnibox - Google Chrome Extensions

新しいタブで開く

結局 API が無いので Chrome Extensions でやれる事はひとまずここまでです。
とりあえず自社サービスのURL を開いた状態で Tab を開くわけですが、本来であれば「ログイン」という行為が必要です。ただ、そこを API 抜きでやろうとすると割と面倒くさい(というか Get してトークン抜いて、POSTし直してぐらいですが、設定画面作る時間がなかった。。)ので、ログイン状態のセッションを維持してる状態での使用を想定しているという仕様にしていきなり開くと検索窓のある画面に入るという事にします。

tabs
var urls = 'サービスの URL';
chrome.tabs.create({
  url:urls,
  selected:true // 選択状態で開く
});

Tabs - Google Chrome Extensions

検索を実行する

つまり何がしたいかと言うと、API が無い上に、クエリ引数で検索ワードを渡す仕様にもなっていないので、検索するには POST のリクエストを飛ばすしか無いわけです。新しいタブを開いたところで、そのリクエストを強引に飛ばすという方法もあるでしょうが、不精な私はてっとり早く、検索窓に取得した検索用文字列を入れて、検索ボタンを押してやればいいんではないかと考えたわけですね。(この時点で発表会まで残り3時間、、本来の発表のためのスライドも作れていない。)

executeScript

スマートにやる方法が思いつかなかったので、タブを開いた時点でのイベントでスクリプトを流しこむという手段を取りました。

chrome.tabs.create({
  url:urls,
  selected:true
}, function(tabid) {
  var srcs = "document.getElementById('検索窓テキストボックスのID').value = '" + searchWord + "';"
               + "document.getElementById('検索のトリガーとなるボタンのID').click();"
  chrome.tabs.executeScript(tabid, { code : srcs });
});

このタブを開いた時点のイベントってのが、タブの中の DOM が構築し終わった後なのかがよく分からなかったのですが、とりあえず動いたのでよしとしました。見てる限りは全ての DOM が構築される前に呼ばれてるように見えますが、まあ大丈夫だったようです。必要な要素は上の方に集まっていましたし。

まとめ

まあ、手抜きも甚だしいツールではありましたが、フロントメンバーには少し驚いてもらえたりでやってみるもんだなーと思ったり。
後、FireFox Addon と比べて Chrome Extensions は楽ですね。必要なものも本当に少ないですし。今回も manifest.json と background.html しか作ってないですからねー。
ドキュメントやサンプルも充実してるので作るのにも困らなくて非常に良いですね。