xonecode 0.26.1 → 0.29.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/apps/web/dist/assets/{EditorDeFichero-BW6i19HW.js → EditorDeFichero-ChyJtiiz.js} +1 -1
- package/apps/web/dist/assets/{index-CJycg35E.js → index-CFIrUOmW.js} +84 -84
- package/apps/web/dist/assets/{index-DICdq4UC.css → index-IptObD2z.css} +1 -1
- package/apps/web/dist/assets/{php-DxWUQTjM.js → php-B91ZcS-9.js} +1 -1
- package/apps/web/dist/assets/{ruby-gCKsUWxP.js → ruby-DrxrTSz0.js} +1 -1
- package/apps/web/dist/index.html +2 -2
- package/dist/agent/dispositivos/hotswap.js +27 -0
- package/dist/agent/dispositivos/hotswap.js.map +1 -1
- package/dist/agent/dispositivos/lanzamientoEnMaquina.js +33 -1
- package/dist/agent/dispositivos/lanzamientoEnMaquina.js.map +1 -1
- package/dist/agent/dispositivos/recargaEnAparato.js +190 -0
- package/dist/agent/dispositivos/recargaEnAparato.js.map +1 -0
- package/dist/agent/grafo/arbolDeProyecto.js +34 -11
- package/dist/agent/grafo/arbolDeProyecto.js.map +1 -1
- package/dist/agent/grafo/codificacionDelProyecto.js +282 -0
- package/dist/agent/grafo/codificacionDelProyecto.js.map +1 -0
- package/dist/agent/grafo/proyecto.js +6 -1
- package/dist/agent/grafo/proyecto.js.map +1 -1
- package/dist/agent/motores/trueforge/sesionTrueforge.js +4 -1
- package/dist/agent/motores/trueforge/sesionTrueforge.js.map +1 -1
- package/dist/agent/sesiones/baseDeFichero.js +8 -8
- package/dist/agent/sesiones/baseDeFichero.js.map +1 -1
- package/dist/agent/subagentes/escrituraExterna.js +4 -1
- package/dist/agent/subagentes/escrituraExterna.js.map +1 -1
- package/dist/agent/turno/turnoReal.js +4 -1
- package/dist/agent/turno/turnoReal.js.map +1 -1
- package/dist/core/codificacion.js +134 -0
- package/dist/core/codificacion.js.map +1 -0
- package/dist/core/recargaEnCaliente.js +122 -0
- package/dist/core/recargaEnCaliente.js.map +1 -0
- package/dist/web/servidor/arranque.js +184 -5
- package/dist/web/servidor/arranque.js.map +1 -1
- package/dist/web/servidor/transporte.js.map +1 -1
- package/package.json +1 -1
- package/skills/xone-hotswap/SKILL.md +3 -2
- package/skills/xone-hotswap/references/comandos.md +17 -1
- package/skills/xone-hotswap/scripts/xone-desplegar-android +62 -24
- package/skills/xone-hotswap/scripts/xone-recargar-android +59 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transporte.js","sourceRoot":"","sources":["../../../src/web/servidor/transporte.ts"],"names":[],"mappings":"AA4HA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,aAAa;IACb,cAAc;IACd,UAAU;IACV,aAAa;IACb,UAAU;IACV,sBAAsB;CACd,CAAC;AAGX,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,CAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"transporte.js","sourceRoot":"","sources":["../../../src/web/servidor/transporte.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -107,7 +107,8 @@ xone-desplegar-android --app MiApp --serie emulator-5554
|
|
|
107
107
|
# «cambié un botón / una función / un color»: NO despliegues entero. Compara el proyecto con el
|
|
108
108
|
# aparato, sube SOLO lo que difiere y lo aplica por la vía más barata (1-2 s si es una colección):
|
|
109
109
|
# colección (.xne) → recarga en caliente JavaScript (.js) → recarga del include
|
|
110
|
-
# CSS
|
|
110
|
+
# CSS (.css) → recarga en caliente (loadCssFile; en frameworks viejos, por runScript)
|
|
111
|
+
# app.xml, app.ini, mappings → relanza la app (unos 6 s)
|
|
111
112
|
# Necesita la app YA desplegada. Lo que no sabe aplicar (iconos, bd) lo dice y manda a desplegar.
|
|
112
113
|
xone-recargar-android
|
|
113
114
|
xone-recargar-android MenuPrincipal.xne functions.js # solo esos, sin comparar
|
|
@@ -246,7 +247,7 @@ Detalle de despliegue, relanzado y endpoints de fichero: [conexión y despliegue
|
|
|
246
247
|
| Tocar (`click`, `tap`, `doubleTap`, `longPress`, `openSelector`, `fill`, `clear`, `scroll`, `pressKey`) | sí | **sí**, con desviaciones (abajo) |
|
|
247
248
|
| Ciclo de app (`launchApplication`, `exitApplication`, `directdownload`) | sí | `launchApplication` y `directdownload` sí; `exitApplication` no |
|
|
248
249
|
| Atributos y colecciones (`setAttribute`, `deleteAttribute`, `loadCollection`) | sí | sí |
|
|
249
|
-
| CSS, `replaceProperty`, `refresh`, `relayout`, `loadIncludeFile` | sí | **no** |
|
|
250
|
+
| CSS (`setCssAttribute`, `loadCssFile`/`unloadCssFile`), `replaceProperty`, `refresh`, `relayout`, `loadIncludeFile` | sí | **no** |
|
|
250
251
|
| Ficheros (`/file_upload`, `/file_download`, `uploadFile`, `getFileChecksum`) | sí | **no** (`listappfiles` sí) |
|
|
251
252
|
| Scripts y SQL (`runScript`, `runSql`, `getDatabaseTableNames`, `queryDatabaseTable`) | sí | **no** |
|
|
252
253
|
| Logs (`getLog`, `*DeviceLogging`, `setLog*`) | sí | **no** |
|
|
@@ -81,6 +81,7 @@ por los dos canales.
|
|
|
81
81
|
| `deleteAttribute` | sí | sí | **solo WS** |
|
|
82
82
|
| `replaceProperty` | sí | — | — |
|
|
83
83
|
| `setCssAttribute` / `deleteCssAttribute` | sí | — | — |
|
|
84
|
+
| `loadCssFile` / `unloadCssFile` (desde 5.0.5.7dev) | sí | — | — |
|
|
84
85
|
| `refresh` / `relayout` | sí | — | — |
|
|
85
86
|
| `status` / `state` | sí | sí | **solo WS** |
|
|
86
87
|
| `uploadFile` | sí | — | — |
|
|
@@ -542,7 +543,8 @@ Carga o recarga una colección XML en caliente. **Entrada:** `xmlNode` (XML en *
|
|
|
542
543
|
|---|---|---|
|
|
543
544
|
| Colección `.xne` | `loadCollection` con el fichero entero en Base64 y `encoding=UTF-8` | Se repinta en ~2 s, **solo en memoria**: al relanzar la app vuelve la versión de disco. Para que persista, subir también el fichero con `uploadFile`. |
|
|
544
545
|
| JavaScript | `uploadFile` y luego `loadIncludeFile` con `compile=true` | Se aplica al instante. Solo subirlo, o `loadCollection`, **no** lo recarga. |
|
|
545
|
-
| CSS | `uploadFile` y luego `
|
|
546
|
+
| CSS (5.0.5.7dev en adelante) | `uploadFile` y luego `loadCssFile` con `fileName` | Se aplica al instante (medido: ~50 ms), **sin relanzar ni `refresh`**: sustituye la hoja en su sitio de la cascada y relayouta. |
|
|
547
|
+
| CSS (antes de 5.0.5.7dev, donde `loadCssFile` es `Unknown command`) | `uploadFile`, `runScript` con `appData.unloadCssFile(n); appData.loadCssFile(n, enc); return "ok";` y luego `refresh` | Se aplica sin relanzar. **Sin el `refresh` no se ve**: el cambio entra en el siguiente pintado. `setCssAttribute`, `relayout`, `refresh` y `loadCollection` solos contestan `result:true` y el color **no cambia**; `loadIncludeFile` no admite css (`Unknown script language css`). |
|
|
546
548
|
|
|
547
549
|
`uploadFile`: `destinationPath` cuelga del directorio de datos del framework, no del de la app.
|
|
548
550
|
La app vive en `app_<nombre en minúsculas>/`, así que hay que dar `app_holamundo/functions.js`; con
|
|
@@ -567,6 +569,20 @@ relayout o refresh según el atributo. **(iOS)** también es legado: solo WebSoc
|
|
|
567
569
|
### `setCssAttribute` / `deleteCssAttribute` — solo Android
|
|
568
570
|
`fileName`, `className`, `attributeName` (+ `attributeValue` en el set).
|
|
569
571
|
|
|
572
|
+
### `loadCssFile` / `unloadCssFile` — solo Android, desde 5.0.5.7dev
|
|
573
|
+
`loadCssFile`: `fileName` (sí), `encoding` (no, `UTF-8`), `conditions` (no, vacío = siempre),
|
|
574
|
+
`strictMode` (no, `false`). Carga una hoja que **ya está en el dispositivo** (súbela antes con
|
|
575
|
+
`uploadFile`), como un `<style>` del `<app>`, y relayouta las ventanas visibles. Si ya estaba cargada
|
|
576
|
+
con las mismas `conditions`, la **sustituye** en su sitio: así se aplica una hoja recién subida, sin
|
|
577
|
+
`unloadCssFile` antes. `unloadCssFile`: `fileName` (sí); quita la hoja y relayouta; una que no está
|
|
578
|
+
cargada responde éxito.
|
|
579
|
+
|
|
580
|
+
**Medido (5.0.5.7dev, emulador):** `uploadFile` + `loadCssFile fileName=default-colors.css` cambia el
|
|
581
|
+
color de un botón en ~50 ms, sin relanzar. Un nombre que no existe: `result:false` con
|
|
582
|
+
`FileNotFoundException`. Sin app cargada contestan `App is not running` en `status`. En 5.0.5.5dev el
|
|
583
|
+
comando no existe (`Unknown command: loadCssFile`): ahí, las funciones de XOne por `runScript` + `refresh`
|
|
584
|
+
(tabla de arriba).
|
|
585
|
+
|
|
570
586
|
### `refresh` / `relayout` — solo Android
|
|
571
587
|
En iOS las ramas existen en el dispatcher pero están **vacías**: no hacen nada.
|
|
572
588
|
|
|
@@ -359,6 +359,68 @@ function exigirAparato() {
|
|
|
359
359
|
const cuerpo = crearZip(process.cwd(), [".xonecode", ".git"]);
|
|
360
360
|
console.log(` ${(cuerpo.length / 1024).toFixed(0)} KB`);
|
|
361
361
|
|
|
362
|
+
const cliente = join(import.meta.dirname, "xone-hotswap");
|
|
363
|
+
/**
|
|
364
|
+
* **En `clave=valor`, que es lo único que el cliente entiende.**
|
|
365
|
+
*
|
|
366
|
+
* Esto mandaba `JSON.stringify(comando)` y se rompió ENTERO el día que el cliente dejó de
|
|
367
|
+
* aceptar JSON: el objeto se metía como NOMBRE del comando, el aparato contestaba
|
|
368
|
+
* `Unknown command: {…}` y el despliegue no lanzaba nada. Lanzar la app, pedir el árbol y
|
|
369
|
+
* capturar —las tres cosas que hace este paso— pasaban por aquí, así que se cayeron las
|
|
370
|
+
* tres a la vez, y en silencio: el script reintenta diez veces y acaba diciendo que el
|
|
371
|
+
* canal no levantó, que manda a mirar el puerto y el paquete en vez de al cliente.
|
|
372
|
+
*
|
|
373
|
+
* La conversión es la misma que hace el cliente al revés: cada campo que no es `command`
|
|
374
|
+
* sale como `clave=valor`, y un objeto o un array se serializan porque el tipado del
|
|
375
|
+
* cliente los reconoce por la forma.
|
|
376
|
+
*/
|
|
377
|
+
const mandar = (comando) => {
|
|
378
|
+
const { command, ...resto } = comando;
|
|
379
|
+
const pares = Object.entries(resto).map(([k, v]) =>
|
|
380
|
+
`${k}=${typeof v === "object" && v !== null ? JSON.stringify(v) : String(v)}`,
|
|
381
|
+
);
|
|
382
|
+
// El hijo habla por el MISMO puerto que el túnel de arriba, aunque venga de `--puerto`.
|
|
383
|
+
return execFileSync(NODE, [cliente, command, ...pares], { encoding: "utf8", env: { ...process.env, HOTSWAP_URL: process.env.HOTSWAP_URL ?? `wss://127.0.0.1:${PUERTO}/hotswap` } }).trim();
|
|
384
|
+
};
|
|
385
|
+
const esperar = (segundos) => dormir(segundos);
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* **El servidor del framework, ANTES de subir: la subida va por él.** Medido en el emulador: con el
|
|
389
|
+
* framework parado (`am force-stop`) la subida moría con un error de TLS, porque el túnel acepta y no
|
|
390
|
+
* hay nadie detrás; el reinicio del paso 4 —lo único que lo arrancaba— llega DESPUÉS. Se pregunta una
|
|
391
|
+
* vez (`getAllElements` contesta «App is not running» con el framework vivo y sin app, y el cliente
|
|
392
|
+
* sale con error si no hay servidor); si no contesta, se arranca su pantalla y se espera a que conteste.
|
|
393
|
+
* Es la misma regla que Ejecutar (`lanzamientoEnMaquina.ts`).
|
|
394
|
+
*/
|
|
395
|
+
const contesta = () => {
|
|
396
|
+
try {
|
|
397
|
+
// Con su stderr CALLADO: aquí que falle es la respuesta, no un error, y la línea del cliente
|
|
398
|
+
// («no se pudo hablar con el aparato») haría creer que el despliegue va mal.
|
|
399
|
+
execFileSync(NODE, [cliente, "getAllElements", "format=xone"], {
|
|
400
|
+
encoding: "utf8",
|
|
401
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
402
|
+
env: { ...process.env, HOTSWAP_URL: process.env.HOTSWAP_URL ?? `wss://127.0.0.1:${PUERTO}/hotswap` },
|
|
403
|
+
});
|
|
404
|
+
return true;
|
|
405
|
+
} catch {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
if (!contesta()) {
|
|
410
|
+
console.log(" el servidor del framework no contesta: se arranca su pantalla");
|
|
411
|
+
adb("shell", "am", "start", "-n", ACTIVIDAD);
|
|
412
|
+
let arranco = false;
|
|
413
|
+
for (let intento = 1; intento <= 60 && !arranco; intento++) {
|
|
414
|
+
esperar(1);
|
|
415
|
+
arranco = contesta();
|
|
416
|
+
}
|
|
417
|
+
if (!arranco) {
|
|
418
|
+
console.error(`el servidor del framework no arrancó en 60 s. Comprueba que ${PAQUETE} está instalado.`);
|
|
419
|
+
process.exit(1);
|
|
420
|
+
}
|
|
421
|
+
console.log(" el servidor del framework ya contesta");
|
|
422
|
+
}
|
|
423
|
+
|
|
362
424
|
console.log(`3/5 subiendo a ${app}`);
|
|
363
425
|
const url = `https://127.0.0.1:${PUERTO}/file_upload?file=debug_app_update.zip&appName=${encodeURIComponent(app)}`;
|
|
364
426
|
const respuesta = await fetch(url, {
|
|
@@ -385,30 +447,6 @@ function exigirAparato() {
|
|
|
385
447
|
adb("shell", "am", "start", "-n", ACTIVIDAD);
|
|
386
448
|
|
|
387
449
|
console.log("5/5 esperando al canal, lanzando y comprobando que está VIVA");
|
|
388
|
-
const cliente = join(import.meta.dirname, "xone-hotswap");
|
|
389
|
-
/**
|
|
390
|
-
* **En `clave=valor`, que es lo único que el cliente entiende.**
|
|
391
|
-
*
|
|
392
|
-
* Esto mandaba `JSON.stringify(comando)` y se rompió ENTERO el día que el cliente dejó de
|
|
393
|
-
* aceptar JSON: el objeto se metía como NOMBRE del comando, el aparato contestaba
|
|
394
|
-
* `Unknown command: {…}` y el despliegue no lanzaba nada. Lanzar la app, pedir el árbol y
|
|
395
|
-
* capturar —las tres cosas que hace este paso— pasaban por aquí, así que se cayeron las
|
|
396
|
-
* tres a la vez, y en silencio: el script reintenta diez veces y acaba diciendo que el
|
|
397
|
-
* canal no levantó, que manda a mirar el puerto y el paquete en vez de al cliente.
|
|
398
|
-
*
|
|
399
|
-
* La conversión es la misma que hace el cliente al revés: cada campo que no es `command`
|
|
400
|
-
* sale como `clave=valor`, y un objeto o un array se serializan porque el tipado del
|
|
401
|
-
* cliente los reconoce por la forma.
|
|
402
|
-
*/
|
|
403
|
-
const mandar = (comando) => {
|
|
404
|
-
const { command, ...resto } = comando;
|
|
405
|
-
const pares = Object.entries(resto).map(([k, v]) =>
|
|
406
|
-
`${k}=${typeof v === "object" && v !== null ? JSON.stringify(v) : String(v)}`,
|
|
407
|
-
);
|
|
408
|
-
// El hijo habla por el MISMO puerto que el túnel de arriba, aunque venga de `--puerto`.
|
|
409
|
-
return execFileSync(NODE, [cliente, command, ...pares], { encoding: "utf8", env: { ...process.env, HOTSWAP_URL: process.env.HOTSWAP_URL ?? `wss://127.0.0.1:${PUERTO}/hotswap` } }).trim();
|
|
410
|
-
};
|
|
411
|
-
const esperar = (segundos) => dormir(segundos);
|
|
412
450
|
|
|
413
451
|
/**
|
|
414
452
|
* **El canal no está en pie justo después del reinicio**, y esto se descubrió corriéndolo:
|
|
@@ -13,9 +13,13 @@
|
|
|
13
13
|
* devuelve a la versión anterior.
|
|
14
14
|
* JavaScript (.js) → `loadIncludeFile` con compile=true. Subir el fichero NO basta,
|
|
15
15
|
* y `loadCollection` tampoco lo recarga.
|
|
16
|
-
* CSS
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* CSS (.css) → el comando `loadCssFile` (framework 5.0.5.7dev en adelante): la
|
|
17
|
+
* sustituye y relayouta solo. En uno anterior, que contesta
|
|
18
|
+
* `Unknown command`, `runScript` con `appData.unloadCssFile` +
|
|
19
|
+
* `appData.loadCssFile` y un `refresh`. Medidos los dos: el color
|
|
20
|
+
* cambia SIN relanzar. Lo que no sirve, también medido:
|
|
21
|
+
* `setCssAttribute`, `relayout`, `refresh` o `loadCollection` solos.
|
|
22
|
+
* .ini, app.xml, mappings → relanzar la app (`launchApplication`): solo se leen al cargarla.
|
|
19
23
|
*
|
|
20
24
|
* **`result:true` es «aceptado», no «aplicado».** Lo que dice si funcionó es el árbol de
|
|
21
25
|
* controles, y por eso el script lo pide al acabar. Un atributo que XOne no conoce tampoco da
|
|
@@ -202,10 +206,33 @@ if (cambiados.length === 0) {
|
|
|
202
206
|
function clase(rel) {
|
|
203
207
|
const ext = extname(rel).toLowerCase();
|
|
204
208
|
if (ext === ".js") return "js";
|
|
209
|
+
if (ext === ".css") return "css";
|
|
205
210
|
if (ext === ".xne") return /<coll[\s>]/.test(readFileSync(rel, "latin1")) ? "coleccion" : "relanzar";
|
|
206
211
|
return "relanzar";
|
|
207
212
|
}
|
|
208
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Lo que se le da a `loadCollection`: el MISMO XML en UTF-8 y con el prólogo diciendo UTF-8.
|
|
216
|
+
* MEDIDO (5.0.5.5dev): con los bytes de un `.xne` en ISO-8859-15, cada tilde salía doble («Año»).
|
|
217
|
+
* La misma regla que `core/recargaEnCaliente.ts#xmlParaCargarEnMemoria`. Solo para memoria: a disco
|
|
218
|
+
* va el fichero tal cual, que es lo que el framework lee al relanzar.
|
|
219
|
+
*/
|
|
220
|
+
function xmlEnUtf8(bytes) {
|
|
221
|
+
let texto;
|
|
222
|
+
try {
|
|
223
|
+
texto = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
224
|
+
} catch {
|
|
225
|
+
const cabeza = bytes.subarray(0, 256).toString("latin1");
|
|
226
|
+
const tabla = /encoding\s*=\s*["'][^"']*(8859-15|latin-?9)/i.test(cabeza) ? "iso-8859-15" : "windows-1252";
|
|
227
|
+
texto = new TextDecoder(tabla).decode(bytes);
|
|
228
|
+
}
|
|
229
|
+
texto = texto.replace(/^\uFEFF/, "").replace(
|
|
230
|
+
/^(\s*<\?xml[^?]*?encoding\s*=\s*)(["'])[^"']*\2/i,
|
|
231
|
+
(_t, antes, comilla) => `${antes}${comilla}UTF-8${comilla}`,
|
|
232
|
+
);
|
|
233
|
+
return Buffer.from(texto, "utf8");
|
|
234
|
+
}
|
|
235
|
+
|
|
209
236
|
// 1. Subir a disco (siempre): lo que solo está en memoria se pierde al relanzar.
|
|
210
237
|
const subidos = [];
|
|
211
238
|
for (const rel of cambiados) {
|
|
@@ -226,6 +253,7 @@ for (const rel of cambiados) {
|
|
|
226
253
|
const clases = new Map(subidos.map((f) => [f, clase(f)]));
|
|
227
254
|
const hayQueRelanzar = [...clases.values()].includes("relanzar");
|
|
228
255
|
const fallos = [];
|
|
256
|
+
let necesitaRefresh = false;
|
|
229
257
|
|
|
230
258
|
if (hayQueRelanzar) {
|
|
231
259
|
const r = mandar("launchApplication", { appName: app });
|
|
@@ -238,15 +266,42 @@ if (hayQueRelanzar) {
|
|
|
238
266
|
} else {
|
|
239
267
|
for (const [f, c] of clases) {
|
|
240
268
|
if (c === "coleccion") {
|
|
241
|
-
const r = mandar("loadCollection", { xmlNode: readFileSync(f).toString("base64"), encoding: "UTF-8" });
|
|
269
|
+
const r = mandar("loadCollection", { xmlNode: xmlEnUtf8(readFileSync(f)).toString("base64"), encoding: "UTF-8" });
|
|
242
270
|
if (r.result !== true) fallos.push(`${f}: loadCollection ${r.exceptionMessage ?? r.status ?? "sin motivo"}`);
|
|
243
271
|
else console.log(` ${f} → colección recargada en caliente`);
|
|
272
|
+
} else if (c === "css") {
|
|
273
|
+
// La codificación de SUS bytes: `loadCssFile` asume UTF-8 si no se le dice.
|
|
274
|
+
let tabla = "UTF-8";
|
|
275
|
+
try {
|
|
276
|
+
new TextDecoder("utf-8", { fatal: true }).decode(readFileSync(f));
|
|
277
|
+
} catch {
|
|
278
|
+
tabla = "windows-1252";
|
|
279
|
+
}
|
|
280
|
+
const nativo = mandar("loadCssFile", { fileName: f, encoding: tabla });
|
|
281
|
+
if (nativo.result === true) {
|
|
282
|
+
console.log(` ${f} → estilos recargados en caliente`);
|
|
283
|
+
} else if (/Unknown command/i.test(String(nativo.exceptionMessage ?? nativo.status ?? ""))) {
|
|
284
|
+
// Framework anterior a 5.0.5.7dev: las mismas funciones de XOne, por `runScript`, y un
|
|
285
|
+
// `refresh` (abajo) para que se pinte.
|
|
286
|
+
const script = `appData.unloadCssFile(${JSON.stringify(f)}); appData.loadCssFile(${JSON.stringify(f)}, ${JSON.stringify(tabla)}); return "ok";`;
|
|
287
|
+
const r = mandar("runScript", { scriptLanguage: "javascript", scriptText: Buffer.from(script, "utf8").toString("base64") });
|
|
288
|
+
if (r.result !== true) fallos.push(`${f}: loadCssFile ${r.exceptionMessage ?? r.status ?? "sin motivo"}`);
|
|
289
|
+
else {
|
|
290
|
+
necesitaRefresh = true;
|
|
291
|
+
console.log(` ${f} → estilos recargados en caliente (por runScript)`);
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
fallos.push(`${f}: loadCssFile ${nativo.exceptionMessage ?? nativo.status ?? "sin motivo"}`);
|
|
295
|
+
}
|
|
244
296
|
} else {
|
|
245
297
|
const r = mandar("loadIncludeFile", { file: f, language: "javascript", encoding: "UTF-8", compile: true });
|
|
246
298
|
if (r.result !== true) fallos.push(`${f}: loadIncludeFile ${r.exceptionMessage ?? r.status ?? "sin motivo"}`);
|
|
247
299
|
else console.log(` ${f} → JavaScript recargado`);
|
|
248
300
|
}
|
|
249
301
|
}
|
|
302
|
+
// Por `runScript` los estilos se ven en el SIGUIENTE pintado: sin este `refresh`, no cambia nada
|
|
303
|
+
// (medido). El comando `loadCssFile` relayouta él solo.
|
|
304
|
+
if (necesitaRefresh) mandar("refresh");
|
|
250
305
|
dormir(1);
|
|
251
306
|
}
|
|
252
307
|
|