41
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

Chromeエクステンションでcontentの情報を取得する

初めてChrome Extention作ってみました。
https://github.com/NewGyu/redmine_tickets_printable

そもそも論的なところはこんないいまとめ

があるので割愛して、自分が詰まったところをメモ代わりに書いておきます。

ざっくり要件

今回作ったのはRedmineのチケット一覧を付箋みたいにブロックを並べた見た目にするものです。

Redmineのチケット一覧はリスト形式で、それをA4印刷して貼りだすと小さくて読めないので大きく、付箋っぽくしようというものです。

before
before.PNG

after
after.PNG

そして、今回はブラウザアクションではなくページアクション(該当ページの場合にオムニボックスにアイコンが表示される奴)で、
pageAction.PNG

別タブに印刷用ページを開く
tab.PNG

というものです。

オムニボックス(アドレスバー)にアイコンが出ない

まず最初に詰まったのがアイコンが出ないんですね。

manifest.json
  "page_action": {
    "default_icon" : "icon/unko16.png"
    ,"default_title": "印刷用ページ出す"
  },

こう書いとけば出るんだろうくらいに思ってましたが、実際には明示的にchrome.pageAction.showする必要がありました。

chrome.pageAction.showはbackgroundからじゃないと呼べない

どうもcontent scriptを使うのが常套手段のようです。content scriptは懐かしいGreaseMonkeyみたいに、ページにリアクションするやつですね。
ところが、chrome.pageAction.showはcontent scriptからはコールできないようです。そのため、次のような周りくどいことをする必要がありました。

1. まずバックグラウンドにメッセージを送る

contentscript.js
chrome.runtime.sendMessage({issues: issues}, function(response) {});

今回はレスポンスを受けるcallbackに意味はありません。書かなきゃいけないから書いただけですね。

2. バックグラウンドでメッセージを受けてそこでchrome.pageAction.showする

onMessageのリスナーにリアクションするcallbackを登録し、その中でやります。

background/bk.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
  chrome.pageAction.show(sender.tab.id);
  sendResponse({tabid:sender.tab.id});
});

今回はレスポンスに意味はありません。書かなきゃまずいのかと思って書いただけです。
pageAction.showがtabidを要求しているのですが、それは第二引数のsenderから取れるみたいです。
実はここ結構悩みました。

アイコンをクリックした時の新しいTabの作成ができない

さてさて、これでアイコンが出るようになったので次はアイコンをクリックした時にNew Tabを開きたいところです。これはchrome.tabs.createを呼べばいいようですね。アイコンがクリックされた時のハンドリングはバックグラウンドでpageAction.onClickedで。

background/bk.js
chrome.pageAction.onClicked.addListener(function(tab){
    chrome.tabs.create({url:"printable.html?tabid=" + tab.id},function(tab){
    });
});

ん・・・が、出ない。
上記コードは最終的なもので動くのですが、この時点ではくだらないミスがあってcreateをcallする以前に実行時エラーでコケていたのです。

バックグラウンドのconsole.logが出ない

…が、ChromeのDevToolのconsoleにログがでなくてそこがわかりませんでした。
バックグラウンドのログは別のところに出ます。chrome://extensions/ のページからバックグラウンドページのデバッガを起動して、
extentions.PNG
そこのコンソールで確認する必要があります。

tab create したページに元ページの情報を渡せない

これでようやくウン○をクリックするとNew Tabが開くようになりました。

あとは元となるRedmineのチケット一覧ページから必要なチケット情報をつまんできて並べるだけなのでjQueryでやればいいやと思っていたのですが…New Tabのprintable.htmlから元となるRedmineのチケット一覧ページのElementsをどうやって持ってきたらいいの…? ここにイチバン悩んだのでした。

悩んだ末に結局とった方法は「バックグラウンドに一旦覚えさせる」でした。
もっといい方法があるような気もするのでここは教えていただけると助かります、というところです。

1. content script から runtime.sendMessageに送りつける

バックグラウンドに情報を渡すこと自体は、runtime.sendMessageで送れます。
が、しかし、渡せるものに制限があります。jQueryオブジェクトをドカーンと渡したりはできません。そこでほしい情報をドキュメントのままではなく一旦json化しました。(下記例のissuesです)

contentscript.js
var issues = $("table.issues tbody>tr.issue").map(function() {
   var td = $(this).find("td");
   return {
     id: td.filter(".id").text()
     ,tracker: td.filter(".tracker").text()
     ,project: td.filter(".project").text()
     ,subject: td.filter(".subject").text()
     ,requester: td.filter(".cf_57").text()
     ,client: td.filter(".cf_80").text()
     ,storyPoint: td.filter(".cf_64").text()
     ,hours: td.filter(".estimated_hours").text()
   };
}).get();

chrome.runtime.sendMessage({issues: issues}, function(response) {
  console.log("tabid="+response.tabid);
});

本当はこのjsonへの変換をウ○コをクリックした時にしたかったのですが、バックグラウンドからcontentへのアクセス方法がよくわからず。。Tabオブジェクトからたどれるんですかね?

2. バックグラウンドで大域変数に保存する

なーんかいまいちですが。localStrageに入れるのでもいいんでしょうね。

background/bk.js
var issues = {};

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
  chrome.pageAction.show(sender.tab.id);
  issues[sender.tab.id] = request.issues;
  sendResponse({tabid:sender.tab.id});
});

複数TABから同時使用の想定はないのですが、念のためtabId別に領域を確保しています。

3. printable.html からバックグラウンドの大域変数にアクセス

なんだかprintable.htmlに直接スクリプトを書くとエラーになったので実際には外部JSファイルです。

printable.js
var template = $("#tmpl").html();
var bk = chrome.extension.getBackgroundPage();
var tabid= location.search.match(/tabid=([^&]+)/)[1];
document.write(Mustache.to_html(template, {issues: bk.issues[tabid]}));

テンプレートエンジンMustacheのコードが入っているので本質が見えづらいですが、キモはvar bk = chrome.extension.getBackgroundPage();と、bk.issuesのところです。

というわけで大したことやってないけどいろいろ躓いたのでした。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
41
Help us understand the problem. What are the problem?