@jvsoft/utils 0.0.13-alpha.6 → 1.0.0-alpha.11
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 +5 -0
- package/directives/auto-select-first.directive.d.ts +13 -0
- package/directives/autocomplete-match-validator.directive.d.ts +10 -0
- package/directives/autocomplete.directive.d.ts +23 -0
- package/{src/functions → directives}/index.d.ts +1 -1
- package/directives/popover/popover-listener.directive.d.ts +12 -0
- package/directives/popover/popover-panel.component.d.ts +13 -0
- package/directives/popover/popover.directive.d.ts +23 -0
- package/directives/popover/popover.interface.d.ts +8 -0
- package/directives/popover/popover.service.d.ts +17 -0
- package/directives/public-api.d.ts +8 -0
- package/fesm2022/jvsoft-utils-directives.mjs +459 -0
- package/fesm2022/jvsoft-utils-directives.mjs.map +1 -0
- package/fesm2022/{jvsoft-utils-src-functions.mjs → jvsoft-utils-functions.mjs} +485 -191
- package/fesm2022/jvsoft-utils-functions.mjs.map +1 -0
- package/fesm2022/{jvsoft-utils-src-interfaces.mjs → jvsoft-utils-interfaces.mjs} +1 -1
- package/fesm2022/jvsoft-utils-interfaces.mjs.map +1 -0
- package/fesm2022/{jvsoft-utils-src-pipes.mjs → jvsoft-utils-pipes.mjs} +57 -2
- package/fesm2022/jvsoft-utils-pipes.mjs.map +1 -0
- package/fesm2022/jvsoft-utils-services.mjs +105 -0
- package/fesm2022/jvsoft-utils-services.mjs.map +1 -0
- package/fesm2022/jvsoft-utils.mjs +1084 -197
- package/fesm2022/jvsoft-utils.mjs.map +1 -1
- package/functions/base64.d.ts +63 -0
- package/functions/dev-log.d.ts +97 -0
- package/functions/index.d.ts +4 -0
- package/functions/mat-form-controls/autocomplete.d.ts +43 -27
- package/functions/objects-arrays.d.ts +13 -97
- package/functions/public-api.d.ts +1 -0
- package/interfaces/index.d.ts +4 -0
- package/package.json +32 -15
- package/pipes/display-with.pipe.d.ts +14 -0
- package/pipes/index.d.ts +4 -0
- package/pipes/public-api.d.ts +1 -0
- package/public-api.d.ts +6 -4
- package/{src/pipes → services}/index.d.ts +1 -1
- package/services/public-api.d.ts +1 -0
- package/services/reloj.service.d.ts +31 -0
- package/fesm2022/jvsoft-utils-src-functions.mjs.map +0 -1
- package/fesm2022/jvsoft-utils-src-interfaces.mjs.map +0 -1
- package/fesm2022/jvsoft-utils-src-pipes.mjs.map +0 -1
- package/src/functions/base64.d.ts +0 -26
- package/src/functions/browser.d.ts +0 -1
- package/src/functions/crypto-js.d.ts +0 -2
- package/src/functions/date.d.ts +0 -3
- package/src/functions/email.d.ts +0 -2
- package/src/functions/file.d.ts +0 -10
- package/src/functions/forms.d.ts +0 -23
- package/src/functions/http-client.d.ts +0 -2
- package/src/functions/local-storage.d.ts +0 -29
- package/src/functions/mat-form-controls/autocomplete.d.ts +0 -51
- package/src/functions/mat-form-controls/index.d.ts +0 -2
- package/src/functions/number.d.ts +0 -2
- package/src/functions/object-transformation.d.ts +0 -2
- package/src/functions/objects-arrays.d.ts +0 -147
- package/src/functions/public-api.d.ts +0 -16
- package/src/functions/string.d.ts +0 -23
- package/src/functions/sweetalert.d.ts +0 -5
- package/src/functions/utiles.d.ts +0 -1
- package/src/interfaces/datos.d.ts +0 -4
- package/src/interfaces/index.d.ts +0 -5
- package/src/interfaces/public-api.d.ts +0 -1
- package/src/pipes/data-en-lista.pipe.d.ts +0 -8
- package/src/pipes/date-diff-string.pipe.d.ts +0 -17
- package/src/pipes/filtro.pipe.d.ts +0 -18
- package/src/pipes/form-control-is-required.pipe.d.ts +0 -9
- package/src/pipes/json-parse.pipe.d.ts +0 -7
- package/src/pipes/no-sanitize.pipe.d.ts +0 -10
- package/src/pipes/public-api.d.ts +0 -8
- package/src/pipes/tipo-valor-funcion.pipe.d.ts +0 -9
- package/src/pipes/zero-fill.pipe.d.ts +0 -8
- /package/{classes → src/classes}/data-model.d.ts +0 -0
|
@@ -1,27 +1,24 @@
|
|
|
1
|
-
import { Validators, FormGroup, FormControl, FormArray } from '@angular/forms';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import { Validators, FormGroup, FormControl, FormArray, NG_VALIDATORS, NgControl, FormControlName } from '@angular/forms';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { inject, DestroyRef, Pipe, input, forwardRef, Directive, computed, Component, TemplateRef, Injectable, ElementRef, ViewContainerRef, HostListener, output, effect, untracked, signal } from '@angular/core';
|
|
4
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
|
+
import { tap, startWith, debounceTime, isObservable, switchMap, of, finalize, Subject, merge, distinctUntilChanged, map as map$1 } from 'rxjs';
|
|
4
6
|
import { map } from 'rxjs/operators';
|
|
5
7
|
import { Buffer } from 'buffer';
|
|
6
8
|
import CryptoJS from 'crypto-js';
|
|
7
|
-
import
|
|
9
|
+
import * as i1$1 from '@angular/common';
|
|
10
|
+
import { formatDate, CommonModule } from '@angular/common';
|
|
8
11
|
import { saveAs } from 'file-saver';
|
|
9
12
|
import { ReactiveFormConfig } from '@rxweb/reactive-form-validators';
|
|
10
13
|
import moment from 'moment';
|
|
11
14
|
import swal from 'sweetalert2';
|
|
12
15
|
import { jwtDecode } from 'jwt-decode';
|
|
13
|
-
import * as i0 from '@angular/core';
|
|
14
|
-
import { Pipe } from '@angular/core';
|
|
15
16
|
import * as i1 from '@angular/platform-browser';
|
|
17
|
+
import { Overlay, OverlayPositionBuilder } from '@angular/cdk/overlay';
|
|
18
|
+
import { ComponentPortal } from '@angular/cdk/portal';
|
|
19
|
+
import { ToastrService } from 'ngx-toastr';
|
|
20
|
+
import { format } from 'date-fns';
|
|
16
21
|
|
|
17
|
-
/**
|
|
18
|
-
* Realiza una fusión profunda entre dos objetos, sin modificar el original.
|
|
19
|
-
* Si el valor en target no es un objeto, lo reemplaza directamente.
|
|
20
|
-
*
|
|
21
|
-
* @param source - Objeto fuente que se clonará y fusionará.
|
|
22
|
-
* @param target - Objeto destino cuyos valores se fusionarán.
|
|
23
|
-
* @returns Un nuevo objeto con la fusión profunda.
|
|
24
|
-
*/
|
|
25
22
|
function deepMerge(source, target) {
|
|
26
23
|
// Crea un clon profundo sin usar JSON.parse(JSON.stringify)
|
|
27
24
|
let cloneSource = deepClone(source);
|
|
@@ -43,12 +40,7 @@ function deepMerge(source, target) {
|
|
|
43
40
|
}
|
|
44
41
|
return cloneSource; // Retorna el clon y no modifica el original
|
|
45
42
|
}
|
|
46
|
-
|
|
47
|
-
* Realiza una clonación profunda de un objeto, manejando funciones, fechas y arrays.
|
|
48
|
-
*
|
|
49
|
-
* @param obj - Objeto a clonar.
|
|
50
|
-
* @returns Una copia profunda del objeto.
|
|
51
|
-
*/
|
|
43
|
+
// Función de clonación profunda que maneja funciones, fechas y otros tipos especiales
|
|
52
44
|
function deepClone(obj) {
|
|
53
45
|
if (obj === null || typeof obj !== 'object') {
|
|
54
46
|
return obj; // Devuelve el valor si no es un objeto
|
|
@@ -74,7 +66,6 @@ function deepClone(obj) {
|
|
|
74
66
|
/**
|
|
75
67
|
* Busca un elemento en un array o jerarquía de objetos según un campo y valor especificado.
|
|
76
68
|
*
|
|
77
|
-
* @param datosFn - Objeto con los parámetros de búsqueda: items, campo, valor y opcionalmente campoHijo.
|
|
78
69
|
* @returns El elemento encontrado o undefined si no existe.
|
|
79
70
|
*/
|
|
80
71
|
function buscarPorCampo(datosFn) {
|
|
@@ -101,33 +92,13 @@ function buscarPorCampo(datosFn) {
|
|
|
101
92
|
// Si no se encuentra nada, retorna undefined
|
|
102
93
|
return undefined;
|
|
103
94
|
}
|
|
104
|
-
/**
|
|
105
|
-
* Suma los valores de las propiedades especificadas de un objeto.
|
|
106
|
-
*
|
|
107
|
-
* @param item - Objeto con las propiedades a sumar.
|
|
108
|
-
* @param campos - Array de nombres de las propiedades a sumar.
|
|
109
|
-
* @returns La suma de los valores de las propiedades.
|
|
110
|
-
*/
|
|
111
95
|
function sumarPropiedades(item, campos) {
|
|
112
96
|
const datosSumar = campos.map(campo => (item[campo] * 1));
|
|
113
97
|
return datosSumar.reduce((a, b) => a + b, 0);
|
|
114
98
|
}
|
|
115
|
-
/**
|
|
116
|
-
* Verifica si el valor proporcionado es un número válido.
|
|
117
|
-
*
|
|
118
|
-
* @param value - Valor a verificar.
|
|
119
|
-
* @returns true si es un número, false en caso contrario.
|
|
120
|
-
*/
|
|
121
99
|
function esNumero(value) {
|
|
122
100
|
return !isNaN(Number(value));
|
|
123
101
|
}
|
|
124
|
-
/**
|
|
125
|
-
* Suma los valores de las propiedades especificadas en un array de objetos.
|
|
126
|
-
*
|
|
127
|
-
* @param arrayObjetos - Array de objetos a procesar.
|
|
128
|
-
* @param campos - Array de nombres de las propiedades a sumar.
|
|
129
|
-
* @returns Objeto con la suma de cada propiedad.
|
|
130
|
-
*/
|
|
131
102
|
function sumarObjetos(arrayObjetos, campos) {
|
|
132
103
|
return arrayObjetos.reduce((accumulator, item) => {
|
|
133
104
|
campos.forEach(campo => {
|
|
@@ -139,22 +110,9 @@ function sumarObjetos(arrayObjetos, campos) {
|
|
|
139
110
|
return accumulator;
|
|
140
111
|
}, {});
|
|
141
112
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Obtiene los valores únicos de un array.
|
|
144
|
-
*
|
|
145
|
-
* @param array - Array de valores.
|
|
146
|
-
* @returns Array con los valores únicos.
|
|
147
|
-
*/
|
|
148
113
|
function getUniqueValues(array) {
|
|
149
114
|
return array.filter((currentValue, index, arr) => (arr.indexOf(currentValue) === index));
|
|
150
115
|
}
|
|
151
|
-
/**
|
|
152
|
-
* Obtiene los objetos únicos de un array según una propiedad específica.
|
|
153
|
-
*
|
|
154
|
-
* @param objetos - Array de objetos.
|
|
155
|
-
* @param campo - Nombre de la propiedad para determinar unicidad.
|
|
156
|
-
* @returns Array de objetos únicos por la propiedad.
|
|
157
|
-
*/
|
|
158
116
|
function getUniqueValuesByProperty(objetos, campo) {
|
|
159
117
|
const objetosUnicos = {};
|
|
160
118
|
objetos.forEach(objeto => {
|
|
@@ -170,14 +128,6 @@ function getUniqueValuesByProperty(objetos, campo) {
|
|
|
170
128
|
// Convertir el objeto de claves únicas de vuelta a una lista de objetos
|
|
171
129
|
return Object.values(objetosUnicos);
|
|
172
130
|
}
|
|
173
|
-
/**
|
|
174
|
-
* Ordena un array de valores numéricos o alfabéticos.
|
|
175
|
-
*
|
|
176
|
-
* @param array - Array a ordenar.
|
|
177
|
-
* @param numeros - Si es true, ordena como números.
|
|
178
|
-
* @param sentido - 'ASC' para ascendente, 'DESC' para descendente.
|
|
179
|
-
* @returns Array ordenado.
|
|
180
|
-
*/
|
|
181
131
|
function ordenarArray(array, numeros = false, sentido = 'ASC') {
|
|
182
132
|
if (numeros) {
|
|
183
133
|
if (sentido != 'ASC') {
|
|
@@ -187,24 +137,9 @@ function ordenarArray(array, numeros = false, sentido = 'ASC') {
|
|
|
187
137
|
}
|
|
188
138
|
return array.sort((a, b) => (a > b) ? 1 : ((b > a) ? -1 : 0));
|
|
189
139
|
}
|
|
190
|
-
/**
|
|
191
|
-
* Ordena un array de objetos por una propiedad específica.
|
|
192
|
-
*
|
|
193
|
-
* @param objData - Array de objetos a ordenar.
|
|
194
|
-
* @param propiedad - Propiedad por la que se ordena.
|
|
195
|
-
* @param numeros - (Obsoleto) Si es true, ordena como números.
|
|
196
|
-
* @returns Array ordenado.
|
|
197
|
-
*/
|
|
198
140
|
function ordenarPorPropiedad(objData, propiedad, /**@deprecated*/ numeros = false) {
|
|
199
141
|
return ordenarPorPropiedades(objData, { propiedades: [propiedad], direcciones: ['asc'] });
|
|
200
142
|
}
|
|
201
|
-
/**
|
|
202
|
-
* Ordena un array de objetos por varias propiedades y direcciones.
|
|
203
|
-
*
|
|
204
|
-
* @param arr - Array de objetos a ordenar.
|
|
205
|
-
* @param options - Opciones con propiedades y direcciones de orden.
|
|
206
|
-
* @returns Array ordenado.
|
|
207
|
-
*/
|
|
208
143
|
function ordenarPorPropiedades(arr, options) {
|
|
209
144
|
const { propiedades, direcciones = [] } = options;
|
|
210
145
|
const orden = direcciones.map(d => d === 'desc' ? -1 : 1);
|
|
@@ -224,13 +159,6 @@ function ordenarPorPropiedades(arr, options) {
|
|
|
224
159
|
}, 0);
|
|
225
160
|
});
|
|
226
161
|
}
|
|
227
|
-
/**
|
|
228
|
-
* Agrupa los elementos de un array según una clave o función de clave.
|
|
229
|
-
*
|
|
230
|
-
* @param array - Array de objetos a agrupar.
|
|
231
|
-
* @param key - Propiedad o función para agrupar.
|
|
232
|
-
* @returns Objeto con los grupos por clave.
|
|
233
|
-
*/
|
|
234
162
|
function groupBy(array, key) {
|
|
235
163
|
const keyFn = key instanceof Function ? key : (obj) => obj[key];
|
|
236
164
|
return array.reduce((objectsByKeyValue, obj) => {
|
|
@@ -239,13 +167,6 @@ function groupBy(array, key) {
|
|
|
239
167
|
return objectsByKeyValue;
|
|
240
168
|
}, {});
|
|
241
169
|
}
|
|
242
|
-
/**
|
|
243
|
-
* Agrupa y anida los elementos de un array según una lista de propiedades.
|
|
244
|
-
*
|
|
245
|
-
* @param arr - Array de objetos a agrupar.
|
|
246
|
-
* @param properties - Propiedades para agrupar de forma anidada.
|
|
247
|
-
* @returns Objeto anidado por los grupos de propiedades.
|
|
248
|
-
*/
|
|
249
170
|
function nestGroupsBy(arr, properties) {
|
|
250
171
|
const fnGroupBy = (conversions, property2) => {
|
|
251
172
|
return conversions.reduce((acc, obj) => {
|
|
@@ -319,13 +240,6 @@ function eliminarColumnaPorIndex(data, columnIndex) {
|
|
|
319
240
|
return newRow;
|
|
320
241
|
});
|
|
321
242
|
}
|
|
322
|
-
/**
|
|
323
|
-
* Elimina elementos duplicados de un array de objetos según claves específicas.
|
|
324
|
-
*
|
|
325
|
-
* @param array - Array de objetos.
|
|
326
|
-
* @param claves - Claves para determinar unicidad. Si no se especifica, compara todo el objeto.
|
|
327
|
-
* @returns Array sin duplicados.
|
|
328
|
-
*/
|
|
329
243
|
function eliminarDuplicados(array, claves) {
|
|
330
244
|
const unicos = new Map();
|
|
331
245
|
for (const item of array) {
|
|
@@ -338,14 +252,6 @@ function eliminarDuplicados(array, claves) {
|
|
|
338
252
|
}
|
|
339
253
|
return Array.from(unicos.values());
|
|
340
254
|
}
|
|
341
|
-
/**
|
|
342
|
-
* Elimina elementos de un array origen que estén presentes en otro array, según claves específicas.
|
|
343
|
-
*
|
|
344
|
-
* @param origen - Array original.
|
|
345
|
-
* @param elementosAEliminar - Elementos a eliminar del array origen.
|
|
346
|
-
* @param claves - Claves para comparar los objetos. Si no se especifica, compara todo el objeto.
|
|
347
|
-
* @returns Array filtrado sin los elementos eliminados.
|
|
348
|
-
*/
|
|
349
255
|
function eliminarElementos(origen, elementosAEliminar, claves) {
|
|
350
256
|
const clavesSet = new Set();
|
|
351
257
|
for (const item of elementosAEliminar) {
|
|
@@ -361,41 +267,12 @@ function eliminarElementos(origen, elementosAEliminar, claves) {
|
|
|
361
267
|
return !clavesSet.has(key);
|
|
362
268
|
});
|
|
363
269
|
}
|
|
364
|
-
|
|
365
270
|
/**
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
if (!lista)
|
|
372
|
-
return null;
|
|
373
|
-
if (campos.campoId === '*object*' || campos.campoId === '*objeto*') {
|
|
374
|
-
return lista.find((x) => JSON.stringify(x).trim() === JSON.stringify(idxSel).trim());
|
|
375
|
-
}
|
|
376
|
-
return lista.find((x) => x[campos.campoId] === idxSel);
|
|
377
|
-
};
|
|
378
|
-
const impDataMostrar = () => {
|
|
379
|
-
let vD = buscarEnLista(campos.lista) || (campos.opcExtra && buscarEnLista(campos.opcExtra));
|
|
380
|
-
if (!vD)
|
|
381
|
-
return '';
|
|
382
|
-
if (Array.isArray(campos.campoValue)) {
|
|
383
|
-
return campos.campoValue.map((vCampo) => vD[vCampo] ?? '').join(' - ').trim();
|
|
384
|
-
}
|
|
385
|
-
return (vD[campos.campoValue] ?? '').trim();
|
|
386
|
-
};
|
|
387
|
-
if (esNumero(idxSel)) {
|
|
388
|
-
if ((idxSel > 0 && campos.lista?.length) || (idxSel && typeof idxSel === 'object')) {
|
|
389
|
-
return impDataMostrar();
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
else if (campos.lista?.length) {
|
|
393
|
-
return impDataMostrar();
|
|
394
|
-
}
|
|
395
|
-
return '';
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Filtra datos locales de un array basado en un valor de búsqueda.
|
|
271
|
+
* Filtra datos localmente según un valor de búsqueda
|
|
272
|
+
* @param data - Array de datos a filtrar
|
|
273
|
+
* @param value - Valor de búsqueda
|
|
274
|
+
* @param campoBuscar - Campo(s) por el cual buscar
|
|
275
|
+
* @returns Array filtrado
|
|
399
276
|
*/
|
|
400
277
|
function filtrarDatosLocal(data, value, campoBuscar) {
|
|
401
278
|
if (!value)
|
|
@@ -414,32 +291,286 @@ function filtrarDatosLocal(data, value, campoBuscar) {
|
|
|
414
291
|
});
|
|
415
292
|
});
|
|
416
293
|
}
|
|
294
|
+
|
|
417
295
|
/**
|
|
418
|
-
*
|
|
296
|
+
* Intenta obtener el DestroyRef desde el llamador (objThis/control)
|
|
297
|
+
* o inyectándolo si estamos en un contexto de inyección.
|
|
419
298
|
*/
|
|
420
|
-
function
|
|
421
|
-
|
|
299
|
+
function obtenerDestroyRef(caller, manualDRef, fnName = 'N/A') {
|
|
300
|
+
let dRef = manualDRef || caller?.['destroyRef'] || caller?.['_destroyRef'];
|
|
301
|
+
if (!dRef) {
|
|
302
|
+
try {
|
|
303
|
+
dRef = inject(DestroyRef, { optional: true });
|
|
304
|
+
}
|
|
305
|
+
catch (e) {
|
|
306
|
+
console.warn(`${fnName}: Falló inject(DestroyRef) (fuera del contexto de inyección). Pasa el destroyRef explícitamente o decláralo en el componente para habilitar la limpieza.`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return dRef ?? undefined;
|
|
310
|
+
}
|
|
311
|
+
function mostrarValorEnBusqueda(campos, idxSel) {
|
|
312
|
+
const impDataMostrar = () => {
|
|
313
|
+
let vD;
|
|
314
|
+
if (campos.campoId == '*object*' || campos.campoId == '*objeto*') {
|
|
315
|
+
console.log(campos);
|
|
316
|
+
vD = campos.lista.find((x) => JSON.stringify(x).trim() == JSON.stringify(idxSel).trim());
|
|
317
|
+
console.log(vD);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
vD = campos.lista.find((x) => x[campos.campoId] == idxSel);
|
|
321
|
+
}
|
|
322
|
+
if (!vD && campos.opcExtra) {
|
|
323
|
+
console.log('eval ', campos.opcExtra);
|
|
324
|
+
if (campos.campoId == '*object*' || campos.campoId == '*objeto*') {
|
|
325
|
+
console.log(campos);
|
|
326
|
+
vD = campos.opcExtra.find((x) => JSON.stringify(x).trim() == JSON.stringify(idxSel).trim());
|
|
327
|
+
console.log(vD);
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
vD = campos.opcExtra.find((x) => x[campos.campoId] == idxSel);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
if (vD) {
|
|
334
|
+
let txtFinal = '';
|
|
335
|
+
if (Array.isArray(campos.campoValue)) {
|
|
336
|
+
campos.campoValue.forEach((vCampo, idx) => {
|
|
337
|
+
txtFinal += (vD[vCampo] ?? '');
|
|
338
|
+
if (idx < campos.campoValue.length - 1) {
|
|
339
|
+
txtFinal += ' - ';
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
txtFinal = vD[campos.campoValue] ?? '';
|
|
345
|
+
}
|
|
346
|
+
return txtFinal.trim();
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
console.log('ASSSSS ----- SSSS ');
|
|
350
|
+
}
|
|
351
|
+
return '';
|
|
352
|
+
};
|
|
353
|
+
if (esNumero(idxSel)) {
|
|
354
|
+
if (idxSel > 0 && campos.lista?.length > 0) {
|
|
355
|
+
return impDataMostrar();
|
|
356
|
+
}
|
|
357
|
+
else if (idxSel && typeof idxSel == 'object') {
|
|
358
|
+
return impDataMostrar();
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
if (campos.lista?.length > 0) {
|
|
363
|
+
return impDataMostrar();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return '';
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
|
|
370
|
+
*/
|
|
371
|
+
function changeSelectData(objThis, dataFiltro) {
|
|
372
|
+
const dRef = obtenerDestroyRef(objThis, dataFiltro.destroyRef, 'changeSelectData');
|
|
373
|
+
objThis['filtrados'][dataFiltro.variableResultado] = dataFiltro.formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { })).pipe(startWith(''), map(value => {
|
|
374
|
+
const varN = dataFiltro.data;
|
|
375
|
+
if (varN) {
|
|
376
|
+
if (value) {
|
|
377
|
+
return varN.map(x => x).filter(dat => {
|
|
378
|
+
if (Array.isArray(dataFiltro.campoBuscar)) {
|
|
379
|
+
let encontrado = false;
|
|
380
|
+
for (const vCampo of dataFiltro.campoBuscar) {
|
|
381
|
+
// console.log(vCampo, value, dat[vCampo]);
|
|
382
|
+
if (isNaN(Number(value))) {
|
|
383
|
+
// NO ES NUMERO
|
|
384
|
+
if (value && dat[vCampo] && dat[vCampo].toLowerCase().includes(value?.toString().toLowerCase())) {
|
|
385
|
+
encontrado = true;
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
if (value && dat[vCampo] && dat[vCampo].toString().includes(value?.toString())) {
|
|
391
|
+
encontrado = true;
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return encontrado;
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
if (isNaN(Number(value))) {
|
|
400
|
+
return dat[dataFiltro.campoBuscar].toLowerCase().includes(value?.toString().toLowerCase());
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
return dat[dataFiltro.campoBuscar].toString().includes(value?.toString());
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
return varN;
|
|
409
|
+
}
|
|
410
|
+
return false;
|
|
411
|
+
}));
|
|
422
412
|
}
|
|
423
413
|
/**
|
|
424
|
-
*
|
|
414
|
+
* @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
|
|
425
415
|
*/
|
|
426
|
-
function changeSelect(control, formControl, tipo, campoBuscar, campoFiltro = null) {
|
|
427
|
-
|
|
428
|
-
|
|
416
|
+
function changeSelect(control, formControl, tipo, campoBuscar, campoFiltro = null, destroyRef) {
|
|
417
|
+
// console.log(formControl);
|
|
418
|
+
// const formGroup = formControl.parent.controls;
|
|
419
|
+
// console.warn( Object.keys(formGroup).find(name => formControl === formGroup[name]) || null );
|
|
420
|
+
if (!campoFiltro) {
|
|
421
|
+
campoFiltro = tipo;
|
|
422
|
+
}
|
|
423
|
+
const dRef = obtenerDestroyRef(control, destroyRef, 'changeSelect');
|
|
424
|
+
control['filtrados'][campoFiltro ?? '__'] = formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { })).pipe(startWith(''), map(value => {
|
|
425
|
+
// console.warn(value);
|
|
429
426
|
const partes = tipo.split('.');
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
control
|
|
433
|
-
|
|
427
|
+
let varN;
|
|
428
|
+
if (control['dataServidor']) {
|
|
429
|
+
varN = (partes.length > 1) ? control['dataServidor'][partes[0]][partes[1]] : control['dataServidor'][tipo];
|
|
430
|
+
}
|
|
431
|
+
else if (control['dataServidorSuscripcion']) {
|
|
432
|
+
varN = control['dataServidorSuscripcion'][tipo].getValue();
|
|
433
|
+
}
|
|
434
|
+
if (varN) {
|
|
435
|
+
if (value) {
|
|
436
|
+
return varN.map((x) => x).filter((dat) => {
|
|
437
|
+
if (Array.isArray(campoBuscar)) {
|
|
438
|
+
let encontrado = false;
|
|
439
|
+
for (const vCampo of campoBuscar) {
|
|
440
|
+
// console.log(vCampo, value, dat[vCampo]);
|
|
441
|
+
if (isNaN(Number(value))) {
|
|
442
|
+
// NO ES NUMERO
|
|
443
|
+
if (value && dat[vCampo] && dat[vCampo].toLowerCase().includes(value?.toString().toLowerCase())) {
|
|
444
|
+
encontrado = true;
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
if (value && dat[vCampo] && dat[vCampo].toString().includes(value?.toString())) {
|
|
450
|
+
encontrado = true;
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return encontrado;
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
if (isNaN(Number(value))) {
|
|
459
|
+
return dat[campoBuscar].toLowerCase().includes(value?.toString().toLowerCase());
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
return dat[campoBuscar].toString().includes(value?.toString());
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
return varN;
|
|
468
|
+
}
|
|
469
|
+
return false;
|
|
434
470
|
}));
|
|
435
471
|
}
|
|
472
|
+
/**
|
|
473
|
+
* @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
|
|
474
|
+
*/
|
|
475
|
+
function changeSelectDataApi(objThis, dataFiltro) {
|
|
476
|
+
if (!dataFiltro.variableResultado) {
|
|
477
|
+
dataFiltro.variableResultado = dataFiltro.tipoReq;
|
|
478
|
+
}
|
|
479
|
+
const idFiltrado = dataFiltro.variableResultado;
|
|
480
|
+
const dRef = obtenerDestroyRef(objThis, dataFiltro.destroyRef, 'changeSelectDataApi');
|
|
481
|
+
dataFiltro.formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { }), debounceTime(500), tap(() => {
|
|
482
|
+
objThis.filtrados[dataFiltro.variableResultado + 'tmp'] = isObservable(objThis.filtrados[idFiltrado]) ? [] : objThis.filtrados[idFiltrado] || [];
|
|
483
|
+
if (objThis.filtrados[idFiltrado] !== objThis.filtrados[idFiltrado + 'tmp']) {
|
|
484
|
+
objThis.filtrados[idFiltrado] = [];
|
|
485
|
+
}
|
|
486
|
+
objThis.isLoading = true;
|
|
487
|
+
}), switchMap(value => {
|
|
488
|
+
if (dataFiltro.campoId) {
|
|
489
|
+
const busquedaActual2 = objThis.filtrados[idFiltrado + 'tmp'].findIndex((item) => item[dataFiltro.campoId ?? '--'] === value);
|
|
490
|
+
if (busquedaActual2 >= 0) {
|
|
491
|
+
return of({ [dataFiltro.tipoReq]: objThis.filtrados[idFiltrado + 'tmp'] });
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return !value || value.length < (dataFiltro.minLength ?? 3) ? [] : (dataFiltro.queryService.getDataMethod('GET', dataFiltro.tipoReq, {
|
|
495
|
+
...(dataFiltro.dataExtra ?? {}),
|
|
496
|
+
...(dataFiltro.dataExtraVariable ? Object.fromEntries(dataFiltro.dataExtraVariable.map((objData) => [objData.campo, objData.ctrlValue.value])) : {}),
|
|
497
|
+
txtBuscar: value,
|
|
498
|
+
}, dataFiltro.anonimo).pipe(finalize(() => objThis.isLoading = false)));
|
|
499
|
+
})).subscribe((data) => {
|
|
500
|
+
objThis.filtrados[idFiltrado] = data[dataFiltro.tipoReq] ?? [];
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
|
|
505
|
+
*/
|
|
506
|
+
function changeSelectApi(control, queryService, formControl, tipo, dataExtra = {}, dataExtraVariable = null, minLength = 1, anonimo = false, destroyRef) {
|
|
507
|
+
const dRef = obtenerDestroyRef(control, destroyRef, 'changeSelectApi');
|
|
508
|
+
formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { }), debounceTime(500), tap((value) => {
|
|
509
|
+
control['filtrados'][tipo + 'tmp'] = isObservable(control['filtrados'][tipo]) ? [] : control['filtrados'][tipo];
|
|
510
|
+
if (control['filtrados'][tipo] != control['filtrados'][tipo + 'tmp']) {
|
|
511
|
+
control['filtrados'][tipo] = [];
|
|
512
|
+
}
|
|
513
|
+
control['isLoading'] = true;
|
|
514
|
+
}), switchMap(value => {
|
|
515
|
+
const formGroup = formControl.parent?.controls;
|
|
516
|
+
const nombreControl = Object.keys(formGroup).find(name => formControl === formGroup[name]) || null;
|
|
517
|
+
if (nombreControl && control['filtrados'][tipo + 'tmp'] && control['filtrados'][tipo + 'tmp'].length > 0) {
|
|
518
|
+
const busquedaActual = control['filtrados'][tipo + 'tmp'].findIndex((item) => item[nombreControl] == value);
|
|
519
|
+
if (busquedaActual >= 0) {
|
|
520
|
+
const vRet = {};
|
|
521
|
+
vRet[tipo] = control['filtrados'][tipo + 'tmp'];
|
|
522
|
+
control['isLoading'] = false;
|
|
523
|
+
return of(vRet);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
if (!value || value.length < minLength) {
|
|
527
|
+
return [];
|
|
528
|
+
}
|
|
529
|
+
const dataExtraVariableData = {};
|
|
530
|
+
if (dataExtraVariable) {
|
|
531
|
+
// @ts-ignore
|
|
532
|
+
for (const objData of dataExtraVariable) {
|
|
533
|
+
dataExtraVariableData[objData.campo] = objData.ctrlValue.value;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return queryService.getDataMethod('GET', tipo, { ...dataExtra, ...dataExtraVariableData, ...{ txtBuscar: value } }, anonimo).pipe(finalize(() => {
|
|
537
|
+
control['isLoading'] = false;
|
|
538
|
+
}));
|
|
539
|
+
})).subscribe((data) => {
|
|
540
|
+
if (data[tipo] == undefined) {
|
|
541
|
+
control['filtrados'][tipo] = [];
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
control['filtrados'][tipo] = data[tipo];
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Comprueba si un valor es una Promesa
|
|
550
|
+
* @param valor - Valor a verificar
|
|
551
|
+
* @returns true si es una Promise
|
|
552
|
+
*/
|
|
553
|
+
function esPromise(valor) {
|
|
554
|
+
return !!valor && typeof valor.then === 'function';
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Selecciona todo el texto de un input
|
|
558
|
+
* @param event - Evento del input
|
|
559
|
+
*/
|
|
560
|
+
function seleccionarTextoInput$1(event) {
|
|
561
|
+
event.target.select();
|
|
562
|
+
}
|
|
436
563
|
/**
|
|
437
564
|
* Función genérica para vincular un FormControl con datos desde API o Promise.
|
|
438
565
|
* Preparada para migrar a signals en el futuro.
|
|
439
566
|
*/
|
|
567
|
+
/**
|
|
568
|
+
* @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
|
|
569
|
+
*/
|
|
440
570
|
function changeSelectReformateado(config) {
|
|
441
|
-
const { objThis, tipoReq, formControl, queryService, campoId, minLength = 3, dataExtra = {}, dataExtraVariable = [], anonimo = false, variableResultado = tipoReq, } = config;
|
|
442
|
-
|
|
571
|
+
const { objThis, tipoReq, formControl, queryService, campoId, minLength = 3, dataExtra = {}, dataExtraVariable = [], anonimo = false, variableResultado = tipoReq, destroyRef } = config;
|
|
572
|
+
const dRef = obtenerDestroyRef(objThis, destroyRef, 'changeSelectReformateado');
|
|
573
|
+
formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { }), debounceTime(500), tap(() => {
|
|
443
574
|
objThis.filtrados[variableResultado + 'tmp'] = isObservable(objThis.filtrados[variableResultado])
|
|
444
575
|
? []
|
|
445
576
|
: objThis.filtrados[variableResultado] || [];
|
|
@@ -459,10 +590,11 @@ function changeSelectReformateado(config) {
|
|
|
459
590
|
objThis.isLoading = false;
|
|
460
591
|
return of({ [tipoReq]: [] });
|
|
461
592
|
}
|
|
462
|
-
const extraVars = Object.fromEntries(dataExtraVariable.map(v => [v.campo, v.ctrlValue.value]));
|
|
593
|
+
const extraVars = Object.fromEntries(dataExtraVariable.map((v) => [v.campo, v.ctrlValue.value]));
|
|
463
594
|
const query = queryService.getDataMethod('GET', tipoReq, { ...dataExtra, ...extraVars, txtBuscar: value }, anonimo);
|
|
464
595
|
if (esPromise(query)) {
|
|
465
|
-
return query
|
|
596
|
+
return query
|
|
597
|
+
.then((data) => ({ [tipoReq]: data[tipoReq] ?? [] }))
|
|
466
598
|
.finally(() => { objThis.isLoading = false; });
|
|
467
599
|
}
|
|
468
600
|
return query.pipe(finalize(() => { objThis.isLoading = false; }));
|
|
@@ -470,57 +602,39 @@ function changeSelectReformateado(config) {
|
|
|
470
602
|
objThis.filtrados[variableResultado] = data[tipoReq] ?? [];
|
|
471
603
|
});
|
|
472
604
|
}
|
|
473
|
-
/**
|
|
474
|
-
* Alias para compatibilidad.
|
|
475
|
-
*/
|
|
476
|
-
function changeSelectDataApi(objThis, dataFiltro) {
|
|
477
|
-
return changeSelectReformateado({
|
|
478
|
-
objThis,
|
|
479
|
-
tipoReq: dataFiltro.tipoReq,
|
|
480
|
-
formControl: dataFiltro.formControl,
|
|
481
|
-
queryService: dataFiltro.queryService,
|
|
482
|
-
campoId: dataFiltro.campoId,
|
|
483
|
-
minLength: dataFiltro.minLength,
|
|
484
|
-
dataExtra: dataFiltro.dataExtra,
|
|
485
|
-
dataExtraVariable: dataFiltro.dataExtraVariable,
|
|
486
|
-
anonimo: dataFiltro.anonimo,
|
|
487
|
-
variableResultado: dataFiltro.variableResultado,
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* Alias para compatibilidad.
|
|
492
|
-
*/
|
|
493
|
-
function changeSelectApi(control, queryService, formControl, tipo, dataExtra = {}, dataExtraVariable = null, minLength = 1, anonimo = false) {
|
|
494
|
-
return changeSelectReformateado({
|
|
495
|
-
objThis: control,
|
|
496
|
-
tipoReq: tipo,
|
|
497
|
-
formControl,
|
|
498
|
-
queryService,
|
|
499
|
-
minLength,
|
|
500
|
-
dataExtra,
|
|
501
|
-
dataExtraVariable: dataExtraVariable ?? [],
|
|
502
|
-
anonimo,
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* Comprueba si un valor es una Promesa.
|
|
507
|
-
*/
|
|
508
|
-
function esPromise(valor) {
|
|
509
|
-
return !!valor && typeof valor.then === 'function';
|
|
510
|
-
}
|
|
511
605
|
|
|
512
606
|
function seleccionarTextoInput(event) {
|
|
513
607
|
event.target.select();
|
|
514
608
|
}
|
|
515
609
|
|
|
610
|
+
/**
|
|
611
|
+
* Codifica un string a base64 (método legacy)
|
|
612
|
+
* @param val - String a codificar
|
|
613
|
+
* @returns String codificado en base64
|
|
614
|
+
* @deprecated Use encodeBase64String() en su lugar
|
|
615
|
+
*/
|
|
516
616
|
function b64Encode(val) {
|
|
517
617
|
return Buffer.from(val, 'binary').toString('base64');
|
|
518
618
|
}
|
|
619
|
+
/**
|
|
620
|
+
* Decodifica un string desde base64 (método legacy)
|
|
621
|
+
* @param val - String en base64 a decodificar
|
|
622
|
+
* @returns String decodificado
|
|
623
|
+
* @deprecated Use decodeBase64String() en su lugar
|
|
624
|
+
*/
|
|
519
625
|
function b64Decode(val) {
|
|
520
626
|
return Buffer.from(val, 'base64').toString('binary');
|
|
521
627
|
}
|
|
522
628
|
/**
|
|
523
629
|
* Codificar string a Base64 (UTF-8 seguro)
|
|
630
|
+
* @param str - String a codificar
|
|
631
|
+
* @returns String codificado en base64
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
* ```typescript
|
|
635
|
+
* const encoded = encodeBase64String('Hola Mundo ñ');
|
|
636
|
+
* // encoded: "SG9sYSBNdW5kbyDDsQ=="
|
|
637
|
+
* ```
|
|
524
638
|
*/
|
|
525
639
|
function encodeBase64String(str) {
|
|
526
640
|
const encoder = new TextEncoder();
|
|
@@ -531,6 +645,14 @@ function encodeBase64String(str) {
|
|
|
531
645
|
}
|
|
532
646
|
/**
|
|
533
647
|
* Decodificar Base64 a string (UTF-8 seguro)
|
|
648
|
+
* @param b64 - String en base64 a decodificar
|
|
649
|
+
* @returns String decodificado
|
|
650
|
+
*
|
|
651
|
+
* @example
|
|
652
|
+
* ```typescript
|
|
653
|
+
* const decoded = decodeBase64String('SG9sYSBNdW5kbyDDsQ==');
|
|
654
|
+
* // decoded: "Hola Mundo ñ"
|
|
655
|
+
* ```
|
|
534
656
|
*/
|
|
535
657
|
function decodeBase64String(b64) {
|
|
536
658
|
const binary = atob(b64);
|
|
@@ -543,18 +665,43 @@ function decodeBase64String(b64) {
|
|
|
543
665
|
}
|
|
544
666
|
/**
|
|
545
667
|
* Codificar un objeto a base64 (UTF-8 seguro)
|
|
668
|
+
* @param obj - Objeto a codificar
|
|
669
|
+
* @returns String codificado en base64
|
|
670
|
+
*
|
|
671
|
+
* @example
|
|
672
|
+
* ```typescript
|
|
673
|
+
* const obj = { nombre: 'Juan', edad: 25 };
|
|
674
|
+
* const encoded = encodeBase64Object(obj);
|
|
675
|
+
* ```
|
|
546
676
|
*/
|
|
547
677
|
function encodeBase64Object(obj) {
|
|
548
678
|
return encodeBase64String(JSON.stringify(obj));
|
|
549
679
|
}
|
|
550
680
|
/**
|
|
551
681
|
* Decodificar un base64 y obtener el objeto original
|
|
682
|
+
* @param b64 - String en base64 a decodificar
|
|
683
|
+
* @returns Objeto decodificado
|
|
684
|
+
*
|
|
685
|
+
* @example
|
|
686
|
+
* ```typescript
|
|
687
|
+
* const obj = decodeBase64Object<{ nombre: string, edad: number }>(encoded);
|
|
688
|
+
* // obj: { nombre: 'Juan', edad: 25 }
|
|
689
|
+
* ```
|
|
552
690
|
*/
|
|
553
691
|
function decodeBase64Object(b64) {
|
|
554
692
|
return JSON.parse(decodeBase64String(b64));
|
|
555
693
|
}
|
|
556
694
|
/**
|
|
557
695
|
* Codificar archivo a Base64 (retorna solo el contenido, sin "data:...")
|
|
696
|
+
* @param file - Archivo o Blob a codificar
|
|
697
|
+
* @returns Promise con el string en base64
|
|
698
|
+
*
|
|
699
|
+
* @example
|
|
700
|
+
* ```typescript
|
|
701
|
+
* const file = event.target.files[0];
|
|
702
|
+
* const base64 = await encodeBase64File(file);
|
|
703
|
+
* // base64: "iVBORw0KGgoAAAANSUhEUgAA..."
|
|
704
|
+
* ```
|
|
558
705
|
*/
|
|
559
706
|
function encodeBase64File(file) {
|
|
560
707
|
return new Promise((resolve, reject) => {
|
|
@@ -569,6 +716,16 @@ function encodeBase64File(file) {
|
|
|
569
716
|
}
|
|
570
717
|
/**
|
|
571
718
|
* Decodificar Base64 a Blob (para reconstruir archivos en Angular)
|
|
719
|
+
* @param b64 - String en base64
|
|
720
|
+
* @param mimeType - Tipo MIME del archivo (opcional)
|
|
721
|
+
* @returns Blob con el contenido decodificado
|
|
722
|
+
*
|
|
723
|
+
* @example
|
|
724
|
+
* ```typescript
|
|
725
|
+
* const blob = decodeBase64ToBlob(base64String, 'image/png');
|
|
726
|
+
* const url = URL.createObjectURL(blob);
|
|
727
|
+
* // Usar url para mostrar imagen o descargar
|
|
728
|
+
* ```
|
|
572
729
|
*/
|
|
573
730
|
function decodeBase64ToBlob(b64, mimeType = 'application/octet-stream') {
|
|
574
731
|
const byteChars = atob(b64);
|
|
@@ -642,6 +799,147 @@ function formatearFechaCadena(fecha) {
|
|
|
642
799
|
return new Date(year, month, day);
|
|
643
800
|
}
|
|
644
801
|
|
|
802
|
+
/**
|
|
803
|
+
* Configuración global para las utilidades de logging
|
|
804
|
+
*/
|
|
805
|
+
let isProductionMode = false;
|
|
806
|
+
/**
|
|
807
|
+
* Configura el modo de producción para las utilidades de logging
|
|
808
|
+
* @param production - true si está en modo producción, false para desarrollo
|
|
809
|
+
*
|
|
810
|
+
* @example
|
|
811
|
+
* ```typescript
|
|
812
|
+
* import { setProductionMode } from '@jvsoft/utils';
|
|
813
|
+
* import { environment } from './environments/environment';
|
|
814
|
+
*
|
|
815
|
+
* setProductionMode(environment.production);
|
|
816
|
+
* ```
|
|
817
|
+
*/
|
|
818
|
+
function setProductionMode(production) {
|
|
819
|
+
isProductionMode = production;
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* Obtiene el estado actual del modo de producción
|
|
823
|
+
* @returns true si está en modo producción, false en desarrollo
|
|
824
|
+
*/
|
|
825
|
+
function isProduction() {
|
|
826
|
+
return isProductionMode;
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Muestra mensajes de log solo en modo desarrollo
|
|
830
|
+
* @param args - Argumentos a mostrar en consola
|
|
831
|
+
*
|
|
832
|
+
* @example
|
|
833
|
+
* ```typescript
|
|
834
|
+
* devLog('Usuario cargado:', usuario);
|
|
835
|
+
* devLog('Estado:', { activo: true, rol: 'admin' });
|
|
836
|
+
* ```
|
|
837
|
+
*/
|
|
838
|
+
function devLog(...args) {
|
|
839
|
+
if (!isProductionMode) {
|
|
840
|
+
console.log(...args);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Muestra advertencias solo en modo desarrollo
|
|
845
|
+
* @param args - Argumentos a mostrar como advertencia
|
|
846
|
+
*
|
|
847
|
+
* @example
|
|
848
|
+
* ```typescript
|
|
849
|
+
* devWarn('Función deprecada, usar nuevaFuncion() en su lugar');
|
|
850
|
+
* ```
|
|
851
|
+
*/
|
|
852
|
+
function devWarn(...args) {
|
|
853
|
+
if (!isProductionMode) {
|
|
854
|
+
console.warn(...args);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Muestra errores en consola (siempre, incluso en producción)
|
|
859
|
+
* @param args - Argumentos a mostrar como error
|
|
860
|
+
*
|
|
861
|
+
* @example
|
|
862
|
+
* ```typescript
|
|
863
|
+
* devError('Error al cargar datos:', error);
|
|
864
|
+
* ```
|
|
865
|
+
*/
|
|
866
|
+
function devError(...args) {
|
|
867
|
+
console.error(...args);
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Crea un grupo de logs solo en modo desarrollo
|
|
871
|
+
* @param label - Etiqueta del grupo
|
|
872
|
+
* @param collapsed - Si el grupo debe estar colapsado por defecto
|
|
873
|
+
*
|
|
874
|
+
* @example
|
|
875
|
+
* ```typescript
|
|
876
|
+
* devGroup('Datos del usuario');
|
|
877
|
+
* devLog('Nombre:', usuario.nombre);
|
|
878
|
+
* devLog('Email:', usuario.email);
|
|
879
|
+
* devGroupEnd();
|
|
880
|
+
* ```
|
|
881
|
+
*/
|
|
882
|
+
function devGroup(label, collapsed = false) {
|
|
883
|
+
if (!isProductionMode) {
|
|
884
|
+
if (collapsed) {
|
|
885
|
+
console.groupCollapsed(label);
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
console.group(label);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Cierra el grupo de logs actual
|
|
894
|
+
*/
|
|
895
|
+
function devGroupEnd() {
|
|
896
|
+
if (!isProductionMode) {
|
|
897
|
+
console.groupEnd();
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Muestra una tabla en consola solo en modo desarrollo
|
|
902
|
+
* @param data - Datos a mostrar en formato tabla
|
|
903
|
+
*
|
|
904
|
+
* @example
|
|
905
|
+
* ```typescript
|
|
906
|
+
* devTable([
|
|
907
|
+
* { nombre: 'Juan', edad: 25 },
|
|
908
|
+
* { nombre: 'María', edad: 30 }
|
|
909
|
+
* ]);
|
|
910
|
+
* ```
|
|
911
|
+
*/
|
|
912
|
+
function devTable(data) {
|
|
913
|
+
if (!isProductionMode) {
|
|
914
|
+
console.table(data);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Inicia un temporizador solo en modo desarrollo
|
|
919
|
+
* @param label - Etiqueta del temporizador
|
|
920
|
+
*
|
|
921
|
+
* @example
|
|
922
|
+
* ```typescript
|
|
923
|
+
* devTime('carga-datos');
|
|
924
|
+
* // ... código a medir
|
|
925
|
+
* devTimeEnd('carga-datos'); // Muestra: carga-datos: 123.45ms
|
|
926
|
+
* ```
|
|
927
|
+
*/
|
|
928
|
+
function devTime(label) {
|
|
929
|
+
if (!isProductionMode) {
|
|
930
|
+
console.time(label);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Finaliza un temporizador y muestra el tiempo transcurrido
|
|
935
|
+
* @param label - Etiqueta del temporizador
|
|
936
|
+
*/
|
|
937
|
+
function devTimeEnd(label) {
|
|
938
|
+
if (!isProductionMode) {
|
|
939
|
+
console.timeEnd(label);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
645
943
|
function maskEmail(email) {
|
|
646
944
|
const [user, domain] = email.split("@");
|
|
647
945
|
if (user.length <= 2) {
|
|
@@ -1850,18 +2148,607 @@ function zeroFill(value, digitos, ...args) {
|
|
|
1850
2148
|
return new ZeroFillPipe().transform(value, digitos, args);
|
|
1851
2149
|
}
|
|
1852
2150
|
|
|
2151
|
+
class JvsDisplayWithPipe {
|
|
2152
|
+
/**
|
|
2153
|
+
* Retorna una función compatible con [displayWith] de MatAutocomplete.
|
|
2154
|
+
* @param lista La lista de objetos donde buscar.
|
|
2155
|
+
* @param campoId El nombre del campo que coincide con el valor del control (ej: 'iCarreraId').
|
|
2156
|
+
* @param campoValue El nombre del campo (o campos) a mostrar (ej: 'cCarreraNombre' o ['cCodigo', 'cNombre']).
|
|
2157
|
+
* @param opcExtra Lista opcional de objetos extra donde buscar si no se encuentra en la lista principal.
|
|
2158
|
+
*/
|
|
2159
|
+
transform(lista, campoId, campoValue, opcExtra) {
|
|
2160
|
+
return (idxSel) => {
|
|
2161
|
+
if (idxSel === null || idxSel === undefined || !lista) {
|
|
2162
|
+
return '';
|
|
2163
|
+
}
|
|
2164
|
+
const impDataMostrar = (vD) => {
|
|
2165
|
+
if (!vD)
|
|
2166
|
+
return '';
|
|
2167
|
+
if (Array.isArray(campoValue)) {
|
|
2168
|
+
return campoValue
|
|
2169
|
+
.map(field => vD[field] ?? '')
|
|
2170
|
+
.filter(val => !!val)
|
|
2171
|
+
.join(' - ');
|
|
2172
|
+
}
|
|
2173
|
+
return vD[campoValue]?.toString() || '';
|
|
2174
|
+
};
|
|
2175
|
+
// Buscar en la lista principal
|
|
2176
|
+
let item;
|
|
2177
|
+
if (campoId === '*object*' || campoId === '*objeto*') {
|
|
2178
|
+
item = lista.find(x => JSON.stringify(x).trim() === JSON.stringify(idxSel).trim());
|
|
2179
|
+
}
|
|
2180
|
+
else {
|
|
2181
|
+
item = lista.find(x => x[campoId] == idxSel);
|
|
2182
|
+
}
|
|
2183
|
+
// Si no se encuentra, buscar en opcExtra
|
|
2184
|
+
if (!item && opcExtra) {
|
|
2185
|
+
if (campoId === '*object*' || campoId === '*objeto*') {
|
|
2186
|
+
item = opcExtra.find(x => JSON.stringify(x).trim() === JSON.stringify(idxSel).trim());
|
|
2187
|
+
}
|
|
2188
|
+
else {
|
|
2189
|
+
item = opcExtra.find(x => x[campoId] == idxSel);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
return item ? impDataMostrar(item).trim() : '';
|
|
2193
|
+
};
|
|
2194
|
+
}
|
|
2195
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsDisplayWithPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
2196
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: JvsDisplayWithPipe, isStandalone: true, name: "jvsDisplayWith" });
|
|
2197
|
+
}
|
|
2198
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsDisplayWithPipe, decorators: [{
|
|
2199
|
+
type: Pipe,
|
|
2200
|
+
args: [{
|
|
2201
|
+
name: 'jvsDisplayWith',
|
|
2202
|
+
standalone: true
|
|
2203
|
+
}]
|
|
2204
|
+
}] });
|
|
2205
|
+
|
|
1853
2206
|
// export * from './otros';
|
|
1854
2207
|
|
|
2208
|
+
class AutocompleteMatchValidatorDirective {
|
|
2209
|
+
opciones = input([], { alias: 'jvsAutocompleteMatch' });
|
|
2210
|
+
formControlName = input();
|
|
2211
|
+
idLista = input();
|
|
2212
|
+
validate(control) {
|
|
2213
|
+
const idLista = this.idLista() ?? this.formControlName();
|
|
2214
|
+
const value = control.value;
|
|
2215
|
+
const opciones = this.opciones();
|
|
2216
|
+
if (!value)
|
|
2217
|
+
return null;
|
|
2218
|
+
if (!opciones) {
|
|
2219
|
+
console.error('Debe definir opciones para el validador jvsAutocompleteMatch');
|
|
2220
|
+
return { itemSelected: true };
|
|
2221
|
+
}
|
|
2222
|
+
const encontrado = opciones.some(item => typeof value === 'object'
|
|
2223
|
+
? item[idLista] === value[idLista]
|
|
2224
|
+
: item[idLista] === value);
|
|
2225
|
+
return encontrado ? null : { itemSelected: true };
|
|
2226
|
+
}
|
|
2227
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AutocompleteMatchValidatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2228
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.14", type: AutocompleteMatchValidatorDirective, isStandalone: true, selector: "[jvsAutocompleteMatch]", inputs: { opciones: { classPropertyName: "opciones", publicName: "jvsAutocompleteMatch", isSignal: true, isRequired: false, transformFunction: null }, formControlName: { classPropertyName: "formControlName", publicName: "formControlName", isSignal: true, isRequired: false, transformFunction: null }, idLista: { classPropertyName: "idLista", publicName: "idLista", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
2229
|
+
{
|
|
2230
|
+
provide: NG_VALIDATORS,
|
|
2231
|
+
useExisting: forwardRef(() => AutocompleteMatchValidatorDirective),
|
|
2232
|
+
multi: true,
|
|
2233
|
+
},
|
|
2234
|
+
], ngImport: i0 });
|
|
2235
|
+
}
|
|
2236
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AutocompleteMatchValidatorDirective, decorators: [{
|
|
2237
|
+
type: Directive,
|
|
2238
|
+
args: [{
|
|
2239
|
+
selector: '[jvsAutocompleteMatch]',
|
|
2240
|
+
providers: [
|
|
2241
|
+
{
|
|
2242
|
+
provide: NG_VALIDATORS,
|
|
2243
|
+
useExisting: forwardRef(() => AutocompleteMatchValidatorDirective),
|
|
2244
|
+
multi: true,
|
|
2245
|
+
},
|
|
2246
|
+
],
|
|
2247
|
+
standalone: true
|
|
2248
|
+
}]
|
|
2249
|
+
}] });
|
|
2250
|
+
|
|
2251
|
+
class JvsPopoverPanelComponent {
|
|
2252
|
+
content = input(null);
|
|
2253
|
+
templateContent = input(null);
|
|
2254
|
+
context = input(null);
|
|
2255
|
+
customClass = input('');
|
|
2256
|
+
baseClasses = 'bg-white shadow-md rounded border-sm border-gray-700 p-1 mat-elevation-z4';
|
|
2257
|
+
combinedClasses = computed(() => {
|
|
2258
|
+
return `${this.baseClasses} ${this.customClass()}`.trim();
|
|
2259
|
+
});
|
|
2260
|
+
isTemplate() {
|
|
2261
|
+
return !!this.templateContent();
|
|
2262
|
+
}
|
|
2263
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsPopoverPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2264
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.14", type: JvsPopoverPanelComponent, isStandalone: true, selector: "jvs-popover-panel", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, templateContent: { classPropertyName: "templateContent", publicName: "templateContent", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, customClass: { classPropertyName: "customClass", publicName: "customClass", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2265
|
+
<div [class]="combinedClasses()">
|
|
2266
|
+
<ng-container *ngIf="isTemplate(); else htmlContent">
|
|
2267
|
+
<ng-container *ngTemplateOutlet="templateContent(); context: context()"></ng-container>
|
|
2268
|
+
</ng-container>
|
|
2269
|
+
<ng-template #htmlContent>
|
|
2270
|
+
<div [innerHTML]="content()"></div>
|
|
2271
|
+
</ng-template>
|
|
2272
|
+
</div>
|
|
2273
|
+
`, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
2274
|
+
}
|
|
2275
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsPopoverPanelComponent, decorators: [{
|
|
2276
|
+
type: Component,
|
|
2277
|
+
args: [{ selector: 'jvs-popover-panel', standalone: true, imports: [CommonModule], template: `
|
|
2278
|
+
<div [class]="combinedClasses()">
|
|
2279
|
+
<ng-container *ngIf="isTemplate(); else htmlContent">
|
|
2280
|
+
<ng-container *ngTemplateOutlet="templateContent(); context: context()"></ng-container>
|
|
2281
|
+
</ng-container>
|
|
2282
|
+
<ng-template #htmlContent>
|
|
2283
|
+
<div [innerHTML]="content()"></div>
|
|
2284
|
+
</ng-template>
|
|
2285
|
+
</div>
|
|
2286
|
+
`, styles: [":host{display:block}\n"] }]
|
|
2287
|
+
}] });
|
|
2288
|
+
|
|
2289
|
+
class JvsPopoverService {
|
|
2290
|
+
overlay = inject(Overlay);
|
|
2291
|
+
overlayPositionBuilder = inject(OverlayPositionBuilder);
|
|
2292
|
+
overlayRef = null;
|
|
2293
|
+
open(element, content, options = {}) {
|
|
2294
|
+
this.close();
|
|
2295
|
+
const positionStrategy = this.overlayPositionBuilder
|
|
2296
|
+
.flexibleConnectedTo(element)
|
|
2297
|
+
.withPositions([
|
|
2298
|
+
{
|
|
2299
|
+
originX: 'center',
|
|
2300
|
+
originY: options.position === 'top' ? 'top' : 'bottom',
|
|
2301
|
+
overlayX: 'center',
|
|
2302
|
+
overlayY: options.position === 'top' ? 'bottom' : 'top',
|
|
2303
|
+
offsetY: options.position === 'top' ? -8 : 8
|
|
2304
|
+
}
|
|
2305
|
+
]);
|
|
2306
|
+
this.overlayRef = this.overlay.create({
|
|
2307
|
+
positionStrategy,
|
|
2308
|
+
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
2309
|
+
hasBackdrop: false
|
|
2310
|
+
});
|
|
2311
|
+
const portal = new ComponentPortal(JvsPopoverPanelComponent, options.viewContainerRef);
|
|
2312
|
+
const containerRef = this.overlayRef.attach(portal);
|
|
2313
|
+
if (content instanceof TemplateRef) {
|
|
2314
|
+
containerRef.setInput('templateContent', content);
|
|
2315
|
+
}
|
|
2316
|
+
else {
|
|
2317
|
+
containerRef.setInput('content', content);
|
|
2318
|
+
}
|
|
2319
|
+
if (options.customClass) {
|
|
2320
|
+
containerRef.setInput('customClass', options.customClass);
|
|
2321
|
+
}
|
|
2322
|
+
if (options.context) {
|
|
2323
|
+
containerRef.setInput('context', options.context);
|
|
2324
|
+
}
|
|
2325
|
+
return this.overlayRef;
|
|
2326
|
+
}
|
|
2327
|
+
close() {
|
|
2328
|
+
if (this.overlayRef) {
|
|
2329
|
+
this.overlayRef.detach();
|
|
2330
|
+
this.overlayRef.dispose();
|
|
2331
|
+
this.overlayRef = null;
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsPopoverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2335
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsPopoverService, providedIn: 'root' });
|
|
2336
|
+
}
|
|
2337
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsPopoverService, decorators: [{
|
|
2338
|
+
type: Injectable,
|
|
2339
|
+
args: [{
|
|
2340
|
+
providedIn: 'root'
|
|
2341
|
+
}]
|
|
2342
|
+
}] });
|
|
2343
|
+
|
|
2344
|
+
class JvsPopoverDirective {
|
|
2345
|
+
popoverService = inject(JvsPopoverService);
|
|
2346
|
+
elementRef = inject(ElementRef);
|
|
2347
|
+
viewContainerRef = inject(ViewContainerRef);
|
|
2348
|
+
content = input(null, { alias: 'jvsPopover' });
|
|
2349
|
+
context = input(null);
|
|
2350
|
+
trigger = input('hover');
|
|
2351
|
+
position = input('bottom');
|
|
2352
|
+
customClass = input('');
|
|
2353
|
+
onMouseEnter() {
|
|
2354
|
+
if (this.trigger() === 'hover') {
|
|
2355
|
+
this.show();
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
onMouseLeave() {
|
|
2359
|
+
if (this.trigger() === 'hover') {
|
|
2360
|
+
this.hide();
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
onClick() {
|
|
2364
|
+
if (this.trigger() === 'click') {
|
|
2365
|
+
this.show();
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
onFocus() {
|
|
2369
|
+
if (this.trigger() === 'focus') {
|
|
2370
|
+
this.show();
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
onBlur() {
|
|
2374
|
+
if (this.trigger() === 'focus') {
|
|
2375
|
+
this.hide();
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
ngOnDestroy() {
|
|
2379
|
+
this.hide();
|
|
2380
|
+
}
|
|
2381
|
+
show() {
|
|
2382
|
+
const content = this.content();
|
|
2383
|
+
if (!content)
|
|
2384
|
+
return;
|
|
2385
|
+
this.popoverService.open(this.elementRef.nativeElement, content, {
|
|
2386
|
+
position: this.position(),
|
|
2387
|
+
customClass: this.customClass(),
|
|
2388
|
+
viewContainerRef: this.viewContainerRef,
|
|
2389
|
+
context: this.context()
|
|
2390
|
+
});
|
|
2391
|
+
}
|
|
2392
|
+
hide() {
|
|
2393
|
+
this.popoverService.close();
|
|
2394
|
+
}
|
|
2395
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsPopoverDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2396
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.14", type: JvsPopoverDirective, isStandalone: true, selector: "[jvsPopover]", inputs: { content: { classPropertyName: "content", publicName: "jvsPopover", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, customClass: { classPropertyName: "customClass", publicName: "customClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "click": "onClick()", "focusin": "onFocus()", "focusout": "onBlur()" } }, ngImport: i0 });
|
|
2397
|
+
}
|
|
2398
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsPopoverDirective, decorators: [{
|
|
2399
|
+
type: Directive,
|
|
2400
|
+
args: [{
|
|
2401
|
+
selector: '[jvsPopover]',
|
|
2402
|
+
standalone: true
|
|
2403
|
+
}]
|
|
2404
|
+
}], propDecorators: { onMouseEnter: [{
|
|
2405
|
+
type: HostListener,
|
|
2406
|
+
args: ['mouseenter']
|
|
2407
|
+
}], onMouseLeave: [{
|
|
2408
|
+
type: HostListener,
|
|
2409
|
+
args: ['mouseleave']
|
|
2410
|
+
}], onClick: [{
|
|
2411
|
+
type: HostListener,
|
|
2412
|
+
args: ['click']
|
|
2413
|
+
}], onFocus: [{
|
|
2414
|
+
type: HostListener,
|
|
2415
|
+
args: ['focusin']
|
|
2416
|
+
}], onBlur: [{
|
|
2417
|
+
type: HostListener,
|
|
2418
|
+
args: ['focusout']
|
|
2419
|
+
}] } });
|
|
2420
|
+
|
|
2421
|
+
class JvsPopoverListenerDirective {
|
|
2422
|
+
popoverService = inject(JvsPopoverService);
|
|
2423
|
+
elementRef = inject(ElementRef);
|
|
2424
|
+
trigger = input('hover');
|
|
2425
|
+
onMouseOver(event) {
|
|
2426
|
+
if (this.trigger() !== 'hover')
|
|
2427
|
+
return;
|
|
2428
|
+
const target = this.findPopoverTarget(event.target);
|
|
2429
|
+
if (target) {
|
|
2430
|
+
const content = target.getAttribute('data-jvs-popover');
|
|
2431
|
+
if (content) {
|
|
2432
|
+
this.popoverService.open(target, content, {
|
|
2433
|
+
position: target.getAttribute('data-jvs-position') || 'bottom',
|
|
2434
|
+
customClass: target.getAttribute('data-jvs-class') || ''
|
|
2435
|
+
});
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
onMouseOut(event) {
|
|
2440
|
+
if (this.trigger() !== 'hover')
|
|
2441
|
+
return;
|
|
2442
|
+
this.popoverService.close();
|
|
2443
|
+
}
|
|
2444
|
+
onClick(event) {
|
|
2445
|
+
if (this.trigger() !== 'click')
|
|
2446
|
+
return;
|
|
2447
|
+
const target = this.findPopoverTarget(event.target);
|
|
2448
|
+
if (target) {
|
|
2449
|
+
const content = target.getAttribute('data-jvs-popover');
|
|
2450
|
+
if (content) {
|
|
2451
|
+
this.popoverService.open(target, content, {
|
|
2452
|
+
position: target.getAttribute('data-jvs-position') || 'bottom',
|
|
2453
|
+
customClass: target.getAttribute('data-jvs-class') || ''
|
|
2454
|
+
});
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
findPopoverTarget(el) {
|
|
2459
|
+
while (el && el !== this.elementRef.nativeElement) {
|
|
2460
|
+
if (el.hasAttribute('data-jvs-popover')) {
|
|
2461
|
+
return el;
|
|
2462
|
+
}
|
|
2463
|
+
el = el.parentElement;
|
|
2464
|
+
}
|
|
2465
|
+
return null;
|
|
2466
|
+
}
|
|
2467
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsPopoverListenerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2468
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.14", type: JvsPopoverListenerDirective, isStandalone: true, selector: "[jvsPopoverListener]", inputs: { trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseover": "onMouseOver($event)", "mouseout": "onMouseOut($event)", "click": "onClick($event)" } }, ngImport: i0 });
|
|
2469
|
+
}
|
|
2470
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsPopoverListenerDirective, decorators: [{
|
|
2471
|
+
type: Directive,
|
|
2472
|
+
args: [{
|
|
2473
|
+
selector: '[jvsPopoverListener]',
|
|
2474
|
+
standalone: true
|
|
2475
|
+
}]
|
|
2476
|
+
}], propDecorators: { onMouseOver: [{
|
|
2477
|
+
type: HostListener,
|
|
2478
|
+
args: ['mouseover', ['$event']]
|
|
2479
|
+
}], onMouseOut: [{
|
|
2480
|
+
type: HostListener,
|
|
2481
|
+
args: ['mouseout', ['$event']]
|
|
2482
|
+
}], onClick: [{
|
|
2483
|
+
type: HostListener,
|
|
2484
|
+
args: ['click', ['$event']]
|
|
2485
|
+
}] } });
|
|
2486
|
+
|
|
2487
|
+
class JvsAutocompleteDirective {
|
|
2488
|
+
destroyRef = inject(DestroyRef);
|
|
2489
|
+
ngControl = inject(NgControl, { optional: true });
|
|
2490
|
+
focus$ = new Subject();
|
|
2491
|
+
// Signal-based Inputs
|
|
2492
|
+
data = input(null);
|
|
2493
|
+
fields = input('');
|
|
2494
|
+
typeReq = input('');
|
|
2495
|
+
queryService = input(null);
|
|
2496
|
+
minLength = input(3);
|
|
2497
|
+
dataExtra = input({});
|
|
2498
|
+
anonimo = input(false);
|
|
2499
|
+
debounce = input(300);
|
|
2500
|
+
// Modern Outputs
|
|
2501
|
+
filtered = output();
|
|
2502
|
+
loading = output();
|
|
2503
|
+
onFocus() {
|
|
2504
|
+
this.focus$.next();
|
|
2505
|
+
}
|
|
2506
|
+
ngOnInit() {
|
|
2507
|
+
const control = this.ngControl;
|
|
2508
|
+
if (!control || !control.valueChanges) {
|
|
2509
|
+
console.warn('JvsAutocompleteDirective: No se encontró ngControl o valueChanges. Asegúrate de que el input tenga un formControl o formControlName.');
|
|
2510
|
+
return;
|
|
2511
|
+
}
|
|
2512
|
+
// Si es data local, bajamos el debounce por defecto a 0 si no se ha especificado
|
|
2513
|
+
const isLocal = this.data() && !this.typeReq();
|
|
2514
|
+
const actualDebounce = (isLocal && this.debounce() === 300) ? 0 : this.debounce();
|
|
2515
|
+
merge(control.valueChanges.pipe(debounceTime(actualDebounce)), this.focus$).pipe(takeUntilDestroyed(this.destroyRef), startWith(control.value), distinctUntilChanged(), tap(() => {
|
|
2516
|
+
if (this.typeReq())
|
|
2517
|
+
this.loading.emit(true);
|
|
2518
|
+
}), switchMap(() => {
|
|
2519
|
+
const value = control.value;
|
|
2520
|
+
// Si el valor es un objeto (proviene de seleccionar una opción), no volvemos a filtrar
|
|
2521
|
+
if (typeof value === 'object' && value !== null) {
|
|
2522
|
+
if (this.typeReq())
|
|
2523
|
+
this.loading.emit(false);
|
|
2524
|
+
return of(null);
|
|
2525
|
+
}
|
|
2526
|
+
if (this.typeReq() && this.queryService()) {
|
|
2527
|
+
return this.fetchApi(value?.toString() || '');
|
|
2528
|
+
}
|
|
2529
|
+
else if (this.data()) {
|
|
2530
|
+
const res = this.filterLocal(value?.toString() || '');
|
|
2531
|
+
return of(res);
|
|
2532
|
+
}
|
|
2533
|
+
if (this.typeReq())
|
|
2534
|
+
this.loading.emit(false);
|
|
2535
|
+
return of([]);
|
|
2536
|
+
})).subscribe((result) => {
|
|
2537
|
+
if (result !== null) {
|
|
2538
|
+
this.filtered.emit(result);
|
|
2539
|
+
}
|
|
2540
|
+
});
|
|
2541
|
+
}
|
|
2542
|
+
filterLocal(value) {
|
|
2543
|
+
const data = this.data();
|
|
2544
|
+
if (!value)
|
|
2545
|
+
return data || [];
|
|
2546
|
+
const search = value.toLowerCase();
|
|
2547
|
+
const rawFields = this.fields();
|
|
2548
|
+
const fields = Array.isArray(rawFields) ? rawFields : [rawFields];
|
|
2549
|
+
return (data || []).filter(item => {
|
|
2550
|
+
return fields.some(field => {
|
|
2551
|
+
const val = item[field];
|
|
2552
|
+
return val && val.toString().toLowerCase().includes(search);
|
|
2553
|
+
});
|
|
2554
|
+
});
|
|
2555
|
+
}
|
|
2556
|
+
fetchApi(value) {
|
|
2557
|
+
const typeReq = this.typeReq();
|
|
2558
|
+
const queryService = this.queryService();
|
|
2559
|
+
if (!value || value.length < this.minLength()) {
|
|
2560
|
+
this.loading.emit(false);
|
|
2561
|
+
return of([]);
|
|
2562
|
+
}
|
|
2563
|
+
return queryService.getDataMethod('GET', typeReq, {
|
|
2564
|
+
...this.dataExtra(),
|
|
2565
|
+
txtBuscar: value
|
|
2566
|
+
}, this.anonimo()).pipe(map$1((res) => res[typeReq] ?? []), finalize(() => this.loading.emit(false)));
|
|
2567
|
+
}
|
|
2568
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsAutocompleteDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2569
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.14", type: JvsAutocompleteDirective, isStandalone: true, selector: "[jvsAutocomplete]", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null }, typeReq: { classPropertyName: "typeReq", publicName: "typeReq", isSignal: true, isRequired: false, transformFunction: null }, queryService: { classPropertyName: "queryService", publicName: "queryService", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, dataExtra: { classPropertyName: "dataExtra", publicName: "dataExtra", isSignal: true, isRequired: false, transformFunction: null }, anonimo: { classPropertyName: "anonimo", publicName: "anonimo", isSignal: true, isRequired: false, transformFunction: null }, debounce: { classPropertyName: "debounce", publicName: "debounce", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filtered: "filtered", loading: "loading" }, host: { listeners: { "focus": "onFocus()" } }, ngImport: i0 });
|
|
2570
|
+
}
|
|
2571
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsAutocompleteDirective, decorators: [{
|
|
2572
|
+
type: Directive,
|
|
2573
|
+
args: [{
|
|
2574
|
+
selector: '[jvsAutocomplete]',
|
|
2575
|
+
standalone: true
|
|
2576
|
+
}]
|
|
2577
|
+
}], propDecorators: { onFocus: [{
|
|
2578
|
+
type: HostListener,
|
|
2579
|
+
args: ['focus']
|
|
2580
|
+
}] } });
|
|
2581
|
+
|
|
2582
|
+
class AutoSelectFirstDirective {
|
|
2583
|
+
ngControl = inject(NgControl, { optional: true });
|
|
2584
|
+
fcName = inject(FormControlName, { optional: true });
|
|
2585
|
+
toastr = inject(ToastrService, { optional: true });
|
|
2586
|
+
// Inputs using Signals
|
|
2587
|
+
options = input(null, { alias: 'jvsAutoSelectFirst' });
|
|
2588
|
+
jvsIdKey = input(null);
|
|
2589
|
+
jvsEmptyMsg = input('Lista sin elementos');
|
|
2590
|
+
onAutoSelect = output();
|
|
2591
|
+
constructor() {
|
|
2592
|
+
effect(() => {
|
|
2593
|
+
const currentOptions = this.options();
|
|
2594
|
+
const idKey = this.jvsIdKey();
|
|
2595
|
+
const emptyMsg = this.jvsEmptyMsg();
|
|
2596
|
+
if (currentOptions === null)
|
|
2597
|
+
return;
|
|
2598
|
+
const optionsArray = Array.isArray(currentOptions) ? currentOptions : [];
|
|
2599
|
+
if (optionsArray.length > 0) {
|
|
2600
|
+
untracked(() => {
|
|
2601
|
+
const control = this.ngControl?.control;
|
|
2602
|
+
const currentValue = control?.value;
|
|
2603
|
+
// Only autoselect if empty
|
|
2604
|
+
if (control && (currentValue === null || currentValue === undefined || currentValue === '')) {
|
|
2605
|
+
const firstItem = optionsArray[0];
|
|
2606
|
+
let valueToSet;
|
|
2607
|
+
// Resolve key
|
|
2608
|
+
let effectiveKey = idKey;
|
|
2609
|
+
// Default to formControlName if not provided
|
|
2610
|
+
if (!effectiveKey && this.fcName) {
|
|
2611
|
+
effectiveKey = this.fcName.name;
|
|
2612
|
+
}
|
|
2613
|
+
if (effectiveKey) {
|
|
2614
|
+
if (Array.isArray(effectiveKey)) {
|
|
2615
|
+
// Composite key: build an object with the specified keys
|
|
2616
|
+
valueToSet = {};
|
|
2617
|
+
effectiveKey.forEach(key => {
|
|
2618
|
+
valueToSet[key] = firstItem[key];
|
|
2619
|
+
});
|
|
2620
|
+
}
|
|
2621
|
+
else {
|
|
2622
|
+
valueToSet = firstItem[effectiveKey];
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
else {
|
|
2626
|
+
// Use whole item if no key resolution possible
|
|
2627
|
+
valueToSet = firstItem;
|
|
2628
|
+
}
|
|
2629
|
+
control.setValue(valueToSet);
|
|
2630
|
+
this.onAutoSelect.emit(firstItem);
|
|
2631
|
+
}
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2634
|
+
else if (emptyMsg && this.toastr) {
|
|
2635
|
+
this.toastr.warning(emptyMsg, 'Filtrado');
|
|
2636
|
+
}
|
|
2637
|
+
});
|
|
2638
|
+
}
|
|
2639
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AutoSelectFirstDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2640
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.14", type: AutoSelectFirstDirective, isStandalone: true, selector: "[jvsAutoSelectFirst]", inputs: { options: { classPropertyName: "options", publicName: "jvsAutoSelectFirst", isSignal: true, isRequired: false, transformFunction: null }, jvsIdKey: { classPropertyName: "jvsIdKey", publicName: "jvsIdKey", isSignal: true, isRequired: false, transformFunction: null }, jvsEmptyMsg: { classPropertyName: "jvsEmptyMsg", publicName: "jvsEmptyMsg", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAutoSelect: "onAutoSelect" }, ngImport: i0 });
|
|
2641
|
+
}
|
|
2642
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AutoSelectFirstDirective, decorators: [{
|
|
2643
|
+
type: Directive,
|
|
2644
|
+
args: [{
|
|
2645
|
+
selector: '[jvsAutoSelectFirst]',
|
|
2646
|
+
standalone: true
|
|
2647
|
+
}]
|
|
2648
|
+
}], ctorParameters: () => [] });
|
|
2649
|
+
|
|
2650
|
+
class RelojService {
|
|
2651
|
+
// El offset es la diferencia: ServerTime - LocalTime (performance.now())
|
|
2652
|
+
offset = signal(0);
|
|
2653
|
+
STORAGE_KEY = 'srv_clock_offset';
|
|
2654
|
+
// Signal que cambia cada segundo para forzar la reactividad del reloj
|
|
2655
|
+
ticker = signal(0);
|
|
2656
|
+
// Hora actual calculada basándose en performance.now() para evitar drift y suspensión
|
|
2657
|
+
timestamp = computed(() => {
|
|
2658
|
+
this.ticker(); // Dependencia reactiva para que el computed se ejecute cada segundo
|
|
2659
|
+
// performance.now() es monotónico, Date.now() es manipulable por el usuario
|
|
2660
|
+
// Usamos Date.now() inicialmente pero ajustado por el offset calculado
|
|
2661
|
+
return Date.now() + this.offset();
|
|
2662
|
+
});
|
|
2663
|
+
date = computed(() => new Date(this.timestamp()));
|
|
2664
|
+
dateTime = computed(() => {
|
|
2665
|
+
return format(this.date(), "yyyy-MM-dd'T'HH:mm");
|
|
2666
|
+
});
|
|
2667
|
+
constructor() {
|
|
2668
|
+
this.cargarOffsetInicial();
|
|
2669
|
+
this.escucharCambiosOtrasPestanas();
|
|
2670
|
+
this.iniciarVigilanteWarp();
|
|
2671
|
+
// Iniciar el ticker que mantiene el reloj vivo
|
|
2672
|
+
setInterval(() => {
|
|
2673
|
+
this.ticker.update(n => n + 1);
|
|
2674
|
+
}, 1000);
|
|
2675
|
+
}
|
|
2676
|
+
/**
|
|
2677
|
+
* Sincroniza el reloj interno con una hora oficial del servidor.
|
|
2678
|
+
* Calculamos el offset respecto al tiempo local actual.
|
|
2679
|
+
*/
|
|
2680
|
+
sincronizar(serverTime) {
|
|
2681
|
+
const srvTime = new Date(serverTime).getTime();
|
|
2682
|
+
const lclTime = Date.now();
|
|
2683
|
+
const nuevoOffset = srvTime - lclTime;
|
|
2684
|
+
this.offset.set(nuevoOffset);
|
|
2685
|
+
localStorage.setItem(this.STORAGE_KEY, nuevoOffset.toString());
|
|
2686
|
+
this.estaSincronizado.set(true);
|
|
2687
|
+
}
|
|
2688
|
+
/**
|
|
2689
|
+
* Fuerza que la próxima petición HTTP pida la hora al servidor.
|
|
2690
|
+
* Útil tras reconexiones de socket o detecciones de warp.
|
|
2691
|
+
*/
|
|
2692
|
+
forzarSincronizacion() {
|
|
2693
|
+
this.estaSincronizado.set(false);
|
|
2694
|
+
}
|
|
2695
|
+
estaSincronizado = signal(false);
|
|
2696
|
+
get sincronizado() { return this.estaSincronizado(); }
|
|
2697
|
+
cargarOffsetInicial() {
|
|
2698
|
+
const guardado = localStorage.getItem(this.STORAGE_KEY);
|
|
2699
|
+
if (guardado) {
|
|
2700
|
+
this.offset.set(parseInt(guardado, 10));
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
escucharCambiosOtrasPestanas() {
|
|
2704
|
+
window.addEventListener('storage', (event) => {
|
|
2705
|
+
if (event.key === this.STORAGE_KEY && event.newValue) {
|
|
2706
|
+
this.offset.set(parseInt(event.newValue, 10));
|
|
2707
|
+
}
|
|
2708
|
+
});
|
|
2709
|
+
}
|
|
2710
|
+
/**
|
|
2711
|
+
* Monitoriza saltos bruscos en el tiempo (suspensión o cambio manual de hora).
|
|
2712
|
+
* Si detectamos un "warp", podríamos pedir una sincronización forzada.
|
|
2713
|
+
*/
|
|
2714
|
+
iniciarVigilanteWarp() {
|
|
2715
|
+
let lastPerformance = performance.now();
|
|
2716
|
+
let lastDate = Date.now();
|
|
2717
|
+
setInterval(() => {
|
|
2718
|
+
const currentPerformance = performance.now();
|
|
2719
|
+
const currentDate = Date.now();
|
|
2720
|
+
const perfDelta = currentPerformance - lastPerformance;
|
|
2721
|
+
const dateDelta = currentDate - lastDate;
|
|
2722
|
+
// Si la diferencia entre deltas es mayor a 2s (ajustable), hubo un warp
|
|
2723
|
+
if (Math.abs(perfDelta - dateDelta) > 2000) {
|
|
2724
|
+
console.warn('[RelojService] Salto temporal detectado (Warp). Se recomienda sincronizar.');
|
|
2725
|
+
this.forzarSincronizacion();
|
|
2726
|
+
}
|
|
2727
|
+
lastPerformance = currentPerformance;
|
|
2728
|
+
lastDate = currentDate;
|
|
2729
|
+
}, 5000);
|
|
2730
|
+
}
|
|
2731
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RelojService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2732
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RelojService, providedIn: 'root' });
|
|
2733
|
+
}
|
|
2734
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RelojService, decorators: [{
|
|
2735
|
+
type: Injectable,
|
|
2736
|
+
args: [{
|
|
2737
|
+
providedIn: 'root'
|
|
2738
|
+
}]
|
|
2739
|
+
}], ctorParameters: () => [] });
|
|
2740
|
+
|
|
2741
|
+
/*
|
|
2742
|
+
* Public API Surface of utils services
|
|
2743
|
+
*/
|
|
2744
|
+
|
|
1855
2745
|
/*
|
|
1856
2746
|
* Public API Surface of utils
|
|
1857
2747
|
*/
|
|
1858
|
-
// export * from './functions/common.function';
|
|
1859
|
-
// export * from './lib/utils.component';
|
|
1860
|
-
// export * from './lib/utils.service';
|
|
1861
2748
|
|
|
1862
2749
|
/**
|
|
1863
2750
|
* Generated bundle index. Do not edit.
|
|
1864
2751
|
*/
|
|
1865
2752
|
|
|
1866
|
-
export { DataEnListaPipe, DataModel, DateDiffStringPipe, FiltroPipe, FormControlIsRequiredPipe, JsonParsePipe, NoSanitizePipe, TipoValorFuncionPipe, ZeroFillPipe, b64Decode, b64Encode, buscarPorCampo, changeSelect, changeSelectApi, changeSelectData, changeSelectDataApi, changeSelectReformateado, convertirBytes, dataEnLista, dateDiffString, decodeBase64Object, decodeBase64String, decodeBase64ToBlob, deepClone, deepMerge, delLocalStorage, desencriptar, downLoadFileStream, eliminarColumnaPorIndex, eliminarDuplicados, eliminarElementos, encodeBase64File, encodeBase64Object, encodeBase64String, encriptar, esNumero, establecerQuitarRequired, extraerDominio, formControlIsRequired, formatearFecha, formatearFechaCadena, formatearFechaFormato, generateRandomString, getBrowserName, getCambiarPwd, getDataArchivoFromPath, getFormValidationErrors, getLocalStorage, getUniqueValues, getUniqueValuesByProperty, groupBy, inicializarVariablesSessionStorage, isEmail, jwtToken, jwtTokenData, jwtTokenExpiracion, jwtTokenExpiracionFaltante, localStorageKeys, markAsTouchedWithoutEmitEvent, maskEmail, mensajeAlerta, mensajeConfirmacion, mensajeTimer, mensajeToast, mensajesDeError, mensajesErrorFormControl, mostrarValorEnBusqueda, nestGroupsBy, numberToWords, objectPropertiesBoolean, objectPropertiesToType, obtenerHostDesdeUrl, obtenerMimeType, obtenerUltimoOrden, ordenarArray, ordenarPorPropiedad, ordenarPorPropiedades, roundToDecimal, sanitizarNombreArchivo, seleccionarTextoInput, setCambiarPwd, setControlDesdeLista, setJwtTokenData, setLocalStorage, sumarObjetos, sumarPropiedades, tipoValorFuncion, toFormData, transformarFechasPorNombreDeCampo, verificarRUC, zeroFill };
|
|
2753
|
+
export { AutoSelectFirstDirective, AutocompleteMatchValidatorDirective, DataEnListaPipe, DataModel, DateDiffStringPipe, FiltroPipe, FormControlIsRequiredPipe, JsonParsePipe, JvsAutocompleteDirective, JvsDisplayWithPipe, JvsPopoverDirective, JvsPopoverListenerDirective, JvsPopoverPanelComponent, JvsPopoverService, NoSanitizePipe, RelojService, TipoValorFuncionPipe, ZeroFillPipe, b64Decode, b64Encode, buscarPorCampo, changeSelect, changeSelectApi, changeSelectData, changeSelectDataApi, changeSelectReformateado, convertirBytes, dataEnLista, dateDiffString, decodeBase64Object, decodeBase64String, decodeBase64ToBlob, deepClone, deepMerge, delLocalStorage, desencriptar, devError, devGroup, devGroupEnd, devLog, devTable, devTime, devTimeEnd, devWarn, downLoadFileStream, eliminarColumnaPorIndex, eliminarDuplicados, eliminarElementos, encodeBase64File, encodeBase64Object, encodeBase64String, encriptar, esNumero, esPromise, establecerQuitarRequired, extraerDominio, filtrarDatosLocal, formControlIsRequired, formatearFecha, formatearFechaCadena, formatearFechaFormato, generateRandomString, getBrowserName, getCambiarPwd, getDataArchivoFromPath, getFormValidationErrors, getLocalStorage, getUniqueValues, getUniqueValuesByProperty, getValueByPath, groupBy, inicializarVariablesSessionStorage, isEmail, isProduction, jwtToken, jwtTokenData, jwtTokenExpiracion, jwtTokenExpiracionFaltante, localStorageKeys, markAsTouchedWithoutEmitEvent, maskEmail, mensajeAlerta, mensajeConfirmacion, mensajeTimer, mensajeToast, mensajesDeError, mensajesErrorFormControl, mostrarValorEnBusqueda, nestGroupsBy, numberToWords, objectPropertiesBoolean, objectPropertiesToType, obtenerHostDesdeUrl, obtenerMimeType, obtenerUltimoOrden, ordenarArray, ordenarPorPropiedad, ordenarPorPropiedades, roundToDecimal, sanitizarNombreArchivo, seleccionarTextoInput, setCambiarPwd, setControlDesdeLista, setJwtTokenData, setLocalStorage, setProductionMode, sumarObjetos, sumarPropiedades, tipoValorFuncion, toFormData, transformarFechasPorNombreDeCampo, verificarRUC, zeroFill };
|
|
1867
2754
|
//# sourceMappingURL=jvsoft-utils.mjs.map
|