Outils pour utilisateurs

Outils du site


greasemonkey

GreaseMonkey

Cette page (succincte) s'adresse aux développeurs. Connaissances en javascript requises, XPath recommandées. Débutants, passez votre chemin.

C'est quoi ?

GreaseMonkey est une extension Firefox qui permet de modifier à la volée n'importe quelle page web, à chaque fois qu'elle est chargée. Par exemple, pour changer la couleur de fond de votre site favori, ou supprimer une partie de la page qui vous gêne à chaque visite, ou encore ne plus jamais voir les messages d'un utilisateur précis sur votre forum favori. Les possibilités sont multiples.

Comment ça marche ?

Installez d'abord l'extension Firefox, puis ajoutez les scripts de votre choix, ou créez-en vous-même. Ces scripts (écrits en javascript) manipulent la page web au moment où elle est chargée. Les scripts sont définis pour s'activer sélectivement sur certains sites ou pages.

:!: ATTENTION: Ne téléchargez pas n'importe quel script. Les scripts peuvent faire n'importe quoi dans les pages. Utilisez votre cerveau.

Écrire soi-même un script

C'est le but de cette page.

Généralement, quand on veut écrire un script GreaseMonkey, c'est pour supprimer ou modifier quelque chose dans une page. Voici quelques fonctions utilitaires pour simplifier les choses, avec quelques exemples d'appel.

L'entête d'un script GreaseMonkey doit contenir:

  • @name : Nom du script.
  • @namespace : Namespace de votre script (mettez l'URL de votre site, ça fera l'affaire)
  • @include : Indique sur quelles URLs il doit s'activer.
monscript.js
// ==UserScript==
// @name        Essai
// @namespace   sebsauvage.net
// @include     http://sebsauvage.net/links/*
// ==/UserScript==
 
 
(function () {
    // Removes all occurences of elements whose XPath is provided from the document.
    //
    // Example: Remove all tables which use the CSS class 'toto':
    //          removeElement("//table[@class='toto']");
    function removeElement(ElementXpath)
    {
        var alltags = document.evaluate(ElementXpath,document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);
        for (i=0; i<alltags.snapshotLength; i++)
        {
            element = alltags.snapshotItem(i);
            element.parentNode.removeChild(element);  // Remove this element from its parent.
        }
    }  
 
    // Removes an attribute from all occurences of elements whose XPath is provided.
    // (All occurences of this elements are processed.)
    //
    // Example: Remove the bgcolor of all <table>:
    //          removeAttributeOfElement('bgcolor',"//table[@bgcolor]")
    //          Remove the fixed with of all tables or cells::
    //          removeAttributeOfElement('width',"//table[@width]|//td[@width]")
    function removeAttributeOfElement(attributeName,ElementXpath)
    {
        var alltags = document.evaluate(ElementXpath,document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);
        for (i=0; i<alltags.snapshotLength; i++)
            alltags.snapshotItem(i).removeAttribute(attributeName);    
    }
 
    // Set an attribute from all occurences of elements to a specified value.
    // The previous value of this attribute is discarded.
    // (All occurences of this elements are processed.)
    //
    // Example: Set with to 80 columns on all texteareas:
    //          setAttributeOfElement('cols',80,"//textarea")
    function setAttributeOfElement(attributeName,attributeValue,ElementXpath)
    {
        var alltags = document.evaluate(ElementXpath,document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);
        for (i=0; i<alltags.snapshotLength; i++)
            alltags.snapshotItem(i).setAttribute(attributeName, attributeValue)
    }    
 
    // Inject your own CSS in the page.
    // Example: Do not underline link:
    //          injectCSS("a{text-decoration: none;}")
    function injectCSS(cssdata)
    {
        head = document.getElementsByTagName("head")[0];
        style = document.createElement("style");
        style.setAttribute("type", 'text/css');
        style.innerHTML = cssdata;
        head.appendChild(style);
    }
 
    // Converts an image to text.
    // Attributes, links and javascript actions are preserved.
    //
    // Examples: imageToText("//img[@src='/forum/images/editer-bleu.png']","[Editer]")
    //           imageToText("//img[@src='/images/g.gif' or @src='../images/g.gif']","[Gras] "),
    function imageToText(ElementXpath,text)
    {
        var alltags = document.evaluate(ElementXpath,document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);
        for (i=0; i<alltags.snapshotLength; i++)
        {
            tag = alltags.snapshotItem(i)
            lien = document.createTextNode(text)
            tag.parentNode.replaceChild(lien, tag);
        }    
    }
 
    try
    {
        // Mettez votre code ici. EXEMPLES:
 
        // Supprimer des actions Javascript sur certains éléments d'un formulaire.
        removeAttributeOfElement('onfocus',"//input[@name='titre']");
        removeAttributeOfElement('onblur',"//input[@name='titre']");
 
        // Supprimer toutes les couleurs de fond:
        injectCSS('* { color: None !important; background: None !important; background-color: None !important; }');
 
        // supprimer les couleurs des tableaux:
        removeAttributeOfElement('bgcolor',"//td");
        removeAttributeOfElement('bgcolor',"//table");
 
        // forcer la largeur d'un textarea:
        setAttributeOfElement('cols','120',"//textarea[@name='message']");  
 
        // Convertir une image en texte:
        imageToText("//img[@src='/images/btn_gras.gif']","[Gras]");
 
        // et divers autres exemples en vrac, histoire de montrer quelques possibilité de XPath:
        removeElement("//div/p/b[starts-with(.,'tous les utilisateurs du site se doivent de respecter les autres')]/../../*[position()>=6 and position()<=9]");
        removeElement("//th[text()='Nombre de discussions']/ancestor::table[1]");
        setAttributeOfElement('style','font-weight:bold; background-color:#FFFFE8',"//tr/td[position()=last() and text()='0']/../descendant::*");
        setAttributeOfElement('style','font-size:8pt;','//tr[@class=\"fb\"]/td')
        removeElement("//span[@class='Datered' or @class='Dategris' or @class='Date']/following-sibling::br");
        removeElement("//div[@id='colonneDroite']/div/div/h2[text()='Extraits de la charte']/ancestor::div[1]"); 
    }
    catch (e)
    {
        alert("UserScript exception:\n" + e);
    }
 
})();

