Visit Mozilla.org

Code snippets:Tabbed browser

出典: MDC


このページには Firefox のタブブラウザを扱うのに有用なコードがリストされています。あなた自身のコードを挿入すべき場所には通常コメントが入れられています。

通常、それぞれのコードには初期化の際に実行するべきコードが含まれています。これらは load リスナーで実行するのがいいでしょう。コードはブラウザウィンドウのコンテキストの中で実行されることを想定しています。もし、ブラウザでないウィンドウでタブを操作したい場合は、ブラウザウィンドウへの参照を最初に取得する必要があります。詳細は chrome コードでウィンドウを操作する を参照してください。

Firefox 2 はタブでの変更をより簡単に取得可能ですので、Firefox 2 以上向けに開発しているなら、そのバージョン向けのサンプルを利用すべきです。Firefox 1.5 もしくはそれ以下向けのサンプルは、通常 Firefox 2 でも正常に動作します。

目次

[編集] ブラウザへのアクセス方法

ブラウザは、アプリケーションのメインウィンドウ (Firefox では browser.xul) の中に配置された tabbrowser 要素です。browser.xul へオーバーレイを出すような拡張機能では普通ですが、ブラウザウィンドウで実行されるコードならば、大域変数 gBrowser もしくは関数 getBrowser() を使ってブラウザにアクセスできます。

// gBrowser/getBrowser() はブラウザウィンドウ (browser.xul) のスコープからのみアクセス可能
gBrowser.addTab(...);
getBrowser().addTab(...);

gBrowser が未定義ならば、あなたのコードはブラウザウィンドウのスコープで実行されていないか、もしくは早い段階で実行されすぎています。gBrowser にはブラウザウィンドウが完全にロードされた後でのみアクセス出来ます。ウィンドウが開かれたすぐ後に gBrowser に対して何かしたければ、 load イベントをリッスン し、イベントリスナの中で gBrowser を使ってください。

あなたのコードがサイドバーやダイアログ内で動作している場合、gBrowserを利用するにはまず必要なブラウザウィンドウへのアクセスを取得する必要があります。これについてのより詳細の情報は chrome コードでウィンドウを操作する にあります。

基本的には、拡張機能がサイドバーで動作しているなら以下のようにできます。

var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                   .getInterface(Components.interfaces.nsIWebNavigation)
                   .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
                   .rootTreeItem
                   .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                   .getInterface(Components.interfaces.nsIDOMWindow);

mainWindow.getBrowser().addTab(...);

もし、コードがブラウザウィンドウから直接立ち上げられたダイアログで実行されているなら、以下のようにできます。

window.opener.getBrowser().addTab(...);

もし、window.opener が動作しないなら、このコードによって最も最近使われたブラウザウィンドウを取得できます。

var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                   .getService(Components.interfaces.nsIWindowMediator);
var mainWindow = wm.getMostRecentWindow("navigator:browser");
mainWindow.getBrowser().addTab(...);

[編集] 新しいタブを開く

// タブの追加
gBrowser.addTab("http://www.google.com/");

// タブの追加とアクティブ化
gBrowser.selectedTab = gBrowser.addTab("http://www.google.com/");

[編集] URL を適切なウィンドウやタブで開く

次のコードでは、押されたマウスのボタンや、押されている Ctrl などのホットキーによって、新しいタブ、現在のタブ、現在のウィンドウのどこに URL が開かれるかが決まります。このコードは menuitem 用のものですが、他の XUL 要素でも同じように動作します。このコードは browser.xul のオーバーレイでのみ動作します。

XUL:

<menuitem oncommand="myExtension.foo(event)" onclick="checkForMiddleClick(this, event)" label="Click me"/>

JS:

var myExtension = {
  foo: function(event) {
    openUILink("http://www.example.com", event, false, true);
  }
}

[編集] タブを閉じる

このサンプルは現在選択されているタブを閉じます。

gBrowser.removeCurrentTab();

