Nei primo tutorial abbiamo utilizzato Portofino 4 per creare un blog modellando la struttura dei dati e creando le pagine principali. Nel secondo articolo abbiamo introdotto i permessi e modificato il layout grafico. Per tutte queste operazioni abbiamo utilizzato solo l'interfaccia di Portofino.

In questo terzo tutorial della serie creiamo pagine personalizzate per i post. L'obiettivo finale è mostrato nella figura seguente.

 

Passo 1. Cambiamo la visualizzazione dell'elenco dei post

Attualmente la home page mostra l'elenco dei post in forma tabellare come avviene in tutte le pagine CRUD di Portofino, mentre i blog solitamente presentano i post in sequenza, mostrando il titolo, un summary e di seguito un link “Read” per leggere l'intero articolo.
 
Creiamo una pagina custom per la visualizzazione (una jsp) che sostituisca la pagina di ricerca. Modifichiamo lo script Groovy perché carichi gli oggetti da visualizzare e reindirizzi ad una nuova pagina.
Per la crearla prendiamo spunto da quella standard posizionata in layouts/crud/search.jsp.
 
Vediamo lo script.
    //*******************************************************
    // List objects
    //*******************************************************

    @DefaultHandler
    @Override
    public Resolution execute() {
        if (object == null) {
            return doList();
        } else {
            return read();
        }
    }

    public Resolution doList(){
        firstResult = 0;
        maxResults= 10;
        loadObjects();
        return forwardToPortletPage("/apps/default/web/listPosts.jsp");
    }
Nello script facciamo l'ovveride del metodo execute chiamato di default da Stripes, originariamente il metodo reindirizza alla doRead o a doSearch. Noi lo facciamo reindirizzare ad un nostro metodo doList. Il metodo doList chiama un metodo già presente nel CRUD per caricare gli oggetti e fa il il forward ad una pagina jsp che andremo a creare.
 
La pagina jsp è mostrata in seguito. Portofino utilizza il templating di Stripes per definire le pagine jsp.
 
<%@ page import="com.google.inject.internal.Objects" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="com.manydesigns.elements.xml.XhtmlBuffer" %>
<%@ page import="org.apache.commons.lang.StringUtils" %>
<%@ page contentType="text/html;charset=UTF-8" language="java"
         pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="stripes"
    uri="http://stripes.sourceforge.net/stripes-dynattr.tld"%>
<%@taglib prefix="mde" uri="/manydesigns-elements"%>
<%@ taglib tagdir="/WEB-INF/tags" prefix="portofino" %>
<stripes:layout-render name="/skins/${skin}/portlet.jsp">
 <jsp:useBean id="actionBean" scope="request"
   type="com.manydesigns.portofino.pageactions.crud.CrudAction"/>
 <stripes:layout-component name="portletTitle">
   <c:out value="${actionBean.crudConfiguration.searchTitle}"/>
 </stripes:layout-component>
 <stripes:layout-component name="portletBody">
  <div id="posts" >
   <portofino:buttons list="crud-search" cssClass="portletButton" />
   <%
     XhtmlBuffer buffer = new XhtmlBuffer();
     int i = 0;
     for (HashMap object : (List<HashMap>)actionBean.objects){
       buffer.writeH2((String)object.get("title"));
       buffer.write(StringUtils.abbreviate(
        (String) object.get("summary"),300));
       buffer.writeBr();
       buffer.writeAnchor("post/"+object.get("id"), "Read");
       buffer.writeHr();
       i++;
       if(i==10)
         break;
     }
     out.println(buffer.toString());
     %>
   </div>
<script type="text/javascript">
   result = 10;
   isLoading=false;
   $(window).scroll(function () {
      if ($(window).scrollTop() + $(window).height() > 
            $('#posts').height() - 5 && !isLoading ) {
         isLoading = true;
         $.ajax({
            type: 'GET',
            url: "post?jsonSearchData=1&firstResult="+
                  result+"&maxResults=10",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: function (msg) {
            for (var i = 0; i < msg.Result.length; i++) {
                  $("div#posts").append('<h2>'+
                   msg.Result[i].title.value+
                   '</h2>'+msg.Result[i].summary.value+'<br/>'+
                   '<a href="post/'+msg.Result[i].id.value+
                   '">Read</a><hr/>');
                }
                isLoading = false;
                }
              });
              result = result+10;
            }
         });

</script>
  <portofino:buttons list="crud-search" cssClass="portletButton" />
  </stripes:layout-component>
</stripes:layout-render>
Notiamo che nella prima parte ciclo sulla lista di oggetti “actionBean.objects” esposta dalla mia action. Per ogni oggetto stampo il titolo, il summary e creo un link al dettaglio. Tramite un contatore stampo solo i primi dieci elementi.
 
Per visualizzare gli elementi successivi nella pagina, utilizzo un metodo di caricamento via JavaScript, che carichi 10 post quando l'utente raggiunge il fondo della pagina (lo stesso meccanismo che usa Facebook per visualizzare i suoi post).
 
JavaScript fa una chiamata Ajax all'indirizzo
post?jsonSearchData=1&firstResult="+result+"&maxResults=10
Il metodo jsonSearchData è un metodo già presente nella CRUD che restituisce i risultati di una ricerca in JSon ed è utilizzato ad esempio per la paginazione.
I dati vengono caricati come JSON e stampati in coda a quelli presenti.  
 
