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,422 @@
|
|
|
1
|
+
# XOne JavaScript — ui: navegación, mensajes y vista
|
|
2
|
+
|
|
3
|
+
> Fuente: `xone/v2/xone-help-docs/topics/03b-js-ui.md` §3.1–§3.4. Referencia de la skill; el índice está en [../../SKILL.md](../../SKILL.md).
|
|
4
|
+
|
|
5
|
+
Contenido: §3.1 navegación (openEditView, openMenu) · §3.2 mensajes y diálogos (msgBox, showToast, showSnackbar) · §3.3 refrescar y acceder a controles, showcase · §3.4 date/time pickers
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
### 3.1 Navegación
|
|
10
|
+
|
|
11
|
+
`ui.openEditView()` es el mecanismo principal de navegación en XOne. Sirve tanto para "abrir una pantalla" como para "editar un objeto existente":
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
// === Abrir una pantalla (la forma habitual) ===
|
|
15
|
+
// Firma: ui.openEditView(target, [exit])
|
|
16
|
+
// target : dataObject | string — un dataObject ya preparado, o el nombre de la coll destino
|
|
17
|
+
// exit : boolean — si true, cierra la vista origen al abrir la nueva (default false)
|
|
18
|
+
|
|
19
|
+
// Forma corta: pasar el nombre de la coll. XOne crea internamente un dataObject
|
|
20
|
+
// vacío de esa coll (createObject + addItem) y abre su vista de edición.
|
|
21
|
+
ui.openEditView("Productos");
|
|
22
|
+
|
|
23
|
+
// Pasar un objeto NUEVO con datos pre-rellenados
|
|
24
|
+
let coll = appData.getCollection("Productos");
|
|
25
|
+
let obj = new Productos({ MAP_CATEGORIA_ID: idCategoria });
|
|
26
|
+
coll.addItem(obj);
|
|
27
|
+
ui.openEditView(obj);
|
|
28
|
+
|
|
29
|
+
// Abrir un objeto EXISTENTE recuperado de la BD
|
|
30
|
+
let producto = appData.getCollection("Productos").findObject("ID = " + nId);
|
|
31
|
+
if (producto) {
|
|
32
|
+
ui.openEditView(producto);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Cerrar la vista origen al abrir la nueva (flujos lineales sin botón atrás)
|
|
36
|
+
ui.openEditView(obj, true);
|
|
37
|
+
|
|
38
|
+
// === Obtener la ventana actual ===
|
|
39
|
+
let window = ui.getView(self); // Ventana del objeto actual
|
|
40
|
+
let window = ui.getView(); // Ventana actual sin parametro
|
|
41
|
+
|
|
42
|
+
// === Cerrar ventana actual ===
|
|
43
|
+
let window = ui.getView(self);
|
|
44
|
+
if (window) {
|
|
45
|
+
window.exit();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// === Cerrar la aplicación ===
|
|
49
|
+
appData.exit();
|
|
50
|
+
|
|
51
|
+
// === Mostrar/ocultar grupos (tabs) ===
|
|
52
|
+
ui.showGroup(2); // Mostrar grupo por indice
|
|
53
|
+
|
|
54
|
+
// Con animacion
|
|
55
|
+
ui.showGroup(2, "##ALPHA_IN##", 200, "##ALPHA_OUT##", 200);
|
|
56
|
+
|
|
57
|
+
// Ejemplo real: navegacion entre paginas con animacion
|
|
58
|
+
function mostrarGrupo(nGroup, sAnimIn, sAnimOut) {
|
|
59
|
+
sAnimIn = sAnimIn || "##ALPHA_IN##";
|
|
60
|
+
sAnimOut = sAnimOut || "##ALPHA_OUT##";
|
|
61
|
+
ui.showGroup(nGroup, sAnimIn, 200, sAnimOut, 200);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Animaciones predefinidas disponibles:**
|
|
66
|
+
|
|
67
|
+
| Constante | Descripción |
|
|
68
|
+
|-----------|-------------|
|
|
69
|
+
| `##ALPHA_IN##` / `##ALPHA_OUT##` | Entrada/salida con fundido |
|
|
70
|
+
| `##ZOOM_IN##` / `##ZOOM_OUT##` | Entrada/salida con zoom |
|
|
71
|
+
| `##LEFT_IN##` / `##LEFT_OUT##` | Deslizar desde/hacia la izquierda |
|
|
72
|
+
| `##RIGHT_IN##` / `##RIGHT_OUT##` | Deslizar desde/hacia la derecha |
|
|
73
|
+
| `##TOP_IN##` / `##TOP_OUT##` | Deslizar desde/hacia arriba |
|
|
74
|
+
| `##BOTTOM_IN##` / `##BOTTOM_OUT##` | Deslizar desde/hacia abajo |
|
|
75
|
+
|
|
76
|
+
#### Caso especial — abrir la LISTA de una coll directamente
|
|
77
|
+
|
|
78
|
+
`ui.openEditView()` siempre abre el EditView de un dataObject. Si lo que se necesita es lanzar directamente la **lista** de una coll como pantalla independiente (`MainListCollectionActivity` o `MainCalendarViewActivity` si tiene `viewmode="calendar"`), hay que recurrir al método legacy `ui.openMenu(collName, mask, mode)` con `mode=0`:
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
// Lista con todas las opciones del menú (mode=0, mask=0xFFFFFF)
|
|
82
|
+
ui.openMenu("Productos", 0xFFFFFF, 0);
|
|
83
|
+
|
|
84
|
+
// Lista en modo sólo lectura (mask = MENU_MASK_VIEW)
|
|
85
|
+
ui.openMenu("Productos", 0x000200, 0);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Constantes `mask` (combinables con OR — JavaScript NO expone los nombres, usar el valor numérico): `ADD=0x01`, `EDIT=0x02`, `DELETE=0x04`, `EXIT=0x08`, `FILTRAR=0x10`, `SAVE=0x40`, `SORT=0x80`, `REFRESH=0x100`, `VIEW=0x200`, `FULLMASK=0xFFFFFF`.
|
|
89
|
+
|
|
90
|
+
> Para el resto de necesidades de navegación (abrir una pantalla nueva, abrir un objeto existente, abrir un detalle desde un `<selecteditem>`) usar siempre `ui.openEditView()`. Habitualmente las "listas" en XOne se muestran como `<contents>` embebido en una pantalla padre, no como activity independiente — por eso `mode=0` se necesita poco.
|
|
91
|
+
|
|
92
|
+
### 3.2 Mensajes y Dialogos
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
// === Message Box clasico ===
|
|
96
|
+
// Tipo 0 = Solo botón OK
|
|
97
|
+
// Tipo 4 = Botones Si/No (retorna 6=Si, 7=No)
|
|
98
|
+
let nResult = ui.msgBox("Desea continuar?", "Confirmar", 4);
|
|
99
|
+
if (nResult == 6) {
|
|
100
|
+
// Usuario pulso Si
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// === Toast simple ===
|
|
104
|
+
ui.showToast("Mensaje rápido");
|
|
105
|
+
|
|
106
|
+
// === Toast personalizado ===
|
|
107
|
+
ui.showToast({
|
|
108
|
+
color : "#4CAF50", // Color de fondo
|
|
109
|
+
duration : "short", // "short" o "long"
|
|
110
|
+
text : "Guardado correctamente",
|
|
111
|
+
textColor: "#FFFFFF", // Color del texto
|
|
112
|
+
textFont : "Roboto-Regular.ttf", // Fuente (debe estar en fonts/)
|
|
113
|
+
textSize : 14, // Tamano de fuente
|
|
114
|
+
rounded : true // Esquinas redondeadas
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// === Snackbar simple (solo texto) ===
|
|
118
|
+
ui.showSnackbar("Registro eliminado"); // duración "long", texto blanco por defecto
|
|
119
|
+
|
|
120
|
+
// === Snackbar con acción ===
|
|
121
|
+
ui.showSnackbar({
|
|
122
|
+
text : "Registro eliminado", // OBLIGATORIO (vacío => excepción)
|
|
123
|
+
color : "#323232",
|
|
124
|
+
duration : "long", // "short" | "long" | "indefinite" (otro valor => excepción)
|
|
125
|
+
width : "80%", // "100%" => ancho completo
|
|
126
|
+
textColor : "#FFFFFF",
|
|
127
|
+
actionText : "Deshacer", // solo se muestra si TAMBIÉN hay actionMethod
|
|
128
|
+
actionTextColor: "#FFEB3B",
|
|
129
|
+
maxLines : 1, // solo aplica si > 1
|
|
130
|
+
align : "center|bottom",
|
|
131
|
+
height : "10%", // Altura del snackbar (opcional)
|
|
132
|
+
actionMethod : function() { // se ejecuta en un hilo aparte, no en el de UI
|
|
133
|
+
deshacerEliminacion();
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Ocultar snackbar manualmente (oculta el último mostrado; false si no hay ninguno visible)
|
|
138
|
+
ui.hideSnackbar();
|
|
139
|
+
|
|
140
|
+
// NOTA: showSnackbar solo funciona dentro de una pantalla de edición.
|
|
141
|
+
// En otros contextos lanza una excepción.
|
|
142
|
+
|
|
143
|
+
// === msgBox con DataObject (dialogo completamente personalizado) ===
|
|
144
|
+
|
|
145
|
+
// Variante SINCRONA: bloquea hasta que el usuario pulsa
|
|
146
|
+
// La coll debe tener botones con button-option="N"
|
|
147
|
+
// ui.msgBox() devuelve el valor del button-option del botón pulsado
|
|
148
|
+
let msgBoxObj = new MessageBoxNormal();
|
|
149
|
+
let nResult = ui.msgBox(msgBoxObj);
|
|
150
|
+
// nResult == 1 -> pulsó Cancel (button-option="1")
|
|
151
|
+
// nResult == 2 -> pulsó OK (button-option="2")
|
|
152
|
+
|
|
153
|
+
// Variante ASINCRONA con callbacks (no bloquea)
|
|
154
|
+
// La coll debe tener: hardware-accelerated="false", bgcolor="#00000000"
|
|
155
|
+
// y campos type="O" para los callbacks
|
|
156
|
+
function showMsgBoxAsync(callbackOk, callbackCancel) {
|
|
157
|
+
let obj = new MessageBoxAsync({ MAP_CALLBACK_OK: callbackOk, MAP_CALLBACK_CANCEL: callbackCancel });
|
|
158
|
+
ui.openEditView(obj);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Uso:
|
|
162
|
+
showMsgBoxAsync(
|
|
163
|
+
function() { ui.showToast("OK pulsado"); ui.getView(self).exit(); },
|
|
164
|
+
function() { ui.showToast("Cancel pulsado"); ui.getView(self).exit(); }
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
// === Wait Dialog (indicador de carga) ===
|
|
168
|
+
ui.showWaitDialog("Cargando datos...");
|
|
169
|
+
ui.setWaitDialogText("Procesando registros...");
|
|
170
|
+
ui.hideWaitDialog();
|
|
171
|
+
|
|
172
|
+
// === Notificaciones ===
|
|
173
|
+
// Notificación simple
|
|
174
|
+
ui.showNotification(1, "Titulo", "Texto de la notificación");
|
|
175
|
+
|
|
176
|
+
// Notificación con ticker
|
|
177
|
+
ui.showNotification(2, "Titulo", "Texto", "Texto en barra de estado");
|
|
178
|
+
|
|
179
|
+
// Notificación con callback al pulsar
|
|
180
|
+
ui.showNotification(3, "Titulo", "Texto", "Ticker", self, "miNodoCallback");
|
|
181
|
+
|
|
182
|
+
// Notificación avanzada con botones
|
|
183
|
+
ui.showNotification({
|
|
184
|
+
id : 5000,
|
|
185
|
+
title : "Nueva tarea asignada",
|
|
186
|
+
text : "Tiene una nueva tarea pendiente",
|
|
187
|
+
textHtml : "<b>Tarea urgente</b>: Revision de inventario",
|
|
188
|
+
icon : "app_icon1", // app_icon1 a app_icon10
|
|
189
|
+
largeIcon : "app_icon4",
|
|
190
|
+
backgroundColor: "#1976D2",
|
|
191
|
+
sound : "notification.wav",
|
|
192
|
+
cancelable : true,
|
|
193
|
+
dataObject : self,
|
|
194
|
+
nodeName : "callbackNotificacion",
|
|
195
|
+
parameters : '{ "tareaId": "123" }',
|
|
196
|
+
buttons : [{
|
|
197
|
+
id : 5001,
|
|
198
|
+
title : "Responder",
|
|
199
|
+
directReply : true,
|
|
200
|
+
directReplyLabel: "Escriba su respuesta...",
|
|
201
|
+
dataObject : self,
|
|
202
|
+
nodeName : "respuestaCallback"
|
|
203
|
+
}]
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// LED de notificación (solo Android)
|
|
207
|
+
ui.setNotificationLed("#00FF00", 1000, 1000); // color, onMs, offMs
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
#### msgBox con DataObject (Dialogos Personalizados)
|
|
211
|
+
|
|
212
|
+
`ui.msgBox(dataObject)` permite abrir una coleccion XOne como dialogo completamente personalizado.
|
|
213
|
+
|
|
214
|
+
**Variante sincrona** — Los botones usan `button-option`. `ui.msgBox()` bloquea hasta que el usuario pulsa y devuelve el valor del `button-option` pulsado:
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
let msgBoxObj = new MessageBoxNormal();
|
|
218
|
+
let nResult = ui.msgBox(msgBoxObj);
|
|
219
|
+
// nResult == 1 -> pulsó Cancel (button-option="1")
|
|
220
|
+
// nResult == 2 -> pulsó OK (button-option="2")
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
La coll `MessageBoxNormal` requiere: `notab="true"`, `show-toolbar="false"`, `check-owner="false"`, `dependent="false"`, y botones con `button-option="N"`.
|
|
224
|
+
|
|
225
|
+
**Variante asíncrona con callbacks** — Los botones invocan `self.MAP_CALLBACK_OK()`. Usa campos `type="O"` para las funciones callback:
|
|
226
|
+
|
|
227
|
+
```javascript
|
|
228
|
+
function showMessageBoxDataObject(callbackOk, callbackCancel) {
|
|
229
|
+
let newMsgBox = new MessageBoxAsync({ MAP_CALLBACK_OK: callbackOk, MAP_CALLBACK_CANCEL: callbackCancel });
|
|
230
|
+
ui.openEditView(newMsgBox);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Uso
|
|
234
|
+
showMessageBoxDataObject(
|
|
235
|
+
function() { ui.showToast("OK pulsado"); ui.getView(self).exit(); },
|
|
236
|
+
function() { ui.showToast("Cancel pulsado"); ui.getView(self).exit(); }
|
|
237
|
+
);
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
La coll `MessageBoxAsync` requiere además: `hardware-accelerated="false"` y `bgcolor="#00000000"` para fondo transparente sin fondo negro.
|
|
241
|
+
|
|
242
|
+
### 3.3 Vista - Refrescar y Acceder a Controles
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
// === Obtener la ventana actual ===
|
|
246
|
+
let window = ui.getView(self);
|
|
247
|
+
let window = ui.getView(); // Sin parametro = ventana activa actual
|
|
248
|
+
|
|
249
|
+
// === Acceder a un control por nombre ===
|
|
250
|
+
let control = window["MAP_BOTON"];
|
|
251
|
+
|
|
252
|
+
// === getControl(name, [dataObject]) - función NATIVA global (recomendado) ===
|
|
253
|
+
// Disponible directamente, NO hace falta declarar el helper. Devuelve el control
|
|
254
|
+
// resuelto en la ventana destino:
|
|
255
|
+
// - getControl(name) → última ventana visible.
|
|
256
|
+
// - getControl(name, dataObject) → ventana asociada a ese DataObject.
|
|
257
|
+
//
|
|
258
|
+
// Semántica ESTRICTA: lanza error si el nombre está vacío, el control no
|
|
259
|
+
// existe, no hay ventana destino, o el dataObject no es válido.
|
|
260
|
+
//
|
|
261
|
+
// Si un proyecto ya tiene "function getControl(...)" propia, esa sombrea a la
|
|
262
|
+
// nativa en su scope local (compatibilidad hacia atrás preservada).
|
|
263
|
+
let control = getControl("MAP_BOTON");
|
|
264
|
+
let controlEnOtraVentana = getControl("MAP_TITULO", objPadre);
|
|
265
|
+
|
|
266
|
+
// === Refrescar campos de la interfaz ===
|
|
267
|
+
ui.refresh(); // Refrescar TODO (costoso, evitar)
|
|
268
|
+
ui.refresh("MAP_NOMBRE"); // Refrescar un campo específico
|
|
269
|
+
ui.refresh("MAP_NOMBRE,MAP_ESTADO"); // Refrescar multiples campos
|
|
270
|
+
|
|
271
|
+
// Solo actualizar el valor (sin reconstruir la vista del control)
|
|
272
|
+
ui.refreshValue("MAP_CAMPO");
|
|
273
|
+
// Multiples campos (cada uno como argumento)
|
|
274
|
+
let ventana = ui.getView(self);
|
|
275
|
+
ventana.refreshValue("MAP_CAMPO1", "MAP_CAMPO2", "MAP_CAMPO3");
|
|
276
|
+
|
|
277
|
+
// Refrescar una fila específica de un content
|
|
278
|
+
ui.refreshContentRow("MAP_CONTENT", 0);
|
|
279
|
+
|
|
280
|
+
// Refrescar la fila seleccionada de un content
|
|
281
|
+
ui.refreshContentSelectedRow("MAP_CONTENT");
|
|
282
|
+
|
|
283
|
+
// Refrescar usando la ventana directamente
|
|
284
|
+
window.refresh("MAP_CAMPO");
|
|
285
|
+
window.refreshAll("frmMiFrame"); // Refresca el frame y todos sus hijos
|
|
286
|
+
|
|
287
|
+
// === Grupos (tabs) y Drawers ===
|
|
288
|
+
// Mostrar un grupo por indice
|
|
289
|
+
ui.showGroup(2);
|
|
290
|
+
ui.showGroup(2, "##ALPHA_IN##", 300, "##ALPHA_OUT##", 300); // Con animacion
|
|
291
|
+
|
|
292
|
+
// Comprobar si un grupo esta abierto (util para drawers)
|
|
293
|
+
if (window.isGroupOpen(999)) {
|
|
294
|
+
window.hideGroup(999); // Cerrar el drawer
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Patron: botón atrás cierra drawer antes de salir
|
|
298
|
+
function doOnBack() {
|
|
299
|
+
let window = ui.getView();
|
|
300
|
+
if (!window) return;
|
|
301
|
+
if (window.isGroupOpen(999)) {
|
|
302
|
+
window.hideGroup(999);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
window.exit();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// === Nombre de la coleccion activa ===
|
|
309
|
+
function getCurrentCollectionName() {
|
|
310
|
+
let window = ui.getView();
|
|
311
|
+
if (!window) return "";
|
|
312
|
+
let dataObject = window.getDataObject();
|
|
313
|
+
if (!dataObject) return "";
|
|
314
|
+
let coll = dataObject.getOwnerCollection();
|
|
315
|
+
if (!coll) return "";
|
|
316
|
+
return coll.getName();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// === Traer app al primer plano (desde handler de notificación) ===
|
|
320
|
+
ui.returnToForeground();
|
|
321
|
+
|
|
322
|
+
// === Scroll de Frames ===
|
|
323
|
+
let frame = window["frmScroll"];
|
|
324
|
+
frame.scrollToTop(true); // true = animado
|
|
325
|
+
frame.scrollToBottom(true);
|
|
326
|
+
|
|
327
|
+
// === Bottom Sheet ===
|
|
328
|
+
// sFrame: nombre del frame con behavior="bottom-sheet"
|
|
329
|
+
// sState: "expanded" / "collapsed" / "hidden"
|
|
330
|
+
// bLockDrag: true = impedir que el usuario lo arrastre
|
|
331
|
+
window.setBottomSheetState("mi_panel", "expanded", false);
|
|
332
|
+
window.setBottomSheetState("mi_panel", "collapsed", true); // Bloqueado
|
|
333
|
+
let sEstado = window.getBottomSheetState("mi_panel");
|
|
334
|
+
|
|
335
|
+
// === Progress Bar JS ===
|
|
336
|
+
let control = window["MAP_PROGRESS_BAR"];
|
|
337
|
+
control.setIndeterminate(true); // Activar animacion continua
|
|
338
|
+
control.setIndeterminate(false); // Desactivar, mostrar valor actual
|
|
339
|
+
control.toggleIndeterminate(); // Alternar estado
|
|
340
|
+
let bIndet = control.isIndeterminate();
|
|
341
|
+
|
|
342
|
+
// === Efectos visuales en frame: setBlur / setSaturation ===
|
|
343
|
+
// NO son API de XOne: los expone la vista nativa de Android/iOS que hay por debajo.
|
|
344
|
+
// Se llaman sobre el frame o el control, nunca sobre ui, y no hay ui.setBlur.
|
|
345
|
+
// Documentados en metodos-nativos-de-la-vista.md, con el envoltorio y el patron de slider.
|
|
346
|
+
|
|
347
|
+
// === Color de la barra de estado ===
|
|
348
|
+
window.setStatusBarColor("#1565C0"); // Color RRGGBB
|
|
349
|
+
window.setStatusBarColor(null); // Restaurar color por defecto
|
|
350
|
+
|
|
351
|
+
// === Showcase (tutorial interactivo) ===
|
|
352
|
+
window.startShowcase({
|
|
353
|
+
continueOnCancel: true, // Si cancela un paso, ir al siguiente
|
|
354
|
+
tapTargets: [{
|
|
355
|
+
target : "MAP_CAMPO1",
|
|
356
|
+
title : "Paso 1",
|
|
357
|
+
description : "Descripción del primer paso",
|
|
358
|
+
cancelable : true,
|
|
359
|
+
transparentTarget : true,
|
|
360
|
+
targetRadius : 90,
|
|
361
|
+
outerCircleOpacity : 96,
|
|
362
|
+
outerCircleColor : "#1565C0",
|
|
363
|
+
targetCircleColor : "#FF0000",
|
|
364
|
+
dimColor : "#CC000000",
|
|
365
|
+
titleTextSize : 20,
|
|
366
|
+
descriptionTextSize : 15,
|
|
367
|
+
textColor : "#FFFFFF",
|
|
368
|
+
titleTextColor : "#FFFF00",
|
|
369
|
+
descriptionTextColor: "#FFFFFF",
|
|
370
|
+
textFont : "MiFuente.ttf",
|
|
371
|
+
drawShadow : true
|
|
372
|
+
}, {
|
|
373
|
+
target : "MAP_CAMPO2",
|
|
374
|
+
title : "Paso 2",
|
|
375
|
+
description: "Segundo paso del tutorial",
|
|
376
|
+
cancelable : true
|
|
377
|
+
}]
|
|
378
|
+
});
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### 3.4 Date/Time Pickers
|
|
382
|
+
|
|
383
|
+
```javascript
|
|
384
|
+
// Date Picker con callback
|
|
385
|
+
ui.showDatePicker({
|
|
386
|
+
initialYear : 2024,
|
|
387
|
+
initialMonth: 6,
|
|
388
|
+
initialDay : 15,
|
|
389
|
+
title : "Seleccione fecha",
|
|
390
|
+
theme : "holo_light", // Tema visual del picker
|
|
391
|
+
onDateSet : function(nYear, nMonth, nDay) {
|
|
392
|
+
self.MAP_FECHA = nDay + "/" + nMonth + "/" + nYear;
|
|
393
|
+
ui.refresh("MAP_FECHA");
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// Date Picker que escribe directamente en un campo (sin callback)
|
|
398
|
+
ui.showDatePicker({
|
|
399
|
+
targetProperty: "MAP_FECHA" // El picker escribe aquí al confirmar
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Time Picker con callback
|
|
403
|
+
ui.showTimePicker({
|
|
404
|
+
initialHour : 17,
|
|
405
|
+
initialMinute: 30,
|
|
406
|
+
is24HoursMode: true,
|
|
407
|
+
title : "Seleccione hora",
|
|
408
|
+
theme : "holo_light",
|
|
409
|
+
onTimeSet : function(nHours, nMinutes) {
|
|
410
|
+
let h = ("0" + nHours).slice(-2);
|
|
411
|
+
let m = ("0" + nMinutes).slice(-2);
|
|
412
|
+
self.MAP_HORA = h + ":" + m;
|
|
413
|
+
ui.refresh("MAP_HORA");
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// Time Picker que escribe directamente en un campo
|
|
418
|
+
ui.showTimePicker({
|
|
419
|
+
targetProperty: "MAP_HORA"
|
|
420
|
+
});
|
|
421
|
+
```
|
|
422
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Resumen por capa: JavaScript, datos y dispositivo
|
|
2
|
+
|
|
3
|
+
> Referencia de `xone-development`. Sale del `SKILL.md` para que las reglas
|
|
4
|
+
> duras quepan en una lectura por omisión (100 líneas).
|
|
5
|
+
|
|
6
|
+
## JavaScript
|
|
7
|
+
|
|
8
|
+
JavaScript ejecutado en bloques `<script>` de los `.xne` y en `functions.js`. No es JavaScript de navegador ni de Node: no hay módulos (`require`/`import`) y el código compartido es global. Los LLMs inventan sistemáticamente `self.lock()`, `ui.startChronometer()` y variantes de `setCircularReveal` que no existen.
|
|
9
|
+
|
|
10
|
+
**Objetos globales.** `self` (DataObject actual, alias `dataobject`) · `selfDataColl` (su colección, alias `datacollection`) · `ui` · `appData` (alias `appdata`) · `err` (alias `error`) · `user`.
|
|
11
|
+
|
|
12
|
+
Singletons de acceso directo, **sin `new`**: `$http`, `crypto`, `clipboard`, `deviceInfo`, `systemSettings`, `packageManager`, `biometricsManager`, `fingerprintManager`, `bleManager`, `sensorManager`, `paymentManager`, `pushMessage`, `appBroadcastManager`, `replica`, `live`, `smsService`, `serial`, `bluetoothSerial`, `bleSerial`, `ml`, `ai`.
|
|
13
|
+
|
|
14
|
+
Objetos que se crean con `new` (o `createObject`): `FileManager`, `GpsTools`, `SqlManager`, `IniParser`, `EncodingUtils`, `AndroidIntent`, `DeviceManager`, `WifiManager`, `BluetoothSerialPort`, `OAuth2`, `Worker`, `Animation`, `Socket`, `WebSocket`, `DebugTools`, `IrManager`, `SoundManager`, `VibrationManager`, `WearableConnection`, `AccountManager`, `XOneNFC`, `ImageDrawing`, `BarcodeGenerator`, `XOnePrinter`, `XOnePDF`, `XOneOCR`, `XOneSigner` y los demás de la lista canónica.
|
|
15
|
+
|
|
16
|
+
**Acceso a datos.** `self.CAMPO`, `self["CAMPO"]` y `self.getValue("CAMPO")` son válidos. **`self("CAMPO")` no existe**: la notación de `self` como función no es parte del motor.
|
|
17
|
+
|
|
18
|
+
**Controles.** `getControl(name, [dataObject])` es una **función nativa global** del motor (Rhino y V8), no un método de `ui`. Con un solo argumento usa la última ventana visible; con `dataObject`, la ventana asociada a ese objeto. Lanza error si el nombre está vacío, si el control no existe en la ventana destino, si no hay ventana o si el `dataObject` no es válido. Si el proyecto define su propia `function getControl(...)`, esa sombrea a la nativa en su ámbito local.
|
|
19
|
+
|
|
20
|
+
Los métodos específicos (`getValue`/`setValue`/`setMin`/`setMax`/`setStepSize` de un stepper, `getOtpValue`/`clearOtp`/`focusOtp` de un OTP, `startChronometer`/`stopChronometer`) son métodos **del control**, no de `ui`.
|
|
21
|
+
|
|
22
|
+
**Patrones críticos.** Modifica colecciones dentro de `unlock()` y devuelve el estado con `lock()` en `finally`. `lock()` activa el modo solo lectura: con la bandera activa, `clear()` y `loadAll()` son no-op. Las colecciones nacen desbloqueadas, pero el convenio es dejarlas bloqueadas tras operar para que código posterior no las mute por accidente.
|
|
23
|
+
|
|
24
|
+
- `lock()`/`unlock()` son métodos de la **colección**, nunca de `self`. Para bloquear la de un contents: `self.getContents("X").unlock()`.
|
|
25
|
+
- Navega con `startBrowse()` y `endBrowse()` en `finally`. Para contents: `getContents(nombre)` → `unlock` → `createObject`/`addItem` → `lock` → `saveAll`. Cierra siempre cursores y conexiones SQL. Un `WaitDialog` abierto va dentro de `try/finally`.
|
|
26
|
+
- En callbacks asíncronos (`$http`, WebSocket, GPS) guarda el contexto **antes** de la llamada: `var miSelf = self;`.
|
|
27
|
+
- Para crear objetos, el patrón preferido es `new NombreColeccion({ PROP: valor })` (el parámetro es opcional). `coll.createObject()` queda para contents anidados —vincula al padre— o cuando el nombre de la colección es dinámico.
|
|
28
|
+
|
|
29
|
+
**APIs web y sus equivalentes.**
|
|
30
|
+
|
|
31
|
+
| API web | Equivalente XOne |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `document.getElementById("X")` | `ui.getView(self)["X"]` o `getControl("X")` |
|
|
34
|
+
| `window.location` / `window.history` | `ui.openEditView("Coll")`, `ui.getView(self).exit()` |
|
|
35
|
+
| `localStorage` | `appData.getGlobalMacro("##X##")` / `setGlobalMacro` |
|
|
36
|
+
| `sessionStorage` | `coll.setVariable`/`getVariable` o variables de empresa |
|
|
37
|
+
| `new XMLHttpRequest()` | `$http.get(url, request, success, error)` |
|
|
38
|
+
| `alert` / `confirm` / `prompt` | `ui.msgBox(msg, título, 0)` o `ui.showToast(msg)` |
|
|
39
|
+
| `navigator.geolocation.getCurrentPosition` | `ui.startGps({nodeName: "callbackgps"})` |
|
|
40
|
+
| `require()` / `import` | `<include file="..."/>` o `<script src="..."/>` en `<app>`; dinámico solo con `appData.loadIncludeFile(...)` |
|
|
41
|
+
|
|
42
|
+
## Datos e integración
|
|
43
|
+
|
|
44
|
+
**Modelo local.** La BD es `gestion.db`, normalmente bajo `bd/`, y las tablas suelen llevar prefijo `gen_` en minúsculas. Usa siempre `##PREF##`, nunca el prefijo literal. Cada registro replicable tiene `ROWID` como GUID hexadecimal de 32 caracteres sin guiones, declarado `type="T" fieldsize="32"`. Las colecciones con `objname`/`updateobj` generan tabla; si falta, regenera con `python3 -m xone_db_generator mi_proyecto --overwrite`.
|
|
45
|
+
|
|
46
|
+
Macros habituales: `##PREF##`, `##ENTID##`, `##USERID##`, `##NOW##`, `##NOW_DATE##`, `##NOW_TIME##`, `##FLD_CAMPO##`. Guarda y restaura filtros con `try/finally` y limpia la colección antes de recargar.
|
|
47
|
+
|
|
48
|
+
**Seguridad.**
|
|
49
|
+
|
|
50
|
+
- Parametriza SQL: `sqlManager.doRawQuery("… WHERE ID=?", id)`. Nunca concatenes entrada de usuario. Si un filtro exige texto, escapa `'` como `''`; valida los numéricos antes de concatenar.
|
|
51
|
+
- Cierra cursor y conexión en `finally`.
|
|
52
|
+
- HTTPS siempre, con `allowUnsafeCertificates: false` en producción. Pinning con `enablePinning`/`allowedRootCas`; mTLS con `privateKey`/`certificateChain`.
|
|
53
|
+
- No hardcodees ni registres credenciales. Cifra los tokens antes de guardarlos en macros globales y límpialos al cerrar sesión.
|
|
54
|
+
- Valida obligatorios, longitud, rangos y formato antes de `save()`: un obligatorio vacío produce `-8100`.
|
|
55
|
+
|
|
56
|
+
**Integración y réplica.** `$http` devuelve respuestas string y futures cancelables: parsea con `try/catch`, preserva `self` antes del callback y cancela la búsqueda anterior antes de lanzar otra. OAuth2 se usa con `new OAuth2()`. `replica.processReplicatorQueue` sincroniza por `ROWID`; la configuración programada vive en el evento `maintenance` de `Empresas`. El error `-11888` con `##EXIT##` cierra la pantalla y con `##EXITAPP##` cierra la aplicación.
|
|
57
|
+
|
|
58
|
+
Para almacenamiento clave-valor, el equivalente de `localStorage` es `appData.setGlobalMacro`/`getGlobalMacro`; para datos de sesión, variables de colección (`setVariable`/`getVariable`).
|
|
59
|
+
|
|
60
|
+
Los **eventos** implicados en la sincronización y el provisionamiento (`maintenance`, `sys-message` con sus códigos detallados, eventos de réplica) están documentados en [eventos de sistema, login y personalizados](references/xml-ui/eventos-sistema-login-y-personalizados.md), porque se declaran en el XML.
|
|
61
|
+
|
|
62
|
+
Para probar integraciones sin backend, usa `mock/http.json` con `xone-simulator` (skill `xone-review`).
|
|
63
|
+
|
|
64
|
+
## Dispositivo
|
|
65
|
+
|
|
66
|
+
`xone-simulator` reproduce muchas capacidades con `mock/device.json` (skill `xone-review`).
|
|
67
|
+
|
|
68
|
+
- Pide y comprueba permisos antes de GPS, cámara, micrófono o biometría. Los permisos se solicitan con `systemSettings.requestPermissions`, que devuelve un future. En el simulador se conceden automáticamente.
|
|
69
|
+
- Declara los permisos que use la app en el nodo `<permissions>`: `location-foreground`, `location-background`, `camera`, `notifications`, `contacts`…
|
|
70
|
+
- GPS: `ui.startGps()` antes de leer la colección de GPS; recórrela con `startBrowse`/`endBrowse`, comprueba `STATUS == 1` y que `LONGITUD` no esté vacío. `ui.checkGpsStatus()` devuelve `0` sin hardware, `1` solo GPS, `2` solo redes, `3` ninguno y `4` GPS y redes.
|
|
71
|
+
- La colección de GPS (`GPSColl`/`GpsCollection`) **la declara el proyecto** con el connector GPS: no es built-in de XOne.
|
|
72
|
+
- En callbacks de cámara, GPS y escáner conserva `self` antes de la operación y refresca solo los campos modificados.
|
|
73
|
+
- Cierra Bluetooth y WebSocket al terminar. Prefiere `ui.executeActionAfterDelay()` (segundos) a una espera bloqueante.
|
|
74
|
+
- `biometricsManager` es el singleton actual; `fingerprintManager` es legacy.
|
|
75
|
+
- La firma se hace con `<prop type="DR">` (`stroke-color`, `stroke-width`, `apply-format-to-file`, `ui.saveDrawing`, `ui.clearDrawing`). `type="IMG" readonly="false"` es la forma **obsoleta**.
|
|
76
|
+
- En archivos, comprueba `fileExists(...) === 0`; `saveFile(..., false)` sobrescribe.
|
|
77
|
+
|
|
78
|
+
Del registro de GPS se leen `LATITUD`, `LONGITUD`, `ALTITUD`, `VELOCIDAD`, `RUMBO`, `FGPS`, `HGPS`, `STATUS`, `SATELITES`, `FUENTE`, `PRECISION` y el campo `FAKE`. Para cálculos hay `GpsTools` (`distanceBetweenCoordinates`, `getPositionFromAddress`, encode/decode, `simplifyPolyline`, `addExifLocationToFile`, `routeTo`).
|
|
79
|
+
|
|
80
|
+
Los métodos de los controles de cámara, vídeo, dibujo y escáner están en [métodos de los controles](references/javascript/metodos-de-los-controles.md). Los atributos XML de esos props, en [atributos-prop.md](references/xml-ui/atributos-prop.md).
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Resumen por capa: XML y CSS
|
|
2
|
+
|
|
3
|
+
> Referencia de `xone-development`. Sale del `SKILL.md` para que las reglas
|
|
4
|
+
> duras quepan en una lectura por omisión (100 líneas).
|
|
5
|
+
|
|
6
|
+
## Estructura XML
|
|
7
|
+
|
|
8
|
+
Capa declarativa de XOne: ficheros `.xne`, jerarquía `coll > group > frame > prop`, `contents`, macros, eventos y permisos. Antes de proponer código, inspecciona los `.xne` y el CSS del proyecto para respetar sus convenciones.
|
|
9
|
+
|
|
10
|
+
- Jerarquía: `coll > group > frame > prop`. Un `<prop>` vive dentro de un `<group>` o de un `<frame>`.
|
|
11
|
+
- Una coll de datos lleva `sql`, `objname` y `updateobj`, y usa `##PREF##` como prefijo de tabla: `sql="SELECT ID, NOMBRE FROM ##PREF##Clientes"`.
|
|
12
|
+
- Una pantalla sin datos (menú, login) usa `special="true"` y **no** lleva `sql`. Son excluyentes.
|
|
13
|
+
- `<prop>` tiene dos atributos obligatorios: `name` y `type`.
|
|
14
|
+
- `notab="true"` cuando solo hay un grupo visible.
|
|
15
|
+
- El splash es un **fichero estático en la raíz** (`splash.png`/`.jpg`/`.gif`/`.webp`/`.apng`/`.mp4`/`.3gp`) que carga el framework. No es una `<coll>`, no es `EntradaApp` (pantalla post-login), y no es `load-imgbk` del `<app>` (fondo del EditView).
|
|
16
|
+
|
|
17
|
+
**Combo y selector.** Un combo **no tiene tipo propio**: son dos props vinculados, uno oculto con el ID y otro visible con la descripción. Para valores fijos sin tabla, `mapcol-values` en el prop oculto. `mapcol` debe apuntar a una coll existente, y `mapfld`/`linkedfield` a campos reales de esa coll: `xone-simulator` lo valida.
|
|
18
|
+
|
|
19
|
+
**Contents y listas.**
|
|
20
|
+
|
|
21
|
+
- El `name` del contents lleva prefijo `@`; sin él no vincula.
|
|
22
|
+
- `src` es obligatorio y apunta a una coll existente. `filter` y `sort` son opcionales.
|
|
23
|
+
- Filtros dinámicos por el objeto padre con `##FLD_CAMPO##`, p. ej. `filter="IDPADRE=##FLD_IDPADRE##"`.
|
|
24
|
+
- Un mapa es `type="Z" viewmode="mapview"` vinculado a un `<contents>`, no un tipo inventado.
|
|
25
|
+
|
|
26
|
+
**Layout.** Los elementos son `newline="true"` por defecto y se apilan. Para ponerlos en la misma fila, `newline="false"` va en el **segundo y siguientes**; el primero de la fila nunca lo lleva. Si el primer elemento de un `<frame>` lleva `newline="false"`, el frame entero puede no montarse y sus controles desaparecen de la pantalla. Dimensiones en `p` o `%`, nunca `px`/`em`/`rem`.
|
|
27
|
+
|
|
28
|
+
**Macros.** `##PREF##` prefijo de tablas · `##FLD_CAMPO##` valor del campo del objeto padre en un contents · macros del sistema como `##NOW_TIME##`, `##USERID##`, `##DEVICE_OS##`, `##DEVICE_TYPE##`, `##CURRENT_ORIENTATION##`, `##FRAME_VERSION_CODE##`.
|
|
29
|
+
|
|
30
|
+
Una macro de colección debe declararse en el XML antes de usarla: `<macro name="##NOMBRE##" value="..." default="true" />` como hijo directo de `<coll>`, al mismo nivel que los `<group>`. Sin esa declaración, `setMacro` no inyecta nada en el SQL. La API es `setMacro`/`getMacro`; `coll.macro(...)` no existe.
|
|
31
|
+
|
|
32
|
+
## CSS
|
|
33
|
+
|
|
34
|
+
Sistema de estilos propietario, con sintaxis parecida a CSS web pero atributos propios. Antes de editar, lee el `default.css` del proyecto y respeta sus convenciones de nombres de clase.
|
|
35
|
+
|
|
36
|
+
**Archivos.** `default.css` en la raíz del proyecto es obligatorio y es el único que se declara en `app.xml`: `<style url="default.css" encoding="UTF-8" />`. Las variantes se cargan automáticamente por convención de nombre.
|
|
37
|
+
|
|
38
|
+
Si el atributo `compatibility-mode` del nodo `<app>` vale `true`, **el CSS se ignora por completo** — compruébalo antes de diagnosticar cualquier estilo que «no se aplica».
|
|
39
|
+
|
|
40
|
+
> **El TEMA OSCURO está sin definir, y hasta que se defina no se genera.** El corpus escribe el
|
|
41
|
+
> nombre del fichero de variante de dos formas incompatibles —con guion bajo
|
|
42
|
+
> (`default_night.css`) y con punto (`default.night.css`)—, y en los proyectos reales de
|
|
43
|
+
> referencia no existe ninguno de los dos: lo que hay son variantes con guion normal
|
|
44
|
+
> (`default-ios.css`, `default-colors.css`). Como el framework carga estas variantes **por
|
|
45
|
+
> convención de nombre**, un nombre equivocado no da error: el fichero no se carga y la app
|
|
46
|
+
> se ve en claro sin que nada lo diga. **Decisión del proyecto (2026-08-29): no proponer ni
|
|
47
|
+
> generar el fichero de tema oscuro hasta fijar su nombre.** Los ejemplos de tema que quedan
|
|
48
|
+
> en las referencias de CSS ilustran la CASCADA, no el nombre — no los copies como ruta.
|
|
49
|
+
|
|
50
|
+
**Cascada.** De menor a mayor prioridad: `default.css` → plataforma → orientación → tema → condiciones combinadas → **atributos inline en XML** (máxima prioridad). Lo más específico gana atributo por atributo, no bloque por bloque.
|
|
51
|
+
|
|
52
|
+
**Selectores.** Solo estos: `coll`, `prop`, `prop:TYPE` (`prop:T`, `prop:N`, `prop:B`, `prop:NC`, `prop:Z`, `prop:IMG`, `prop:D`…), `group`, `frame` y `.clase`. Las clases se asignan con `class="..."` en el XML.
|
|
53
|
+
|
|
54
|
+
**Unidades.**
|
|
55
|
+
|
|
56
|
+
- `p` para dimensiones absolutas, `%` relativo al contenedor.
|
|
57
|
+
- Sin unidad: `fontsize`, `border-corner-radius`, `border-width`, `labelwidth`, `lines`, `visible`, `gallery-columns`, `img-width`, `img-height`.
|
|
58
|
+
- Prohibidas: `px`, `em`, `rem`, `vw`, `vh`, `vmin`, `vmax`.
|
|
59
|
+
|
|
60
|
+
**Colores.** `#RRGGBB` o ARGB `#AARRGGBB`. **El alpha va primero**, al contrario que el `#RRGGBBAA` de CSS web.
|
|
61
|
+
|
|
62
|
+
**Herencia.** Dos mecanismos equivalentes: el atributo `extends: .claseBase;` y la at-rule `@extend selector;`. Diferencia relevante: `@extend` detecta ciclos en tiempo de parseo (auto-referencia, 2 vías y N vías) y admite referencias adelantadas; `extends:` no detecta ciclos automáticamente. En un proyecto que ya usa `extends:`, mantén `extends:` por consistencia.
|
|
63
|
+
|
|
64
|
+
**Funciones del parser.**
|
|
65
|
+
|
|
66
|
+
**Sí soportadas:** comentarios `/* */` y `//`; `@import "ruta";` (solo al inicio del archivo); variables CSS en `:root` o locales de bloque, con `var(--nombre)` y `var(--nombre, fallback)`; `calc()` con `+ - * /`, paréntesis y `-` unario sobre números puros; `!important`; `!default`; selectores múltiples `a, b, c { }`.
|
|
67
|
+
|
|
68
|
+
**No soportadas:** `min()`, `max()`, `clamp()`, `@media`, pseudo-clases (`:hover`, `:focus`, `:active`, `:nth-child`), pseudo-elementos (`::before`, `::after`), selectores de atributo (`[data-attr]`), combinadores (`>`, `+`, `~`, descendiente), `transition`, `transform`, Flexbox, CSS Grid, `box-shadow`, `text-shadow` y gradientes.
|
|
69
|
+
|
|
70
|
+
Para sombras usa `elevation` y `shadow-color`. No hay abreviados `margin` ni `padding`: usa `tmargin`, `bmargin`, `lmargin`, `rmargin` y sus equivalentes `*padding`.
|
|
71
|
+
|
|
72
|
+
**Estilos dinámicos.** No existe selector condicional puro. Dos vías: tokens `##FLD_CAMPO##` en el valor (funcionan en CSS y en atributos inline XML) y cambio de clase desde JavaScript en tiempo de ejecución.
|
|
73
|
+
|
|
74
|
+
Si un estilo no se aplica, empieza por `compatibility-mode`; el resto de síntomas está en la skill `xone-debugging`.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Tipos de `prop` válidos
|
|
2
|
+
|
|
3
|
+
> Referencia de `xone-development`. Sale del `SKILL.md` para que las reglas
|
|
4
|
+
> duras quepan en una lectura por omisión (100 líneas).
|
|
5
|
+
|
|
6
|
+
## Tipos de prop válidos
|
|
7
|
+
|
|
8
|
+
| Tipo | Descripción |
|
|
9
|
+
|---|---|
|
|
10
|
+
| `T` | Texto editable |
|
|
11
|
+
| `TN` / `TN2`…`TN6` | Texto numérico; el sufijo son los decimales visibles |
|
|
12
|
+
| `L` | Etiqueta de solo lectura. Sin `title`, muestra el valor del campo |
|
|
13
|
+
| `TL` | Alias legacy de `L` |
|
|
14
|
+
| `THTML` | Texto con formato HTML |
|
|
15
|
+
| `N` / `N2`…`N6` | Número; el sufijo son los decimales visibles |
|
|
16
|
+
| `D` / `DT` / `TT` | Fecha / fecha y hora / solo hora |
|
|
17
|
+
| `B` | Botón |
|
|
18
|
+
| `NC` | Checkbox, toggle, radio o switch |
|
|
19
|
+
| `X` | Password enmascarado |
|
|
20
|
+
| `IMG` / `PH` | Imagen referenciada / foto capturable |
|
|
21
|
+
| `VD` | Vídeo o escáner QR/barcode |
|
|
22
|
+
| `DR` | Dibujo o firma digital |
|
|
23
|
+
| `Z` | Contenedor de lista embebida |
|
|
24
|
+
| `WEB` | WebView |
|
|
25
|
+
| `AT` | Adjunto |
|
|
26
|
+
| `O` | Sub-objeto JavaScript, no persiste |
|
|
27
|
+
|
|
28
|
+
Los combos **no tienen tipo propio**: se hacen con `type="T"` (o `type="N"`) más `mapcol` y `mapfld`. No existen `type="C"`, `"M"`, `"A"`, `"F"`, `"S"`, `"P"`, `"E"`, `"R"`, `"H"`, `"W"`, `"CAM"`, `"ARRAY"`, `"STRING"`, `"N1"` ni `"BT"`.
|