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)