Pour trouver quels éléments atteindre, utilisez l'inspecteur de Firefox (clic-droit > Examiner l'élément). Si l'élément en question a un id, c'est bonheur: il est (en principe) unique dans la page. Sinon bon courage avec les classes, parent/ancestor/sibling et autres bricolages à base de XPath (comme dans les horribles exemples que j'ai donnés).

A titre d'exemple, pour virer la boite de recherche de mon Shaarli, on ferait:

// ==UserScript==
// @name        Essai
// @namespace   tototititata.com
// @include     http://sebsauvage.net/links/*
// ==/UserScript==
 
(function () {
...code supprimé...
    try
    {
       removeElement("//div[@id='headerform']");
    }
    catch (e)
    {
        alert("UserScript exception:\n" + e);
    }
})();

ou encore forcer tous les liens en bleu:

injectCSS("a { color:blue !important; }");

À vous de jouer !

Autres exemples

Redirection de page dans Tumblr

Si vous êtes sur une page tumblr du genre: http://*.tumblr.com/image/12345, ce script vous redirigera immédiatement vers l'URL directe de l'image (pour l'afficher pleine page):

// ==UserScript==
// @name        Tumblr image redirector (/image --> direct image URL)
// @namespace   sebsauvage.net
// @include     http://*.tumblr.com/image/*
// @version     1
// ==/UserScript==
 
try {
    var alltags = document.evaluate("//div[@id='content']/img",document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);
    if (alltags.snapshotItem(0) != null)
    {
        document.location=alltags.snapshotItem(0).src;
    }
}
catch (e)
{
    alert("UserScript exception:\n" + e);
}
greasemonkey.txt · Dernière modification: 2014/07/12 13:26 (modification externe)