Java Server Caritas

Friday, January 05, 2007

¿Vale la pena JQuery?

Creo que si, podemos tomar el tutorial anterior y reducir drásticamente el JavaScript en la página utilizando Jquery.

Dejando el Servlet y la página totalmente iguales importamos Jquery (después de bajarlo y colocarlo dentro del proyecto web):

<script type="text/javascript" src="jquery-latest.js"/>

Nos volamos todo el JavaScript y sustituimos el método sndReq que es el que llama el botón por esto:

function sndReq() {
$.get("Mensaje",function(xml){
$("div#mensaje").html($("mensaje",xml).text());
$("div#fecha").html($("fecha",xml).text());
});
}


Con esas pocas líneas se logra exactamente el mismo efecto que en el tutorial, sin estarse preocupando por como se inicializa el XMLHttpRequest en Internet Explorer o Mozilla ni nada de eso.

Creo que sí vale la pena jquery, definitivamente.

¿Qué es AJAX? + Tutorial Hola Mundo

¿Qué no es?
Quizá la mejor manera de entender que es AJAX es entender que NO es.

  • No es un lenguaje de programación.
  • No es una tecnología.
  • No es un framework ni una libería.

AJAX es la combinación de tecnologías ya existentes: HTML/XHTML, XML, DHTML, el objeto XmlHttpRequest y JavaScript, combinadas de una manera particular.

¿De qué se trata?
El objetivo básico y lo más importante es que permite refrescar una parte del documento HTML con datos obtenidos desde el servidor sin recargar el documento completo como en un submit tradicional.
Las ventajas son obvias, pero no todo es gratis, conlleva algunas complicaciones.


¿Cómo funciona?
Con una combinación de código del lado del cliente mediante DHTML + JavaScript, y del lado del servidor con cualquier lenguaje, para Java lo lógico es un Servlet. Idealmente la comunicación entre las dos capas se hace mediante XML, pero puede ser texto plano.

Del lado del cliente se llama a un elemento en el servidor que devuelva XML y se proporciona una función que procese el XML resultante de la llamada en cuanto ésta se complete. Procesar el XML significa obtener la data de éste y actualizar con la misma el DOM del documento HTML, o, más sencillo, modificar una parte del HTML con la data.

Tutorial “Hola Mundo”
Vamos a crear una página donde el usuario presione un botón y se escriba en la misma un mensaje que viene desde el servidor, pero que se refresque únicamente el div que contiene al mensaje y no la página completa, además del texto “Hola Mundo” vamos a ponerle la fecha actual de manera que se vea como va cambiando (al menos los segundos o minutos) con cada nuevo click al botón, y que no se refresca la página completa para que se vea el cambio.


Así que, en cualquier IDE (Esto lo hice con Websphere) creamos un nuevo proyecto web dinámico y creamos primero el Servlet (Con todo lo que implica), Mensaje.java, y en el doGet:

public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {

resp.setHeader("Cache-Control", "no-cache"); //HTTP1.1
resp.setHeader("Pragma", "no-cache"); //HTTP 1.0
resp.setDateHeader("Expires", 0);
resp.setContentType("text/xml;charset=utf-8");
ServletOutputStream out = resp.getOutputStream();
out.println("<?xml version=\"1.0\"?>");

out.println("<datos>");
out.println("<mensaje>Hola Mundo</mensaje>");
out.println("<fecha>");
out.println(new Date().toString());
out.println("</fecha>");
out.println("</datos>");
out.close();
}


Si probamos directamente el Servlet en algún servidor podemos observar como devuelve el XML puro.

Ahora vamos a la página, que no necesita ser un JSP, puede ser un HTML puro y así es completamente agnóstica de la tecnología del servidor, yo la llamé ajax.html:

Dentro de body colocamos:

Mensaje: <div id="mensaje"></div>
Fecha: <div id="fecha"></div>

Estas dos etiquetas div son la única parte del documento que se va a actualizar cuando la persona presione un botón que colocaremos en la página.

Ahora el JavaScript; Primeramente se inicializa el objeto XMLHttpRequest, como se hace de distintas formas según el browser del cliente conviene hacerlo en un método que se encargue de ver que explorador se está usando y nos devuelva el objeto creado, después lo colocamos en una variable global.

En teoría a partir de IE7 XMLHttpRequest es un objeto nativo en Internet Explorer, así que a menos que se quiera soportar IE6 bastará con hacer ro= new XMLHttpRequest();


