Visit Mozilla.org

Extraits de code:Onglets de navigation

Un article de MDC.

Cette page vient d'être traduite, mais elle a besoin d'un relecteur différent du traducteur. Pensez également à toujours vérifier le contenu avec sa toute dernière version en anglais.

Sur cette page, vous trouverez un ensemble de morceaux de code utiles pour vous aider à travailler avec la navigation par onglets de Firefox. Les commentaires indiquent normalement les endroits où vous devez insérer votre propre code.

Chaque extrait contient en principe du code à exécuter lors de l'initialisation, et le meilleur moyen de la faire est d'utiliser un événement de chargement. Ces morceaux de code sont supposés être exécutés dans le contexte d'une fenêtre de navigation. Si vous devez travailler avec des onglets en dehors d'une fenêtre de navigation, vous devrez au préalable obtenir une référence à une fenêtre, voir Travailler avec des fenêtres dans le chrome pour plus de détails.

Notez que Firefox 2 a rendu la détection des modifications sur les onglets beaucoup plus simple, et si vous ne développez que pour Firefox 2 et suivants, vous devriez utiliser les exemples s'y rapportant. Les exemples pour Firefox 1.5 et précédents devraient fonctionner sous Firefox 2 sans problème.

Consultez également la référence de l'élément XUL tabbrowser. L'objet gBrowser (identique à getBrowser()) est un élément tabbrowser.

Sommaire

[modifier] Accéder au navigateur (Browser)

Le navigateur est un élément tabbrowser situé dans la fenêtre principale de l'application (browser.xul pour Firefox). Si votre extension a accès à la fenêtre principale, commune aux extensions qui recouvrent (overlay) browser.xul, alors le navigateur est accessible par la variable globale gBrowser ou par la fonction getBrowser().

// gBrowser/getBrowser() est uniquement accessible depuis le périmètre de la fenêtre principale
gBrowser.addTab(...);
getBrowser().addTab(...);

Si votre extension n'a pas accès à la fenêtre principale parce que c'est un panneau latéral ou une boîte de dialogue, vous devez obtenir un accès à la fenêtre principale avant de pouvoir utiliser le navigateur. Vous pourrez trouver plus d'informations quant aux moyens d'accéder à la fenêtre principale dans l'article Travailler avec des fenêtres dans le chrome.

Fondamentalement, si le code de votre extension est dans un panneau latéral, vous pouvez utiliser :

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(...);

Si le code de votre extension est dans une boîte de dialogue ouverte directement depuis la fenêtre principale, vous pouvez utiliser :

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

Si window.opener ne fonctionne pas, essayez :

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

[modifier] Ouverture d'un nouvel onglet

// Ajout d'un onglet
gBrowser.addTab("http://www.google.fr/");

// Ajout et activation d'un onglet
gBrowser.selectedTab = gBrowser.addTab("http://www.google.fr/");

[modifier] Fermeture d'un onglet

Cet exemple ferme l'onglet actuellement sélectionné.

gBrowser.removeTab(gBrowser.selectedTab);

[modifier] Modification de l'onglet actif

Cet exemple déplace la sélection vers l'onglet suivant (sur la droite).

gBrowser.mTabContainer.advanceSelectedTab(1, true);

Celui-ci la déplace vers l'onglet sur la gauche.

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

[modifier] Détection du chargement d'une page

function examplePageLoad(event)
{
  if (event.originalTarget instanceof HTMLDocument) {
    var doc = event.originalTarget;
    if (event.originalTarget.defaultView.frameElement) {
      // Le cadre au sein de l'onglet a été chargé. doc devrait être le document
      // racine du frameset. Si vous ne voulez rien faire quand les frames/iframes
      // ont été chargées dans cette page Web, décommentez la ligne suivante :
      // return;
      // Recherche du document racine
      while (doc.defaultView.frameElement) {
        doc=doc.defaultView.frameElement.ownerDocument;
      }
    }
  }
}

// N'essayez pas d'ajouter un callback avant que la fenêtre du 
// navigateur n'aie été initialisée. On ajoute un callback à 
// l'onglet quand la fenêtre du navigateur est chargée.
window.addEventListener(
  "load",
  function () {
    // Ajoute un callback à lancer chaque fois qu'un document se charge.
    // Notez que cela inclut les frames/iframes au sein du document
    gBrowser.addEventListener("load", examplePageLoad, true);
  },
  false
);

...
// Quand la détection n'est plus nécessaire
gBrowser.removeEventListener("load", examplePageLoad, true);
...

[modifier] Notification lorsqu'un onglet est ajouté ou enlevé (<= Firefox 1.5)