また、引数として XUL の tab 要素を一つだけ取る、より汎用的な removeTab というメソッドもあります。

[編集] 選択されているタブを変更する

タブを一つ右へ移動します。

gBrowser.mTabContainer.advanceSelectedTab(1, true);

こちらは左へ移動します。

gBrowser.mTabContainer.advanceSelectedTab(-1, true);

[編集] ページ読み込みの検出

function examplePageLoad(event)
{
  if (event.originalTarget instanceof HTMLDocument) {
    var doc = event.originalTarget;
    if (event.originalTarget.defaultView.frameElement) {
      // タブにフレームが読み込まれました。doc はフレームセットのルート
      // ドキュメントでなければなりません。もし、このウェブページに frame/iframe が
      // 読み込まれたときに何もしないなら、次の行のコメントアウトを外してください
      // return;
      // ルートドキュメントを探索する
      while (doc.defaultView.frameElement) {
        doc=doc.defaultView.frameElement.ownerDocument;
      }
    }
  }
}

// ブラウザウィンドウが初期化されるまでコールバック関数を追加しようとしないで
// ください。タブブラウザへのコールバックの追加はブラウザウィンドウが
// 読み込まれたあとにする必要があります。
window.addEventListener(
  "load",
  function () {
    // ドキュメントが読み込まれるたびに実行されるコールバック関数を追加する
    // ドキュメント内部の frame/iframe にも適用されるので注意が必要
    gBrowser.addEventListener("load", examplePageLoad, true);
  },
  false
);

...
// もし、必要なくなれば
gBrowser.removeEventListener("load", examplePageLoad, true);
...

[編集] タブが追加・削除されたときに通知する (<= Firefox 1.5)

function exampleTabAdded(event)
{ // 新規タブを監視
  if (event.relatedNode != gBrowser.mPanelContainer)
    return; 
      // DOM のどこかになる (インターフェースで変化が捉えられるまで?)

  var browser;
  if (event.target.localName == "browser") // SeaMonkey
    browser = event.target;
  else if (event.target.localName == "vbox") // Firefox
    browser = event.target.childNodes[1];
  // browser は追加された browser の XUL 要素です
}

function exampleTabRemoved(event)
{
  if (event.relatedNode != gBrowser.mPanelContainer)
    return;

  var browser;
  if (event.target.localName == "browser") // SeaMonkey
    browser = event.target;
  else if (event.target.localName == "vbox") // Firefox
    browser = event.target.childNodes[1];
  // browser は削除された browser の XUL 要素です
}

// 初期化中に
var container = gBrowser.mPanelContainer;
container.addEventListener("DOMNodeInserted", exampleTabAdded, false);
container.addEventListener("DOMNodeRemoved", exampleTabRemoved, false);

// 必要なくなれば
container.removeEventListener("DOMNodeInserted", exampleTabAdded, false);
container.removeEventListener("DOMNodeRemoved", exampleTabRemoved, false);

[編集] タブが追加もしくは削除されたときに通知する (Firefox 2+)

function exampleTabAdded(event)
{
  var browser = event.target.linkedBrowser;
  // browser は追加された browser をさす XUL 要素です
}

function exampleTabMoved(event)
{
  var browser = event.target.linkedBrowser;
  // browser は移動した browser をさす XUL 要素です
}

function exampleTabRemoved(event)
{
  var browser = event.target.linkedBrowser;
  // browser は削除された browser をさす XUL 要素です
}

// 初期化中に
var container = gBrowser.tabContainer;
container.addEventListener("TabOpen", exampleTabAdded, false);
container.addEventListener("TabMove", exampleTabMoved, false);
container.addEventListener("TabClose", exampleTabRemoved, false);

// 必要なくなれば
container.removeEventListener("TabOpen", exampleTabAdded, false);
container.removeEventListener("TabMove", exampleTabMoved, false);
container.removeEventListener("TabClose", exampleTabRemoved, false);