function createRequestObject() {
var ro;

if (window.XMLHttpRequest){
ro= new XMLHttpRequest();}

else
//Internet Explorer 6
{if (window.ActiveXObject){
ro = new ActiveXObject("Microsoft.XMLHTTP");}

}
return ro;
}

var http = createRequestObject();


Después vamos a hacer el método que maneje la respuesta del servidor, es decir, que del XML resultante obtenga el mensaje y la fecha y actualice el contenido de ambos div.



function handleResponse() {
if(http.readyState == 4){

var response = http.responseXML;

document.getElementById("mensaje").innerHTML =
response.documentElement.getElementsByTagName('mensaje')[0].firstChild.data;

document.getElementById("fecha").innerHTML =
response.documentElement.getElementsByTagName('fecha')[0].firstChild.data;
}
}

Aquí hay una correspondencia uno a uno entre los tags XML mensaje y fecha y los div con id mensaje y fecha, por eso es tan sencillo, pero XML no es trivial, falta acá también el manejo de errores.

Y finalmente el método que llame al Servlet y obtenga el XML.



function sndReq() {
http.open('get','Mensaje');
http.onreadystatechange = handleResponse;
http.send(null);
}


El método open recibe una ruta a un recurso en el servidor, además del tipo de request. Asumiendo que “/Mensaje” es el url-pattern del Servlet en web.xml es eso lo que recibe el método open, además de el texto "get", que indica el tipo de request (Pusimos en el Servlet el código en doGet), después se asigna el método que va a manejar el XML resultante cuando el request termine, esto es lo que le da la primera A a AJAX (Asíncrono), ese request puede durar un milisegundo o 10 minutos, mientras tanto el usuario puede hacer en la página cualquier cosa, handleResponse se llama con cada cambio de estado del request, y cuando finalmente sea “4”, (completo) se actualizará el HTML.

Basta con llamar a sndReq desde un botón y probar todo en algún servidor, en mi caso Jboss.

<input type="button" onclick="sndReq()" value="Enviar" />

Al darle click al botón una y otra vez debe actualizarse la fecha sin que la página se refresque completa, además de aparecer “Hola Mundo” la primer vez.

Para pasarle parámetros al Servlet:

function sndReq(parametro) {
http.open('get','Mensaje?parametro=' + parametro);
http.onreadystatechange = handleResponse;
http.send(null);
}

Y se leen como parámetros "get" en el Servlet. Con Post, la cosa cambia un poco, pero creo que el ejemplo ilustra suficiente.

Y eso es todo, parece trivial, pero la A de asíncrono involucra muchas cosas, de igual forma el crear JavaScript que sea portable en varios browsers y ambientes no es tan secillo, así como manejar errores. Es por eso que nadie hace esto a mano, a menos que sea una cosa muy sencilla, se utilizan frameworks o librerías, como dojo, jquery, y para JSF, ajax4jsf, donde se obtiene el mismo efecto sin colocar una sola línea de JavaScript, es decir, actualizar únicamente alguno de los componentes de una página sin refrescarla toda. Podría implementarse con un par de outputTextBox con el mensaje y la fecha y que sea lo único que se actualice en la página al presionar el botón.

Voy a estar hablando mucho de ajax4jsf en adelante.

Este tutorial fue probado en IE7, Firefox 2.0 y K-Meleon.

CréditosEl código JavaScript está parcialmente basado en el tutorial AJAX en 30 segundos de Rasmus.

Wednesday, December 27, 2006

Crear componentes: fácil y divertido (3/3)

En el capítulo anterior...
Así que estamos creando un componente, en la primera entrega creamos la clase de la etiqueta, en la segunda, la clase del componente, falta crear el archivo tld y probarlo.

El archivo TLD
Es un XML que configura una librería de etiquetas, en nuestro caso tendrá una sola etiqueta... pero tiene sentido agrupar etiquetas similares (componentes similares) en una librería común.

Lo llamamos messagesDisplay.tld, y comienza así:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>0.01</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>enthea</short-name>
<uri>http://enthea.net/messagesdisplay</uri>
<description>Componente para mostrar Faces Messages</description>


Después vienen los tags, en nuestro caso, uno solo:

<tag>
<name>emessages</name>
<tag-class>net.enthea.faces.components.messages.MessagesDisplayTag</tag-class>

Sencillo, en nombre ponemos un texto con el que haremos referencia a la etiqueta en la página, y en tag-class ponemos el fully qualified name de la clase de la etiqueta.

