Menu verticale multi livello con jQuery (Multi Level slide accordion menu with jQuery)

In questo post discuterò dell'utilizzo "concreto" di uno dei puù citati menù accordion jQuery, descritto in molti articoli come ad esempio:
Da subito ci si renderà conto dell'impossibilità di utilizzare facilmente il menù in un sito web. Infatti il menù presenta 2 problemi: il primo è che non è possibile cambiare il valore di href negli item che possiedono sotto livelli ed il secondo è che anche cambiando il valore di href negli item figli, l'evento onclick su tali livelli sarà interdetto.
Per spiegarmi meglio, consideriamo la struttura originale:
<ul class="topnav">
	<li><a href="#" target="scriptbreaker">Home</a></li>
	<li><a href="#">JavaScript</a>
		<ul>
			 <li><a href="#">Cookies</a></li>
			 <li><a href="#">Events</a></li>
				<ul>
					<li><a href="#">CSS</a></li>
					<li><a href="#">JavaScript</a></li>
				</ul>
			</li>
			 <li><a href="#">Tabs</a></li>
		</ul>
	</li>
	<li><a href="#">Tutorials</a>
		<ul>
			 <li class="active"><a href="#">HTML</a></li>
			 <li><a href="#">CSS</a></li>
			 <li><a href="#">Java</a>
				<ul>
					<li><a href="#">JSP</a></li>
					<li><a href="#">JSF</a></li>
				</ul>
			</li>
			 <li><a href="#">Tabs</a></li>
		</ul>
	</li>
	<li><a href="#" target="_blank">Contact</a></li>
	<li><a href="#">Upload script</a></li>
</ul>
 Analizzando il file scriptbreaker-multiple-accordion-1.js necessario per il funzionamento del menù si osserva che affinché l'effetto accordion funzioni si deve lasciare inalterato il valore di href (href='#') negli item che possiedo sotto item mentre è possibile cambiare il valore di href negli altri item. Ad esempio:
<ul class="topnav">
	<li><a href="pagina1.html" target="scriptbreaker">Home</a></li>
	<li><a href="#">JavaScript</a>
		<ul>
			 <li><a href="pagina2.html">Cookies</a></li>
			 <li><a href="#">Events</a></li>
				<ul>
					<li><a href="pagina3.html">CSS</a></li>
					<li><a href="pagina4.html">JavaScript</a></li>
				</ul>
			</li>
			 <li><a href="pagina5.html">Tabs</a></li>
		</ul>
	</li>
	<li><a href="#">Tutorials</a>
		<ul>
			 <li class="active"><a href="pagina6.html">HTML</a></li>
			 <li><a href="pagina7.html">CSS</a></li>
			 <li><a href="#">Java</a>
				<ul>
					<li><a href="pagina8.html">JSP</a></li>
					<li><a href="pagina9.html">JSF</a></li>
				</ul>
			</li>
			 <li><a href="pagina10.html">Tabs</a></li>
		</ul>
	</li>
	<li><a href="pagina11.html" target="_blank">Contact</a></li>
	<li><a href="pagina12.html">Upload script</a></li>
</ul>
Se si effettua la modifica sopra riportata si osserverà che dopo aver cliccato su una voce di menù principale per espandere le sotto voci, i link sulle sotto voci non funzionano più!
Il problema è dovuto al file scriptbreaker-multiple-accordion-1.js ed in particolare alla seguente funzione:
if($(this).find("a:first-child").attr('href') == "#"){
 				    $(this).click(function () {
 				        return false;
                    });
 		  		}
che evita lo spostamento ad inizio pagina quando un item principale, con href="#", viene premuto. E' quindi necessario cancellare o commentare la seguente funzione ed assegnare all'evento onclick in valore "return false" direttamente nelle voci principali. Quindi:
<ul class="topnav">
	<li><a href="pagina1.html" target="scriptbreaker">Home</a></li>
	<li><a href="#" onclick='return false;'>JavaScript</a>
		<ul>
			 <li><a href="pagina2.html">Cookies</a></li>
			 <li onclick='return false;'><a href="#">Events</a></li>
				<ul>
					<li><a href="pagina3.html">CSS</a></li>
					<li><a href="pagina4.html">JavaScript</a></li>
				</ul>
			</li>
			 <li><a href="pagina5.html">Tabs</a></li>
		</ul>
	</li>
	<li><a href="#" onclick='return false;'>Tutorials</a>
		<ul>
			 <li class="active"><a href="pagina6.html">HTML</a></li>
			 <li><a href="pagina7.html">CSS</a></li>
			 <li onclick='return false;'><a href="#">Java</a>
				<ul>
					<li><a href="pagina8.html">JSP</a></li>
					<li><a href="pagina9.html">JSF</a></li>
				</ul>
			</li>
			 <li><a href="pagina10.html">Tabs</a></li>
		</ul>
	</li>
	<li><a href="pagina11.html" target="_blank">Contact</a></li>
	<li><a href="pagina12.html">Upload script</a></li>