function exampleTabAdded(event)
{ // Écoute des nouveaux onglets
  if (event.relatedNode != gBrowser.mPanelContainer)
    return; //peut être n'importe où dans le DOM (à moins que l'événement ne provienne de l'interface ?)

  var browser;
  if (event.target.localName == "browser") // SeaMonkey
    browser = event.target;
  else if (event.target.localName == "vbox") // Firefox
    browser = event.target.childNodes[1];
  // browser est l'élément XUL du navigateur qui a été ajouté
}

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 est l'élément XUL du navigateur qui a été supprimé
}

// Pendant l'initialisation
var container = gBrowser.mPanelContainer;
container.addEventListener("DOMNodeInserted", exampleTabAdded, false);
container.addEventListener("DOMNodeRemoved", exampleTabRemoved, false);

// Quand les événements ne sont plus nécessaires
container.removeEventListener("DOMNodeInserted", exampleTabAdded, false);
container.removeEventListener("DOMNodeRemoved", exampleTabRemoved, false);

[modifier] Notification lorsqu'un onglet est ajouté ou enlevé (Firefox 2+)

function exampleTabAdded(event)
{
  var browser = event.target.linkedBrowser;
  // browser est l'élément XUL du navigateur qui a été ajouté
}

function exampleTabMoved(event)
{
  var browser = event.target.linkedBrowser;
  // browser est l'élément XUL du navigateur qui a été déplacé
}

function exampleTabRemoved(event)
{
  var browser = event.target.linkedBrowser;
  // browser est l'élément XUL du navigateur qui a été supprimé
}

// Pendant l'initialisation
var container = gBrowser.tabContainer;
container.addEventListener("TabOpen", exampleTabAdded, false);
container.addEventListener("TabMove", exampleTabMoved, false);
container.addEventListener("TabClose", exampleTabRemoved, false);

// Quand les événements ne sont plus nécessaires
container.removeEventListener("TabOpen", exampleTabAdded, false);
container.removeEventListener("TabMove", exampleTabMoved, false);
container.removeEventListener("TabClose", exampleTabRemoved, false);

[modifier] Détection de la sélection d'un onglet (<= Firefox 1.5)

Le code suivant permet de détecter la sélection d'un nouvel onglet du navigateur :

function exampleTabSelected(event)
{
  var browser = gBrowser.getBrowserAtIndex(gBrowser.mTabContainer.selectedIndex);
  // browser est l'onglet sélectionné
}

// Pendant l'initialisation
var container = gBrowser.mPanelContainer;
container.addEventListener("select", exampleTabSelected, false);

// Quand les événements ne sont plus nécessaires
var container = gBrowser.mPanelContainer;
container.removeEventListener("select", exampleTabSelected, false);

[modifier] Détection de la sélection d'un onglet (Firefox 2+)

Le code suivant permet de détecter la sélection d'un nouvel onglet du navigateur :

function exampleTabSelected(event)
{
  var browser = gBrowser.selectedTab;
  // browser est l'onglet sélectionné
}

// Pendant l'initialisation
var container = gBrowser.tabContainer;
container.addEventListener("TabSelect", exampleTabSelected, false);

// Quand les événements ne sont plus nécessaires
container.removeEventListener("TabSelect", exampleTabSelected, false);

[modifier] Récupération du document de l'onglet actif

Le code suivant vous permet de récupérer le document qui se trouve dans l'onglet sélectionné :

gBrowser.selectedBrowser.contentDocument;

ou

content.document

Consultez également Travailler avec des fenêtres dans le chrome.

[modifier] Énumération d'onglets

Pour parcourir tous les onglets ouverts dans un navigateur, vous devez d'abord obtenir une référence à la fenêtre de navigation. Si votre code est exécuté depuis un overlay Firefox de browser.xul (par exemple, s'il s'agit d'un bouton d'une barre d'outils ou du gestionnaire click d'un menu), vous pouvez accéder à la fenêtre courante par la variable prédéfinie window. Cependant, si votre code est exécuté depuis sa propre fenêtre (par exemple, une boîte de dialogue de préférence ou d'options), vous pouvez utiliser nsIWindowMediator pour obtenir une fenêtre de navigation.

Ensuite, obtenez l'élément <tabbrowser/>. Vous l'obtenez avec win.gBrowser, où win est la fenêtre de navigation de l'étape précédente. Vous pouvez simplement utiliser gBrowser au lieu de window.gBrowser si vous exécutez dans le contexte d'un overlay browser.xul.

Finalement, utilisez gBrowser.mPanelContainer.childNodes.length pour obtenir le nombre d'onglets ouverts et gBrowser.getBrowserAtIndex() pour obtenir un élément <browser/>. Par exemple :

