バグ修正・・・。

前回のエントリー しなもんとどこでも遊べるGreasemonkey & Bookmarklet - sawatの日記 のやつについて、
Greasemonkeyで実行した場合にはてなブックマークコメントの取得ができておらず、しなもんがおしゃべりをしないことに2週間たった今頃気付きました…。

バグが発生した経緯は以下の通り。

  1. はてなブックマークコメントの取得は、はじめJSONPバージョンを使って行っていた。
  2. しかし、Greasemonkeyスクリプト内で定義された関数は他からは参照できない(サンドボックス機能)*1。そのため、Greasemonkeyで実行する場合はJSONPのコールバック呼び出しができない。
  3. なので、Bookmarkletで実行されたときはJSONPを呼び出し、Greasemonkeyの時はGM_xmlhttpRequestを使って、普通のJSONAPIを呼び出すように修正。

    if ( typeof(xmlhttpRequest) == 'function' ) {
      // Greasemonkeyの場合 xmlhttpRequestでJSON呼び出し
    } else {
      // bookmarkletの場合 appendChild(script)でJSONP呼び出し
    }

  4. しかし、Trixieの場合、Trixie版のGM_xmlhttpRequestが使えるはずだが、なぜかうまく実行されない。逆にTrixieにはサンドボックスがないらしく*2JSONP呼び出しならうまくいく。
  5. TrixieGM_xmlhttpRequestについて詳しく調べたりしたくなかったので、TrixieではJSONP呼び出しをするように変更。GM_xmlhttpRequestの有無だとGreasemonkeyTrixieを区別できないため、Trixieには定義されていないGM_logで判別するようする。

    if ( typeof(window.GM_log) == 'function' ) {
      // Greasemonkeyの場合 xmlhttpRequestでJSON呼び出し
    } else {
      // bookmarkletとTrixieの場合 appendChild(script)でJSONP呼び出し
    }

  6. やったTrixieでもちゃんと動いたぞ。よし。これで完成!
となりました。

で、どこにバグがあるかというと、window.GM_logの部分。なぜかGM_logにしたときにwindow.をつけてしまった。GM_logはトップレベルの関数だから、windowオブジェクトのプロパティに違いないという思い込み。しかし、実際はそうではなく、typeof(window.GM_log)はつねに"undefined"を返し、Greasemonkeyの場合でもJSONP呼び出しをするというバグが残ってしまったのでした。あべし。

非常にいまさらですが、修正版をおいておきます。
http://sawat.jf.land.to/cinnamon/browsertop_accesory_cinnamon.user.js
Greasemonkeyにインストールして、いまだに使い続けているひとが万が一*3いましたらアップデートをお願いします。



しなもんいっぱい!
あと、無駄に機能追加。しなもんをダブルクリックすると、なんと2匹目のしなもんを召喚することができるようになりました!(右図)
前から、ブックマークレット版を複数回実行すればできましたけどね。*4

*1:正しくは、HTMLのscriptタグで実行されるスクリプトサンドボックス内で、Greasemonkeyスクリプトサンドボックス外。GM_xmlhttpRequestはセキュリティ制限のかからないサンドボックス外で実行されるため、任意のドメインにアクセスできる。

*2:このためTrixieにはセキュリティ的な問題があるのかもしれない

*3:数十分も使っていると「かわいい」というよりも「ウザい」と感じるようになる可能性が非常に高いため、これを使い続けている人がいるとは考え難い。

*4:IEだとブックマークレットを実行した瞬間に表示されているアニメーションGIFが停止してしまう問題はあったけど。