muumoo.jp


ニュース記事検索


過去ログ 2007年08月24日 - ニュース過去ログ

ニュース過去ログ

2007/08/24 管理人日記 LDC/はてブにブクマコメントを埋め込むGMスクリプトをOperaにも対応させる (管理人日記)

上記2つのGMスクリプトは自分で作ったものですが結構お気に入りで、よく使っていました。ところが、最近ブラウザをOperaに変えたので、使えなくなっちゃいました。

これは非常に不便なので、Operaでも動くように改良してみました。

完成品

まずは完成品をどぞ。

新規にOpera専用バージョンを作ったのではなく、以前作ったやつをFirefoxでもOperaでもどっちでも動くように直しました。また、URLに「#」を含んだ場合の処理の不具合も直ってますので、今までFirefoxで使っていた人もインストールしなおして欲しい。Operaの人は、「ツール」「設定」「詳細設定」「コンテンツ」「JavaScript オプション」「ユーザー JavaScript ファイル」のところに好きなディレクトリを指定して、そのディレクトリに上記のuser.jsファイルを配置して下さい。

使い方は、この記事の冒頭に貼ったリンク先を参照。

修正点

ここからは(人によっては)難しい話。修正点はおおきく2箇所。

unsafeWindowはOperaでは使えないのでwindowにした

これは簡単。冒頭に

var w = (typeof unsafeWindow != 'undefined') ? unsafeWindow : window;

と書いておいて、コード中でunsafeWindowを呼んでるところを全部wに書き換えればいい。

GM_xmlhttpRequestはOperaでは使えないのでJSONPにした

GM_xmlhttpRequestはいわゆるAjax風な通信をする機能ですが、これをOperaに対応させるには、

ということになると思います(違ったらゴメン))。今回は、アクセス先はYahoo! Pipesなので、2番目のやり方でいけます。

JSONPの呼び出しは、以前「複数のJSONPを連続で呼び出して最後にコールバック関数を呼ぶ」のときに作ったJSONLoaderクラスを使ってみました。コピペで貼るだけ。

あとは、

GM_xmlhttpRequest({
    method: 'GET',
    url: 'http://(略)',
    onload: function(res){
        var obj = eval('(' + res.responseText + ')');
        (略)
    }
});

こんな感じの呼び出し部分を

var json_uri = 'http://(略)'
var callback = function(obj){
    (略)
};
if(typeof GM_xmlhttpRequest == 'undefined'){
    
    var jsonp_uri = json_uri + '&callback=';
    var loader = new JSONLoader();
    loader.config = [{ uri: jsonp_uri }];
    loader.callback = function(results){ callback(results[jsonp_uri]); };
    loader.load();
   
}else{
   
    GM_xmlhttpRequest({
        method: 'GET',
        url: json_uri,
        onload: function(res){ callback(eval('(' + res.responseText + ')')); }
    });
   
}

上記のように書き換えます。GM_xmlhttpRequestがundefinedのときだけJSONPを使うようにしています。なのでFirefoxでは今までどおりGM_xmlhttpRequestを使います。

別に、わざわざブラウザを振り分けないで常にJSONPを使うようにしてもいいと思います。

OperaはJSONPが非同期じゃない

ここまででうまく行ったように見えましたが、まだ問題があった。OperaはJSONPを非同期に呼び出せないのです。つまり、JSONPのための script要素を挿入すると、処理が終わるまで待たされる。それで我慢できることもあるかと思いますが、今回のuser.jsはYahoo! Pipesを使っているので待ち時間が長く、できれば非同期でやりたい。

そこで、Operaでも非同期リクエストが並列処理できる img-JSONP(TAKESAKO @ Yet another Cybozu Labs)で解説されてる方法を使ってみた。

  1. JSONPのリクエストをscript要素ではなくimg要素を使って投げる(imgのsrcにJSONPのURLを入れる)。
  2. img要素のロードは非同期なので、Yahoo! Pipesがどんなに遅くても平気。
  3. しかしimgにJSONPを読み込ませるわけで、結局これは当然エラーになる。
  4. そのエラーをimg.onerrorハンドラで捕まえる。
  5. onerrorハンドラの中で、本当のJSONPつまりscript要素を使ったリクエストをする。
  6. さっきimgに読み込んだときのキャッシュがあるので、すぐに結果が返る。
  7. JSONPのコードが走り出す。

こんな感じの流れ。すばらしいアイディア。感動しました。みんなすごすぎるよ。

さて、これを実装するため、JSONLoaderクラスを以下のように直しました。

var JSONLoader = function(){};
JSONLoader._count = 0;
JSONLoader.prototype.load = function(){
    var jsonp_callback_name = 'JSONLoader_callback_' + (JSONLoader._count++);
    w[jsonp_callback_name] = this.callback;
   
    var img = document.createElement('img');
    img.src = this.uri + jsonp_callback_name;
    img.onerror = function(e){
        var script = document.createElement('script');
        script.setAttribute('src', this.src);
        script.setAttribute('type', 'text/javascript');
        script.setAttribute('charset', 'utf-8');
        document.getElementsByTagName('head')[0].appendChild(script);
    };
    img.width = 0;
    img.height = 0;
    document.body.appendChild(img);
};

このJSONLoaderクラスは他のところでもそのまま使えると思います。Operaで非同期JSONPをやりたい場合はぜひ。

修正のついでに、「複数のJSONPを呼び出して最後にコールバック」の機能を削除しました。今回は1個のJSONPを呼ぶだけなので。これによって、JSONLoader利用側もちょっと変わりました。

var json_uri = 'http://(略)'
var callback = function(obj){
    (略)
};
if(typeof GM_xmlhttpRequest == 'undefined'){
   
    var loader = new JSONLoader();
    loader.uri = json_uri + '&callback=';
    loader.callback = callback;
    loader.load();
   
}else{
   
    GM_xmlhttpRequest({
        method: 'GET',
        url: json_uri,
        onload: function(res){ callback(eval('(' + res.responseText + ')')); }
    });
   
}

複数のJSONPを呼び出す機能を削除したので、利用側のコードがシンプルになった。

うまくいった!

これらの修正をした結果、Operaでも問題なく動作するようになりました。もしかしたらCreammonkeyとかSleipnirでも動くのかな?試してない。

Yahoo! Pipes側も直しています

URLに「#」を含んだ場合の処理で、user.js側に不具合があって今回直しましたが、サーバ側つまりYahoo! Pipesで作ったAPI側にも不具合がありました。そっちも直したので、今後は「#」のあるURLでも正しく動作するかと思います。いままでこの問題を放置していてすみませんでした。

この記事のURI:
http://muumoo.jp/news/2007/08/24/0commentlistinsertioonopera.html


Copyright© 2002-2007 muumoo.jp All Rights Reserved.