Articoli di febbraio, 2009

Estendere i selettori di jQuery

Nessun Commento »

download esempio

jQuery, il potente framework javascript creato da John Resig, è già fornito nativamente di versatili selettori standard, che coprono la quasi totalità delle necessità degli sviluppatori, garantendo la possibilità di selezionare gli elementi del DOM sulla base di una gerarchia, di un attributo o del contenuto.

Tuttavia possono crearsi situazioni in cui la selezione degli elementi risulta più complessa, creando la necessità di sviluppare specifiche funzioni che applichino una certa logica di selezione.

Fortunatamente esiste un semplice metodo per estendere le potenzialità del framework, creando dei selettori custom, personalizzabili, ed integrabili nelle precedenti espressioni di selezione.

Vediamo come.

Iniziamo con la creazione di un plug-in vuoto, in un file che chiameremo moreselectors.jquery.js, la struttura del plug-in sarà più o meno questa:

(function($) {
    // estensione del namespace jQuery
    $.extend(
        // con questo estendiamo il parser dei selettori jQuery...
        $.expr[":"],
        {
            // aggiungendo una nuova regola e relativa funzione
            espressione: function(e) { ... }
        }
    );
})(jQuery);

La funzione associata alla regola funzionerà da predicato, restituendo true o false determinerà l’inclusione o meno nell’array dei risultati dell’elemento corrente. Il parametro e, o element, indica l’elemento DOM in esame e sono possibili altri 2 parametri i che indica l’indice nell’array della selezione e c che rappresenta i componenti del selettore (come vedremo successivamente).
Una volta che si sarà definita l’espressione e si è incluso il plug-in della pagina la sintassi per il suo utilizzo è quella che ben conosciamo:

$("div:espressione")
// es. filtrerà i div che rispettano il predicato della funzione
$("div:not(:espressione)")
// filtra gli elementi div che non rispettano il predicato

Utiliziamo come esempio questo blocco di html:

...
<div>
<div class="divLevel1">
<div class="divLevel2">a</div>
</div>
<div class="divLevel1" style="border:dotted 1px #dedede;">
<div class="divLevel2">b</div>
</div>
<div class="divLevel1">(vuoto)</div>
<div class="divLevel1" style="background-color:Red;">
<div class="divLevel2">d</div>
</div>
</div>
...

e vediamo come può essere l’espressione per la selezione dell’unico div.divLevel1 senza elementi child, selettore che chiameremo per l’appunto “no-child” (virgolette necessarie, in quanto c’è il carattere -):

...
"no-child": function(e) {
                return $(e).find("*").length == 0;
            }
...
... utilizzo
$("div.divLevel1:no-child")

Ora tentiamo di fare qualcosa di più complicato: selezioniamo il div con lo sfondo rosso:

...
red: function(e) {
    var color = $(e).css("background-color").toLowerCase();
    if (color.indexOf("rgb") == -1)
    {
        return color == "#ff0000" || color == "red";
    }
    else
    {
        var rgb = $(e).css("background-color")
                      .replace("rgb(", "").replace(")", "");
        var componenti = rgb.split(", ");
        return (255 === parseInt(componenti[0], 10))
                && (0 === parseInt(componenti[1], 10))
                && (0 === parseInt(componenti[2], 10));
    }
}
...
... utilizzo
$("#div:red")

In questo caso abbiamo dovuto fare una distinzione tra il modo in cui IE e firefox trattano l’informazione sul colore. In firefox la lettura (quantomeno con jQuery) di un color o di un background-color restituisce la rappresentazione rgb del colore stesso, mentre in IE si ottiene o il nome del colore o la sua rappresentazione esadecimale.

Infine vediamo come può essere creato un semplice selettore con parametri.
Come abbiamo detto prima, il parametro c della funzione di espressione contiene i componenti del selettore, ed è in realtà un array restituito dal parser jQuery il cui contenuto, ipotizzando un selettore nella forma :selettore(parametro) è il seguente:
c[0] -> ':selettore(parametro)'
c[1] -> ':'
c[2] -> 'selettore'
c[3] -> 'parametro'

Detto ciò vediamo come può essere un selettore in grado di selezionare gli elementi con un border-style di un certo tipo:

...
hasBorder: function(e, i, c) {
    // con un'espressione regolare controlliamo che il parametro
    // appartenga a un insieme di valori consentiti
    if (/none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset/
        .test(c[3]))
    {
        // poi controlliamo che i 4 border-style corrispondano al
        // parametro indicato
        return ((c[3] == $(e).css("border-right-style")) &&
                (c[3] == $(e).css("border-bottom-style")) &&
                (c[3] == $(e).css("border-left-style")) &&
                (c[3] == $(e).css("border-top-style")));
    }
    else
    {
        return false;
    }
}
...
... utilizzo
$(".divLevel1:hasBorder(dotted)")

…e si potrebbe andare avanti per delle ore facendo esempi più o meno inutili.
I selettori così creati ovviamente coesistono con i selettori standard e niente ci vieta di combinarli come ci pare.
Commenti? Suggerimenti?


Recoding.it

1 Commento »

Recoding.it nasce come nuovo blog rivolto agli sviluppatori web.

Spazieremo dalle tecnologie di base (HTML/CSS) al DHTML (Javascript/jQuery) fino al server-side basato su piattaforma Asp.Net (C#).

Proporremo soluzioni presentate principalmente in forma di tutorial e snippet di codice, correlati da esempi e progetti scaricabili.

A presto per aggiornamenti.