xonecode 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -0
- package/dist/agent/authEnDisco.js +56 -0
- package/dist/agent/authEnDisco.js.map +1 -0
- package/dist/agent/configEnDisco.js +109 -0
- package/dist/agent/configEnDisco.js.map +1 -0
- package/dist/agent/crearProyecto.js +34 -0
- package/dist/agent/crearProyecto.js.map +1 -0
- package/dist/agent/entorno.js +124 -0
- package/dist/agent/entorno.js.map +1 -0
- package/dist/agent/guionizado.js +53 -0
- package/dist/agent/guionizado.js.map +1 -0
- package/dist/agent/instantanea.js +129 -0
- package/dist/agent/instantanea.js.map +1 -0
- package/dist/agent/interrupts.js +83 -0
- package/dist/agent/interrupts.js.map +1 -0
- package/dist/agent/mensajes.js +24 -0
- package/dist/agent/mensajes.js.map +1 -0
- package/dist/agent/modelos.js +42 -0
- package/dist/agent/modelos.js.map +1 -0
- package/dist/agent/normalizar.js +20 -0
- package/dist/agent/normalizar.js.map +1 -0
- package/dist/agent/perfiles.js +103 -0
- package/dist/agent/perfiles.js.map +1 -0
- package/dist/agent/proyecto.js +107 -0
- package/dist/agent/proyecto.js.map +1 -0
- package/dist/agent/puente.js +142 -0
- package/dist/agent/puente.js.map +1 -0
- package/dist/agent/resumenDeTool.js +48 -0
- package/dist/agent/resumenDeTool.js.map +1 -0
- package/dist/agent/skills.js +65 -0
- package/dist/agent/skills.js.map +1 -0
- package/dist/agent/textoDeTool.js +113 -0
- package/dist/agent/textoDeTool.js.map +1 -0
- package/dist/agent/turnoReal.js +173 -0
- package/dist/agent/turnoReal.js.map +1 -0
- package/dist/agent/verificador.js +65 -0
- package/dist/agent/verificador.js.map +1 -0
- package/dist/agent/xoneAgent.js +106 -0
- package/dist/agent/xoneAgent.js.map +1 -0
- package/dist/bin.js +9 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli/aprobar.js +82 -0
- package/dist/cli/aprobar.js.map +1 -0
- package/dist/cli/config.js +133 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/consola.js +346 -0
- package/dist/cli/consola.js.map +1 -0
- package/dist/cli/describe.js +53 -0
- package/dist/cli/describe.js.map +1 -0
- package/dist/cli/doctor.js +45 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/main.js +520 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/markdown.js +90 -0
- package/dist/cli/markdown.js.map +1 -0
- package/dist/cli/run.js +164 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/spinner.js +89 -0
- package/dist/cli/spinner.js.map +1 -0
- package/dist/cli/stdio.js +193 -0
- package/dist/cli/stdio.js.map +1 -0
- package/dist/cli/tema.js +40 -0
- package/dist/cli/tema.js.map +1 -0
- package/dist/cli/verify.js +62 -0
- package/dist/cli/verify.js.map +1 -0
- package/dist/core/bitacora.js +30 -0
- package/dist/core/bitacora.js.map +1 -0
- package/dist/core/config.js +236 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/contextos.js +56 -0
- package/dist/core/contextos.js.map +1 -0
- package/dist/core/deps.js +51 -0
- package/dist/core/deps.js.map +1 -0
- package/dist/core/diff.js +79 -0
- package/dist/core/diff.js.map +1 -0
- package/dist/core/esqueleto.js +366 -0
- package/dist/core/esqueleto.js.map +1 -0
- package/dist/core/events.js +2 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/modelos.js +85 -0
- package/dist/core/modelos.js.map +1 -0
- package/dist/core/notify.js +106 -0
- package/dist/core/notify.js.map +1 -0
- package/dist/core/ports.js +114 -0
- package/dist/core/ports.js.map +1 -0
- package/dist/core/turno.js +127 -0
- package/dist/core/turno.js.map +1 -0
- package/dist/vendor/hitl.js +103 -0
- package/dist/vendor/hitl.js.map +1 -0
- package/dist/vendor/skillLoaders/catalog.js +74 -0
- package/dist/vendor/skillLoaders/catalog.js.map +1 -0
- package/dist/vendor/tokenTracking.js +58 -0
- package/dist/vendor/tokenTracking.js.map +1 -0
- package/package.json +41 -0
- package/skills/xone-debugging/SKILL.md +52 -0
- package/skills/xone-debugging/references/faq.md +561 -0
- package/skills/xone-debugging/references/troubleshooting-y-glosario.md +429 -0
- package/skills/xone-development/SKILL.md +105 -0
- package/skills/xone-development/references/anti-patrones.md +94 -0
- package/skills/xone-development/references/css/atributos-por-categoria.md +509 -0
- package/skills/xone-development/references/css/buenas-practicas-y-parser.md +419 -0
- package/skills/xone-development/references/css/dinamicos-cascada-y-componentes.md +550 -0
- package/skills/xone-development/references/css/patrones-material-y-temas.md +1140 -0
- package/skills/xone-development/references/css/propiedades-y-herencia.md +885 -0
- package/skills/xone-development/references/css/selectores-unidades-colores.md +840 -0
- package/skills/xone-development/references/datos/appdata-referencia-ampliada.md +457 -0
- package/skills/xone-development/references/datos/appdata.md +611 -0
- package/skills/xone-development/references/datos/http-sqlmanager-y-crypto.md +720 -0
- package/skills/xone-development/references/datos/http.md +366 -0
- package/skills/xone-development/references/datos/oauth2-y-replica.md +156 -0
- package/skills/xone-development/references/device/biometria-imagedrawing-y-otros.md +544 -0
- package/skills/xone-development/references/device/objetos-de-dispositivo.md +583 -0
- package/skills/xone-development/references/device/systemsettings-referencia-ampliada.md +396 -0
- package/skills/xone-development/references/device/systemsettings-y-permisos.md +342 -0
- package/skills/xone-development/references/fundamentos/conceptos-clave.md +695 -0
- package/skills/xone-development/references/fundamentos/configuracion-app-xml-ini-mappings.md +668 -0
- package/skills/xone-development/references/fundamentos/errores-comunes.md +312 -0
- package/skills/xone-development/references/fundamentos/navegacion-convenciones-y-primer-proyecto.md +576 -0
- package/skills/xone-development/references/fundamentos/plataforma-y-anatomia-de-proyecto.md +387 -0
- package/skills/xone-development/references/indice-completo.md +77 -0
- package/skills/xone-development/references/javascript/coleccion-error-y-usuario.md +260 -0
- package/skills/xone-development/references/javascript/debugging-y-best-practices.md +245 -0
- package/skills/xone-development/references/javascript/metodos-de-los-controles.md +556 -0
- package/skills/xone-development/references/javascript/metodos-nativos-de-la-vista.md +114 -0
- package/skills/xone-development/references/javascript/motor-js-y-contexto-de-ejecucion.md +319 -0
- package/skills/xone-development/references/javascript/objeto-ai-llm-en-dispositivo.md +358 -0
- package/skills/xone-development/references/javascript/objetos-creables-a-m.md +527 -0
- package/skills/xone-development/references/javascript/objetos-creables-n-z.md +385 -0
- package/skills/xone-development/references/javascript/patrones-criticos-seguridad-y-rendimiento.md +595 -0
- package/skills/xone-development/references/javascript/patrones-de-navegacion-datos-y-codigo.md +751 -0
- package/skills/xone-development/references/javascript/patrones-de-ui-voz-integracion-y-seguridad.md +701 -0
- package/skills/xone-development/references/javascript/plantillas-y-funciones-utilitarias.md +647 -0
- package/skills/xone-development/references/javascript/self-y-dataobject.md +449 -0
- package/skills/xone-development/references/javascript/singletons-globales.md +361 -0
- package/skills/xone-development/references/javascript/ui-catalogo-de-metodos.md +464 -0
- package/skills/xone-development/references/javascript/ui-gps-camara-y-multimedia.md +506 -0
- package/skills/xone-development/references/javascript/ui-navegacion-mensajes-y-vista.md +422 -0
- package/skills/xone-development/references/resumen-js-datos-dispositivo.md +80 -0
- package/skills/xone-development/references/resumen-xml-y-css.md +74 -0
- package/skills/xone-development/references/tipos-de-prop.md +28 -0
- package/skills/xone-development/references/xml-ui/asfilter-visibilidad-eventos-y-macros.md +576 -0
- package/skills/xone-development/references/xml-ui/atributos-coll-group-frame.md +235 -0
- package/skills/xone-development/references/xml-ui/atributos-method-macro-script-event-app.md +244 -0
- package/skills/xone-development/references/xml-ui/atributos-prop.md +439 -0
- package/skills/xone-development/references/xml-ui/contents-y-macros.md +392 -0
- package/skills/xone-development/references/xml-ui/errores-comunes-xml.md +245 -0
- package/skills/xone-development/references/xml-ui/estructura-y-nodo-coll.md +326 -0
- package/skills/xone-development/references/xml-ui/eventos-ciclo-de-vida-e-interaccion.md +704 -0
- package/skills/xone-development/references/xml-ui/eventos-sistema-login-y-personalizados.md +944 -0
- package/skills/xone-development/references/xml-ui/layouts-herencia-y-buenas-practicas.md +618 -0
- package/skills/xone-development/references/xml-ui/mapas.md +685 -0
- package/skills/xone-development/references/xml-ui/mappings-y-colecciones-separadas.md +148 -0
- package/skills/xone-development/references/xml-ui/nodos-group-y-frame.md +666 -0
- package/skills/xone-development/references/xml-ui/patrones-de-pantalla.md +643 -0
- package/skills/xone-development/references/xml-ui/prop-atributos-y-condiciones.md +298 -0
- package/skills/xone-development/references/xml-ui/prop-tipos-basicos.md +493 -0
- package/skills/xone-development/references/xml-ui/prop-tipos-combos-y-controles.md +664 -0
- package/skills/xone-development/references/xml-ui/prop-tipos-listas-y-mapas.md +412 -0
- package/skills/xone-plan-builder/SKILL.md +183 -0
- package/skills/xone-plan-builder/agents/openai.yaml +5 -0
- package/skills/xone-plan-builder/references/TASKS-FORMAT.md +132 -0
- package/skills/xone-project-generator/SKILL.md +111 -0
- package/skills/xone-project-generator/references/canonical-sizes.md +292 -0
- package/skills/xone-project-generator/references/colecciones-base.md +16 -0
- package/skills/xone-project-generator/references/convenciones-de-nombres.md +16 -0
- package/skills/xone-project-generator/references/ejemplos-por-sector-y-prohibiciones.md +140 -0
- package/skills/xone-project-generator/references/fase-3-estilos-css.md +597 -0
- package/skills/xone-project-generator/references/fase-6-colecciones.md +762 -0
- package/skills/xone-project-generator/references/fase-7-asfilter-e-integraciones.md +142 -0
- package/skills/xone-project-generator/references/fase-7-entidades-y-estructura-de-pantalla.md +494 -0
- package/skills/xone-project-generator/references/fase-7-plantilla-consola.md +477 -0
- package/skills/xone-project-generator/references/fase-7-plantillas-de-pantalla.md +302 -0
- package/skills/xone-project-generator/references/fase-7-viewmodes-graficos-y-listas.md +681 -0
- package/skills/xone-project-generator/references/fase-7-viewmodes-mapa-y-calendario.md +479 -0
- package/skills/xone-project-generator/references/fases-0-2-analisis-y-modelo-de-datos.md +350 -0
- package/skills/xone-project-generator/references/fases-10-12-readmes-y-validacion.md +194 -0
- package/skills/xone-project-generator/references/fases-4-5-estructura-y-configuracion.md +587 -0
- package/skills/xone-project-generator/references/fases-8-9-eventos-y-javascript.md +861 -0
- package/skills/xone-project-generator/references/flujo-de-generacion.md +67 -0
- package/skills/xone-project-generator/references/plantillas-estandar.md +98 -0
- package/skills/xone-project-generator/references/tamanos-canonicos.md +49 -0
- package/skills/xone-review/SKILL.md +189 -0
- package/skills/xone-spec-builder/SKILL.md +235 -0
- package/skills/xone-spec-builder/agents/openai.yaml +5 -0
- package/skills/xone-spec-builder/references/ADR-FORMAT.md +55 -0
- package/skills/xone-spec-builder/references/CONTEXT-FORMAT.md +42 -0
- package/skills/xone-spec-builder/references/PLAN-FORMAT.md +120 -0
|
@@ -0,0 +1,762 @@
|
|
|
1
|
+
# Generación XOne — Fase 6: generación de colecciones
|
|
2
|
+
|
|
3
|
+
> Fuente: `xone/v2/xone-project-generator/references/xone-project-generation-workflow.md` §7. Referencia de la skill; el índice está en [../SKILL.md](../SKILL.md).
|
|
4
|
+
|
|
5
|
+
Contenido: §7 nomenclatura, cuándo usar el prefijo MAP_, plantillas de colección, atributos de coll y prop, herencia inherits e include-layout, contents, campos por tipo de dato, relaciones y modos de edición
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 7. Fase 6: Generación de Colecciones
|
|
10
|
+
|
|
11
|
+
### 6.1 Objetivo
|
|
12
|
+
|
|
13
|
+
Crear un archivo `.xne` independiente por cada coleccion adicional del proyecto (todas excepto Empresas y Usuarios que van en `mappings.xne`).
|
|
14
|
+
|
|
15
|
+
### 6.2 Nomenclatura y Convenciones
|
|
16
|
+
|
|
17
|
+
- Nombre del archivo: `[NombreColeccion].xne` (PascalCase)
|
|
18
|
+
- Nombre de la coleccion (`name`): Mismo nombre que el archivo sin extensión
|
|
19
|
+
- Ejemplo: `Productos.xne` contiene `<coll name="Productos" ...>`
|
|
20
|
+
|
|
21
|
+
**Convenciones de nomenclatura de campos (name del prop):**
|
|
22
|
+
|
|
23
|
+
| Prefijo | Cuando usarlo | Ejemplo |
|
|
24
|
+
|---------|---------------|---------|
|
|
25
|
+
| Sin prefijo | Campos propios de la tabla, se graban en BD | `NOMBRE`, `FECHA`, `ESTADO` |
|
|
26
|
+
| `MAP_` | Valor NO es columna de la tabla `objname` (JOIN, `linkedto`, o prop puramente visual: L/TL, B, calculado, UI-state). No se graba en BD | `MAP_NOMBRECLIENTE`, `MAP_TIPO_DESC`, `MAP_TITULO`, `MAP_BTN_GUARDAR`, `MAP_TOTAL` |
|
|
27
|
+
| `@` | Campos tipo `Z` (contents embebidos) | `@LineasPedido` |
|
|
28
|
+
| `$` | Campos calculados (formula) | `$IMPORTE_TOTAL` |
|
|
29
|
+
| `%` | Campos tipo NC usados como bitmask | `%OPCIONES` |
|
|
30
|
+
|
|
31
|
+
### 6.2b Cuando usar el prefijo `MAP_`
|
|
32
|
+
|
|
33
|
+
El prefijo `MAP_` es una **señal al framework** que dice: *"este prop NO es una columna de la tabla apuntada por `objname`, no intentes persistirlo"*. Cuando el framework genera los `INSERT`/`UPDATE`, **excluye automáticamente** todos los props con prefijo `MAP_`. Por eso, **`MAP_loquesea` no existe ni debe existir como columna en la base de datos**.
|
|
34
|
+
|
|
35
|
+
#### Regla de oro
|
|
36
|
+
|
|
37
|
+
> **Si el valor del prop NO proviene de una columna de la tabla de `objname`, su `name` debe empezar por `MAP_`.**
|
|
38
|
+
|
|
39
|
+
#### Los tres casos en los que se usa `MAP_`
|
|
40
|
+
|
|
41
|
+
**Caso 1 — Campos que vienen de un JOIN en el SQL de la coll**
|
|
42
|
+
|
|
43
|
+
El SQL hace `LEFT JOIN` a otra tabla y trae descripciones. Los alias llevan `MAP_`:
|
|
44
|
+
|
|
45
|
+
```xml
|
|
46
|
+
<coll name="Pedidos"
|
|
47
|
+
sql="SELECT t1.*,
|
|
48
|
+
c.NOMBRE AS MAP_NOMBRECLIENTE,
|
|
49
|
+
c.TELEFONO AS MAP_TELEFONOCLIENTE
|
|
50
|
+
FROM ##PREF##Pedidos t1
|
|
51
|
+
LEFT OUTER JOIN ##PREF##Clientes c ON t1.IDCLIENTE=c.ID"
|
|
52
|
+
objname="pedidos" updateobj="pedidos" ...>
|
|
53
|
+
<group name="General" id="1">
|
|
54
|
+
<!-- FK: SI es columna de Pedidos, sin MAP_ -->
|
|
55
|
+
<prop name="IDCLIENTE" type="N" visible="7" mapcol="Clientes" mapfld="ID" />
|
|
56
|
+
|
|
57
|
+
<!-- Campos del JOIN: NO son columnas de Pedidos, con MAP_ -->
|
|
58
|
+
<prop name="MAP_NOMBRECLIENTE" type="T" visible="7" locked="true" fieldsize="150" />
|
|
59
|
+
<prop name="MAP_TELEFONOCLIENTE" type="T" visible="7" locked="true" fieldsize="20" />
|
|
60
|
+
</group>
|
|
61
|
+
</coll>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Caso 2 — Campos enlazados via `linkedto` (combos/lookups)**
|
|
65
|
+
|
|
66
|
+
El combo usa dos props. El oculto con el ID es columna de la tabla (sin `MAP_`); el visible con la descripción obtenida del lookup lleva `MAP_`:
|
|
67
|
+
|
|
68
|
+
```xml
|
|
69
|
+
<!-- Oculto: FK, SI es columna -->
|
|
70
|
+
<prop name="IDTIPO" type="N" visible="0" mapcol="TiposProducto" mapfld="ID" />
|
|
71
|
+
|
|
72
|
+
<!-- Visible: descripción del lookup, NO es columna -->
|
|
73
|
+
<prop name="MAP_TIPO_DESC" type="T" visible="1"
|
|
74
|
+
title="Tipo"
|
|
75
|
+
linkedto="IDTIPO" linkedfield="DESCRIPCION" showinline="true" />
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
En combos con `mapcol-values` (valores inline en XML) el prop oculto también lleva `MAP_` porque no existe tabla de la que leer:
|
|
79
|
+
|
|
80
|
+
```xml
|
|
81
|
+
<prop name="MAP_IDTIPO" type="T" visible="0"
|
|
82
|
+
mapcol-values="CC,TI,CE,Otro" mapfld="DATA" />
|
|
83
|
+
<prop name="MAP_TIPO" type="T" visible="1"
|
|
84
|
+
linkedto="MAP_IDTIPO" linkedfield="DATA" showinline="true" />
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Caso 3 — Props puramente visuales (sin origen de datos)**
|
|
88
|
+
|
|
89
|
+
Cualquier prop sin dato persistible lleva `MAP_`:
|
|
90
|
+
|
|
91
|
+
| Uso | Tipo | Ejemplo |
|
|
92
|
+
|-----|------|---------|
|
|
93
|
+
| Etiquetas / títulos | `L` (alias legacy: `TL`) | `MAP_TITULO`, `MAP_SUBTITULO` |
|
|
94
|
+
| Botones | `B` | `MAP_BTN_GUARDAR`, `MAP_BTN_CANCELAR` |
|
|
95
|
+
| Imágenes decorativas | `IMG` | `MAP_LOGO`, `MAP_ICONO_CABECERA` |
|
|
96
|
+
| Contenedores de contents | `Z` | `MAP_LISTA_PRODUCTOS` |
|
|
97
|
+
| Valores calculados en runtime | `N2`, `F` | `MAP_TOTAL`, `MAP_SUBTOTAL_IVA` |
|
|
98
|
+
| Estados de UI | `T`, `N`, `NC` | `MAP_TAB`, `MAP_MODO`, `MAP_SELECCIONADO` |
|
|
99
|
+
| Buscadores / filtros temporales | `T` | `MAP_BUSQUEDA`, `MAP_FILTRO` |
|
|
100
|
+
| Callbacks / objetos JS | `O` | `MAP_CALLBACK` |
|
|
101
|
+
|
|
102
|
+
```xml
|
|
103
|
+
<prop name="MAP_TITULO" type="L" title="Gestion de Pedidos" class="textoTitulo" />
|
|
104
|
+
<prop name="MAP_BTN_GUARDAR" type="B" visible="1" title="Guardar" method="executenode(guardar)" />
|
|
105
|
+
<prop name="MAP_TOTAL" type="N2" visible="1" locked="true" title="Total" />
|
|
106
|
+
<prop name="MAP_BUSQUEDA" type="T" visible="1" title="Buscar" onchange="Refresh" />
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### Mecanismo y consecuencias
|
|
110
|
+
|
|
111
|
+
- Los `MAP_*` **no se persisten**: el framework los excluye del SQL generado. Viven en memoria del DataObject durante la vida de la pantalla.
|
|
112
|
+
- Se leen y escriben desde JS como cualquier otro campo: `self.MAP_CAMPO`, `self["MAP_CAMPO"]`, `self.getValue("MAP_CAMPO")`.
|
|
113
|
+
- Pueden ser referenciados en `disablevisible`, en macros (`##FLD_MAP_xxx##`), en `ui.refresh("MAP_xxx")`, en `<action name="setval" field="MAP_xxx">`, etc.
|
|
114
|
+
- **No son de solo lectura.** `locked="true"` es una decisión de UI independiente del prefijo.
|
|
115
|
+
|
|
116
|
+
#### Anti-patrones
|
|
117
|
+
|
|
118
|
+
| Error | Consecuencia |
|
|
119
|
+
|-------|--------------|
|
|
120
|
+
| Poner `MAP_` a un campo que SI esta en BD | El dato no se persiste: se pierde al guardar |
|
|
121
|
+
| Omitir `MAP_` en un alias de JOIN | El framework genera UPDATE sobre columna inexistente -> error SQL |
|
|
122
|
+
| Omitir `MAP_` en el prop visible de un combo con `linkedto` | El framework intenta persistir la descripción del lookup -> error SQL |
|
|
123
|
+
| Declarar columna `MAP_LOQUESEA` en el `CREATE TABLE` | Columna muerta: el framework nunca escribe en ella |
|
|
124
|
+
| Poner `MAP_` a una etiqueta `L`/`TL` que muestra un campo real de BD | La etiqueta no refleja el dato persistido; confusion semantica |
|
|
125
|
+
|
|
126
|
+
### 6.3 Plantilla Base para Coleccion de Datos
|
|
127
|
+
|
|
128
|
+
```xml
|
|
129
|
+
<?xml version="1.0" encoding="iso-8859-15"?>
|
|
130
|
+
<coll name="NombreColeccion"
|
|
131
|
+
title="nombre coleccion"
|
|
132
|
+
sql="SELECT t1.* FROM ##PREF##NombreColeccion t1"
|
|
133
|
+
objname="NombreColeccion"
|
|
134
|
+
updateobj="NombreColeccion"
|
|
135
|
+
progid="ASData.CASBasicDataObj"
|
|
136
|
+
loadall="true"
|
|
137
|
+
notab="true"
|
|
138
|
+
group-swipe="false">
|
|
139
|
+
|
|
140
|
+
<!-- GRUPO 1 - Formulario de edicion -->
|
|
141
|
+
<group name="General" id="1">
|
|
142
|
+
<!-- ID siempre oculto -->
|
|
143
|
+
<!-- Campos de datos propios -->
|
|
144
|
+
<prop name="CODIGO" type="T" visible="7" fieldsize="20" />
|
|
145
|
+
<prop name="NOMBRE" type="T" visible="7" fieldsize="150" />
|
|
146
|
+
<prop name="DESCRIPCION" type="T" visible="7" fieldsize="500" lines="3" />
|
|
147
|
+
<prop name="ACTIVO" type="NC" visible="7" />
|
|
148
|
+
<prop name="FECHA_CREACION" type="DT" visible="0" />
|
|
149
|
+
</group>
|
|
150
|
+
|
|
151
|
+
</coll>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 6.4 Plantilla para Coleccion con Foreign Key y campos enlazados
|
|
155
|
+
|
|
156
|
+
```xml
|
|
157
|
+
<?xml version="1.0" encoding="iso-8859-15"?>
|
|
158
|
+
<coll name="Pedidos"
|
|
159
|
+
title="el pedido"
|
|
160
|
+
sql="SELECT t1.*,
|
|
161
|
+
c.NOMBRE AS MAP_NOMBRECLIENTE,
|
|
162
|
+
u.NOMBRE AS MAP_NOMBREUSUARIO
|
|
163
|
+
FROM ##PREF##Pedidos t1
|
|
164
|
+
LEFT OUTER JOIN ##PREF##Clientes c ON t1.IDCLIENTE=c.ID
|
|
165
|
+
LEFT OUTER JOIN ##PREF##usuarios u ON t1.IDUSUARIO=u.ID"
|
|
166
|
+
objname="pedidos"
|
|
167
|
+
updateobj="pedidos"
|
|
168
|
+
progid="ASData.CASBasicDataObj"
|
|
169
|
+
loadall="true"
|
|
170
|
+
filter="t1.IDEMPRESA=##ENTID##"
|
|
171
|
+
sort="t1.FECHA DESC"
|
|
172
|
+
notab="true"
|
|
173
|
+
group-swipe="false">
|
|
174
|
+
|
|
175
|
+
<group name="General" id="1">
|
|
176
|
+
<!-- Foreign Keys (IDLOQUESEA — todo junto, en mayusculas) -->
|
|
177
|
+
<prop name="IDCLIENTE" type="N" visible="7" mapcol="Clientes" mapfld="ID" />
|
|
178
|
+
<prop name="IDUSUARIO" type="N" visible="7" mapcol="Usuarios" mapfld="ID" />
|
|
179
|
+
<!-- Campos enlazados de otras tablas (prefijo MAP_, no se graban en BD) -->
|
|
180
|
+
<prop name="MAP_NOMBRECLIENTE" type="T" visible="7" locked="true" fieldsize="150" />
|
|
181
|
+
<prop name="MAP_NOMBREUSUARIO" type="T" visible="7" locked="true" fieldsize="100" />
|
|
182
|
+
<!-- Campos propios -->
|
|
183
|
+
<prop name="FECHA" type="DT" visible="7" />
|
|
184
|
+
<prop name="ESTADO" type="T" visible="7" fieldsize="20" />
|
|
185
|
+
<prop name="TOTAL" type="N2" visible="7" />
|
|
186
|
+
<prop name="OBSERVACIONES" type="T" visible="7" fieldsize="500" lines="3" />
|
|
187
|
+
</group>
|
|
188
|
+
|
|
189
|
+
<!-- Evento create: inicializar valores al crear un objeto nuevo -->
|
|
190
|
+
<create>
|
|
191
|
+
<action name="setval" field="FECHA" value="##NOW##" />
|
|
192
|
+
<action name="setval" field="IDEMPRESA" value="##ENTID##" />
|
|
193
|
+
<action name="setval" field="ESTADO" value="PENDIENTE" />
|
|
194
|
+
</create>
|
|
195
|
+
|
|
196
|
+
</coll>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 6.5 Atributos del nodo `<coll>`
|
|
200
|
+
|
|
201
|
+
#### Obligatorios para colecciones de datos
|
|
202
|
+
|
|
203
|
+
| Atributo | Descripción |
|
|
204
|
+
|----------|-------------|
|
|
205
|
+
| `name` | Nombre único de la coleccion en toda la app |
|
|
206
|
+
| `sql` | Query SQL. Siempre con `##PREF##`. El campo `ID` de la tabla principal SIEMPRE debe estar en el SELECT |
|
|
207
|
+
| `objname` | Nombre de la tabla principal para lectura de datos |
|
|
208
|
+
| `updateobj` | Nombre de la tabla para escritura. Normalmente igual que `objname` |
|
|
209
|
+
| `progid` | Tipo de objeto de datos. **Opcional** (default = genérico). `ASData.CASBasicDataObj` para colecciones de negocio; `ASGestion.CASEmpresa`/`ASGestion.CASUser` solo en Empresas/Usuarios |
|
|
210
|
+
|
|
211
|
+
#### Atributos de comportamiento frecuentes
|
|
212
|
+
|
|
213
|
+
| Atributo | Descripción | Valor por defecto |
|
|
214
|
+
|----------|-------------|-------------------|
|
|
215
|
+
| `title` | Nombre descriptivo de la coleccion | — |
|
|
216
|
+
| `loadall` | `true` carga todos los registros de golpe / `false` carga bajo demanda (usar para listas grandes) | `false` |
|
|
217
|
+
| `filter` | Clausula WHERE del SQL (sin la palabra WHERE). Soporta macros como `##ENTID##`, `##USERID##` | — |
|
|
218
|
+
| `sort` | Clausula ORDER BY (sin ORDER BY). Ej: `FECHA DESC, NOMBRE ASC` | — |
|
|
219
|
+
| `notab` | `true` oculta las pestanas de grupos y usa toda la pantalla | `false` |
|
|
220
|
+
| `group-swipe` | `true` permite deslizar entre grupos con el dedo | `true` |
|
|
221
|
+
| `special` | `true` indica coleccion especial (pantallas de menu, entrada, login) — no tiene tabla en BD | `false` |
|
|
222
|
+
| `editmask` | Bitmask que controla modos de edición (0=todos, 2=solo lista, 8=readonly) | `0` |
|
|
223
|
+
| `readonly` | `true` la coleccion es solo lectura, no permite modificaciones | `false` |
|
|
224
|
+
| `dependent` | `true` la coleccion depende del objeto padre | `false` |
|
|
225
|
+
| `check-owner` | `true` verifica que el registro pertenece al usuario actual | `false` |
|
|
226
|
+
| `autorefresh` | `true` refresca los datos al volver de otra ventana si hubo cambios | `false` |
|
|
227
|
+
| `cell-even-color` | Color de filas pares en modo lista | — |
|
|
228
|
+
| `cell-odd-color` | Color de filas impares en modo lista | — |
|
|
229
|
+
| `cell-height` | Alto de cada fila en modo lista (en puntos `p`) | — |
|
|
230
|
+
| `userawsql` | `true` usa el SQL exactamente como esta escrito sin modificaciones del framework | `false` |
|
|
231
|
+
| `start-from-bottom` | `true` el scroll empieza desde el final y se ancla al último item. Útil para chats. Se puede declarar en la coll o en el content (`type="Z"`); el del content tiene preferencia | `false` |
|
|
232
|
+
| `no-data-text` | Texto a mostrar cuando la coleccion no tiene registros | `" "` |
|
|
233
|
+
| `cell-height` | Alto fijo de cada fila en modo listado (en puntos `p`) | — |
|
|
234
|
+
| `cell-tpadding` | Margen interior superior de cada celda | — |
|
|
235
|
+
| `cell-bpadding` | Margen interior inferior de cada celda | — |
|
|
236
|
+
| `cell-bgcolor` | Color de fondo general de todas las celdas | — |
|
|
237
|
+
| `stringkey` | `true` indica que la clave primaria es de tipo texto en lugar de entero | `false` |
|
|
238
|
+
| `idfieldname` | Nombre del campo clave primaria cuando no se llama `ID` | `"ID"` |
|
|
239
|
+
| `group-theme` | `"material"` activa el estilo Material Design en las pestanas | — |
|
|
240
|
+
| `tab-mode` | `"fixed"` (pestanas fijas) o `"scrollable"` (pestanas con scroll) | — |
|
|
241
|
+
| `page-limit-off` | Limita el número de pestanas precargadas en memoria (por defecto 6) | `6` |
|
|
242
|
+
|
|
243
|
+
### 6.5b Herencia entre colecciones (`inherits`) y composición (`<include-layout>`)
|
|
244
|
+
|
|
245
|
+
XOne soporta dos mecanismos para reutilizar estructura XML entre colecciones. Son ortogonales al CSS `extends` — operan sobre groups, frames, props y eventos.
|
|
246
|
+
|
|
247
|
+
#### Atributo `inherits` en `<coll>`
|
|
248
|
+
|
|
249
|
+
Permite que una coll herede la estructura completa (grupos, frames, props y eventos) de otra coll declarada en el proyecto. Regla de precedencia: ante mismo `name`, **prevalece la hija**; los elementos no duplicados del padre se conservan.
|
|
250
|
+
|
|
251
|
+
```xml
|
|
252
|
+
<coll name="PantallaConcreta" inherits="groupsFixed" special="true" notab="false">
|
|
253
|
+
...
|
|
254
|
+
</coll>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Reglas operativas:**
|
|
258
|
+
- Un solo padre por coll. No existe `inherits="A,B"`.
|
|
259
|
+
- Admite cadenas (A → B → C) — la resolución recorre toda la cadena aplicando hijo-gana en cada nivel.
|
|
260
|
+
- Los eventos duplicados también siguen hijo-gana (no hay `super()`).
|
|
261
|
+
- El padre puede estar en el mismo fichero `.xne` o en otro fichero `.xne` del proyecto; basta con referenciarlo por su `name`.
|
|
262
|
+
|
|
263
|
+
#### Patron recomendado: scaffolding visual compartido
|
|
264
|
+
|
|
265
|
+
Cuando el proyecto tiene varias pantallas con el mismo esqueleto (header fijo, footer de paginación, botones comunes, evento `<onback>` común), se crea una coll base `special="true"` que contenga ese scaffolding, y cada pantalla la hereda.
|
|
266
|
+
|
|
267
|
+
**Paso 1 — Crear la coll base** (fichero `layoutsFijos.xne` o similar):
|
|
268
|
+
|
|
269
|
+
```xml
|
|
270
|
+
<?xml version="1.0" encoding="iso-8859-15"?>
|
|
271
|
+
<coll name="layoutsFijos" title="" special="true">
|
|
272
|
+
<!-- Header comun: logo, título, botón salir -->
|
|
273
|
+
<group name="HEADER" id="999" class="groupfixed_header">
|
|
274
|
+
<frame name="frmTitulo" class="frmsuperior">
|
|
275
|
+
<prop name="BTSALIR" type="B" class="btvolversuper"
|
|
276
|
+
method="ExecuteNode(onback)" />
|
|
277
|
+
<prop name="LBL_TITULO" type="L" class="tlsuper" title="App" />
|
|
278
|
+
</frame>
|
|
279
|
+
</group>
|
|
280
|
+
<!-- Footer comun: paginador -->
|
|
281
|
+
<group name="FOOTER" id="0" class="groupfixed_footer">
|
|
282
|
+
<prop name="MAP_GROUP" type="N" visible="0" />
|
|
283
|
+
<prop name="MAP_TOTAL_PAGES" type="N" visible="0" />
|
|
284
|
+
</group>
|
|
285
|
+
<!-- Evento de salida comun -->
|
|
286
|
+
<onback show-wait-dialog="false">
|
|
287
|
+
<action name="runscript">
|
|
288
|
+
<script language="javascript">
|
|
289
|
+
ui.getView(self).exit();
|
|
290
|
+
</script>
|
|
291
|
+
</action>
|
|
292
|
+
</onback>
|
|
293
|
+
</coll>
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Paso 2 — Las pantallas concretas la heredan:**
|
|
297
|
+
|
|
298
|
+
```xml
|
|
299
|
+
<?xml version="1.0" encoding="iso-8859-15"?>
|
|
300
|
+
<coll name="PantallaA" inherits="layoutsFijos" special="true" notab="false">
|
|
301
|
+
<!-- Solo sobreescribe el título del header -->
|
|
302
|
+
<group name="HEADER" id="999">
|
|
303
|
+
<frame name="frmTitulo" class="frmsuperior">
|
|
304
|
+
<prop name="LBL_TITULO" type="L" class="tlsuper" title="Pantalla A" />
|
|
305
|
+
</frame>
|
|
306
|
+
</group>
|
|
307
|
+
<!-- Contenido propio -->
|
|
308
|
+
<group name="Group1" id="1">
|
|
309
|
+
<prop name="MAP_CAMPO1" type="T" visible="1" />
|
|
310
|
+
</group>
|
|
311
|
+
<before-edit>
|
|
312
|
+
<action name="runscript">
|
|
313
|
+
<script language="javascript">
|
|
314
|
+
self.MAP_GROUP = 1;
|
|
315
|
+
self.MAP_TOTAL_PAGES = 1;
|
|
316
|
+
</script>
|
|
317
|
+
</action>
|
|
318
|
+
</before-edit>
|
|
319
|
+
</coll>
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Decisión: cuando SI y cuando NO usar `inherits`**
|
|
323
|
+
|
|
324
|
+
| Escenario | Decisión |
|
|
325
|
+
|-----------|----------|
|
|
326
|
+
| 3+ pantallas con mismo header/footer/navegación | SI — extraer a coll base `special="true"` |
|
|
327
|
+
| 2 pantallas con estructura muy parecida y lógica distinta | SI — coll base común, override de eventos en la hija |
|
|
328
|
+
| 1-2 pantallas con algunas piezas comunes | Normalmente NO — duplicar es más claro |
|
|
329
|
+
| Colecciones de datos (con `objname`) | Raro — `inherits` es útil sobre todo entre colecciones `special="true"` |
|
|
330
|
+
| Pantallas con estructura totalmente distinta | NO — la herencia no aporta |
|
|
331
|
+
|
|
332
|
+
#### Nodo `<include-layout>` (composición por fragmentos)
|
|
333
|
+
|
|
334
|
+
Nodo hijo de `<coll>` que inyecta el contenido de un fichero XML externo. Útil para factorizar **botoneras, bloques de props recurrentes o eventos compartidos**.
|
|
335
|
+
|
|
336
|
+
```xml
|
|
337
|
+
<include-layout file="misBotones.xml" group="1" frame="todo" />
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
- `file`: ruta **relativa a la raiz del proyecto**
|
|
341
|
+
- `group`/`frame`: defaults para props del fichero incluido que no los declaren
|
|
342
|
+
|
|
343
|
+
**Formato del fichero incluido:**
|
|
344
|
+
|
|
345
|
+
```xml
|
|
346
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
347
|
+
<xml>
|
|
348
|
+
<!-- Props, groups, frames y eventos al mismo nivel (plano) -->
|
|
349
|
+
<prop name="MAP_SALIR" type="B" title="Salir" visible="1"
|
|
350
|
+
method="ExecuteNode(salir)" width="100%" labelwidth="10" />
|
|
351
|
+
<salir refresh="false">
|
|
352
|
+
<action name="runscript">
|
|
353
|
+
<script language="javascript">
|
|
354
|
+
appData.exit();
|
|
355
|
+
</script>
|
|
356
|
+
</action>
|
|
357
|
+
</salir>
|
|
358
|
+
</xml>
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Reglas clave:**
|
|
362
|
+
- Encoding del fichero incluido: **`utf-8`** (los `.xne` pueden ir en UTF-8 o iso-8859-15).
|
|
363
|
+
- Raiz: `<xml>` (NO `<coll>`).
|
|
364
|
+
- Estructura plana, no jerárquica.
|
|
365
|
+
- **No se pueden anidar `<include-layout>`**: el fichero incluido no puede contener a su vez otro `<include-layout>`.
|
|
366
|
+
- Los nombres (`name`) deben ser únicos en el ambito final tras la composición.
|
|
367
|
+
|
|
368
|
+
#### Checklist para el agente
|
|
369
|
+
|
|
370
|
+
- [ ] Si 3+ pantallas comparten estructura, extraer a coll base `special="true"` y usar `inherits`.
|
|
371
|
+
- [ ] La coll base va en su propio fichero `.xne` (PascalCase: `LayoutsFijos.xne`).
|
|
372
|
+
- [ ] Recordar: `inherits` admite cadena A→B→C pero NO herencia multiple.
|
|
373
|
+
- [ ] Si hay botoneras o bloques repetidos entre colls heredadas y no heredadas, factorizar con `<include-layout>` a fichero externo.
|
|
374
|
+
- [ ] En el fichero de `<include-layout>`: encoding `utf-8`, raiz `<xml>`, estructura plana, sin anidar otros `<include-layout>`.
|
|
375
|
+
- [ ] Nombres únicos en el ambito final tras herencia + composición.
|
|
376
|
+
|
|
377
|
+
### 6.6 Nodo `<contents>` — Coleccion embebida
|
|
378
|
+
|
|
379
|
+
Para mostrar una relación 1-N dentro de una coleccion, se usa un `prop type="Z"` con su `<contents>` asociado:
|
|
380
|
+
|
|
381
|
+
```xml
|
|
382
|
+
<!-- Dentro del group, el prop que muestra el contents -->
|
|
383
|
+
<prop name="@LineasPedido" type="Z" visible="1"
|
|
384
|
+
contents="LineasPedido"
|
|
385
|
+
width="100%" height="60%"
|
|
386
|
+
locked="true" />
|
|
387
|
+
|
|
388
|
+
<!-- El nodo contents define el origen de datos del Z -->
|
|
389
|
+
<contents name="LineasPedido" src="ColeccionLineasPedido"
|
|
390
|
+
filter="IDPEDIDO=##FLD_ID##" />
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
> El `filter` del `<contents>` usa `##FLD_CAMPO##` para referenciar campos del objeto padre.
|
|
394
|
+
|
|
395
|
+
### 6.7 Atributos de `<prop>` — Referencia de los más importantes
|
|
396
|
+
|
|
397
|
+
| Atributo | Descripción |
|
|
398
|
+
|----------|-------------|
|
|
399
|
+
| `name` | Nombre del campo. **SIEMPRE EN MAYUSCULAS** |
|
|
400
|
+
| `type` | Tipo del campo (ver sección 3.3) |
|
|
401
|
+
| `visible` | Bitmask de visibilidad. Estático — no cambia en tiempo de ejecución. Valores: 0=oculto, 1=edición, 2=lista, 3=edición+lista, 4=content, 7=edición+lista+content, 8=combo, 15=todos (ver sección 3.4) |
|
|
402
|
+
| `title` | Etiqueta/label a mostrar junto al campo |
|
|
403
|
+
| `width` | Ancho. Usar `%` o `p` (puntos). Ej: `"90%"`, `"200p"` |
|
|
404
|
+
| `height` | Alto. Usar `%` o `p`. Valor especial `-2` = altura automática según contenido |
|
|
405
|
+
| `fieldsize` | Tamaño máximo del campo de texto en BD |
|
|
406
|
+
| `size` | Tamaño visual del campo |
|
|
407
|
+
| `lines` | Número de lineas para campos de texto multilínea |
|
|
408
|
+
| `fixed-lines` | `true` el campo ocupa exactamente las lineas indicadas en `lines` |
|
|
409
|
+
| `newline` | Por defecto `true` — cada elemento ocupa su propia línea. Con `false` el elemento se coloca a la derecha del anterior. Funciona igual en `<frame>` y `<prop>`. Los anchos de los elementos en la misma fila deben sumar 100% o menos |
|
|
410
|
+
| `locked` | `true` el campo es solo lectura para el usuario |
|
|
411
|
+
| `labelwidth` | Proporcion de la etiqueta. `0` = sin etiqueta, solo el valor |
|
|
412
|
+
| `forecolor` | Color del texto de la etiqueta |
|
|
413
|
+
| `bgcolor` | Color de fondo del campo |
|
|
414
|
+
| `fontsize` | Tamaño de la fuente de la etiqueta |
|
|
415
|
+
| `textfont-size` | Tamaño de la fuente del valor del campo |
|
|
416
|
+
| `textfont-bold` | `true` el valor del campo en negrita |
|
|
417
|
+
| `text-forecolor` | Color del texto del valor del campo |
|
|
418
|
+
| `text-bgcolor` | Color de fondo del área de texto del campo |
|
|
419
|
+
| `text-align` | Alineacion del texto: `left`, `center`, `right`, `left\|center` |
|
|
420
|
+
| `text-border` | `true/false` borde alrededor del área de texto |
|
|
421
|
+
| `text-border-bottom` | `true/false` solo borde inferior |
|
|
422
|
+
| `lmargin` / `tmargin` / `rmargin` / `bmargin` | Margenes exteriores |
|
|
423
|
+
| `lpadding` / `tpadding` / `rpadding` / `bpadding` | Margenes interiores |
|
|
424
|
+
| `align` | Posición del elemento dentro de su contenedor (`<group>`, `<frame>` o `<prop>`). Mismo comportamiento en los tres nodos. Valores: `left`, `right`, `center`, `top`, `bottom` y combinaciones con `\|` como `center\|center`, `left\|top`, `left\|center`, `center\|top`. Ver tabla completa en 02-xml-ui-complete-guide sección 4.2 |
|
|
425
|
+
| `disablevisible` | Oculta el elemento en tiempo de ejecución si se cumple la condición. Aplica en `<group>`, `<frame>` y `<prop>`. Se reevalua al hacer `ui.refresh()` o cuando el campo referenciado tiene `onchange="refresh"`. Formato: `CAMPO=VALOR`, `CAMPO>VALOR`, `CAMPO<VALOR` |
|
|
426
|
+
| `disableedit` | **Bloquea edición del campo SI se cumple la condición**. Ej: `"ESTADO=2"` |
|
|
427
|
+
| `mapcol` | Coleccion a la que enlaza este campo (FK) |
|
|
428
|
+
| `mapfld` | Campo de la coleccion enlazada que devuelve el valor |
|
|
429
|
+
| `linkedto` | Campo de esta coleccion donde se guarda el valor seleccionado del enlace |
|
|
430
|
+
| `linkedfield` | Campo de la coleccion enlazada que se muestra al usuario |
|
|
431
|
+
| `showinline` | `true` abre las opciones del selector en un panel inferior |
|
|
432
|
+
| `showinline-keyboard` | `true` añade una caja de búsqueda en la cabecera del panel `showinline` para filtrar las opciones |
|
|
433
|
+
| `bgcolor-dialog` / `forecolor-dialog` / `fontsize-dialog` | Personalizan el panel `showinline` y los pickers `D`/`DT`/`TT`: fondo, color de texto/acento y tamaño |
|
|
434
|
+
| `floating-tooltip` | `true` muestra el `tooltip` como placeholder flotante sobre el campo |
|
|
435
|
+
| `tooltip` | Texto de ayuda o placeholder del campo |
|
|
436
|
+
| `method` | Método XOne a ejecutar al pulsar. Ej: `"ExecuteNode(guardar)"` |
|
|
437
|
+
| `onclick` | Script JavaScript inline al pulsar. Ej: `"javascript:miFuncion();"` |
|
|
438
|
+
| `onchange` | Acción al cambiar el valor. Ej: `"Refresh"` o `"javascript:calcular();"` |
|
|
439
|
+
| `img` | Imagen para botones (`type="B"`) |
|
|
440
|
+
| `imgsel` | Imagen al pulsar el botón |
|
|
441
|
+
| `keep-aspect-ratio` | `true` mantiene proporcion al redimensionar imágenes |
|
|
442
|
+
| `error-image` | Imagen alternativa si la principal falla. Ej: `error-image="avatar_error.png"` |
|
|
443
|
+
| `repeat-mode` | **Solo animaciones Lottie en `type="IMG"`**: `restart` (defecto, vuelve a empezar) o `reverse` (ida y vuelta). La animación arranca sola en bucle infinito |
|
|
444
|
+
| `clip-text-to-bounds` | **Solo animaciones Lottie en `type="IMG"`**: recorta el texto de párrafo a la caja definida en el diseño (defecto `false`) |
|
|
445
|
+
| `use-internal-camera` | `true` captura con la cámara que trae el framework en vez de abrir la app de cámara del dispositivo |
|
|
446
|
+
| `motion-photo` | `true` captura una foto en movimiento: JPG con un clip de vídeo corto embebido. Requiere `use-internal-camera="true"` e ignora los atributos `file-*` |
|
|
447
|
+
| `contents` | Nombre del contents asociado (para `type="Z"`) |
|
|
448
|
+
| `viewmode` | Modo de visualizacion del contents (ver sección 7.13) |
|
|
449
|
+
| `group` | ID del grupo al que pertenece este prop (forma alternativa de asignacion) |
|
|
450
|
+
| `info` | Metadato informativo sin efecto visual. Útil para documentar campos |
|
|
451
|
+
| `fixed-text` | `true` combinado con `size` impide introducir más caracteres del limite en UI |
|
|
452
|
+
| `floating` | `true` el prop se superpone al layout. Posicionar con `top` y `left` |
|
|
453
|
+
| `keep-aspect-ratio` | Ya documentado: `true` mantiene la proporcion original de la imagen |
|
|
454
|
+
| `updates` | Al cambiar este campo, propaga el cambio al campo indicado en la coleccion contents |
|
|
455
|
+
| `contextual-search` | `true` activa la busqueda en tiempo real sobre un contents |
|
|
456
|
+
| `contextual-target` | Nombre del `type="Z"` que se filtra con la busqueda contextual |
|
|
457
|
+
| `contextual-filter` | Clausula WHERE para el filtro contextual. `##VAL##` se sustituye por el texto escrito |
|
|
458
|
+
| `formula` | Calcula el valor con una SQL externa. Formato: `ext.[NOMBRE]`. Requiere nodo `<ext-formula>` |
|
|
459
|
+
|
|
460
|
+
### 6.8 Regla de Campos por Tipo de Dato
|
|
461
|
+
|
|
462
|
+
| Tipo de Campo | Atributo `fieldsize` | Notas |
|
|
463
|
+
|---------------|----------------------|-------|
|
|
464
|
+
| Texto corto (T) | `fieldsize="20"` a `"50"` | Códigos, estados, telefonos |
|
|
465
|
+
| Texto medio (T) | `fieldsize="100"` a `"150"` | Nombres, emails, títulos |
|
|
466
|
+
| Texto largo (T) | `fieldsize="255"` a `"500"` | Descripciones, direcciones, observaciones |
|
|
467
|
+
| Password (X) | `fieldsize="100"` | Siempre `visible="0"` |
|
|
468
|
+
| Numéricos (N, N2...) | No requiere fieldsize | IDs, cantidades, precios |
|
|
469
|
+
| Fechas (D, DT) | No requiere fieldsize | Fechas y timestamps |
|
|
470
|
+
| Booleanos (NC) | No requiere fieldsize | Flags 0/1 |
|
|
471
|
+
| ID campos FK | No requiere fieldsize | Convenir `IDLOQUESEA` todo junto en mayusculas |
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
### 6.8b Atributos especiales por tipo
|
|
476
|
+
|
|
477
|
+
**Radio button (type="NC" con check-type="radio"):**
|
|
478
|
+
|
|
479
|
+
```xml
|
|
480
|
+
<prop name="MAP_OPCION_A" type="NC" visible="1"
|
|
481
|
+
title="Opción A" check-type="radio" radio-group="1"
|
|
482
|
+
width="100%" height="120p" />
|
|
483
|
+
<prop name="MAP_OPCION_B" type="NC" visible="1"
|
|
484
|
+
title="Opción B" check-type="radio" radio-group="1"
|
|
485
|
+
width="100%" height="120p" />
|
|
486
|
+
<prop name="MAP_OPCION_C" type="NC" visible="1"
|
|
487
|
+
title="Opción C" check-type="radio" radio-group="1"
|
|
488
|
+
width="100%" height="120p" />
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
| Atributo | Descripción |
|
|
492
|
+
|----------|-------------|
|
|
493
|
+
| `check-type="radio"` | Convierte el NC en radio button en lugar de checkbox |
|
|
494
|
+
| `radio-group` | ID numérico del grupo. Solo puede estar activo uno del mismo grupo |
|
|
495
|
+
| `allow-radio-group-uncheck` | `true` permite deseleccionar el radio pulsandolo de nuevo |
|
|
496
|
+
|
|
497
|
+
**onchange — refresco al cambiar valor:**
|
|
498
|
+
|
|
499
|
+
```xml
|
|
500
|
+
<!-- Refrescar toda la pantalla al cambiar -->
|
|
501
|
+
<prop name="ESTADO" type="N" visible="1" onchange="refresh" />
|
|
502
|
+
|
|
503
|
+
<!-- Refrescar un prop específico -->
|
|
504
|
+
<prop name="TIPO" type="T" visible="1" onchange="refresh(MAP_SUBTIPO)" />
|
|
505
|
+
|
|
506
|
+
<!-- Ejecutar nodo custom -->
|
|
507
|
+
<prop name="IMPORTE" type="N2" visible="1" onchange="ExecuteNode(calcularTotal)" />
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**Animación Lottie (type="IMG"):**
|
|
511
|
+
|
|
512
|
+
Un `IMG` cuyo fichero sea `.json`, `.lottie` o `.tgs` se renderiza como animación Lottie y **arranca sola en bucle infinito**, sin llamar a nada. El atributo `path` (igual que `img`) acepta además PNG, JPG, SVG (renderizado nativo, sin `type="WEB"`) y GIF animado; el formato se decide por la extensión del fichero.
|
|
513
|
+
|
|
514
|
+
```xml
|
|
515
|
+
<!-- Animación de carga, ida y vuelta -->
|
|
516
|
+
<prop name="MAP_LOADER" type="IMG" visible="1"
|
|
517
|
+
path="loader.json"
|
|
518
|
+
labelwidth="0"
|
|
519
|
+
width="120p" height="120p"
|
|
520
|
+
repeat-mode="reverse" />
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
| Extensión | Qué es |
|
|
524
|
+
|-----------|--------|
|
|
525
|
+
| `.json` | La animación en texto plano; sus imágenes pueden ir embebidas dentro o aparte |
|
|
526
|
+
| `.lottie` | Paquete comprimido con la animación y sus imágenes |
|
|
527
|
+
| `.tgs` | Sticker de Telegram: un `.json` comprimido con gzip |
|
|
528
|
+
|
|
529
|
+
- **Fuentes:** si la animación lleva texto, la fuente se busca **solo** en `fonts/` con el nombre de familia que declara el fichero (una que pida `Roboto` necesita `fonts/Roboto.ttf` o `.otf`); si falta, se usa la del dispositivo.
|
|
530
|
+
- **Imágenes:** embebidas en el fichero, dentro del `.lottie`, o sueltas junto a él respetando la subcarpeta que declare el diseño (normalmente `images/`).
|
|
531
|
+
- **Control desde JavaScript:** `playAnimation(obj)`, `pauseAnimation()`, `resumeAnimation()`, `stopAnimation()` (además rebobina al primer frame), `setAnimationFrame(frame)`, `getMaxFrameCount()` sobre el control obtenido con `getControl(...)`.
|
|
532
|
+
|
|
533
|
+
`playAnimation(obj)` admite `{reverse, speed, repeatCount, repeatMode, fromFrame, toFrame}`. Ojo: como la animación ya se reproduce sola en bucle infinito, llamar a `playAnimation({...})` con `repeatCount: 0` (defecto) la corta tras **una sola pasada** — para mantener el bucle infinito usar `repeatCount: -1`. `speed` debe ser positivo; `repeatMode` es `"restart"` (defecto) o `"reverse"`; `toFrame: 0` significa "hasta el final".
|
|
534
|
+
|
|
535
|
+
```javascript
|
|
536
|
+
// Reproducir una vez, al doble de velocidad
|
|
537
|
+
getControl("MAP_LOADER").playAnimation({ speed: 2 });
|
|
538
|
+
|
|
539
|
+
// Volver a dejarla en bucle infinito, ida y vuelta
|
|
540
|
+
getControl("MAP_LOADER").playAnimation({ repeatCount: -1, repeatMode: "reverse" });
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### 6.9 Relaciones entre Colecciones
|
|
544
|
+
|
|
545
|
+
XOne tiene tres tipos de relaciones entre colecciones:
|
|
546
|
+
|
|
547
|
+
| Tipo | Cuando usarlo |
|
|
548
|
+
|------|---------------|
|
|
549
|
+
| **1 a 1 — Lupa** | Relación con colecciones que tienen muchos datos. El usuario abre un buscador para seleccionar |
|
|
550
|
+
| **1 a 1 — Combo** | Relación con colecciones que tienen pocos datos. Se muestran como lista desplegable inline |
|
|
551
|
+
| **1 a 1 — Combo sin BD** | Valores fijos predefinidos en el propio XML, sin tabla auxiliar |
|
|
552
|
+
| **1 a N — Contents** | Relación maestro-detalle donde el número de registros es variable |
|
|
553
|
+
|
|
554
|
+
#### Relación 1 a 1: Lupa
|
|
555
|
+
|
|
556
|
+
El campo FK guarda el ID seleccionado. Campos `MAP_` adicionales muestran datos de la fila seleccionada sin grabarse en BD. La lupa aparece en el campo sin `locked="true"`.
|
|
557
|
+
|
|
558
|
+
```xml
|
|
559
|
+
<!-- Campo FK — se graba en BD, normalmente oculto -->
|
|
560
|
+
<prop name="IDCLIENTE" type="N" visible="0" mapcol="Clientes" mapfld="ID" />
|
|
561
|
+
|
|
562
|
+
<!-- Campo que muestra el valor — con lupa activa para buscar -->
|
|
563
|
+
<prop name="MAP_CLIENTE" type="T" visible="1"
|
|
564
|
+
linkedto="IDCLIENTE" linkedfield="NOMBRE" onchange="Refresh" />
|
|
565
|
+
|
|
566
|
+
<!-- Campos adicionales de la misma fila — locked=true evita que salga la lupa -->
|
|
567
|
+
<prop name="MAP_TELEFONO" type="T" visible="1" locked="true"
|
|
568
|
+
linkedto="IDCLIENTE" linkedfield="TELEFONO" onchange="Refresh" />
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
#### Relación 1 a 1: Combo (coleccion auxiliar)
|
|
572
|
+
|
|
573
|
+
Identica a la lupa pero con `showinline="true"`. Usar solo cuando la coleccion tiene pocos registros, ya que se carga completa en memoria al abrir la pantalla.
|
|
574
|
+
|
|
575
|
+
```xml
|
|
576
|
+
<!-- Campo FK — se graba en BD -->
|
|
577
|
+
<prop name="IDTIPO" type="N" visible="0" mapcol="TiposVisita" mapfld="ID" />
|
|
578
|
+
|
|
579
|
+
<!-- Campo combo — showinline="true" lo convierte en desplegable -->
|
|
580
|
+
<prop name="MAP_TIPO" type="T" visible="1"
|
|
581
|
+
linkedto="IDTIPO" linkedfield="DESCRIPCION" showinline="true" />
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
#### Relación 1 a 1: Combo sin BD (valores fijos)
|
|
585
|
+
|
|
586
|
+
Cuando los valores son pocos y fijos. No necesita tabla auxiliar. El atributo `mapcol-values` define los valores separados por comas.
|
|
587
|
+
|
|
588
|
+
```xml
|
|
589
|
+
<!-- Campo con valores predefinidos — MAP_ porque no se graba directamente -->
|
|
590
|
+
<prop name="MAP_IDTIPO" type="N" visible="0"
|
|
591
|
+
mapcol-values="COMERCIAL,TECNICO,ADMINISTRACION" />
|
|
592
|
+
|
|
593
|
+
<!-- Campo que se graba en BD — linkedfield siempre es DATA en este caso -->
|
|
594
|
+
<prop name="TIPO" type="T" visible="1"
|
|
595
|
+
linkedto="MAP_IDTIPO" linkedfield="DATA" showinline="true" />
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
#### Relación 1 a N: Contents (maestro-detalle)
|
|
599
|
+
|
|
600
|
+
Para mostrar registros hijos dentro de un registro padre. La coleccion hija es independiente y se usa como contents filtrado por el ID del padre.
|
|
601
|
+
|
|
602
|
+
```xml
|
|
603
|
+
<!-- En la coleccion padre (Pedidos) -->
|
|
604
|
+
<prop name="@DETALLES" type="Z" visible="1"
|
|
605
|
+
contents="Detalles" width="100%" height="60%" locked="true" />
|
|
606
|
+
<contents name="Detalles" src="ColDetalles"
|
|
607
|
+
filter="IDPEDIDO=##ID##" />
|
|
608
|
+
|
|
609
|
+
<!-- Evento insert en el padre: enlaza los hijos al grabarse -->
|
|
610
|
+
<insert>
|
|
611
|
+
<action name="link" coll="ColDetalles" field="IDPEDIDO" value="##ID##" />
|
|
612
|
+
</insert>
|
|
613
|
+
|
|
614
|
+
<!-- Evento delete en el padre: borra los hijos al borrar el padre -->
|
|
615
|
+
<delete>
|
|
616
|
+
<action name="executesql"
|
|
617
|
+
sql="DELETE FROM ##PREF##detalles WHERE IDPEDIDO=##ID##" />
|
|
618
|
+
</delete>
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
```xml
|
|
622
|
+
<!-- Coleccion hija (ColDetalles) — evento create: asigna el ID del padre al crearse -->
|
|
623
|
+
<create>
|
|
624
|
+
<action name="setfldval" targetfld="IDPEDIDO" sourcefld="ID" />
|
|
625
|
+
</create>
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
> **REGLA:** Toda coleccion padre que tenga un `<contents>` debe tener un evento `<delete>` con `executesql` para borrar los registros hijos cuando se borre el padre.
|
|
629
|
+
|
|
630
|
+
#### Macro `##OWNERCOLL##` — Contents reutilizables
|
|
631
|
+
|
|
632
|
+
Cuando una misma coleccion hija puede usarse como contents para varias colecciones padre diferentes, se usa `##OWNERCOLL##` en el `mapcol` del campo FK de la coleccion hija. Sera sustituido automáticamente por el nombre de la coleccion padre que la use en cada caso.
|
|
633
|
+
|
|
634
|
+
```xml
|
|
635
|
+
<!-- Coleccion hija reutilizable -->
|
|
636
|
+
<coll name="Detalles" ...>
|
|
637
|
+
<prop name="IDDOCUMENTO" type="N" visible="0"
|
|
638
|
+
mapcol="##OWNERCOLL##" mapfld="ID" />
|
|
639
|
+
</coll>
|
|
640
|
+
|
|
641
|
+
<!-- Puede usarse desde Facturas Y desde Albaranes sin cambiar la definición -->
|
|
642
|
+
<coll name="Facturas" ...>
|
|
643
|
+
<prop name="@DETALLES" type="Z" contents="Detalles" />
|
|
644
|
+
<contents name="Detalles" src="Detalles" filter="IDDOCUMENTO=##ID##" />
|
|
645
|
+
</coll>
|
|
646
|
+
|
|
647
|
+
<coll name="Albaranes" ...>
|
|
648
|
+
<prop name="@DETALLES" type="Z" contents="Detalles" />
|
|
649
|
+
<contents name="Detalles" src="Detalles" filter="IDDOCUMENTO=##ID##" />
|
|
650
|
+
</coll>
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
### 6.10 Atributos del nodo `<contents>` y del `prop type="Z"`
|
|
656
|
+
|
|
657
|
+
#### Atributos del prop type="Z"
|
|
658
|
+
|
|
659
|
+
| Atributo | Descripción |
|
|
660
|
+
|----------|-------------|
|
|
661
|
+
| `contents` | Nombre del nodo `<contents>` asociado |
|
|
662
|
+
| `width` / `height` | Dimensiones del área del contents |
|
|
663
|
+
| `locked` | `true` impide la edición de registros |
|
|
664
|
+
| `edit-inrow` | `true` edita el registro en la misma fila del listado (por defecto `true`) |
|
|
665
|
+
| `editmodal` | `true` al hacer doble click abre el registro en una ventana separada |
|
|
666
|
+
| `forceonchange` | `true` fuerza el refresco al volver de la ventana de edición |
|
|
667
|
+
| `mask` | Bitmask de operaciones permitidas: 1=nuevo, 2=editar, 4=borrar, 8=filtro, 16=salir |
|
|
668
|
+
| `disableedit` | Deshabilita edición si se cumple la condición |
|
|
669
|
+
| `disablevisible` | Oculta el contents si se cumple la condición |
|
|
670
|
+
| `filter` | Filtro adicional aplicado al contents en tiempo de ejecución |
|
|
671
|
+
| `viewmode` | Modo de visualizacion (ver sección 7.13 para la lista completa) |
|
|
672
|
+
|
|
673
|
+
#### Atributos del nodo `<contents>`
|
|
674
|
+
|
|
675
|
+
| Atributo | Descripción |
|
|
676
|
+
|----------|-------------|
|
|
677
|
+
| `name` | Nombre del contents, debe coincidir con el atributo `contents` del prop Z |
|
|
678
|
+
| `src` | Nombre de la coleccion de datos que alimenta este contents |
|
|
679
|
+
| `filter` | Filtro de registros. Usar `##ID##` para el ID del objeto padre, `##FLD_CAMPO##` para campos del padre |
|
|
680
|
+
| `disableedit` | Deshabilita edición si se cumple la condición |
|
|
681
|
+
| `disablevisible` | Oculta el contents si se cumple la condición |
|
|
682
|
+
| `sort` | Ordenacion de los registros del contents |
|
|
683
|
+
|
|
684
|
+
---
|
|
685
|
+
|
|
686
|
+
### 6.11 Modos de Edición del Contents
|
|
687
|
+
|
|
688
|
+
#### Edición directa (por defecto)
|
|
689
|
+
|
|
690
|
+
Al tocar un elemento del contents, se abre el objeto en edición. Es el comportamiento por defecto.
|
|
691
|
+
|
|
692
|
+
```xml
|
|
693
|
+
<prop name="@content1" type="Z" contents="content1"
|
|
694
|
+
height="96%" width="100%" bgcolor="#FFFFFF" />
|
|
695
|
+
<contents name="content1" src="MiColeccion" filter="IDPADRE=##ID##" />
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
#### Edición en la fila (`edit-inrow="true"`)
|
|
699
|
+
|
|
700
|
+
El registro se edita directamente en la misma fila del listado, sin abrir una ventana nueva.
|
|
701
|
+
|
|
702
|
+
```xml
|
|
703
|
+
<prop name="@content2" type="Z" contents="content2"
|
|
704
|
+
edit-inrow="true" mask="0" height="75%" width="100%" />
|
|
705
|
+
<contents name="content2" src="MiColeccion" filter="IDPADRE=##ID##" />
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
#### Edición con `selecteditem`
|
|
709
|
+
|
|
710
|
+
Se programa lo que ocurre al seleccionar un elemento. Útil para lógica personalizada al seleccionar.
|
|
711
|
+
|
|
712
|
+
```xml
|
|
713
|
+
<!-- En la coleccion padre -->
|
|
714
|
+
<prop name="@content3" type="Z" contents="content3"
|
|
715
|
+
disableedit="1=1" height="70%" width="100%" />
|
|
716
|
+
<contents name="content3" src="MiColeccion" filter="IDPADRE=##ID##" />
|
|
717
|
+
|
|
718
|
+
<!-- En la coleccion hija (MiColeccion) -->
|
|
719
|
+
<selecteditem refresh="false" show-wait-dialog="false">
|
|
720
|
+
<action name="runscript">
|
|
721
|
+
<script language="javascript">
|
|
722
|
+
// self es el objeto seleccionado
|
|
723
|
+
// getParent() devuelve el objeto padre
|
|
724
|
+
self.getParent().MAP_SELECCIONADO = self.NOMBRE;
|
|
725
|
+
ui.refresh("MAP_SELECCIONADO");
|
|
726
|
+
</script>
|
|
727
|
+
</action>
|
|
728
|
+
</selecteditem>
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
#### Filtro y multiseleccion
|
|
732
|
+
|
|
733
|
+
Para permitir filtrar el contents dinámicamente y seleccionar multiples registros:
|
|
734
|
+
|
|
735
|
+
```xml
|
|
736
|
+
<!-- Campo de texto para filtrar -->
|
|
737
|
+
<prop name="MAP_BUSCAR" type="T" visible="1" labelwidth="0"
|
|
738
|
+
onchange="javascript:filtrarContent();" />
|
|
739
|
+
|
|
740
|
+
<!-- Contents con filtro dinámico usando ##FLD_MAP_BUSCAR## -->
|
|
741
|
+
<prop name="@contentFiltro" type="Z" contents="contentFiltro"
|
|
742
|
+
edit-inrow="true" mask="0" forceonchange="true"
|
|
743
|
+
onchange="Refresh" editmodal="true" />
|
|
744
|
+
<contents name="contentFiltro" src="MiColeccion"
|
|
745
|
+
filter="NOMBRE LIKE ##FLD_MAP_BUSCAR##" />
|
|
746
|
+
|
|
747
|
+
<!-- En la coleccion hija: campo NC para multiseleccion -->
|
|
748
|
+
<prop name="MAP_SELECTED" type="NC" visible="4" labelwidth="0"
|
|
749
|
+
width="10%" height="60p" newline="false" />
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
**JavaScript para recargar el contents al cambiar el filtro:**
|
|
753
|
+
|
|
754
|
+
```javascript
|
|
755
|
+
function filtrarContent() {
|
|
756
|
+
var coll = self.getContents("contentFiltro");
|
|
757
|
+
coll.clear();
|
|
758
|
+
coll.loadAll();
|
|
759
|
+
ui.refresh("@contentFiltro");
|
|
760
|
+
}
|
|
761
|
+
```
|
|
762
|
+
|