<?xml version = "1.0" encoding = "ISO-8859-1"?> <!DOCTYPE editores SYSTEM "dtds/editores.dtd"> <editores> <editor .../> ... </editores>Simplemente contiene la definición de un conjunto de editores, y un editor se define así:
<editor nombre="nombre" <!-- 1 Nuevo en v2.1.3 --> url="url" <!-- 2 --> formatear="true|false" <!-- 3 --> depende-de-estereotipos="estereotipos" <!-- 4 --> depende-de-propiedades="propiedades" <!-- 5 --> enmarcable="true|false" <!-- 6 --> recargar-siempre="true|false" <!-- 7 Nuevo en v3.1.2 --> compuesto="true|false" <!-- 8 Nuevo en v3.1.3 --> icono="icono" <!-- 9 Nuevo en v5.7 --> accion-iniciar="Controlador.accion" <!-- 10 Nuevo en v5.7 --> accion-liberar="Controlador.accion" <!-- 11 Nuevo en v5.7 --> elementos-seleccionables="true|false" <!-- 12 Nuevo en v5.7 -->
formato-etiqueta-defecto="normal|pequena|sin-etiqueta" <!-- 13 Nuevo en v7.4 -->
> <propiedad ... /> ... <!-- 14 --> <formateador ... /> <!-- 15 --> <formateador-lista ... /> <!-- 16 Nuevo en v3.1.4 --> <para-estereotipo ... /> ... <!-- 17 -->
<para-anotacion ... /> ... <!-- 18 Nuevo en v6.6 -->
<para-tipo ... /> ... <!-- 19 --> <para-propiedad-modelo ... /> ... <!-- 20 --> <para-referencia ... /> ... <!-- 21 Nuevo en v3.1.3 --> <para-coleccion ... /> ... <!-- 22 Nuevo en v3.1.3 --> <para-tab ... /> ... <!-- 23 Nuevo en v4.6 --> <para-valores-posibles /> <!-- 24 Nuevo en v2.1.2 --> <para-referencias /> <!-- 25 Nuevo en v3.1.3 --> <para-colecciones /> <!-- 26 Nuevo en v3.1.3 --> <para-colecciones-elementos /> <!-- 27 Nuevo en v5.0 --> <para-tabs /> <!-- 28 Nuevo en v4.6 --> </editor>
<editor url="textEditor.jsp"> <for-type type="java.lang.String"/> <for-type type="java.math.BigDecimal"/> <for-type type="int"/> <for-type type="java.lang.Integer"/> <for-type type="long"/> <for-type type="java.lang.Long"/> </editor>Aquí asignamos a un grupo de tipos básicos el editor textEditor.jsp (podemos encontrarlo en openxava/src/main/resources/META-INF/resources/xava/editors). El código JSP de este editor es:
<%@ page import="org.openxava.model.meta.MetaProperty" %> <% String propertyKey = request.getParameter("propertyKey"); // 1 MetaProperty p = (MetaProperty) request.getAttribute(propertyKey); // 2 String fvalue = (String) request.getAttribute(propertyKey + ".fvalue"); // 3 String align = p.isNumber()?"right":"left"; // 4 boolean editable="true".equals(request.getParameter("editable")); // 5 String disabled=editable?"":"disabled"; // 5 String script = request.getParameter("script"); // 6 Ignorado desde v7.2, por lo que ya no es necesario boolean label = org.openxava.util.XavaPreferences.getInstance().isReadOnlyAsLabel(); if (editable || !label) { // 5 %> <input id="<%=propertyKey%>" name="<%=propertyKey%>" class=editor <!-- 1 --> type="text" tabindex="1" <!-- 7 --> title="<%=p.getDescription(request)%>" align='<%=align%>' <!-- 4 --> maxlength="<%=p.getSize()%>" size="<%=p.getSize()%>" value="<%=fvalue%>" <!-- 3 --> <%=disabled%> <!-- 5 --> <%=script%> <!-- 6 Ignorado desde v7.2 --> /> <% } else { %> <%=fvalue%> <% } %> <% if (!editable) { %> <input type="hidden" name="<%=propertyKey%>" value="<%=fvalue%>"> <% } %>Un editor JSP recibe un conjunto de parámetros y tiene accesos a atributos que le permiten configurarse adecuadamente para encajar bien en una vista OpenXava. En primer lugar vemos como cogemos propertyKey (1) que después usaremos como id HTML. A partir de ese id podemos acceder a la MetaProperty (2) (que contiene toda la meta información de la propiedad a editar). El atributo fvalue(3) contiene el valor ya formateado y listo para visualizar. Averiguamos también la alineación (4) y si es o no editable (5). También recibimos el trozo de script de javascript (6) que hemos de poner en el editor (a partir de v7.2 no tienes que especificar script, es ignorado).
<editor url="textEditor.jsp"> <formatedor clase="org.openxava.formatters.UpperCaseFormatter"/> <para-tipo tipo="java.lang.String"/> </editor>Estaremos sobreescribiendo el comportamiento de OpenXava para las propiedades de tipo String, ahora todas las cadenas se visualizaran y aceptaran en mayúsculas. Podemos ver el código del formateador:
package org.openxava.formatters; import javax.servlet.http.*; /** * @author Javier Paniza */ public class UpperCaseFormatter implements IFormatter { // 1 public String format(HttpServletRequest request, Object string) { // 2 return string==null?"":string.toString().toUpperCase(); } public Object parse(HttpServletRequest request, String string) { // 3 return string==null?"":string.toString().toUpperCase(); } }Un formateador ha de implementar IFormatter (1) o IMetaPropertyFormatter (nuevo en v5.9) lo que lo obliga a tener un método format() (2) que convierte el valor de la propiedad que puede ser un objeto Java cualquiera en una cadena para ser visualizada en un documento HTML; y un método parse() (3) que convierte la cadena recibida de un submit del formulario HTML en un objeto Java listo para asignar a la propiedad.
@Stereotype("REGIONES") private String [] regiones;Entonces podemos añadir una entrada en el archivo tipo-estereotipo-defecto.xml como sigue:
<para estereotipo="REGIONES" tipo="String []"/>
Y definir nuestro editor en el editores.xml de nuestro proyecto:<editor url="editorRegiones.jsp"> <!-- 1 --> <propiedad nombre="cantidadRegiones" valor="3"/> <!-- 2 --> <formateador clase="org.openxava.formatters.MultipleValuesByPassFormatter"/> <!-- 3 --> <para-estereotipo estereotipo="REGIONES"/> </editor>editorRegiones.jsp (1) es el archivo JSP que dibuja nuestro editor. Podemos definir propiedades que serán enviada al JSP como parámetros del request (2). El formateador tiene que implementar IMultipleValuesFormatter, que es similar a IFormatter pero usa String [] en vez de String. En este caso usamos un formateador genérico que simplemente deja pasar el dato.
<%@ page import="java.util.Collection" %> <%@ page import="java.util.Collections" %> <%@ page import="java.util.Arrays" %> <%@ page import="org.openxava.util.Labels" %> <jsp:useBean id="style" class="org.openxava.web.style.Style" scope="request"/> <% String propertyKey = request.getParameter("propertyKey"); String [] fvalues = (String []) request.getAttribute(propertyKey + ".fvalue"); // (1) boolean editable="true".equals(request.getParameter("editable")); String disabled=editable?"":"disabled"; String script = request.getParameter("script"); // Ignorado desde v7.2, ya no es necesario boolean label = org.openxava.util.XavaPreferences.getInstance().isReadOnlyAsLabel(); if (editable || !label) { String sregionsCount = request.getParameter("cantidadRegiones"); int regionsCount = sregionsCount == null?5:Integer.parseInt(sregionsCount); Collection regions = fvalues==null?Collections.EMPTY_LIST:Arrays.asList(fvalues); %> <select id="<%=propertyKey%>" name="<%=propertyKey%>" multiple="multiple" class=<%=style.getEditor()%> <%=disabled%> <%=script%>> <!-- No se usa desde v7.2 --> <% for (int i=1; i<regionsCount+1; i++) { String selected = regions.contains(Integer.toString(i))?"selected":""; %> <option value="<%=i%>" <%=selected%>> <%=Labels.get("regions." + i, request.getLocale())%> </option> <% } %> </select> <% } else { for (int i=0; i<fvalues.length; i++) { %> <%=Labels.get("regions." + fvalues[i], request.getLocale())%> <% } } %> <% if (!editable) { for (int i=0; i<fvalues.length; i++) { %> <input type="hidden" name="<%=propertyKey%>" value="<%=fvalues[i]%>"> <% } } %>Como se puede ver es como definir un editor para un valor simple, la principal diferencia es que el valor formateado (1) es un array de cadenas (String []) y no una cadena simple (String).
<%@ page import="java.util.Collection" %> <%@ page import="java.util.Collections" %> <%@ page import="java.util.Arrays" %> <%@ page import="org.openxava.util.Labels" %> <jsp:useBean id="style" class="org.openxava.web.style.Style" scope="request"/> <% String propertyKey = request.getParameter("propertyKey"); String [] fvalues = (String []) request.getAttribute(propertyKey + ".fvalue"); boolean editable="true".equals(request.getParameter("editable")); String disabled=editable?"":"disabled"; String script = request.getParameter("script"); // Ignorado desde v7.2, ya no es necesario boolean label = org.openxava.util.XavaPreferences.getInstance().isReadOnlyAsLabel(); if (editable || !label) { String sregionsCount = request.getParameter("cantidadRegiones"); int regionsCount = sregionsCount == null?5:Integer.parseInt(sregionsCount); Collection regions = fvalues==null?Collections.EMPTY_LIST:Arrays.asList(fvalues); for (int i=1; i<regionsCount+1; i++) { String checked = regions.contains(Integer.toString(i))?"checked":""; %> <input name="<%=propertyKey%>" type="checkbox" class="<%=style.getEditor()%>" tabindex="1" value="<%=i%>" <%=checked%> <%=disabled%> <%=script%> <!-- No se usa desde v7.2 --> /> <%=Labels.get("regions." + i, request.getLocale())%> <% } } else { for (int i=0; i<fvalues.length; i++) { %> <%=Labels.get("regions." + fvalues[i], request.getLocale())%> <% } } %> <% if (!editable) { for (int i=0; i<fvalues.length; i++) { %> <input type="hidden" name="<%=propertyKey%>" value="<%=fvalues[i]%>"> <% } } %>
<editor url="colorEditor.jsp"> <para-referencia modelo="Color"/> </editor>Con este código estamos diciendo que cualquier referencia a la entidad Color se tiene que visualizar usando colorEditor.jsp (para usar un editor solo para una referencia concreta en una entidad concreta véase la sección Escoger un editor del capítulo sobre Vista).
<%@page import="java.util.Iterator"%>
<%@page import="org.openxava.test.model.Color"%>
<%
String propertyKey = request.getParameter("propertyKey"); // Id de la propiedad clave de la referencia (1)
Object value = request.getAttribute(propertyKey + ".value"); // Podemos usar propertyKey + ".value" (2)
if (value == null) value = new Integer(0);
%>
<%
Iterator it = Color.findAll().iterator();
for (int c=0; it.hasNext() && c < 3; c++) {
Color color = (Color) it.next();
String checked = value.equals(color.getNumber())?"checked='checked'":"";
%>
<input name="<%=propertyKey%>" value="<%=color.getNumber()%>" type="radio" <%=checked%> <!-- (3) -->
tabindex="1"/>
<span>
<font color="#<%=color.getHexValue()%>"><b><%=color.getName()%></b></font>
</span>
<%
}
%>
<editor nombre="MiReferencia" url="miReferenciaEditor.jsp" enmarcable="true" compuesto="true"> <para-referencias/> </editor>Ya que hemos marcado el editor con <para-referencias/> ahora todas las referencias de nuestra aplicación se visualizarán usando nuestro miReferenciaEditor.jsp. Esta es una forma sencilla de personalizar el comportamiento del generador de interfaz de usuario de OpenXava.
<editor url="comentariosBlogEditor.jsp"> <para-coleccion modelo="ComentarioBlog"/> </editor>Con el código de arriba estamos diciendo que cualquier colección de entidades ComentarioBlog tiene que ser visualizada y editada usando comentariosBlogEditor.jsp (para usar un editor solo para una colección concreta en una entidad concreta ver la sección Escoger un editor en el capítulo sobre Vista).
<jsp:include page="collectionEditor.jsp"> <jsp:param name="listEditor" value="comentariosBlogListEditor.jsp"/> </jsp:include>Esta es una forma habitual de crear un editor para colecciones. Aquí llamamos a collectionEditor.jsp (el editor por defecto de OpenXava para colecciones) enviando como argumento para listEditor un JSP que contiene el editor para parte de la lista. De esta forma tenemos gratis todas las acciones y comportamiento por defecto de las colecciones, por tanto solo hemos de preocuparnos por dibujar la lista.
<%@ include file="../imports.jsp"%> <%@page import="org.openxava.view.View"%> <%@page import="org.openxava.model.MapFacade"%> <%@page import="org.openxava.test.model.Blog"%> <%@page import="org.openxava.test.model.BlogComment"%> <%@page import="java.util.Iterator"%> <%@page import="java.util.Map"%> <%@page import="java.text.DateFormat"%> <%@page import="org.openxava.util.Locales"%> <%@page import="org.openxava.util.Is"%> <jsp:useBean id="context" class="org.openxava.controller.ModuleContext" scope="session"/> <% String viewObject = request.getParameter("viewObject"); // Id para acceder al objeto view de la colección View collectionView = (View) context.get(request, viewObject); // Obtenemos el objeto view de la colección mediante context View rootView = collectionView.getRoot(); // En este caso usamos la vista raiz, la vista de Blog Map key = rootView.getKeyValues(); if (Is.empty(key)) { %> No hay comentarios <% } else { // Si la clave tiene valor dibujamos la colección de comentarios Blog blog = (Blog) MapFacade.findEntity("Blog", key); String action = request.getParameter("rowAction"); // rowAction es la acción para editar o visualizar cada elemento String actionArgv = ",viewObject=" + viewObject; %> Estos son los comentarios<br/> <% DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locales.getCurrent()); int f=0; for (Iterator it = blog.getComentarios().iterator(); it.hasNext(); f++) { ComentarioBlog comentario = (ComentarioBlog) it.next(); %> <i><b><big>Comentario del <%=df.format(comentario.getFecha())%></big></b></i> <xava:action action='<%=action%>' argv='<%="row=" + f + actionArgv%>'/> <p> <i><%=comentario.getCuerpo()%></i> </p> <hr/> <% } } %>Este editor dibuja los comentarios del blog como un texto simple con una cabecera con la fecha.
<%@page import="org.openxava.view.View"%> <%@page import="org.openxava.model.MapFacade"%> <%@page import="org.openxava.test.model.Carrier"%> <%@page import="java.util.Iterator"%> <jsp:useBean id="context" class="org.openxava.controller.ModuleContext" scope="session"/> <% String viewObject = request.getParameter("viewObject"); // viewObject es el id del objeto view del padre View view = (View) context.get(request, viewObject); // view es el objeto view de Transportista, el padre de la colección Transportista transportista = (Transportista) MapFacade.findEntity("Transportista", view.getKeyValues()); %> Los compañeros de <%=transportista.getNombre()%> son:<br> <ul> <% for (Iterator it = transportista.getCompaneros().iterator(); it.hasNext(); ) { Transportista companero = (Transportista) it.next(); %> <li><%=companero.getNombre()%></li> <% } %> </ul>En este caso escribimos el código para dibujar la colección completamente, si queremos tener algunas acciones para trabajar con la colección tenemos que ponerlas nosotros mismos. ¡Ojo!, porque aquí viewObject es la vista del objeto que contiene la colección, no de la colección en sí.
<editor nombre="MiColeccion" url="miColeccionEditor.jsp"> <para-colecciones/> </editor> <editor nombre="MiColeccionElementos" url="miColeccionElementosEditor.jsp"> <para-colecciones-elementos/> <!-- Nuevo en v5.0 --> </editor>Ahora todas las colecciones @OneToMany/@ManyToMany en nuestra aplicación se visualizan usando nuestro miColeccionEditor.jsp y las @ElementCollection usando nuestro miColeccionElementosEditor.jsp.
<editor url="empleadoCorporativoListEditor.jsp"> <para-tab modelo="EmpleadoCorporativo"/> </editor>Con el código de arriba estamos diciendo que todos los tabs (es decir todas la listas) para la entidad EmpleadoCorporativo tienen que ser editados y visualizados usando empleadoCorporativoListEditor.jsp (para usar un editor sólo para un tab concreto de una entidad ver la sección Escogiendo un editor).
<%@ include file="../imports.jsp"%> <jsp:useBean id="context" class="org.openxava.controller.ModuleContext" scope="session"/> <% String tabObject = request.getParameter("tabObject"); tabObject = (tabObject == null || tabObject.equals(""))?"xava_tab":tabObject; org.openxava.tab.Tab tab = (org.openxava.tab.Tab) context.get(request, tabObject); String condition = tab.getBaseCondition()==null?"":tab.getBaseCondition(); String all = condition.equals("")?"selected":""; String low = condition.contains("<=")?"selected":""; String high = condition.contains(">")?"selected":""; String action="openxava.executeAction('OpenXavaTest', 'EmpleadoCorporativo'," + "false, false, 'EmpleadoCorporativo.filtrar', 'segmento='+this.value)"; %> <select name="<xava:id name='escogerSegmento'/>" onchange= "<%=action%>"> <option value="all" <%=todos%>>Todos los empleados</option> <option value="low" <%=bajo%>>Empleados con salario bajo</option> <option value="high" <%=alto%>>Empleados con salario alto</option> </select> <jsp:include page="listEditor.jsp"/>Un detalle importante es que este editor incluye listEditor.jsp al final. listEditor.jsp es el editor por defecto para modo lista, por tanto en este caso simplemente estamos refinando la lista estándar añadiendo un combo para escoger un filtro personalizado. Sin embargo, podemos crear nuestro propio editor para lista desde cero, por ejemplo, el siguiente editor, fichasClienteListEditor.jsp, muestra la lista de clientes como una fila de fichas:
<%@ include file="../imports.jsp"%> <jsp:useBean id="context" class="org.openxava.controller.ModuleContext" scope="session"/> <% String collection = request.getParameter("collection"); String id = "list"; String collectionArgv = ""; String prefix = ""; String tabObject = request.getParameter("tabObject"); tabObject = (tabObject == null || tabObject.equals(""))?"xava_tab":tabObject; if (collection != null && !collection.equals("")) { id = collection; collectionArgv=",collection="+collection; prefix = tabObject + "_"; } org.openxava.tab.Tab tab = (org.openxava.tab.Tab) context.get(request, tabObject); org.openxava.tab.impl.IXTableModel model = tab.getTableModel(); for (int r=tab.getInitialIndex(); r<model.getRowCount() && r < tab.getFinalIndex(); r++) { %> <xava:link action="List.viewDetail"><div class="ficha-cliente"> <h4><%=model.getValueAt(r, 1)%>(<%=model.getValueAt(r, 0)%>)</h4> <%=model.getValueAt(r, 2)%><br/> <%=model.getValueAt(r, 3)%> (<%=model.getValueAt(r, 4)%>) </div></xava:link> <% } %>Para este editor usamos una clase CSS, ficha-cliente (el estilo en línea no está permitido desde v7.1), pon esta clase CSS en un archivo fichasClienteListEditor.css dentro de la carpeta src/main/webapp/xava/editors/style (web/xava/editors/style en v6 o anterior) de tu proyecto, puede que necesites crear la carpeta style la primera vez:
.ficha-cliente {
border: 2px solid rgb(130, 143, 149);
display: inline-block;
padding: 10px;
margin-bottom: 10px;
}
<editor nombre="MiLista" url="miListaEditor.jsp"> <para-tabs/> </editor>Como hemos marcado el editor con <for-tabs/> ahora todos los tabs de nuestra aplicación se visualizaran usando nuestro miListaEditor.jsp. Esta es una forma sencilla de personalizar el comportamiento del generador de interfaz gráfica de OpenXava.
<editor name="List" url="listEditor.jsp" icon="table-large"> <for-tabs/> </editor> <editor name="Charts" url="chartsEditor.jsp" selectable-items="false" icon="chart-line" init-action="Chart.init" release-action="Chart.release"> <for-tabs/> </editor>Y esto en editores.xml de tu proyecto:
<editor nombre="MiFicha" url="miFichaEditor.jsp" icono="view-module"> <para-tabs/> </editor>Tu usuario tendrá tres formatos para escoger en la lista:
<editor nombre="MiEditor" url="miEditor.jsp" icono="puzzle"> <para-tabs>
<tiene-tipo tipo="java.util.Date">
<tiene-tipo tipo="java.time.LocalDate">
<tiene-anotacion anotacion="DateTime">
<tiene-estereotipo estereotipo="FECHAHORA">
</para-tabs> </editor>
package com.tuempresa.facturacion.anotaciones;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface Colorido {
String color() default "black";
}
@Column(length=40) @Required
@Colorido(color = "green")
String nombre;
<editor nombre="Colorido" url="coloridoEditor.jsp">
<propiedad nombre="fondo" valor="yellow"/>
<para-anotacion anotacion="com.tuempresa.facturacion.anotaciones.Colorido"/>
</editor>
<%
String fondo = request.getParameter("fondo");
String color = request.getParameter("color");
%>
<span class="colorido-color-<%=color%> colorido-fondo-<%=background%>">
<jsp:include page="textEditor.jsp"/>
</span>
.colorido-color-black input { color: black; }
.colorido-fondo-black input { background: black; }
.colorido-color-white input{ color: white; }
.colorido-fondo-white input{ background: white; }
.colorido-color-red input{ color: red; }
.colorido-fondo-red input{ background: red; }
.colorido-color-green input{ color: green; }
.colorido-fondo-green input{ background: green; }
.colorido-color-blue input{ color: blue; }
.colorido-fondo-blue input{ background: blue; }
.colorido-color-yellow input{ color: yellow; }
.colorido-fondo-yellow input{ background: yellow; }
.colorido-color-orange input{ color: orange; }
.colorido-fondo-orange input{ background: orange; }
.colorido-color-purple input{ color: purple; }
.colorido-fondo-purple input{ background: purple; }
.colorido-color-gray input{ color: gray; }
.colorido-fondo-gray input{ background: gray; }
package com.tuempresa.facturacion.anotaciones;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface Colorido {
/**
* Lista de nombres de vistas separados por comas donde se aplica esta anotación. <p>
*
* Exclusivo con notForViews.<br>
* Si se omiten tanto forViews como notForViews, entonces esta anotación se aplica
* a todas las vistas.<br>
* Puedes usar la cadena "DEFAULT" para hacer referencia a la vista
* predeterminada (la vista sin nombre).
*/
String forViews() default "";
/**
* Lista de nombres de vistas separados por comas donde esta anotación no se aplica. <p>
*
* Exclusivo con forViews.<br>
* Si se omiten tanto forViews como notForViews, entonces esta anotación se aplica
* a todas las vistas.<br>
* Puedes usar la cadena "DEFAULT" para hacer referencia a la vista
* predeterminada (la vista sin nombre).
*/
String notForViews() default "";
String color() default "black";
}
@Column(length=40) @Required
@Colorido(forViews="Completa, Colorida", color = "green")
String nombre;
<input ... onclick="f()"/> <!-- NO PERMITIDO DESDE V7.1-->
En su lugar has de asociar los eventos desde el código en tus archivos JS. Para tu código JavaScript crea un archivo llamado miEditor.js (o cualquier otro nombre que quieras), y ponlo en la carpeta src/main/webapp/xava/editors/js (web/xava/editors/js en v6 o anteriores). openxava.addEditorInitFunction(function() { /* Aquí tu código de inicialización para tu editor. Es decir, las cosas que normalmente pondrías en el event onload de JavaScript o $(function() { ... }) de jQuery */ ... });Vemos como usamos openxava.addEditorInitFunction() para registrar una función de inicialización. El evento JavaScript onload o el evento ready() de jQuery no funciona, porque no se produce carga de página, en vez de eso el editor se genera en el servidor, se carga vía AJAX y se inserta en la página que ya se estaba visualizando.
openxava.addEditorDestroyFunction(function() { // Nuevo en v4.8.1 /* Aquí el código de destrucción de tu editor. Esto es para liberar los recursos obtenidos por el editor. */ ... });
A partir de v7.1 puedes definir una función a ejecutar antes de cada llamada AJAX de OpenXava, ponla en tu miEditor.js:
openxava.addEditorPreRequestFunction(function() { // Nuevo en v7.1 /* Aquí el código a ejecutar para tu editor antes de cada llamada AJAX de OpenXava. */ ... });
Por ejemplo, si quieres mostrar un diálogo de JavaScript con un mensaje cuando el usuario pulse en un botón de tu editor, y tienes este código en tu miEditor.jsp:
<input class="mi-editor" type="button" value="Di hola"/>
openxava.addEditorInitFunction(function() {
$(".mi-editor").click(function() {
alert("Hola");
});
});
@Stereotype("FAMILY") private int familyNumber; @Stereotype("SUBFAMILY") private int subfamilyNumber;Y en nuestro editores.xml ponemos:
<editor url="descriptionsEditor.jsp"> <!-- 10 --> <propiedad nombre="modelo" valor="Familia"/> <!-- 1 --> <propiedad nombre="propiedadClave" valor="codigo"/> <!-- 2 --> <propiedad nombre="propiedadDescripcion" valor="descripcion"/> <!-- 3 --> <propiedad nombre="ordenadoPorClave" valor="true"/> <!-- 4 --> <propiedad nombre="readOnlyAsLabel" valor="true"/> <!-- 5 --> <para-estereotipo estereotipo="FAMILIA"/> <!-- 11 --> </editor> <!-- Es posible especificar dependencias de estereotipos o propiedades --> <editor url="descriptionsEditor.jsp" <!-- 10 --> depende-de-estereotipos="FAMILIA"> <!-- 12 --> <!-- <editor url="descriptionsEditor.jsp" depende-de-propiedades="codigoFamilia"> <!-- 13 --> --> <propiedad nombre="modelo" valor="Subfamilia"/> <!-- 1 --> <propiedad nombre="propiedadClave" valor="codigo"/> <!-- 2 --> <propiedad nombre="propiedadesDescripcion" valor="codigo, descripcion"/> <!-- 3 --> <propiedad nombre="condicion" value="${codigoFamilia} = ?"/> <!-- 6 --> <propiedad nombre="estereotiposValoresParametros" valor="FAMILIA"/> <!-- 7 --> <!-- <propiedad nombre="propiedadesValoresParametros" valor="codigoFamilia"/> <!-- 8 --> --> <propiedad nombre="formateadorDescripciones" <!-- 9 --> valor="org.openxava.test.formatters.FormateadorDescripcionesFamilia"/> <para-estereotipo estereotipo="SUBFAMILIA"/> <!-- 11 --> </editor>Al visualizar una vista con estas dos propiedades codigoFamilia y codigoSubfamilia sacará un combo para cada una de ellas, el de familias con todas las familias disponible y el de subfamilias estará vacío y al escoger una familia se rellenará con sus subfamilias correspondientes.
<modulo nombre="ComercialJSP" carpeta="facturacion.variaciones"> <modelo nombre="Comercial"/> <vista nombre="ParaJSPPropio"/> <!-- 1 --> <vista-web url="jsp-propios/comercial.jsp"/> <!-- 2 --> <controlador nombre="Typical"/> </modulo>Si usamos vista-web (2) al definir el módulo, OpenXava usa nuestro JSP para dibujar el detalle, en vez de usar la vista generada automáticamente. Opcionalmente podemos definir una vista OpenXava con vista (1), esta vista es usada para saber que eventos lanzar y que propiedades llenar, si no se especifica se usa la vista por defecto de la entidad; aunque es aconsejable crear una vista OpenXava explícita para nuestra vista JSP, de esta manera podemos controlar los eventos, las propiedades a rellenar, el orden del foco, etc explicitamente. Podemos poner nuestro JSP dentro de la carpeta src/main/webapp/custom-jsp/jsp-propios (u otra de nuestra elección) de nuestro proyecto (web en lugar de src/main/webapp para versiones anteriores a v7.0), y este JSP puede ser así:
<%@ include file="../xava/imports.jsp"%> <table> <tr> <td>Código: </td> <td> <xava:editor property="codigo"/> </td> </tr> <tr> <td>Nombre: </td> <td> <xava:editor property="nombre"/> </td> </tr> <tr> <td>Nivel: </td> <td> <xava:editor property="nivel.id"/> <xava:editor property="nivel.descripcion"/> </td> </tr> </table>Somos libres de crear el archivo JSP como queramos, pero puede ser práctico usar las taglibs de OpenXava, en este caso, por ejemplo, se usa <xava:editor/>, esto dibuja un editor apto para la propiedad indicada, además añade el JavaScript necesario para lanzar los eventos. Si usamos <xava:editor/>, podemos manejar la información visualizada usando el objeto xava_view (del tipo org.openxava.view.View), por lo tanto todos los controladores estándar de OpenXava (CRUD incluido) funcionan.
<xava:editor property="nombrePropiedad" <!-- 1 --> editable="true|false" <!-- 2 Nuevo en v2.0.1 --> throwPropertyChanged="true|false" <!-- 3 Nuevo en v2.0.1 --> />
<xava:action action="controlador.accion" argv="argv"/>
El atributo action indica la acción a ejecutar, y el atributo argv (opcional) nos permite establecer valores a algunas propiedades de la acción antes de ejecutarla. Un ejemplo:<xava:action action="CRUD.save" argv="resetAfter=true"/>
Cuando el usuario pulse en la acción se ejecutará CRUD.save, antes pone a true la propiedad resetAfter de la acción.<xava:action action=""/>
En este caso la marca (tag) no tiene efecto y no se produce error. Esta característica puede ser útil cuando el nombre de la acción lo obtenemos dinámicamente (es decir action=”<%=micodigo()%>”), y el valor pueda estar vacío en ciertos casos.<xava:message key="clave_mensaje" param="parametroMensaje" intParam="paramMensaje"/>
El mensaje es buscado primero en los archivos de recursos de nuestro proyecto (miproyecto/src/main/resources/i18n/miproyecto-messages_es.properties para v7 o superior, y MiProyecto/i18n/MensajesMiProyecto.properties para v6 o anterior) y si no se encuentra ahí es buscado en los mensajes por defecto de OpenXava (openxava/src/main/resources/i18n/Messages_en.properties para v7 o superior, y OpenXava/i18n/Messages.properties para v6 o anterior).<xava:message key="cantidad_lista" intParam="<%=cantidadTotal%>"/>
<xava:label key="nombreMiembro"/>
El mensaje es buscado primero en los archivos de etiquetas de nuestro proyecto (miproyecto/src/main/resources/i18n/miproyecto-labels_es.properties para v7 o superior, y MiProyecto/i18n/EtiquetasMiProyecto.properties para v6 o anterior) y si no se encuentra ahí es buscado en los mensajes por defecto de OpenXava (openxava/src/main/resources/i18n/Labels_en.properties para v7 o superior, y OpenXava/i18n/Labels.properties para v6 o anterior).<tr> <td>Number: </td><td> <xava:editor property="number"/> </td> </tr>Puedes escribir esto:
<tr> <td><xava:label key="number"/>: </td><td> <xava:editor property="number"/> </td> </tr>Y así tener la etiqueta traducida.
<xava:descriptionsList reference="nombreReferencia" <!-- 1 -->
readOnlyAsLabel="true|false" <!-- 2 Nuevo en v6.0.1 -->
/>
<tr> <td>Nivel: </td> <td> <xava:descriptionsList reference="nivel"/> </td> </tr>En este caso nivel es una referencia al modelo actual (por ejemplo Comercial). Un combo es mostrado con todos los niveles disponibles.
<%@include file="../xava/imports.jsp"%>
...
<script type="text/javascript" <xava:nonce/>>
var button = document.getElementById('welcome_go_signin');
button.onclick = function () { window.location='m/SignIn'; }
</script>
Propiedad |
Descripción |
Valor por defecto |
Correo Electronico |
||
emailAsUserNameInPortal (quitado a partir de v7.0) | false |
|
smtpHost |
Servidor de correo SMTP |
|
smtpHostTrusted (nuevo en v4.7) |
Si es true se puede utilizar un servidor de correos SMTP con el certificado vencido |
false |
smtpPort |
Puerto para envio de correos |
|
smtpUserId |
Usuario para conectar al servidor SMTP |
|
smtpUserPassword |
Contraseña del usuario para servicios de correo |
|
smtpStartTLSEnable (nuevo en v5.6) |
Si es true activa el uso de la orden STARTTLS (si lo soporta el servidor) para cambiar la conexión a una conexión protegida con TLS antes de usar cualquier orden de identificación. |
false |
smtpFromEmail (nuevo en v6.2) |
Valor para el campo from del mensaje. Úsalo si necesitas un valor diferente para el id de usuario y para el campo from (útil en entornos del tipo AWS SES). |
El valor de smtpUserId |
Persistencia |
||
defaultPersistenceUnit |
Unidad de persistencia predeterminada |
default |
jpaCodeInPOJOs (quitado a partir de v5.6) |
Depends on persistence provider |
|
mapFacadeAsEJB |
false |
|
mapFacadeAutoCommit |
false |
|
persistenceProviderClass (quitado a partir de v5.6) |
Clase encargada de manejar la persistencia de datos |
org.openxava.model.impl.JPAPersistenceProvider |
Etiquetas, Mensajes y Localización |
||
i18nWarnings |
false |
|
portletLocales (quitado a partir de v7.0) | Si no se especifica se usan los locales incluidos en la carpeta i18n |
bg, ca, de, en, es, fr, in, it, ja, ko, nl, pl, pt, ru, sv, zh |
Aplicación y Controladores |
||
defaultLabelFormat |
Possibles values for defaultLabelFormat are: NORMAL, SMALL and NO_LABEL |
NORMAL |
defaultLabelStyle |
Se han definido: bold-label, italic-label, además de que puede definir sus propios estilos |
|
defaultModeController (nuevo en v4m5) |
Los valores posibles para defaultModeController son: Mode, DetailList, DetailOnly, ListOnly and SplitOnly |
Mode |
duplicateComponentWarnings |
Cuando se encuentran componentes con nombres duplicados se generan mensajes de advertencia |
true |
failOnAnnotationMisuse |
Lanza un error si algún miembro (propiedades, referencias o colecciones) tienen anotaciones que no les son aplicables |
true |
generateDefaultModules |
Si es true no es requerido definir los módulos en application.xml / applicacion.xml. OX se encarga de generarlos automaticamente |
true |
Estilos |
||
liferay6StyleClass (nuevo en v4m6, quitado a partir de v7.0) |
Estilo compatible con liferay 6 |
org.openxava.web.style.Liferay6Style |
liferay51StyleClass (quitado a partir de v7.0) | Estilo compatible con liferay 5.1 |
org.openxava.web.style.Liferay51Style |
liferay41StyleClass (quitado a partir de v7.0) | Estilo compatible con liferay 4.1 |
org.openxava.web.style.Liferay41Style |
liferay43StyleClass (quitado a partir de v7.0) | Estilo compatible con liferay 4.3 |
org.openxava.web.style.Liferay43Style |
webSpherePortal61StyleClass (quitado a partir de v7.0) | Estilo compatible WebSphere Portal 6.1 |
org.openxava.web.style.WebSpherePortal61Style |
styleClass |
Maneja la asignación de atributos class para los elementos desplegables. |
org.openxava.web.style.XavaStyle (desde v6.0) org.openxava.web.style.Liferay51Style (hasta v5.9.1) |
styleCSS |
URL del archivo CSS que provee las caracteristicas de la interfase visual. |
terra.css (desde v6.0) liferay51/css/everything_unpacked.css (hasta v5.9.1) |
themes (nuevo en v6.3) |
Lista de archivos CSS separados por coma de los estilos disponibles para ser elegidos como temas por el usuario. Si el valor está vacío el selector de temas no está disponible para el usuario. |
Vacío |
Vistas |
||
alignedByColumns (nuevo en v4.7.1) |
Si es true las propiedades de la vista son desplegadas alineadas por columnas. Sólo funciona en las implementaciones por defecto de layoutParser & layoutPainter. Provoca que las todas las vistas se comporten como si tuviesen # al inicio |
false |
buttonsForNoImageActions |
Si es true, cuando una acción no tiene imagen asociada muestra un botón. Si es false entonces muestra un hipervínculo |
false |
layoutParser (nuevo en v4.5, hasta v6.0.2) |
Nombre del interpretador de despliegue de vistas. Ha de implementar org.openxava.web.layout.ILayoutParser |
Hasta v5.4.1: org.openxava.web.layout.impl.DefaultLayoutParser A partir de v5.5: null (por tanto usa JSP) |
layoutPainter (nuevo en v4.5, hasta v6.0.2) |
Nombre de la clase encargada de dibujar las vistas. Ha de implementar org.openxava.web.layout.ILayoutPainter |
Hasta v5.4.1: org.openxava.web.layout.impl.DefaultLayoutPainter A partir de v5.5: null (por tanto usa JSP) |
maxSizeForTextEditor |
Limita el tamaño del campo de entrada para propiedades que representen textos largos |
100 |
messagesOnTop (nuevo en v4.5. hasta v5.7.1) |
Si es true los errores, advertencias y mensajes son mostrados en la parte superior de la página, si es false son mostrados al pie de la página. A partir de v5.8 se puede user CSS para poner los mensajes abajo. |
true |
readOnlyAsLabel |
false |
|
showIconForViewReadOnly (nuevo en v4.6) |
||
showLabelsForToolBarActions (nuevo en v4m6) |
Si es false, la barra de botones no despliega lo nombre de las acciones, sólo las imágenes |
true |
useIconsInsteadOfImages (nuevo en v5.4) |
Cuando se especifique un icono y una imagen para una acción, se usará el icono |
true |
flowLayout (nuevo en v5.7) |
Si es true la disposición de los campos se ajusta al tamaño de la página, ignorando los , ; # de @View |
false |
showDefaultActionInBottom (nuevo en v5.8) |
Si es true la acción por defecto aparece como la primera acción abajo, incluso si ya está en la barra de botones superior |
true |
Listas y Colecciones |
||
addColumnsPageRowCount (hasta v5.1.1) |
Limita el numero de propiedades seleccionables para ser adicionadas a las columnas de las listas o propiedades |
100 |
customizeList (nuevo en v4m5) |
Si es false, no se permite personalizar las columnas de la lista |
true |
detailOnBottomInCollections |
false |
|
ignoreAccentsForStringArgumentsInConditions (nuevo en v4m6) |
Si es true Ignora las acentuaciones en las condiciones de lista y colecciones |
false |
pageRowCount |
Default number of objects to show in lists and collections |
10 |
resizeColumns (nuevo en v4m5) |
Si es false, No se permite cambiar el tamaño de las columnas |
true hasta v5.9.1, false a partir de v6.0 |
saveAndStayForCollections (nuevo en v4m6) |
Si es false, el boton grabar y continuar no es mostrado cuando adicionan elementos a collecciones |
true |
showCountInList |
true |
|
showIconForViewReadOnly |
true |
|
showFilterByDefaultInList |
Si es true, la fila de filtrar se muestra inicialmente en las listas, El usuario siempre tiene la opción de mostrar / ocultar la fila de filtrado |
true |
showFilterByDefaultInCollections (quitada a partir de v6.0) |
Si es true, la fila de filtrar se muestra inicialmente en las colecciones, El usuario siempre tiene la opción de mostrar / ocultar la fila de filtrado |
true |
summationInList (nuevo en v4.3) |
Si es true Se muestra una fila de totales al final de la lista, bajo los campos numericos. El usuario puede manualmente encender o apagar los totales para cada columna |
true |
tabAsEJB |
false |
|
toUpperForStringArgumentsInConditions |
Si es true se convierten a mayusculas los argumentos de busqueda en las listas y colecciones. Aunque esto permite las busquedas de datos independientemente de que esten en mayusculas o minusculas, puede producir bajos rendimientos con algunos manejadores de base de datos |
true |
filterOnChange (nuevo en v4.8) |
El filtrado se realiza automáticamente al seleccionar una opción de un combo, sin pulsar en el botón de filtrar |
true |
Ayuda |
||
helpAvailable (nuevo en v5.6) |
Si es true un icono para acceder a la ayuda se muestra en el módulo |
false since v6.0, true until v5.9.1 |
helpInNewWindow (nuevo en v4m5) |
Si es true la página de ayuda se muestra en una nueva ventana, si es false, la página de ayuda es abierta en la ventana actual |
true |
helpPrefix (nuevo en v4m5) |
Prefijo para la generación del URL de ayuda |
|
helpSuffix (nuevo en v4m5) |
Sufijo para la generación del URL de ayuda |
|
Estereotipo FILE/ARCHIVO |
||
filePersistorClass |
Clase encargada de almacenar los archivos adjuntos |
org.openxava.web.editors.FileSystemPersistor |
filesPath |
Directorio de almacenamiento de los archivos, en caso no se use base de datos. |
|
Estereotipo COORDENADAS/COORDINATES (nuevo en v6.6) |
||
mapsTileProvider |
La URL del proveedor de imágenes de mapa (tile provider). Puedes usar un tile provider de OpenTopoMap (https://b.tile.opentopomap.org/{z}/{x}/{y}.png), MapBox (https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=YOUR_ACCESS_TOKEN), Stamen (http://tile.stamen.com/toner/{z}/{x}/{y}.png), OpenStreeMap (https://tile.openstreetmap.org/{z}/{x}/{y}.png) o Thunderforest (https://tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png?apikey=YOUR_API_KEY), entre otros. Te cuidado con cumplir con los términos de servicio del proveedor correspondiente. | https://b.tile.opentopomap.org/{z}/{x}/{y}.png |
mapsAttribution |
Texto de atribución a mostrar en una esquina del mapa. Depende del proveedor que uses. Asegurate de usar la atribución correcta. |
Map data © OpenStreetMap contributors, Imagery © OpenTopoMap (CC-BY-SA) |
mapsTileSize |
Ancho y alto de la imagen en la rejilla. |
256 |
mapsZoomOffset |
El número de zoom usado en la URL será ajustado según este valor. |
0 |
Reportes |
||
reportParametersProviderClass |
Clase para obtener los parametros para los informes. Tiene que implementar IReportParametersProvider o IRequestReportParametersProvider. |
org.openxava.util.DefaultReportParametersProvider |
Content Security Policy (CSP) |
||
trustedHostsForImages (nuevo en v7.1.2) |
Lista de sitios, separados por comas, que se pueden utilizar como origen para las imágenes. Se añade a img-src de la Política de Seguridad de Contenido (Content Security Policy, CSP). Puedes utilizar cualquier <host-source> como se explica en la documentación de CSP. |
|
trustedHostsForScripts (nuevo en v7.1.2) |
Lista de sitios, separados por comas, que se pueden utilizar como origen para los scripts. Se añade a script-src de la Política de Seguridad de Contenido (Content Security Policy, CSP). Puedes utilizar cualquier <host-source> como se explica en la documentación de CSP. | |
trustedHostsForStyles (nuevo en v7.1.2) |
Lista de sitios, separados por comas, que se pueden utilizar como origen para los archivos CSS. Se añade a style-src de la Política de Seguridad de Contenido (Content Security Policy, CSP). Puedes utilizar cualquier <host-source> como se explica en la documentación de CSP. | |
trustedHostsForFrames (nuevo en v7.1.2) |
Lista de sitios, separados por comas, que se pueden utilizar como origen para los frames e iframes. Se añade a frame-src de la Política de Seguridad de Contenido (Content Security Policy, CSP). Puedes utilizar cualquier <host-source> como se explica en la documentación de CSP. | |
unsafeEvalInScripts (nuevo en v7.3) | Si es true, los encabezados de la Content Security Policy se configuran para permitir el uso de eval() inseguro en el código JavaScript. Esto permitiría la ejecución de código malicioso en la página web de la aplicación, por lo que es recomendable reescribir tu código JavaScript para no usar eval() en lugar de poner esta propiedad a true. | false |
turnOffWebSecurity (nuevo en v7.2) | Si es true las cabeceras de Content Security Policy no se envían. Esto permitiría la ejecución de código malicioso en la página web de la aplicación, por eso es aconsejable utilizar las propiedades de arriba (las trustedHostForXXXX) antes de poner turnOffWebSecurity a true. | false |
Miscelánea |
||
csvEncoding (nuevo en v4.2.1) |
Porque es imposible obtener la codificación del cliente, que es usada por Excel al abrir el archivo. UTF-8, ISO-8859-1 |
|
csvSeparator |
; |
|
hibernateJavaLoggingLevel |
Nivel para la bitácora de Hibernate. Los valores pueden ser: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL, OFF |
INFO |
javaLoggingLevel |
Nivel para la bitácora de Java. Los valores válidos son: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL, OFF |
INFO |
componentParsersClasses (nuevo en v5.6) |
Lista de clases separadas por comas para analizar los componentes, tienen que implementar org.openxava.component.parse.IComponentParser |
org.openxava.component.parse.XMLComponentParser, org.openxava.component.parse.AnnotatedClassParser |
connectionRefinerClass (nuevo en v5.6) |
Clase para crear un org.openxava.util.IConnectionRefiner para refinar las conexiones JDBC justo después de obtenerlas de la fuente de datos y antes de usarlas. |
|
accessTrackerProvidersClasses (nuevo en v5.9) |
Lista de clases separadas por comas usadas para monitorear cada cambio o acceso de lectura hecho por los usuarios a los datos. Las clases tienen que implementar org.openxava.util.IAccessTrackerProvider. Ya hay algunos proveedores incluidos en OpenXava como org.openxava.util.EmailNotificationsAccessTrackerProvider y org.openxava.util.LogAccessTrackerProvider. |
|
enterMovesToNextField (nuevo en v6.4) |
Si true la tecla INTRO (ENTER) mueve el foco al siguiente campo, como la tecla TAB, en lugar de aceptar el formulario. |
false |
applicationPort (nuevo en v6.4.2) | El puerto usado por el lanzador de la aplicación (la clase _Run_TuAplicacion). | 8080 |
defaultDescriptionPropertiesValueForDescriptionsList (nuevo en v7.1) | Nombres de las propiedades a mostrar en el combo de un @DescriptionsList cuando el atributo descriptionProperties se omite. | descripcion, description, nombre, name |
currencySymbol (nuevo en v7.4) |
Permite definir el símbolo de dinero para toda la aplicación sin importar el idioma del servidor. |
Símbolo de moneda correspondiente al locale del servidor de aplicaciones |