var num = gBrowser.mPanelContainer.childNodes.length;
for (var i = 0; i < num; i++) {
  var b = gBrowser.getBrowserAtIndex(i);
  try {
    dump(b.currentURI.spec); // Affiche toutes les URLs des onglets ouverts dans la console
  } catch(e) {
    Components.utils.reportError(e);
  }
}

Pour connaître quelles sont les méthodes disponibles pour les éléments <browser/> et <tabbrowser/>, utilisez l'inspecteur DOM ou regardez les liaisons XBL correspondantes dans browser.xml et tabbrowser.xml.

[modifier] Réutilisation d'onglets

Plutôt que d'ouvrir un nouveau navigateur ou un nouvel onglet à chaque fois que vous en avez besoin, il est préférable d'essayer de réutiliser un onglet qui affiche déjà l'URL désirée -- s'il y en a un d'ouvert. En suivant cet exercice, votre extension minimisera la prolifération d'onglets et de navigateurs créés.

[modifier] Réutilisation par URL/URI

Une fonctionnalité classique rencontrée dans de nombreuses extensions est de diriger l'utilisateur vers des URIs chrome:// dans une fenêtre de navigation (par ex., la rubrique d'aide ou À propos) ou des documents HTML externes (liens http(s):// en ligne) lorsqu'il clique sur un lien ou un bouton de l'extension. Le code suivant montre comment réutiliser un onglet existant qui affiche déjà l'URL/URI désiré. Si un tel onglet n'existe pas, un nouveau sera ouvert avec l'URL/URI spécifié.

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

  // Vérifier chaque navigateur avec notre URL
  for (var found = false, browserInstance;
       browserEnumerator.hasMoreElements() && !found;
       browserInstance = browserEnumerator.getNext().getBrowser()) {

    // Vérifier chaque onglet de l'instance de ce navigateur
    for(var index=0, numTabs = browserInstance.mPanelContainer.childNodes.length;
        index < numTabs && !found;
        index++) {

      var currentTab = browserInstance.getBrowserAtIndex(index);
      if (url == currentTab.currentURI.spec) {

        // L'URL est déjà ouverte. Sélectionner cet onglet.
        browserInstance.selectedTab = currentTab;

        // Donner le focus à ce navigateur
        browserInstance.focus();
        found = true;
      }
    }
  }

  // Notre URL n'est pas ouverte. L'ouvrir maintenant.
  if (!found) {
    var recentWindow = wm.getMostRecentWindow("navigator:browser");
    if (recentWindow) {
      // Utiliser une fenêtre de navigation existante
      recentWindow.delayedOpenTab(url, null, null, null, null);
    }
    else {
      // Aucune fenêtre de navigation n'est ouverte, donc en ouvrir une nouvelle
      window.open(url);
    }
  }
}

[modifier] Réutilisation par d'autres critères

Parfois, vous pouvez réutiliser un onglet déjà ouvert indépendamment de l'URL/URI qui y est affiché. Ceci suppose que l'onglet est ouvert par votre extension, et non par un autre composant de navigation. Vous pouvez réutiliser un onglet arbitraire en lui attachant un attribut personnalisé lors de son ouverture. Plus tard, lorsque vous voulez réutiliser cet onglet, vous devez parcourir tous les onglets ouverts pour chercher celui qui contient l'attribut personnalisé. Si un tel onglet existe, nous modifions son URL/URI et nous le sélectionnons et nous en lui donnons le focus. Si un tel onglet n'existe pas (peut être parce que l'utilisateur l'a fermé ou ne l'a jamais ouvert), nous en créons un nouveau avec notre attribut personnalisé.

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++) {

    // Récupèrer l'onglet suivant
    var currentTab = browserInstance.mTabContainer.childNodes[index];
  
    // Est-ce que cet onglet contient notre attribut personnalisé ?
    if (currentTab.hasAttribute(attrName)) {

      // Oui--Le sélectionner et lui donner le focus.
      browserInstance.selectedTab = currentTab;

      // Donner le focus à *ce* navigateur au cas où un autre l'aurait
      browserInstance.focus();
      found = true;
    }
  }

  if (!found) {
    // Notre onglet n'est pas ouvert. L'ouvrir.
    var browserEnumerator = wm.getEnumerator("navigator:browser");
    var browserInstance = browserEnumerator.getNext().getBrowser(); 
  
    // Créer l'onglet
    var newTab = browserInstance.addTab(url);
    newTab.setAttribute("myextension-myattribute", "xyz");
  
    // Donner le focus à l'onglet
    browserInstance.selectedTab = newTab;
    
    // Donner le focus à *ce* navigateur au cas où un autre l'aurait
    browserInstance.focus();
  }

La fonction peut être appelée comme ceci : openAndReuseOneTabPerAttribute("myextension-myattribute", "http://developer.mozilla.org/").