Ahora se colocan todos los atributos, además de los 3 atributos que son propios de nuestro componente, coloqué id, rendered (por si mi interesa que los mensajes no se muestren nunca) y binding, que son 3 atributos comunes a todos los componentes Faces.

<attribute>
<name>binding</name>
<description>A value binding that points to a bean property</description>
</attribute>

<attribute>
<name>id</name>
<description>The client id of this component</description>
</attribute>

<attribute>
<name>rendered</name>
<description>Is this component rendered?</description>

</attribute>

<attribute>
<name>styleInfo</name>
<description>estilo del div para Severity info</description>
</attribute>

<attribute>

<name>styleWarning</name>
<description>
estilo del div para Severity warning</description>
</attribute>

<attribute>
<name>styleError</name>
<description>
estilo del div para SeverityErrort</description>
</attribute>

</tag>

Eso es todo, ahora hay que empaquetar todo en un Jar, y hay que tener cuidado de incluir el archivo tld en el mismo, después ese Jar lo colocamos en el classpath de nuestra aplicación web.


Uso del componente

Registramos el componente en faces-config.xml:

<component>
<component-type>net.enthea.faces.components.messages.MessagesDisplay</component-type>
<component-class>net.enthea.faces.components.messages.MessagesDisplayUIComp</component-class>
</component>

En component type ponemos un texto, que es el mismo que colocamos que devolviese el método de la clase de la etiqueta:

public String getComponentType(){
return "net.enthea.faces.components.messages.MessagesDisplay";}


Esto es lo que enlaza a la clase de la etiqueta con la clase del componente, de manera que una clase de etiqueta no está amarrada sin remedio a una única clase de componente, puede cambiarse declarativamente en faces-config.xml por otra clase de componente, obviamente si maneja los mismos atributos pero quizá implementa al componente de manera distinta.

Ahora es cuestión de colocar el componente en alguna página, basta declarar una importación al tld en la misma (usando el uri), yo uso Sun Studio Creator, que utiliza xhtml, de manera que la importación es algo así:

<jsp:root version="1.2" xmlns:enthea="http://enthea.net/messagesdisplay" ....>

En WebSphere o Rational, sería algo así:

<%@taglib uri="http://enthea.net/messagesdisplay" prefix="enthea"%>

Aquí es posible que WebSphere se queje de que no consigue la librería tld, a pesar de que el jar que la contiene junto con las clases de etiqueta y componente esté en el classpath, yo lo solucioné así: saqué del Jar el archivo tld y lo coloqué en la carpeta WEB-INF, después puse la siguiente entrada en web.xml:

<taglib>
<taglib-uri>http://enthea.net/messagesdisplay</taglib-uri>
<taglib-location>/WEB-INF/messagesDisplay.tld</taglib-location>
</taglib>

Y después de cerrarlo, abrirlo, construir el proyecto, etc. dejó de quejarse.

Ahora en una hoja de estilo vamos a crear 3 clases para las 3 severidades de los errores, aquí se puede poner cualquier cosa, y esta es la idea del componente, que pueda colocarse cualquier estilo a cualquier severidad según la aplicación donde se vaya a usar, yo por ejemplo estoy utilizando esta para los mensajes informativos, y para los mensajes de error cambio el color de fondo, la imagen y el color de los bordes llamando a la clase severityError:

.severityInfo
{
background-color: #CEE6FE;
background-image: url(info.png);
background-position: left center;

background-repeat: no-repeat;
border-bottom-color: #0066cc;
border-bottom-style: dashed;
border-bottom-width: 2px;
border-left-color: #0066cc;
border-left-style: dashed;

border-left-width: 2px;
border-right-color: #0066cc;
border-right-style: dashed;
border-right-width: 2px;
border-top-color: #0066cc;
border-top-style: dashed;
border-top-width: 2px;
font-family: Geneva,Arial,Helvetica,sans-serif;
font-size: 12px;
font-style: normal;
font-weight: bold;
height: 30px;
margin-left: 3px;
margin-right: 3px;
margin-top: 3px;
padding-bottom: 3px;
padding-left: 3px;
padding-right: 3px;
padding-top: 3px;
text-align: center;
vertical-align: middle;
width: 70%
}


Y el componente en la página (el ide no va a soportar arrastrarlo al editor visual, hay que colocar el código a mano):

