Firefox XUL/XPCOM extensions

De Banane Atomic
Révision datée du 22 septembre 2016 à 21:25 par Nicolas (discussion | contributions) (→‎Signer les add-ons)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à la navigationAller à la recherche
Ce type d'extension ne sera bientôt plus compatible.
Créer plutôt des WebExtensions ou des Add-on SDK.


Liens utiles

Hiérarchie des dossiers et fichiers

  • chrome.manifest
  • install.rdf
  • chrome
    • content
      • monextension.js
      • monextension.xul
    • locale
    • skin
      • monextension.css
      • icon.png
  • defaults
    • preferences
      • monextension.js

install.rdf

install.rdf
<?xml version="1.0"?>

<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
     xmlns:em="http://www.mozilla.org/2004/em-rdf#">

  <Description about="urn:mozilla:install-manifest">
    <!-- ID de votre extension au format email (ne doit pas être une adresse existante) ou GUID -->
    <em:id>mon.extension@moi.fr</em:id>
    <em:version>1.0</em:version>
    <!-- le 2 indique qu'il s'agit d'une extension -->
    <em:type>2</em:type>
    <em:name>Mon Extension</em:name>
    <em:description>Une extension test</em:description>
    <em:creator>Moi</em:creator>
    <em:homepageURL>http://www.example.com</em:homepageURL>
    <!-- icone dans la page add-ons manager -->
    <em:iconURL>chrome://monextension/skin/icon.png</em:iconURL>
   
    <!-- L'application cible de votre extension, avec les versions minimums et maximums supportées. --> 
    <em:targetApplication>
      <Description>
        <!-- L'ID de l'application Firefox -->
        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
        <em:minVersion>2.0</em:minVersion>
        <em:maxVersion>46.0a1</em:maxVersion>
      </Description>
    </em:targetApplication>
  </Description>      
</RDF>

chrome.manifest

Spécifie l'emplacement des fichiers.
La ligne overlay indique à Firefox de fusionner browserOverlay.xul dans browser.xul lorsque browser.xul est chargé.

chrome.manifest
content   monextension                chrome/content/

skin      monextension  classic/1.0   chrome/skin/

locale    monextension  en-US         chrome/locale/en-US/

style     chrome://global/content/customizeToolbar.xul  chrome://monextension/skin/toolbar.css

overlay   chrome://browser/content/browser.xul          chrome://monextension/content/browserOverlay.xul
La ligne style ne semble servir à rien.
C'est le fichier skin/monextension.css qui sera utilisé.

overlay

monextension.xul
<?xml version="1.0" ?>

<?xml-stylesheet href="chrome://monextension/skin/" type="text/css" ?>

<overlay id="monextension" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  
  <script type="application/x-javascript" src="monextension.js" />
    
  <toolbarpalette id="BrowserToolbarPalette">
    <!-- ne pas mettre schromeclass-toolbar-additional permet d'avoir le bouton sur les sous-fenêtres -->
    <toolbarbutton id="monextension-button"
                   class="toolbarbutton-1 chromeclass-toolbar-additional"
                   label="label"
	           tooltiptext="tooltip"
                   oncommand="MonExtension.DoSomething();" />
  </toolbarpalette>
    
</overlay>
monextension.js
if ( "undefined" == typeof(MonExtension) ) { MonExtension = {}; }

MonExtension.DoSomething = function(){
  window.alert("message");
}
monextension.css
#monextension-button {
  list-style-image: url("chrome://monextension/skin/icon.png");
}

Outils

Recommended development preferences

Installer l'add-on DevPrefs pour régler les paramètres de développement.

Development extensions

  • DOM Inspector + Inspect Context : clique-droit → Inspect

Test

  1. Dans le dossier extensions, créer un fichier ayant pour nom son ID
  2. Mettre le chemin vers le dossier contenant le fichier install.rdf
