Progress Listeners
Progress listeners を使うことで拡張機能にドキュメントの読み込みやタブの切替イベントなどを通知することができます。 Progress listeners は nsIWebProgressListener
インターフェースを実装しています。
メモ: 単にページをロードするごとにコードを実行したいだけなら、 もっと簡単な関数 (onPageLoad()
) でできます。
例
nsIWebProgressListener
を実装するオブジェクトを作ります。const STATE_START = Components.interfaces.nsIWebProgressListener.STATE_START; const STATE_STOP = Components.interfaces.nsIWebProgressListener.STATE_STOP; var myListener = { 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; }, onStateChange: function(aWebProgress, aRequest, aFlag, aStatus) { // myListener を二つ以上のタブ/ブラウザで使うなら、onStateChangeイベントを起こした // タブ/ウインドウを取得するのに aWebProgress.DOMWindow を使用してください。 if(aFlag & STATE_START) { // ここはロードイベントが始まったときに実行されます。 } if(aFlag & STATE_STOP) { // ここはロードが終わったときに実行されます。 } return 0; }, onLocationChange: function(aProgress, aRequest, aURI) { // これはロケーションバーが変更されたとき実行されます。例: ロードイベントが完了したとき、ユーザーがタブを切り替えたとき。 // myListener を二つ以上のタブ/ウインドウで使うなら、 // イベントを起こしたタブ/ウインドウを取得するのに aProgress.DOMWindow を使用してください。 return 0; }, // 残りの関数の定義については XULPlanet.com を見てください。 onProgressChange: function() {return 0;}, onStatusChange: function() {return 0;}, onSecurityChange: function() {return 0;}, onLinkIconAvailable: function() {return 0;} }
- progress listener を <browser> か <tabbrowser> 要素に追加してください。例: Firefox の場合は、次のコードをメインウインドウの
load
listener に追加してください【訳注: 詳しくは次の節のコードを参考にしてください】。gBrowser.addProgressListener(myListener, Components.interfaces.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
二番目の引数は受け取るイベントのタイプを決める status filter です。例えフィルターが使われていても、 六つ全ての progress handler 関数が定義されなければなりません。
unload
イベントハンドラか、あるいはもっと早くにremoveProgressListener
を呼ぶことを忘れないでください。
myListener
を独自の識別子(名前)に変更すること忘れないでください【訳注: 他の拡張機能と名前がかぶらないようにするため】。Also remember that if you're adding listeners inside a function, make sure to have a reference to your listener object that stays in memory (this is due to the required nsISupportsWeakReference interface). That is, the listener object shouldn't be declared solely in the temporal function.
例:アドレスバーの値の変更を検出する
よく聞かれる質問にアドレスバー(ロケーションバーとも言う)のURLの変更を、どうやって検出するのかというのがあります。次のコードを使うことで、ユーザーが他のページへ移動する操作を行ったとき(リンクをクリックしたり、戻る/進むボタンを使ったり、ロケーションバーにアドレスを打ち込んだときなど)あるいはタブを切り替えたときを検出することができます。
var myExt_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; }, onLocationChange: function(aProgress, aRequest, aURI) { myExtension.processNewURL(aURI); }, onStateChange: function() {}, onProgressChange: function() {}, onStatusChange: function() {}, onSecurityChange: function() {}, onLinkIconAvailable: function() {} }; var myExtension = { oldURL: null, init: function() { // ウェブページのロードをリスンする。 gBrowser.addProgressListener(myExt_urlBarListener, Components.interfaces.nsIWebProgress.NOTIFY_STATE_DOCUMENT); }, uninit: function() { gBrowser.removeProgressListener(myExt_urlBarListener); }, processNewURL: function(aURI) { if (aURI.spec == this.oldURL) return; //これでurlが新しく更新されたことを知る alert(aURI.spec); this.oldURL = aURI.spec; } }; window.addEventListener("load", function() {myExtension.init()}, false); window.addEventListener("unload", function() {myExtension.uninit()}, false);
メモ : もし二つ以上のタブ/ウインドウで同じリスナーを使っているなら、コールバックメソッドにおいて state change イベントを起こしたタブ/ウインドウを取得するのに aWebProgress.DOMWindow を使用してください。