ngx-dsxlibrary 2.21.69 → 2.21.71
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.
|
@@ -32,9 +32,6 @@ import { Button, ButtonModule } from 'primeng/button';
|
|
|
32
32
|
import moment from 'moment-timezone';
|
|
33
33
|
import { ToastrService } from 'ngx-toastr';
|
|
34
34
|
import Swal from 'sweetalert2';
|
|
35
|
-
import { AutoComplete, AutoCompleteModule } from 'primeng/autocomplete';
|
|
36
|
-
import * as i6 from 'primeng/floatlabel';
|
|
37
|
-
import { FloatLabel, FloatLabelModule } from 'primeng/floatlabel';
|
|
38
35
|
import { FileUpload, FileUploadModule } from 'primeng/fileupload';
|
|
39
36
|
import { LottieComponent } from 'ngx-lottie';
|
|
40
37
|
import { createTimeline } from 'animejs';
|
|
@@ -44,9 +41,12 @@ import * as i4 from 'primeng/menubar';
|
|
|
44
41
|
import { MenubarModule } from 'primeng/menubar';
|
|
45
42
|
import { JwtHelperService } from '@auth0/angular-jwt';
|
|
46
43
|
import { CookieService } from 'ngx-cookie-service';
|
|
44
|
+
import * as i6 from 'primeng/floatlabel';
|
|
45
|
+
import { FloatLabelModule, FloatLabel } from 'primeng/floatlabel';
|
|
47
46
|
import * as i7 from 'primeng/password';
|
|
48
47
|
import { PasswordModule } from 'primeng/password';
|
|
49
48
|
import { AccordionModule } from 'primeng/accordion';
|
|
49
|
+
import { AutoCompleteModule, AutoComplete } from 'primeng/autocomplete';
|
|
50
50
|
import { AutoFocusModule } from 'primeng/autofocus';
|
|
51
51
|
import { AvatarGroupModule } from 'primeng/avatargroup';
|
|
52
52
|
import { BadgeModule } from 'primeng/badge';
|
|
@@ -2184,6 +2184,181 @@ function provideEnvironment(environment) {
|
|
|
2184
2184
|
};
|
|
2185
2185
|
}
|
|
2186
2186
|
|
|
2187
|
+
/**
|
|
2188
|
+
* action-message.model.ts
|
|
2189
|
+
*
|
|
2190
|
+
* Centraliza los tipos de acción y la configuración de mensajes para acciones de botones y operaciones comunes en la UI.
|
|
2191
|
+
*
|
|
2192
|
+
* - Define los tipos de acción estándar usados en dsx-button y otros componentes.
|
|
2193
|
+
* - Permite mantener uniformidad y evitar errores por typos en los tipos de acción.
|
|
2194
|
+
* - Provee la función getActionMessageConfig para obtener los textos, títulos e íconos de confirmación según la acción y el estado.
|
|
2195
|
+
* - Si se usa una acción válida pero sin mensaje configurado, en modo desarrollo muestra un warning para facilitar el mantenimiento.
|
|
2196
|
+
*
|
|
2197
|
+
* Uso recomendado:
|
|
2198
|
+
* - Importa ACTION_TYPES y ActionType donde se requiera validar o tipar acciones de botones.
|
|
2199
|
+
* - Usa getActionMessageConfig para obtener la configuración de confirmación antes de ejecutar acciones destructivas o de restauración.
|
|
2200
|
+
*
|
|
2201
|
+
* Ejemplo:
|
|
2202
|
+
* import { ACTION_TYPES, ActionType, getActionMessageConfig } from '.../action-message.model';
|
|
2203
|
+
* const config = getActionMessageConfig('softDelete', true);
|
|
2204
|
+
* // config: { title, message, icon }
|
|
2205
|
+
*
|
|
2206
|
+
* Si agregas un nuevo tipo de acción, recuerda añadir su mensaje en getActionMessageConfig.
|
|
2207
|
+
*/
|
|
2208
|
+
/**
|
|
2209
|
+
* Tipos de acción disponibles para el componente `dsx-button`.
|
|
2210
|
+
*
|
|
2211
|
+
* Usa `ACTION_TYPES` en el consumidor para evitar typos.
|
|
2212
|
+
*
|
|
2213
|
+
* **Persistencia de datos (formulario)**
|
|
2214
|
+
* - `create` → Navega a la ruta de nuevo registro (azul)
|
|
2215
|
+
* - `saveOrUpdate` → Muestra "Guardar" si `id` es 0, "Actualizar" si `id` > 0 (amarillo)
|
|
2216
|
+
*
|
|
2217
|
+
* **Eliminar**
|
|
2218
|
+
* - `delete` → Eliminar registro permanentemente (rojo)
|
|
2219
|
+
* - `softDelete` → Borrar registro con borrado lógico (amarillo)
|
|
2220
|
+
*
|
|
2221
|
+
* **Formulario**
|
|
2222
|
+
* - `validate` → Validar formulario sin guardar (gris)
|
|
2223
|
+
* - `restore` → Restaurar datos originales (gris)
|
|
2224
|
+
*
|
|
2225
|
+
* **Navegación / Utilidades**
|
|
2226
|
+
* - `home` → Ir al inicio (gris)
|
|
2227
|
+
* - `refresh` → Recargar datos desde el servidor (morado)
|
|
2228
|
+
*
|
|
2229
|
+
* **Consulta / Descarga**
|
|
2230
|
+
* - `details` → Ver el detalle de un registro (azul índigo)
|
|
2231
|
+
* - `view` → Previsualizar o abrir detalle (azul cielo)
|
|
2232
|
+
* - `export` → Exportar información a Excel (verde Excel)
|
|
2233
|
+
* - `download` → Descargar archivo o recurso (ámbar cálido)
|
|
2234
|
+
* - `import` → Importar datos desde archivo (azul acero)
|
|
2235
|
+
*/
|
|
2236
|
+
const ACTION_TYPES = {
|
|
2237
|
+
hardDelete: 'hardDelete',
|
|
2238
|
+
softDelete: 'softDelete',
|
|
2239
|
+
return: 'return',
|
|
2240
|
+
home: 'home',
|
|
2241
|
+
validate: 'validate',
|
|
2242
|
+
restore: 'restore',
|
|
2243
|
+
edit: 'edit',
|
|
2244
|
+
create: 'create',
|
|
2245
|
+
save: 'save',
|
|
2246
|
+
update: 'update',
|
|
2247
|
+
refresh: 'refresh',
|
|
2248
|
+
details: 'details',
|
|
2249
|
+
view: 'view',
|
|
2250
|
+
export: 'export',
|
|
2251
|
+
download: 'download',
|
|
2252
|
+
import: 'import',
|
|
2253
|
+
};
|
|
2254
|
+
function getActionMessageConfig(action, secondArg, thirdArg) {
|
|
2255
|
+
const isActive = action === 'softDelete' || action === 'hardDelete'
|
|
2256
|
+
? typeof secondArg === 'boolean'
|
|
2257
|
+
? secondArg
|
|
2258
|
+
: true
|
|
2259
|
+
: true;
|
|
2260
|
+
const dataPreview = action === 'softDelete' || action === 'hardDelete'
|
|
2261
|
+
? thirdArg
|
|
2262
|
+
: typeof secondArg === 'string'
|
|
2263
|
+
? secondArg
|
|
2264
|
+
: undefined;
|
|
2265
|
+
// Valores por defecto para todas las propiedades
|
|
2266
|
+
const defaults = {
|
|
2267
|
+
title: '',
|
|
2268
|
+
message: '',
|
|
2269
|
+
icon: undefined,
|
|
2270
|
+
confirmButtonText: undefined,
|
|
2271
|
+
cancelButtonText: undefined,
|
|
2272
|
+
showConfirmButton: undefined,
|
|
2273
|
+
showCancelButton: undefined,
|
|
2274
|
+
};
|
|
2275
|
+
if (action === 'softDelete') {
|
|
2276
|
+
if (isActive) {
|
|
2277
|
+
return {
|
|
2278
|
+
...defaults,
|
|
2279
|
+
title: '¿Borrar registro?',
|
|
2280
|
+
message: 'El registro dejará de estar disponible en las listas principales.' +
|
|
2281
|
+
(dataPreview ? `<br>${dataPreview}` : ''),
|
|
2282
|
+
icono: 'icon/trash-bin.png',
|
|
2283
|
+
confirmButtonText: 'Eliminar',
|
|
2284
|
+
cancelButtonText: 'Cancelar',
|
|
2285
|
+
showConfirmButton: true,
|
|
2286
|
+
showCancelButton: true,
|
|
2287
|
+
};
|
|
2288
|
+
}
|
|
2289
|
+
else {
|
|
2290
|
+
return {
|
|
2291
|
+
...defaults,
|
|
2292
|
+
title: '¿Restaurar registro?',
|
|
2293
|
+
message: 'El registro volverá a estar <strong>activo</strong> y visible en todas las listas principales del sistema.' +
|
|
2294
|
+
(dataPreview ? `<br>${dataPreview}` : ''),
|
|
2295
|
+
icono: 'icon/documentation.png',
|
|
2296
|
+
confirmButtonText: 'Sí, restaurar',
|
|
2297
|
+
cancelButtonText: 'Dejar archivado',
|
|
2298
|
+
showConfirmButton: true,
|
|
2299
|
+
showCancelButton: true,
|
|
2300
|
+
};
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
if (action === 'hardDelete') {
|
|
2304
|
+
return {
|
|
2305
|
+
...defaults,
|
|
2306
|
+
title: '¿Eliminar permanentemente?',
|
|
2307
|
+
message: 'Esta acción <strong>no se puede deshacer</strong>. Se perderán todos los datos asociados a este registro de forma inmediata.' +
|
|
2308
|
+
(dataPreview ? `<br>${dataPreview}` : ''),
|
|
2309
|
+
icono: 'icon/delete.png',
|
|
2310
|
+
confirmButtonText: 'Eliminar permanentemente',
|
|
2311
|
+
cancelButtonText: 'Cancelar',
|
|
2312
|
+
showConfirmButton: true,
|
|
2313
|
+
showCancelButton: true,
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2316
|
+
if (action === 'save') {
|
|
2317
|
+
return {
|
|
2318
|
+
...defaults,
|
|
2319
|
+
title: '¿Guardar registro?',
|
|
2320
|
+
message: 'El nuevo registro se guardará en el sistema.' +
|
|
2321
|
+
(dataPreview ? `<br>${dataPreview}` : ''),
|
|
2322
|
+
icono: 'icon2/save_2029637.png',
|
|
2323
|
+
confirmButtonText: 'Guardar',
|
|
2324
|
+
cancelButtonText: 'Cancelar',
|
|
2325
|
+
showConfirmButton: true,
|
|
2326
|
+
showCancelButton: true,
|
|
2327
|
+
};
|
|
2328
|
+
}
|
|
2329
|
+
if (action === 'update') {
|
|
2330
|
+
return {
|
|
2331
|
+
...defaults,
|
|
2332
|
+
title: '¿Actualizar registro?',
|
|
2333
|
+
message: 'Los cambios realizados se actualizarán en el sistema.' +
|
|
2334
|
+
(dataPreview ? `<br>${dataPreview}` : ''),
|
|
2335
|
+
icono: 'icon2/save_2029637.png',
|
|
2336
|
+
confirmButtonText: 'Actualizar',
|
|
2337
|
+
cancelButtonText: 'Cancelar',
|
|
2338
|
+
showConfirmButton: true,
|
|
2339
|
+
showCancelButton: true,
|
|
2340
|
+
};
|
|
2341
|
+
}
|
|
2342
|
+
if (action === 'restore') {
|
|
2343
|
+
return {
|
|
2344
|
+
...defaults,
|
|
2345
|
+
title: '¿Revertir cambios?',
|
|
2346
|
+
message: 'Se perderán todos los cambios que hayas realizado en el formulario y se volverán a cargar los datos originales.',
|
|
2347
|
+
icono: 'icon/data-recovery.png',
|
|
2348
|
+
confirmButtonText: 'Restaurar',
|
|
2349
|
+
cancelButtonText: 'Cancelar',
|
|
2350
|
+
showConfirmButton: true,
|
|
2351
|
+
showCancelButton: true,
|
|
2352
|
+
};
|
|
2353
|
+
}
|
|
2354
|
+
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
2355
|
+
console.warn(`[getActionMessageConfig] Acción "${action}" existe pero no tiene mensaje configurado. ` +
|
|
2356
|
+
'Agrega la configuración correspondiente para evitar este warning.');
|
|
2357
|
+
}
|
|
2358
|
+
// Retorna los valores por defecto si la acción no es válida
|
|
2359
|
+
return { ...defaults };
|
|
2360
|
+
}
|
|
2361
|
+
|
|
2187
2362
|
const INITIAL_PARAMETERS = new InjectionToken('InitialParameters');
|
|
2188
2363
|
|
|
2189
2364
|
/**
|
|
@@ -4103,222 +4278,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
4103
4278
|
}] });
|
|
4104
4279
|
|
|
4105
4280
|
/**
|
|
4106
|
-
*
|
|
4107
|
-
*
|
|
4108
|
-
* Centraliza los tipos de acción y la configuración de mensajes para acciones de botones y operaciones comunes en la UI.
|
|
4109
|
-
*
|
|
4110
|
-
* - Define los tipos de acción estándar usados en dsx-button y otros componentes.
|
|
4111
|
-
* - Permite mantener uniformidad y evitar errores por typos en los tipos de acción.
|
|
4112
|
-
* - Provee la función getActionMessageConfig para obtener los textos, títulos e íconos de confirmación según la acción y el estado.
|
|
4113
|
-
* - Si se usa una acción válida pero sin mensaje configurado, en modo desarrollo muestra un warning para facilitar el mantenimiento.
|
|
4114
|
-
*
|
|
4115
|
-
* Uso recomendado:
|
|
4116
|
-
* - Importa ACTION_TYPES y ActionType donde se requiera validar o tipar acciones de botones.
|
|
4117
|
-
* - Usa getActionMessageConfig para obtener la configuración de confirmación antes de ejecutar acciones destructivas o de restauración.
|
|
4118
|
-
*
|
|
4119
|
-
* Ejemplo:
|
|
4120
|
-
* import { ACTION_TYPES, ActionType, getActionMessageConfig } from '.../action-message.model';
|
|
4121
|
-
* const config = getActionMessageConfig('softDelete', true);
|
|
4122
|
-
* // config: { title, message, icon }
|
|
4123
|
-
*
|
|
4124
|
-
* Si agregas un nuevo tipo de acción, recuerda añadir su mensaje en getActionMessageConfig.
|
|
4125
|
-
*/
|
|
4126
|
-
/**
|
|
4127
|
-
* Tipos de acción disponibles para el componente `dsx-button`.
|
|
4128
|
-
*
|
|
4129
|
-
* Usa `ACTION_TYPES` en el consumidor para evitar typos.
|
|
4130
|
-
*
|
|
4131
|
-
* **Persistencia de datos (formulario)**
|
|
4132
|
-
* - `create` → Navega a la ruta de nuevo registro (azul)
|
|
4133
|
-
* - `saveOrUpdate` → Muestra "Guardar" si `id` es 0, "Actualizar" si `id` > 0 (amarillo)
|
|
4134
|
-
*
|
|
4135
|
-
* **Eliminar**
|
|
4136
|
-
* - `delete` → Eliminar registro permanentemente (rojo)
|
|
4137
|
-
* - `softDelete` → Borrar registro con borrado lógico (amarillo)
|
|
4138
|
-
*
|
|
4139
|
-
* **Formulario**
|
|
4140
|
-
* - `validate` → Validar formulario sin guardar (gris)
|
|
4141
|
-
* - `restore` → Restaurar datos originales (gris)
|
|
4281
|
+
* Paleta corporativa de colores para `dsx-button`.
|
|
4142
4282
|
*
|
|
4143
|
-
*
|
|
4144
|
-
*
|
|
4145
|
-
* - `refresh` → Recargar datos desde el servidor (morado)
|
|
4283
|
+
* Cada token tiene un significado semántico fijo. Úsala como referencia
|
|
4284
|
+
* para asignar `colorToken` al añadir nuevos tipos de botón.
|
|
4146
4285
|
*
|
|
4147
|
-
*
|
|
4148
|
-
*
|
|
4149
|
-
*
|
|
4150
|
-
*
|
|
4151
|
-
*
|
|
4152
|
-
*
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
create: 'create',
|
|
4163
|
-
save: 'save',
|
|
4164
|
-
update: 'update',
|
|
4165
|
-
refresh: 'refresh',
|
|
4166
|
-
details: 'details',
|
|
4167
|
-
view: 'view',
|
|
4168
|
-
export: 'export',
|
|
4169
|
-
download: 'download',
|
|
4170
|
-
import: 'import',
|
|
4171
|
-
};
|
|
4172
|
-
function getActionMessageConfig(action, secondArg, thirdArg) {
|
|
4173
|
-
const isActive = action === 'softDelete' || action === 'hardDelete'
|
|
4174
|
-
? typeof secondArg === 'boolean'
|
|
4175
|
-
? secondArg
|
|
4176
|
-
: true
|
|
4177
|
-
: true;
|
|
4178
|
-
const dataPreview = action === 'softDelete' || action === 'hardDelete'
|
|
4179
|
-
? thirdArg
|
|
4180
|
-
: typeof secondArg === 'string'
|
|
4181
|
-
? secondArg
|
|
4182
|
-
: undefined;
|
|
4183
|
-
// Valores por defecto para todas las propiedades
|
|
4184
|
-
const defaults = {
|
|
4185
|
-
title: '',
|
|
4186
|
-
message: '',
|
|
4187
|
-
icon: undefined,
|
|
4188
|
-
confirmButtonText: undefined,
|
|
4189
|
-
cancelButtonText: undefined,
|
|
4190
|
-
showConfirmButton: undefined,
|
|
4191
|
-
showCancelButton: undefined,
|
|
4192
|
-
};
|
|
4193
|
-
if (action === 'softDelete') {
|
|
4194
|
-
if (isActive) {
|
|
4195
|
-
return {
|
|
4196
|
-
...defaults,
|
|
4197
|
-
title: '¿Borrar registro?',
|
|
4198
|
-
message: 'El registro dejará de estar disponible en las listas principales.' +
|
|
4199
|
-
(dataPreview ? `<br>${dataPreview}` : ''),
|
|
4200
|
-
icono: 'icon/trash-bin.png',
|
|
4201
|
-
confirmButtonText: 'Eliminar',
|
|
4202
|
-
cancelButtonText: 'Cancelar',
|
|
4203
|
-
showConfirmButton: true,
|
|
4204
|
-
showCancelButton: true,
|
|
4205
|
-
};
|
|
4206
|
-
}
|
|
4207
|
-
else {
|
|
4208
|
-
return {
|
|
4209
|
-
...defaults,
|
|
4210
|
-
title: '¿Restaurar registro?',
|
|
4211
|
-
message: 'El registro volverá a estar <strong>activo</strong> y visible en todas las listas principales del sistema.' +
|
|
4212
|
-
(dataPreview ? `<br>${dataPreview}` : ''),
|
|
4213
|
-
icono: 'icon/documentation.png',
|
|
4214
|
-
confirmButtonText: 'Sí, restaurar',
|
|
4215
|
-
cancelButtonText: 'Dejar archivado',
|
|
4216
|
-
showConfirmButton: true,
|
|
4217
|
-
showCancelButton: true,
|
|
4218
|
-
};
|
|
4219
|
-
}
|
|
4220
|
-
}
|
|
4221
|
-
if (action === 'hardDelete') {
|
|
4222
|
-
return {
|
|
4223
|
-
...defaults,
|
|
4224
|
-
title: '¿Eliminar permanentemente?',
|
|
4225
|
-
message: 'Esta acción <strong>no se puede deshacer</strong>. Se perderán todos los datos asociados a este registro de forma inmediata.' +
|
|
4226
|
-
(dataPreview ? `<br>${dataPreview}` : ''),
|
|
4227
|
-
icono: 'icon/delete.png',
|
|
4228
|
-
confirmButtonText: 'Eliminar permanentemente',
|
|
4229
|
-
cancelButtonText: 'Cancelar',
|
|
4230
|
-
showConfirmButton: true,
|
|
4231
|
-
showCancelButton: true,
|
|
4232
|
-
};
|
|
4233
|
-
}
|
|
4234
|
-
if (action === 'save') {
|
|
4235
|
-
return {
|
|
4236
|
-
...defaults,
|
|
4237
|
-
title: '¿Guardar registro?',
|
|
4238
|
-
message: 'El nuevo registro se guardará en el sistema.' +
|
|
4239
|
-
(dataPreview ? `<br>${dataPreview}` : ''),
|
|
4240
|
-
icono: 'icon2/save_2029637.png',
|
|
4241
|
-
confirmButtonText: 'Guardar',
|
|
4242
|
-
cancelButtonText: 'Cancelar',
|
|
4243
|
-
showConfirmButton: true,
|
|
4244
|
-
showCancelButton: true,
|
|
4245
|
-
};
|
|
4246
|
-
}
|
|
4247
|
-
if (action === 'update') {
|
|
4248
|
-
return {
|
|
4249
|
-
...defaults,
|
|
4250
|
-
title: '¿Actualizar registro?',
|
|
4251
|
-
message: 'Los cambios realizados se actualizarán en el sistema.' +
|
|
4252
|
-
(dataPreview ? `<br>${dataPreview}` : ''),
|
|
4253
|
-
icono: 'icon2/save_2029637.png',
|
|
4254
|
-
confirmButtonText: 'Actualizar',
|
|
4255
|
-
cancelButtonText: 'Cancelar',
|
|
4256
|
-
showConfirmButton: true,
|
|
4257
|
-
showCancelButton: true,
|
|
4258
|
-
};
|
|
4259
|
-
}
|
|
4260
|
-
if (action === 'restore') {
|
|
4261
|
-
return {
|
|
4262
|
-
...defaults,
|
|
4263
|
-
title: '¿Revertir cambios?',
|
|
4264
|
-
message: 'Se perderán todos los cambios que hayas realizado en el formulario y se volverán a cargar los datos originales.',
|
|
4265
|
-
icono: 'icon/data-recovery.png',
|
|
4266
|
-
confirmButtonText: 'Restaurar',
|
|
4267
|
-
cancelButtonText: 'Cancelar',
|
|
4268
|
-
showConfirmButton: true,
|
|
4269
|
-
showCancelButton: true,
|
|
4270
|
-
};
|
|
4271
|
-
}
|
|
4272
|
-
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
4273
|
-
console.warn(`[getActionMessageConfig] Acción "${action}" existe pero no tiene mensaje configurado. ` +
|
|
4274
|
-
'Agrega la configuración correspondiente para evitar este warning.');
|
|
4275
|
-
}
|
|
4276
|
-
// Retorna los valores por defecto si la acción no es válida
|
|
4277
|
-
return { ...defaults };
|
|
4278
|
-
}
|
|
4279
|
-
|
|
4280
|
-
/**
|
|
4281
|
-
* Paleta corporativa de colores para `dsx-button`.
|
|
4282
|
-
*
|
|
4283
|
-
* Cada token tiene un significado semántico fijo. Úsala como referencia
|
|
4284
|
-
* para asignar `colorToken` al añadir nuevos tipos de botón.
|
|
4285
|
-
*
|
|
4286
|
-
* | Token | Color | Uso semántico |
|
|
4287
|
-
* |-----------|----------------|---------------------------------------------------|
|
|
4288
|
-
* | danger | Coral rojo | Acción destructiva e irreversible (eliminar) |
|
|
4289
|
-
* | warning | Naranja cálido | Acción con riesgo moderado / borrado lógico |
|
|
4290
|
-
* | caution | Ámbar dorado | Requiere verificación del usuario (actualizar) |
|
|
4291
|
-
* | success | Verde menta | Guardar nuevo registro / agregar |
|
|
4292
|
-
* | primary | Azul claro | Editar / navegar con contexto de registro |
|
|
4293
|
-
* | info | Cian suave | Recargar datos / refrescar vista |
|
|
4294
|
-
* | neutral | Gris azulado | Acción secundaria / navegación sin contexto |
|
|
4295
|
-
* | restore | Violeta suave | Deshacer / restaurar estado anterior |
|
|
4296
|
-
* | view | Teal profundo | Ver / previsualizar detalle |
|
|
4297
|
-
* | excel | Verde Excel | Exportar información a hoja de cálculo |
|
|
4298
|
-
* | download | Naranja quemado| Descargar archivo o recurso |
|
|
4299
|
-
* | import | Azul acero | Importar información desde archivo |
|
|
4300
|
-
* | details | Azul índigo | Abrir detalle de registro |
|
|
4286
|
+
* | Token | Color | Uso semántico |
|
|
4287
|
+
* |-----------|----------------|---------------------------------------------------|
|
|
4288
|
+
* | danger | Coral rojo | Acción destructiva e irreversible (eliminar) |
|
|
4289
|
+
* | warning | Naranja cálido | Acción con riesgo moderado / borrado lógico |
|
|
4290
|
+
* | caution | Ámbar dorado | Requiere verificación del usuario (actualizar) |
|
|
4291
|
+
* | success | Verde menta | Guardar nuevo registro / agregar |
|
|
4292
|
+
* | primary | Azul claro | Editar / navegar con contexto de registro |
|
|
4293
|
+
* | info | Cian suave | Recargar datos / refrescar vista |
|
|
4294
|
+
* | neutral | Gris azulado | Acción secundaria / navegación sin contexto |
|
|
4295
|
+
* | restore | Violeta suave | Deshacer / restaurar estado anterior |
|
|
4296
|
+
* | view | Teal profundo | Ver / previsualizar detalle |
|
|
4297
|
+
* | excel | Verde Excel | Exportar información a hoja de cálculo |
|
|
4298
|
+
* | download | Naranja quemado| Descargar archivo o recurso |
|
|
4299
|
+
* | import | Azul acero | Importar información desde archivo |
|
|
4300
|
+
* | details | Azul índigo | Abrir detalle de registro |
|
|
4301
4301
|
*/
|
|
4302
4302
|
const DSX_PALETTE = {
|
|
4303
4303
|
danger: '#EF5350',
|
|
4304
4304
|
warning: '#FF7043',
|
|
4305
4305
|
caution: '#FFB300',
|
|
4306
|
-
success: '#0ba055',
|
|
4307
|
-
primary: '#0066cc',
|
|
4306
|
+
success: '#0ba055',
|
|
4307
|
+
primary: '#0066cc',
|
|
4308
4308
|
info: '#26C6DA',
|
|
4309
4309
|
neutral: '#90A4AE',
|
|
4310
|
-
restore: '#B0BEC5',
|
|
4311
|
-
return: '#11438d',
|
|
4310
|
+
restore: '#B0BEC5',
|
|
4311
|
+
return: '#11438d',
|
|
4312
4312
|
view: '#00838F',
|
|
4313
4313
|
excel: '#217346',
|
|
4314
4314
|
download: '#E65100',
|
|
4315
4315
|
import: '#546E7A',
|
|
4316
4316
|
details: '#3949AB',
|
|
4317
|
-
magenta: '#D81B60',
|
|
4318
|
-
cyan: '#00BCD4',
|
|
4319
|
-
olive: '#808000',
|
|
4320
|
-
brown: '#8D6E63',
|
|
4321
|
-
slate: '#607D8B',
|
|
4317
|
+
magenta: '#D81B60',
|
|
4318
|
+
cyan: '#00BCD4',
|
|
4319
|
+
olive: '#808000',
|
|
4320
|
+
brown: '#8D6E63',
|
|
4321
|
+
slate: '#607D8B',
|
|
4322
4322
|
};
|
|
4323
4323
|
/** Tipos que necesitan un `[id]` mayor a 0 para poder mostrarse. */
|
|
4324
4324
|
const TYPES_REQUIRING_ID = [
|
|
@@ -4331,23 +4331,56 @@ class DsxButtonComponent {
|
|
|
4331
4331
|
renderCount = 0;
|
|
4332
4332
|
_paramService = inject((ParameterValuesService));
|
|
4333
4333
|
_router = inject(Router);
|
|
4334
|
-
|
|
4334
|
+
_isDev = isDevMode();
|
|
4335
|
+
lastValidationState = null;
|
|
4335
4336
|
size = input(undefined, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
4336
4337
|
_environment = inject(ENVIRONMENT, {
|
|
4337
4338
|
optional: true,
|
|
4338
4339
|
});
|
|
4339
4340
|
constructor() {
|
|
4340
|
-
|
|
4341
|
+
// Solo activar efectos de debug en desarrollo
|
|
4342
|
+
if (this._isDev) {
|
|
4343
|
+
// Efecto principal que captura todo el estado
|
|
4341
4344
|
effect(() => {
|
|
4342
4345
|
if (!this.debug())
|
|
4343
4346
|
return;
|
|
4344
4347
|
this.renderCount++;
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4348
|
+
this.logFullState();
|
|
4349
|
+
});
|
|
4350
|
+
// Efecto específico para validaciones
|
|
4351
|
+
effect(() => {
|
|
4352
|
+
if (!this.debug())
|
|
4353
|
+
return;
|
|
4354
|
+
const visible = this.visible();
|
|
4355
|
+
const validations = {
|
|
4356
|
+
global: this.passesGlobalVisibilityPolicy(),
|
|
4357
|
+
parameter: this.passesParameterValidation(),
|
|
4358
|
+
id: this.passesIdValidation(),
|
|
4359
|
+
visible,
|
|
4360
|
+
};
|
|
4361
|
+
const stateKey = JSON.stringify(validations);
|
|
4362
|
+
if (stateKey !== this.lastValidationState) {
|
|
4363
|
+
this.lastValidationState = stateKey;
|
|
4364
|
+
this.logValidationIssues(validations);
|
|
4365
|
+
}
|
|
4366
|
+
});
|
|
4367
|
+
// Efecto para detectar problemas con IDs
|
|
4368
|
+
effect(() => {
|
|
4369
|
+
if (!this.debug())
|
|
4370
|
+
return;
|
|
4371
|
+
const type = this.type();
|
|
4372
|
+
if (TYPES_REQUIRING_ID.includes(type)) {
|
|
4373
|
+
const id = this.getNormalizedId();
|
|
4374
|
+
const routeId = this.getIdFromNavigationTarget(this.effectiveRouterLink());
|
|
4375
|
+
if (!id && !routeId) {
|
|
4376
|
+
console.warn(`%c⚠️ [dsx-button:${type}] ID no disponible para acción que lo requiere`, 'color:#ed6c02;font-weight:bold', {
|
|
4377
|
+
type,
|
|
4378
|
+
explicitId: this.id(),
|
|
4379
|
+
routeId,
|
|
4380
|
+
requireIdInput: this.requireIdInput(),
|
|
4381
|
+
});
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4351
4384
|
});
|
|
4352
4385
|
}
|
|
4353
4386
|
}
|
|
@@ -4357,17 +4390,7 @@ class DsxButtonComponent {
|
|
|
4357
4390
|
type = input(ACTION_TYPES.hardDelete, ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
|
|
4358
4391
|
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
4359
4392
|
routerLink = input(undefined, ...(ngDevMode ? [{ debugName: "routerLink" }] : /* istanbul ignore next */ []));
|
|
4360
|
-
/**
|
|
4361
|
-
* Ruta de navegación simplificada. La `/` inicial se agrega automáticamente.
|
|
4362
|
-
* Cada segmento solo admite: letras, números, `-`, `_`, `.` y `:` (params de ruta).
|
|
4363
|
-
* Ejemplos válidos: `'home'`, `'container/nuevo'`, `'item/123'`
|
|
4364
|
-
* Ejemplos inválidos: `'item/*'`, `'item?foo=bar'`, `'item/../other'`
|
|
4365
|
-
* Para rutas dinámicas complejas usa `[routerLink]` directamente.
|
|
4366
|
-
*/
|
|
4367
4393
|
routerPath = input(undefined, ...(ngDevMode ? [{ debugName: "routerPath" }] : /* istanbul ignore next */ []));
|
|
4368
|
-
/** Ancho del botón. Usa `rem` para que escale con la preferencia de fuente del usuario.
|
|
4369
|
-
* Ejemplo: `'8rem'`, `'12rem'`. Valor por defecto: `'9rem'`.
|
|
4370
|
-
*/
|
|
4371
4394
|
width = input('9rem', ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
4372
4395
|
iconOnly = input(false, ...(ngDevMode ? [{ debugName: "iconOnly" }] : /* istanbul ignore next */ []));
|
|
4373
4396
|
iconOnlyWidth = input('2.5rem', ...(ngDevMode ? [{ debugName: "iconOnlyWidth" }] : /* istanbul ignore next */ []));
|
|
@@ -4383,24 +4406,12 @@ class DsxButtonComponent {
|
|
|
4383
4406
|
tooltipOverride = input(undefined, ...(ngDevMode ? [{ debugName: "tooltipOverride" }] : /* istanbul ignore next */ []));
|
|
4384
4407
|
iconOverride = input(undefined, ...(ngDevMode ? [{ debugName: "iconOverride" }] : /* istanbul ignore next */ []));
|
|
4385
4408
|
primeIconOverride = input(undefined, ...(ngDevMode ? [{ debugName: "primeIconOverride" }] : /* istanbul ignore next */ []));
|
|
4386
|
-
/** Permite personalizar el color usando únicamente tokens de la paleta DSX. */
|
|
4387
4409
|
colorOverride = input(undefined, ...(ngDevMode ? [{ debugName: "colorOverride" }] : /* istanbul ignore next */ []));
|
|
4388
|
-
/** Permite forzar estilo outlined o sólido por instancia. */
|
|
4389
4410
|
outlinedOverride = input(undefined, ...(ngDevMode ? [{ debugName: "outlinedOverride" }] : /* istanbul ignore next */ []));
|
|
4390
|
-
/**
|
|
4391
|
-
* Override por instancia para el botón `validate`.
|
|
4392
|
-
* Tiene prioridad sobre `environment.showValidateButton`.
|
|
4393
|
-
*/
|
|
4394
4411
|
showValidateButtonOverride = input(undefined, ...(ngDevMode ? [{ debugName: "showValidateButtonOverride" }] : /* istanbul ignore next */ []));
|
|
4395
|
-
/**
|
|
4396
|
-
* Override por instancia para el botón `restore`.
|
|
4397
|
-
* Tiene prioridad sobre `environment.showRestoreButton`.
|
|
4398
|
-
*/
|
|
4399
4412
|
showRestoreButtonOverride = input(undefined, ...(ngDevMode ? [{ debugName: "showRestoreButtonOverride" }] : /* istanbul ignore next */ []));
|
|
4400
4413
|
action = output();
|
|
4401
|
-
/** Valida y normaliza `routerPath`: agrega `/` inicial y rechaza caracteres inválidos. */
|
|
4402
4414
|
resolvedRouterLink = computed(() => {
|
|
4403
|
-
this.log('computed resolvedRouterLink');
|
|
4404
4415
|
const raw = this.routerPath();
|
|
4405
4416
|
if (!raw)
|
|
4406
4417
|
return undefined;
|
|
@@ -4409,23 +4420,22 @@ class DsxButtonComponent {
|
|
|
4409
4420
|
const rawSegments = normalizedRaw.split('/');
|
|
4410
4421
|
const hasEmptySegments = normalizedRaw.length > 0 && rawSegments.some((s) => s.length === 0);
|
|
4411
4422
|
if (hasEmptySegments) {
|
|
4412
|
-
|
|
4413
|
-
`
|
|
4423
|
+
if (this._isDev && this.debug()) {
|
|
4424
|
+
console.warn(`[dsx-button] routerPath contiene segmentos vacíos: "${raw}"`);
|
|
4425
|
+
}
|
|
4414
4426
|
return undefined;
|
|
4415
4427
|
}
|
|
4416
4428
|
const segments = rawSegments.filter(Boolean);
|
|
4417
4429
|
const invalid = segments.filter((s) => !VALID_SEGMENT.test(s));
|
|
4418
4430
|
if (invalid.length > 0) {
|
|
4419
|
-
|
|
4420
|
-
`
|
|
4421
|
-
|
|
4431
|
+
if (this._isDev && this.debug()) {
|
|
4432
|
+
console.warn(`[dsx-button] routerPath contiene segmentos inválidos: "${invalid.join('", "')}"`);
|
|
4433
|
+
}
|
|
4422
4434
|
return undefined;
|
|
4423
4435
|
}
|
|
4424
4436
|
return `/${segments.join('/')}`;
|
|
4425
4437
|
}, ...(ngDevMode ? [{ debugName: "resolvedRouterLink" }] : /* istanbul ignore next */ []));
|
|
4426
|
-
/** Prioriza routerPath (validado) sobre routerLink (libre). */
|
|
4427
4438
|
effectiveRouterLink = computed(() => {
|
|
4428
|
-
this.log('computed effectiveRouterLink');
|
|
4429
4439
|
const resolvedPath = this.resolvedRouterLink();
|
|
4430
4440
|
if (resolvedPath) {
|
|
4431
4441
|
return resolvedPath;
|
|
@@ -4438,7 +4448,6 @@ class DsxButtonComponent {
|
|
|
4438
4448
|
if (!trimmed) {
|
|
4439
4449
|
return link;
|
|
4440
4450
|
}
|
|
4441
|
-
// URLs externas no se normalizan ni validan como rutas internas.
|
|
4442
4451
|
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(trimmed)) {
|
|
4443
4452
|
return link;
|
|
4444
4453
|
}
|
|
@@ -4448,20 +4457,20 @@ class DsxButtonComponent {
|
|
|
4448
4457
|
const hasEmptySegments = pathForValidation.length > 0 &&
|
|
4449
4458
|
rawSegments.some((segment) => segment.length === 0);
|
|
4450
4459
|
if (hasEmptySegments) {
|
|
4451
|
-
|
|
4452
|
-
`
|
|
4460
|
+
if (this._isDev && this.debug()) {
|
|
4461
|
+
console.warn(`[dsx-button] routerLink contiene segmentos vacíos: "${link}"`);
|
|
4462
|
+
}
|
|
4453
4463
|
return link;
|
|
4454
4464
|
}
|
|
4455
4465
|
const invalid = rawSegments
|
|
4456
4466
|
.filter(Boolean)
|
|
4457
4467
|
.filter((segment) => !VALID_SEGMENT.test(segment));
|
|
4458
4468
|
if (invalid.length > 0) {
|
|
4459
|
-
|
|
4460
|
-
`
|
|
4461
|
-
|
|
4469
|
+
if (this._isDev && this.debug()) {
|
|
4470
|
+
console.warn(`[dsx-button] routerLink contiene segmentos inválidos: "${invalid.join('", "')}"`);
|
|
4471
|
+
}
|
|
4462
4472
|
return link;
|
|
4463
4473
|
}
|
|
4464
|
-
// Si llega una ruta simple sin prefijo, se normaliza a absoluta para evitar navegación relativa inesperada.
|
|
4465
4474
|
if (link.startsWith('/') ||
|
|
4466
4475
|
link.startsWith('./') ||
|
|
4467
4476
|
link.startsWith('../')) {
|
|
@@ -4472,23 +4481,6 @@ class DsxButtonComponent {
|
|
|
4472
4481
|
}
|
|
4473
4482
|
return `/${trimmed.split('/').filter(Boolean).join('/')}`;
|
|
4474
4483
|
}, ...(ngDevMode ? [{ debugName: "effectiveRouterLink" }] : /* istanbul ignore next */ []));
|
|
4475
|
-
// get buttonStyle(): Record<string, string> {
|
|
4476
|
-
// this.log('getter buttonStyle');
|
|
4477
|
-
// const color = DSX_PALETTE[this.config.colorToken];
|
|
4478
|
-
// const width = this.iconOnly() ? this.iconOnlyWidth() : this.width();
|
|
4479
|
-
// if (this.isCompactIconButton) {
|
|
4480
|
-
// return {
|
|
4481
|
-
// width,
|
|
4482
|
-
// background: 'transparent',
|
|
4483
|
-
// borderColor: 'transparent',
|
|
4484
|
-
// color,
|
|
4485
|
-
// };
|
|
4486
|
-
// }
|
|
4487
|
-
// if (this.config.outlined) {
|
|
4488
|
-
// return { width, background: 'transparent', borderColor: color, color };
|
|
4489
|
-
// }
|
|
4490
|
-
// return { width, background: color, borderColor: color, color: '#ffffff' };
|
|
4491
|
-
// }
|
|
4492
4484
|
buttonStyleComputed = computed(() => {
|
|
4493
4485
|
const color = DSX_PALETTE[this.config.colorToken];
|
|
4494
4486
|
const width = this.iconOnly() ? this.iconOnlyWidth() : this.width();
|
|
@@ -4518,17 +4510,13 @@ class DsxButtonComponent {
|
|
|
4518
4510
|
get buttonLabel() {
|
|
4519
4511
|
return this.iconOnly() ? undefined : this.label;
|
|
4520
4512
|
}
|
|
4521
|
-
// Y modifica el getter buttonSize
|
|
4522
4513
|
get buttonSize() {
|
|
4523
|
-
// Si el usuario especificó un tamaño, úsalo
|
|
4524
4514
|
if (this.size()) {
|
|
4525
4515
|
return this.size();
|
|
4526
4516
|
}
|
|
4527
|
-
// Si es compacto, siempre small
|
|
4528
4517
|
if (this.isCompactIconButton) {
|
|
4529
4518
|
return 'small';
|
|
4530
4519
|
}
|
|
4531
|
-
// Por defecto, small para todos los botones
|
|
4532
4520
|
return 'small';
|
|
4533
4521
|
}
|
|
4534
4522
|
get buttonStyleClass() {
|
|
@@ -4541,7 +4529,6 @@ class DsxButtonComponent {
|
|
|
4541
4529
|
const cfg = ACTION_CONFIG[this.type()];
|
|
4542
4530
|
const colorOverride = this.colorOverride();
|
|
4543
4531
|
const outlinedOverride = this.outlinedOverride();
|
|
4544
|
-
// Ya no se gestiona softDelete/return como modo, cada acción es independiente
|
|
4545
4532
|
return {
|
|
4546
4533
|
...cfg,
|
|
4547
4534
|
colorToken: colorOverride ?? cfg.colorToken,
|
|
@@ -4551,10 +4538,6 @@ class DsxButtonComponent {
|
|
|
4551
4538
|
get label() {
|
|
4552
4539
|
return this.labelOverride() ?? this.config.label;
|
|
4553
4540
|
}
|
|
4554
|
-
// get tooltip(): string {
|
|
4555
|
-
// this.log('getter tooltip');
|
|
4556
|
-
// return this.tooltipOverride() ?? this.config.tooltip;
|
|
4557
|
-
// }
|
|
4558
4541
|
tooltip = computed(() => {
|
|
4559
4542
|
return this.tooltipOverride() ?? this.config.tooltip;
|
|
4560
4543
|
}, ...(ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []));
|
|
@@ -4570,18 +4553,6 @@ class DsxButtonComponent {
|
|
|
4570
4553
|
}
|
|
4571
4554
|
return 'primeIcon' in this.config ? this.config.primeIcon : undefined;
|
|
4572
4555
|
}
|
|
4573
|
-
// showButton(): boolean {
|
|
4574
|
-
// this.time('showButton');
|
|
4575
|
-
// const result =
|
|
4576
|
-
// this.passesGlobalVisibilityPolicy() &&
|
|
4577
|
-
// this.passesParameterValidation() &&
|
|
4578
|
-
// this.passesIdValidation();
|
|
4579
|
-
// this.log('showButton()', {
|
|
4580
|
-
// result,
|
|
4581
|
-
// });
|
|
4582
|
-
// this.timeEnd('showButton');
|
|
4583
|
-
// return result;
|
|
4584
|
-
// }
|
|
4585
4556
|
visible = computed(() => {
|
|
4586
4557
|
return (this.passesGlobalVisibilityPolicy() &&
|
|
4587
4558
|
this.passesParameterValidation() &&
|
|
@@ -4606,45 +4577,44 @@ class DsxButtonComponent {
|
|
|
4606
4577
|
return true;
|
|
4607
4578
|
}
|
|
4608
4579
|
async onButtonClick() {
|
|
4609
|
-
this.
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4580
|
+
if (this._isDev && this.debug()) {
|
|
4581
|
+
console.group(`%c🖱️ [dsx-button:${this.type()}] Click`, 'color:#1976d2;font-weight:bold;font-size:13px');
|
|
4582
|
+
console.log('ID:', this.id());
|
|
4583
|
+
console.log('Target:', this.effectiveRouterLink());
|
|
4584
|
+
console.log('Disabled:', this.disabled());
|
|
4585
|
+
console.groupEnd();
|
|
4586
|
+
}
|
|
4613
4587
|
this.action.emit();
|
|
4614
4588
|
const target = this.effectiveRouterLink();
|
|
4615
4589
|
if (target == null) {
|
|
4616
|
-
if (this.type() === 'home') {
|
|
4617
|
-
console.warn(
|
|
4590
|
+
if (this.type() === 'home' && this._isDev && this.debug()) {
|
|
4591
|
+
console.warn(`[dsx-button:${this.type()}] No tiene routerLink ni routerPath configurado.`);
|
|
4618
4592
|
}
|
|
4619
4593
|
return;
|
|
4620
4594
|
}
|
|
4621
4595
|
try {
|
|
4622
4596
|
const start = performance.now();
|
|
4623
4597
|
const navigated = await this.navigateToTarget(target);
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
navigated
|
|
4627
|
-
|
|
4628
|
-
|
|
4598
|
+
const duration = Math.round(performance.now() - start);
|
|
4599
|
+
if (this._isDev && this.debug()) {
|
|
4600
|
+
const emoji = navigated ? '✅' : '⚠️';
|
|
4601
|
+
const color = navigated ? '#2e7d32' : '#ed6c02';
|
|
4602
|
+
console.log(`%c${emoji} Navegación ${navigated ? 'exitosa' : 'rechazada'} (${duration}ms)`, `color:${color};font-weight:bold`, target);
|
|
4603
|
+
}
|
|
4629
4604
|
if (!navigated) {
|
|
4630
|
-
// El router rechazó la navegación, lo más común durante hot-reload
|
|
4631
|
-
// es que un guard de autenticación aún no tiene el estado listo.
|
|
4632
|
-
// Se reintenta una vez tras un tick para darle tiempo al guard.
|
|
4633
4605
|
const retried = await new Promise((resolve) => setTimeout(async () => resolve(await this.navigateToTarget(target)), 0));
|
|
4634
|
-
if (!retried) {
|
|
4635
|
-
console.warn(
|
|
4636
|
-
'Si ocurre solo tras hot-reload, es normal que el guard rechace ' +
|
|
4637
|
-
'la primera navegación mientras los servicios de autenticación ' +
|
|
4638
|
-
'no han terminado de restaurar su estado.', target);
|
|
4606
|
+
if (!retried && this._isDev && this.debug()) {
|
|
4607
|
+
console.warn(`[dsx-button:${this.type()}] Navegación rechazada por route guard.`, target);
|
|
4639
4608
|
}
|
|
4640
4609
|
}
|
|
4641
4610
|
}
|
|
4642
4611
|
catch (error) {
|
|
4643
|
-
|
|
4612
|
+
if (this._isDev && this.debug()) {
|
|
4613
|
+
console.error(`[dsx-button:${this.type()}] Error al navegar:`, target, error);
|
|
4614
|
+
}
|
|
4644
4615
|
}
|
|
4645
4616
|
}
|
|
4646
4617
|
passesIdValidation() {
|
|
4647
|
-
this.log('passesIdValidation');
|
|
4648
4618
|
const explicitId = this.getNormalizedId();
|
|
4649
4619
|
const routeId = this.getIdFromNavigationTarget(this.effectiveRouterLink());
|
|
4650
4620
|
const id = explicitId ?? routeId;
|
|
@@ -4653,7 +4623,6 @@ class DsxButtonComponent {
|
|
|
4653
4623
|
this.type() === 'softDelete' ||
|
|
4654
4624
|
this.type() === 'restore' ||
|
|
4655
4625
|
this.type() === 'return';
|
|
4656
|
-
// Permite exigir que venga [id] cuando el caso de uso lo requiera.
|
|
4657
4626
|
if (this.requireIdInput() && typeof id !== 'number') {
|
|
4658
4627
|
return false;
|
|
4659
4628
|
}
|
|
@@ -4713,16 +4682,6 @@ class DsxButtonComponent {
|
|
|
4713
4682
|
}
|
|
4714
4683
|
return undefined;
|
|
4715
4684
|
}
|
|
4716
|
-
hasExplicitIdInput() {
|
|
4717
|
-
const value = this.id();
|
|
4718
|
-
if (value === null || value === undefined) {
|
|
4719
|
-
return false;
|
|
4720
|
-
}
|
|
4721
|
-
if (typeof value === 'string') {
|
|
4722
|
-
return value.trim() !== '';
|
|
4723
|
-
}
|
|
4724
|
-
return true;
|
|
4725
|
-
}
|
|
4726
4685
|
navigateToTarget(target) {
|
|
4727
4686
|
if (Array.isArray(target)) {
|
|
4728
4687
|
return this._router.navigate(target);
|
|
@@ -4734,41 +4693,154 @@ class DsxButtonComponent {
|
|
|
4734
4693
|
return this._router.navigateByUrl(target);
|
|
4735
4694
|
}
|
|
4736
4695
|
passesParameterValidation() {
|
|
4737
|
-
this.log('passesParameterValidation');
|
|
4738
4696
|
const parameterName = this.parameterName();
|
|
4739
|
-
// Si no se define un parámetro de seguridad, el botón se muestra sin restricción.
|
|
4740
4697
|
if (!parameterName) {
|
|
4741
4698
|
return true;
|
|
4742
4699
|
}
|
|
4743
|
-
// Mantiene una UX estable durante refresh de parámetros: evita parpadeo
|
|
4744
|
-
// y no evalúa permisos hasta que ParameterValuesService termine de cargar.
|
|
4745
4700
|
if (!this._paramService.loaded) {
|
|
4746
4701
|
return false;
|
|
4747
4702
|
}
|
|
4748
|
-
// Conserva el comportamiento original del servicio:
|
|
4749
|
-
// - retorna false si no cumple el valor esperado
|
|
4750
|
-
// - alerta si el parámetro no existe (ayuda a detectar typos)
|
|
4751
4703
|
return this._paramService.isParameterValue(parameterName, this.parameterExpectedValue(), this.parameterIndex());
|
|
4752
4704
|
}
|
|
4753
|
-
|
|
4754
|
-
|
|
4705
|
+
// ============ MÉTODOS DE DEBUG ============
|
|
4706
|
+
logFullState() {
|
|
4707
|
+
if (!this._isDev || !this.debug())
|
|
4755
4708
|
return;
|
|
4756
|
-
|
|
4709
|
+
const id = this.getNormalizedId();
|
|
4710
|
+
const routeId = this.getIdFromNavigationTarget(this.effectiveRouterLink());
|
|
4711
|
+
const paramName = this.parameterName();
|
|
4712
|
+
const paramLoaded = this._paramService.loaded;
|
|
4713
|
+
const paramValue = paramName && paramLoaded
|
|
4714
|
+
? this._paramService.getValue(paramName, this.parameterIndex())
|
|
4715
|
+
: undefined;
|
|
4716
|
+
console.group(`%c📊 [dsx-button:${this.type()}] Render #${this.renderCount}`, 'color:#1976d2;font-weight:bold;font-size:14px');
|
|
4717
|
+
// 1. Estado general
|
|
4718
|
+
console.log('🎯 Estado:', {
|
|
4719
|
+
visible: this.visible(),
|
|
4720
|
+
disabled: this.disabled(),
|
|
4721
|
+
type: this.type(),
|
|
4722
|
+
size: this.size(),
|
|
4723
|
+
iconOnly: this.iconOnly(),
|
|
4724
|
+
rounded: this.rounded(),
|
|
4725
|
+
isCompact: this.isCompactIconButton,
|
|
4726
|
+
});
|
|
4727
|
+
// 2. Configuración
|
|
4728
|
+
console.log('⚙️ Configuración:', {
|
|
4729
|
+
label: this.label,
|
|
4730
|
+
icon: this.icon,
|
|
4731
|
+
primeIcon: this.primeIcon,
|
|
4732
|
+
colorToken: this.config.colorToken,
|
|
4733
|
+
outlined: this.config.outlined,
|
|
4734
|
+
tooltip: this.tooltip(),
|
|
4735
|
+
});
|
|
4736
|
+
// 3. Router
|
|
4737
|
+
console.log('🔗 Router:', {
|
|
4738
|
+
routerLink: this.routerLink(),
|
|
4739
|
+
routerPath: this.routerPath(),
|
|
4740
|
+
resolvedRouterLink: this.resolvedRouterLink(),
|
|
4741
|
+
effectiveRouterLink: this.effectiveRouterLink(),
|
|
4742
|
+
});
|
|
4743
|
+
// 4. IDs
|
|
4744
|
+
console.log('🆔 IDs:', {
|
|
4745
|
+
inputId: this.id(),
|
|
4746
|
+
normalizedId: id,
|
|
4747
|
+
routeId: routeId,
|
|
4748
|
+
requireIdInput: this.requireIdInput(),
|
|
4749
|
+
requiresExistingRecord: this.requiresIdGreaterThanZero() ||
|
|
4750
|
+
['hardDelete', 'softDelete', 'restore', 'return'].includes(this.type()),
|
|
4751
|
+
});
|
|
4752
|
+
// 5. Parámetros
|
|
4753
|
+
if (paramName) {
|
|
4754
|
+
console.log('🔐 Parámetros:', {
|
|
4755
|
+
name: paramName,
|
|
4756
|
+
expected: this.parameterExpectedValue(),
|
|
4757
|
+
index: this.parameterIndex(),
|
|
4758
|
+
loaded: paramLoaded,
|
|
4759
|
+
actual: paramValue,
|
|
4760
|
+
matches: paramLoaded
|
|
4761
|
+
? paramValue === this.parameterExpectedValue()
|
|
4762
|
+
: 'No cargado',
|
|
4763
|
+
});
|
|
4764
|
+
}
|
|
4765
|
+
// 6. Overrides
|
|
4766
|
+
const overrides = {
|
|
4767
|
+
label: this.labelOverride(),
|
|
4768
|
+
tooltip: this.tooltipOverride(),
|
|
4769
|
+
icon: this.iconOverride(),
|
|
4770
|
+
primeIcon: this.primeIconOverride(),
|
|
4771
|
+
color: this.colorOverride(),
|
|
4772
|
+
outlined: this.outlinedOverride(),
|
|
4773
|
+
showValidate: this.showValidateButtonOverride(),
|
|
4774
|
+
showRestore: this.showRestoreButtonOverride(),
|
|
4775
|
+
};
|
|
4776
|
+
const activeOverrides = Object.entries(overrides)
|
|
4777
|
+
.filter(([_, value]) => value !== undefined)
|
|
4778
|
+
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {});
|
|
4779
|
+
if (Object.keys(activeOverrides).length > 0) {
|
|
4780
|
+
console.log('🔄 Overrides activos:', activeOverrides);
|
|
4781
|
+
}
|
|
4782
|
+
// 7. Validaciones
|
|
4783
|
+
console.log('✅ Validaciones:', {
|
|
4784
|
+
globalVisibility: this.passesGlobalVisibilityPolicy(),
|
|
4785
|
+
parameterValidation: this.passesParameterValidation(),
|
|
4786
|
+
idValidation: this.passesIdValidation(),
|
|
4787
|
+
visible: this.visible(),
|
|
4788
|
+
});
|
|
4789
|
+
// 8. Estilos
|
|
4790
|
+
console.log('🎨 Estilos:', {
|
|
4791
|
+
width: this.iconOnly() ? this.iconOnlyWidth() : this.width(),
|
|
4792
|
+
style: this.buttonStyleComputed(),
|
|
4793
|
+
styleClass: this.buttonStyleClass,
|
|
4794
|
+
size: this.buttonSize,
|
|
4795
|
+
});
|
|
4796
|
+
console.groupEnd();
|
|
4757
4797
|
}
|
|
4758
|
-
|
|
4759
|
-
if (!this.debug())
|
|
4798
|
+
logValidationIssues(validations) {
|
|
4799
|
+
if (!this._isDev || !this.debug())
|
|
4760
4800
|
return;
|
|
4761
|
-
|
|
4801
|
+
if (!validations.visible) {
|
|
4802
|
+
console.group(`%c❌ [dsx-button:${this.type()}] NO VISIBLE`, 'color:#d32f2f;font-weight:bold;font-size:13px');
|
|
4803
|
+
console.log('Validaciones fallidas:', {
|
|
4804
|
+
globalVisibility: validations.global,
|
|
4805
|
+
parameterValidation: validations.parameter,
|
|
4806
|
+
idValidation: validations.id,
|
|
4807
|
+
});
|
|
4808
|
+
if (!validations.id) {
|
|
4809
|
+
const id = this.getNormalizedId();
|
|
4810
|
+
const routeId = this.getIdFromNavigationTarget(this.effectiveRouterLink());
|
|
4811
|
+
console.warn('⚠️ Problema con ID:', {
|
|
4812
|
+
explicitId: this.id(),
|
|
4813
|
+
normalizedId: id,
|
|
4814
|
+
routeId: routeId,
|
|
4815
|
+
requireIdInput: this.requireIdInput(),
|
|
4816
|
+
requiresExistingRecord: this.requiresIdGreaterThanZero() ||
|
|
4817
|
+
['hardDelete', 'softDelete', 'restore', 'return'].includes(this.type()),
|
|
4818
|
+
});
|
|
4819
|
+
}
|
|
4820
|
+
if (!validations.parameter && this.parameterName()) {
|
|
4821
|
+
console.warn('⚠️ Problema con parámetro:', {
|
|
4822
|
+
name: this.parameterName(),
|
|
4823
|
+
expected: this.parameterExpectedValue(),
|
|
4824
|
+
index: this.parameterIndex(),
|
|
4825
|
+
loaded: this._paramService.loaded,
|
|
4826
|
+
actualValue: this._paramService.loaded
|
|
4827
|
+
? this._paramService.getValue(this.parameterName(), this.parameterIndex())
|
|
4828
|
+
: 'No cargado',
|
|
4829
|
+
});
|
|
4830
|
+
}
|
|
4831
|
+
console.groupEnd();
|
|
4832
|
+
}
|
|
4762
4833
|
}
|
|
4763
|
-
|
|
4764
|
-
|
|
4834
|
+
// Métodos de log existentes mejorados
|
|
4835
|
+
log(message, data) {
|
|
4836
|
+
if (!this._isDev || !this.debug())
|
|
4765
4837
|
return;
|
|
4766
|
-
console.
|
|
4838
|
+
console.log(`%c[dsx-button:${this.type()}] ${message}`, 'color:#1976d2;font-weight:bold', data ?? '');
|
|
4767
4839
|
}
|
|
4768
|
-
|
|
4769
|
-
if (!this.debug())
|
|
4840
|
+
warn(message, data) {
|
|
4841
|
+
if (!this._isDev || !this.debug())
|
|
4770
4842
|
return;
|
|
4771
|
-
console.
|
|
4843
|
+
console.warn(`[dsx-button:${this.type()}] ${message}`, data ?? '');
|
|
4772
4844
|
}
|
|
4773
4845
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4774
4846
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: DsxButtonComponent, isStandalone: true, selector: "dsx-button", inputs: { debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, routerPath: { classPropertyName: "routerPath", publicName: "routerPath", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, iconOnly: { classPropertyName: "iconOnly", publicName: "iconOnly", isSignal: true, isRequired: false, transformFunction: null }, iconOnlyWidth: { classPropertyName: "iconOnlyWidth", publicName: "iconOnlyWidth", isSignal: true, isRequired: false, transformFunction: null }, raised: { classPropertyName: "raised", publicName: "raised", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, parameterName: { classPropertyName: "parameterName", publicName: "parameterName", isSignal: true, isRequired: false, transformFunction: null }, parameterExpectedValue: { classPropertyName: "parameterExpectedValue", publicName: "parameterExpectedValue", isSignal: true, isRequired: false, transformFunction: null }, parameterIndex: { classPropertyName: "parameterIndex", publicName: "parameterIndex", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, requireIdInput: { classPropertyName: "requireIdInput", publicName: "requireIdInput", isSignal: true, isRequired: false, transformFunction: null }, requiresIdGreaterThanZero: { classPropertyName: "requiresIdGreaterThanZero", publicName: "requiresIdGreaterThanZero", isSignal: true, isRequired: false, transformFunction: null }, labelOverride: { classPropertyName: "labelOverride", publicName: "labelOverride", isSignal: true, isRequired: false, transformFunction: null }, tooltipOverride: { classPropertyName: "tooltipOverride", publicName: "tooltipOverride", isSignal: true, isRequired: false, transformFunction: null }, iconOverride: { classPropertyName: "iconOverride", publicName: "iconOverride", isSignal: true, isRequired: false, transformFunction: null }, primeIconOverride: { classPropertyName: "primeIconOverride", publicName: "primeIconOverride", isSignal: true, isRequired: false, transformFunction: null }, colorOverride: { classPropertyName: "colorOverride", publicName: "colorOverride", isSignal: true, isRequired: false, transformFunction: null }, outlinedOverride: { classPropertyName: "outlinedOverride", publicName: "outlinedOverride", isSignal: true, isRequired: false, transformFunction: null }, showValidateButtonOverride: { classPropertyName: "showValidateButtonOverride", publicName: "showValidateButtonOverride", isSignal: true, isRequired: false, transformFunction: null }, showRestoreButtonOverride: { classPropertyName: "showRestoreButtonOverride", publicName: "showRestoreButtonOverride", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { properties: { "class.dsx-button-compact-host": "this.compactHostClass" } }, ngImport: i0, template: "<!--Bot\u00F3n con las configuraciones din\u00E1micas para CRUD -->\r\n@if (visible()) {\r\n<p-button\r\n [label]=\"buttonLabel\"\r\n [style]=\"buttonStyleComputed()\"\r\n [styleClass]=\"buttonStyleClass\"\r\n [pTooltip]=\"tooltip()\"\r\n [tooltipDisabled]=\"disabled()\"\r\n tooltipPosition=\"top\"\r\n [rounded]=\"rounded()\"\r\n [text]=\"isCompactIconButton\"\r\n [size]=\"buttonSize\"\r\n severity=\"secondary\"\r\n [disabled]=\"disabled()\"\r\n [icon]=\"iconOnly() ? primeIcon : undefined\"\r\n (click)=\"onButtonClick()\"\r\n>\r\n @if (!iconOnly()) {\r\n <span class=\"material-symbols-outlined dsx-button-icon-small\"\r\n >{{ materialIcon }}</span\r\n >\r\n }\r\n</p-button>\r\n}\r\n", styles: [".dsx-button-icon-small{font-size:1.25rem;vertical-align:middle}:host{display:inline-flex;margin-bottom:.25rem}:host.dsx-button-compact-host{margin-bottom:0}:host ::ng-deep .p-button.dsx-button-compact{min-height:2rem;padding-block:.2rem}:host ::ng-deep .p-button .material-symbols-outlined.p-button-icon{line-height:1;vertical-align:middle}:host ::ng-deep .p-button.dsx-button-compact .p-button-icon{margin:0;font-size:1.2rem;line-height:1}:host ::ng-deep .p-button.dsx-button-compact .material-symbols-outlined.p-button-icon{font-variation-settings:\"FILL\" 1,\"wght\" 500,\"GRAD\" 0,\"opsz\" 24}:host ::ng-deep .p-button:disabled,:host ::ng-deep .p-button.p-disabled{cursor:not-allowed!important;opacity:.45!important;filter:grayscale(.2) saturate(.75)}:host ::ng-deep .p-button:disabled *,:host ::ng-deep .p-button.p-disabled *{cursor:not-allowed!important}.p-button.dsx-button-outlined-neutral,.p-button.dsx-button-outlined-info{background:#f5f7fa!important;border:1.5px solid #0066cc!important;color:#06c!important}.p-button.dsx-button-outlined-neutral:disabled,.p-button.dsx-button-outlined-info:disabled{background:#f5f7fa!important;border:1.5px solid #b0bec5!important;color:#b0bec5!important}\n"], dependencies: [{ kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }] });
|
|
@@ -4873,7 +4945,7 @@ const ACTION_CONFIG = {
|
|
|
4873
4945
|
view: {
|
|
4874
4946
|
label: 'Visualizar',
|
|
4875
4947
|
icon: 'visibility',
|
|
4876
|
-
primeIcon: '
|
|
4948
|
+
primeIcon: 'fa-solid fa-eye',
|
|
4877
4949
|
colorToken: 'view',
|
|
4878
4950
|
tooltip: 'Vista previa',
|
|
4879
4951
|
},
|
|
@@ -4900,167 +4972,11 @@ const ACTION_CONFIG = {
|
|
|
4900
4972
|
},
|
|
4901
4973
|
};
|
|
4902
4974
|
|
|
4903
|
-
class
|
|
4904
|
-
// Inputs
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
delay = input(100, ...(ngDevMode ? [{ debugName: "delay" }] : /* istanbul ignore next */ []));
|
|
4909
|
-
idKey = input.required(...(ngDevMode ? [{ debugName: "idKey" }] : /* istanbul ignore next */ []));
|
|
4910
|
-
dataKey = input('', ...(ngDevMode ? [{ debugName: "dataKey" }] : /* istanbul ignore next */ []));
|
|
4911
|
-
permitirCrear = input(false, ...(ngDevMode ? [{ debugName: "permitirCrear" }] : /* istanbul ignore next */ []));
|
|
4912
|
-
debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
|
|
4913
|
-
factoryNuevoRegistro = input(...(ngDevMode ? [undefined, { debugName: "factoryNuevoRegistro" }] : /* istanbul ignore next */ []));
|
|
4914
|
-
// Estado Interno
|
|
4915
|
-
dataFiltrada = signal([], ...(ngDevMode ? [{ debugName: "dataFiltrada" }] : /* istanbul ignore next */ []));
|
|
4916
|
-
value = [];
|
|
4917
|
-
onChange = () => { };
|
|
4918
|
-
onTouched = () => { };
|
|
4919
|
-
disabled = false;
|
|
4920
|
-
lastLogTime = 0;
|
|
4921
|
-
timeoutLimpieza = null;
|
|
4922
|
-
logDebug(message, data) {
|
|
4923
|
-
if (!this.debug())
|
|
4924
|
-
return;
|
|
4925
|
-
const now = Date.now();
|
|
4926
|
-
if (now - this.lastLogTime < 50)
|
|
4927
|
-
return;
|
|
4928
|
-
this.lastLogTime = now;
|
|
4929
|
-
console.log(`[DsxAutocomplete] ${message}`, data || '');
|
|
4930
|
-
}
|
|
4931
|
-
searchRequisitos(event) {
|
|
4932
|
-
const inicio = performance.now();
|
|
4933
|
-
const label = this.optionLabel();
|
|
4934
|
-
// FLUJO A: Dropdown (sin texto)
|
|
4935
|
-
if (!event.query || event.query.trim() === '') {
|
|
4936
|
-
const todoElUniverso = this.datasource();
|
|
4937
|
-
this.dataFiltrada.set(todoElUniverso);
|
|
4938
|
-
this.logDebug('Modo dropdown activo', {
|
|
4939
|
-
registros: todoElUniverso.length,
|
|
4940
|
-
});
|
|
4941
|
-
return;
|
|
4942
|
-
}
|
|
4943
|
-
// FLUJO B: Búsqueda
|
|
4944
|
-
const palabrasBuscadas = event.query
|
|
4945
|
-
.toLowerCase()
|
|
4946
|
-
.trim()
|
|
4947
|
-
.split(/\s+/)
|
|
4948
|
-
.filter((palabra) => palabra.length > 0);
|
|
4949
|
-
const filtrados = this.datasource()
|
|
4950
|
-
.filter((item) => {
|
|
4951
|
-
const textoRegistro = String(item[label] || '').toLowerCase();
|
|
4952
|
-
return palabrasBuscadas.every((palabra) => textoRegistro.includes(palabra));
|
|
4953
|
-
})
|
|
4954
|
-
.slice(0, 10);
|
|
4955
|
-
this.dataFiltrada.set(filtrados);
|
|
4956
|
-
this.logDebug(`Búsqueda "${event.query}" (${(performance.now() - inicio).toFixed(2)}ms)`, { encontrados: filtrados.length });
|
|
4957
|
-
}
|
|
4958
|
-
evaluarYAgregar(event) {
|
|
4959
|
-
const valorInput = event.target.value?.trim();
|
|
4960
|
-
if (!valorInput) {
|
|
4961
|
-
this.dataFiltrada.set([]);
|
|
4962
|
-
return;
|
|
4963
|
-
}
|
|
4964
|
-
const sugerencias = this.dataFiltrada();
|
|
4965
|
-
const actuales = this.value || [];
|
|
4966
|
-
const campoId = this.idKey();
|
|
4967
|
-
if (sugerencias.length > 0) {
|
|
4968
|
-
const primeraMatch = sugerencias[0];
|
|
4969
|
-
const yaExiste = actuales.some((item) => item[campoId] === primeraMatch[campoId]);
|
|
4970
|
-
if (!yaExiste) {
|
|
4971
|
-
this.actualizarFormulario([...actuales, primeraMatch]);
|
|
4972
|
-
this.logDebug('✅ Elemento agregado');
|
|
4973
|
-
}
|
|
4974
|
-
}
|
|
4975
|
-
else if (this.permitirCrear()) {
|
|
4976
|
-
let nuevo;
|
|
4977
|
-
if (this.factoryNuevoRegistro()) {
|
|
4978
|
-
nuevo = this.factoryNuevoRegistro()(valorInput);
|
|
4979
|
-
}
|
|
4980
|
-
else {
|
|
4981
|
-
nuevo = {
|
|
4982
|
-
[campoId]: 0,
|
|
4983
|
-
[this.optionLabel()]: valorInput.toUpperCase(),
|
|
4984
|
-
activo: true,
|
|
4985
|
-
};
|
|
4986
|
-
}
|
|
4987
|
-
this.actualizarFormulario([...actuales, nuevo]);
|
|
4988
|
-
this.logDebug('🆕 Nuevo elemento creado', valorInput);
|
|
4989
|
-
}
|
|
4990
|
-
event.target.value = '';
|
|
4991
|
-
this.dataFiltrada.set([]);
|
|
4992
|
-
}
|
|
4993
|
-
onHide() {
|
|
4994
|
-
this.logDebug('Dropdown ocultado - Limpiando estado');
|
|
4995
|
-
// Limpiar timeout anterior si existe
|
|
4996
|
-
if (this.timeoutLimpieza) {
|
|
4997
|
-
clearTimeout(this.timeoutLimpieza);
|
|
4998
|
-
this.timeoutLimpieza = null;
|
|
4999
|
-
}
|
|
5000
|
-
// Limpiar después de un pequeño delay
|
|
5001
|
-
this.timeoutLimpieza = setTimeout(() => {
|
|
5002
|
-
this.dataFiltrada.set([]);
|
|
5003
|
-
this.timeoutLimpieza = null;
|
|
5004
|
-
}, 100);
|
|
5005
|
-
}
|
|
5006
|
-
onShow() {
|
|
5007
|
-
this.logDebug('Dropdown mostrado');
|
|
5008
|
-
// Limpiar timeout pendiente
|
|
5009
|
-
if (this.timeoutLimpieza) {
|
|
5010
|
-
clearTimeout(this.timeoutLimpieza);
|
|
5011
|
-
this.timeoutLimpieza = null;
|
|
5012
|
-
}
|
|
5013
|
-
}
|
|
5014
|
-
actualizarFormulario(nuevaLista) {
|
|
5015
|
-
this.value = nuevaLista;
|
|
5016
|
-
this.onChange(this.value);
|
|
5017
|
-
this.logDebug('Formulario actualizado', {
|
|
5018
|
-
total: nuevaLista.length,
|
|
5019
|
-
});
|
|
5020
|
-
}
|
|
5021
|
-
// --- ControlValueAccessor ---
|
|
5022
|
-
writeValue(value) {
|
|
5023
|
-
this.value = value || [];
|
|
5024
|
-
this.dataFiltrada.set([]);
|
|
5025
|
-
if (this.timeoutLimpieza) {
|
|
5026
|
-
clearTimeout(this.timeoutLimpieza);
|
|
5027
|
-
this.timeoutLimpieza = null;
|
|
5028
|
-
}
|
|
5029
|
-
}
|
|
5030
|
-
registerOnChange(fn) {
|
|
5031
|
-
this.onChange = fn;
|
|
5032
|
-
}
|
|
5033
|
-
registerOnTouched(fn) {
|
|
5034
|
-
this.onTouched = fn;
|
|
5035
|
-
}
|
|
5036
|
-
setDisabledState(isDisabled) {
|
|
5037
|
-
this.disabled = isDisabled;
|
|
5038
|
-
}
|
|
5039
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxAutocomplete, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5040
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: DsxAutocomplete, isStandalone: true, selector: "dsx-autocomplete", inputs: { datasource: { classPropertyName: "datasource", publicName: "datasource", isSignal: true, isRequired: true, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null }, idKey: { classPropertyName: "idKey", publicName: "idKey", isSignal: true, isRequired: true, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: false, transformFunction: null }, permitirCrear: { classPropertyName: "permitirCrear", publicName: "permitirCrear", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, factoryNuevoRegistro: { classPropertyName: "factoryNuevoRegistro", publicName: "factoryNuevoRegistro", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
5041
|
-
{
|
|
5042
|
-
provide: NG_VALUE_ACCESSOR,
|
|
5043
|
-
useExisting: forwardRef(() => DsxAutocomplete),
|
|
5044
|
-
multi: true,
|
|
5045
|
-
},
|
|
5046
|
-
], ngImport: i0, template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n multiple\r\n [dropdown]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange(value)\"\r\n (onBlur)=\"onTouched()\"\r\n (onShow)=\"onShow()\"\r\n (onHide)=\"onHide()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n placeholder=\"Ingresa un texto....\"\r\n >\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n", styles: [""], dependencies: [{ kind: "component", type: AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }] });
|
|
5047
|
-
}
|
|
5048
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxAutocomplete, decorators: [{
|
|
5049
|
-
type: Component,
|
|
5050
|
-
args: [{ selector: 'dsx-autocomplete', imports: [AutoComplete, FormsModule, FloatLabel], providers: [
|
|
5051
|
-
{
|
|
5052
|
-
provide: NG_VALUE_ACCESSOR,
|
|
5053
|
-
useExisting: forwardRef(() => DsxAutocomplete),
|
|
5054
|
-
multi: true,
|
|
5055
|
-
},
|
|
5056
|
-
], template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n multiple\r\n [dropdown]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange(value)\"\r\n (onBlur)=\"onTouched()\"\r\n (onShow)=\"onShow()\"\r\n (onHide)=\"onHide()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n placeholder=\"Ingresa un texto....\"\r\n >\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n" }]
|
|
5057
|
-
}], propDecorators: { datasource: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasource", required: true }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], delay: [{ type: i0.Input, args: [{ isSignal: true, alias: "delay", required: false }] }], idKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "idKey", required: true }] }], dataKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataKey", required: false }] }], permitirCrear: [{ type: i0.Input, args: [{ isSignal: true, alias: "permitirCrear", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], factoryNuevoRegistro: [{ type: i0.Input, args: [{ isSignal: true, alias: "factoryNuevoRegistro", required: false }] }] } });
|
|
5058
|
-
|
|
5059
|
-
class FileComponent {
|
|
5060
|
-
// Inputs
|
|
5061
|
-
existingFile = input(null, ...(ngDevMode ? [{ debugName: "existingFile" }] : /* istanbul ignore next */ []));
|
|
5062
|
-
existingFileName = input(null, ...(ngDevMode ? [{ debugName: "existingFileName" }] : /* istanbul ignore next */ []));
|
|
5063
|
-
overrideFileName = input(null, ...(ngDevMode ? [{ debugName: "overrideFileName" }] : /* istanbul ignore next */ []));
|
|
4975
|
+
class FileComponent {
|
|
4976
|
+
// Inputs
|
|
4977
|
+
existingFile = input(null, ...(ngDevMode ? [{ debugName: "existingFile" }] : /* istanbul ignore next */ []));
|
|
4978
|
+
existingFileName = input(null, ...(ngDevMode ? [{ debugName: "existingFileName" }] : /* istanbul ignore next */ []));
|
|
4979
|
+
overrideFileName = input(null, ...(ngDevMode ? [{ debugName: "overrideFileName" }] : /* istanbul ignore next */ []));
|
|
5064
4980
|
debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
|
|
5065
4981
|
required = input(true, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
5066
4982
|
accept = input('.xls,.xlsx', ...(ngDevMode ? [{ debugName: "accept" }] : /* istanbul ignore next */ []));
|
|
@@ -8597,7 +8513,7 @@ class DsxdateShort {
|
|
|
8597
8513
|
useExisting: forwardRef(() => DsxdateShort),
|
|
8598
8514
|
multi: true,
|
|
8599
8515
|
},
|
|
8600
|
-
], ngImport: i0, template: "<!-- dsxdate-short.html -->\r\n<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "component", type: DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] });
|
|
8516
|
+
], ngImport: i0, template: "<!-- dsxdate-short.html -->\r\n<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n appendTo=\"body\"\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "component", type: DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] });
|
|
8601
8517
|
}
|
|
8602
8518
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxdateShort, decorators: [{
|
|
8603
8519
|
type: Component,
|
|
@@ -8614,7 +8530,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
8614
8530
|
useExisting: forwardRef(() => DsxdateShort),
|
|
8615
8531
|
multi: true,
|
|
8616
8532
|
},
|
|
8617
|
-
], template: "<!-- dsxdate-short.html -->\r\n<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n" }]
|
|
8533
|
+
], template: "<!-- dsxdate-short.html -->\r\n<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n appendTo=\"body\"\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n" }]
|
|
8618
8534
|
}], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], showIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcon", required: false }] }], showOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOnFocus", required: false }] }], showButtonBar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showButtonBar", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }] } });
|
|
8619
8535
|
|
|
8620
8536
|
// dsx-input-currency.ts
|
|
@@ -8852,6 +8768,666 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
8852
8768
|
args: [InputNumber]
|
|
8853
8769
|
}], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], minFractionDigits: [{ type: i0.Input, args: [{ isSignal: true, alias: "minFractionDigits", required: false }] }], maxFractionDigits: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFractionDigits", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], selectAllOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAllOnFocus", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], showError: [{ type: i0.Input, args: [{ isSignal: true, alias: "showError", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], focus: [{ type: i0.Output, args: ["focus"] }], blur: [{ type: i0.Output, args: ["blur"] }] } });
|
|
8854
8770
|
|
|
8771
|
+
class DsxAutocomplete {
|
|
8772
|
+
injector = inject(Injector);
|
|
8773
|
+
cdr = inject(ChangeDetectorRef);
|
|
8774
|
+
ngControl = null;
|
|
8775
|
+
isDevModeInternal = isDevMode();
|
|
8776
|
+
controlSignal = signal(null, ...(ngDevMode ? [{ debugName: "controlSignal" }] : /* istanbul ignore next */ []));
|
|
8777
|
+
// ✅ Almacenar IDs pendientes (privado)
|
|
8778
|
+
pendingIdsInternal = [];
|
|
8779
|
+
pendingValue = null;
|
|
8780
|
+
pendingLogs = [];
|
|
8781
|
+
datasource = input.required(...(ngDevMode ? [{ debugName: "datasource" }] : /* istanbul ignore next */ []));
|
|
8782
|
+
optionLabel = input.required(...(ngDevMode ? [{ debugName: "optionLabel" }] : /* istanbul ignore next */ []));
|
|
8783
|
+
label = input('Seleccionar', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
8784
|
+
delay = input(100, ...(ngDevMode ? [{ debugName: "delay" }] : /* istanbul ignore next */ []));
|
|
8785
|
+
idKey = input.required(...(ngDevMode ? [{ debugName: "idKey" }] : /* istanbul ignore next */ []));
|
|
8786
|
+
dataKey = input('', ...(ngDevMode ? [{ debugName: "dataKey" }] : /* istanbul ignore next */ []));
|
|
8787
|
+
permitirCrear = input(false, ...(ngDevMode ? [{ debugName: "permitirCrear" }] : /* istanbul ignore next */ []));
|
|
8788
|
+
isMultiple = input(true, ...(ngDevMode ? [{ debugName: "isMultiple" }] : /* istanbul ignore next */ []));
|
|
8789
|
+
debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
|
|
8790
|
+
factoryNuevoRegistro = input(...(ngDevMode ? [undefined, { debugName: "factoryNuevoRegistro" }] : /* istanbul ignore next */ []));
|
|
8791
|
+
returnID = input(false, ...(ngDevMode ? [{ debugName: "returnID" }] : /* istanbul ignore next */ []));
|
|
8792
|
+
showError = input(true, ...(ngDevMode ? [{ debugName: "showError" }] : /* istanbul ignore next */ []));
|
|
8793
|
+
errorControl = computed(() => {
|
|
8794
|
+
const control = this.controlSignal();
|
|
8795
|
+
if (!this.showError())
|
|
8796
|
+
return null;
|
|
8797
|
+
return control?.control ?? null;
|
|
8798
|
+
}, ...(ngDevMode ? [{ debugName: "errorControl" }] : /* istanbul ignore next */ []));
|
|
8799
|
+
get isDevMode() {
|
|
8800
|
+
return this.isDevModeInternal;
|
|
8801
|
+
}
|
|
8802
|
+
// ✅ Getter público para IDs pendientes (solo para debug)
|
|
8803
|
+
get pendingIds() {
|
|
8804
|
+
return this.pendingIdsInternal;
|
|
8805
|
+
}
|
|
8806
|
+
// ✅ Getter para logs de pendientes
|
|
8807
|
+
get pendingLogsInfo() {
|
|
8808
|
+
return this.pendingLogs.join(' | ');
|
|
8809
|
+
}
|
|
8810
|
+
get formValue() {
|
|
8811
|
+
return this.ngControl?.control?.value;
|
|
8812
|
+
}
|
|
8813
|
+
get controlName() {
|
|
8814
|
+
return this.ngControl?.name || null;
|
|
8815
|
+
}
|
|
8816
|
+
get controlValid() {
|
|
8817
|
+
return this.ngControl?.control?.valid ?? true;
|
|
8818
|
+
}
|
|
8819
|
+
get controlTouched() {
|
|
8820
|
+
return this.ngControl?.control?.touched ?? false;
|
|
8821
|
+
}
|
|
8822
|
+
get controlDirty() {
|
|
8823
|
+
return this.ngControl?.control?.dirty ?? false;
|
|
8824
|
+
}
|
|
8825
|
+
get controlErrors() {
|
|
8826
|
+
return this.ngControl?.control?.errors ?? null;
|
|
8827
|
+
}
|
|
8828
|
+
get controlValue() {
|
|
8829
|
+
return this.ngControl?.control?.value;
|
|
8830
|
+
}
|
|
8831
|
+
get controlStatus() {
|
|
8832
|
+
if (!this.ngControl?.control)
|
|
8833
|
+
return 'sin control';
|
|
8834
|
+
const control = this.ngControl.control;
|
|
8835
|
+
return `valid: ${control.valid}, touched: ${control.touched}, dirty: ${control.dirty}, errors: ${JSON.stringify(control.errors)}`;
|
|
8836
|
+
}
|
|
8837
|
+
dataFiltrada = signal([], ...(ngDevMode ? [{ debugName: "dataFiltrada" }] : /* istanbul ignore next */ []));
|
|
8838
|
+
value = this.isMultiple() ? [] : null;
|
|
8839
|
+
onChange = () => { };
|
|
8840
|
+
onTouched = () => { };
|
|
8841
|
+
disabled = false;
|
|
8842
|
+
lastLogTime = 0;
|
|
8843
|
+
timeoutLimpieza = null;
|
|
8844
|
+
initialValueSet = false;
|
|
8845
|
+
constructor() {
|
|
8846
|
+
effect(() => {
|
|
8847
|
+
this.ngControl = this.injector.get(NgControl, null);
|
|
8848
|
+
this.controlSignal.set(this.ngControl);
|
|
8849
|
+
if (this.shouldDebug() && this.ngControl) {
|
|
8850
|
+
this.logDebug('Inferred from formControlName:', {
|
|
8851
|
+
controlName: this.getFormControlName(),
|
|
8852
|
+
optionLabel: this.optionLabel(),
|
|
8853
|
+
label: this.label(),
|
|
8854
|
+
showError: this.showError(),
|
|
8855
|
+
returnID: this.returnID(),
|
|
8856
|
+
isMultiple: this.isMultiple(),
|
|
8857
|
+
});
|
|
8858
|
+
}
|
|
8859
|
+
});
|
|
8860
|
+
// ✅ Effect mejorado para recargar cuando cambia el datasource
|
|
8861
|
+
effect(() => {
|
|
8862
|
+
const ds = this.datasource();
|
|
8863
|
+
if (ds.length > 0) {
|
|
8864
|
+
this.logDebug('📚 Datasource actualizado:', ds.length);
|
|
8865
|
+
// ✅ Si hay IDs pendientes, intentar cargarlos
|
|
8866
|
+
if (this.pendingIdsInternal.length > 0) {
|
|
8867
|
+
this.logDebug('🔄 Procesando IDs pendientes:', this.pendingIdsInternal);
|
|
8868
|
+
this.procesarIdsPendientes(this.pendingIdsInternal);
|
|
8869
|
+
// ✅ No limpiamos inmediatamente para poder ver el estado en debug
|
|
8870
|
+
}
|
|
8871
|
+
// ✅ Si ya se inicializó y hay valor en el formulario, recargar
|
|
8872
|
+
if (this.initialValueSet && this.ngControl?.control?.value) {
|
|
8873
|
+
this.logDebug('🔄 Recargando valor con nuevo datasource');
|
|
8874
|
+
this.writeValue(this.ngControl.control.value);
|
|
8875
|
+
}
|
|
8876
|
+
}
|
|
8877
|
+
});
|
|
8878
|
+
effect(() => {
|
|
8879
|
+
const control = this.ngControl?.control;
|
|
8880
|
+
if (control && this.shouldDebug()) {
|
|
8881
|
+
const subscription = control.statusChanges?.subscribe(() => {
|
|
8882
|
+
this.logDebug('📊 Estado del control cambiado:', {
|
|
8883
|
+
controlName: this.getFormControlName(),
|
|
8884
|
+
valid: control.valid,
|
|
8885
|
+
touched: control.touched,
|
|
8886
|
+
dirty: control.dirty,
|
|
8887
|
+
errors: control.errors,
|
|
8888
|
+
value: control.value,
|
|
8889
|
+
});
|
|
8890
|
+
});
|
|
8891
|
+
return () => {
|
|
8892
|
+
if (subscription) {
|
|
8893
|
+
subscription.unsubscribe();
|
|
8894
|
+
}
|
|
8895
|
+
};
|
|
8896
|
+
}
|
|
8897
|
+
return () => { };
|
|
8898
|
+
});
|
|
8899
|
+
}
|
|
8900
|
+
ngOnInit() {
|
|
8901
|
+
this.logDebug('🚀 Componente inicializado');
|
|
8902
|
+
this.value = this.isMultiple() ? [] : null;
|
|
8903
|
+
}
|
|
8904
|
+
ngAfterViewInit() {
|
|
8905
|
+
this.cdr.detectChanges();
|
|
8906
|
+
}
|
|
8907
|
+
shouldDebug() {
|
|
8908
|
+
return this.isDevModeInternal && this.debug();
|
|
8909
|
+
}
|
|
8910
|
+
logDebug(message, data) {
|
|
8911
|
+
if (!this.shouldDebug())
|
|
8912
|
+
return;
|
|
8913
|
+
const now = Date.now();
|
|
8914
|
+
if (now - this.lastLogTime < 50)
|
|
8915
|
+
return;
|
|
8916
|
+
this.lastLogTime = now;
|
|
8917
|
+
console.log(`[DsxAutocomplete] ${message}`, data || '');
|
|
8918
|
+
}
|
|
8919
|
+
// ✅ Método para registrar eventos de pendientes
|
|
8920
|
+
logPending(message, ids) {
|
|
8921
|
+
if (!this.shouldDebug())
|
|
8922
|
+
return;
|
|
8923
|
+
const timestamp = new Date().toISOString().substring(11, 19);
|
|
8924
|
+
const logEntry = `[${timestamp}] ${message} ${ids ? `IDs: [${ids.join(', ')}]` : ''}`;
|
|
8925
|
+
this.pendingLogs.push(logEntry);
|
|
8926
|
+
// Mantener solo los últimos 10 logs
|
|
8927
|
+
if (this.pendingLogs.length > 10) {
|
|
8928
|
+
this.pendingLogs.shift();
|
|
8929
|
+
}
|
|
8930
|
+
console.log(`[DsxAutocomplete] ⏳ PENDING: ${logEntry}`, {
|
|
8931
|
+
pendingIds: this.pendingIdsInternal,
|
|
8932
|
+
totalPending: this.pendingIdsInternal.length,
|
|
8933
|
+
});
|
|
8934
|
+
}
|
|
8935
|
+
// ✅ Nuevo método: Procesar IDs pendientes con logs mejorados
|
|
8936
|
+
procesarIdsPendientes(ids) {
|
|
8937
|
+
if (ids.length === 0) {
|
|
8938
|
+
this.logDebug('✅ No hay IDs pendientes para procesar');
|
|
8939
|
+
return;
|
|
8940
|
+
}
|
|
8941
|
+
const sourceData = this.datasource();
|
|
8942
|
+
if (sourceData.length === 0) {
|
|
8943
|
+
this.logPending('⚠️ Datasource vacío, no se pueden procesar IDs pendientes', ids);
|
|
8944
|
+
return;
|
|
8945
|
+
}
|
|
8946
|
+
this.logPending(`🔍 Procesando ${ids.length} IDs pendientes`, ids);
|
|
8947
|
+
const objetos = sourceData.filter((item) => ids.includes(Number(item[this.idKey()])));
|
|
8948
|
+
const objetosOrdenados = ids
|
|
8949
|
+
.map((id) => objetos.find((item) => Number(item[this.idKey()]) === id))
|
|
8950
|
+
.filter((item) => item !== undefined);
|
|
8951
|
+
const encontrados = objetosOrdenados.length;
|
|
8952
|
+
const noEncontrados = ids.length - encontrados;
|
|
8953
|
+
this.logPending(`✅ Procesados: ${encontrados} encontrados, ${noEncontrados} no encontrados`, ids);
|
|
8954
|
+
if (noEncontrados > 0) {
|
|
8955
|
+
const idsNoEncontrados = ids.filter((id) => !objetos.some((item) => Number(item[this.idKey()]) === id));
|
|
8956
|
+
this.logPending(`⚠️ IDs no encontrados en datasource:`, idsNoEncontrados);
|
|
8957
|
+
}
|
|
8958
|
+
// Si se encontraron todos los objetos, actualizar la vista
|
|
8959
|
+
if (encontrados > 0) {
|
|
8960
|
+
if (this.isMultiple()) {
|
|
8961
|
+
this.value = objetosOrdenados;
|
|
8962
|
+
}
|
|
8963
|
+
else {
|
|
8964
|
+
this.value = objetosOrdenados.length > 0 ? objetosOrdenados[0] : null;
|
|
8965
|
+
}
|
|
8966
|
+
this.cdr.detectChanges();
|
|
8967
|
+
// ✅ Limpiar pendientes solo si se encontraron todos
|
|
8968
|
+
if (noEncontrados === 0) {
|
|
8969
|
+
this.pendingIdsInternal = [];
|
|
8970
|
+
this.logPending('✅ Todos los IDs pendientes fueron resueltos', ids);
|
|
8971
|
+
}
|
|
8972
|
+
else {
|
|
8973
|
+
// Mantener solo los no encontrados
|
|
8974
|
+
const idsNoEncontrados = ids.filter((id) => !objetos.some((item) => Number(item[this.idKey()]) === id));
|
|
8975
|
+
this.pendingIdsInternal = idsNoEncontrados;
|
|
8976
|
+
this.logPending(`⏳ ${idsNoEncontrados.length} IDs pendientes aún no resueltos`, idsNoEncontrados);
|
|
8977
|
+
}
|
|
8978
|
+
}
|
|
8979
|
+
else {
|
|
8980
|
+
this.logPending('❌ Ningún ID pendiente pudo ser resuelto', ids);
|
|
8981
|
+
}
|
|
8982
|
+
}
|
|
8983
|
+
searchRequisitos(event) {
|
|
8984
|
+
const inicio = performance.now();
|
|
8985
|
+
const label = this.optionLabel();
|
|
8986
|
+
if (!event.query || event.query.trim() === '') {
|
|
8987
|
+
const todoElUniverso = this.datasource();
|
|
8988
|
+
this.dataFiltrada.set(todoElUniverso);
|
|
8989
|
+
this.logDebug('Modo dropdown activo', {
|
|
8990
|
+
registros: todoElUniverso.length,
|
|
8991
|
+
});
|
|
8992
|
+
return;
|
|
8993
|
+
}
|
|
8994
|
+
const queryNormalizado = this.normalizarTexto(event.query.trim());
|
|
8995
|
+
if (!queryNormalizado) {
|
|
8996
|
+
this.dataFiltrada.set(this.datasource());
|
|
8997
|
+
return;
|
|
8998
|
+
}
|
|
8999
|
+
const palabrasBuscadas = queryNormalizado
|
|
9000
|
+
.toLowerCase()
|
|
9001
|
+
.split(/\s+/)
|
|
9002
|
+
.filter((palabra) => palabra.length > 0);
|
|
9003
|
+
const filtrados = this.datasource()
|
|
9004
|
+
.filter((item) => {
|
|
9005
|
+
const textoRegistro = this.normalizarTexto(String(item[label] || '')).toLowerCase();
|
|
9006
|
+
return palabrasBuscadas.every((palabra) => textoRegistro.includes(palabra));
|
|
9007
|
+
})
|
|
9008
|
+
.slice(0, 10);
|
|
9009
|
+
this.dataFiltrada.set(filtrados);
|
|
9010
|
+
this.logDebug(`Búsqueda "${event.query}" (${(performance.now() - inicio).toFixed(2)}ms)`, { encontrados: filtrados.length });
|
|
9011
|
+
}
|
|
9012
|
+
normalizarTexto(texto) {
|
|
9013
|
+
if (!texto)
|
|
9014
|
+
return '';
|
|
9015
|
+
return texto
|
|
9016
|
+
.normalize('NFD')
|
|
9017
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
9018
|
+
.replace(/\s+/g, ' ')
|
|
9019
|
+
.trim();
|
|
9020
|
+
}
|
|
9021
|
+
evaluarYAgregar(event) {
|
|
9022
|
+
const valorInput = event.target.value?.trim();
|
|
9023
|
+
if (!valorInput) {
|
|
9024
|
+
this.dataFiltrada.set([]);
|
|
9025
|
+
if (this.obtenerArrayValue().length === 0) {
|
|
9026
|
+
this.actualizarFormulario([]);
|
|
9027
|
+
}
|
|
9028
|
+
return;
|
|
9029
|
+
}
|
|
9030
|
+
const sugerencias = this.dataFiltrada();
|
|
9031
|
+
const actuales = this.obtenerArrayValue();
|
|
9032
|
+
const campoId = this.idKey();
|
|
9033
|
+
if (sugerencias.length > 0) {
|
|
9034
|
+
const valorNormalizado = this.normalizarTexto(valorInput).toLowerCase();
|
|
9035
|
+
const primeraMatch = sugerencias.find((item) => {
|
|
9036
|
+
const itemLabel = this.normalizarTexto(String(item[this.optionLabel()] || '')).toLowerCase();
|
|
9037
|
+
return itemLabel === valorNormalizado;
|
|
9038
|
+
}) || sugerencias[0];
|
|
9039
|
+
if (!this.isMultiple()) {
|
|
9040
|
+
this.actualizarFormulario([primeraMatch]);
|
|
9041
|
+
this.logDebug('✅ Elemento reemplazado (modo single)', primeraMatch[this.optionLabel()]);
|
|
9042
|
+
event.target.value = '';
|
|
9043
|
+
this.dataFiltrada.set([]);
|
|
9044
|
+
return;
|
|
9045
|
+
}
|
|
9046
|
+
const yaExiste = actuales.some((item) => item[campoId] === primeraMatch[campoId]);
|
|
9047
|
+
if (!yaExiste) {
|
|
9048
|
+
this.actualizarFormulario([...actuales, primeraMatch]);
|
|
9049
|
+
this.logDebug('✅ Elemento agregado');
|
|
9050
|
+
}
|
|
9051
|
+
else {
|
|
9052
|
+
this.logDebug('⚠️ Elemento ya existe en la selección');
|
|
9053
|
+
event.target.value = '';
|
|
9054
|
+
this.dataFiltrada.set([]);
|
|
9055
|
+
return;
|
|
9056
|
+
}
|
|
9057
|
+
}
|
|
9058
|
+
else if (this.permitirCrear()) {
|
|
9059
|
+
const valorNormalizado = this.normalizarTexto(valorInput).toLowerCase();
|
|
9060
|
+
const yaExisteEnActuales = actuales.some((item) => {
|
|
9061
|
+
const itemLabel = this.normalizarTexto(String(item[this.optionLabel()] || '')).toLowerCase();
|
|
9062
|
+
return itemLabel === valorNormalizado;
|
|
9063
|
+
});
|
|
9064
|
+
if (yaExisteEnActuales) {
|
|
9065
|
+
this.logDebug('⚠️ Elemento ya existe en la selección');
|
|
9066
|
+
event.target.value = '';
|
|
9067
|
+
this.dataFiltrada.set([]);
|
|
9068
|
+
return;
|
|
9069
|
+
}
|
|
9070
|
+
let nuevo;
|
|
9071
|
+
if (this.factoryNuevoRegistro()) {
|
|
9072
|
+
nuevo = this.factoryNuevoRegistro()(valorInput);
|
|
9073
|
+
}
|
|
9074
|
+
else {
|
|
9075
|
+
nuevo = {
|
|
9076
|
+
[campoId]: 0,
|
|
9077
|
+
[this.optionLabel()]: valorInput.toUpperCase(),
|
|
9078
|
+
activo: true,
|
|
9079
|
+
};
|
|
9080
|
+
}
|
|
9081
|
+
this.actualizarFormulario(this.isMultiple() ? [...actuales, nuevo] : [nuevo]);
|
|
9082
|
+
this.logDebug('🆕 Nuevo elemento creado', valorInput);
|
|
9083
|
+
}
|
|
9084
|
+
else {
|
|
9085
|
+
this.logDebug('⚠️ No se encontraron coincidencias y no se permite crear', valorInput);
|
|
9086
|
+
this.actualizarFormulario([]);
|
|
9087
|
+
if (this.ngControl?.control) {
|
|
9088
|
+
this.ngControl.control.markAsTouched();
|
|
9089
|
+
this.onTouched();
|
|
9090
|
+
}
|
|
9091
|
+
}
|
|
9092
|
+
event.target.value = '';
|
|
9093
|
+
this.dataFiltrada.set([]);
|
|
9094
|
+
}
|
|
9095
|
+
clearSelection() {
|
|
9096
|
+
this.actualizarFormulario([]);
|
|
9097
|
+
this.logDebug('🧹 Selección limpiada');
|
|
9098
|
+
}
|
|
9099
|
+
onNgModelChange(selectedItems) {
|
|
9100
|
+
let items = [];
|
|
9101
|
+
if (selectedItems === null || selectedItems === undefined) {
|
|
9102
|
+
items = [];
|
|
9103
|
+
}
|
|
9104
|
+
else if (Array.isArray(selectedItems)) {
|
|
9105
|
+
items = selectedItems;
|
|
9106
|
+
}
|
|
9107
|
+
else {
|
|
9108
|
+
items = [selectedItems];
|
|
9109
|
+
}
|
|
9110
|
+
this.logDebug('📝 onNgModelChange:', {
|
|
9111
|
+
items: items.length,
|
|
9112
|
+
isMultiple: this.isMultiple(),
|
|
9113
|
+
isArray: Array.isArray(selectedItems),
|
|
9114
|
+
isNull: selectedItems === null,
|
|
9115
|
+
returnID: this.returnID(),
|
|
9116
|
+
});
|
|
9117
|
+
if (this.isMultiple()) {
|
|
9118
|
+
this.value = items;
|
|
9119
|
+
}
|
|
9120
|
+
else {
|
|
9121
|
+
this.value = items.length > 0 ? items[0] : null;
|
|
9122
|
+
}
|
|
9123
|
+
const outputValue = this.getOutputValue(items);
|
|
9124
|
+
this.onChange(outputValue);
|
|
9125
|
+
this.logDebug('📊 Estado del control después de onChange:', {
|
|
9126
|
+
controlName: this.getFormControlName(),
|
|
9127
|
+
status: this.controlStatus,
|
|
9128
|
+
value: outputValue,
|
|
9129
|
+
});
|
|
9130
|
+
if (items.length === 0 && this.ngControl?.control) {
|
|
9131
|
+
this.ngControl.control.markAsTouched();
|
|
9132
|
+
this.onTouched();
|
|
9133
|
+
this.logDebug('📝 Control marcado como touched (selección vacía)', {
|
|
9134
|
+
newStatus: this.controlStatus,
|
|
9135
|
+
});
|
|
9136
|
+
}
|
|
9137
|
+
this.logDebug('📝 Selección actualizada', {
|
|
9138
|
+
returnID: this.returnID(),
|
|
9139
|
+
items: items.length,
|
|
9140
|
+
output: outputValue,
|
|
9141
|
+
});
|
|
9142
|
+
}
|
|
9143
|
+
getOutputValue(items) {
|
|
9144
|
+
if (items.length === 0) {
|
|
9145
|
+
return this.isMultiple() ? [] : null;
|
|
9146
|
+
}
|
|
9147
|
+
if (this.returnID()) {
|
|
9148
|
+
const ids = items.map((item) => Number(item[this.idKey()]));
|
|
9149
|
+
return this.isMultiple() ? ids : ids[0];
|
|
9150
|
+
}
|
|
9151
|
+
return this.isMultiple() ? items : items[0];
|
|
9152
|
+
}
|
|
9153
|
+
obtenerArrayValue() {
|
|
9154
|
+
if (this.isMultiple()) {
|
|
9155
|
+
return Array.isArray(this.value) ? this.value : [];
|
|
9156
|
+
}
|
|
9157
|
+
return this.value ? [this.value] : [];
|
|
9158
|
+
}
|
|
9159
|
+
getValueLength() {
|
|
9160
|
+
if (this.isMultiple()) {
|
|
9161
|
+
return Array.isArray(this.value) ? this.value.length : 0;
|
|
9162
|
+
}
|
|
9163
|
+
return this.value ? 1 : 0;
|
|
9164
|
+
}
|
|
9165
|
+
getValueDisplay(type) {
|
|
9166
|
+
if (!this.value || (Array.isArray(this.value) && this.value.length === 0)) {
|
|
9167
|
+
return 'Ninguno';
|
|
9168
|
+
}
|
|
9169
|
+
const items = Array.isArray(this.value) ? this.value : [this.value];
|
|
9170
|
+
if (type === 'id') {
|
|
9171
|
+
return items.map((item) => item[this.idKey()]).join(', ') || 'Ninguno';
|
|
9172
|
+
}
|
|
9173
|
+
else {
|
|
9174
|
+
return (items.map((item) => item[this.optionLabel()]).join(', ') || 'Ninguno');
|
|
9175
|
+
}
|
|
9176
|
+
}
|
|
9177
|
+
onHide() {
|
|
9178
|
+
this.logDebug('Dropdown ocultado - Limpiando estado');
|
|
9179
|
+
if (this.timeoutLimpieza) {
|
|
9180
|
+
clearTimeout(this.timeoutLimpieza);
|
|
9181
|
+
this.timeoutLimpieza = null;
|
|
9182
|
+
}
|
|
9183
|
+
this.timeoutLimpieza = setTimeout(() => {
|
|
9184
|
+
this.dataFiltrada.set([]);
|
|
9185
|
+
this.timeoutLimpieza = null;
|
|
9186
|
+
}, 100);
|
|
9187
|
+
if (this.ngControl?.control) {
|
|
9188
|
+
const estabaTouched = this.ngControl.control.touched;
|
|
9189
|
+
if (!estabaTouched) {
|
|
9190
|
+
this.ngControl.control.markAsTouched();
|
|
9191
|
+
this.onTouched();
|
|
9192
|
+
this.logDebug('Control marked as touched (onHide)', {
|
|
9193
|
+
controlName: this.getFormControlName(),
|
|
9194
|
+
newStatus: this.controlStatus,
|
|
9195
|
+
});
|
|
9196
|
+
}
|
|
9197
|
+
else {
|
|
9198
|
+
this.logDebug('Control ya estaba touched (onHide)', {
|
|
9199
|
+
controlName: this.getFormControlName(),
|
|
9200
|
+
status: this.controlStatus,
|
|
9201
|
+
});
|
|
9202
|
+
}
|
|
9203
|
+
}
|
|
9204
|
+
}
|
|
9205
|
+
onShow() {
|
|
9206
|
+
this.logDebug('Dropdown mostrado');
|
|
9207
|
+
if (this.timeoutLimpieza) {
|
|
9208
|
+
clearTimeout(this.timeoutLimpieza);
|
|
9209
|
+
this.timeoutLimpieza = null;
|
|
9210
|
+
}
|
|
9211
|
+
}
|
|
9212
|
+
actualizarFormulario(nuevaLista) {
|
|
9213
|
+
if (nuevaLista.length === 0) {
|
|
9214
|
+
if (this.isMultiple()) {
|
|
9215
|
+
this.value = [];
|
|
9216
|
+
}
|
|
9217
|
+
else {
|
|
9218
|
+
this.value = null;
|
|
9219
|
+
}
|
|
9220
|
+
const outputValue = this.isMultiple() ? [] : null;
|
|
9221
|
+
this.onChange(outputValue);
|
|
9222
|
+
this.logDebug('Formulario actualizado (vacío)', {
|
|
9223
|
+
isMultiple: this.isMultiple(),
|
|
9224
|
+
output: outputValue,
|
|
9225
|
+
});
|
|
9226
|
+
return;
|
|
9227
|
+
}
|
|
9228
|
+
if (this.isMultiple()) {
|
|
9229
|
+
this.value = nuevaLista;
|
|
9230
|
+
}
|
|
9231
|
+
else {
|
|
9232
|
+
this.value = nuevaLista.length > 0 ? nuevaLista[0] : null;
|
|
9233
|
+
}
|
|
9234
|
+
const outputValue = this.getOutputValue(nuevaLista);
|
|
9235
|
+
this.onChange(outputValue);
|
|
9236
|
+
this.logDebug('Formulario actualizado', {
|
|
9237
|
+
total: nuevaLista.length,
|
|
9238
|
+
isMultiple: this.isMultiple(),
|
|
9239
|
+
returnID: this.returnID(),
|
|
9240
|
+
output: outputValue,
|
|
9241
|
+
});
|
|
9242
|
+
}
|
|
9243
|
+
getFormControlName() {
|
|
9244
|
+
return this.ngControl?.name || null;
|
|
9245
|
+
}
|
|
9246
|
+
// ✨ MEJORADO: writeValue con manejo de IDs pendientes y logs
|
|
9247
|
+
writeValue(value) {
|
|
9248
|
+
const timestamp = new Date().toISOString();
|
|
9249
|
+
this.logDebug(`🔄 writeValue INVOCADO ${timestamp}`, {
|
|
9250
|
+
value,
|
|
9251
|
+
type: value === null
|
|
9252
|
+
? 'null'
|
|
9253
|
+
: value === undefined
|
|
9254
|
+
? 'undefined'
|
|
9255
|
+
: Array.isArray(value)
|
|
9256
|
+
? 'array'
|
|
9257
|
+
: typeof value === 'object'
|
|
9258
|
+
? 'object'
|
|
9259
|
+
: typeof value,
|
|
9260
|
+
returnID: this.returnID(),
|
|
9261
|
+
isMultiple: this.isMultiple(),
|
|
9262
|
+
hasDatasource: this.datasource().length > 0,
|
|
9263
|
+
datasourceSize: this.datasource().length,
|
|
9264
|
+
pendingIdsActuales: this.pendingIdsInternal,
|
|
9265
|
+
});
|
|
9266
|
+
if (value === null || value === undefined) {
|
|
9267
|
+
this.logDebug(`⚠️ Valor null/undefined, limpiando selección`);
|
|
9268
|
+
this.value = this.isMultiple() ? [] : null;
|
|
9269
|
+
if (this.pendingIdsInternal.length > 0) {
|
|
9270
|
+
this.logPending('🧹 Limpiando IDs pendientes por null/undefined', this.pendingIdsInternal);
|
|
9271
|
+
this.pendingIdsInternal = [];
|
|
9272
|
+
}
|
|
9273
|
+
this.pendingValue = null;
|
|
9274
|
+
this.initialValueSet = true;
|
|
9275
|
+
this.cdr.markForCheck();
|
|
9276
|
+
this.cdr.detectChanges();
|
|
9277
|
+
return;
|
|
9278
|
+
}
|
|
9279
|
+
let items = [];
|
|
9280
|
+
let ids = [];
|
|
9281
|
+
if (Array.isArray(value)) {
|
|
9282
|
+
if (value.length === 0) {
|
|
9283
|
+
this.value = this.isMultiple() ? [] : null;
|
|
9284
|
+
if (this.pendingIdsInternal.length > 0) {
|
|
9285
|
+
this.logPending('🧹 Limpiando IDs pendientes por array vacío', this.pendingIdsInternal);
|
|
9286
|
+
this.pendingIdsInternal = [];
|
|
9287
|
+
}
|
|
9288
|
+
this.pendingValue = null;
|
|
9289
|
+
this.initialValueSet = true;
|
|
9290
|
+
this.cdr.markForCheck();
|
|
9291
|
+
this.cdr.detectChanges();
|
|
9292
|
+
return;
|
|
9293
|
+
}
|
|
9294
|
+
if (typeof value[0] === 'number') {
|
|
9295
|
+
ids = value;
|
|
9296
|
+
this.logDebug(`📊 Recibidos ${ids.length} IDs:`, ids);
|
|
9297
|
+
}
|
|
9298
|
+
else if (typeof value[0] === 'object' && value[0] !== null) {
|
|
9299
|
+
items = value;
|
|
9300
|
+
this.logDebug(`📊 Recibidos ${items.length} objetos:`, items.map((i) => i[this.optionLabel()]));
|
|
9301
|
+
}
|
|
9302
|
+
}
|
|
9303
|
+
else if (typeof value === 'number') {
|
|
9304
|
+
ids = [value];
|
|
9305
|
+
this.logDebug(`📊 Recibido 1 ID:`, [value]);
|
|
9306
|
+
}
|
|
9307
|
+
else if (typeof value === 'object' && value !== null) {
|
|
9308
|
+
items = [value];
|
|
9309
|
+
this.logDebug(`📊 Recibido 1 objeto:`, value[this.optionLabel()]);
|
|
9310
|
+
}
|
|
9311
|
+
else {
|
|
9312
|
+
this.value = this.isMultiple() ? [] : null;
|
|
9313
|
+
if (this.pendingIdsInternal.length > 0) {
|
|
9314
|
+
this.logPending('🧹 Limpiando IDs pendientes por tipo no soportado', this.pendingIdsInternal);
|
|
9315
|
+
this.pendingIdsInternal = [];
|
|
9316
|
+
}
|
|
9317
|
+
this.pendingValue = null;
|
|
9318
|
+
this.initialValueSet = true;
|
|
9319
|
+
this.cdr.markForCheck();
|
|
9320
|
+
this.cdr.detectChanges();
|
|
9321
|
+
return;
|
|
9322
|
+
}
|
|
9323
|
+
const sourceData = this.datasource();
|
|
9324
|
+
// ✅ Si tenemos IDs y el datasource está vacío, guardarlos para después
|
|
9325
|
+
if (ids.length > 0 && sourceData.length === 0) {
|
|
9326
|
+
this.logPending(`⏳ Datasource vacío (${sourceData.length}), guardando ${ids.length} IDs para procesar después`, ids);
|
|
9327
|
+
this.pendingIdsInternal = ids;
|
|
9328
|
+
this.pendingValue = value;
|
|
9329
|
+
this.initialValueSet = true;
|
|
9330
|
+
// ✅ Mostrar un placeholder visual mientras se cargan los datos
|
|
9331
|
+
this.value = this.isMultiple() ? [] : null;
|
|
9332
|
+
this.cdr.markForCheck();
|
|
9333
|
+
this.cdr.detectChanges();
|
|
9334
|
+
this.logDebug(`⏳ IDs guardados como pendientes:`, this.pendingIdsInternal);
|
|
9335
|
+
return;
|
|
9336
|
+
}
|
|
9337
|
+
// ✅ Si tenemos IDs y el datasource existe, buscar los objetos
|
|
9338
|
+
if (ids.length > 0 && sourceData.length > 0) {
|
|
9339
|
+
this.logDebug(`🔍 Buscando ${ids.length} IDs en datasource de ${sourceData.length} elementos`);
|
|
9340
|
+
const objetos = sourceData.filter((item) => ids.includes(Number(item[this.idKey()])));
|
|
9341
|
+
const objetosOrdenados = ids
|
|
9342
|
+
.map((id) => objetos.find((item) => Number(item[this.idKey()]) === id))
|
|
9343
|
+
.filter((item) => item !== undefined);
|
|
9344
|
+
items = objetosOrdenados;
|
|
9345
|
+
// ✅ Si no se encontraron algunos IDs, guardarlos como pendientes
|
|
9346
|
+
const idsNoEncontrados = ids.filter((id) => !objetos.some((item) => Number(item[this.idKey()]) === id));
|
|
9347
|
+
if (idsNoEncontrados.length > 0) {
|
|
9348
|
+
this.logPending(`⚠️ ${idsNoEncontrados.length} IDs no encontrados en datasource`, idsNoEncontrados);
|
|
9349
|
+
this.pendingIdsInternal = idsNoEncontrados;
|
|
9350
|
+
this.pendingValue = value;
|
|
9351
|
+
}
|
|
9352
|
+
else {
|
|
9353
|
+
// ✅ Todos los IDs fueron encontrados
|
|
9354
|
+
if (this.pendingIdsInternal.length > 0) {
|
|
9355
|
+
this.logPending('✅ Todos los IDs pendientes fueron resueltos', this.pendingIdsInternal);
|
|
9356
|
+
this.pendingIdsInternal = [];
|
|
9357
|
+
this.pendingValue = null;
|
|
9358
|
+
}
|
|
9359
|
+
}
|
|
9360
|
+
this.logDebug(`🔍 Encontrados ${items.length} de ${ids.length} IDs`);
|
|
9361
|
+
}
|
|
9362
|
+
// ✅ Verificar que los items existan en el datasource
|
|
9363
|
+
if (items.length > 0 && sourceData.length > 0) {
|
|
9364
|
+
const itemsValidos = items.filter((item) => sourceData.some((s) => s[this.idKey()] === item[this.idKey()]));
|
|
9365
|
+
if (itemsValidos.length !== items.length) {
|
|
9366
|
+
this.logDebug(`⚠️ Algunos objetos no existen en datasource`, {
|
|
9367
|
+
original: items.length,
|
|
9368
|
+
validos: itemsValidos.length,
|
|
9369
|
+
});
|
|
9370
|
+
items = itemsValidos;
|
|
9371
|
+
}
|
|
9372
|
+
}
|
|
9373
|
+
// ✅ Asignar el valor
|
|
9374
|
+
if (this.isMultiple()) {
|
|
9375
|
+
this.value = items;
|
|
9376
|
+
}
|
|
9377
|
+
else {
|
|
9378
|
+
this.value = items.length > 0 ? items[0] : null;
|
|
9379
|
+
}
|
|
9380
|
+
this.initialValueSet = true;
|
|
9381
|
+
this.cdr.detectChanges();
|
|
9382
|
+
this.logDebug(`✅ Vista actualizada con ${items.length} elementos (${this.isMultiple() ? 'multiple' : 'single'})`);
|
|
9383
|
+
if (this.pendingIdsInternal.length > 0) {
|
|
9384
|
+
this.logDebug(`⏳ IDs pendientes actuales:`, this.pendingIdsInternal);
|
|
9385
|
+
}
|
|
9386
|
+
}
|
|
9387
|
+
forceReload() {
|
|
9388
|
+
this.logDebug('🔄 Forzando recarga');
|
|
9389
|
+
if (this.ngControl?.control) {
|
|
9390
|
+
const currentValue = this.ngControl.control.value;
|
|
9391
|
+
this.logDebug('🔄 Valor actual del formulario:', currentValue);
|
|
9392
|
+
this.writeValue(currentValue);
|
|
9393
|
+
}
|
|
9394
|
+
}
|
|
9395
|
+
registerOnChange(fn) {
|
|
9396
|
+
this.onChange = fn;
|
|
9397
|
+
}
|
|
9398
|
+
registerOnTouched(fn) {
|
|
9399
|
+
this.onTouched = fn;
|
|
9400
|
+
}
|
|
9401
|
+
setDisabledState(isDisabled) {
|
|
9402
|
+
this.disabled = isDisabled;
|
|
9403
|
+
this.cdr.markForCheck();
|
|
9404
|
+
}
|
|
9405
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxAutocomplete, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9406
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: DsxAutocomplete, isStandalone: true, selector: "dsx-autocomplete", inputs: { datasource: { classPropertyName: "datasource", publicName: "datasource", isSignal: true, isRequired: true, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null }, idKey: { classPropertyName: "idKey", publicName: "idKey", isSignal: true, isRequired: true, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: false, transformFunction: null }, permitirCrear: { classPropertyName: "permitirCrear", publicName: "permitirCrear", isSignal: true, isRequired: false, transformFunction: null }, isMultiple: { classPropertyName: "isMultiple", publicName: "isMultiple", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, factoryNuevoRegistro: { classPropertyName: "factoryNuevoRegistro", publicName: "factoryNuevoRegistro", isSignal: true, isRequired: false, transformFunction: null }, returnID: { classPropertyName: "returnID", publicName: "returnID", isSignal: true, isRequired: false, transformFunction: null }, showError: { classPropertyName: "showError", publicName: "showError", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
9407
|
+
{
|
|
9408
|
+
provide: NG_VALUE_ACCESSOR,
|
|
9409
|
+
useExisting: forwardRef(() => DsxAutocomplete),
|
|
9410
|
+
multi: true,
|
|
9411
|
+
},
|
|
9412
|
+
], ngImport: i0, template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n [multiple]=\"isMultiple()\"\r\n [dropdown]=\"true\"\r\n [showClear]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onNgModelChange($event)\"\r\n (onBlur)=\"onTouched()\"\r\n (onShow)=\"onShow()\"\r\n (onHide)=\"onHide()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n placeholder=\"Ingresa un texto....\"\r\n [inputStyle]=\"{'text-transform': 'uppercase'}\"\r\n >\r\n <ng-template let-item pTemplate=\"selectedItem\">\r\n {{ item[optionLabel()] }}\r\n </ng-template>\r\n\r\n <ng-template let-item pTemplate=\"item\">\r\n {{ item[optionLabel()] }}\r\n </ng-template>\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n\r\n<!-- \u2728 Indicador de carga (cuando hay IDs pendientes) -->\r\n@if (pendingIds.length > 0 && debug() && isDevMode) {\r\n<div\r\n style=\"\r\n font-size: 10px;\r\n color: #f59e0b;\r\n margin-top: 2px;\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n \"\r\n>\r\n <span>\u23F3</span>\r\n <span\r\n >Cargando datos pendientes ({{ pendingIds.length }} IDs: [{{\r\n pendingIds.join(', ') }}])</span\r\n >\r\n</div>\r\n}\r\n\r\n<!-- \u2728 Bot\u00F3n de limpiar para modo single -->\r\n@if (!isMultiple() && value) {\r\n<button\r\n type=\"button\"\r\n (click)=\"clearSelection()\"\r\n style=\"\r\n position: absolute;\r\n right: 10px;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n background: transparent;\r\n border: none;\r\n cursor: pointer;\r\n color: #999;\r\n font-size: 14px;\r\n z-index: 1;\r\n \"\r\n aria-label=\"Limpiar selecci\u00F3n\"\r\n>\r\n \u2715\r\n</button>\r\n}\r\n\r\n<!-- Mensaje de error -->\r\n@if (showError() && errorControl()) {\r\n<dsx-message-error [control]=\"errorControl()\" />\r\n}\r\n\r\n<!-- Panel de Debug -->\r\n@if (debug() && isDevMode) {\r\n<div\r\n style=\"\r\n margin-top: 8px;\r\n font-size: 11px;\r\n color: #666;\r\n background: #f5f5f5;\r\n padding: 6px 10px;\r\n border-radius: 4px;\r\n font-family: monospace;\r\n border: 1px solid #ddd;\r\n \"\r\n>\r\n <div\r\n style=\"\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n gap: 8px;\r\n flex-wrap: wrap;\r\n \"\r\n >\r\n <div>\r\n <strong>\uD83D\uDD0D Debug:</strong>\r\n <span style=\"margin-left: 8px\">Items: {{ getValueLength() }}</span>\r\n <span style=\"margin-left: 8px\">IDs: {{ getValueDisplay('id') }}</span>\r\n <span style=\"margin-left: 8px\"\r\n >Nombres: {{ getValueDisplay('nombre') }}</span\r\n >\r\n <span style=\"margin-left: 8px; color: #888; font-size: 10px\">\r\n | returnID: {{ returnID() ? '\u2705 IDs' : '\u274C Objetos' }} | Multiple: {{\r\n isMultiple() ? '\u2705' : '\u274C' }} | Control: {{ controlName || 'sin nombre'\r\n }}\r\n </span>\r\n @if (pendingIds.length > 0) {\r\n <span style=\"margin-left: 8px; color: #f59e0b; font-weight: bold\">\r\n | \u23F3 Pendientes: {{ pendingIds.length }} ({{ pendingIds.join(', ') }})\r\n </span>\r\n } @else {\r\n <span style=\"margin-left: 8px; color: #10b981; font-weight: bold\">\r\n | \u2705 Sin pendientes\r\n </span>\r\n }\r\n <span style=\"margin-left: 8px; color: #888; font-size: 9px\">\r\n | Logs: {{ pendingLogsInfo }}\r\n </span>\r\n </div>\r\n <div\r\n style=\"\r\n font-size: 10px;\r\n color: #333;\r\n background: #e8e8e8;\r\n padding: 2px 8px;\r\n border-radius: 4px;\r\n \"\r\n >\r\n <strong>\uD83D\uDCCA Validaci\u00F3n:</strong>\r\n <span [style.color]=\"controlValid ? 'green' : 'red'\">\r\n {{ controlValid ? '\u2705 V\u00E1lido' : '\u274C Inv\u00E1lido' }}\r\n </span>\r\n <span style=\"margin-left: 4px\">\r\n | Touched: {{ controlTouched ? '\u2705' : '\u274C' }}\r\n </span>\r\n <span style=\"margin-left: 4px\">\r\n | Dirty: {{ controlDirty ? '\u2705' : '\u274C' }}\r\n </span>\r\n @if (controlErrors) {\r\n <span style=\"margin-left: 4px; color: red\">\r\n | Errors: {{ controlErrors | json }}\r\n </span>\r\n }\r\n </div>\r\n <button\r\n (click)=\"forceReload()\"\r\n style=\"\r\n font-size: 10px;\r\n padding: 2px 8px;\r\n border-radius: 4px;\r\n border: 1px solid #ccc;\r\n background: white;\r\n cursor: pointer;\r\n \"\r\n type=\"button\"\r\n >\r\n \uD83D\uDD04 Recargar\r\n </button>\r\n </div>\r\n</div>\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "pipe", type: JsonPipe, name: "json" }] });
|
|
9413
|
+
}
|
|
9414
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxAutocomplete, decorators: [{
|
|
9415
|
+
type: Component,
|
|
9416
|
+
args: [{ selector: 'dsx-autocomplete', imports: [
|
|
9417
|
+
AutoComplete,
|
|
9418
|
+
FormsModule,
|
|
9419
|
+
FloatLabel,
|
|
9420
|
+
JsonPipe,
|
|
9421
|
+
AppMessageErrorComponent,
|
|
9422
|
+
], providers: [
|
|
9423
|
+
{
|
|
9424
|
+
provide: NG_VALUE_ACCESSOR,
|
|
9425
|
+
useExisting: forwardRef(() => DsxAutocomplete),
|
|
9426
|
+
multi: true,
|
|
9427
|
+
},
|
|
9428
|
+
], template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n [multiple]=\"isMultiple()\"\r\n [dropdown]=\"true\"\r\n [showClear]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onNgModelChange($event)\"\r\n (onBlur)=\"onTouched()\"\r\n (onShow)=\"onShow()\"\r\n (onHide)=\"onHide()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n placeholder=\"Ingresa un texto....\"\r\n [inputStyle]=\"{'text-transform': 'uppercase'}\"\r\n >\r\n <ng-template let-item pTemplate=\"selectedItem\">\r\n {{ item[optionLabel()] }}\r\n </ng-template>\r\n\r\n <ng-template let-item pTemplate=\"item\">\r\n {{ item[optionLabel()] }}\r\n </ng-template>\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n\r\n<!-- \u2728 Indicador de carga (cuando hay IDs pendientes) -->\r\n@if (pendingIds.length > 0 && debug() && isDevMode) {\r\n<div\r\n style=\"\r\n font-size: 10px;\r\n color: #f59e0b;\r\n margin-top: 2px;\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n \"\r\n>\r\n <span>\u23F3</span>\r\n <span\r\n >Cargando datos pendientes ({{ pendingIds.length }} IDs: [{{\r\n pendingIds.join(', ') }}])</span\r\n >\r\n</div>\r\n}\r\n\r\n<!-- \u2728 Bot\u00F3n de limpiar para modo single -->\r\n@if (!isMultiple() && value) {\r\n<button\r\n type=\"button\"\r\n (click)=\"clearSelection()\"\r\n style=\"\r\n position: absolute;\r\n right: 10px;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n background: transparent;\r\n border: none;\r\n cursor: pointer;\r\n color: #999;\r\n font-size: 14px;\r\n z-index: 1;\r\n \"\r\n aria-label=\"Limpiar selecci\u00F3n\"\r\n>\r\n \u2715\r\n</button>\r\n}\r\n\r\n<!-- Mensaje de error -->\r\n@if (showError() && errorControl()) {\r\n<dsx-message-error [control]=\"errorControl()\" />\r\n}\r\n\r\n<!-- Panel de Debug -->\r\n@if (debug() && isDevMode) {\r\n<div\r\n style=\"\r\n margin-top: 8px;\r\n font-size: 11px;\r\n color: #666;\r\n background: #f5f5f5;\r\n padding: 6px 10px;\r\n border-radius: 4px;\r\n font-family: monospace;\r\n border: 1px solid #ddd;\r\n \"\r\n>\r\n <div\r\n style=\"\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n gap: 8px;\r\n flex-wrap: wrap;\r\n \"\r\n >\r\n <div>\r\n <strong>\uD83D\uDD0D Debug:</strong>\r\n <span style=\"margin-left: 8px\">Items: {{ getValueLength() }}</span>\r\n <span style=\"margin-left: 8px\">IDs: {{ getValueDisplay('id') }}</span>\r\n <span style=\"margin-left: 8px\"\r\n >Nombres: {{ getValueDisplay('nombre') }}</span\r\n >\r\n <span style=\"margin-left: 8px; color: #888; font-size: 10px\">\r\n | returnID: {{ returnID() ? '\u2705 IDs' : '\u274C Objetos' }} | Multiple: {{\r\n isMultiple() ? '\u2705' : '\u274C' }} | Control: {{ controlName || 'sin nombre'\r\n }}\r\n </span>\r\n @if (pendingIds.length > 0) {\r\n <span style=\"margin-left: 8px; color: #f59e0b; font-weight: bold\">\r\n | \u23F3 Pendientes: {{ pendingIds.length }} ({{ pendingIds.join(', ') }})\r\n </span>\r\n } @else {\r\n <span style=\"margin-left: 8px; color: #10b981; font-weight: bold\">\r\n | \u2705 Sin pendientes\r\n </span>\r\n }\r\n <span style=\"margin-left: 8px; color: #888; font-size: 9px\">\r\n | Logs: {{ pendingLogsInfo }}\r\n </span>\r\n </div>\r\n <div\r\n style=\"\r\n font-size: 10px;\r\n color: #333;\r\n background: #e8e8e8;\r\n padding: 2px 8px;\r\n border-radius: 4px;\r\n \"\r\n >\r\n <strong>\uD83D\uDCCA Validaci\u00F3n:</strong>\r\n <span [style.color]=\"controlValid ? 'green' : 'red'\">\r\n {{ controlValid ? '\u2705 V\u00E1lido' : '\u274C Inv\u00E1lido' }}\r\n </span>\r\n <span style=\"margin-left: 4px\">\r\n | Touched: {{ controlTouched ? '\u2705' : '\u274C' }}\r\n </span>\r\n <span style=\"margin-left: 4px\">\r\n | Dirty: {{ controlDirty ? '\u2705' : '\u274C' }}\r\n </span>\r\n @if (controlErrors) {\r\n <span style=\"margin-left: 4px; color: red\">\r\n | Errors: {{ controlErrors | json }}\r\n </span>\r\n }\r\n </div>\r\n <button\r\n (click)=\"forceReload()\"\r\n style=\"\r\n font-size: 10px;\r\n padding: 2px 8px;\r\n border-radius: 4px;\r\n border: 1px solid #ccc;\r\n background: white;\r\n cursor: pointer;\r\n \"\r\n type=\"button\"\r\n >\r\n \uD83D\uDD04 Recargar\r\n </button>\r\n </div>\r\n</div>\r\n}\r\n" }]
|
|
9429
|
+
}], ctorParameters: () => [], propDecorators: { datasource: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasource", required: true }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], delay: [{ type: i0.Input, args: [{ isSignal: true, alias: "delay", required: false }] }], idKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "idKey", required: true }] }], dataKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataKey", required: false }] }], permitirCrear: [{ type: i0.Input, args: [{ isSignal: true, alias: "permitirCrear", required: false }] }], isMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "isMultiple", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], factoryNuevoRegistro: [{ type: i0.Input, args: [{ isSignal: true, alias: "factoryNuevoRegistro", required: false }] }], returnID: [{ type: i0.Input, args: [{ isSignal: true, alias: "returnID", required: false }] }], showError: [{ type: i0.Input, args: [{ isSignal: true, alias: "showError", required: false }] }] } });
|
|
9430
|
+
|
|
8855
9431
|
// dsx-select.component.ts
|
|
8856
9432
|
class DsxSelect {
|
|
8857
9433
|
injector = inject(Injector);
|