~/.mozilla/firefox/xxxxxxxx.profil/extensions/MonExtension@domaine.fr
/chemin/vers/dossier contenant install.rdf/

Signer les add-ons

Exemples

Tester l'URL des pages

monextension.js
function examplePageLoad(event) {
  if (event.originalTarget instanceof Components.interfaces.nsIDOMHTMLDocument) {
    
    var win = event.originalTarget.defaultView;
    if (win.frameElement) {
      // Frame within a tab was loaded. win should be the top window of the frameset.
      // If you don't want do anything when frames/iframes are loaded in this web page, return
      return;
    }
    
    var regex = /^https?:\/\/mon\.url\.fr/;
    if (regex.test(event.originalTarget.defaultView.location.href)) { ... }
    else { ... }
    
  }
}

// do not try to add a callback until the browser window has been initialised.
// We add a callback to the tabbed browser when the browser's window gets loaded.
window.addEventListener("load", function () {
  // Add a callback to be run every time a document loads.
  // note that this includes frames/iframes within the document
  gBrowser.addEventListener("load", examplePageLoad, true);
}, false);

Parser le contenu de la page chargée

monextension.js
function DoSomething() {

  var contentDoc = content.document;  
  var elt1 = contentDoc.getElementById("MonID");
  var elt2 = elt1.getElementsByTagName("MonTag")[0];

  alert(elt2.getAttribute("MonAttribut"));

}

Télécharger un fichier

monextension.js
Components.utils.import("resource://gre/modules/Downloads.jsm");
Components.utils.import("resource://gre/modules/osfile.jsm");

Downloads.fetch('http://www.site.net/image.jpg', OS.Path.join('/dossier', 'monImage.jpg'));

Créer un dossier

monextension.js
Components.utils.import("resource://gre/modules/osfile.jsm");

var chemin = OS.Path.join('dossier1', 'dossier2'); // dossier1/dossier2

OS.File.makeDir('/dossier', { ignoreExisting: true });
// ignoreExisting: If true, succeed even if the directory already exists (default behavior). 
// Otherwise, fail if the directory already exists.

Préférences

defaults/preferences/yourextensionname.js
// Path to the folder where to download picture
pref("extensions.xulschoolhello.destination", "/folder");

// Amount of messages shown to the user.
pref("extensions.xulschoolhello.message.count", 0);
install.rdf
<!-- bouton preferences -->
<em:optionsURL>chrome://xulschoolhello/content/preferencesWindow.xul</em:optionsURL>
chrome/content/preferencesWindow.xul
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <prefpane label="Preferences">
    
    <preferences>
      <preference id="xulschoolhello-destination-pref" name="extensions.xulschoolhello.destination" type="string" />
    </preferences>
    
    <hbox align="center">
      <label control="symbol" value="Destination: " />
      <textbox preference="xulschoolhello-destination-pref" />
    </hbox>

  </prefpane>
</prefwindow>
chrome/content/browserOverlay.js
  Destination: "",
  
  startup: function() {
    this.prefs = Components.classes["@mozilla.org/preferences-service;1"]
                           .getService(Components.interfaces.nsIPrefService)
                           .getBranch("extensions.xulschoolhello.");
    this.prefs.QueryInterface(Components.interfaces.nsIPrefBranch2);
		
    this.Destination = this.prefs.getCharPref("destination");
    if (!this.Destination) { // si destination est nulle ou vide
      this.Destination = OS.Constants.Path.desktopDir;
      this.prefs.setCharPref("destination", this.Destination);
    }

Détection d'un changement d'onglet

Javascript.svg
function onTabChange() {
    var href = gBrowser.contentDocument.location.href;
}

window.addEventListener("load", function(e) {
    gBrowser.tabContainer.addEventListener("TabSelect", onTabChange, false);
}, false);

window.addEventListener("unload", function(e) {
    gBrowser.tabContainer.removeEventListener("TabSelect", onTabChange, false);
}, false);