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.
Files changed (187) hide show
  1. package/README.md +167 -0
  2. package/dist/agent/authEnDisco.js +56 -0
  3. package/dist/agent/authEnDisco.js.map +1 -0
  4. package/dist/agent/configEnDisco.js +109 -0
  5. package/dist/agent/configEnDisco.js.map +1 -0
  6. package/dist/agent/crearProyecto.js +34 -0
  7. package/dist/agent/crearProyecto.js.map +1 -0
  8. package/dist/agent/entorno.js +124 -0
  9. package/dist/agent/entorno.js.map +1 -0
  10. package/dist/agent/guionizado.js +53 -0
  11. package/dist/agent/guionizado.js.map +1 -0
  12. package/dist/agent/instantanea.js +129 -0
  13. package/dist/agent/instantanea.js.map +1 -0
  14. package/dist/agent/interrupts.js +83 -0
  15. package/dist/agent/interrupts.js.map +1 -0
  16. package/dist/agent/mensajes.js +24 -0
  17. package/dist/agent/mensajes.js.map +1 -0
  18. package/dist/agent/modelos.js +42 -0
  19. package/dist/agent/modelos.js.map +1 -0
  20. package/dist/agent/normalizar.js +20 -0
  21. package/dist/agent/normalizar.js.map +1 -0
  22. package/dist/agent/perfiles.js +103 -0
  23. package/dist/agent/perfiles.js.map +1 -0
  24. package/dist/agent/proyecto.js +107 -0
  25. package/dist/agent/proyecto.js.map +1 -0
  26. package/dist/agent/puente.js +142 -0
  27. package/dist/agent/puente.js.map +1 -0
  28. package/dist/agent/resumenDeTool.js +48 -0
  29. package/dist/agent/resumenDeTool.js.map +1 -0
  30. package/dist/agent/skills.js +65 -0
  31. package/dist/agent/skills.js.map +1 -0
  32. package/dist/agent/textoDeTool.js +113 -0
  33. package/dist/agent/textoDeTool.js.map +1 -0
  34. package/dist/agent/turnoReal.js +173 -0
  35. package/dist/agent/turnoReal.js.map +1 -0
  36. package/dist/agent/verificador.js +65 -0
  37. package/dist/agent/verificador.js.map +1 -0
  38. package/dist/agent/xoneAgent.js +106 -0
  39. package/dist/agent/xoneAgent.js.map +1 -0
  40. package/dist/bin.js +9 -0
  41. package/dist/bin.js.map +1 -0
  42. package/dist/cli/aprobar.js +82 -0
  43. package/dist/cli/aprobar.js.map +1 -0
  44. package/dist/cli/config.js +133 -0
  45. package/dist/cli/config.js.map +1 -0
  46. package/dist/cli/consola.js +346 -0
  47. package/dist/cli/consola.js.map +1 -0
  48. package/dist/cli/describe.js +53 -0
  49. package/dist/cli/describe.js.map +1 -0
  50. package/dist/cli/doctor.js +45 -0
  51. package/dist/cli/doctor.js.map +1 -0
  52. package/dist/cli/main.js +520 -0
  53. package/dist/cli/main.js.map +1 -0
  54. package/dist/cli/markdown.js +90 -0
  55. package/dist/cli/markdown.js.map +1 -0
  56. package/dist/cli/run.js +164 -0
  57. package/dist/cli/run.js.map +1 -0
  58. package/dist/cli/spinner.js +89 -0
  59. package/dist/cli/spinner.js.map +1 -0
  60. package/dist/cli/stdio.js +193 -0
  61. package/dist/cli/stdio.js.map +1 -0
  62. package/dist/cli/tema.js +40 -0
  63. package/dist/cli/tema.js.map +1 -0
  64. package/dist/cli/verify.js +62 -0
  65. package/dist/cli/verify.js.map +1 -0
  66. package/dist/core/bitacora.js +30 -0
  67. package/dist/core/bitacora.js.map +1 -0
  68. package/dist/core/config.js +236 -0
  69. package/dist/core/config.js.map +1 -0
  70. package/dist/core/contextos.js +56 -0
  71. package/dist/core/contextos.js.map +1 -0
  72. package/dist/core/deps.js +51 -0
  73. package/dist/core/deps.js.map +1 -0
  74. package/dist/core/diff.js +79 -0
  75. package/dist/core/diff.js.map +1 -0
  76. package/dist/core/esqueleto.js +366 -0
  77. package/dist/core/esqueleto.js.map +1 -0
  78. package/dist/core/events.js +2 -0
  79. package/dist/core/events.js.map +1 -0
  80. package/dist/core/modelos.js +85 -0
  81. package/dist/core/modelos.js.map +1 -0
  82. package/dist/core/notify.js +106 -0
  83. package/dist/core/notify.js.map +1 -0
  84. package/dist/core/ports.js +114 -0
  85. package/dist/core/ports.js.map +1 -0
  86. package/dist/core/turno.js +127 -0
  87. package/dist/core/turno.js.map +1 -0
  88. package/dist/vendor/hitl.js +103 -0
  89. package/dist/vendor/hitl.js.map +1 -0
  90. package/dist/vendor/skillLoaders/catalog.js +74 -0
  91. package/dist/vendor/skillLoaders/catalog.js.map +1 -0
  92. package/dist/vendor/tokenTracking.js +58 -0
  93. package/dist/vendor/tokenTracking.js.map +1 -0
  94. package/package.json +41 -0
  95. package/skills/xone-debugging/SKILL.md +52 -0
  96. package/skills/xone-debugging/references/faq.md +561 -0
  97. package/skills/xone-debugging/references/troubleshooting-y-glosario.md +429 -0
  98. package/skills/xone-development/SKILL.md +105 -0
  99. package/skills/xone-development/references/anti-patrones.md +94 -0
  100. package/skills/xone-development/references/css/atributos-por-categoria.md +509 -0
  101. package/skills/xone-development/references/css/buenas-practicas-y-parser.md +419 -0
  102. package/skills/xone-development/references/css/dinamicos-cascada-y-componentes.md +550 -0
  103. package/skills/xone-development/references/css/patrones-material-y-temas.md +1140 -0
  104. package/skills/xone-development/references/css/propiedades-y-herencia.md +885 -0
  105. package/skills/xone-development/references/css/selectores-unidades-colores.md +840 -0
  106. package/skills/xone-development/references/datos/appdata-referencia-ampliada.md +457 -0
  107. package/skills/xone-development/references/datos/appdata.md +611 -0
  108. package/skills/xone-development/references/datos/http-sqlmanager-y-crypto.md +720 -0
  109. package/skills/xone-development/references/datos/http.md +366 -0
  110. package/skills/xone-development/references/datos/oauth2-y-replica.md +156 -0
  111. package/skills/xone-development/references/device/biometria-imagedrawing-y-otros.md +544 -0
  112. package/skills/xone-development/references/device/objetos-de-dispositivo.md +583 -0
  113. package/skills/xone-development/references/device/systemsettings-referencia-ampliada.md +396 -0
  114. package/skills/xone-development/references/device/systemsettings-y-permisos.md +342 -0
  115. package/skills/xone-development/references/fundamentos/conceptos-clave.md +695 -0
  116. package/skills/xone-development/references/fundamentos/configuracion-app-xml-ini-mappings.md +668 -0
  117. package/skills/xone-development/references/fundamentos/errores-comunes.md +312 -0
  118. package/skills/xone-development/references/fundamentos/navegacion-convenciones-y-primer-proyecto.md +576 -0
  119. package/skills/xone-development/references/fundamentos/plataforma-y-anatomia-de-proyecto.md +387 -0
  120. package/skills/xone-development/references/indice-completo.md +77 -0
  121. package/skills/xone-development/references/javascript/coleccion-error-y-usuario.md +260 -0
  122. package/skills/xone-development/references/javascript/debugging-y-best-practices.md +245 -0
  123. package/skills/xone-development/references/javascript/metodos-de-los-controles.md +556 -0
  124. package/skills/xone-development/references/javascript/metodos-nativos-de-la-vista.md +114 -0
  125. package/skills/xone-development/references/javascript/motor-js-y-contexto-de-ejecucion.md +319 -0
  126. package/skills/xone-development/references/javascript/objeto-ai-llm-en-dispositivo.md +358 -0
  127. package/skills/xone-development/references/javascript/objetos-creables-a-m.md +527 -0
  128. package/skills/xone-development/references/javascript/objetos-creables-n-z.md +385 -0
  129. package/skills/xone-development/references/javascript/patrones-criticos-seguridad-y-rendimiento.md +595 -0
  130. package/skills/xone-development/references/javascript/patrones-de-navegacion-datos-y-codigo.md +751 -0
  131. package/skills/xone-development/references/javascript/patrones-de-ui-voz-integracion-y-seguridad.md +701 -0
  132. package/skills/xone-development/references/javascript/plantillas-y-funciones-utilitarias.md +647 -0
  133. package/skills/xone-development/references/javascript/self-y-dataobject.md +449 -0
  134. package/skills/xone-development/references/javascript/singletons-globales.md +361 -0
  135. package/skills/xone-development/references/javascript/ui-catalogo-de-metodos.md +464 -0
  136. package/skills/xone-development/references/javascript/ui-gps-camara-y-multimedia.md +506 -0
  137. package/skills/xone-development/references/javascript/ui-navegacion-mensajes-y-vista.md +422 -0
  138. package/skills/xone-development/references/resumen-js-datos-dispositivo.md +80 -0
  139. package/skills/xone-development/references/resumen-xml-y-css.md +74 -0
  140. package/skills/xone-development/references/tipos-de-prop.md +28 -0
  141. package/skills/xone-development/references/xml-ui/asfilter-visibilidad-eventos-y-macros.md +576 -0
  142. package/skills/xone-development/references/xml-ui/atributos-coll-group-frame.md +235 -0
  143. package/skills/xone-development/references/xml-ui/atributos-method-macro-script-event-app.md +244 -0
  144. package/skills/xone-development/references/xml-ui/atributos-prop.md +439 -0
  145. package/skills/xone-development/references/xml-ui/contents-y-macros.md +392 -0
  146. package/skills/xone-development/references/xml-ui/errores-comunes-xml.md +245 -0
  147. package/skills/xone-development/references/xml-ui/estructura-y-nodo-coll.md +326 -0
  148. package/skills/xone-development/references/xml-ui/eventos-ciclo-de-vida-e-interaccion.md +704 -0
  149. package/skills/xone-development/references/xml-ui/eventos-sistema-login-y-personalizados.md +944 -0
  150. package/skills/xone-development/references/xml-ui/layouts-herencia-y-buenas-practicas.md +618 -0
  151. package/skills/xone-development/references/xml-ui/mapas.md +685 -0
  152. package/skills/xone-development/references/xml-ui/mappings-y-colecciones-separadas.md +148 -0
  153. package/skills/xone-development/references/xml-ui/nodos-group-y-frame.md +666 -0
  154. package/skills/xone-development/references/xml-ui/patrones-de-pantalla.md +643 -0
  155. package/skills/xone-development/references/xml-ui/prop-atributos-y-condiciones.md +298 -0
  156. package/skills/xone-development/references/xml-ui/prop-tipos-basicos.md +493 -0
  157. package/skills/xone-development/references/xml-ui/prop-tipos-combos-y-controles.md +664 -0
  158. package/skills/xone-development/references/xml-ui/prop-tipos-listas-y-mapas.md +412 -0
  159. package/skills/xone-plan-builder/SKILL.md +183 -0
  160. package/skills/xone-plan-builder/agents/openai.yaml +5 -0
  161. package/skills/xone-plan-builder/references/TASKS-FORMAT.md +132 -0
  162. package/skills/xone-project-generator/SKILL.md +111 -0
  163. package/skills/xone-project-generator/references/canonical-sizes.md +292 -0
  164. package/skills/xone-project-generator/references/colecciones-base.md +16 -0
  165. package/skills/xone-project-generator/references/convenciones-de-nombres.md +16 -0
  166. package/skills/xone-project-generator/references/ejemplos-por-sector-y-prohibiciones.md +140 -0
  167. package/skills/xone-project-generator/references/fase-3-estilos-css.md +597 -0
  168. package/skills/xone-project-generator/references/fase-6-colecciones.md +762 -0
  169. package/skills/xone-project-generator/references/fase-7-asfilter-e-integraciones.md +142 -0
  170. package/skills/xone-project-generator/references/fase-7-entidades-y-estructura-de-pantalla.md +494 -0
  171. package/skills/xone-project-generator/references/fase-7-plantilla-consola.md +477 -0
  172. package/skills/xone-project-generator/references/fase-7-plantillas-de-pantalla.md +302 -0
  173. package/skills/xone-project-generator/references/fase-7-viewmodes-graficos-y-listas.md +681 -0
  174. package/skills/xone-project-generator/references/fase-7-viewmodes-mapa-y-calendario.md +479 -0
  175. package/skills/xone-project-generator/references/fases-0-2-analisis-y-modelo-de-datos.md +350 -0
  176. package/skills/xone-project-generator/references/fases-10-12-readmes-y-validacion.md +194 -0
  177. package/skills/xone-project-generator/references/fases-4-5-estructura-y-configuracion.md +587 -0
  178. package/skills/xone-project-generator/references/fases-8-9-eventos-y-javascript.md +861 -0
  179. package/skills/xone-project-generator/references/flujo-de-generacion.md +67 -0
  180. package/skills/xone-project-generator/references/plantillas-estandar.md +98 -0
  181. package/skills/xone-project-generator/references/tamanos-canonicos.md +49 -0
  182. package/skills/xone-review/SKILL.md +189 -0
  183. package/skills/xone-spec-builder/SKILL.md +235 -0
  184. package/skills/xone-spec-builder/agents/openai.yaml +5 -0
  185. package/skills/xone-spec-builder/references/ADR-FORMAT.md +55 -0
  186. package/skills/xone-spec-builder/references/CONTEXT-FORMAT.md +42 -0
  187. package/skills/xone-spec-builder/references/PLAN-FORMAT.md +120 -0
