02 Mar 2010

Progress Listenersでロケーションバーのurl変更されたときに何かする

firefoxの拡張機能開発メモ. 戻るボタンが押されたり, タブが切り替わったり, ページがロードされるなど表示されているページが切り替わるタイミングで何か実行したい. 調べてみるとProgress Listenersというものを使えば実現できるようです.

正直, めちゃくちゃ理解が曖昧なんですが, こうやるとできましたというメモです.

Progress Listeners

Progress listenersを使うとロケーションバーのurlの変化をイベントとして扱うことができるようになります. ロケーションバーのurlが変化するタイミングとは, ページがロードされた, タブが切り替わった, 戻る・進むボタンが押されたなどの場合です.

ちなみに, 単にページロードのイベントが欲しいだけだったら, onPageLoadを使った方が簡単です. Progress Listenersはそれよりも細かい条件を指定できます.

Progress Listeners - Code snippets | MDN

方法は, 基本的に上記チュートリアルのサンプルコードの通りにすればできます. nsIWebProgressというインタフェースを実装して, それをgBrowserのaddProgressListener()というメソッドでブラウザに渡します. 以下の関数を実装して, ひとつのオブジェクトにまとめて, addProgressListenerに引数として渡します. 今回の用途だと, onLocationChangeだけ実装すれば大丈夫です.

Listening to events on all tabs | MDN

  • onStateChange
  • onLocationChange
  • onProgressChange
  • onStatusChange
  • onSecurityChange
  • onLinkIconAvailable

コード全体はこんな感じ.

window.addEventListener('load', function() { myExtension.init(); }, false);
window.addEventListener("unload", function() { myExtension.uninit(); }, false);

var myExtension = {
  // 古いurlを保存
  oldUrl: null,

  // nsIWebProgressインタフェースの実装
  urlBarListener: {
    QueryInterface: function(aIID) {
      if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
          aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
          aIID.equals(Components.interfaces.nsISupports))
        return this;
      throw Components.results.NS_NOINTERFACE;
    },

    // 現在のタブのドキュメントのURIが変更されたらコールされる
    onLocationChange: function(aProgress, aRequest, aUri) {
      myExtension.processNewUrl(aUri);
    },

    onStateChange: function() {},
    onProgressChange: function() {},
    onStatusChange: function() {},
    onSecurityChange: function() {},
    onLinkIconAvailable: function() {}
  },

  // progress listener を追加する
  init: function() {
    gBrowser.addProgressListener(myExtension.urlBarListener, Components.interfaces.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
  },

  // progress listener を削除する
  uninit: function() {
    gBrowser.removeProgressListener(myExtension.urlBarListener);
  },

  // urlが変わっていたら何かする
  processNewUrl: function(aUri) {
    if (aUri.spec == myExtension.oldUrl)
      return;
   
    // ここにコードを書く

    myExtension.oldUrl = aUri.spec;
  }
};

参考