La primera vez que me engañes sera culpa tuya;la segunda vez sera mia.
Proverbio árabe

[Tiles] [Spring] - Menú Desplegables

Los menús desplegables son una preciosidad desde el punto de vista visual y un infierno desde el punto de vista técnico… y como los usuarios mandan pues montemos un menú desplegable. Y evidentemente, el usuario siempre encontrará la forma de complicarlo.

Lo que parece muy fácil cuando ya está hecho resulta bastante complejo técnicamente, así que si tienes que hacer uno de estos asegúrate de tener TODOS los requisitos definitivos antes de empezar, porque un cambio puede resultar sencillo o hacerte tirar todo a la basura. 

Menú Desplegable

Implementar los Objetos Item del Menú y Menú

public class LinkItem {

      private String classtype;

      private String key;

      private String href;      

      private String img;

      private String onclick;

      private String seleccion;

      private boolean cabecera = false;

      private List subapartados;

//Getters y Setters…

}

public class Menu {

      private List apartados;

//Getter y Setter…

}

Definir el Menú

En nuestro fichero XML descriptor de Spring debemos definir un bean del tipo Menú para cada menú desplegable de nuestra aplicación. Cada menú debe declarar el listado de los apartados que va a contener.

 <!– MENU SOLICITANTE–>

<bean id="menuRegistrado" class="es.xxx.arquitectura.utilidades.Menu" singleton="true">

      <property name="apartados" >

            <list>

                  <ref bean="Solicitante"/>

                  <ref bean="Proyecto"/>

                  <ref bean="Investigadores"/>

                  <ref bean="Presupuesto"/>

                  <ref bean="ImplicacionesEticas"/>

                  <ref bean="Buque"/>

                  <ref bean="Beneficiario"/>

                  <ref bean="Documentos"/>

            </list>

      </property>

</bean>

Ahora debemos declarar un bean del tipo Item para cada apartado, indicando el literal que mostrará, si es cabecera, la URL que tendrá asociada y el listado de los items que contiene cada uno. Por ejemplo:

<bean id="Presupuesto" class="es.xxx.arquitectura.utilidades.LinkItem" singleton="true">

      <property name="key" value="literal.presupuesto" />

      <property name="cabecera" value="true" />

      <!– <property name="seleccion" value="costesPersonal.titulo" /> –>

      <property name="href" value="listadoItemGastoPersonal.mec" />

      <property name="subapartados" >

            <list>

                  <ref bean="costePersonal"/>

                  <ref bean="suplementosSalariales"/>

                  <ref bean="costeEjecucion"/>

                  <ref bean="resumenPresupuesto"/>

            </list>

      </property>

</bean>

Y a su vez, definimos cada subapartado recursivamente. En este caso sólo hay dos niveles, pero podríamos tener más de forma recursiva.

 <bean id="costePersonal" class="es.xxx.arquitectura.utilidades.LinkItem" singleton="true">

      <property name="key" value="costesPersonal.titulo" />

      <property name="href" value="listadoItemGastoPersonal.mec" />

</bean>

Definir las Tiles

Normalmente al utilizar menús se utilizarán Struts Tiles. 

Por eso definimos una tile, del estilo a "tiles.menu". En nuestra tile contenedor utilizamos la tile menú y le indicamos el item del menú seleccionado (para que aparezca con un estilo diferente a los demás).

<definition name=" ContenedorInicio " path="/jsp/ContenedorInicio.jsp">

      <put name="cabecera" value="tiles.cabecera" />

      <put name="menu" value="tiles.menu" />

<put name="itemMenuSeleccionado" value="menu.acceso" />

      <put name="mensajes" value="tiles.mensajes" />

      <put name="central" value="FormularioLogin" />

</definition>

<definition name="tiles.menu" page="/jsp/MenuDesplegable.jsp"/>

 

Uitlizar el código!!!

Nuestra JSP contenedor,"/jsp/ContenedorInicio.jsp", será algo parecido a 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

"http://www.w3.org/TR/html4/loose.dtd">

<%@ taglib prefix="bean" uri="http://struts.apache.org/tags-bean"%>

<%@ taglib prefix="tiles" uri="http://struts.apache.org/tags-tiles"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ page errorPage="/jsp/ForwardError.jsp"%>

<c:catch>  

      <tiles:importAttribute name="itemMenuSeleccionado"/>

</c:catch>

<html>

<head>…</head>

<body>

<!– CABECERA DE LA APLICACION: TITULO Y OPCIONES DE MENU GENERALES–>

<div id="cabeceraTitulo">

      <tiles:insert attribute="cabecera" />

</div>

<!– CONTENEDOR CENTRAL–>

<div id="generalContenedor">

      <!– COLUMNA IZQUIERDA –>

      <div id="izquierdaContenedor">

<tiles:insert attribute="menu" >

<c:if test="${itemMenuSeleccionado != null}">

            <tiles:put name="actual" value="${itemMenuSeleccionado}"/>

</c:if>

            </tiles:insert>

      </div>

      <div id="centralContenedor">

<!– MENSAJES –>

            <div id="erroresMecDiv">

                  <tiles:insert attribute="mensajes" />

            </div>     

            <!– COLUMNA CENTRAL –>

            <tiles:insert attribute="central" />

      </div>

      <!– ZONA PARA QUE SE VEA CORRECTAMENTE CON MOZILLA –>

      <div class="clear"></div>