La stampa dei pulsanti relativi alla search è inclusa nelle righe
<portofino:buttons list="crud-search" cssClass="portletButton" />
Questa riga stampa l'elenco dei bottoni presenti nella search definiti nella classe  AbstractCrudAction da cui la nostra Action deriva. I bottoni sono definiti aggiungendo l'annotazione @Button ad un qualsiasi metodo che restituisca una Resolution.
 
Se nel blog volete rimuovere dei pulsanti, ad esempio quelli che esportano in Excel e in Pdf, i bulk edit e delete (inutile con questa visualizzazione). Li possiamo disabilitare facendo nella nostra Action l'ovverride dei metodi in AbstractCrudAction senza mettere le annotation relative al button. Con questo metodo disabilito i pulsanti pdf ed excel sia nei post sia nei commenti.
...

//Buttons disabled
    @Override
    Resolution exportReadExcel() {
        return super.exportReadExcel()
    }

    @Override
    Resolution exportReadPdf() {
        return super.exportReadPdf()
    }

    @Override
    Resolution exportSearchExcel() {
        return super.exportSearchExcel()
    }

    @Override
    Resolution exportSearchPdf() {
        return super.exportSearchPdf()
    }

    @Override
    Resolution bulkDelete() {
        return super.bulkDelete()
    }


    @Override
    Resolution bulkEdit() {
        return super.bulkEdit()
...
Il risultato è mostrato nella seguente figura
 
 

Passo 2. Editor html nei post

In questo passo modifichiamo la create, la read e l'edit del singolo post perché utilizzi un editor html per scrivere e visualizzare il campo body del post. Portofino 4 già utilizza l'editor javascript CKEditor per creare le pagine di tipo Text. Per utilizzarla anche nel CRUD basta inserire l'annotation “RichText” nel campo body.
 
Andiamo in administration > Tables
Selezioniamo la tabella “post”. Infine clicchiamo sul campo “body”. 
Qui possiamo selezionare in “Type of content” il valore “RichText” per l'utilizzo dell'editor html
 
 
Con questa operazione abbiamo un editor html anche per la creazione e la modifica.
 

Passo 3. Cambiamo la visualizzazione dei post

Come ultimo passo cambiamo la visualizzazione del singolo post per non avere il formato proprietà/valore di Portofino 4. Come abbiamo fatto precedentemente nella lista dei post, modifichiamo lo script Groovy perché reindirizzi ad una nostra pagina jsp custom.
@Override
    Resolution read() {
        super.read();
        return forwardToPortletPage("/apps/default/web/readPost.jsp");
    }
E scriviamo la pagina jsp readPost.jsp
<%@ page import="java.util.HashMap" %>
<%@ page import="com.manydesigns.elements.xml.XhtmlBuffer" %>
<%@ page contentType="text/html;charset=UTF-8" language="java"
       pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="stripes" 
       uri="http://stripes.sourceforge.net/stripes-dynattr.tld"%>
<%@taglib prefix="mde" uri="/manydesigns-elements"%>
<%@ taglib tagdir="/WEB-INF/tags" prefix="portofino" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<stripes:layout-render name="/skins/${skin}/portlet.jsp">
    <jsp:useBean id="actionBean" scope="request" 
       type="com.manydesigns.portofino.pageactions.crud.CrudAction"/>
    <stripes:layout-component name="portletTitle">
        <% HashMap obj = (HashMap)actionBean.object;%>
        <%= obj.get("title")%>
    </stripes:layout-component>
    <stripes:layout-component name="portletBody">
        <!-- Print the post -->
        <%
            HashMap obj = (HashMap)actionBean.object;
            XhtmlBuffer buffer = new XhtmlBuffer();
            buffer.openElement("em");
            buffer.write((String) obj.get("summary"));
            buffer.closeElement("em");
            buffer.writeBr();
            buffer.writeBr();
            buffer.writeNoHtmlEscape((String) obj.get("body"));
            buffer.writeBr();
            buffer.openElement("strong");
            buffer.write((String) obj.get("author"));
            buffer.closeElement("strong");
            buffer.writeBr();
            out.println(buffer.toString());
        %>

        <c:if test="${not empty actionBean.searchString}">
            <input type="hidden" name="searchString"
             value="<c:out value="${actionBean.searchString}"/>"/>
        </c:if>
    </stripes:layout-component>
    <stripes:layout-component name="portletFooter">
        <div class="crudReadButtons">
            <portofino:buttons list="crud-read" cssClass="portletButton" />
        </div>
        <stripes:submit name="print" value="Print" 
          disabled="true" class="portletButton"/>-->
        <script type="text/javascript">
            $(".crudReadButtons button[name=delete]").click(function() {
                return confirm ('<fmt:message key="commons.confirm" />');
            });
        </script>
    </stripes:layout-component>
</stripes:layout-render>
 
La pagina jsp sopra stampa i campi dell'oggetto nel formato desiderato. Il risultato finale è quello desiderato ed è di seguito mostrato. 
 
 

Nel prossimo tutorial andremo a personalizzare la pagina dei commenti, mettendo l'elenco e la creazione in un'unica pagina.

 

comments powered by Disqus