Chrome、Firefoxと拡張を開発できたので、調子にのって普段まったく使わないOperaの拡張も作ってみました。
で、何ヶ月ぶりかで起動してみたら、案の定バージョンが偉く上がっていて、早速バージョンアップしてみたら、また一段と我が道を行くUIに変わってましたね……
Operaはバージョンアップするたびにボタンの位置とかメニューとかガラっと変わる印象があるんですけど、中の人の入れ替わりが激しいのか、あるいは単に開発者の気まぐれなのか?
それはさておき、全体的に情報が少なくて大変でしたが、なんとか目的のクロスドメイン通信ができたので載せておきます。
やりたいことは、開いたページのURLを取得して、外部のウェブサービスに投げて結果を受け取り、その結果を元に開いたページをちょこちょこと書き換える、というものです。
最初にバックグラウンドページ。ここにバックグラウンドページ処理のスクリプト(background.js)を配置。
<doctype html> <html> <head> <title>Edit the Page</title> <script type="text/javascript" src="background.js"></script> </head> </html>
そのバックグラウンド処理(background.js)の中身
// background.js window.addEventListener("load", setupConnection, false); function setupConnection(){ // ページが開くと、content scriptがbackground page にAttachしてくる opera.extension.onconnect = function(event) { event.source.postMessage("echoURL"); // content scriptにURL下さい、とメッセージ } // content script から返答を待ち受ける opera.extension.onmessage = function(event){ var url = event.data; // 外部APIを呼ぶ var xhr = new XMLHttpRequest() xhr.onreadystatechange = function(){ if(this.readyState == 4){ if(this.status == 200){ event.source.postMessage(xhr.responseText); // content scriptにAPI結果を渡す } else if(this.status == 400){ opera.postError(xhr.responseText); } } }; xhr.open("GET", "http://api.someservice/somefunc.json?url=" + url, false); xhr.send(); } }
そして開いたページのコンテキストで動くスクリプト。includes以下に置くルール……だと思います。
// includes/content.js opera.extension.onmessage = function(event){ var message = event.data; if(message == "echoURL"){ event.source.postMessage(encodeURIComponent(document.URL)); // background.jsに返信 } else { // XHRの結果を処理。window.$ に注意 window.$("#some-id").html(message); } };
jqueryなどは、includesディレクトリに一緒に放り込んでおけば、勝手にロードされて使えます。
ただグローバルスコープがwindowオブジェクトじゃないので、$を呼ぶにはwindow.$とか呼ばなきゃいけないのが少し面倒です。
あとはconfig.xmlにクロスドメインする先のURLを登録しておけばオッケーです。
<?xml version="1.0" encoding="utf-8"?> <widget xmlns="http://www.w3.org/ns/widgets"> <name>mytest</name> <description>mytest</description> <access origin="http://api.someservice" subdomains="true"/> </widget>
拡張は、ファイル全部をzipでまとめて拡張子を「oex」にする、ということなので、こんなMakefileを作っておくと便利かもしれません。
all: mytest.oex mytest.oex: background.js config.xml index.html includes/content.js rm -f $@ zip $@ background.js zip $@ index.html zip $@ config.xml zip -r $@ includes