Spesso mi capita di sviluppare funzionalità in Liferay, specialmente riguardanti l'interfaccia utente, di perdere tantissimo tempo nel perfezionare una routine javascript che faccia sparire un DIV, che ne evidenzi un'altro o che ne posizioni un'altro ancora.
Poi, dopo giorni di lavoro, mi accorgo che c'e' un oggetto in Liferay che fa esattamente quello che voglio, con 2 righe di codice.
E' questo il caso della taglib liferay-ui:form-navigator: è quel box azzurro che si trova alla destra di molte form del pannello di controllo, come ad esempio la gestione utente o la gestione di un site.
Ovviamente l'aspetto grafico è governato dai CSS per cui è utilizzabile anche al di fuori del control panel e personalizzabile come tutto in Liferay.
Per utilizzare il form navigator occorre importare le seguenti taglib:
<%@ taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui" %>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
<%@ taglib uri="http://liferay.com/tld/util" prefix="liferay-util" %>
Il form navigator si usa così nella home.jsp (o comunque si chiami):
<portlet:actionURL name="saveAll" var="saveAll"/>
<aui:form action="<%=saveAll%>" name="form">
<liferay-ui:form-navigator
backURL="<%=backURL %>"
categoryNames="<%= categoryNames %>"
categorySections="<%= categorySections %>"
formName="form"
htmlTop="<%=htmlTop %>"
htmlBottom="<%=htmlBottom %>"
jspPath="/sections/"
showButtons="<%=true %>"
/>
</aui:form>
dove:
backUrl: (opzionale) è la URL associata al pulsante Cancel
categoryNames: è uno String array con le label delle sezioni (nell'esempio, dopo la localizzazione delle label: User Information, Identification, Miscellaneous)
categorySections: è uno String[ ][ ] che contiene le voci di ogni sezione; all'i-esimo categoryName corrisponde l'i-esimo categorySection[ ]. Nell'esempio, categorySections[0]={"details","password","organizations","sites","usergroups","roles","personal_site","categorization"}
formName: (opzionale) il nome della form che racchiude il form-navigator
htmlTop: (opzionale) è il pezzo di codice html che andrà al top del form navigator
htmlBottom: come sopra, ma sotto :-)
jspPath: è il path che contiene i files jsp corrispondenti alle categorySections: nell'esempio, esiste una pagina password.jsp, una pagina organizations.jsp etc; il file si deve chiamare come la stringa contenuta nell'array e non come la sua versione localizzata a schermo.
showButtons:(opzionale) di default a true, serve per visualizzare o nascondere la button bar con Save e Cancel.
In sostanza la taglibcrea un div nascosto per ogni pagina jsp che trova nel jspPath e che corrisponde a una voce di categorySections; poi crea il codice per gestire i click sui link del menù, per evidenziare il link cliccato, visualizzare il div corrispondente e nascondere quello attualmente visualizzato.
Il pulsante Save esegue l'action della form che racchiude il form-navigator (nel mio caso"saveAll"); la form conterrà la somma di tutti gli elementi html inseriti in tutte le categorySections.
Le pagine jsp delle varie sections possono essere complicate a piacere, tanto da poter includere altre form con altre actions, o risultati di ricerca con il search-container, anche paginati etc.
Piccolo problema: se la pagina jsp contiene una form che fa POST su un'action, al ritorno dall'elaborazione il browser atterrerà sulla pagina principale, visualizzando la prima section (questo perchè devo sempre scrivere actionRequest.setRenderParameter("jspPage","home.jsp") e non posso impostare una sottopagina nel renderparameter. Di conseguenza se sto editando, ad esempio, i ruoli dell'utente ad ogni "add" LR ritorna sui dettagli. Il trucco c'e', ma non si vede: con un po' di javascript viene reimpostata la pagina corretta subito dopo, per questo tutto sembra filare liscio.
Purtroppo questa cosa non è automatica, cioè non è inclusa nel taglib del form-navigator, per cui occorre industrarsi un pò.
Studiando, come al solito, il funzionamento del codice html con google chrome, ho visto cheper ogni categorySection il div che contiene la pagina corrispondente ha id<portlet:namespace/>nomeCategorySection
Il link che lo fa apparire ha id<portlet:namespace/>nomeCategorySectionLink
la classe css che fa sparire il div è aui-helper-hidden-accessible,
mentre quella che fa apparire un div o visualizzare il link come selezionato è selected
La mia soluzione prevede che ad ogni action delle varie categorySections venga impostato un request attribute che contiene il nome della pagina da visualizzare.
Ad esempio, nel mio casoesiste una categorySection "video" e una pagina "video.jsp" che contiene a form che invoca l'action saveVideo, la cui ultima istruzione è
actionRequest.setAttribute("page2show","video");
Alla fine della jsp home.jsp che contiene il form navigator ho inserito queste istruzioni jquery:
<script type="text/javascript">
$('#<portlet:namespace/><%=page2show%>').addClass("selected");
$('#<portlet:namespace/><%=page2show%>').removeClass("aui-helper-hidden-accessible");
$('#<portlet:namespace/>primaSection').addClass("aui-helper-hidden-accessible");
$('#<portlet:namespace/>primaSection').removeClass("selected");
$('#<portlet:namespace/>primaSectionLink').parent().removeClass("selected");
$('#<portlet:namespace/><%=page2show%>Link').parent().addClass("selected");
</script>
Nel mio caso "primaSection" è la prima categorySection.
Le ultime 2 istruzioni impostano i link. La struttura del menù html che si vede nell'HTML della paginaè simile alla seguente:
<ul>
<li class="selected">
<a id="<portlet:namespace/>primaSectionLink">
</li>
<li class>
<a id="<portlet:namespace/>videoLink">
</li>
</ul>
La selezione del menù viene implementata con una classe dell'elemento LI (che non ha id)che racchiude il link; a questo sono dovute le due modifiche alle classi css del parent().
In sostanza, al ritorno da ogni action nascondo il primo DIV, deseleziono il link corrispondente, visualizzo il DIV deciso nell'action e seleziono il link corrispondente.
Probabilmente esiste una soluzione più liferay-istica, ma questa funziona bene ed è molto semplice.
Spero possa esser d'aiuto.
Buon lavoro!
Marcello