Liens
- installer Extension Auto-Installer
- Tools → Add-ons → Extension Auto-Installer → Preferences → Automatic Updates = On
|
# créé le fichier xpi et fait la mise à jour dans firefox
jpm post --post-url http://localhost:8888/
# à chaque fois qu'un fichier est modifié, créé le fichier xpi et fait la mise à jour dans firefox
jpm watchpost --post-url http://localhost:8888/
|
|
Par défaut, le niveau de log des extensions installé est à error.
Ce qui veut dire que les messages console.log ne seront pas affichés dans la Browser Console. |
Changer le niveau de log pour toutes les extensions:
- about:config
- extensions.sdk.console.logLevel = all
about:debugging
index.js
|
var buttons = require('sdk/ui/button/action');
var tabs = require("sdk/tabs");
var button = buttons.ActionButton({
id: "mozilla-link",
label: "Visit Mozilla",
icon: {
"16": "./icon-16.png",
"32": "./icon-32.png",
"64": "./icon-64.png"
},
onClick: handleClick
});
function handleClick(state) {
tabs.open("https://www.mozilla.org/");
}
|
|
mkdir data
# mettre dans le dossier data les images: icon-16.png, icon-32.png, icon-64.png
|
index.js
|
var { ToggleButton } = require('sdk/ui/button/toggle');
var panels = require("sdk/panel");
var self = require("sdk/self");
var button = ToggleButton({
id: "my-button",
label: "my button",
icon: {
"16": "./icon-16.png",
"32": "./icon-32.png",
"64": "./icon-64.png"
},
onChange: handleChange
});
function handleChange(state) {
if (state.checked) {
panel.show({
position: button
});
}
}
var panel = panels.Panel({
width: 250,
height: 100,
contentURL: self.data.url("panel.html"),
contentStyleFile: self.data.url("panel.css"),
onHide: handleHide
});
function handleHide() {
button.state('window', {checked: false});
}
panel.port.on("panel_click", function(id) {
// écoute les messages panel_click
});
|
data/panel.html
|
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="1">Menu 1</div>
<div id="2">Menu 2</div>
</body>
</html>
|
data/panel.css
|
html, body {
background-color: black;
color: white;
}
div {
border-bottom: solid 1px black;
margin: 10px 0;
}
div:hover {
border-color: red;
cursor: pointer;
}
|
data/panel.js
|
/*
Listen for clicks in the panel.
*/
document.addEventListener("click", function(e) {
if (e.target.tagName != "DIV") {
return;
}
var id = e.target.getAttribute("id");
// envoie le message panel_click au panel dans index.js
self.port.emit("panel_click", id);
});
|
index.js
|
var pageMod = require("sdk/page-mod");
var page = pageMod.PageMod({
include: "*.mozilla.org",
contentScriptFile: "./content-script.js"
});
// envoie du message Hello au fichier content-script.js
page.port.emit("Hello");
|
data/content-script.js
|
// écrase le contenu de la page
document.body.innerHTML = "<h1>Nouvelle page</h1>";
// écoute des messages Hello
self.port.on("Hello", function() { /* */ });
|
|
Si la page web récupéré ne correspond pas, il peut être nécessaire de mettre en place un timer pour attendre que la page soit complètement chargée: setTimeout(maFonction, 1000); |
|
Erreur: workerFor(...) is undefined, recharger la page. |
Déclaration
index.js
|
// un fichier: data/content-script.js
contentScriptFile: "./content-script.js",
// plusieurs fichiers
contentScriptFile: ["./jquery.min.js", "./content-script.js"],
// variables passées au script
contentScriptOptions: {
var-id: "valeur",
var-id2: data.url("fichier.ext")
},
// un fichier css: data/content-style.css
contentStyleFile: "./content-style.css",
|
data/content-script.js
|
// variables passées au script
console.log(self.options.var-id);
|
|
var tabs = require("sdk/tabs");
// Listen for tab openings.
tabs.on('open', function onOpen(tab) {
// à l'ouverture d'un nouvel onglet
});
// Listen for tab content loads.
tabs.on('ready', function(tab) {
// une fois le contenu de la page chargé
console.log('tab is loaded', tab.title, tab.url);
});
|
|
var notifications = require("sdk/notifications");
var data = require("sdk/self").data;
notifications.notify({
title: "Titre",
text: "message",
iconURL: data.url("icon-16.png")
});
|
|
const tabs = require("sdk/tabs");
const {viewFor} = require('sdk/view/core');
const {modelFor} = require('sdk/model/core');
const {getBrowserForTab, getTabForContentWindow} = require("sdk/tabs/utils");
const {Ci, Cu} = require("chrome");
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
var progressListener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
onLocationChange: function(aProgress, aRequest, aURI) {
// getTabForContentWindow cause le warning unsafe/forbidden CPOW usage
var highLevelTab = modelFor(getTabForContentWindow(aProgress.DOMWindow));
console.log("onLocationChange ", highLevelTab.url);
// plus simplement, sans warning
console.log("onLocationChange ", aURI.asciiSpec);
}
};
pageMod.PageMod({
include: "https://www.site.com/*",
onAttach: startListening
});
function startListening(worker) {
var lowLevel = viewFor(worker.tab);
var browser = getBrowserForTab(lowLevel);
browser.addProgressListener(progressListener);
}
// remove listeners on extension unload
exports.onUnload = function (reason) {
var tab = tabs.activeTab
var lowLevelTab = viewFor(tab);
var browser = getBrowserForTab(lowLevelTab);
browser.removeProgressListener(progressListener);
};
|
|
const fileIO = require("sdk/io/file");
var path = fileIO.join("/dossier1", "dossier2"); // /dossier1/dossier2
if (!fileIO.exists(path)) {
fileIO.mkpath(path); // créé tous le chemin des dossiers
}
// lister les fichiers d'un dossier
var allFiles = fileIO.list(path);
for (i = 0; i < allFiles.length; i++) { ... }
|
Ouvrir l'explorateur de fichier
|
var {Cc, Ci} = require("chrome");
var localFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
localFile.initWithPath("/usr/bin/nemo");
var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.init(localFile);
process.run(false, Array(path), 1); // ouvre l'explorateur de fichier à l'emplacement path
|
|
var {Cc, Ci, Cu} = require("chrome");
Cu.import("resource://gre/modules/Downloads.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Task.spawn(function () {
yield Downloads.fetch(pictureUrl, destination);
console.log("image téléchargée!");
}).then(null, Cu.reportError);
|
icône
Utilise le fichier icon.png à la racine du dossier de l'add-on, sinon utilise le fichier package.json:
package.json
|
"icon": "resource://@your-addon-name/data/your-icon-name.png",
|
|
The icon may be up to 48x48 pixels in size |
Préférences
package.json
|
"preferences": [{
"name": "destinationPath",
"title": "Path where to save data",
"type": "directory"
},
{
"name": "fileExplorerPath",
"title": "Path to the file explorer application",
"type": "file"
}]
|
|
var preferences = require("sdk/simple-prefs").prefs;
var destination = preferences.destinationPath;
|
jpm
|
jpm run -b /usr/bin/firefox-developer --binary-args '-url google.fr -jsconsole'
# -b pour forcer le binaire à exécuter au lieu de firefox
# --binary-args pour passer des arguments comme l'url à utiliser et ouvrir la console web
|
|
# créé le fichier xpi
jpm xpi
|
|
# créer un dossier pour l'extension
mkdir MonExtension
# se rendre dans le dossier de l'extension
cd MonExtension
# créé les fichiers package.json, index.js, README.md, test/test-indes.js
jpm init
|
|
# installer NodeJS Packet Manager
sudo pacman -S npm
# installe aussi nodejs
# installer jpm
sudo npm install jpm --global
|
Signer les add-ons
- Se créer un compte sur https://addons.mozilla.org
- Se rendre sur la page Developer Hub → Submit a New Add-on
- Envoyer l'add-on zippée sans le dossier .git et sans dossier contenant
Une fois l'add-on validée, un lien est donné pour permettre de télécharger l'add-on signé.
|
On peut signer un add-on sans le publier sur le site de mozilla. |
about:config → xpinstall.signatures.required → false
|
Plus possible depuis la version 43. Alternative: utiliser les versions ESR, Developer Edition ou Nightly |