Cos'è Alloy UI
Alloy UI si presenta come un framework completo che abbraccia tre livelli operativi fondamentali di un browser:
Struttura
- Fornisce taglib per la creazione di form HTML e disposizione elementi
- Offre supporto HTML5 anche in Internet Explorer
Stile
- Supporto a CSS3
- Sfrutta il concetto di progressive enhancement
Comportamento
- Basato sul framework YUI3
- Consente la gestione di DOM, eventi, Ajax
- Fornisce widget per dialog, tree, tabs, autocomplete e altri componenti
Cos'è YUI
YUI (Yahoo User Interface) è descritto come "una libreria gratuita e open source di JavaScript e CSS per costruire applicazioni web interattive". Il framework si distingue per caratteristiche di modularità e leggerezza, permettendo di "caricare in memoria i plugin necessari solamente all'occorrenza".
Nota importante: Alloy estende YUI3 ma non include tutte le funzionalità di YUI. Al momento della scrittura, Alloy utilizza la versione 3.4.0 di YUI (su cui si basa Liferay 6.1.1), mentre YUI aveva già raggiunto la versione 3.7.3.
Sandbox
La sandbox rappresenta un concetto ereditato da YUI che struttura il codice JavaScript. Consente di:
- Dichiarare i moduli necessari
- Risolvere automaticamente le dipendenze
- Caricare moduli on demand
- Mettere in cache i moduli caricati
- Confinare la visibilità dei dati, evitando conflitti di variabili globali
Creazione della Sandbox
Gli oggetti globali disponibili sono:
- YUI per il framework di Yahoo
- AUI per il framework di Liferay
var A = AUI();
A.use(moduli_da_usare, function(A) {
// codice applicativo
});
Esempio pratico
AUI().use('event', 'node', function(A) {
A.one('#console').html('Ciao mondo!');
});
Taglib Alloy
La taglib <aui:script> sostituisce il tradizionale window.addEventListener('DOMContentLoaded'). Tutto il codice JavaScript contenuto viene trasferito in un unico blocco <script> in fondo alla pagina ed eseguito in modo asincrono all'evento DOM Ready.
<aui:script use="event,node">
function localFunction() {
alert('Funzione locale');
}
localFunction();
var node = A.one('#console');
node.html('Ciao mondo');
</aui:script>
Funzioni globali
Per definire funzioni visibili su tutta la pagina si utilizza Liferay.provide():
Liferay.provide(
window,
'<portlet_namespace />globalFunction',
function(param1, param2, ...) {
var A = AUI();
var node = A.one('#<portlet_namespace />console');
node.html(param1);
},
['node','event']
);
I quattro parametri sono:
1. Oggetto DOM a cui associare la funzione 2. Nome da assegnare alla funzione 3. Corpo della funzione 4. Elenco dei moduli necessari
Manipolazione del DOM
Metodi di selezione
Recuperare un singolo elemento (equivalente di .miaclasse:first in jQuery):
var foo = A.one('.miaclasse');
Recuperare più elementi (equivalente di .miaclasse in jQuery):
var foo = A.all('.miaclasse');
Navigazione nel DOM
foo.next() // elemento successivo foo.previous() // elemento precedente
Gestione degli attributi
foo.attr('title') // lettura
foo.attr('title','Titolo') // scrittura
foo.removeAttribute('title') // rimozione
Gestione del contenuto
foo.html() // lettura HTML
foo.html('...') // scrittura HTML
foo.text() // lettura testo
foo.text('...') // scrittura testo
foo.val() // lettura valore form
foo.val('...') // scrittura valore form
Gestione degli stili CSS
foo.getStyle('visibility') // lettura
foo.setStyle('visibility', 'hidden') // scrittura
Gestione delle classi
foo.addClass('css1')
foo.removeClass('css1')
foo.toggleClass('css1')
foo.hasClass('css1')
foo.replaceClass('css1', 'css2')
Visibilità
Alloy gestisce la visibilità applicando la classe CSS aui-helper-hidden:
foo.show() foo.hide() foo.toggle()
Iterazione tra elementi
A.all('.miaclasse').each(function(item, index, collection) {
// codice applicativo
});
Gestione degli eventi
A differenza di jQuery, Alloy non dispone di metodi specifici per singoli eventi. Utilizza un metodo unico on():
foo.on('blur', callback_function_1);
foo.on('click', callback_function_2);
// Alternativa con notazione JSON
foo.on({
blur: callback_function_1,
click: callback_function_2
});
Esempio con elemento singolo
var foo = A.one('#mioelemento');
foo.on('click', function(event) {
var thisId = this.get('id'); // elemento su cui è invocato on
var targetId = event.target.get('id'); // elemento che ha generato evento
});
Esempio con lista di elementi
var nodi = A.all('.miaclasse');
nodi.on('click', function(event) {
this.size(); // NodeList su cui è invocato on
event.target.get('id'); // elemento che ha generato evento
});
Event Delegation
La delegazione degli eventi sfrutta il principio dell'event bubbling:
<ul id='contenitore'>
<li class='item'>Voce di menu 1</li>
<li class='item'>Voce di menu 2</li>
<li class='item'>Voce di menu 3</li>
</ul>
var contenitore = A.one('#contenitore');
contenitore.delegate(
'click',
function(event) {
// codice applicativo
},
'li.item'
);
Questo approccio è efficiente in memoria e gestisce automaticamente elementi aggiunti dinamicamente.
Chiamate Ajax
Alloy mette a disposizione due plugin distinti: aui-io-request e aui-io-plugin. Nel contesto di Liferay, si distinguono tre tipologie di URL:
- Action: esecuzione di logica di business
- Render: caricamento di frammenti JSP
- Resource: caricamento di oggetti JSON
Ajax Action Request
<liferay-portlet:actionURL name="submitForm" var="actionURL" />
<aui:script use='aui-io-request'>
A.io.request(
'<%=actionURL%>',
{
dataType: 'json',
form: {
id: '<portlet_namespace />fm'
},
method: 'POST',
on: {
end: function(event) {
var response = this.get('responseData');
// codice applicativo
}
}
}
);
</aui:script>
Ajax Render Request
<liferay-portlet:renderURL
var='renderURL'
windowState="<%=LiferayWindowState.EXCLUSIVE.toString()%>" />
<aui:script use='aui-io-request'>
A.io.request(
'<%=renderURL%>',
{
on: {
success: function(event) {
A.one('#foo').html(this.get('responseData'));
}
}
}
);
</aui:script>
Utilizzo del plugin IO:
<aui:script use='aui-io-plugin'>
var foo = A.one('#foo');
foo.plug(
A.Plugin.IO,
{
failureMessage: 'Si è verificato un errore',
showLoading: true,
uri: '<%=renderURL%>'
}
);
foo.io.start();
</aui:script>
Ajax Resource Request
<liferay-portlet:resourceURL var='resourceURL'>
<liferay-portlet:param name="<%=Constants.CMD%>" value="echo" />
</liferay-portlet:resourceURL>
<aui:script use='aui-io-request'>
A.io.request(
'<%=resourceURL%>',
{
data: {
<portlet_namespace />param: value
},
dataType: 'json',
on: {
success: function() {
var response = this.get('responseData');
alert(response.echoParam);
}
}
}
);
</aui:script>
Implementazione lato portlet:
public void serveResource(ResourceRequest resourceRequest,
ResourceResponse resourceResponse)
throws IOException, PortletException {
String cmd = resourceRequest.getParameter(Constants.CMD);
if("echo".equals(cmd)) {
String param1 = ParamUtil.getString("param1");
JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
jsonObj.put("echoParam", param1);
writeJSON(resourceRequest, resourceResponse, jsonObj);
}
}
Widget Alloy UI
Il framework fornisce numerosi widget grafici ereditati e arricchiti da YUI:
- Autocomplete
- Grafici
- Treeview
- Calendar
- Carousel
- Dialog
- Toolbar
- Drag & Drop
Conclusioni
Alloy UI si presenta come framework estremamente interessante con enormi potenzialità. Vale la pena approfondire soprattutto gli aspetti legati ai widget, grazie ai quali è possibile rendere davvero "rich" le applicazioni web costruite con Liferay.
Riferimenti
- [AlloyUI](http://www.liferay.com/community/liferay-projects/alloy-ui/)
- [YUI3](http://yuilibrary.com/)
- [YUI3 API](http://yuilibrary.com/yui/docs/api/)
- [AlloyUI demo](http://www.liferay.com/community/liferay-projects/alloy-ui/demos)
- [AlloyUI API](http://alloyui.com/deploy/api/)
- [AlloyUI issue tracker](http://issues.liferay.com/browse/AUI)