[編集] タブが選択されたことを検出する (<= Firefox 1.5)

次のコードでブラウザの新たにタブが選択されたことを検出できます。

function exampleTabSelected(event)
{
  var browser = gBrowser.getBrowserAtIndex(gBrowser.mTabContainer.selectedIndex);
  // browser はその時に選択された browser の XUL 要素
}

// 初期化中に
var container = gBrowser.mPanelContainer;
container.addEventListener("select", exampleTabSelected, false);

// 必要なくなれば
var container = gBrowser.mPanelContainer;
container.removeEventListener("select", exampleTabSelected, false);

[編集] タブが選択されたことを検出する (Firefox 2+)

次のコードでブラウザの新たにタブが選択されたことを検出できます。

function exampleTabSelected(event)
{
  var browser = gBrowser.selectedTab.linkedBrowser;
  // browser はその時に選択された browser の XUL 要素
}

// 初期化中に
var container = gBrowser.tabContainer;
container.addEventListener("TabSelect", exampleTabSelected, false);

// 必要なくなれば
container.removeEventListener("TabSelect", exampleTabSelected, false);

[編集] 現在選択されているタブのドキュメントを取得する

次のコードで現在選択されているタブのドキュメントを取得できます。このコードはブラウザウィンドウのスコープで動作します (ブラウザウィンドウへのオーバーレイで動作させる時など) 。

gBrowser.selectedBrowser.contentDocument;

もしくは

content.document

ブラウザウィンドウから開かれたウィンドウやダイアログで動作させる場合は、このコードを使って、そのウィンドウを開いたブラウザウィンドウの、選択されているタブで表示されているドキュメントを取得できます。

window.opener.content.document

ブラウザウィンドウから開かれたものでないウィンドウやダイアログからは、nsIWindowMediator を使って、一番最近使われたブラウザウィンドウの、選択されているタブで表示されているドキュメントを取得できます。

var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
         getService(Components.interfaces.nsIWindowMediator);
var recentWindow = wm.getMostRecentWindow("navigator:browser");
return recentWindow ? recentWindow.content.document.location : null;

chrome コードでウィンドウを操作する も参照してください。

[編集] タブの列挙

ブラウザで開いている全てのタブを取得するには、最初にブラウザウィンドウへの参照を取得します。もし、Firefox の browser.xul オーバーレイから実行されているコード (たとえば、ツールバーボタンやメニューでの click ハンドラなど) なら、現在のウィンドウにすでに定義されている変数である window でアクセスできます。しかしながら、それ自身のウィンドウから実行されているコード (たとえば、設定やオプションダイアログなど) なら、nsIWindowMediator をブラウザのウィンドウを取得するのに利用する必要があります。

次に、<tabbrowser/>要素を取得します。前の手順で取得したブラウザのウィンドウを win とすると、win.gBrowser によって取得できます。もし、browser.xul オーバーレイの中で動作しているなら、より簡単に window.gBrowser でなく、gBrowser で取得可能です。

最後に、gBrowser.browsers.length により開いているタブの数を取得し、gBrowser.getBrowserAtIndex() により <browser/> 要素を取得します。たとえば、

var num = gBrowser.browsers.length;
for (var i = 0; i < num; i++) {
  var b = gBrowser.getBrowserAtIndex(i);
  try {
    dump(b.currentURI.spec);
    // 開いている全てのタブの URL をコンソールへ出力
  } catch(e) {
    Components.utils.reportError(e);
  }
}

<browser/><tabbrowser/> 要素でどんなメソッドが利用できるかについてより詳細は、DOM Inspector を利用するか、browser.xmltabbrowser.xml の対応する XBL バインディングを参照してください。

[編集] タブの再利用

毎回必要なときに新しいブラウザウィンドウやタブを開くより、もしあれば必要としている URL をすでに表示している既存のタブを再利用することを考える方がよいでしょう。この方法をとれば、あなたの拡張機能が作成するブラウザやタブを最小にすることができます。