</div>

</body>

</html>

Ahora la JSP "/jsp/MenuDesplegable.jsp". Una forma bastante elegante es definir una tag para pintar los menús, así en el JSP sólo necesitamos declarar:

 

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="utilidades" uri="/WEB-INF/tld/utilidades.tld"%>

<c:catch>

      <tiles:useAttribute name="actual" />

</c:catch>

<utilidades:menu menuDefecto="menuInicio" actual="${actual}"/>

Nuestro fichero descriptor de la librería de etiquetas utilidades.tld relacionamos la etiqueta con nuestra clase MenuTag:

<taglib>

      <tlib-version>1.0</tlib-version>

      <jsp-version>1.1</jsp-version>

      <short-name>utilidades</short-name>

      <uri></uri>

      <description>Tags de utilidades</description>

      <tag>

            <name>menu</name>

            <tag-class>es.xxx.arquitectura.utilidades.tags.MenuTag</tag-class>

            <body-content>empty</body-content>

            <description>Tag que muestra el menú</description>

            <attribute>

                  <name>menuDefecto</name>

                  <required>true</required>

                  <rtexprvalue>true</rtexprvalue>

            </attribute>

            <attribute>

                  <name>actual</name>

                  <required>false</required>

                  <rtexprvalue>true</rtexprvalue>

            </attribute>

      </tag>

</taglib>

Y la clase MenuTag… idMenu es un String con el nombre del menú que vamos a cargar, en este caso menuRegistrado. actual es la opción del menú elegida.

public int doStartTag() throws JspException {

      ApplicationContext ctx =  WebApplicationContextUtils.getRequiredWebApplicationContext(pageContext.getServletContext());  

      Menu menu = (Menu)ctx.getBean(idMenu);

      if(pageContext.getRequest().getParameter("actual") != null) {

            actual = pageContext.getRequest().getParameter("actual");

}    

      resultado.append(mostrarSubapartados(opcionesMenu, actual));

      try {

            pageContext.getOut().print(resultado.toString());

      } catch (IOException e)    {}

      return SKIP_BODY;

}

Método mostrarSubaparatados (), genera el código HTML del Menú Desplegable. En nuestro caso, las cabeceras se implementan como <h2> y los subapartados como <ul>. Además, este método es recursivo.

private StringBuffer mostrarSubapartados(      List subapartados, String actual) throws JspException {

      StringBuffer resultado = new StringBuffer();

      LinkItem item           = (LinkItem)subapartados.get(0);

      boolean esCabecera      = item.isCabecera();

      //Si es cabecera se implementa como <h2>

      //Si no es cabecera se implementa como una lista

      if (!esCabecera) {

            resultado.append("<ul>\n");

      }

      for (int i = 0; i < subapartados.size(); i++) {

            item = (LinkItem)subapartados.get(i);

            boolean esActual        = item.getKey().equals(actual);

            boolean contieneActual    = contieneActual(item.getSubapartados(), actual);

            esCabecera              = item.isCabecera();

            //Si es cabecera se implementa como <h2>

            //Si no es cabecera se implementa como una lista

            if (esCabecera) {

                  resultado.append("<h2>");

            } else {

                  resultado.append("<li");

                  resultado.append(">\n");

            }

            resultado.append("<a");

            if (esActual || contieneActual){

                  resultado.append(" class=\"activo\"" );

            }

            resultado.append(" xhref=\"");

            resultado.append(item.getHref());

            resultado.append("\">");

            resultado.append(getMensajePropiedad(item.getKey()));

            resultado.append("</a>\n");

            if (esCabecera) {

                  resultado.append("</h2>");

                  if (contieneActual || esActual) {

resultado.append(mostrarSubapartados(item.getSubapartados(), actual));

                  }

            } else {

                  if (contieneActual || esActual) {

resultado.append(mostrarSubapartados(item.getSubapartados(), actual));

            }

      resultado.append("</li>");

            }

}

      if (!esCabecera) {

            resultado.append("</ul>");

      }

      return resultado;

}

Simple, verdad ? Menos mal que Chema lo montó :P

Technorati Tags: , ,

Attached Files:

4 Comentarios hasta el momento »

  1. jose dijo

    3 de December del 2008 a las 9:08 pm

    Lo unico que te falto , fue el codigo fuente, eso seria un golazo.

    joe

  2. silvia dijo

    12 de January del 2009 a las 9:13 pm

    Seria buenos tener el src.

    Saludos.

  3. yoyoooyoy dijo

    14 de January del 2009 a las 10:10 am

    Cuando monté el ejemplo no guardé el código, pero lo más importante lo copié aquí. Creo que esto sería suficiente.

    Si faltase algo dadme un toque. De todas formas cuando saque tiempo (calcula un mes!) reharé este ejemplo y colgaré el código.

    Saludos

  4. cristo dijo

    9 de June del 2009 a las 7:41 am

    no mames weyyyyyyyyy esta perrisimo esooo
    deb de haber algo mas facillllllll

Comentarios RSS · TrackBack URI

Dejanos tu Comentario

Nombre: (Requerido)

E-Mail: (Requerido)

Sitio WEB:

Comentario:

Comenta