※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

DOMイベントを利用する

// タブの切り替え
gBrowser.mTabContainer.addEventListener("TabSelect", function(){}, false);
// ページドキュメントの読み込み
gBrowser.mPanelContainer.addEventListener("DOMContentLoaded", function(){}, false);
// ページの読み込み完了
gBrowser.mPanelContainer.addEventListener("load", function(){}, false);
// ページの表示/非表示
gBrowser.mPanelContainer.addEventListener("pageshow", function(){}, false);
gBrowser.mPanelContainer.addEventListener("pagehide", function(){}, false);
// ページの破棄
gBrowser.mPanelContainer.addEventListener("unload", function(){}, false);

メモ

DOMContentLoaded, pageshow, pagehide はフレームからも発行されるので、aEvent.target.defaultView でどこから発行されたのかを見極める必要がある。

EventListener を利用する

Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
var myListener = {
  init : function() {
      gBrowser.addProgressListener(this);
  },
 
  uninit : function() {
      gBrowser.removeProgressListener(this);
  },
 
  QueryInterface : XPCOMUtils.generateQI([
      Ci.nsIWebProgressListener,
      Ci.nsISupportsWeakReference]),
 
  onStateChange : function(aWebProgress, aRequest, aFlag, aStatus) {
      // myListener を二つ以上のタブ/ブラウザで使うなら、onStateChangeイベントを起こした
      // タブ/ウインドウを取得するのに aWebProgress.DOMWindow を使用
      if(aFlag & Ci.nsIWebProgressListener.STATE_START) {
          // ロードイベントが始まったときに実行
          log(aRequest.name); // aRequest.name は多くの場合リクエストURIを示す
      }
      if(aFlag & Ci.nsIWebProgressListener.STATE_STOP) {
          // ロードが終わったときに実行
      }
      if (aFlag & Ci.nsIWebProgressListener.STATE_STOP &&
          aFlag & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
          // ネットワークの読み込みが終わったときに実行
      }
  },
 
  onLocationChange : function(aProgress, aRequest, aURI, aFlags) {
      // ロケーションバーが変更されたとき実行。
      // myListener を二つ以上のタブ/ブラウザで使うなら、onStateChangeイベントを起こした
      // タブ/ウインドウを取得するのに aProgress.DOMWindow を使用。
      if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
          // アンカーでのロケーション変更の場合。
          return;
      }
      if (aProgress.isLoadingDocument) {
          if (aURI.spec == "about:blank") {
              // 空白ページに移動した場合。
              // STATE_STOPが発行されない=onStateChangeが期待できないので注意(メモ3)。
          } else {
              // 読み込み中の場合。
          }
      } else {
          // 読み込み完了状態の場合。タブ切り替え時など。
          var document = aProgress.DOMWindow.document;
      }
  },
 
  onProgressChange : function(aWebProgress, aRequest, curSelf, maxSelf, curTot, maxTot) { },
  onStatusChange   : function(aWebProgress, aRequest, aStatus, aMessage) { },
  onSecurityChange : function(aWebProgress, aRequest, aState) { }
} 
myListener.init();

メモ1

xul:browserにリスナー登録する場合は第2引数に受け取るイベントを指定するNotifyMaskを設定できるが、xul:tabbrowser(gBrowser)に登録する場合は指定できない?指定しても機能しない?
→gBrowserに登録するリスナーが全部で一つだけの場合は機能するっぽい? 拡張機能を色々入れてリスナーをいくつも登録したりする状況だと駄目みたい?

→Minefield4.2a1pre で第2引数が廃止され、第2引数を指定していると警告ダイアログが表示されるようになった。

メモ2

onStateChange で aFlag を利用した状況判定について。STATE_STOP と STATE_IS_REQUEST の二つは、単独およびこの二つのみの組み合わせで使用するのは避けるべき? 監視対象にエラーコンソールのような刻一刻と表示を変化させるコンテンツをロードさせたりすると大変な事になる。
以下のコードで onStateChange イベントがどのように発行されているか観察できるので見てみると良い。
onStateChange : function(aWebProgress, aRequest, aFlag, aStatus) {
    var message = '';
    ['STATE_START', 'STATE_STOP', 'STATE_REDIRECTING', 'STATE_TRANSFERRING',
     'STATE_IS_REQUEST', 'STATE_IS_DOCUMENT', 'STATE_IS_NETWORK', 'STATE_IS_WINDOW',
     'STATE_RESTORING']
    .forEach(function(flag){
        if(aFlag & Ci.nsIWebProgressListener[flag]) {
            message += '\n' + flag;
        }
    });
    if (aWebProgress.isLoadingDocument) {
        message += '\n読み込み中';
    }
    if (aRequest) {
        message += '\naRequest有り';
    }
    Application.console.log(message);
},

メモ3

最後のタブを閉じて about:blank のタブだけ残った状態にする時や、あるいは新しいタブを開いた時にも onLocationChange が呼ばれる。この際 aWebProgress.isLoadingDocument は true になっているが、その後 STATE_STOP などは発行されない。