mercoledì 6 febbraio 2008

xslt per il menu dinamico di rujoch.it

Alcune settimane fa (anche parecchie), Simone, un lettore del blog, mi aveva chiesto se potevo spiegargli come avevo realizzato i menu dinamici del sito www.rujoch.it.

Ecco la risposta:


Javascript


Come è lecito ipotizzare, la base di questo menù non è altro che un javascript, scaricato dall'eccellente Dynamic Drive. Lo script si chiama AnyLink Drop Down Menu e il codice si trova su questa pagina: http://www.dynamicdrive.com/dynamicindex1/dropmenuindex.htm


Per semplicità, ho spostato il codice javascript all'esterno e, nel sito realizzato con Umbraco, lo chiamerò nella sezione head di un template con la chiamata:


<script language="JavaScript" type="text/javascript" src="/menuSup.aspx"></script>


Avete letto bene: il javascript diventerà un file con estensione .aspx, perché deve essere generato dinamicamente.


Come si può notare dal codice visibile su Dynamic Drive, per ogni voce del menu, c'è una chiamata a due funzioni presenti nel file javascript. Anche questa parte (l'intero menu), nel mio sito con Umbraco, diventa dinamica.


La navigazione


In un sito realizzato con Umbraco, la difficoltà maggiore sta nel selezionare i nodi del file umbraco.config su cui si vuole intervenire. Per il menù, sembrerebbe molto semplice perché la struttura del sito è quella che l'utente si costruisce nel riquadro contenuti dell'interfaccia. Basterebbe quindi decidere quanti livelli si vogliono visualizzare. (Un file xslt con questa funzione viene installato insieme alla versione 3 di Umbraco, vedi sezione developper dell'interfaccia).


Prendendo confidenza con Umbraco si comincia però a inserire in quella struttura ad albero dei contenuti che non devono mai essere rappresentati come pagina html (un feed rss, dei javascript dinamici, ecc.). Inoltre, non tutte le pagine di un determinato "nodo" devono sempre finire nel menù.


Seguendo il metodo suggerito da Warren Buckley, si può quindi dotare ogni tipo di documenti (Dokumenttyper) di un campo di tipo boolean che potrebbe chiamarsi isVisible. In questo modo, potrò selezionare i nodi che hanno un attributo isVisible uguale à 1.


Xslt per il menu


Xslt per il menu nella pagina (la parte inclusa fra i tag <ul id="menu"> e </ul>) del sito www.rujoch.it, da inserire nel master template comune a tutte le pagine. (comando inserisci macro)


Ometto tutta l'intestazione del file xml, che Umbraco fornisce nel suo template di file xslt; il contenuto di seguito indicato va adattato e inserito dopo il commento <!-- start writing XSLT -->


<ul id="menu">

<xsl:for-each select="$currentPage/ancestor::root/*/node[@level='2']">

<!-- Traduzione: dovunque io mi trovi, torna alla radice del file xml e seleziona i nodi che si chiamano node e hanno un attributo level uguale a 2 (in pratica, nell'albero dei contenuti, sono le prime diramazioni) e per ognuno di loro (istruzione for-each) esegue l'istruzione seguente -->

<!--=====================================================================================-->

<xsl:variable name="posizione">

<xsl:value-of select="position()-1"/>

</xsl:variable>

<!-- mi serviva una variabile xslt che restituisse la posizione del nodo selezionato nell'array dei nodi selezionati; gli array in javascript e in xslt sono trattati in modo diverso: il primo elemento in javascript ha indice 0, in xslt 1. La variabile viene definita qui prima di poter essere utilizzata. -->

<xsl:if test="./data[@alias='isVisible']=1">

<!-- Se ho specificato tramite il booleano di cui sopra che la voce deve essere visibile scrivo nel file generato al volo: -->

<li>

<a href="#" onclick="return clickreturnvalue(),location.href='{umbraco.library:NiceUrl(@id)}'" onmouseover="dropdownmenu(this, event, menu{$posizione}, '100px')" onmouseout="delayhidemenu()"><xsl:value-of select="@nodeName"/></a></li>

</xsl:if>

<!-- Questa parte è solo la chiamata al javascript per ogni collegamento, ho inserito in modo dinamico una url, un numero che corrisponde alla posizione della voce di menù e un nome da visualizzare nel menù -->

<!--============================================================================================-->

</xsl:for-each>

</ul>

Inserita nel template, questa macro scrive il codice seguente:


<ul id="menu"><li><a href="#" onclick="return clickreturnvalue(),location.href='/sci-club.aspx'" onmouseover="dropdownmenu(this, event, menu1, '100px')" onmouseout="delayhidemenu()">Sci club</a></li>[poiché ho utilizzato l'istruzione xsl:for-each, seguono tutte le altre voci del menu… e alla fine, il tag che chiude l'elenco non ordinato ]</ul>


Il javascript "dinamico"


Abbiamo ora una pagina che chiama un javascript e si aspetta di trovarci degli array.
Ci resta da scrivere il javascript. (Controllare eventualmente il codice javascript su Dynamic Drive, per capire come deve risultare il javascript.)


La logica è la stessa ma le istruzioni xsl:for-each da utilizzare sono due, l'una all'interno dell'altra.

La parte di xslt restituisce semplicemente tutti gli array del javascript.


<xsl:for-each select="$currentPage/ancestor::root/*/node[@level='2']">

<!--=====================================================================================-->

<xsl:variable name="posizione">

<xsl:value-of select="position()-1"/>

</xsl:variable>

<xsl:if test="./data[@alias='isVisible']=1">

var menu<xsl:value-of select="position()-1"/>=new Array()

<xsl:for-each select="node[@level='3' and string(data [@alias='isVisible']) = '1']">

menu<xsl:value-of select="$posizione"/>[<xsl:value-of select="position()-1"/>]='<a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="@nodeName"/></a>'

</xsl:for-each>

</xsl:if>

Il risultato (parziale) sarà :


var menu1=new Array()

menu1[0]='<a href="/sci-club/tesseramento.aspx">Tesseramento</a>'

menu1[1]='<a href="/sci-club/vantaggi.aspx">Vantaggi</a>'

menu1[2]='<a href="/sci-club/direttivo.aspx">Direttivo</a>'

Non basta perché questo è solo la parte degli array. Devo scrivere tutto il resto.

Creo pertanto un tipo di documento (Dokumenttyper) di nome javascript e il relativo template. Nella scheda info del tipo di documento, l'unico template autorizzato deve essere quello corrispondente (si chiama javascript se ho permesso a Umbraco di crearlo per me, spuntando Create matching template nel creare il tipo di documento). Non serve altro. Non devo definire nessun "tab" e nessuna proprietà !


Il template per javascript:


Nell'editor di template, digitare:

// &lt;![CDATA[

/***********************************************

* AnyLink Drop Down Menu- © Dynamic Drive (www.dynamicdrive.com)

* This notice MUST stay intact for legal use

* Visit http://www.dynamicdrive.com/ for full source code

***********************************************/

in questo punto inserire la macro xslt precedentemente creata.


segue il codice javascript situato sotto gli array (non lo scrivo, basta fare taglia incolla dal sito di Dynamic Drive)

e, IMPORTANTISSIMO, chiudo la sezione CDATA che racchiude il javascript digitando


// ]]&gt;


E' fatta ! vi basta ora creare nella sezione contenuti dell'interfaccia di Umbraco un file basato sul template javascript e chiamarlo menuSup (o nel modo in cui avrete deciso di chiamare il vostro javascript esterno). Lo richiamate allora dalla sezione head, come precedentemente indicato.

1 commento:

Simone ha detto...

Grandissimo hai fatto una giuda perfetta!!

Simone