◆ ブログの編集画面を開く拡張機能を使って解説

拡張機能講座TOP
http://var.blog.jp/archives/47552015.html 

このブログ記事のページから編集画面を開く拡張機能を参考に 拡張機能の作り方解説します


この拡張機能はページアクションの拡張機能です
URL入力するところにボタンがでるやつです
olde-01

ボタンの表示切り替え

ボタンは登録されたURLでだけ表示されるようにします
拡張機能にはオプションページを作ることが出来るので オプションページで localStorage にURLデータを保存しておきます
拡張機能のページでは同じ localStorage を読み書きできるのでバックグラウンドのページでタブの更新を監視して登録された URL にマッチしていれば表示するようにします
chrome.tabs.onUpdated.addListener(update_button)

function update_button(tabid, info){
info.url && (match_page(info.url) ? chrome.pageAction.show(tabid) : chrome.pageAction.hide(tabid))
}
1行目はリスナ登録です
chrome.pageAction の show か hide で表示非表示を切り替えられます
info.url には 更新後の URL が入ります
リロードなど変更ないときは undefined です
info.url があれば localStorage のデータにマッチするか確認して show か hide してます

最近は ルール定義すれば自動でやってくれるのがあるみたいですが 昔のを使いまわしてるのでまだこの方法使ってます

処理の流れ

目的はボタンを押したら ブログの編集画面を出すことです
編集画面を出すためには ブログページのIDとユーザIDが必要です
この2つはページ内の変数に存在します
ページ内のデータを取得するためには content script を埋め込む必要があります
また 組み立てたURLを新しいタブで開くのは拡張機能側でやることなので content script から ID 情報を返してもらう必要があります

図にするとこんな流れです
chext-image01
書いていませんけど
(0) が「ボタンを押した」 です

content script を埋め込む

content script を埋め込むのはこれだけでできます
chrome.tabs.executeScript(tab_id, {code: inject_script}, function(result){})
inject_script というのが埋め込むコードの文字列です
文字列じゃなくてファイルを埋め込むこともできます

tab_id にはタブの ID を入れるのですが取得にも非同期関数を実行する必要があります
chrome.tabs.query({active:true, currentWindow:true}, function(tabs){})
query でカレントウィンドウのアクティブタブを指定すれば今開いてるタブになります
カレントウィンドウを指定しなければ全部のウィンドウのアクティブなタブになってしまいます
今のタブだけを取得すれば要素が 1 つだけの配列がコールバック関数の引数になるので tabs を受け取って tabs[0].id で取り出します

content script から結果を受け取る

次は (2) の content script からどうやってデータを受け取るかです
よく sendMessage というのがあるので 私も最初はそれ使おうかと思ってました

ですが executeScript のコールバック関数はこうなっています
function(array of any result) {...};
結果を受け取れる?

CSS を埋め込む insertCSS にはないですし 引数の説明には 埋め込んだスクリプトの結果と書いています
配列なのは1つのタブの複数のフレームに埋め込むことができるからです
iframe には埋め込まずに top のフレームにだけ埋め込めば result の length は 1 です

どうやって値を返せるか考えたのですが 埋め込まれたスクリプトでコールバック関数なんて受け取ってませんし 関数実行されてるわけじゃないので 埋め込むスクリプト内で return なんて書くとエラーと言われます

コンソール画面のように最後に評価したのが返って来たりしないかなと ダメ元で最後の行に返したい値をそのまま書いたら なんと受け取れました

ページのタイトルとURLを返したいのならこれだけです
chrome.tabs.executeScript(tab_id, {code:`
var title = document.querySelector("title").textContent
var url = location.href
var obj = {title, url}
obj
`}, function(results){console.log(result[0])})

拡張機能側の console に title とurl が表示されてるはずです

content script でグローバル変数へのアクセス

DOMアクセスしてデータもってくるなら簡単だったのですが 今回はグローバル変数にセットされた記事の ID を取り出す必要があります

ですが content script 内の window と通常のページ内の window は別物になっています
そのせいで ページ内でグローバル変数にセットされた変数を見ることはできません

ですが document は共有されているので script タグを作って document 内に追加すると ページ内の window で実行されます
これを利用して content script 内に グローバル変数の ID 情報を持ってくればいいのですが そうすると script タグを追加するところで非同期処理になってしまいます
非同期処理になると content script から 拡張機能に値を返せなくなってしまいます

sendMessage にするのも嫌だったのでこの拡張機能では無理矢理やってますけど こうなったら content script の返り値を諦めて sendMessage などの方法を取ったほうがいいと思います


無理矢理というのは DOMが共通なので全 script タグの中から ID をグローバル変数を宣言している script タグを見つけて innerHTML 取得して content script 側で eval してしまう方法です
こうすれば非同期処理を入れずに content script 側でもグローバル変数として ID を取得できるようになります

でもこれはあまりオススメできないです

ページを開く

chrome.tabs.create({active:true,url:url})

受け取ったデータからURLを作ったら タブを開けば完了です
url に開く url を入れて 開いたあとにアクティブにしたければ active を true にします

まとめ

page action について書くはずがなんか完全にこの拡張機能の説明になってしまいました
それに長くて我ながら読もうと思えないです

もっとシンプルにこう書けばおっけいというのだけ書いてくようにしたいですね