ng-components-tsi 0.0.77 → 0.0.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/ng-components-tsi.mjs +536 -1
- package/fesm2022/ng-components-tsi.mjs.map +1 -1
- package/lib/modals/general/md-generico/md-generico.component.d.ts +1 -1
- package/lib/models/table-data.model.d.ts +2 -0
- package/lib/ui/forms/inputs/input/input.component.d.ts +4 -4
- package/lib/ui/forms/inputs/input-radio/input-radio.component.d.ts +1 -1
- package/lib/ui/forms/lists/list-option/list-option.component.d.ts +1 -1
- package/lib/ui/tables/paginador/paginador.component.d.ts +1 -1
- package/lib/ui/tables/table-ultimate/table-ultimate.component.d.ts +2 -2
- package/lib/ui/tables/table-ultimate-pinned/table-ultimate-pinned.component.d.ts +196 -0
- package/lib/ui/tables/table-ultimate-pivot/table-ultimate-pivot.component.d.ts +2 -2
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
|
@@ -4161,6 +4161,539 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
|
|
|
4161
4161
|
args: ['window:resize', ['$event']]
|
|
4162
4162
|
}] } });
|
|
4163
4163
|
|
|
4164
|
+
class TableUltimatePinnedComponent {
|
|
4165
|
+
scrollContainer = viewChild('scrollContainer');
|
|
4166
|
+
customActions = contentChild('customActions');
|
|
4167
|
+
columnDefs = contentChildren(TsiColumnDefDirective);
|
|
4168
|
+
columnDefMap = computed(() => new Map(this.columnDefs().map(d => [d.fieldname(), d.template])));
|
|
4169
|
+
formateador = inject(FormateadorService);
|
|
4170
|
+
// ── Inputs ──────────────────────────────────────────────────────────────────
|
|
4171
|
+
rows = input([]);
|
|
4172
|
+
columns = input([]);
|
|
4173
|
+
footerRows = input([]);
|
|
4174
|
+
rowHeight = input(0);
|
|
4175
|
+
buffer = input(10);
|
|
4176
|
+
altoContainer = input(0);
|
|
4177
|
+
altoContenedor = input(400);
|
|
4178
|
+
minAlto = input(200);
|
|
4179
|
+
identifier = input([]);
|
|
4180
|
+
withFiltro = input(false);
|
|
4181
|
+
withDetails = input(false);
|
|
4182
|
+
withCheckbox = input(false);
|
|
4183
|
+
withTotal = input(false);
|
|
4184
|
+
withHeight = input(false);
|
|
4185
|
+
withAttachment = input(false);
|
|
4186
|
+
variante = input('standard');
|
|
4187
|
+
rendered = input([]);
|
|
4188
|
+
dragOverRowId = signal(null); // dropzone para adjuntos
|
|
4189
|
+
titleTabla = input('Contrato');
|
|
4190
|
+
activeMobileMode = input(true);
|
|
4191
|
+
isLoadingResponsive = signal(false);
|
|
4192
|
+
isMobile = signal(window.innerWidth <= 768);
|
|
4193
|
+
contentFilter = contentChild('header'); // inyect content in filter
|
|
4194
|
+
// ── Output ──────────────────────────────────────────────────────────────────
|
|
4195
|
+
rowEvent = output();
|
|
4196
|
+
// ── ROW ACTIONS ──────────────────────────────────────────────────────────────────
|
|
4197
|
+
selectedRow = model(null);
|
|
4198
|
+
rowClassFn = input(null);
|
|
4199
|
+
rowDisabledFn = input(null);
|
|
4200
|
+
selectItems = model([]);
|
|
4201
|
+
rowFormat = computed(() => this.formateador.procesarLista(this.rows(), this.columns()));
|
|
4202
|
+
// ── Estado interno ───────────────────────────────────────────────────────────
|
|
4203
|
+
busqueda = model('');
|
|
4204
|
+
scrollTop = signal(0);
|
|
4205
|
+
containerHeight = signal(0); // altura real medida del DOM
|
|
4206
|
+
// ── Sort ─────────────────────────────────────────────────────────────────────
|
|
4207
|
+
sortField = signal(null);
|
|
4208
|
+
sortDir = signal('none');
|
|
4209
|
+
//-- EXPANDED ROWS
|
|
4210
|
+
expandedRows = signal(null);
|
|
4211
|
+
classTotales = input('');
|
|
4212
|
+
// ── CSS height del contenedor ─────────────────────────────────────────────────
|
|
4213
|
+
/** Valor aplicado como [style.height] en el template */
|
|
4214
|
+
heightStyle = computed(() => {
|
|
4215
|
+
if (this.altoContainer() > 0) {
|
|
4216
|
+
return `clamp(${this.minAlto()}px, calc(100vh - ${this.altoContainer()}px), 100vh)`;
|
|
4217
|
+
}
|
|
4218
|
+
return `${this.altoContenedor()}px`;
|
|
4219
|
+
});
|
|
4220
|
+
// ── Filtrado + Ordenamiento ───────────────────────────────────────────────────
|
|
4221
|
+
rowFilter = computed(() => {
|
|
4222
|
+
const term = this.busqueda().toLowerCase().trim();
|
|
4223
|
+
const filtered = term
|
|
4224
|
+
? this.rowFormat().filter(item => this.filtraItem(item, term))
|
|
4225
|
+
: this.rowFormat();
|
|
4226
|
+
const field = this.sortField();
|
|
4227
|
+
const dir = this.sortDir();
|
|
4228
|
+
if (!field || dir === 'none')
|
|
4229
|
+
return filtered;
|
|
4230
|
+
return [...filtered].sort((a, b) => {
|
|
4231
|
+
const valueA = a[field] ?? '';
|
|
4232
|
+
const valueB = b[field] ?? '';
|
|
4233
|
+
if (typeof valueA === 'number' && typeof valueB === 'number') {
|
|
4234
|
+
return dir === 'asc' ? valueA - valueB : valueB - valueA;
|
|
4235
|
+
}
|
|
4236
|
+
const numA = Number(valueA);
|
|
4237
|
+
const numB = Number(valueB);
|
|
4238
|
+
if (!isNaN(numA) && !isNaN(numB)) {
|
|
4239
|
+
return dir === 'asc' ? numA - numB : numB - numA;
|
|
4240
|
+
}
|
|
4241
|
+
const va = String(valueA).toLowerCase();
|
|
4242
|
+
const vb = String(valueB).toLowerCase();
|
|
4243
|
+
const cmp = va.localeCompare(vb, undefined, { numeric: true });
|
|
4244
|
+
return dir === 'asc' ? cmp : -cmp;
|
|
4245
|
+
});
|
|
4246
|
+
});
|
|
4247
|
+
// ── Virtual scroll ────────────────────────────────────────────────────────────
|
|
4248
|
+
// Alto efectivo de fila: si no se pasa rowHeight (0), se resuelve por variante.
|
|
4249
|
+
// DEBE coincidir con el height del td en el SCSS (42px modern / 30px standard) o el scroll se desalinea.
|
|
4250
|
+
rowH = computed(() => this.rowHeight() || (this.variante() === 'modern' ? 40 : 30));
|
|
4251
|
+
totalHeight = computed(() => this.rowFilter().length * this.rowH());
|
|
4252
|
+
startIndex = computed(() => {
|
|
4253
|
+
const idx = Math.floor(this.scrollTop() / this.rowH()) - this.buffer();
|
|
4254
|
+
return Math.max(0, idx);
|
|
4255
|
+
});
|
|
4256
|
+
endIndex = computed(() => {
|
|
4257
|
+
const visible = Math.ceil(this.containerHeight() / this.rowH());
|
|
4258
|
+
const idx = this.startIndex() + visible + this.buffer() * 2;
|
|
4259
|
+
return Math.min(this.rowFilter().length - 1, idx);
|
|
4260
|
+
});
|
|
4261
|
+
visibleRows = computed(() => this.rowFilter().slice(this.startIndex(), this.endIndex() + 1));
|
|
4262
|
+
/** Espacio en blanco antes de las filas renderizadas */
|
|
4263
|
+
paddingTop = computed(() => this.startIndex() * this.rowH());
|
|
4264
|
+
/** Espacio en blanco después de las filas renderizadas */
|
|
4265
|
+
paddingBottom = computed(() => {
|
|
4266
|
+
const remaining = this.rowFilter().length - this.endIndex() - 1;
|
|
4267
|
+
return Math.max(0, remaining * this.rowH());
|
|
4268
|
+
});
|
|
4269
|
+
// ── Scroll hacia fila seleccionada al cargar datos ───────────────────────────
|
|
4270
|
+
scrollEffect = effect(() => {
|
|
4271
|
+
const rows = this.rowFilter();
|
|
4272
|
+
const selected = untracked(() => this.selectedRow());
|
|
4273
|
+
if (rows.length > 0 && selected != null) {
|
|
4274
|
+
queueMicrotask(() => this.scrollToSelected(selected));
|
|
4275
|
+
}
|
|
4276
|
+
});
|
|
4277
|
+
// ── ResizeObserver ────────────────────────────────────────────────────────────
|
|
4278
|
+
resizeObserver;
|
|
4279
|
+
resizeEffect = effect(() => {
|
|
4280
|
+
if (!this.scrollContainer())
|
|
4281
|
+
return;
|
|
4282
|
+
const el = this.scrollContainer().nativeElement;
|
|
4283
|
+
this.containerHeight.set(el.clientHeight);
|
|
4284
|
+
this.syncScrollX(el);
|
|
4285
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
4286
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
4287
|
+
this.containerHeight.set(el.clientHeight);
|
|
4288
|
+
this.scrollTop.set(el.scrollTop);
|
|
4289
|
+
this.syncScrollX(el);
|
|
4290
|
+
});
|
|
4291
|
+
this.resizeObserver.observe(el);
|
|
4292
|
+
// Observa también la tabla: si cambian columnas/datos cambia el ancho scrolleable
|
|
4293
|
+
const table = el.querySelector('table');
|
|
4294
|
+
if (table)
|
|
4295
|
+
this.resizeObserver.observe(table);
|
|
4296
|
+
}
|
|
4297
|
+
});
|
|
4298
|
+
ngOnDestroy() {
|
|
4299
|
+
this.resizeObserver?.disconnect();
|
|
4300
|
+
}
|
|
4301
|
+
// ── Manejadores ──────────────────────────────────────────────────────────────
|
|
4302
|
+
onScroll(event) {
|
|
4303
|
+
const el = event.target;
|
|
4304
|
+
this.scrollTop.set(el.scrollTop);
|
|
4305
|
+
this.syncScrollX(el);
|
|
4306
|
+
}
|
|
4307
|
+
selectRow(row, idList) {
|
|
4308
|
+
this.rowEvent.emit({ usecase: TABLE_EVENTS.CLICK, data: row });
|
|
4309
|
+
if (this.identifier().length < 1) {
|
|
4310
|
+
this.selectedRow.set(idList);
|
|
4311
|
+
}
|
|
4312
|
+
else {
|
|
4313
|
+
this.selectedRow.set(this.concatenarValue(row, this.identifier()));
|
|
4314
|
+
}
|
|
4315
|
+
}
|
|
4316
|
+
isSelected(row, idList) {
|
|
4317
|
+
if (this.identifier().length < 1) {
|
|
4318
|
+
return this.selectedRow() == idList;
|
|
4319
|
+
}
|
|
4320
|
+
return this.selectedRow() == this.concatenarValue(row, this.identifier());
|
|
4321
|
+
}
|
|
4322
|
+
textoDigitado() {
|
|
4323
|
+
this.scrollTop.set(0);
|
|
4324
|
+
if (this.scrollContainer()?.nativeElement) {
|
|
4325
|
+
this.scrollContainer().nativeElement.scrollTop = 0;
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
toggleSort(field) {
|
|
4329
|
+
if (this.sortField() !== field) {
|
|
4330
|
+
this.sortField.set(field);
|
|
4331
|
+
this.sortDir.set('asc');
|
|
4332
|
+
}
|
|
4333
|
+
else {
|
|
4334
|
+
if (this.sortDir() === 'asc') {
|
|
4335
|
+
this.sortDir.set('desc');
|
|
4336
|
+
}
|
|
4337
|
+
else if (this.sortDir() === 'desc') {
|
|
4338
|
+
this.sortDir.set('none');
|
|
4339
|
+
this.sortField.set(null);
|
|
4340
|
+
}
|
|
4341
|
+
else {
|
|
4342
|
+
this.sortDir.set('asc');
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4346
|
+
// ── COLUMNAS FIJADAS (PINNED) ─────────────────────────────────────────────────
|
|
4347
|
+
/** Ancho por defecto de una columna fijada que no define width (el offset necesita ancho fijo) */
|
|
4348
|
+
PINNED_DEFAULT_WIDTH = 120;
|
|
4349
|
+
/** Anchos fijos de las columnas utilitarias cuando participan del pinning izquierdo */
|
|
4350
|
+
UTIL_W = { details: 36, checkbox: 36, actions: 44 };
|
|
4351
|
+
/** Posición horizontal del scroll (para las sombras de las columnas fijadas) */
|
|
4352
|
+
scrollLeft = signal(0);
|
|
4353
|
+
maxScrollLeft = signal(0);
|
|
4354
|
+
syncScrollX(el) {
|
|
4355
|
+
this.scrollLeft.set(el.scrollLeft);
|
|
4356
|
+
this.maxScrollLeft.set(el.scrollWidth - el.clientWidth);
|
|
4357
|
+
}
|
|
4358
|
+
/** Lado al que se fija una columna. `pinned: true` = derecha (default) */
|
|
4359
|
+
pinnedSide(col) {
|
|
4360
|
+
if (!col?.pinned)
|
|
4361
|
+
return null;
|
|
4362
|
+
return col.pinned === 'left' ? 'left' : 'right';
|
|
4363
|
+
}
|
|
4364
|
+
pinnedWidth(col) {
|
|
4365
|
+
return col.width || this.PINNED_DEFAULT_WIDTH;
|
|
4366
|
+
}
|
|
4367
|
+
hasLeftPinned = computed(() => this.columnasRenderizadas().some(c => this.pinnedSide(c) === 'left'));
|
|
4368
|
+
hasRightPinned = computed(() => this.columnasRenderizadas().some(c => this.pinnedSide(c) === 'right'));
|
|
4369
|
+
/** Ancho total de las columnas utilitarias fijadas (base del offset de las pinned left) */
|
|
4370
|
+
utilCheckboxLeft = computed(() => this.withDetails() ? this.UTIL_W.details : 0);
|
|
4371
|
+
utilActionsLeft = computed(() => this.utilCheckboxLeft() + (this.withCheckbox() ? this.UTIL_W.checkbox : 0));
|
|
4372
|
+
utilTotalWidth = computed(() => this.utilActionsLeft() + (this.customActions() ? this.UTIL_W.actions : 0));
|
|
4373
|
+
/** Mapa fieldname → PinInfo con los offsets acumulados de cada columna fijada */
|
|
4374
|
+
pinInfo = computed(() => {
|
|
4375
|
+
const map = new Map();
|
|
4376
|
+
const cols = this.columnasRenderizadas();
|
|
4377
|
+
const lefts = cols.filter(c => this.pinnedSide(c) === 'left');
|
|
4378
|
+
const rights = cols.filter(c => this.pinnedSide(c) === 'right');
|
|
4379
|
+
let accLeft = lefts.length > 0 ? this.utilTotalWidth() : 0;
|
|
4380
|
+
lefts.forEach((col, i) => {
|
|
4381
|
+
map.set(col.fieldname, {
|
|
4382
|
+
side: 'left',
|
|
4383
|
+
left: accLeft,
|
|
4384
|
+
right: null,
|
|
4385
|
+
edge: i === lefts.length - 1,
|
|
4386
|
+
width: this.pinnedWidth(col)
|
|
4387
|
+
});
|
|
4388
|
+
accLeft += this.pinnedWidth(col);
|
|
4389
|
+
});
|
|
4390
|
+
let accRight = 0;
|
|
4391
|
+
[...rights].reverse().forEach((col, i) => {
|
|
4392
|
+
map.set(col.fieldname, {
|
|
4393
|
+
side: 'right',
|
|
4394
|
+
left: null,
|
|
4395
|
+
right: accRight,
|
|
4396
|
+
edge: i === rights.length - 1, // la última iterada es la primera visualmente (borde interno)
|
|
4397
|
+
width: this.pinnedWidth(col)
|
|
4398
|
+
});
|
|
4399
|
+
accRight += this.pinnedWidth(col);
|
|
4400
|
+
});
|
|
4401
|
+
return map;
|
|
4402
|
+
});
|
|
4403
|
+
/** PinInfo de una columna, o undefined si no está fijada */
|
|
4404
|
+
pin(col) {
|
|
4405
|
+
return this.pinInfo().get(col.fieldname);
|
|
4406
|
+
}
|
|
4407
|
+
/** Ancho a forzar en la celda: el declarado, o el default si está fijada */
|
|
4408
|
+
colWidth(col) {
|
|
4409
|
+
const p = this.pin(col);
|
|
4410
|
+
if (p)
|
|
4411
|
+
return p.width;
|
|
4412
|
+
return col.width || null;
|
|
4413
|
+
}
|
|
4414
|
+
/** Sombra izquierda: hay columnas fijadas left y se scrolleó */
|
|
4415
|
+
hasShadowLeft = computed(() => this.hasLeftPinned() && this.scrollLeft() > 0);
|
|
4416
|
+
/** Sombra derecha: hay columnas fijadas right y queda contenido oculto a la derecha */
|
|
4417
|
+
hasShadowRight = computed(() => this.hasRightPinned() && this.scrollLeft() < this.maxScrollLeft() - 1);
|
|
4418
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
4419
|
+
concatenarValue(obj, fields) {
|
|
4420
|
+
return fields.reduce((acc, f) => acc + (obj[f] ?? ''), '');
|
|
4421
|
+
}
|
|
4422
|
+
getHighlight(text, fieldname) {
|
|
4423
|
+
if (text == null)
|
|
4424
|
+
text = '';
|
|
4425
|
+
if (!this.filtrarColumnas()[fieldname] || !this.busqueda())
|
|
4426
|
+
return text;
|
|
4427
|
+
if (typeof text !== 'string') {
|
|
4428
|
+
text = text.toString();
|
|
4429
|
+
}
|
|
4430
|
+
const regex = new RegExp(`(${this.busqueda()})`, 'gi');
|
|
4431
|
+
return text?.replace(regex, '<mark>$1</mark>');
|
|
4432
|
+
}
|
|
4433
|
+
filtraItem(item, term) {
|
|
4434
|
+
const columnasActivas = Object.entries(this.filtrarColumnas())
|
|
4435
|
+
.filter(([_campo, activo]) => activo);
|
|
4436
|
+
return columnasActivas.some(([campo]) => {
|
|
4437
|
+
const raw = item[campo];
|
|
4438
|
+
const formatted = item._format?.[campo];
|
|
4439
|
+
const valor = (formatted ?? raw ?? '').toString().toLowerCase();
|
|
4440
|
+
return valor.includes(term);
|
|
4441
|
+
});
|
|
4442
|
+
}
|
|
4443
|
+
scrollToSelected(selected) {
|
|
4444
|
+
const rows = this.rowFilter();
|
|
4445
|
+
const idx = this.identifier().length < 1
|
|
4446
|
+
? (typeof selected === 'number' ? selected : -1)
|
|
4447
|
+
: rows.findIndex(r => this.concatenarValue(r, this.identifier()) === selected);
|
|
4448
|
+
if (idx < 0 || !this.scrollContainer()?.nativeElement)
|
|
4449
|
+
return;
|
|
4450
|
+
const targetTop = idx * this.rowH();
|
|
4451
|
+
const container = this.scrollContainer().nativeElement;
|
|
4452
|
+
const containerH = this.containerHeight();
|
|
4453
|
+
if (targetTop < container.scrollTop || targetTop + this.rowH() > container.scrollTop + containerH) {
|
|
4454
|
+
container.scrollTop = targetTop - containerH / 2;
|
|
4455
|
+
}
|
|
4456
|
+
}
|
|
4457
|
+
/** Índice real en rowFilter de una fila visible (para isSelected) */
|
|
4458
|
+
realIndex(visibleIdx) {
|
|
4459
|
+
return this.startIndex() + visibleIdx;
|
|
4460
|
+
}
|
|
4461
|
+
/** Mostrar columnas para realizar el filtro */
|
|
4462
|
+
filtrarColumnas = computed(() => {
|
|
4463
|
+
const columns = this.columns();
|
|
4464
|
+
const filtro = {};
|
|
4465
|
+
columns.forEach((col) => {
|
|
4466
|
+
if (col.fieldname) {
|
|
4467
|
+
filtro[col.fieldname] = true;
|
|
4468
|
+
}
|
|
4469
|
+
});
|
|
4470
|
+
return filtro;
|
|
4471
|
+
});
|
|
4472
|
+
toggleFiltros(event) {
|
|
4473
|
+
const checked = event.target.checked;
|
|
4474
|
+
const filtros = this.filtrarColumnas();
|
|
4475
|
+
Object.keys(filtros).forEach(key => {
|
|
4476
|
+
filtros[key] = checked;
|
|
4477
|
+
});
|
|
4478
|
+
}
|
|
4479
|
+
/** MOSTRAR/ORDENAR COLUMNAS DE LA TABLA (engranaje del header) */
|
|
4480
|
+
/** orden y visibilidad elegidos por el usuario, por fieldname — sembrado siempre desde columns() */
|
|
4481
|
+
columnState = signal(new Map());
|
|
4482
|
+
/** Reconstruye el estado cada vez que cambia columns() (columns() es la única fuente de verdad) */
|
|
4483
|
+
columnStateEffect = effect(() => {
|
|
4484
|
+
const cols = this.columns();
|
|
4485
|
+
untracked(() => this.columnState.set(this.buildColumnState(cols)));
|
|
4486
|
+
});
|
|
4487
|
+
buildColumnState(cols) {
|
|
4488
|
+
const map = new Map();
|
|
4489
|
+
cols.forEach((col, i) => {
|
|
4490
|
+
map.set(col.fieldname, {
|
|
4491
|
+
visible: this.validaVisibilidad(col.visible),
|
|
4492
|
+
order: col.order ?? i
|
|
4493
|
+
});
|
|
4494
|
+
});
|
|
4495
|
+
return map;
|
|
4496
|
+
}
|
|
4497
|
+
/** Columnas configurables (permitidas por diseño), en el orden elegido por el usuario.
|
|
4498
|
+
* El caption es solo presentación: sin caption la columna igual se configura y renderiza (identidad = fieldname). */
|
|
4499
|
+
columnasConfigurables = computed(() => {
|
|
4500
|
+
const state = this.columnState();
|
|
4501
|
+
return this.columns()
|
|
4502
|
+
.filter(col => this.validaVisibilidad(col.visible))
|
|
4503
|
+
.slice()
|
|
4504
|
+
.sort((a, b) => (state.get(a.fieldname)?.order ?? 0) - (state.get(b.fieldname)?.order ?? 0));
|
|
4505
|
+
});
|
|
4506
|
+
/** Columnas que realmente se pintan: configurables y marcadas como visibles.
|
|
4507
|
+
* Las fijadas se reordenan: left al inicio, right al final (una pinned en medio no tiene sentido visual). */
|
|
4508
|
+
columnasRenderizadas = computed(() => {
|
|
4509
|
+
const state = this.columnState();
|
|
4510
|
+
const visibles = this.columnasConfigurables().filter(col => state.get(col.fieldname)?.visible !== false);
|
|
4511
|
+
const left = visibles.filter(c => this.pinnedSide(c) === 'left');
|
|
4512
|
+
const middle = visibles.filter(c => this.pinnedSide(c) === null);
|
|
4513
|
+
const right = visibles.filter(c => this.pinnedSide(c) === 'right');
|
|
4514
|
+
return [...left, ...middle, ...right];
|
|
4515
|
+
});
|
|
4516
|
+
isColumnVisible(fieldname) {
|
|
4517
|
+
return this.columnState().get(fieldname)?.visible !== false;
|
|
4518
|
+
}
|
|
4519
|
+
toggleColumnVisible(fieldname, event) {
|
|
4520
|
+
const checked = event.target.checked;
|
|
4521
|
+
this.columnState.update(map => {
|
|
4522
|
+
const next = new Map(map);
|
|
4523
|
+
const prev = next.get(fieldname);
|
|
4524
|
+
next.set(fieldname, { visible: checked, order: prev?.order ?? 0 });
|
|
4525
|
+
return next;
|
|
4526
|
+
});
|
|
4527
|
+
}
|
|
4528
|
+
onColumnDrop(event) {
|
|
4529
|
+
const list = [...this.columnasConfigurables()];
|
|
4530
|
+
moveItemInArray(list, event.previousIndex, event.currentIndex);
|
|
4531
|
+
this.columnState.update(map => {
|
|
4532
|
+
const next = new Map(map);
|
|
4533
|
+
list.forEach((col, i) => {
|
|
4534
|
+
const prev = next.get(col.fieldname);
|
|
4535
|
+
next.set(col.fieldname, { visible: prev?.visible ?? true, order: i });
|
|
4536
|
+
});
|
|
4537
|
+
return next;
|
|
4538
|
+
});
|
|
4539
|
+
}
|
|
4540
|
+
guardarConfiguracionColumnas() {
|
|
4541
|
+
const state = this.columnState();
|
|
4542
|
+
const config = this.columnasConfigurables().map(col => ({
|
|
4543
|
+
fieldname: col.fieldname,
|
|
4544
|
+
visible: state.get(col.fieldname)?.visible !== false,
|
|
4545
|
+
order: state.get(col.fieldname)?.order ?? 0
|
|
4546
|
+
}));
|
|
4547
|
+
this.rowEvent.emit({ usecase: TABLE_EVENTS.SAVE_COLUMN_CONFIG, data: config });
|
|
4548
|
+
}
|
|
4549
|
+
/** Descarta los cambios sin guardar (drags/toggles) y vuelve al orden/visibilidad de columns() */
|
|
4550
|
+
restablecerConfiguracionColumnas() {
|
|
4551
|
+
this.columnState.set(this.buildColumnState(this.columns()));
|
|
4552
|
+
}
|
|
4553
|
+
validaVisibilidad(value) {
|
|
4554
|
+
return validarBoolean(value);
|
|
4555
|
+
}
|
|
4556
|
+
/** CELL RENDER */
|
|
4557
|
+
resolveCell(col, row) {
|
|
4558
|
+
const value = row[col];
|
|
4559
|
+
const r = this.rendered().find(r => r.matches(col, value, row));
|
|
4560
|
+
return r ? r.render(value, row) : null;
|
|
4561
|
+
}
|
|
4562
|
+
getRowClass(row) {
|
|
4563
|
+
return {
|
|
4564
|
+
'text-error': row.situac == 'J',
|
|
4565
|
+
'text-alerta': row.situac == 'L'
|
|
4566
|
+
};
|
|
4567
|
+
}
|
|
4568
|
+
getPosition(col) {
|
|
4569
|
+
if (col.position)
|
|
4570
|
+
return `text-${col.position}`;
|
|
4571
|
+
if (['decimal', 'number'].includes(col.tipo))
|
|
4572
|
+
return `text-end`;
|
|
4573
|
+
if (['fecha', 'date'].includes(col.tipo))
|
|
4574
|
+
return `text-center`;
|
|
4575
|
+
return 'text-start';
|
|
4576
|
+
}
|
|
4577
|
+
//** WITH DETAILS - EXPANDED ROW */
|
|
4578
|
+
toggleExpandRow(idRow) {
|
|
4579
|
+
const value = this.expandedRows() == idRow ? null : idRow;
|
|
4580
|
+
this.expandedRows.set(value);
|
|
4581
|
+
}
|
|
4582
|
+
//** WITH TOTAL - FOOTER DE TOTALES */
|
|
4583
|
+
getTotals(fieldname) {
|
|
4584
|
+
const itemsSelected = this.withCheckbox() ? this.selectItems().map(item => item.data) : this.rowFormat();
|
|
4585
|
+
const final = itemsSelected.reduce((acc, row) => {
|
|
4586
|
+
const val = row[fieldname];
|
|
4587
|
+
return acc + (typeof val == 'number' ? val : 0);
|
|
4588
|
+
}, 0);
|
|
4589
|
+
return formatDecimal(final);
|
|
4590
|
+
}
|
|
4591
|
+
getColspanBeforeTotals() {
|
|
4592
|
+
const columns = this.columnasRenderizadas();
|
|
4593
|
+
const firstTotalizableIndex = columns.findIndex(c => c.totalizable);
|
|
4594
|
+
const result = firstTotalizableIndex >= 0 ? firstTotalizableIndex : columns.length;
|
|
4595
|
+
const addColumns = (this.withDetails() ? 1 : 0) + (this.withCheckbox() ? 1 : 0) + (this.customActions() ? 1 : 0);
|
|
4596
|
+
return result + addColumns;
|
|
4597
|
+
}
|
|
4598
|
+
//** WITHCHECKBOX LOGICA */
|
|
4599
|
+
allCheck(event) {
|
|
4600
|
+
const input = event.target;
|
|
4601
|
+
const checked = input.checked;
|
|
4602
|
+
this.rowEvent.emit({ usecase: TABLE_EVENTS.CHECK_ALL, data: checked });
|
|
4603
|
+
this.checkAll(checked);
|
|
4604
|
+
}
|
|
4605
|
+
isCheckboxDisabled(row) {
|
|
4606
|
+
return this.rowDisabledFn?.()?.(row) ?? false;
|
|
4607
|
+
}
|
|
4608
|
+
checkAll(checked) {
|
|
4609
|
+
if (checked) {
|
|
4610
|
+
const total = this.rowFilter()
|
|
4611
|
+
.filter(r => !this.isCheckboxDisabled(r))
|
|
4612
|
+
.map(r => ({ id: r.idListTsi, data: r }));
|
|
4613
|
+
this.selectItems.set(total);
|
|
4614
|
+
}
|
|
4615
|
+
else {
|
|
4616
|
+
this.selectItems.set([]);
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4619
|
+
validaAllCheck() {
|
|
4620
|
+
const selectable = this.rowFilter().filter(r => !this.isCheckboxDisabled(r));
|
|
4621
|
+
const selectedIds = new Set(this.selectItems().map(s => s.id));
|
|
4622
|
+
return selectable.length > 0 && selectable.every(row => selectedIds.has(row.idListTsi));
|
|
4623
|
+
}
|
|
4624
|
+
isItemSelected(id) {
|
|
4625
|
+
return this.selectItems().some(item => item.id == id);
|
|
4626
|
+
}
|
|
4627
|
+
toogleItem(idList, event) {
|
|
4628
|
+
const row = this.rowFormat().find(r => r.idListTsi == idList);
|
|
4629
|
+
if (!row || this.isCheckboxDisabled(row)) {
|
|
4630
|
+
return;
|
|
4631
|
+
}
|
|
4632
|
+
const input = event.target;
|
|
4633
|
+
const checked = input.checked;
|
|
4634
|
+
this.rowEvent.emit({ usecase: TABLE_EVENTS.CHECK_ROW, data: { row, checked } });
|
|
4635
|
+
if (checked) {
|
|
4636
|
+
const item = { id: idList, data: row };
|
|
4637
|
+
this.selectItems.update(sel => [...sel, item]);
|
|
4638
|
+
return;
|
|
4639
|
+
}
|
|
4640
|
+
this.selectItems.update(sel => sel.filter(s => s.id != idList));
|
|
4641
|
+
}
|
|
4642
|
+
/* EVENTOS DE LA FILA */
|
|
4643
|
+
onDoubleClick(row) {
|
|
4644
|
+
if (window.getSelection()?.type === 'Range')
|
|
4645
|
+
return;
|
|
4646
|
+
this.rowEvent.emit({ usecase: TABLE_EVENTS.DOUBLE_CLICK, data: row });
|
|
4647
|
+
}
|
|
4648
|
+
onRightClick(event, row) {
|
|
4649
|
+
event.preventDefault();
|
|
4650
|
+
this.rowEvent.emit({ usecase: TABLE_EVENTS.RIGHT_CLICK, data: row });
|
|
4651
|
+
}
|
|
4652
|
+
/* MOBILE MODE */
|
|
4653
|
+
onResize(event) {
|
|
4654
|
+
if (!this.activeMobileMode())
|
|
4655
|
+
return;
|
|
4656
|
+
this.isMobile.set(event.target.innerWidth <= 768);
|
|
4657
|
+
}
|
|
4658
|
+
mobileEffect = effect(() => {
|
|
4659
|
+
if (!this.activeMobileMode())
|
|
4660
|
+
return;
|
|
4661
|
+
this.isMobile();
|
|
4662
|
+
this.isLoadingResponsive.set(true);
|
|
4663
|
+
setTimeout(() => this.isLoadingResponsive.set(false), 200);
|
|
4664
|
+
});
|
|
4665
|
+
// DRAG AND DROP ADJUNTOS
|
|
4666
|
+
onDragOver(event, idList) {
|
|
4667
|
+
event.preventDefault();
|
|
4668
|
+
event.stopPropagation();
|
|
4669
|
+
this.dragOverRowId.set(idList);
|
|
4670
|
+
}
|
|
4671
|
+
onDragLeave() {
|
|
4672
|
+
this.dragOverRowId.set(null);
|
|
4673
|
+
}
|
|
4674
|
+
onDrop(event, row) {
|
|
4675
|
+
event.preventDefault();
|
|
4676
|
+
event.stopPropagation();
|
|
4677
|
+
this.dragOverRowId.set(null);
|
|
4678
|
+
const file = event.dataTransfer?.files?.[0];
|
|
4679
|
+
if (file) {
|
|
4680
|
+
this.rowEvent.emit({ usecase: TABLE_EVENTS.DRAG_DROP, data: { file, row } });
|
|
4681
|
+
}
|
|
4682
|
+
}
|
|
4683
|
+
getRows = () => this.rowFormat().map(({ idListTsi, format, ...rest }) => rest);
|
|
4684
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TableUltimatePinnedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4685
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: TableUltimatePinnedComponent, isStandalone: true, selector: "app-table-ultimate-pinned", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, footerRows: { classPropertyName: "footerRows", publicName: "footerRows", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, buffer: { classPropertyName: "buffer", publicName: "buffer", isSignal: true, isRequired: false, transformFunction: null }, altoContainer: { classPropertyName: "altoContainer", publicName: "altoContainer", isSignal: true, isRequired: false, transformFunction: null }, altoContenedor: { classPropertyName: "altoContenedor", publicName: "altoContenedor", isSignal: true, isRequired: false, transformFunction: null }, minAlto: { classPropertyName: "minAlto", publicName: "minAlto", isSignal: true, isRequired: false, transformFunction: null }, identifier: { classPropertyName: "identifier", publicName: "identifier", isSignal: true, isRequired: false, transformFunction: null }, withFiltro: { classPropertyName: "withFiltro", publicName: "withFiltro", isSignal: true, isRequired: false, transformFunction: null }, withDetails: { classPropertyName: "withDetails", publicName: "withDetails", isSignal: true, isRequired: false, transformFunction: null }, withCheckbox: { classPropertyName: "withCheckbox", publicName: "withCheckbox", isSignal: true, isRequired: false, transformFunction: null }, withTotal: { classPropertyName: "withTotal", publicName: "withTotal", isSignal: true, isRequired: false, transformFunction: null }, withHeight: { classPropertyName: "withHeight", publicName: "withHeight", isSignal: true, isRequired: false, transformFunction: null }, withAttachment: { classPropertyName: "withAttachment", publicName: "withAttachment", isSignal: true, isRequired: false, transformFunction: null }, variante: { classPropertyName: "variante", publicName: "variante", isSignal: true, isRequired: false, transformFunction: null }, rendered: { classPropertyName: "rendered", publicName: "rendered", isSignal: true, isRequired: false, transformFunction: null }, titleTabla: { classPropertyName: "titleTabla", publicName: "titleTabla", isSignal: true, isRequired: false, transformFunction: null }, activeMobileMode: { classPropertyName: "activeMobileMode", publicName: "activeMobileMode", isSignal: true, isRequired: false, transformFunction: null }, selectedRow: { classPropertyName: "selectedRow", publicName: "selectedRow", isSignal: true, isRequired: false, transformFunction: null }, rowClassFn: { classPropertyName: "rowClassFn", publicName: "rowClassFn", isSignal: true, isRequired: false, transformFunction: null }, rowDisabledFn: { classPropertyName: "rowDisabledFn", publicName: "rowDisabledFn", isSignal: true, isRequired: false, transformFunction: null }, selectItems: { classPropertyName: "selectItems", publicName: "selectItems", isSignal: true, isRequired: false, transformFunction: null }, busqueda: { classPropertyName: "busqueda", publicName: "busqueda", isSignal: true, isRequired: false, transformFunction: null }, classTotales: { classPropertyName: "classTotales", publicName: "classTotales", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowEvent: "rowEvent", selectedRow: "selectedRowChange", selectItems: "selectItemsChange", busqueda: "busquedaChange" }, host: { listeners: { "window:resize": "onResize($event)" }, properties: { "class.ll-variant--modern": "variante() === \"modern\"" } }, queries: [{ propertyName: "customActions", first: true, predicate: ["customActions"], descendants: true, isSignal: true }, { propertyName: "columnDefs", predicate: TsiColumnDefDirective, isSignal: true }, { propertyName: "contentFilter", first: true, predicate: ["header"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (withFiltro()) {\n<div class=\"ll-search-bar\">\n\n <div class=\"ll-search-bar__left\">\n <ng-container *ngTemplateOutlet=\"contentFilter();\"></ng-container>\n </div>\n\n <div class=\"ll-search-bar__right\">\n\n <div class=\"ll-search-group\">\n\n <label class=\"form-label mb-0 ll-search-label\">Buscar:</label>\n <div class=\"ll-search-input-wrap\">\n\n <input type=\"text\" class=\"form-control cw-250\" placeholder=\"Buscar...\" [(ngModel)]=\"busqueda\" (input)=\"textoDigitado()\" />\n <app-dropdown-cdk [altoContainer]=\"300\">\n <ng-template #trigger>\n <button class=\"btn btn-dark boton-buscar fs-7\">\n <i class=\"fas fa-cog\"></i>\n </button>\n </ng-template>\n\n <ng-template #content>\n <div class=\"popover-menu-filter bg-white shadow my-2\" @fadeInOut>\n <div class=\"popover-title fs-7 bg-white\">\n Filtros\n </div>\n\n <div class=\"form-check form-switch text-start d-flex align-items-center\">\n <input class=\"form-check-input py-0 my-0 cw-25 ch-15\" type=\"checkbox\" [checked]=\"true\"\n (change)=\"toggleFiltros($event)\" id=\"filter_table_pinned_todos\" />\n <label class=\"form-check-label ps-2 fs-6 mb-0 cursor-pointer\"\n for=\"filter_table_pinned_todos\">\n Todos\n </label>\n </div>\n\n @for (col of columns(); track col.fieldname) {\n <div class=\"form-check form-switch text-start d-flex align-items-center\">\n <input type=\"checkbox\" class=\"form-check-input py-0 my-0 cw-25 ch-15\"\n id=\"{{ 'filter_pinned_' + col.fieldname }}\" [(ngModel)]=\"filtrarColumnas()[col.fieldname]\" />\n <label class=\"form-check-label ps-2 fs-6 cursor-pointer mb-0\"\n for=\"{{ 'filter_pinned_' + col.fieldname }}\">\n {{ col.caption || col.fieldname }}\n </label>\n </div>\n }\n </div>\n </ng-template>\n </app-dropdown-cdk>\n\n </div>\n\n </div>\n\n\n </div>\n\n\n</div>\n}\n\n@if (activeMobileMode()) {\n@if (isLoadingResponsive()) {\n<div class=\"d-flex flex-column justify-content-center align-items-center py-2\">\n <div class=\"spinner-border text-secondary mb-2\" role=\"status\"></div>\n <span class=\"ms-2 fs-6\">Cargando...</span>\n</div>\n}\n\n@if (!isLoadingResponsive()) {\n@if (isMobile()) {\n<app-card-mobile [data]=\"rowFilter()\" [columns]=\"columns()\" [actions]=\"customActions()\" [identifier]=\"identifier()\"\n [titleTabla]=\"titleTabla()\" [altoContainer]=\"altoContainer()\" />\n}\n@if (!isMobile()) {\n<ng-container *ngTemplateOutlet=\"table\"></ng-container>\n}\n}\n}\n@else {\n<ng-container *ngTemplateOutlet=\"table\"></ng-container>\n}\n\n<ng-template #table>\n <!-- Contenedor scrolleable \u2014 solo el BODY hace scroll; header y footer son sticky.\n Las clases ll-scrolled-* activan las sombras de las columnas fijadas. -->\n <div #scrollContainer class=\"ll-scroll-container\"\n [class.ll-scrolled-start]=\"hasShadowLeft()\"\n [class.ll-scrolled-end]=\"hasShadowRight()\"\n [style.height]=\"withHeight() ? heightStyle() : ''\"\n [style.max-height]=\"heightStyle()\" (scroll)=\"onScroll($event)\">\n <table class=\"ll-table\">\n\n <!-- \u2500\u2500 HEADER sticky \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <thead class=\"ll-thead\">\n <tr>\n @if (withDetails()) {\n <th class=\"cw-25\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? 0 : null\"\n [style.width.px]=\"hasLeftPinned() ? UTIL_W.details : null\"\n [style.min-width.px]=\"hasLeftPinned() ? UTIL_W.details : null\"\n [style.max-width.px]=\"hasLeftPinned() ? UTIL_W.details : null\"></th>\n }\n\n @if (withCheckbox()) {\n <th class=\"cw-20\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? utilCheckboxLeft() : null\"\n [style.width.px]=\"hasLeftPinned() ? UTIL_W.checkbox : null\"\n [style.min-width.px]=\"hasLeftPinned() ? UTIL_W.checkbox : null\"\n [style.max-width.px]=\"hasLeftPinned() ? UTIL_W.checkbox : null\">\n <label>\n <input type=\"checkbox\" name=\"check_box_select_table_pinned_main\" id=\"check_box_select_table_pinned_main\"\n animatedCheckbox [checked]=\"validaAllCheck()\" (change)=\"allCheck($event)\">\n </label>\n </th>\n }\n\n @if (customActions()) {\n <th class=\"cw-40\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? utilActionsLeft() : null\"\n [style.width.px]=\"hasLeftPinned() ? UTIL_W.actions : null\"\n [style.min-width.px]=\"hasLeftPinned() ? UTIL_W.actions : null\"\n [style.max-width.px]=\"hasLeftPinned() ? UTIL_W.actions : null\">\n <app-dropdown-cdk [altoContainer]=\"500\">\n <ng-template #trigger>\n <button class=\"btn p-0 text-dark d-flex mx-auto border-0 icon-table\">\n <i class=\"fas fa-cog\"></i>\n </button>\n </ng-template>\n <ng-template #content>\n <div class=\"popover-menu-column bg-white shadow my-2\" @fadeInOut>\n <div class=\"popover-title fs-7 bg-white d-flex align-items-baseline justify-content-between\">\n <span>Columnas</span>\n <span class=\"column-config-hint\">arrastra para ordenar</span>\n </div>\n\n <div cdkDropList class=\"column-config-list\" (cdkDropListDropped)=\"onColumnDrop($event)\">\n @for (col of columnasConfigurables(); track col.fieldname) {\n <div class=\"column-config-row\" cdkDrag>\n <i class=\"fas fa-grip-vertical column-config-grip\" cdkDragHandle></i>\n <div class=\"form-check form-switch text-start d-flex align-items-center mb-0 flex-grow-1\">\n <input type=\"checkbox\" class=\"form-check-input py-0 my-0 cw-25 ch-15\"\n id=\"{{ 'switch_pinned_' + col.fieldname }}\"\n [checked]=\"isColumnVisible(col.fieldname)\"\n (change)=\"toggleColumnVisible(col.fieldname, $event)\" />\n <label class=\"form-check-label ps-2 fs-6 cursor-pointer font-label mb-0\"\n for=\"{{ 'switch_pinned_' + col.fieldname }}\">\n {{ col.caption || col.fieldname }}\n </label>\n </div>\n @if (pinnedSide(col)) {\n <i class=\"fas fa-thumbtack column-config-pin\" title=\"Columna fijada\"></i>\n }\n </div>\n }\n </div>\n\n <div class=\"column-config-footer\">\n <button type=\"button\" class=\"btn btn-sm fs-7 column-config-save\"\n (click)=\"guardarConfiguracionColumnas()\">\n Guardar configuraci\u00F3n\n </button>\n </div>\n </div>\n </ng-template>\n </app-dropdown-cdk>\n </th>\n }\n\n @for (col of columnasRenderizadas(); track col.fieldname) {\n <th [title]=\"col.caption\" [style.width.px]=\"colWidth(col)\"\n [style.min-width.px]=\"colWidth(col)\" [style.max-width.px]=\"colWidth(col)\"\n [class.ll-th-sortable]=\"col.caption\"\n [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\"\n (click)=\"col.caption && toggleSort(col.fieldname)\">\n <span class=\"ll-th-content\">\n <span class=\"ll-th-caption\">{{ col.caption }}</span>\n @if (col.caption) {\n @if (sortField() === col.fieldname) {\n <i class=\"ms-1\"\n [ngClass]=\"sortDir() === 'asc' ? 'fas fa-angle-up fs-6':'fas fa-angle-down fs-6'\"></i>\n } @else {\n <i class=\"fas fa-sort ms-1 ll-sort-idle\"></i>\n }\n }\n </span>\n </th>\n }\n </tr>\n </thead>\n\n <!-- \u2500\u2500 BODY virtual \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <tbody>\n <!-- Spacer superior: ocupa el espacio de las filas NO renderizadas arriba -->\n @if (paddingTop() > 0) {\n <tr class=\"ll-spacer\" [style.height.px]=\"paddingTop()\">\n <td [attr.colspan]=\"columnasRenderizadas().length\"></td>\n </tr>\n }\n\n <!-- Filas visibles -->\n @for (row of visibleRows(); track row.idListTsi) {\n @let idList = row.idListTsi;\n <tr class=\"ll-row\" [class.ll-row--selected]=\"isSelected(row, idList)\"\n [class.ll-row--drag-over]=\"withAttachment() && dragOverRowId() === idList\"\n (click)=\"selectRow(row, idList)\" (dblclick)=\"onDoubleClick(row)\"\n (contextmenu)=\"onRightClick($event,row)\"\n (dragover)=\"withAttachment() && onDragOver($event, idList)\"\n (dragleave)=\"withAttachment() && onDragLeave()\" (drop)=\"withAttachment() && onDrop($event, row)\">\n\n @if (withDetails()) {\n <td class=\"b-table text-center mwp-25\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? 0 : null\">\n <a (click)=\"toggleExpandRow(idList)\" class=\"text-dark cursor-pointer fs-6\">\n <i class=\"fa-solid\" [class.fa-chevron-right]=\"expandedRows() != idList\"\n [class.fa-chevron-down]=\"expandedRows() == idList\"></i>\n </a>\n </td>\n }\n\n @if (withCheckbox()) {\n <td scope=\"col\" class=\"text-center b-table\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? utilCheckboxLeft() : null\">\n <label>\n <input type=\"checkbox\" [name]=\"'check_box_select_table_pinned_' + idList\"\n [id]=\"'check_box_select_table_pinned_' + idList\" animatedCheckbox\n [checked]=\"isItemSelected(idList)\" (click)=\"$event.stopPropagation()\"\n (change)=\"toogleItem(idList , $event)\" [disabled]=\"isCheckboxDisabled(row)\">\n </label>\n </td>\n }\n\n @if (customActions()) {\n <td class=\"text-center\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? utilActionsLeft() : null\">\n <ng-container *ngTemplateOutlet=\"customActions(); context: { $implicit: row }\"></ng-container>\n </td>\n }\n\n @for (col of columnasRenderizadas(); track col.fieldname) {\n @if (columnDefMap().has(col.fieldname)) {\n <td [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\"\n [style.min-width.px]=\"pin(col) ? colWidth(col) : null\"\n [style.max-width.px]=\"pin(col) ? colWidth(col) : null\">\n <ng-container *ngTemplateOutlet=\"columnDefMap().get(col.fieldname)!; context: { $implicit: row, column: col }\">\n </ng-container>\n </td>\n } @else if (col.template) {\n <td [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\"\n [style.min-width.px]=\"pin(col) ? colWidth(col) : null\"\n [style.max-width.px]=\"pin(col) ? colWidth(col) : null\">\n <ng-container *ngTemplateOutlet=\"col.template; context: { $implicit: row, column: col }\">\n </ng-container>\n </td>\n } @else {\n @switch (col.tipo) {\n\n @case ('cell-render') {\n @let resolverItem = resolveCell(col.fieldname, row);\n @if (resolverItem) {\n <td [title]=\"resolverItem.text\" [class.text-center]=\"resolverItem.icon\"\n [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\"\n [style.min-width.px]=\"pin(col) ? colWidth(col) : null\"\n [style.max-width.px]=\"pin(col) ? colWidth(col) : null\">\n @if (resolverItem.icon) {\n <i class=\"fs-5\" [ngClass]=\"resolverItem.icon\"></i>\n } @else if (resolverItem.class) {\n <span [ngClass]=\"row.situac == 'J' ? 'text-error' : resolverItem.class\">\n {{ resolverItem.text }}\n </span>\n } @else {\n {{ resolverItem.text }}\n }\n </td>\n }\n }\n\n @default {\n <td [innerHTML]=\"getHighlight(row._format?.[col.fieldname] ?? row[col.fieldname], col.fieldname)\"\n [style.width.px]=\"colWidth(col)\"\n [style.min-width.px]=\"pin(col) ? colWidth(col) : null\"\n [style.max-width.px]=\"colWidth(col)\"\n [attr.title]=\"row[col.fieldname] || null\"\n [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\"\n [ngClass]=\"rowClassFn() ? rowClassFn()(row) : getRowClass(row)\" class=\"{{getPosition(col)}}\">\n </td>\n }\n\n }\n }\n }\n </tr>\n\n @if (idList == expandedRows()) {\n <tr @fadeInOut>\n <td [attr.colspan]=\"columnasRenderizadas().length + (withDetails() ? 1 : 0) + (customActions() ? 1 : 0) + (withCheckbox() ? 1 : 0)\"\n class=\"table-blank\">\n <div class=\"d-flex flex-column auditoria\">\n <span class=\"fw-bold fs-7 text-dark\">Datos de auditor\u00EDa</span>\n <span class=\"fs-6 text-dark fw-bold\">\n Creaci\u00F3n: {{ row.nomucreac }} el {{ row._format?.fcreac ?? row.fcreac }} a las {{\n row.hcreac }}\n </span>\n <span class=\"fs-6 text-dark fw-bold\">\n Actualizaci\u00F3n: {{ row.nomuactua }} el {{ row._format?.factua ?? row.factua }} a las\n {{\n row.hactua }}\n </span>\n </div>\n </td>\n </tr>\n }\n\n }\n\n <!-- Fila vac\u00EDa si no hay datos -->\n @if (rowFilter().length === 0) {\n <tr>\n <td [attr.colspan]=\"columnasRenderizadas().length\" class=\"ll-empty\">\n Sin datos\n </td>\n </tr>\n }\n\n <!-- Spacer inferior: ocupa el espacio de las filas NO renderizadas abajo -->\n @if (paddingBottom() > 0) {\n <tr class=\"ll-spacer\" [style.height.px]=\"paddingBottom()\">\n <td [attr.colspan]=\"columnasRenderizadas().length\"></td>\n </tr>\n }\n </tbody>\n\n <!-- \u2500\u2500 FOOTER sticky \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (withTotal() && rowFilter().length > 0) {\n <tfoot class=\"ll-tfoot\">\n\n <tr>\n <td [attr.colspan]=\"getColspanBeforeTotals()\" class=\"{{classTotales()}} fw-5 fs-6 ps-2 py-2\">Totales:</td>\n @for (col of columnasRenderizadas() ; track col.fieldname) {\n @if (col.totalizable) {\n <td class=\"{{classTotales()}} ll-footer-cell fw-5 text-end fs-6\"\n [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\">\n {{ getTotals(col.fieldname)}}\n </td>\n }\n }\n </tr>\n </tfoot>\n }\n\n </table>\n </div>\n</ng-template>\n", styles: [":host(.ll-variant--modern) .ll-search-bar .ll-search-label{display:none}:host(.ll-variant--modern) .ll-search-bar .ll-search-input-wrap input.form-control{width:250px!important;min-width:250px!important;border-radius:5px!important;border:1px solid rgba(0,0,0,.12);background-color:#fff;font-size:12px;padding-left:34px;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:10px center;background-size:14px 14px;transition:border-color .15s ease,box-shadow .15s ease;height:30px!important;font-weight:400}:host(.ll-variant--modern) .ll-search-bar .ll-search-input-wrap input.form-control::placeholder{color:#9ca3af}:host(.ll-variant--modern) .ll-search-bar .ll-search-input-wrap input.form-control:focus{border-color:#1e293b;box-shadow:0 0 0 3px #1e293b14;outline:none}:host(.ll-variant--modern) .ll-search-bar .ll-search-input-wrap .boton-buscar{border-radius:5px;height:30px!important;width:30px!important;min-width:30px!important;background-color:#fff!important;border:1px solid rgba(0,0,0,.12)!important;color:#546074!important}:host(.ll-variant--modern) .ll-search-bar .ll-search-input-wrap .boton-buscar:hover{background-color:#f3f4f6!important;border-color:#0003!important}:host(.ll-variant--modern) .ll-scroll-container{border:1px solid rgba(0,0,0,.08);box-shadow:0 1px 3px #0000000f,0 4px 16px #0000000a;background:#fff}:host(.ll-variant--modern) .ll-table{border-collapse:separate;border-spacing:0;background:#fff}:host(.ll-variant--modern) .ll-thead tr th{background:#f1f1f1;color:#333!important;border:none;border-bottom:1px solid rgba(0,0,0,.1);border-top:1px solid rgba(0,0,0,.1);padding:12px 14px;box-shadow:none}:host(.ll-variant--modern) .ll-thead tr th.ll-col-pinned{background:#f1f1f1}:host(.ll-variant--modern) .ll-th-sortable:hover{background-color:#fff!important}:host(.ll-variant--modern) .ll-sort-idle{opacity:.4;color:#1e293b}:host(.ll-variant--modern) .icon-table{color:#5e5959!important;font-size:12px!important}:host(.ll-variant--modern) .ll-row{--row-bg: #ffffff;background-color:var(--row-bg);transition:background-color .1s ease}:host(.ll-variant--modern) .ll-row:nth-child(odd){--row-bg: #ffffff}:host(.ll-variant--modern) .ll-row:nth-child(2n){--row-bg: #f0f0f0}:host(.ll-variant--modern) .ll-row:hover:not(.ll-row--selected){--row-bg: #ebebeb;background-color:var(--row-bg)!important}:host(.ll-variant--modern) .ll-row--selected{--row-bg: var(--table-active-bg);background:var(--table-active-bg)!important;color:var(--table-active-color)!important;box-shadow:inset 4px 0 #334155}:host(.ll-variant--modern) .ll-row--drag-over{--row-bg: color-mix(in srgb, #5b8dee 8%, #ffffff);background-color:var(--row-bg)!important;outline:2px dashed rgba(91,141,238,.5);outline-offset:-2px}:host(.ll-variant--modern) .ll-row td{border-left:none;border-right:none;border-top:none;border-bottom:1px solid rgba(0,0,0,.1);height:40px}:host(.ll-variant--modern) .ll-tfoot tr td:first-child{border-bottom-left-radius:10px}:host(.ll-variant--modern) .ll-tfoot tr td:last-child{border-bottom-right-radius:10px}:host(.ll-variant--modern) .ll-tfoot .ll-footer-cell{background-color:var(--background-card);color:var(--text-color);border:none;border-top:1px solid rgba(0,0,0,.08);padding:10px 14px;box-shadow:none}:host(.ll-variant--modern) .ll-empty{padding:28px;color:#9ca3af;font-size:13px}.ll-search-bar{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-bottom:8px;flex-wrap:wrap}.ll-search-bar__left{display:flex;align-items:center;gap:6px;flex:1;flex-wrap:wrap}.ll-search-bar__right{display:flex;align-items:center;gap:4px;flex-shrink:0}.ll-search-bar__right .ll-search-group{display:flex;align-items:center;gap:4px}.ll-search-bar__right .ll-search-group .ll-search-label{white-space:nowrap}.ll-search-bar__right .ll-search-group .ll-search-input-wrap{display:flex;align-items:center}@media(max-width:576px){.ll-search-bar__right{width:100%;justify-content:space-between}.ll-search-bar__right .ll-search-group{flex-direction:column;align-items:flex-start;width:100%}.ll-search-bar__right .ll-search-group .ll-search-input-wrap{width:100%}.ll-search-bar__right .ll-search-group .ll-search-input-wrap input{flex:1}}.ll-scroll-container{width:100%;overflow-y:auto;overflow-x:auto;display:block;position:relative;border:var(--border-table-header);border-radius:4px;overflow-anchor:none}.ll-table{width:100%;border-collapse:separate;border-spacing:0;table-layout:auto;white-space:nowrap}.ll-thead{position:sticky;top:0;z-index:3;background-color:var(--background-header-table)}.ll-thead tr th{font-size:11px;font-weight:700;color:var(--text-color);text-align:start;padding:6px 8px;border:none;border-right:var(--border-table-header);border-bottom:var(--border-table-header);max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;background-color:var(--background-header-table);box-shadow:0 2px 2px -1px #0000001a}.ll-th-sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.ll-th-sortable:hover{background-color:var(--bs-table-header-hover-bg)!important}.ll-th-content{display:flex;align-items:center;gap:2px}.ll-th-caption{overflow:hidden;text-overflow:ellipsis}.ll-sort-idle{opacity:.25}.ll-tfoot{position:sticky;bottom:0;z-index:3;background-color:var(--background-card)}.ll-tfoot .ll-footer-cell{font-size:11px;color:var(--text-color);padding:10px 8px;border:none;border-right:var(--border-table-header);border-top:var(--border-table-header);background-color:var(--background-card);box-shadow:0 -2px 2px -1px #0000001a}.ll-row{--row-bg: var(--background-card, #ffffff);height:30px;cursor:pointer;background-color:var(--row-bg)}.ll-row:nth-child(odd){--row-bg: color-mix(in srgb, var(--background-card, #ffffff) 94%, #000000)}.ll-row:hover:not(.ll-row--selected){--row-bg: color-mix(in srgb, var(--background-card, #ffffff) 92%, #000000)}.ll-row--selected{--row-bg: var(--table-active-bg);background:var(--table-active-bg)!important;color:var(--table-active-color)!important}.ll-row--drag-over{--row-bg: color-mix(in srgb, #5b8dee 12%, var(--background-card, #ffffff));background-color:var(--row-bg)!important;outline:2px dashed #5b8dee;outline-offset:-2px;cursor:copy}.ll-row--drag-over td{color:#5b8dee!important}.ll-row td{font-size:11px;font-weight:500;color:var(--text-color);vertical-align:middle;padding:0 8px;border:none;border-right:var(--border-table-header);border-bottom:var(--border-table-header);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.ll-col-pinned{position:sticky;z-index:2;background-color:var(--row-bg, var(--background-card, #ffffff));background-clip:padding-box}.ll-thead tr th.ll-col-pinned{z-index:2;background-color:var(--background-header-table)}.ll-tfoot tr td.ll-col-pinned{z-index:2;background-color:var(--background-card)}.ll-scrolled-start .ll-col-pinned--shadow-left{box-shadow:6px 0 8px -4px #00000040}.ll-scrolled-end .ll-col-pinned--shadow-right{box-shadow:-6px 0 8px -4px #00000040}.ll-scrolled-start .ll-thead tr th.ll-col-pinned--shadow-left{box-shadow:6px 0 8px -4px #00000040,0 2px 2px -1px #0000001a}.ll-scrolled-end .ll-thead tr th.ll-col-pinned--shadow-right{box-shadow:-6px 0 8px -4px #00000040,0 2px 2px -1px #0000001a}.ll-spacer td{padding:0;border:none}.ll-empty{text-align:center;padding:16px;color:#6c757d;font-size:12px}@media(max-width:1600px){.ll-thead tr th,.ll-row td,.ll-tfoot .ll-footer-cell{font-size:9px}}.popover-menu-column{border-radius:.375rem;padding:0rem .75rem;display:block;max-height:min(500px,80vh);width:min(400px,100vw - 2rem);max-width:calc(80vw - 2rem);overflow-y:auto}.popover-title{font-weight:700;margin-bottom:.7rem;margin-left:-.75rem;margin-right:-.75rem;padding:.6rem .75rem;border-bottom:1px solid #c4c4c4;position:sticky;top:0;text-align:center}.popover-menu-column::-webkit-scrollbar{width:5px}.popover-menu-column::-webkit-scrollbar-track{background:#f1f1f1;border-radius:4px}.column-config-hint{font-size:10px;font-weight:400;text-transform:none;color:#9aa3ac}.column-config-list{display:flex;flex-direction:column;gap:3px;padding:4px 0 2px}.column-config-row{display:flex;align-items:center;gap:8px;padding:4px 6px;background:#fff;border:1px solid transparent;border-radius:6px;transition:background-color .15s ease,border-color .15s ease}.column-config-row:hover{background:#f6f7f8}.column-config-grip{cursor:grab;color:#adb5bd;font-size:13px;flex:none}.column-config-grip:active{cursor:grabbing}.column-config-pin{color:#64748b;font-size:11px;flex:none;transform:rotate(35deg)}.column-config-row.cdk-drag-preview{box-shadow:0 10px 24px -8px #00000059;border:1px solid #e5e5e5;border-radius:6px;background:#fff;transform:rotate(-1.5deg)}.column-config-row.cdk-drag-placeholder{border:1.5px dashed #6c757d;border-radius:6px;background:#f1f3f5;opacity:.7}.column-config-row.cdk-drag-placeholder *{visibility:hidden}.column-config-list.cdk-drop-list-dragging .column-config-row:not(.cdk-drag-placeholder){transition:transform .2s cubic-bezier(0,0,.2,1)}.column-config-footer{display:flex;align-items:center;justify-content:space-between;gap:8px;position:sticky;bottom:0;background:#fff;border-top:1px solid #e5e5e5;margin:6px -.75rem 0;padding:8px .75rem}.popover-menu-column::-webkit-scrollbar-thumb{background-color:#d7d7d7;border-radius:4px;border:2px solid transparent}.column-config-save{border-radius:6px;border:1px solid rgba(0,0,0,.12);background-color:#fff;color:#272727;padding:4px 12px;box-shadow:0 1px 2px #0000000f;transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease}.column-config-save:hover{background-color:#334155;border-color:#0003;color:#fff;box-shadow:0 2px 6px #00000026}.popover-menu-filter{background-color:#fff;border:1px solid #ddd;border-radius:.375rem;padding:0rem .75rem;display:block;max-height:300px;width:250px;overflow-y:auto;z-index:2}.popover-menu-filter::-webkit-scrollbar{width:5px}.popover-menu-filter::-webkit-scrollbar-track{background:#f1f1f1;border-radius:4px}.popover-menu-filter::-webkit-scrollbar-thumb{background-color:#d7d7d7;border-radius:4px;border:2px solid transparent}.table-blank{background:var(--background-card)}.auditoria{padding-left:35px;padding-top:8px;padding-bottom:10px}.cw-25{min-width:40px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: DropdownCdkComponent, selector: "app-dropdown-cdk", inputs: ["inline", "altoContainer"] }, { kind: "directive", type: AnimatedCheckboxDirective, selector: "input[type=checkbox][animatedCheckbox]", inputs: ["cbClass"] }, { kind: "component", type: CardMobileComponent, selector: "app-card-mobile", inputs: ["data", "columns", "identifier", "titleTabla", "actions", "altoContainer", "rendered"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }], animations: [fadeInOut, dropdownAnimation] });
|
|
4686
|
+
}
|
|
4687
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TableUltimatePinnedComponent, decorators: [{
|
|
4688
|
+
type: Component,
|
|
4689
|
+
args: [{ selector: 'app-table-ultimate-pinned', imports: [FormsModule, CommonModule, DropdownCdkComponent, AnimatedCheckboxDirective, CardMobileComponent, NgTemplateOutlet, CdkDropList, CdkDrag, CdkDragHandle], animations: [fadeInOut, dropdownAnimation], host: {
|
|
4690
|
+
'[class.ll-variant--modern]': 'variante() === "modern"'
|
|
4691
|
+
}, template: "@if (withFiltro()) {\n<div class=\"ll-search-bar\">\n\n <div class=\"ll-search-bar__left\">\n <ng-container *ngTemplateOutlet=\"contentFilter();\"></ng-container>\n </div>\n\n <div class=\"ll-search-bar__right\">\n\n <div class=\"ll-search-group\">\n\n <label class=\"form-label mb-0 ll-search-label\">Buscar:</label>\n <div class=\"ll-search-input-wrap\">\n\n <input type=\"text\" class=\"form-control cw-250\" placeholder=\"Buscar...\" [(ngModel)]=\"busqueda\" (input)=\"textoDigitado()\" />\n <app-dropdown-cdk [altoContainer]=\"300\">\n <ng-template #trigger>\n <button class=\"btn btn-dark boton-buscar fs-7\">\n <i class=\"fas fa-cog\"></i>\n </button>\n </ng-template>\n\n <ng-template #content>\n <div class=\"popover-menu-filter bg-white shadow my-2\" @fadeInOut>\n <div class=\"popover-title fs-7 bg-white\">\n Filtros\n </div>\n\n <div class=\"form-check form-switch text-start d-flex align-items-center\">\n <input class=\"form-check-input py-0 my-0 cw-25 ch-15\" type=\"checkbox\" [checked]=\"true\"\n (change)=\"toggleFiltros($event)\" id=\"filter_table_pinned_todos\" />\n <label class=\"form-check-label ps-2 fs-6 mb-0 cursor-pointer\"\n for=\"filter_table_pinned_todos\">\n Todos\n </label>\n </div>\n\n @for (col of columns(); track col.fieldname) {\n <div class=\"form-check form-switch text-start d-flex align-items-center\">\n <input type=\"checkbox\" class=\"form-check-input py-0 my-0 cw-25 ch-15\"\n id=\"{{ 'filter_pinned_' + col.fieldname }}\" [(ngModel)]=\"filtrarColumnas()[col.fieldname]\" />\n <label class=\"form-check-label ps-2 fs-6 cursor-pointer mb-0\"\n for=\"{{ 'filter_pinned_' + col.fieldname }}\">\n {{ col.caption || col.fieldname }}\n </label>\n </div>\n }\n </div>\n </ng-template>\n </app-dropdown-cdk>\n\n </div>\n\n </div>\n\n\n </div>\n\n\n</div>\n}\n\n@if (activeMobileMode()) {\n@if (isLoadingResponsive()) {\n<div class=\"d-flex flex-column justify-content-center align-items-center py-2\">\n <div class=\"spinner-border text-secondary mb-2\" role=\"status\"></div>\n <span class=\"ms-2 fs-6\">Cargando...</span>\n</div>\n}\n\n@if (!isLoadingResponsive()) {\n@if (isMobile()) {\n<app-card-mobile [data]=\"rowFilter()\" [columns]=\"columns()\" [actions]=\"customActions()\" [identifier]=\"identifier()\"\n [titleTabla]=\"titleTabla()\" [altoContainer]=\"altoContainer()\" />\n}\n@if (!isMobile()) {\n<ng-container *ngTemplateOutlet=\"table\"></ng-container>\n}\n}\n}\n@else {\n<ng-container *ngTemplateOutlet=\"table\"></ng-container>\n}\n\n<ng-template #table>\n <!-- Contenedor scrolleable \u2014 solo el BODY hace scroll; header y footer son sticky.\n Las clases ll-scrolled-* activan las sombras de las columnas fijadas. -->\n <div #scrollContainer class=\"ll-scroll-container\"\n [class.ll-scrolled-start]=\"hasShadowLeft()\"\n [class.ll-scrolled-end]=\"hasShadowRight()\"\n [style.height]=\"withHeight() ? heightStyle() : ''\"\n [style.max-height]=\"heightStyle()\" (scroll)=\"onScroll($event)\">\n <table class=\"ll-table\">\n\n <!-- \u2500\u2500 HEADER sticky \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <thead class=\"ll-thead\">\n <tr>\n @if (withDetails()) {\n <th class=\"cw-25\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? 0 : null\"\n [style.width.px]=\"hasLeftPinned() ? UTIL_W.details : null\"\n [style.min-width.px]=\"hasLeftPinned() ? UTIL_W.details : null\"\n [style.max-width.px]=\"hasLeftPinned() ? UTIL_W.details : null\"></th>\n }\n\n @if (withCheckbox()) {\n <th class=\"cw-20\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? utilCheckboxLeft() : null\"\n [style.width.px]=\"hasLeftPinned() ? UTIL_W.checkbox : null\"\n [style.min-width.px]=\"hasLeftPinned() ? UTIL_W.checkbox : null\"\n [style.max-width.px]=\"hasLeftPinned() ? UTIL_W.checkbox : null\">\n <label>\n <input type=\"checkbox\" name=\"check_box_select_table_pinned_main\" id=\"check_box_select_table_pinned_main\"\n animatedCheckbox [checked]=\"validaAllCheck()\" (change)=\"allCheck($event)\">\n </label>\n </th>\n }\n\n @if (customActions()) {\n <th class=\"cw-40\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? utilActionsLeft() : null\"\n [style.width.px]=\"hasLeftPinned() ? UTIL_W.actions : null\"\n [style.min-width.px]=\"hasLeftPinned() ? UTIL_W.actions : null\"\n [style.max-width.px]=\"hasLeftPinned() ? UTIL_W.actions : null\">\n <app-dropdown-cdk [altoContainer]=\"500\">\n <ng-template #trigger>\n <button class=\"btn p-0 text-dark d-flex mx-auto border-0 icon-table\">\n <i class=\"fas fa-cog\"></i>\n </button>\n </ng-template>\n <ng-template #content>\n <div class=\"popover-menu-column bg-white shadow my-2\" @fadeInOut>\n <div class=\"popover-title fs-7 bg-white d-flex align-items-baseline justify-content-between\">\n <span>Columnas</span>\n <span class=\"column-config-hint\">arrastra para ordenar</span>\n </div>\n\n <div cdkDropList class=\"column-config-list\" (cdkDropListDropped)=\"onColumnDrop($event)\">\n @for (col of columnasConfigurables(); track col.fieldname) {\n <div class=\"column-config-row\" cdkDrag>\n <i class=\"fas fa-grip-vertical column-config-grip\" cdkDragHandle></i>\n <div class=\"form-check form-switch text-start d-flex align-items-center mb-0 flex-grow-1\">\n <input type=\"checkbox\" class=\"form-check-input py-0 my-0 cw-25 ch-15\"\n id=\"{{ 'switch_pinned_' + col.fieldname }}\"\n [checked]=\"isColumnVisible(col.fieldname)\"\n (change)=\"toggleColumnVisible(col.fieldname, $event)\" />\n <label class=\"form-check-label ps-2 fs-6 cursor-pointer font-label mb-0\"\n for=\"{{ 'switch_pinned_' + col.fieldname }}\">\n {{ col.caption || col.fieldname }}\n </label>\n </div>\n @if (pinnedSide(col)) {\n <i class=\"fas fa-thumbtack column-config-pin\" title=\"Columna fijada\"></i>\n }\n </div>\n }\n </div>\n\n <div class=\"column-config-footer\">\n <button type=\"button\" class=\"btn btn-sm fs-7 column-config-save\"\n (click)=\"guardarConfiguracionColumnas()\">\n Guardar configuraci\u00F3n\n </button>\n </div>\n </div>\n </ng-template>\n </app-dropdown-cdk>\n </th>\n }\n\n @for (col of columnasRenderizadas(); track col.fieldname) {\n <th [title]=\"col.caption\" [style.width.px]=\"colWidth(col)\"\n [style.min-width.px]=\"colWidth(col)\" [style.max-width.px]=\"colWidth(col)\"\n [class.ll-th-sortable]=\"col.caption\"\n [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\"\n (click)=\"col.caption && toggleSort(col.fieldname)\">\n <span class=\"ll-th-content\">\n <span class=\"ll-th-caption\">{{ col.caption }}</span>\n @if (col.caption) {\n @if (sortField() === col.fieldname) {\n <i class=\"ms-1\"\n [ngClass]=\"sortDir() === 'asc' ? 'fas fa-angle-up fs-6':'fas fa-angle-down fs-6'\"></i>\n } @else {\n <i class=\"fas fa-sort ms-1 ll-sort-idle\"></i>\n }\n }\n </span>\n </th>\n }\n </tr>\n </thead>\n\n <!-- \u2500\u2500 BODY virtual \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <tbody>\n <!-- Spacer superior: ocupa el espacio de las filas NO renderizadas arriba -->\n @if (paddingTop() > 0) {\n <tr class=\"ll-spacer\" [style.height.px]=\"paddingTop()\">\n <td [attr.colspan]=\"columnasRenderizadas().length\"></td>\n </tr>\n }\n\n <!-- Filas visibles -->\n @for (row of visibleRows(); track row.idListTsi) {\n @let idList = row.idListTsi;\n <tr class=\"ll-row\" [class.ll-row--selected]=\"isSelected(row, idList)\"\n [class.ll-row--drag-over]=\"withAttachment() && dragOverRowId() === idList\"\n (click)=\"selectRow(row, idList)\" (dblclick)=\"onDoubleClick(row)\"\n (contextmenu)=\"onRightClick($event,row)\"\n (dragover)=\"withAttachment() && onDragOver($event, idList)\"\n (dragleave)=\"withAttachment() && onDragLeave()\" (drop)=\"withAttachment() && onDrop($event, row)\">\n\n @if (withDetails()) {\n <td class=\"b-table text-center mwp-25\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? 0 : null\">\n <a (click)=\"toggleExpandRow(idList)\" class=\"text-dark cursor-pointer fs-6\">\n <i class=\"fa-solid\" [class.fa-chevron-right]=\"expandedRows() != idList\"\n [class.fa-chevron-down]=\"expandedRows() == idList\"></i>\n </a>\n </td>\n }\n\n @if (withCheckbox()) {\n <td scope=\"col\" class=\"text-center b-table\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? utilCheckboxLeft() : null\">\n <label>\n <input type=\"checkbox\" [name]=\"'check_box_select_table_pinned_' + idList\"\n [id]=\"'check_box_select_table_pinned_' + idList\" animatedCheckbox\n [checked]=\"isItemSelected(idList)\" (click)=\"$event.stopPropagation()\"\n (change)=\"toogleItem(idList , $event)\" [disabled]=\"isCheckboxDisabled(row)\">\n </label>\n </td>\n }\n\n @if (customActions()) {\n <td class=\"text-center\"\n [class.ll-col-pinned]=\"hasLeftPinned()\"\n [style.left.px]=\"hasLeftPinned() ? utilActionsLeft() : null\">\n <ng-container *ngTemplateOutlet=\"customActions(); context: { $implicit: row }\"></ng-container>\n </td>\n }\n\n @for (col of columnasRenderizadas(); track col.fieldname) {\n @if (columnDefMap().has(col.fieldname)) {\n <td [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\"\n [style.min-width.px]=\"pin(col) ? colWidth(col) : null\"\n [style.max-width.px]=\"pin(col) ? colWidth(col) : null\">\n <ng-container *ngTemplateOutlet=\"columnDefMap().get(col.fieldname)!; context: { $implicit: row, column: col }\">\n </ng-container>\n </td>\n } @else if (col.template) {\n <td [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\"\n [style.min-width.px]=\"pin(col) ? colWidth(col) : null\"\n [style.max-width.px]=\"pin(col) ? colWidth(col) : null\">\n <ng-container *ngTemplateOutlet=\"col.template; context: { $implicit: row, column: col }\">\n </ng-container>\n </td>\n } @else {\n @switch (col.tipo) {\n\n @case ('cell-render') {\n @let resolverItem = resolveCell(col.fieldname, row);\n @if (resolverItem) {\n <td [title]=\"resolverItem.text\" [class.text-center]=\"resolverItem.icon\"\n [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\"\n [style.min-width.px]=\"pin(col) ? colWidth(col) : null\"\n [style.max-width.px]=\"pin(col) ? colWidth(col) : null\">\n @if (resolverItem.icon) {\n <i class=\"fs-5\" [ngClass]=\"resolverItem.icon\"></i>\n } @else if (resolverItem.class) {\n <span [ngClass]=\"row.situac == 'J' ? 'text-error' : resolverItem.class\">\n {{ resolverItem.text }}\n </span>\n } @else {\n {{ resolverItem.text }}\n }\n </td>\n }\n }\n\n @default {\n <td [innerHTML]=\"getHighlight(row._format?.[col.fieldname] ?? row[col.fieldname], col.fieldname)\"\n [style.width.px]=\"colWidth(col)\"\n [style.min-width.px]=\"pin(col) ? colWidth(col) : null\"\n [style.max-width.px]=\"colWidth(col)\"\n [attr.title]=\"row[col.fieldname] || null\"\n [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\"\n [ngClass]=\"rowClassFn() ? rowClassFn()(row) : getRowClass(row)\" class=\"{{getPosition(col)}}\">\n </td>\n }\n\n }\n }\n }\n </tr>\n\n @if (idList == expandedRows()) {\n <tr @fadeInOut>\n <td [attr.colspan]=\"columnasRenderizadas().length + (withDetails() ? 1 : 0) + (customActions() ? 1 : 0) + (withCheckbox() ? 1 : 0)\"\n class=\"table-blank\">\n <div class=\"d-flex flex-column auditoria\">\n <span class=\"fw-bold fs-7 text-dark\">Datos de auditor\u00EDa</span>\n <span class=\"fs-6 text-dark fw-bold\">\n Creaci\u00F3n: {{ row.nomucreac }} el {{ row._format?.fcreac ?? row.fcreac }} a las {{\n row.hcreac }}\n </span>\n <span class=\"fs-6 text-dark fw-bold\">\n Actualizaci\u00F3n: {{ row.nomuactua }} el {{ row._format?.factua ?? row.factua }} a las\n {{\n row.hactua }}\n </span>\n </div>\n </td>\n </tr>\n }\n\n }\n\n <!-- Fila vac\u00EDa si no hay datos -->\n @if (rowFilter().length === 0) {\n <tr>\n <td [attr.colspan]=\"columnasRenderizadas().length\" class=\"ll-empty\">\n Sin datos\n </td>\n </tr>\n }\n\n <!-- Spacer inferior: ocupa el espacio de las filas NO renderizadas abajo -->\n @if (paddingBottom() > 0) {\n <tr class=\"ll-spacer\" [style.height.px]=\"paddingBottom()\">\n <td [attr.colspan]=\"columnasRenderizadas().length\"></td>\n </tr>\n }\n </tbody>\n\n <!-- \u2500\u2500 FOOTER sticky \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (withTotal() && rowFilter().length > 0) {\n <tfoot class=\"ll-tfoot\">\n\n <tr>\n <td [attr.colspan]=\"getColspanBeforeTotals()\" class=\"{{classTotales()}} fw-5 fs-6 ps-2 py-2\">Totales:</td>\n @for (col of columnasRenderizadas() ; track col.fieldname) {\n @if (col.totalizable) {\n <td class=\"{{classTotales()}} ll-footer-cell fw-5 text-end fs-6\"\n [class.ll-col-pinned]=\"!!pin(col)\"\n [class.ll-col-pinned--shadow-left]=\"pin(col)?.side === 'left' && pin(col)?.edge\"\n [class.ll-col-pinned--shadow-right]=\"pin(col)?.side === 'right' && pin(col)?.edge\"\n [style.left.px]=\"pin(col)?.left\"\n [style.right.px]=\"pin(col)?.right\">\n {{ getTotals(col.fieldname)}}\n </td>\n }\n }\n </tr>\n </tfoot>\n }\n\n </table>\n </div>\n</ng-template>\n", styles: [":host(.ll-variant--modern) .ll-search-bar .ll-search-label{display:none}:host(.ll-variant--modern) .ll-search-bar .ll-search-input-wrap input.form-control{width:250px!important;min-width:250px!important;border-radius:5px!important;border:1px solid rgba(0,0,0,.12);background-color:#fff;font-size:12px;padding-left:34px;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:10px center;background-size:14px 14px;transition:border-color .15s ease,box-shadow .15s ease;height:30px!important;font-weight:400}:host(.ll-variant--modern) .ll-search-bar .ll-search-input-wrap input.form-control::placeholder{color:#9ca3af}:host(.ll-variant--modern) .ll-search-bar .ll-search-input-wrap input.form-control:focus{border-color:#1e293b;box-shadow:0 0 0 3px #1e293b14;outline:none}:host(.ll-variant--modern) .ll-search-bar .ll-search-input-wrap .boton-buscar{border-radius:5px;height:30px!important;width:30px!important;min-width:30px!important;background-color:#fff!important;border:1px solid rgba(0,0,0,.12)!important;color:#546074!important}:host(.ll-variant--modern) .ll-search-bar .ll-search-input-wrap .boton-buscar:hover{background-color:#f3f4f6!important;border-color:#0003!important}:host(.ll-variant--modern) .ll-scroll-container{border:1px solid rgba(0,0,0,.08);box-shadow:0 1px 3px #0000000f,0 4px 16px #0000000a;background:#fff}:host(.ll-variant--modern) .ll-table{border-collapse:separate;border-spacing:0;background:#fff}:host(.ll-variant--modern) .ll-thead tr th{background:#f1f1f1;color:#333!important;border:none;border-bottom:1px solid rgba(0,0,0,.1);border-top:1px solid rgba(0,0,0,.1);padding:12px 14px;box-shadow:none}:host(.ll-variant--modern) .ll-thead tr th.ll-col-pinned{background:#f1f1f1}:host(.ll-variant--modern) .ll-th-sortable:hover{background-color:#fff!important}:host(.ll-variant--modern) .ll-sort-idle{opacity:.4;color:#1e293b}:host(.ll-variant--modern) .icon-table{color:#5e5959!important;font-size:12px!important}:host(.ll-variant--modern) .ll-row{--row-bg: #ffffff;background-color:var(--row-bg);transition:background-color .1s ease}:host(.ll-variant--modern) .ll-row:nth-child(odd){--row-bg: #ffffff}:host(.ll-variant--modern) .ll-row:nth-child(2n){--row-bg: #f0f0f0}:host(.ll-variant--modern) .ll-row:hover:not(.ll-row--selected){--row-bg: #ebebeb;background-color:var(--row-bg)!important}:host(.ll-variant--modern) .ll-row--selected{--row-bg: var(--table-active-bg);background:var(--table-active-bg)!important;color:var(--table-active-color)!important;box-shadow:inset 4px 0 #334155}:host(.ll-variant--modern) .ll-row--drag-over{--row-bg: color-mix(in srgb, #5b8dee 8%, #ffffff);background-color:var(--row-bg)!important;outline:2px dashed rgba(91,141,238,.5);outline-offset:-2px}:host(.ll-variant--modern) .ll-row td{border-left:none;border-right:none;border-top:none;border-bottom:1px solid rgba(0,0,0,.1);height:40px}:host(.ll-variant--modern) .ll-tfoot tr td:first-child{border-bottom-left-radius:10px}:host(.ll-variant--modern) .ll-tfoot tr td:last-child{border-bottom-right-radius:10px}:host(.ll-variant--modern) .ll-tfoot .ll-footer-cell{background-color:var(--background-card);color:var(--text-color);border:none;border-top:1px solid rgba(0,0,0,.08);padding:10px 14px;box-shadow:none}:host(.ll-variant--modern) .ll-empty{padding:28px;color:#9ca3af;font-size:13px}.ll-search-bar{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-bottom:8px;flex-wrap:wrap}.ll-search-bar__left{display:flex;align-items:center;gap:6px;flex:1;flex-wrap:wrap}.ll-search-bar__right{display:flex;align-items:center;gap:4px;flex-shrink:0}.ll-search-bar__right .ll-search-group{display:flex;align-items:center;gap:4px}.ll-search-bar__right .ll-search-group .ll-search-label{white-space:nowrap}.ll-search-bar__right .ll-search-group .ll-search-input-wrap{display:flex;align-items:center}@media(max-width:576px){.ll-search-bar__right{width:100%;justify-content:space-between}.ll-search-bar__right .ll-search-group{flex-direction:column;align-items:flex-start;width:100%}.ll-search-bar__right .ll-search-group .ll-search-input-wrap{width:100%}.ll-search-bar__right .ll-search-group .ll-search-input-wrap input{flex:1}}.ll-scroll-container{width:100%;overflow-y:auto;overflow-x:auto;display:block;position:relative;border:var(--border-table-header);border-radius:4px;overflow-anchor:none}.ll-table{width:100%;border-collapse:separate;border-spacing:0;table-layout:auto;white-space:nowrap}.ll-thead{position:sticky;top:0;z-index:3;background-color:var(--background-header-table)}.ll-thead tr th{font-size:11px;font-weight:700;color:var(--text-color);text-align:start;padding:6px 8px;border:none;border-right:var(--border-table-header);border-bottom:var(--border-table-header);max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;background-color:var(--background-header-table);box-shadow:0 2px 2px -1px #0000001a}.ll-th-sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.ll-th-sortable:hover{background-color:var(--bs-table-header-hover-bg)!important}.ll-th-content{display:flex;align-items:center;gap:2px}.ll-th-caption{overflow:hidden;text-overflow:ellipsis}.ll-sort-idle{opacity:.25}.ll-tfoot{position:sticky;bottom:0;z-index:3;background-color:var(--background-card)}.ll-tfoot .ll-footer-cell{font-size:11px;color:var(--text-color);padding:10px 8px;border:none;border-right:var(--border-table-header);border-top:var(--border-table-header);background-color:var(--background-card);box-shadow:0 -2px 2px -1px #0000001a}.ll-row{--row-bg: var(--background-card, #ffffff);height:30px;cursor:pointer;background-color:var(--row-bg)}.ll-row:nth-child(odd){--row-bg: color-mix(in srgb, var(--background-card, #ffffff) 94%, #000000)}.ll-row:hover:not(.ll-row--selected){--row-bg: color-mix(in srgb, var(--background-card, #ffffff) 92%, #000000)}.ll-row--selected{--row-bg: var(--table-active-bg);background:var(--table-active-bg)!important;color:var(--table-active-color)!important}.ll-row--drag-over{--row-bg: color-mix(in srgb, #5b8dee 12%, var(--background-card, #ffffff));background-color:var(--row-bg)!important;outline:2px dashed #5b8dee;outline-offset:-2px;cursor:copy}.ll-row--drag-over td{color:#5b8dee!important}.ll-row td{font-size:11px;font-weight:500;color:var(--text-color);vertical-align:middle;padding:0 8px;border:none;border-right:var(--border-table-header);border-bottom:var(--border-table-header);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.ll-col-pinned{position:sticky;z-index:2;background-color:var(--row-bg, var(--background-card, #ffffff));background-clip:padding-box}.ll-thead tr th.ll-col-pinned{z-index:2;background-color:var(--background-header-table)}.ll-tfoot tr td.ll-col-pinned{z-index:2;background-color:var(--background-card)}.ll-scrolled-start .ll-col-pinned--shadow-left{box-shadow:6px 0 8px -4px #00000040}.ll-scrolled-end .ll-col-pinned--shadow-right{box-shadow:-6px 0 8px -4px #00000040}.ll-scrolled-start .ll-thead tr th.ll-col-pinned--shadow-left{box-shadow:6px 0 8px -4px #00000040,0 2px 2px -1px #0000001a}.ll-scrolled-end .ll-thead tr th.ll-col-pinned--shadow-right{box-shadow:-6px 0 8px -4px #00000040,0 2px 2px -1px #0000001a}.ll-spacer td{padding:0;border:none}.ll-empty{text-align:center;padding:16px;color:#6c757d;font-size:12px}@media(max-width:1600px){.ll-thead tr th,.ll-row td,.ll-tfoot .ll-footer-cell{font-size:9px}}.popover-menu-column{border-radius:.375rem;padding:0rem .75rem;display:block;max-height:min(500px,80vh);width:min(400px,100vw - 2rem);max-width:calc(80vw - 2rem);overflow-y:auto}.popover-title{font-weight:700;margin-bottom:.7rem;margin-left:-.75rem;margin-right:-.75rem;padding:.6rem .75rem;border-bottom:1px solid #c4c4c4;position:sticky;top:0;text-align:center}.popover-menu-column::-webkit-scrollbar{width:5px}.popover-menu-column::-webkit-scrollbar-track{background:#f1f1f1;border-radius:4px}.column-config-hint{font-size:10px;font-weight:400;text-transform:none;color:#9aa3ac}.column-config-list{display:flex;flex-direction:column;gap:3px;padding:4px 0 2px}.column-config-row{display:flex;align-items:center;gap:8px;padding:4px 6px;background:#fff;border:1px solid transparent;border-radius:6px;transition:background-color .15s ease,border-color .15s ease}.column-config-row:hover{background:#f6f7f8}.column-config-grip{cursor:grab;color:#adb5bd;font-size:13px;flex:none}.column-config-grip:active{cursor:grabbing}.column-config-pin{color:#64748b;font-size:11px;flex:none;transform:rotate(35deg)}.column-config-row.cdk-drag-preview{box-shadow:0 10px 24px -8px #00000059;border:1px solid #e5e5e5;border-radius:6px;background:#fff;transform:rotate(-1.5deg)}.column-config-row.cdk-drag-placeholder{border:1.5px dashed #6c757d;border-radius:6px;background:#f1f3f5;opacity:.7}.column-config-row.cdk-drag-placeholder *{visibility:hidden}.column-config-list.cdk-drop-list-dragging .column-config-row:not(.cdk-drag-placeholder){transition:transform .2s cubic-bezier(0,0,.2,1)}.column-config-footer{display:flex;align-items:center;justify-content:space-between;gap:8px;position:sticky;bottom:0;background:#fff;border-top:1px solid #e5e5e5;margin:6px -.75rem 0;padding:8px .75rem}.popover-menu-column::-webkit-scrollbar-thumb{background-color:#d7d7d7;border-radius:4px;border:2px solid transparent}.column-config-save{border-radius:6px;border:1px solid rgba(0,0,0,.12);background-color:#fff;color:#272727;padding:4px 12px;box-shadow:0 1px 2px #0000000f;transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease}.column-config-save:hover{background-color:#334155;border-color:#0003;color:#fff;box-shadow:0 2px 6px #00000026}.popover-menu-filter{background-color:#fff;border:1px solid #ddd;border-radius:.375rem;padding:0rem .75rem;display:block;max-height:300px;width:250px;overflow-y:auto;z-index:2}.popover-menu-filter::-webkit-scrollbar{width:5px}.popover-menu-filter::-webkit-scrollbar-track{background:#f1f1f1;border-radius:4px}.popover-menu-filter::-webkit-scrollbar-thumb{background-color:#d7d7d7;border-radius:4px;border:2px solid transparent}.table-blank{background:var(--background-card)}.auditoria{padding-left:35px;padding-top:8px;padding-bottom:10px}.cw-25{min-width:40px}\n"] }]
|
|
4692
|
+
}], propDecorators: { onResize: [{
|
|
4693
|
+
type: HostListener,
|
|
4694
|
+
args: ['window:resize', ['$event']]
|
|
4695
|
+
}] } });
|
|
4696
|
+
|
|
4164
4697
|
/**
|
|
4165
4698
|
* Tabla pivot con expansión multi-nivel y virtual scroll nativo.
|
|
4166
4699
|
* Cada fila puede expandirse para mostrar sub-filas, que a su vez pueden
|
|
@@ -5457,6 +5990,8 @@ class TableData {
|
|
|
5457
5990
|
condition;
|
|
5458
5991
|
template;
|
|
5459
5992
|
totalizable;
|
|
5993
|
+
/** Fija la columna al hacer scroll horizontal (table-ultimate-pinned). true = 'right' */
|
|
5994
|
+
pinned;
|
|
5460
5995
|
promedioSimple;
|
|
5461
5996
|
promedioPonderado;
|
|
5462
5997
|
cantidadPonderado;
|
|
@@ -5896,5 +6431,5 @@ function handleResourceV2(fn, signal) {
|
|
|
5896
6431
|
* Generated bundle index. Do not edit.
|
|
5897
6432
|
*/
|
|
5898
6433
|
|
|
5899
|
-
export { AlertConfirmationComponent, AlertConfirmationConfig, AlertConfirmationService, AlertErrorComponent, AlertErrorService, AlertService, AlertaComponent, Almacenes, AnimatedCheckboxDirective, AtajosDirective, AutocompleteComponent, AutocompleteV2Component, BadgeComponent, ButtonComponent, ButtonProperties, CaracteresCodigoDirective, CardMobileComponent, CheckBoxComponent, Cobradores, DecimalDirective, DetalleCreditoComponent, Direcciones, DobleInputComponent, DropdownCdkComponent, DropdownComponent, DropdownMenuComponent, DropdownOption, FilterToggleComponent, FormateadorService, HeaderComponent, InputClaseComponent, InputComponent, InputDinamicoComponent, InputRadioComponent, ListOptionComponent, ListSituacionesComponent, MdGenericoComponent, Monedas, MontosCalcularComponent, Motivos, MultiSelectDropdownComponent, MultiselectedComponent, NavTabsComponent, OnlyNumberDirective, OnlyNumberFlexDirective, PaginadorComponent, RadioComponent, Recursos, Series, SidebarComponent, SpinnerComponent, SwitchActivoComponent, SwitchComponent, TABLE_EVENTS, TBanco, TabItemComponent, TableAdvanceComponent, TableAdvanceOptimizadaComponent, TableAgrupadaComponent, TableBusquedaComponent, TableData, TableDetalleComponent, TableSimpleComponent, TableUltimateComponent, TableUltimatePivotComponent, TipoDocumento, ToastService, ToasterComponent, Transportista, TsiColumnDefDirective, Vendedor, configModal, getInputsObligatorios, handleEmptyResult, handleErrorsApi, handleModal, handleModalReturn, handleReset, handleResetNoSignal, handleResource, handleResourceV2, handleSuccessApi, handleSuccessResult, showError, throwIfEmptyArray, validaFecha, validaLista, validaMes, validaPeriodo, validaPeriodoSimple, validaPosicion, validaTipo, validarObligatorio, validarSituacion };
|
|
6434
|
+
export { AlertConfirmationComponent, AlertConfirmationConfig, AlertConfirmationService, AlertErrorComponent, AlertErrorService, AlertService, AlertaComponent, Almacenes, AnimatedCheckboxDirective, AtajosDirective, AutocompleteComponent, AutocompleteV2Component, BadgeComponent, ButtonComponent, ButtonProperties, CaracteresCodigoDirective, CardMobileComponent, CheckBoxComponent, Cobradores, DecimalDirective, DetalleCreditoComponent, Direcciones, DobleInputComponent, DropdownCdkComponent, DropdownComponent, DropdownMenuComponent, DropdownOption, FilterToggleComponent, FormateadorService, HeaderComponent, InputClaseComponent, InputComponent, InputDinamicoComponent, InputRadioComponent, ListOptionComponent, ListSituacionesComponent, MdGenericoComponent, Monedas, MontosCalcularComponent, Motivos, MultiSelectDropdownComponent, MultiselectedComponent, NavTabsComponent, OnlyNumberDirective, OnlyNumberFlexDirective, PaginadorComponent, RadioComponent, Recursos, Series, SidebarComponent, SpinnerComponent, SwitchActivoComponent, SwitchComponent, TABLE_EVENTS, TBanco, TabItemComponent, TableAdvanceComponent, TableAdvanceOptimizadaComponent, TableAgrupadaComponent, TableBusquedaComponent, TableData, TableDetalleComponent, TableSimpleComponent, TableUltimateComponent, TableUltimatePinnedComponent, TableUltimatePivotComponent, TipoDocumento, ToastService, ToasterComponent, Transportista, TsiColumnDefDirective, Vendedor, configModal, getInputsObligatorios, handleEmptyResult, handleErrorsApi, handleModal, handleModalReturn, handleReset, handleResetNoSignal, handleResource, handleResourceV2, handleSuccessApi, handleSuccessResult, showError, throwIfEmptyArray, validaFecha, validaLista, validaMes, validaPeriodo, validaPeriodoSimple, validaPosicion, validaTipo, validarObligatorio, validarSituacion };
|
|
5900
6435
|
//# sourceMappingURL=ng-components-tsi.mjs.map
|