@@ -0,0 +1,611 @@
1
+ # XOne — appData: colecciones, sesión, macros y SQL
2
+
3
+ > Fuente: `xone/v2/xone-help-docs/topics/03c-js-appdata-http.md` §4. Referencia de la skill; el índice está en [../../SKILL.md](../../SKILL.md).
4
+
5
+ Contenido: §4 appData completo: getCollection y operaciones, login/logout, paso de datos entre pantallas, macros globales, SQL directo, detección de dispositivo, loadIncludeFile y loadCssFile
6
+
7
+ ---
8
+
9
+ ## 4. Objeto Global `appData` - Aplicación
10
+
11
+ El objeto global `appData` gestiona datos, configuración, sesión y estado de la aplicación.
12
+
13
+ ### 4.1 Colecciones
14
+
15
+ #### Crear objetos: patrón preferido (constructor `new`)
16
+
17
+ Toda colección de la aplicación está disponible como constructor global. `new NombreColeccion()` crea un objeto nuevo de esa colección y acepta un parámetro opcional con los valores iniciales (cada propiedad se asigna igual que `obj.PROP = valor`, disparando sus `onchange`):
18
+
19
+ ```javascript
20
+ // Crear un objeto nuevo con valores iniciales
21
+ let obj = new Clientes({ NOMBRE: "ACME", ACTIVO: 1 });
22
+
23
+ // El parámetro es opcional
24
+ let obj2 = new Clientes();
25
+
26
+ // Crear, añadir a la colección y guardar
27
+ let coll = appData.getCollection("Clientes");
28
+ let obj3 = new Clientes({ NOMBRE: "Nuevo registro" });
29
+ coll.addItem(obj3);
30
+ obj3.save();
31
+ ```
32
+
33
+ Cuándo NO aplica el constructor:
34
+
35
+ - **Contents anidados**: para crear líneas de un content usa `self.Contents("Lineas").createObject()` — crear desde el content establece el vínculo con el objeto padre; el constructor crea sobre la colección global y no vincula.
36
+ - **Nombre de colección dinámico**: si el nombre llega en una variable, usa el patrón legacy `appData.getCollection(nombre).createObject()`.
37
+
38
+ El constructor solo crea objetos. No existen métodos estáticos tipo ORM (`Usuarios.find(...)`, `Usuarios.create(...)`, `Usuarios.findById(...)`); las consultas se hacen con `appData.getCollection("Usuarios").findObject(...)` y demás métodos de la colección.
39
+
40
+ ```javascript
41
+ // (legacy) Patrón antiguo de creación — sigue funcionando, pero el preferido es el constructor
42
+ let coll = appData.getCollection("Clientes");
43
+ let obj = coll.createObject();
44
+ obj.NOMBRE = "ACME";
45
+ obj.ACTIVO = 1;
46
+ ```
47
+
48
+ #### API de colecciones
49
+
50
+ ```javascript
51
+ // === Obtener una coleccion por nombre ===
52
+ let coll = appData.getCollection("NombreColeccion");
53
+
54
+ // === Crear nuevo objeto y agregarlo ===
55
+ let obj = new NombreColeccion({ MAP_NOMBRE: "Nuevo registro" });
56
+ coll.addItem(obj);
57
+ obj.save();
58
+
59
+ // === Cargar todos los registros ===
60
+ coll.loadAll();
61
+ let nCount = coll.getCount(); // Número de registros cargados
62
+
63
+ // === Iterar registros ===
64
+ for (let i = 0; i < coll.getCount(); i++) {
65
+ let obj = coll.get(i);
66
+ console.log(obj.MAP_NOMBRE);
67
+ }
68
+
69
+ // === Navegacion con browse ===
70
+ coll.startBrowse();
71
+ let item = coll.getCurrentItem();
72
+ coll.moveFirst();
73
+ while (coll.getCurrentItem() != null) {
74
+ // Procesar item
75
+ coll.moveNext();
76
+ }
77
+ coll.endBrowse();
78
+
79
+ // === Buscar objetos ===
80
+ let obj = coll.findObject("LOGIN = 'admin'");
81
+ let obj2 = coll.findObject("ID = 5 AND ACTIVO = 1");
82
+ let obj3 = coll.getItem("MAP_CAMPO", valor);
83
+ let todos = coll.findAllObjects("TIPO = 'A'");
84
+
85
+ // === Filtrar y ordenar ===
86
+ coll.setFilter("ACTIVO = 1 AND TIPO = 'A'");
87
+ coll.clear();
88
+ coll.loadAll();
89
+ coll.doSort("NOMBRE ASC");
90
+
91
+ // === Eliminar registros ===
92
+ coll.deleteItem(indice); // Eliminar por indice
93
+ coll.browseDeleteAll(); // Eliminar todos de la BD
94
+ coll.clear(); // Limpiar solo memoria
95
+
96
+ // === Guardar todos los registros modificados ===
97
+ coll.saveAll();
98
+
99
+ // === Bloquear/desbloquear para modificaciones ===
100
+ coll.lock();
101
+ coll.unlock();
102
+
103
+ // === Clonar coleccion ===
104
+ let collClone = coll.createClone();
105
+
106
+ // === Cargar desde JSON ===
107
+ coll.loadFromJson("[{'ID': 1, 'NOMBRE': 'Item1'}, {'ID': 2, 'NOMBRE': 'Item2'}]");
108
+
109
+ // === Variables y macros de coleccion ===
110
+ coll.setVariable("totalProcesados", 0);
111
+ let total = coll.getVariable("totalProcesados");
112
+ coll.setMacro("##FILTRO##", "activo=1");
113
+ let filtro = coll.getMacro("##FILTRO##");
114
+
115
+ // === Busqueda en memoria ===
116
+ coll.createSearchIndex(["NOMBRE", "DESCRIPCION"]);
117
+ coll.doSearch("texto a buscar");
118
+
119
+ // === Información de la coleccion ===
120
+ let nombre = coll.getName();
121
+ let propCount = coll.getPropertyCount();
122
+ let propName = coll.propertyName(0);
123
+ let propType = coll.getPropType("MAP_CAMPO");
124
+
125
+ // === Generar ROWID ===
126
+ let rowid = coll.generateRowId();
127
+ ```
128
+
129
+ ### 4.2 Autenticación
130
+
131
+ ```javascript
132
+ // === Login ===
133
+ appData.login({
134
+ userName : self.MAP_USER,
135
+ password : self.MAP_PASSWORD,
136
+ entryPoint : "MenuPrincipal",
137
+ onLoginSuccessful : function() {
138
+ ui.showToast("Login OK!");
139
+ },
140
+ onLoginFailed : function() {
141
+ ui.showToast("Login failed!");
142
+ }
143
+ });
144
+
145
+ // === Logout ===
146
+ appData.logout();
147
+
148
+ // === Salir de la app ===
149
+ appData.exit();
150
+
151
+ // === Reiniciar la app ===
152
+ appData.restart();
153
+
154
+ // === Obtener empresa y usuario actual ===
155
+ let empresa = appData.getCurrentEnterprise();
156
+ let empresas = appData.getAllowedEnterprises();
157
+ let usuarios = appData.getAllowedUsers();
158
+ ```
159
+
160
+ ### 4.3 Navegación entre Pantallas con Datos
161
+
162
+ Para abrir una pantalla pasándole datos, se usa el patrón **dataObject + `ui.openEditView()`**:
163
+
164
+ 1. Obtener (o crear) un **dataObject** de la colección destino.
165
+ 2. Asignar los valores deseados a sus propiedades (`obj.MAP_X = valor`).
166
+ 3. Llamar a `ui.openEditView(dataObject)` — XOne abre la vista de edición de ese objeto.
167
+
168
+ ```javascript
169
+ // === Pasar un objeto NUEVO a la pantalla destino ===
170
+ let coll = appData.getCollection("DetalleCliente");
171
+ let obj = new DetalleCliente({ MAP_CLIENTE_ID: clienteId, MAP_MODO: "consulta" });
172
+ coll.addItem(obj);
173
+ ui.openEditView(obj);
174
+
175
+ // === Abrir un objeto EXISTENTE recuperado de la BD ===
176
+ let coll = appData.getCollection("Clientes");
177
+ let cliente = coll.findObject("ID = " + clienteId);
178
+ if (cliente) {
179
+ ui.openEditView(cliente);
180
+ }
181
+ ```
182
+
183
+ **Forma corta — crear + abrir en una sola llamada:**
184
+
185
+ Si solo necesitas abrir un objeto nuevo sin preparar nada de antemano, basta con pasar el nombre de la colección. XOne hace internamente `createObject()` + `addItem()`:
186
+
187
+ ```javascript
188
+ ui.openEditView("DetalleCliente");
189
+ ```
190
+
191
+ **Cerrar la vista actual al abrir la nueva:**
192
+
193
+ `openEditView` admite un segundo argumento booleano para terminar la vista origen tras abrir la siguiente (flujos lineales sin botón atrás):
194
+
195
+ ```javascript
196
+ ui.openEditView(obj, true); // cierra la vista origen al abrir la nueva
197
+ ```
198
+
199
+ ### 4.4 Macros Globales
200
+
201
+ Las macros globales son pares clave-valor accesibles desde toda la aplicación. Son la alternativa de XOne a `localStorage`:
202
+
203
+ ```javascript
204
+ // === Establecer y leer macros personalizadas ===
205
+ appData.setGlobalMacro("##MI_TOKEN##", "abc123");
206
+ let token = appData.getGlobalMacro("##MI_TOKEN##");
207
+
208
+ // === Macros del sistema ===
209
+ let deviceOs = appData.getGlobalMacro("##DEVICE_OS##"); // "android" o "ios"
210
+ let version = appData.getGlobalMacro("##VERSION##");
211
+ let frameVersion = appData.getGlobalMacro("##FRAME_VERSION##");
212
+
213
+ // === Obtener todas las macros ===
214
+ let todasMacros = appData.getAllGlobalMacros();
215
+
216
+ // === Patron comun: almacenar datos de sesion ===
217
+ function guardarSesion(usuario) {
218
+ appData.setGlobalMacro("##USERID##", usuario.ID);
219
+ appData.setGlobalMacro("##USERNAME##", usuario.NOMBRE);
220
+ appData.setGlobalMacro("##USERROLE##", usuario.ROL);
221
+ }
222
+
223
+ function limpiarSesion() {
224
+ appData.setGlobalMacro("##USERID##", "");
225
+ appData.setGlobalMacro("##USERNAME##", "");
226
+ appData.setGlobalMacro("##USERROLE##", "");
227
+ }
228
+ ```
229
+
230
+ ### 4.5 SQL Directo
231
+
232
+ **Firma:** `appData.executeSql(sql)`
233
+
234
+ - Acepta **exactamente 1 parámetro** (string SQL); no admite placeholders `?` ni varargs.
235
+ - **Sustituye automáticamente** las macros del framework (`##USERID##`, `##NOW##`, etc.) en el SQL antes de ejecutar.
236
+ - **No usar para leer escalares**: para `SELECT` no devuelve el valor, devuelve un cursor inutilizable desde JS. Para leer datos usar `SqlManager.doRawQuery()` + cursor.
237
+ - Casos de uso: sentencias de modificación masiva, sobre todo cuando hay cursores abiertos sobre la misma tabla y `CurrentItem` no puede modificarse desde la coll.
238
+
239
+ ```javascript
240
+ // === Ejecutar SQL directo (UPDATE/INSERT/DELETE) ===
241
+ appData.executeSql("UPDATE gen_productos SET ACTIVO=0 WHERE STOCK=0");
242
+
243
+ // NO usar executeSql para leer escalares: no devuelve el COUNT, devuelve un ResultSet
244
+ // var n = appData.executeSql("SELECT COUNT(*) FROM gen_clientes"); // MAL
245
+
246
+ // === SqlManager para consultas avanzadas ===
247
+ let sqlManager = new SqlManager();
248
+ try {
249
+ sqlManager.openDatabase({
250
+ databasePath : "gestion.db",
251
+ useWal : true,
252
+ readOnly : false,
253
+ useExistingConnection: true,
254
+ onDatabaseCorrupted : function() {
255
+ ui.showToast("Base de datos corrupta");
256
+ }
257
+ });
258
+
259
+ // Consulta con parametros (SEGURO contra SQL injection)
260
+ let cursor = sqlManager.doRawQuery(
261
+ "SELECT * FROM gen_usuarios WHERE LOGIN=? AND ACTIVO=?",
262
+ "admin", 1
263
+ );
264
+ try {
265
+ if (cursor.getCount() > 0) {
266
+ cursor.moveToFirst();
267
+ let nombre = cursor.getString("NOMBRE");
268
+ let id = cursor.getInteger("ID");
269
+ }
270
+ } finally {
271
+ cursor.close(); // SIEMPRE cerrar el cursor
272
+ }
273
+
274
+ // Insertar con parametros seguros
275
+ sqlManager.insert({
276
+ tableName: "gen_productos",
277
+ fields: {
278
+ CODIGO: "PROD001",
279
+ NOMBRE: "Producto nuevo",
280
+ PRECIO: 29.99,
281
+ ACTIVO: 1
282
+ }
283
+ });
284
+
285
+ // Batch de SQLs
286
+ let sqls = [];
287
+ sqls.push("UPDATE gen_productos SET PROCESADO=1 WHERE FECHA < '2024-01-01'");
288
+ sqls.push("DELETE FROM gen_log WHERE FECHA < '2023-01-01'");
289
+ sqlManager.doBatchParseSqls(sqls);
290
+
291
+ // Mantenimiento
292
+ sqlManager.doWalCheckpoint();
293
+ sqlManager.doVacuum();
294
+
295
+ } finally {
296
+ sqlManager.close(); // SIEMPRE cerrar la conexión
297
+ }
298
+ ```
299
+
300
+ ### 4.6 Encriptación (Básica)
301
+
302
+ ```javascript
303
+ // Encriptar string (encriptacion simple del framework)
304
+ let encrypted = appData.encryptString("texto secreto");
305
+
306
+ // Desencriptar string
307
+ let decrypted = appData.decryptString(encrypted);
308
+ ```
309
+
310
+ Para encriptación avanzada (AES, RSA, firma digital), usar el objeto `crypto` documentado más adelante en la sección de Seguridad.
311
+
312
+ ### 4.7 Deteccion de Dispositivo
313
+
314
+ ```javascript
315
+ // Tipo de dispositivo
316
+ if (appData.isPhone()) { /* Teléfono */ }
317
+ if (appData.isTablet()) { /* Tablet */ }
318
+ if (appData.isWatch()) { /* Smartwatch */ }
319
+ if (appData.isWatchRound()) { /* Reloj redondo */ }
320
+ if (appData.isWatchSquare()) { /* Reloj cuadrado */ }
321
+
322
+ // Subtipos de teléfono
323
+ appData.isMiniPhone(); // Teléfono pequeño
324
+ appData.isMidPhone(); // Teléfono mediano
325
+ appData.isHiPhone(); // Teléfono grande
326
+
327
+ // Orientacion
328
+ if (appData.isVertical()) { /* Modo vertical (portrait) */ }
329
+ if (appData.isHorizontal()) { /* Modo horizontal (landscape) */ }
330
+
331
+ // Sistema operativo
332
+ let so = appData.getGlobalMacro("##DEVICE_OS##"); // "android" o "ios"
333
+ ```
334
+
335
+ ### 4.8 Push Notifications
336
+
337
+ `appData.registerPush(...)` admite tres firmas:
338
+
339
+ ```javascript
340
+ // Forma 1: objeto con callbacks (los nombres correctos son onSuccess/onFailure/onPushReceived,
341
+ // NO "onRegistered"; el motor lee exactamente esos tres)
342
+ appData.registerPush({
343
+ onSuccess: function(event) {
344
+ let pushToken = event.pushToken; // EventOnPushRegistered.pushToken
345
+ console.log("Push token: " + pushToken);
346
+ // Enviar token al servidor
347
+ },
348
+ onFailure: function(ex) {
349
+ console.error("Push registration failed:", ex);
350
+ },
351
+ onPushReceived: function(message) {
352
+ // Manejar la notificación recibida
353
+ }
354
+ });
355
+
356
+ // Forma 2: una función (callback de éxito)
357
+ appData.registerPush(function(event) { /* event.pushToken */ });
358
+
359
+ // Forma 3: dos funciones posicionales (éxito, fallo)
360
+ appData.registerPush(function(event) { /* OK */ },
361
+ function(ex) { /* error */ });
362
+ ```
363
+
364
+ > Las notificaciones entrantes también se manejan con el nodo `<onpushreceived>` declarado en la `<coll Empresas>`.
365
+
366
+ ### 4.9 Otros Métodos Importantes
367
+
368
+ ```javascript
369
+ // === Cerrar la app ===
370
+ appData.exit();
371
+
372
+ // === Cerrar la ventana actual ===
373
+ ui.getView(self).exit();
374
+
375
+ // === Escribir en consola de debug ===
376
+ appData.writeConsoleString("Debug: valor = " + valor);
377
+
378
+ // === Cargar archivos include (solo para casos dinámicos — preferir <include>/<script> en <app>; ver 4.11) ===
379
+ appData.loadIncludeFile("scripts/miModulo.js", "javascript", "UTF-8");
380
+
381
+ // === Cargar/descargar archivos CSS en runtime (solo para casos dinámicos — preferir <style> en <app>; ver 4.12) ===
382
+ appData.loadCssFile("temas/oscuro.css");
383
+ appData.unloadCssFile("temas/oscuro.css");
384
+
385
+ // === Rutas del sistema ===
386
+ let appPath = appData.getAppPath(); // Ruta base de la aplicación
387
+ let filesPath = appData.getFilesPath(); // Ruta de carpeta files/
388
+
389
+ // === Manejo de errores ===
390
+ let error = appData.error();
391
+ if (error.getNumber() != 0) {
392
+ console.log("Error: " + error.getDescription());
393
+ console.log("SQL fallido: " + error.getFailedSql());
394
+ error.clear();
395
+ }
396
+
397
+ // === Limpiar caches ===
398
+ appData.clearCaches();
399
+
400
+ // === Crear objetos especiales ===
401
+ let pdf = new XOnePDF();
402
+ let ocr = new XOneOCR();
403
+ let nfc = new XOneNFC();
404
+ let printer = new XOnePrinter();
405
+ let wifiMgr = new WifiManager();
406
+
407
+ // === Redondeo seguro ===
408
+ let resultado = appData.safeRound(3.14159, 2); // 3.14
409
+
410
+ // === Replicacion ===
411
+ let isReplicating = appData.isReplicating();
412
+ let replicationId = appData.getReplicationId();
413
+ ```
414
+
415
+ ### 4.10 Métodos Adicionales de appData
416
+
417
+ #### getCurrentEnterprise() - Empresa Actual
418
+
419
+ ```javascript
420
+ var empresa = appData.getCurrentEnterprise();
421
+
422
+ // Almacenar variables de sesion en la empresa
423
+ empresa.setVariable("GPSTime", new Date().toString());
424
+ empresa.setVariable("LATITUD", latitud);
425
+ empresa.setVariable("MIUBICACION", 0);
426
+
427
+ // Recuperar variables de la empresa
428
+ var valor = empresa.getVariable("GPSTime");
429
+ var lat = empresa.getVariable("LATITUD");
430
+ var debug = empresa.getVariable("Debug");
431
+ ```
432
+
433
+ #### safeRound(value, decimals) - Redondeo Seguro
434
+
435
+ ```javascript
436
+ var precio = appData.safeRound(vPendiente, 2);
437
+ var total = appData.safeRound(cantidad * precioUnitario, 2);
438
+ ```
439
+
440
+ #### encryptString(text) / decryptString(text) - Cifrado/Descifrado
441
+
442
+ ```javascript
443
+ var cifrado = appData.encryptString("texto sensible");
444
+ var descifrado = appData.decryptString(cifrado);
445
+ ```
446
+
447
+ #### error() - Objeto de Error del Framework
448
+
449
+ ```javascript
450
+ var error = appData.error();
451
+ if (error.getNumber() != 0) {
452
+ console.log("Código: " + error.getNumber());
453
+ console.log("Descripción: " + error.getDescription());
454
+ console.log("SQL fallido: " + error.getFailedSql());
455
+ error.clear();
456
+ }
457
+ ```
458
+
459
+ #### writeConsoleString(message) - Consola de Depuracion
460
+
461
+ ```javascript
462
+ appData.writeConsoleString("App_log_xone->Mensaje de depuracion");
463
+ ```
464
+
465
+ #### setIsReplicating(boolean) - Control de Replicación
466
+
467
+ ```javascript
468
+ appData.setIsReplicating(false);
469
+ // ... operaciones de mantenimiento local
470
+ appData.setIsReplicating(true);
471
+ ```
472
+
473
+ #### Conexiones
474
+
475
+ ```javascript
476
+ // Conexión por nombre (útil cuando la app declara varias conexiones)
477
+ var conn = appData.getConnection("REMOTA");
478
+
479
+ // String de la conexión PRINCIPAL (la por defecto)
480
+ var s = appData.getConnString();
481
+ ```
482
+
483
+ #### getCollectionCount() / getVisualConditions()
484
+
485
+ ```javascript
486
+ var nColls = appData.getCollectionCount(); // total de colecciones registradas
487
+ var conds = appData.getVisualConditions(); // string con las condiciones visuales activas
488
+ ```
489
+
490
+ ### 4.11 Carga dinámica de scripts (`loadIncludeFile`) y declaración preferida
491
+
492
+ > **Regla general:** declara los scripts en el nodo `<app>` siempre que puedas. Reserva `loadIncludeFile()` para casos especiales que **realmente** necesiten cargar el fichero en runtime (carga condicional según usuario/empresa, scripts descargados dinámicamente, parches en caliente, etc.).
493
+
494
+ #### Forma preferida: declarar en el nodo `<app>` (estática)
495
+
496
+ ```xml
497
+ <app default-language="javascript" ...>
498
+ <!-- functions.js se carga automáticamente, no hace falta declararlo -->
499
+
500
+ <!-- Forma <include>: encoding por defecto ISO-8859-1 -->
501
+ <include file="scripts/utils.js" />
502
+ <include url="scripts/api.js" encoding="UTF-8" />
503
+
504
+ <!-- Forma <script> (alias estilo HTML): encoding por defecto UTF-8 -->
505
+ <script src="scripts/auth.js" />
506
+ </app>
507
+ ```
508
+
509
+ **Atributos comunes a `<include>` y `<script>`:**
510
+
511
+ | Atributo | Alias | Obligatorio | Default | Descripción |
512
+ |---|---|---|---|---|
513
+ | `file` | `url`, `src` | sí | — | Ruta del fichero |
514
+ | `language` | — | no | `default-language` del `<app>` | `"javascript"` o `"vbscript"` |
515
+ | `encoding` | `charset` | no | `ISO-8859-1` en `<include>` · `UTF-8` en `<script>` | Codificación del fichero |
516
+ | `delay-compilation` | — | no | `false` | Difiere la compilación hasta el primer uso |
517
+ | `compile` | — | no | `true` | Si `false`, registra el fichero pero no lo compila |
518
+
519
+ #### Forma dinámica: `appData.loadIncludeFile()` (solo casos especiales)
520
+
521
+ ```javascript
522
+ appData.loadIncludeFile(fileName [, scriptLanguage] [, encoding] [, delayCompilation] [, compile]);
523
+ ```
524
+
525
+ | # | Nombre | Obligatorio | Valor por defecto | Descripción |
526
+ |---|---|---|---|---|
527
+ | 1 | `fileName` | sí | — | Ruta del fichero igual que en el nodo XML `<include>` |
528
+ | 2 | `scriptLanguage` | no | `default-language` del nodo `<app>` | `"javascript"` o `"vbscript"` |
529
+ | 3 | `encoding` | no | `"ISO-8859-1"` | Codificación del fichero. **Atención: el default NO es UTF-8** |
530
+ | 4 | `delayCompilation` | no | `false` | Si `true`, difiere la compilación hasta el primer uso |
531
+ | 5 | `compile` | no | `true` | Si `false`, registra el fichero pero no lo compila |
532
+
533
+ ```javascript
534
+ // Carga simple (asume default-language=javascript y encoding ISO-8859-1)
535
+ appData.loadIncludeFile("scripts/miModulo.js");
536
+
537
+ // Recomendado si el script tiene tildes/ñ guardadas como UTF-8
538
+ appData.loadIncludeFile("scripts/miModulo.js", "javascript", "UTF-8");
539
+ ```
540
+
541
+ **Advertencia sobre el encoding:** el valor por defecto es `ISO-8859-1`, no UTF-8. Si tu script contiene caracteres no-ASCII (tildes, ñ, símbolos) y está guardado como UTF-8, **se romperán** salvo que pases `"UTF-8"` explícitamente como tercer parámetro.
542
+
543
+ Llamadas posteriores al mismo fichero **no recompilan**: el motor reutiliza el bytecode ya cargado.
544
+
545
+ ### 4.12 Carga dinámica de CSS (`loadCssFile` / `unloadCssFile`) y declaración preferida
546
+
547
+ > **Regla general:** declara las hojas de estilo en el nodo `<app>` siempre que puedas. Reserva `loadCssFile()` / `unloadCssFile()` para casos especiales (cambio de tema por usuario, modo oscuro/claro en runtime, A/B testing visual, etc.).
548
+
549
+ #### Forma preferida: declarar en el nodo `<app>` (estática)
550
+
551
+ ```xml
552
+ <app ...>
553
+ <style url="estilos.css" />
554
+ <style url="temas/oscuro.css" encoding="UTF-8" conditions="##DEVICE_OS##='android'" strict-mode="true" />
555
+ </app>
556
+ ```
557
+
558
+ **Atributos del nodo `<style>`:**
559
+
560
+ | Atributo | Obligatorio | Default | Descripción |
561
+ |---|---|---|---|
562
+ | `url` | sí | — | Ruta del fichero CSS |
563
+ | `encoding` | no | (depende del fichero) | Codificación del fichero |
564
+ | `conditions` | no | (sin condición) | Condición de carga evaluada al iniciar (p. ej. macros globales) |
565
+ | `strict-mode` | no | `false` | Si `true`, exige CSS bien formado (avisa de errores como falta de `;`). En modo estricto hay que escapar `:` en valores: `title:Hola\:Mundo;` |
566
+
567
+ #### Forma dinámica: `appData.loadCssFile()` / `appData.unloadCssFile()` (solo casos especiales)
568
+
569
+ **Firmas:**
570
+
571
+ ```javascript
572
+ // Forma 1: argumentos posicionales
573
+ appData.loadCssFile(name [, encoding] [, conditions] [, strictMode]);
574
+
575
+ // Forma 2: objeto literal
576
+ appData.loadCssFile({ name: "...", encoding: "...", conditions: "...", strictMode: false });
577
+
578
+ // Descarga (un único argumento)
579
+ appData.unloadCssFile(name);
580
+ ```
581
+
582
+ **Parámetros de `loadCssFile`:**
583
+
584
+ | # / clave | Obligatorio | Valor por defecto | Descripción |
585
+ |---|---|---|---|
586
+ | `name` | sí | — | Ruta del fichero CSS |
587
+ | `encoding` | no | `"UTF-8"` | Codificación del fichero (¡distinto de `loadIncludeFile`!) |
588
+ | `conditions` | no | (sin condición) | Condición de carga |
589
+ | `strictMode` | no | `false` | Modo estricto de parseo |
590
+
591
+ **Ejemplo (cambio de tema en runtime):**
592
+
593
+ ```javascript
594
+ function aplicarTemaOscuro() {
595
+ appData.unloadCssFile("temas/claro.css");
596
+ appData.loadCssFile("temas/oscuro.css", "UTF-8");
597
+ // El framework limpia caches de propiedades y refresca la cascada
598
+ }
599
+ ```
600
+
601
+ `loadCssFile()` y `unloadCssFile()` invalidan automáticamente los caches internos de propiedades visuales (`ClearCollPropValueCaches()`), por lo que los cambios se reflejan en los siguientes renders sin reiniciar la app.
602
+
603
+ **Diferencia de encoding por defecto:**
604
+
605
+ | Método | Default encoding |
606
+ |---|---|
607
+ | `appData.loadCssFile()` | `"UTF-8"` |
608
+ | `appData.loadIncludeFile()` | `"ISO-8859-1"` |
609
+ | `<style>` en `<app>` | depende del fichero |
610
+ | `<include>` en `<app>` | `"ISO-8859-1"` |
611
+ | `<script>` en `<app>` | `"UTF-8"` |