</ul>
Riguardo invece il primo problema riscontrato, ovvero l'impossibilità di rendere attivi gli item con sotto item, ovvero gli item con valore href="#", una possibile soluzione è quella di duplicare la voce come sottovoce. Pertanto:
<ul class="topnav">
	<li><a href="pagina1.html" target="scriptbreaker">Home</a></li>
	<li><a href="#" onclick='return false;'>JavaScript</a>
		<ul>
			<li><a href="pagina13.html">JavaScript</a></li>
			 <li><a href="pagina2.html">Cookies</a></li>
			 <li onclick='return false;'><a href="#">Events</a></li>
				<ul>
					<li><a href="pagina14.html">Events</a></li>
					<li><a href="pagina3.html">CSS</a></li>
					<li><a href="pagina4.html">JavaScript</a></li>
				</ul>
			</li>
			 <li><a href="pagina5.html">Tabs</a></li>
		</ul>
	</li>
	<li><a href="#" onclick='return false;'>Tutorials</a>
		<ul>
			<li><a href="pagina15.html">Tutorials</a></li>
			 <li class="active"><a href="pagina6.html">HTML</a></li>
			 <li><a href="pagina7.html">CSS</a></li>
			 <li onclick='return false;'><a href="#">Java</a>
				<ul>
					<li><a href="pagina16.html">Java</a></li>
					<li><a href="pagina8.html">JSP</a></li>
					<li><a href="pagina9.html">JSF</a></li>
				</ul>
			</li>
			 <li><a href="pagina10.html">Tabs</a></li>
		</ul>
	</li>
	<li><a href="pagina11.html" target="_blank">Contact</a></li>
	<li><a href="pagina12.html">Upload script</a></li>
</ul>
 

Page.ResolveUrl in head runat="server"

Per utilizzare il metodo Page.ResolveUrl all'interno del tag head con l'attributo runat="server", è sufficiente utilizzare il simbolo # al posto dell' =, come di seguito riportato:
<head runat="server">
<link rel="stylesheet" type="text/css" href="<%#ResolveUrl("~/script/somefile.css")%>" />
</head>
e richiamando Page.Header.DataBind() nella Sub Page_Load()
Public Sub page_load()
        Page.Header.DataBind()
End Sub

ASP.NET Routing e Authorization

Ho utilizzato il routing asp.net per la gestione delle lingue in un sito web registrando nell'Application_Start del Global.asax:
routes.Add("en", New Route("en/{*path}", New GlobalizationRouteHandler(CultureInfo.GetCultureInfo("en"))))
routes.Add("it", New Route("it/{*path}", New GlobalizationRouteHandler(CultureInfo.GetCultureInfo("it-IT"))))
In questo modo una pagina in lingua inglese viene riscritta come http://www.miosito.com/it/pagina.aspx ed un pagina in lingua inglese come http://www.miosito.com/en/pagina.aspx.
Il problema di questa tecnica nasce nel momento in cui alcune pagine appartengono a direttori il cui accesso è limitato dall' "access rules" standard, aggiungendo quindi al direttorio un file web.config simile al seguente che permette l'accesso al solo ruolo "Admin":
<configuration>
    <system.web>
        <authorization>
            <allow roles="Admin" />
            <deny users="*" />
        </authorization>
    </system.web>
</configuration>
Pertanto l'url http://www.miosito.com/direttorio/pagina.aspx viene reindirizzato alla pagina di login a meno che l'utente non sia identificato ed appartenente al ruolo Admin.
Se però l'indirizzo diventa http://www.miosito.com/it/direttorio/pagina.aspx, ovvero l'indirizzo riscritto dal routing, la limitazione imposta nel web.config sembra non funzionare ed è possibile accedere alla pagina protetta!
Per prevenire questo fenomeno è sufficiente aggiungere al web.config principale del sito:
<location path="it/direttorio">
        <system.web>
            <authorization>
                <allow roles="Admin"/>
                <deny users="*" />
            </authorization>
        </system.web>
    </location>

    <location path="en/direttorio">
        <system.web>
            <authorization>
                <allow roles="Admin"/>
                <deny users="*" />
            </authorization>
        </system.web>
    </location>