[編集] URL/URI により再利用する

さまざまな拡張機能で共通する機能として、拡張機能のボタンやリンクをユーザがクリックしたときに、ブラウザウィンドウで chrome:// URI (ヘルプや about 情報など) や外部の (オンラインの http(s)://) HTML 文書を開くようにしています。次のコードは、すでに必要な URL や URI を表示しているタブを再利用する方法を示しています。もし、存在しなければ、指定された URL や URI を新しいタブで開きます。

function openAndReuseOneTabPerURL(url) {
  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                     .getService(Components.interfaces.nsIWindowMediator);
  var browserEnumerator = wm.getEnumerator("navigator:browser");

  // 必要としている URL を開いている browser が無いか確認する
  var found = false;
  while (!found && browserEnumerator.hasMoreElements()) {
    var browserInstance = browserEnumerator.getNext().getBrowser();

    // browser インスタンスの全てのタブを確認する
    var numTabs = browserInstance.tabContainer.childNodes.length;
    for(var index=0; index<numTabs; index++) {
      var currentBrowser = browserInstance.getBrowserAtIndex(index);
      if (url == currentBrowser.currentURI.spec) {

        // URL はすでに開いています。タブを選択します。
        browserInstance.selectedTab = browserInstance.tabContainer.childNodes[index];

        // この browser にフォーカスを移す
        browserInstance.focus();
        found = true;
        break;
      }
    }
  }

  // URL が開かれてないので新たに開く
  if (!found) {
    var recentWindow = wm.getMostRecentWindow("navigator:browser");
    if (recentWindow) {
      // 既存のブラウザウィンドウを利用する
      recentWindow.delayedOpenTab(url, null, null, null, null);
    }
    else {
      // すでに開いている browser ウィンドウがないので、新たに開く
      window.open(url);
    }
  }
}

[編集] その他の条件によって再利用する

すでにどのような URL/URI が開かれているかにかまわず、既存のタブを再利用したいということがあるでしょう。これは、タブがブラウザのほかのコンポーネントにでなく、あなたの拡張機能により開かれたときを想定しています。最初にタブを開いたときに何らかの属性をつけておくことで特定のタブを再利用することが可能です。後に、タブを再利用したくなったとき、われわれは全てのタブについてつけた属性を持っているかどうかを調べるのです。もし、属性を持つタブが見つかれば、その URL/URI を変更して focus/select します。もし、そういったタブが見つからなければ (たとえば、タブがユーザによって閉じられた場合や、最初に開こうとしたときなど)、新しいタブを何らかの属性をつけて開きます。

function openAndReuseOneTabPerAttribute(attrName, url) {
  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
           .getService(Components.interfaces.nsIWindowMediator);
  for (var found = false, index = 0, browserInstance = wm.getEnumerator('navigator:browser').getNext().getBrowser();
       index < browserInstance.mTabContainer.childNodes.length && !found;
       index++) {

    // 次のタブを取得する
    var currentTab = browserInstance.mTabContainer.childNodes[index];

    // タブがつけた属性を持っているかどうかを調べる
    if (currentTab.hasAttribute(attrName)) {

      // 持っている -- なら select して focus します
      browserInstance.selectedTab = currentTab;

      // 他のものに focus がされているならこの browser に focus します
      browserInstance.focus();
      found = true;
    }
  }

  if (!found) {
    // われわれのタブは開かれてませんので開きます
    var browserEnumerator = wm.getEnumerator("navigator:browser");
    var browserInstance = browserEnumerator.getNext().getBrowser(); 

    // タブを作成
    var newTab = browserInstance.addTab(url);
    newTab.setAttribute("myextension-myattribute", "xyz");

    // タブに focus
    browserInstance.selectedTab = newTab;

    // 他のものに focus がされているならこの browser に focus します
    browserInstance.focus();
  }

この関数は次のように呼べます :

openAndReuseOneTabPerAttribute("myextension-myattribute", "http://developer.mozilla.org/").