<enthea:emessages id="alerts" styleError="severityError" styleInfo="severityInfo" styleWarning="severityWarning"/>

Obviamente para que funcione severityError, severityInfo y severityWarning son clases CSS que están en una hoja de estilo enlazada con la página.

Para probar todo el asunto, bastará colocar en algún método de cualquier Backing Bean FacesMessages dentro del FacesContext con las 3 severidades, el constructor de FacesMessage recibe la severidad.

Resumen
Así que, todo funciona más o menos así, el duende Faces se consigue en la página una etiqueta
enthea:emessages, el prefijo enthea se refiere al uri http://enthea.net/messagesdisplay según la declaración de la página, y ese uri corresponde al archivo messagesDisplay.tld, efecitvamente en este archivo hay una declaración para el tag emessages, y se declaran todos los atributos que el desarrollador llenó en la etiqueta, además se indica que la clase de la etiqueta es
net.enthea.faces.components.messages.MessagesDisplayTag, en esta clase se obtienen los valores asociados a los atributos (bien sean literales o a través de E.L.) y se colocan en el mapa de atributos del componente, pero ¿Cuál Componente?, pues esta clase devuelve como componentType el String net.enthea.faces.components.messages.MessagesDisplay, que se asoció en faces-config.xml con la clase net.enthea.faces.components.messages.MessagesDisplayUIComp, que es donde se sacan del mapa los atributos y se pinta con éstos html en la página.

No es tan complicado, y si lo es ojalá esta imagen ayude a aclararlo:

Saturday, December 23, 2006

Crear componentes: fácil y divertido (2/3)

En el capítulo anterior...
Continuando con la creación de un componente, en la entrada anterior creamos la clase de la etiqueta, donde vimos que se colocan como atributos de la clase los atributos propios de nuestro componente, y se implementan varios métodos, entre estos el más importante es el de setProperties, donde recibimos a la clase del componente y le seteamos los atributos en su mapa, es el momento de hacer dicha clase.

Clase del Componente
En el mismo paquete de la clase de la etiqueta creemos otra clase:

public class MessagesDisplayUIComp extends UIComponentBase

Un poco de teoría... UIComponentBase implementa con un comportamiento por defecto para todos los componentes la clase abstracta UIComponent, es decir, la clase de los componentes, vamos a sobreescribir 2 de sus métodos, los que que van a diferenciar este componente de todos los demás, y es justamente donde se escribe el html!, el primero es encodeBegin:


public void encodeBegin(FacesContext context) throws IOException {


ResponseWriter writer = context.getResponseWriter();


String styleInfo=(String)getAttributes().get("styleInfo");


String styleWarning=(String)getAttributes().get("styleWarning");


String styleError=(String) getAttributes().get("styleError");


Primero que nada preparamos el writer donde vamos a escribir, y después sacamos del mapa de atributos nuestras 3 variables para colocarlas en 3 variables temporales, se sacan usando el mismo key con el que fueron introducidas en la clase de la etiqueta, por eso ayuda que este key sea idéntico al nombre de la variable.

Ahora vamos a obtener todos los FacesMessages globales (es decir, que no están asociados a un componente, de manera que si estamos en una página donde existan mensajes de validación asociados al componente no aparezcan tanto en nuestro componente como al lado de cada uno de los campos de entrada)

Iterator i = FacesContext.getCurrentInstance().getMessages(null);


Al pasarle null a este método nos da los mensajes globales.

Si no existe ningún mensaje en la lista queremos que el componente pinte simplemente una etiqueta <br/>

if (!i.hasNext()) {

writer.startElement("br", this);

writer.endElement("br");}

Creo que el código es bastante obvio y no necesita explicación, ahora simplemente vamos a iterar sobre los mensajes para mostrarlos a cada uno encerrado dentro de una etiqueta div que tenga como clase de hoja de estilo la que le corresponde según la severidad del menssaje:

while (i.hasNext()) {
FacesMessage message = (FacesMessage) i.next();
writer.startElement("div", this);
if (message.getSeverity().equals(FacesMessage.SEVERITY_INFO)) {
writer.writeAttribute("class", styleInfo, null);}


else if (message.getSeverity().equals(FacesMessage.SEVERITY_WARN)) {


writer.writeAttribute("class", styleWarning, null);}


else {writer.writeAttribute("class", styleError, null);}


writer.writeText(message.getSummary(), null);


writer.endElement("div");}


Básicamente este ejemplo ilustró como se escriben etiquetas html (div) y además atributos de estas etiquetas (el atributo class del div). Acá está el API

En encodeBegin es donde pasa lo importante, es el alma de cada componente, aquí es donde usamos el writer para escribir html con los datos que nos colocaron en la etiqueta desde el jsp, y que la clase de la etiqueta obtuvo de los Backing Beans si el valor se especificó como E.L.

En nuestro componente, por cada mensaje se colocará en el html final un div con la clase correspondiente a su severidad indicada desde la etiqueta.

Falta sobreescribir otro método:

public String getFamily() {
return "MessagesDisplayFamily";}


Esto de la familia del componente se usa cuando se va a hacer un Renderer propio, la verdad no pinta nada en nuestro ejemplo.

Ahora una pequeña advertencia, para componentes compuestos, es decir, que anidan a otros componentes (por ejemplo un DataTable que anida Columns) la cuestión es ligeramente diferente, a grandes rasgos en encodeBegin se coloca el html que va antes de los hijos (por ejemplo el encabezado de una tabla) y después existe un método encodeEnd donde se escribe el html que va al final del componente, es decir, después de todo el html de los hijos, pero como dije a grandes rasgos, para hacer cosas más complejas es mejor revisar el Api.

Próximas atracciones...
Lo único que falta ahora es crear el archivo tld donde definimos la librería a la que pertenece este componente y ver como podemos usarlo en nuestas páginas, pero eso forma parte de la próxima entrega.

Friday, December 22, 2006

Crear componentes: fácil y divertido (1/3)

¿Qué es un componente?
Es esencialmente una etiqueta que genera dinámicamente html obteniendo data desde un backing bean a través de E.L., por lo tanto el primer paso para crear un componente es crear el html que queremos como resultado y trabajar con esa referencia.

HTML resultado
Supongamos que queremos un componente que muestre los Faces Messages globales en la página, pero que según la severidad del Faces Message le asigne un estilo CSS distinto, de manera que los Info se vean en azul, y los errores en rojo, por ejemplo, esto lo logramos a través de un div:

<div class="estilo">¡Aquí va el mensaje!<div>

El html es bastante simple, la parte dinámica es el mensaje como tal y el estilo, que cambiará según la severidad del mensaje, el componente debería usarse así en la página:

<enthea:emessages id="alerts" styleError="severityError"
styleInfo="severityInfo" styleWarning="severityWarning"/>

Donde le especificamos distintas clases CSS según la severidad del mensaje que se vaya a mostrar en ese momento.

Así que decidimos que el compoennte se llama "emessages" y tiene 3 atributos, las 3 clases de estilo según los 3 niveles de severidad de los mensajes, también tiene id, pero este lo hereda, junto con rendered, y otros atributos que son propios a todos los componentes.

La Clase de la Etiqueta
En cualquier IDE, (yo lo hice en eclipse) hacemos un simple proyecto Java, y creamos inicalmente una clase llamada MessagesDisplayTag, importamos los jars jsf-impl, jsf-api, y alguno donde tengamos una implementación de Servlets.

La clase MessagesDisplayTag es la clase de la etiqueta y extiende UIComponentTag:

public class MessagesDisplayTag extends UIComponentTag

Ahora se colocan como atributos de la clase los atributos que queremos que tenga el componente:

private String styleInfo = null;
private String styleWarning = null;
private String styleError = null;


Creamos además los métodos "get" de estos atributos (no los sets).

Al extender de UIComponentTag hay que implementar una serie de métodos:

public String getComponentType(){
return "net.enthea.faces.components.messages.MessagesDisplay";}

public String getRendererType(){
return null;}

Escogemos un nombre para el tipo de nuestro componente y lo devolvemos en getContetType, es bueno acordarse de ese valor porque se usa en el faces-config.xml, en el rendererType podemos devolver nulo, no vamos a implementar renderers ni nada adicional.

Otro método que hay que implementar es setProperties(UIComponent component), que recibirá la clase del componente como tal (que aun no hemos creado) y le seteará los valores que el desarrollador colocó en la etiqueta para los 3 atributos:

protected void setProperties(UIComponent component) {
super.setProperties(component);

Primero llamamos al método setProperties de la clase padre para que le setee al componente todos los atributos comunes a todos los componentes, (id, rendered, etc...)

Los atributos del componente se setean en un mapa llamado Attributes, y de dos maneras, directamente si en la etiqueta se colocó un valor literal, o mediante un valueBinding si el atributo se especificó como una sentencia de E.L:

if (styleInfo != null) {
if (isValueReference(styleInfo)) {
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ValueBinding vb = app.createValueBinding(styleInfo);
component.setValueBinding("styleInfo", vb);
}else{
component.getAttributes().put("styleInfo", styleInfo);}

Y se repite el mismo código para los otros dos atributos dentro del método setProperties, cambiando styleInfo por StyleWarning y por StyleError aquí caben dos consideraciones, primero, como estamos colocando los atributos en un mapa podríamos poner cualquier String como key, yo le coloqué como key el mismo nombre del atributo para que sea más fácil, la segunda es acerca de como nos enseña sobre Faces el hacer componentes, una vez estaba probando un componente que recibía un url donde estuviese un feed RSS y mostraba todas las entradas del feed en una tabla, si ponía el url literal servía, pero no si lo hacía con E.L., un atributo de un componente no necesariamente puede ser asignado con E.L. a menos que el desarrollador del mismo se haya tomado la molestia de preguntar isValueReference en el método setProperties.

El último método que debemos implementar se llama release y coloca en null todos los atributos de la clase:

public void release() {
super.release();
styleInfo = null;
styleWarning = null;
styleError = null;
}

Ahora es el momento de crear la clase del componente, donde sacaremos del mapa de atributos los 3 valores que se llenaron en setProperties y crearemos el html, pero eso es en una próxima entrega.

Tuesday, December 19, 2006

Bonito Efecto sobre los input text (Meebo Style!)

Hace poco meebo cambió su front end, en particular me gustó el efecto que adquieren los input text cuando se les pone el foco, se resaltan y se cambia el color de fondo.

Esto no es más que caramelo visual, no veo que ayude mucho en cuanto a usabilidad, pero se ve bastante bien así que decidí replicarlo en una cuestión que estoy haciendo.

La implementación de meebo es bastante simple, cambian el estilo del componente en los eventos javascript onfocus, y onblur

<input style="border-width: 1px; margin: 1px; background-color: rgb(233, 240, 245);" onfocus="if (!ui.isSafari) { this.style.margin = '0'; this.style.borderWidth = '2px'; this.style.backgroundColor = '#FFFFFF'; }" onblur="this.style.margin = '1px'; this.style.borderWidth = '1px'; this.style.backgroundColor = '#E9F0F5';" size="16" id="aimpassword" tabindex="1" autocomplete="off" type="password">


Claro, ellos tienen pocos intputs y esa única vista, no me sirve para una aplicación donde tengo infinidad de inputs si tengo que colocar en cada uno los eventos de onfocus y onblur, como estaba jugando con jquery decidí ver que podía hacer al respecto.

El objetivo es básicamente que todos los inputs de mi página aquieran ese comportamiento sin que tenga que especificarlo para cada uno, posiblemente hay muchas opciones para esto, esta utiliza jquery:

Primero cree el estilo que quiero para el input cuando tenga el foco:

.foco{
background-color: #E9F0F5;
border-bottom-color: #000000;
border-bottom-style: dotted;
border-bottom-width: 2px;
border-left-color: #000000;
border-left-style: dotted;
border-left-width: 2px;
border-right-color: #000000;
border-right-style: dotted;
border-right-width: 2px;
border-top-color: #000000;
border-top-style: dotted;
border-top-width: 2px
}


No quedó muy bonito, igual lo pienso cambiar después.

Luego, bastaron pocas líneas de javascript con jquery:

$("input").focus(function(){$(this).addClass("foco");});

$("input").blur(function(){$(this).removeClass("foco");});


Y... eso es todo, tan sencillo como eso, jquery es realmente poderoso, este ejemplo se puede probar con el starter kit y el tutorial de jquery, el código va dentro de la función $(document).ready(function() {...}) y se puede probar con los input texts que trae el starter kit.

Funciona para componentes Faces outputText, porque éstos se transforman finalmente en input, pero cuidado, que también un checkbox es un input!

Monday, December 18, 2006

Esta entrada es para reinaugurar este blog.

Voy a hablar de los siguientes temas:
  • JavaServer Faces en general
  • Desarrollo de Componentes Faces personalizados
  • ajax4jsf
  • Ajax en general
  • jquery
Con dos fines. para que sirva como un archivo para mi mismo y por si a alguien le llega a ser de utilidad o tiene ideas mejores.

Bienvenidos todos.