@esfaenza/es-table 20.3.36 → 20.3.38
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/esfaenza-es-table.mjs +339 -32
- package/fesm2022/esfaenza-es-table.mjs.map +1 -1
- package/index.d.ts +103 -1
- package/package.json +1 -1
|
@@ -7029,6 +7029,54 @@ class EsTable2Component {
|
|
|
7029
7029
|
...cols.filter(c => !c.pinned && !c.fixed)
|
|
7030
7030
|
];
|
|
7031
7031
|
}
|
|
7032
|
+
/** Scroll dello scroller: sposta la finestra solo quando cambia davvero riga */
|
|
7033
|
+
onScrollerScroll(ev) {
|
|
7034
|
+
if (!this.virtualActive())
|
|
7035
|
+
return;
|
|
7036
|
+
const h = this.virtualRowH();
|
|
7037
|
+
if (!h) {
|
|
7038
|
+
this.measureVirtualMetrics();
|
|
7039
|
+
return;
|
|
7040
|
+
}
|
|
7041
|
+
const top = ev.target.scrollTop;
|
|
7042
|
+
const first = Math.max(0, Math.floor(top / h) - this.VIRTUAL_OVERSCAN);
|
|
7043
|
+
if (first !== this.vFirst()) {
|
|
7044
|
+
this.vFirst.set(first);
|
|
7045
|
+
this.cdr.markForCheck();
|
|
7046
|
+
}
|
|
7047
|
+
}
|
|
7048
|
+
/** Misura viewport e altezza di riga dal DOM (una riga NON distanziatrice) */
|
|
7049
|
+
measureVirtualMetrics() {
|
|
7050
|
+
const el = this.scrollEl;
|
|
7051
|
+
if (!el)
|
|
7052
|
+
return;
|
|
7053
|
+
const vh = el.clientHeight;
|
|
7054
|
+
if (vh && vh !== this.vViewportH()) {
|
|
7055
|
+
this.vViewportH.set(vh);
|
|
7056
|
+
this.cdr.markForCheck();
|
|
7057
|
+
}
|
|
7058
|
+
if (this.VirtualRowHeight())
|
|
7059
|
+
return;
|
|
7060
|
+
const row = el.querySelector('tbody tr:not(.est2-vspacer)');
|
|
7061
|
+
const h = row?.offsetHeight ?? 0;
|
|
7062
|
+
if (h && h !== this.vMeasuredRowH()) {
|
|
7063
|
+
this.vMeasuredRowH.set(h);
|
|
7064
|
+
this.cdr.markForCheck();
|
|
7065
|
+
}
|
|
7066
|
+
}
|
|
7067
|
+
/** ViewChild-setter sullo scroller: da qui partono le misure della virtualizzazione */
|
|
7068
|
+
set scrollRefEl(ref) {
|
|
7069
|
+
const el = ref?.nativeElement;
|
|
7070
|
+
if (el === this.scrollEl)
|
|
7071
|
+
return;
|
|
7072
|
+
this.scrollEl = el;
|
|
7073
|
+
this.scrollRO?.disconnect();
|
|
7074
|
+
if (!el || typeof ResizeObserver === 'undefined')
|
|
7075
|
+
return;
|
|
7076
|
+
this.scrollRO = new ResizeObserver(() => this.measureVirtualMetrics());
|
|
7077
|
+
this.scrollRO.observe(el);
|
|
7078
|
+
this.measureVirtualMetrics();
|
|
7079
|
+
}
|
|
7032
7080
|
/**
|
|
7033
7081
|
* Larghezza FISSA (px) di una colonna PINNATA (default direttiva). Una colonna sticky
|
|
7034
7082
|
* è per contratto a larghezza fissa. Default = `PINNED_DEFAULT_W`.
|
|
@@ -7076,6 +7124,13 @@ class EsTable2Component {
|
|
|
7076
7124
|
this._SelectAll = input(null, ...(ngDevMode ? [{ debugName: "_SelectAll", alias: 'SelectAll' }] : [{ alias: 'SelectAll' }]));
|
|
7077
7125
|
this.SelectAll = linkedSignal(() => this.io(this._SelectAll(), null, false), ...(ngDevMode ? [{ debugName: "SelectAll" }] : []));
|
|
7078
7126
|
/** @deprecated NO-OP di parità v1 (cache selezione cross-pagina): dichiarato per il drop-in, non usato */
|
|
7127
|
+
/**
|
|
7128
|
+
* Identità di una riga per la cache di selezione: nome di una proprietà (es. id)
|
|
7129
|
+
* oppure una funzione. Senza, si ricade su un hash del CONTENUTO (parità con
|
|
7130
|
+
* l'originale): funziona, ma basta che il server cambi un campo perché la riga non
|
|
7131
|
+
* venga più riconosciuta. Con una chiave stabile il problema non si pone.
|
|
7132
|
+
*/
|
|
7133
|
+
this.SelectionKey = input(undefined, ...(ngDevMode ? [{ debugName: "SelectionKey" }] : []));
|
|
7079
7134
|
this._UseSelectionCache = input(null, ...(ngDevMode ? [{ debugName: "_UseSelectionCache", alias: 'UseSelectionCache' }] : [{ alias: 'UseSelectionCache' }]));
|
|
7080
7135
|
this.UseSelectionCache = linkedSignal(() => this.io(this._UseSelectionCache(), this.defaults?.UseSelectionCache, true), ...(ngDevMode ? [{ debugName: "UseSelectionCache" }] : []));
|
|
7081
7136
|
this._ShiftClick = input(null, ...(ngDevMode ? [{ debugName: "_ShiftClick", alias: 'ShiftClick' }] : [{ alias: 'ShiftClick' }]));
|
|
@@ -7104,6 +7159,19 @@ class EsTable2Component {
|
|
|
7104
7159
|
this.CountLabel = input('', ...(ngDevMode ? [{ debugName: "CountLabel" }] : []));
|
|
7105
7160
|
this.Height = input(undefined, ...(ngDevMode ? [{ debugName: "Height" }] : []));
|
|
7106
7161
|
this.MaxHeight = input(undefined, ...(ngDevMode ? [{ debugName: "MaxHeight" }] : []));
|
|
7162
|
+
/**
|
|
7163
|
+
* Rende solo le righe VISIBILI nel viewport (più un margine), con due righe
|
|
7164
|
+
* distanziatrici a compensare l'altezza mancante. Serve a tabelle molto lunghe
|
|
7165
|
+
* rese in un colpo solo (paginazione disattivata o pagina enorme).
|
|
7166
|
+
*
|
|
7167
|
+
* È OPT-IN: da spento il corpo della tabella è renderizzato esattamente come prima.
|
|
7168
|
+
* Richiede uno scroller ad altezza limitata (`[MaxHeight]`/`[Height]`) e righe di
|
|
7169
|
+
* altezza UNIFORME. Su raggruppamento e gerarchia si autodisattiva: lì il ciclo
|
|
7170
|
+
* salta le righe non visibili, quindi indice di riga e posizione non coincidono.
|
|
7171
|
+
*/
|
|
7172
|
+
this.VirtualScroll = input(false, ...(ngDevMode ? [{ debugName: "VirtualScroll" }] : []));
|
|
7173
|
+
/** Altezza di riga in px per il calcolo della finestra; se assente viene MISURATA dal DOM */
|
|
7174
|
+
this.VirtualRowHeight = input(undefined, ...(ngDevMode ? [{ debugName: "VirtualRowHeight" }] : []));
|
|
7107
7175
|
this.EmptySpaceBackgroundColor = input('', ...(ngDevMode ? [{ debugName: "EmptySpaceBackgroundColor" }] : []));
|
|
7108
7176
|
this.HighCellDensity = input(false, ...(ngDevMode ? [{ debugName: "HighCellDensity" }] : []));
|
|
7109
7177
|
this.HeaderHidden = input(false, ...(ngDevMode ? [{ debugName: "HeaderHidden" }] : []));
|
|
@@ -7264,6 +7332,53 @@ class EsTable2Component {
|
|
|
7264
7332
|
groupStart: bounds.has(ci)
|
|
7265
7333
|
}));
|
|
7266
7334
|
}, ...(ngDevMode ? [{ debugName: "colStyles" }] : []));
|
|
7335
|
+
// ===========================================================================
|
|
7336
|
+
// Scroll virtuale (opt-in)
|
|
7337
|
+
// ---------------------------------------------------------------------------
|
|
7338
|
+
// Se una qualsiasi misura manca (altezza di riga o del viewport) `virtualWindow`
|
|
7339
|
+
// vale `null` e vengono rese TUTTE le righe: il degrado è verso il comportamento
|
|
7340
|
+
// normale, mai verso una tabella incompleta.
|
|
7341
|
+
// ===========================================================================
|
|
7342
|
+
/** Righe extra rese sopra e sotto il viewport, per non vedere il vuoto durante lo scroll */
|
|
7343
|
+
this.VIRTUAL_OVERSCAN = 8;
|
|
7344
|
+
/** Indice della prima riga della finestra */
|
|
7345
|
+
this.vFirst = signal(0, ...(ngDevMode ? [{ debugName: "vFirst" }] : []));
|
|
7346
|
+
/** Altezza del viewport dello scroller (misurata) */
|
|
7347
|
+
this.vViewportH = signal(0, ...(ngDevMode ? [{ debugName: "vViewportH" }] : []));
|
|
7348
|
+
/** Altezza di riga misurata dal DOM (0 = non ancora nota) */
|
|
7349
|
+
this.vMeasuredRowH = signal(0, ...(ngDevMode ? [{ debugName: "vMeasuredRowH" }] : []));
|
|
7350
|
+
/** Altezza di riga effettiva: input esplicito, altrimenti misura */
|
|
7351
|
+
this.virtualRowH = computed(() => this.VirtualRowHeight() || this.vMeasuredRowH(), ...(ngDevMode ? [{ debugName: "virtualRowH" }] : []));
|
|
7352
|
+
/**
|
|
7353
|
+
* Virtualizzazione attiva. Esclusi raggruppamento e gerarchia: in quelle modalità
|
|
7354
|
+
* il template salta le righe non espanse, quindi la finestra calcolata sugli indici
|
|
7355
|
+
* non corrisponderebbe alle righe effettivamente rese.
|
|
7356
|
+
*/
|
|
7357
|
+
this.virtualActive = computed(() => this.VirtualScroll() && !this.grouped() && !this.Hierarchy(), ...(ngDevMode ? [{ debugName: "virtualActive" }] : []));
|
|
7358
|
+
/** Finestra corrente, o `null` per rendere tutto (fallback sicuro) */
|
|
7359
|
+
this.virtualWindow = computed(() => {
|
|
7360
|
+
if (!this.virtualActive())
|
|
7361
|
+
return null;
|
|
7362
|
+
const total = this.boundSource().length;
|
|
7363
|
+
const h = this.virtualRowH();
|
|
7364
|
+
const vh = this.vViewportH();
|
|
7365
|
+
if (!h || !vh || total === 0)
|
|
7366
|
+
return null; // misure assenti → rendo tutto
|
|
7367
|
+
const perScreen = Math.ceil(vh / h);
|
|
7368
|
+
const start = Math.max(0, this.vFirst());
|
|
7369
|
+
const end = Math.min(total, start + perScreen + this.VIRTUAL_OVERSCAN * 2);
|
|
7370
|
+
if (start === 0 && end >= total)
|
|
7371
|
+
return null; // ci sta tutto: nessuna finestra
|
|
7372
|
+
return { start, end, padTop: start * h, padBottom: (total - end) * h };
|
|
7373
|
+
}, ...(ngDevMode ? [{ debugName: "virtualWindow" }] : []));
|
|
7374
|
+
/** Indice ASSOLUTO della prima riga resa: 0 quando non si virtualizza */
|
|
7375
|
+
this.vStart = computed(() => this.virtualWindow()?.start ?? 0, ...(ngDevMode ? [{ debugName: "vStart" }] : []));
|
|
7376
|
+
/** Righe effettivamente rese: l'intero `boundSource()` se non si virtualizza */
|
|
7377
|
+
this.renderedRows = computed(() => {
|
|
7378
|
+
const w = this.virtualWindow();
|
|
7379
|
+
const rows = this.boundSource();
|
|
7380
|
+
return w ? rows.slice(w.start, w.end) : rows;
|
|
7381
|
+
}, ...(ngDevMode ? [{ debugName: "renderedRows" }] : []));
|
|
7267
7382
|
/** Numero di colonne pinnate visibili */
|
|
7268
7383
|
this.pinnedCount = computed(() => this.visibleColumns().filter(c => c.pinned).length, ...(ngDevMode ? [{ debugName: "pinnedCount" }] : []));
|
|
7269
7384
|
/** true se c'è almeno una colonna pinnata */
|
|
@@ -7344,6 +7459,32 @@ class EsTable2Component {
|
|
|
7344
7459
|
this.updateTimer = null;
|
|
7345
7460
|
/** Ancora per la selezione a range stile Windows (Shift+click) */
|
|
7346
7461
|
this.selectionAnchor = null;
|
|
7462
|
+
/**
|
|
7463
|
+
* Applica il flag _selected alle righe correnti in base allo stato di selezione.
|
|
7464
|
+
* In modalità **all** una riga è selezionata se NON è tra le esclusioni (vale anche
|
|
7465
|
+
* per le pagine non ancora visitate, dove tutte le righe risultano selezionate).
|
|
7466
|
+
*/
|
|
7467
|
+
// ===========================================================================
|
|
7468
|
+
// Cache di selezione (`[UseSelectionCache]`, viewmode)
|
|
7469
|
+
// ---------------------------------------------------------------------------
|
|
7470
|
+
// In viewmode le righe che tornano dal server a ogni pagina sono OGGETTI NUOVI:
|
|
7471
|
+
// confrontarle per riferimento perde la selezione fatta sulle altre pagine. Con
|
|
7472
|
+
// la cache attiva il confronto avviene per CHIAVE, così tornando su una pagina
|
|
7473
|
+
// già visitata le sue righe risultano di nuovo selezionate.
|
|
7474
|
+
// `selection.items`/`exclusions` si riferiscono allora all'INTERA ricerca e non
|
|
7475
|
+
// alla sola pagina corrente: è il contratto documentato su `AppSearch.selection`.
|
|
7476
|
+
// ===========================================================================
|
|
7477
|
+
/** Attiva solo in viewmode: in array mode gli oggetti non cambiano identità */
|
|
7478
|
+
this.selectionCacheOn = computed(() => !!this.UseSelectionCache() && this.viewMode(), ...(ngDevMode ? [{ debugName: "selectionCacheOn" }] : []));
|
|
7479
|
+
/**
|
|
7480
|
+
* Proprietà-identità RILEVATA dai dati, così la cache funziona senza configurare
|
|
7481
|
+
* nulla. Vale per tutta la vita della ricerca: viene ricalcolata solo quando la
|
|
7482
|
+
* selezione riparte, altrimenti una pagina "sfortunata" potrebbe cambiare criterio
|
|
7483
|
+
* a metà strada e far sballare i confronti.
|
|
7484
|
+
*/
|
|
7485
|
+
this.autoKeyProp = signal(null, ...(ngDevMode ? [{ debugName: "autoKeyProp" }] : []));
|
|
7486
|
+
/** true quando la rilevazione è già stata fatta per la ricerca corrente */
|
|
7487
|
+
this.autoKeyResolved = false;
|
|
7347
7488
|
// ===========================================================================
|
|
7348
7489
|
// Fase 5 — Selezione a range (drag cella-per-cella), copia/incolla, editing
|
|
7349
7490
|
//
|
|
@@ -7517,6 +7658,7 @@ class EsTable2Component {
|
|
|
7517
7658
|
ngOnDestroy() {
|
|
7518
7659
|
this.ctxMenuSub?.unsubscribe();
|
|
7519
7660
|
this.headerRO?.disconnect();
|
|
7661
|
+
this.scrollRO?.disconnect();
|
|
7520
7662
|
if (this.noticeTimer)
|
|
7521
7663
|
clearTimeout(this.noticeTimer);
|
|
7522
7664
|
if (this.searchCallTimeout)
|
|
@@ -7571,6 +7713,7 @@ class EsTable2Component {
|
|
|
7571
7713
|
this.researchInProgress.set(false);
|
|
7572
7714
|
this.view.set(obj ?? null);
|
|
7573
7715
|
this.detectMode(obj);
|
|
7716
|
+
this.applySelectionCachePolicy();
|
|
7574
7717
|
this.syncOrdersFromView();
|
|
7575
7718
|
this.refresh();
|
|
7576
7719
|
if (obj)
|
|
@@ -7582,6 +7725,31 @@ class EsTable2Component {
|
|
|
7582
7725
|
// (true su `new AppSearch()`) salta l'auto-ricerca al primo bind.
|
|
7583
7726
|
this.handleWriteValueAutoSearch();
|
|
7584
7727
|
}
|
|
7728
|
+
/**
|
|
7729
|
+
* Decide se la selezione sopravvive al modello appena arrivato. Parità con
|
|
7730
|
+
* l'originale: sopravvive solo alle ricerche INTERNE (cambio pagina, ordinamento,
|
|
7731
|
+
* elementi per pagina), che la tabella marca con `internalsearchrequest`. Una
|
|
7732
|
+
* ricerca dell'utente — filtri cambiati — riparte da selezione vuota, altrimenti
|
|
7733
|
+
* resterebbero selezionate righe che non fanno più parte del risultato.
|
|
7734
|
+
*/
|
|
7735
|
+
applySelectionCachePolicy() {
|
|
7736
|
+
if (!this.viewMode())
|
|
7737
|
+
return;
|
|
7738
|
+
const v = this.view();
|
|
7739
|
+
if (!v)
|
|
7740
|
+
return;
|
|
7741
|
+
const internal = !!v.internalsearchrequest;
|
|
7742
|
+
v.internalsearchrequest = false; // consumata
|
|
7743
|
+
if (this.UseSelectionCache() && v.selection && internal)
|
|
7744
|
+
return;
|
|
7745
|
+
// niente evento se non c'era nulla da azzerare
|
|
7746
|
+
const sel = v.selection;
|
|
7747
|
+
const had = !!sel && (sel.all || (sel.items?.length || 0) > 0 || (sel.exclusions?.length || 0) > 0);
|
|
7748
|
+
this.autoKeyResolved = false; // nuova ricerca → nuova rilevazione
|
|
7749
|
+
if (!had)
|
|
7750
|
+
return;
|
|
7751
|
+
this.resetSelection(true);
|
|
7752
|
+
}
|
|
7585
7753
|
registerOnChange(fn) { this.onChange = fn; }
|
|
7586
7754
|
registerOnTouched(fn) { this.onTouched = fn; }
|
|
7587
7755
|
setDisabledState() { }
|
|
@@ -7984,11 +8152,123 @@ class EsTable2Component {
|
|
|
7984
8152
|
return this.grouped() ? rows.filter(r => r._item) : rows;
|
|
7985
8153
|
}
|
|
7986
8154
|
/**
|
|
7987
|
-
*
|
|
7988
|
-
*
|
|
7989
|
-
*
|
|
8155
|
+
* Identità di una riga ai fini della selezione. A cache SPENTA restituisce
|
|
8156
|
+
* l'oggetto stesso, quindi ogni confronto resta per riferimento e il comportamento
|
|
8157
|
+
* è identico a prima.
|
|
7990
8158
|
*/
|
|
8159
|
+
selKey(item) {
|
|
8160
|
+
if (!this.selectionCacheOn() || item == null)
|
|
8161
|
+
return item;
|
|
8162
|
+
const k = this.SelectionKey();
|
|
8163
|
+
if (typeof k === 'function')
|
|
8164
|
+
return 'k:' + String(k(item));
|
|
8165
|
+
const prop = (typeof k === 'string' && k) ? k : this.autoKeyProp();
|
|
8166
|
+
if (prop)
|
|
8167
|
+
return 'k:' + String(this.readProp(item, prop));
|
|
8168
|
+
return 'h:' + this.contentHash(item);
|
|
8169
|
+
}
|
|
8170
|
+
/**
|
|
8171
|
+
* Cerca una proprietà utilizzabile come identità: prima `[OwnKey]` (che il consumer
|
|
8172
|
+
* ha già dichiarato per la gerarchia), poi una proprietà chiamata `id`. La candidata
|
|
8173
|
+
* viene ACCETTATA solo se sulla pagina è valorizzata ovunque, primitiva e univoca;
|
|
8174
|
+
* altrimenti si ricade sull'hash del contenuto. Meglio nessuna chiave che una
|
|
8175
|
+
* sbagliata: una chiave duplicata selezionerebbe righe diverse insieme.
|
|
8176
|
+
*/
|
|
8177
|
+
resolveAutoKey(items) {
|
|
8178
|
+
if (!items?.length)
|
|
8179
|
+
return null;
|
|
8180
|
+
const src = items[0]?.properties ?? items[0];
|
|
8181
|
+
if (!src || typeof src !== 'object')
|
|
8182
|
+
return null;
|
|
8183
|
+
const own = this.OwnKey();
|
|
8184
|
+
const candidates = [];
|
|
8185
|
+
if (own)
|
|
8186
|
+
candidates.push(own);
|
|
8187
|
+
const idProp = Object.keys(src).find(k => k.toLowerCase() === 'id');
|
|
8188
|
+
if (idProp && idProp !== own)
|
|
8189
|
+
candidates.push(idProp);
|
|
8190
|
+
for (const prop of candidates) {
|
|
8191
|
+
const seen = new Set();
|
|
8192
|
+
let ok = true;
|
|
8193
|
+
for (const it of items) {
|
|
8194
|
+
const v = this.readProp(it, prop);
|
|
8195
|
+
if (v == null || typeof v === 'object' || seen.has(v)) {
|
|
8196
|
+
ok = false;
|
|
8197
|
+
break;
|
|
8198
|
+
}
|
|
8199
|
+
seen.add(v);
|
|
8200
|
+
}
|
|
8201
|
+
if (ok)
|
|
8202
|
+
return prop;
|
|
8203
|
+
}
|
|
8204
|
+
return null;
|
|
8205
|
+
}
|
|
8206
|
+
/** Rileva l'identità una volta per ricerca, prima di applicare i flag di selezione */
|
|
8207
|
+
ensureAutoKey(items) {
|
|
8208
|
+
if (!this.selectionCacheOn() || this.autoKeyResolved)
|
|
8209
|
+
return;
|
|
8210
|
+
if (this.SelectionKey()) {
|
|
8211
|
+
this.autoKeyResolved = true;
|
|
8212
|
+
return;
|
|
8213
|
+
} // scelta esplicita
|
|
8214
|
+
if (!items?.length)
|
|
8215
|
+
return; // riprovo alla prossima pagina
|
|
8216
|
+
this.autoKeyResolved = true;
|
|
8217
|
+
this.autoKeyProp.set(this.resolveAutoKey(items));
|
|
8218
|
+
}
|
|
8219
|
+
/**
|
|
8220
|
+
* Hash stabile del contenuto della riga, ignorando i campi interni (`_selected`,
|
|
8221
|
+
* `_hash`, …). Le chiavi sono ordinate per non dipendere dall'ordine di
|
|
8222
|
+
* serializzazione. È il fallback di parità con l'originale: se il server cambia
|
|
8223
|
+
* anche un solo campo la riga non viene più riconosciuta, per questo conviene
|
|
8224
|
+
* fornire `[SelectionKey]`.
|
|
8225
|
+
*/
|
|
8226
|
+
contentHash(item) {
|
|
8227
|
+
let acc = 5381;
|
|
8228
|
+
const walk = (v) => {
|
|
8229
|
+
if (v == null) {
|
|
8230
|
+
acc = (acc * 33) ^ 1;
|
|
8231
|
+
return;
|
|
8232
|
+
}
|
|
8233
|
+
if (typeof v === 'object') {
|
|
8234
|
+
if (Array.isArray(v)) {
|
|
8235
|
+
for (const e of v)
|
|
8236
|
+
walk(e);
|
|
8237
|
+
return;
|
|
8238
|
+
}
|
|
8239
|
+
for (const key of Object.keys(v).sort()) {
|
|
8240
|
+
if (key.charCodeAt(0) === 95)
|
|
8241
|
+
continue; // salto i campi interni _*
|
|
8242
|
+
for (let i = 0; i < key.length; i++)
|
|
8243
|
+
acc = (acc * 33) ^ key.charCodeAt(i);
|
|
8244
|
+
walk(v[key]);
|
|
8245
|
+
}
|
|
8246
|
+
return;
|
|
8247
|
+
}
|
|
8248
|
+
const str = String(v);
|
|
8249
|
+
for (let i = 0; i < str.length; i++)
|
|
8250
|
+
acc = (acc * 33) ^ str.charCodeAt(i);
|
|
8251
|
+
};
|
|
8252
|
+
walk(item);
|
|
8253
|
+
return (acc >>> 0).toString(36);
|
|
8254
|
+
}
|
|
8255
|
+
/** Aggiunge una riga a una lista di selezione, deduplicando per chiave */
|
|
8256
|
+
selAdd(list, item) {
|
|
8257
|
+
const k = this.selKey(item);
|
|
8258
|
+
const i = list.findIndex(x => this.selKey(x) === k);
|
|
8259
|
+
if (i < 0)
|
|
8260
|
+
list.push(item);
|
|
8261
|
+
else
|
|
8262
|
+
list[i] = item; // sostituisco la copia vecchia con quella fresca
|
|
8263
|
+
return list;
|
|
8264
|
+
}
|
|
8265
|
+
/** Rimuove una riga da una lista di selezione confrontando per chiave */
|
|
8266
|
+
selRemove(list, item) {
|
|
8267
|
+
const k = this.selKey(item);
|
|
8268
|
+
return list.filter(x => this.selKey(x) !== k);
|
|
8269
|
+
}
|
|
7991
8270
|
applySelectionFlags(items, sel) {
|
|
8271
|
+
this.ensureAutoKey(items);
|
|
7992
8272
|
if (!sel) {
|
|
7993
8273
|
for (const it of items)
|
|
7994
8274
|
it._selected = false;
|
|
@@ -7999,9 +8279,13 @@ class EsTable2Component {
|
|
|
7999
8279
|
// O(righe × selezionati): su una tabella array con 5.000 righe tutte
|
|
8000
8280
|
// selezionate erano 25 milioni di confronti per refresh.
|
|
8001
8281
|
const all = !!sel.all;
|
|
8002
|
-
|
|
8003
|
-
|
|
8004
|
-
|
|
8282
|
+
// Con la cache attiva la chiave è una stringa stabile, altrimenti è l'oggetto
|
|
8283
|
+
// stesso: in entrambi i casi il Set resta O(1) e il percorso è lo stesso.
|
|
8284
|
+
const lookup = new Set((all ? sel.exclusions : sel.items).map(i => this.selKey(i)));
|
|
8285
|
+
for (const it of items) {
|
|
8286
|
+
const k = this.selKey(it);
|
|
8287
|
+
it._selected = all ? !lookup.has(k) : lookup.has(k);
|
|
8288
|
+
}
|
|
8005
8289
|
}
|
|
8006
8290
|
/** Ricalcola il conteggio: in modalità **all** è (totale - esclusioni) */
|
|
8007
8291
|
refreshSelectionCount(sel) {
|
|
@@ -8033,19 +8317,17 @@ class EsTable2Component {
|
|
|
8033
8317
|
// "Tutto selezionato": deselezionare = aggiungere alle esclusioni
|
|
8034
8318
|
item._selected = !item._selected;
|
|
8035
8319
|
if (item._selected)
|
|
8036
|
-
sel.exclusions = sel.exclusions
|
|
8037
|
-
else
|
|
8038
|
-
sel.exclusions
|
|
8320
|
+
sel.exclusions = this.selRemove(sel.exclusions, item);
|
|
8321
|
+
else
|
|
8322
|
+
this.selAdd(sel.exclusions, item);
|
|
8039
8323
|
this.selectionAnchor = item;
|
|
8040
8324
|
}
|
|
8041
8325
|
else {
|
|
8042
8326
|
item._selected = !item._selected;
|
|
8043
|
-
if (item._selected)
|
|
8044
|
-
|
|
8045
|
-
sel.items.push(item);
|
|
8046
|
-
}
|
|
8327
|
+
if (item._selected)
|
|
8328
|
+
this.selAdd(sel.items, item);
|
|
8047
8329
|
else
|
|
8048
|
-
sel.items = sel.items
|
|
8330
|
+
sel.items = this.selRemove(sel.items, item);
|
|
8049
8331
|
this.selectionAnchor = item;
|
|
8050
8332
|
}
|
|
8051
8333
|
this.refreshSelectionCount(sel);
|
|
@@ -8064,14 +8346,33 @@ class EsTable2Component {
|
|
|
8064
8346
|
const rows = this.selectableRows();
|
|
8065
8347
|
const pageFully = !sel.all && rows.length > 0 && rows.every(r => r._selected);
|
|
8066
8348
|
if (sel.all || pageFully) {
|
|
8067
|
-
this.
|
|
8349
|
+
if (this.selectionCacheOn() && !sel.all) {
|
|
8350
|
+
// Con la cache la check di testata vale per la PAGINA: deselezionandola le
|
|
8351
|
+
// righe scelte sulle altre pagine devono restare.
|
|
8352
|
+
const drop = new Set(rows.map(r => this.selKey(r)));
|
|
8353
|
+
sel.items = sel.items.filter(i => !drop.has(this.selKey(i)));
|
|
8354
|
+
for (const r of rows)
|
|
8355
|
+
r._selected = false;
|
|
8356
|
+
}
|
|
8357
|
+
else {
|
|
8358
|
+
this.clearSelectionState(sel);
|
|
8359
|
+
}
|
|
8068
8360
|
}
|
|
8069
8361
|
else {
|
|
8070
8362
|
sel.all = false;
|
|
8071
8363
|
sel.exclusions = [];
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
r
|
|
8364
|
+
if (this.selectionCacheOn()) {
|
|
8365
|
+
// sommo la pagina a quanto già selezionato altrove
|
|
8366
|
+
for (const r of rows) {
|
|
8367
|
+
r._selected = true;
|
|
8368
|
+
this.selAdd(sel.items, r);
|
|
8369
|
+
}
|
|
8370
|
+
}
|
|
8371
|
+
else {
|
|
8372
|
+
sel.items = [...rows];
|
|
8373
|
+
for (const r of rows)
|
|
8374
|
+
r._selected = true;
|
|
8375
|
+
}
|
|
8075
8376
|
}
|
|
8076
8377
|
this.refreshSelectionCount(sel);
|
|
8077
8378
|
this.syncGlobalCheck();
|
|
@@ -8184,12 +8485,13 @@ class EsTable2Component {
|
|
|
8184
8485
|
sel.items = [];
|
|
8185
8486
|
}
|
|
8186
8487
|
// Set per il dedup: `sel.items.includes` dentro il ciclo rendeva il range O(righe²)
|
|
8187
|
-
const have = new Set(sel.items);
|
|
8488
|
+
const have = new Set(sel.items.map(i => this.selKey(i)));
|
|
8188
8489
|
for (let i = lo; i <= hi; i++) {
|
|
8189
8490
|
const r = rows[i];
|
|
8190
8491
|
r._selected = true;
|
|
8191
|
-
|
|
8192
|
-
|
|
8492
|
+
const k = this.selKey(r);
|
|
8493
|
+
if (!have.has(k)) {
|
|
8494
|
+
have.add(k);
|
|
8193
8495
|
sel.items.push(r);
|
|
8194
8496
|
}
|
|
8195
8497
|
}
|
|
@@ -8545,21 +8847,23 @@ class EsTable2Component {
|
|
|
8545
8847
|
const target = sel.all ? sel.exclusions : sel.items; // in modalità "tutto" si accumulano esclusioni
|
|
8546
8848
|
if (select === sel.all) {
|
|
8547
8849
|
// rimuovo gli item dalla lista di destinazione
|
|
8548
|
-
const drop = new Set(items);
|
|
8549
|
-
const kept = target.filter(i => !drop.has(i));
|
|
8850
|
+
const drop = new Set(items.map(i => this.selKey(i)));
|
|
8851
|
+
const kept = target.filter(i => !drop.has(this.selKey(i)));
|
|
8550
8852
|
if (sel.all)
|
|
8551
8853
|
sel.exclusions = kept;
|
|
8552
8854
|
else
|
|
8553
8855
|
sel.items = kept;
|
|
8554
8856
|
}
|
|
8555
8857
|
else {
|
|
8556
|
-
// li aggiungo (dedup
|
|
8557
|
-
const have = new Set(target);
|
|
8558
|
-
for (const it of items)
|
|
8559
|
-
|
|
8560
|
-
|
|
8858
|
+
// li aggiungo (dedup per chiave, senza scandire l'array a ogni push)
|
|
8859
|
+
const have = new Set(target.map(i => this.selKey(i)));
|
|
8860
|
+
for (const it of items) {
|
|
8861
|
+
const k = this.selKey(it);
|
|
8862
|
+
if (!have.has(k)) {
|
|
8863
|
+
have.add(k);
|
|
8561
8864
|
target.push(it);
|
|
8562
8865
|
}
|
|
8866
|
+
}
|
|
8563
8867
|
}
|
|
8564
8868
|
this.refreshSelectionCount(sel);
|
|
8565
8869
|
this.syncGlobalCheck();
|
|
@@ -9581,11 +9885,11 @@ class EsTable2Component {
|
|
|
9581
9885
|
this.saveColumnPrefs();
|
|
9582
9886
|
}
|
|
9583
9887
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: EsTable2Component, deps: [{ token: i1.NgControl, optional: true, self: true }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i2.PreferencesService, optional: true }, { token: i0.Injector }, { token: i3.LocalizationService }, { token: EST2_DEFAULTS, optional: true }, { token: EST2_DEBUG, optional: true }, { token: EST2_EXPORT_GLOBAL_ACL, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9584
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: EsTable2Component, isStandalone: false, selector: "es-table2", inputs: { ContextMenu: { classPropertyName: "ContextMenu", publicName: "ContextMenu", isSignal: false, isRequired: false, transformFunction: null }, _Selection: { classPropertyName: "_Selection", publicName: "Selection", isSignal: true, isRequired: false, transformFunction: null }, SingleSelection: { classPropertyName: "SingleSelection", publicName: "SingleSelection", isSignal: true, isRequired: false, transformFunction: null }, SelectionDisabled: { classPropertyName: "SelectionDisabled", publicName: "SelectionDisabled", isSignal: true, isRequired: false, transformFunction: null }, _SelectAll: { classPropertyName: "_SelectAll", publicName: "SelectAll", isSignal: true, isRequired: false, transformFunction: null }, _UseSelectionCache: { classPropertyName: "_UseSelectionCache", publicName: "UseSelectionCache", isSignal: true, isRequired: false, transformFunction: null }, _ShiftClick: { classPropertyName: "_ShiftClick", publicName: "ShiftClick", isSignal: true, isRequired: false, transformFunction: null }, _OrderByColumn: { classPropertyName: "_OrderByColumn", publicName: "OrderByColumn", isSignal: true, isRequired: false, transformFunction: null }, MultipleOrderingDirectives: { classPropertyName: "MultipleOrderingDirectives", publicName: "MultipleOrderingDirectives", isSignal: true, isRequired: false, transformFunction: null }, Removal: { classPropertyName: "Removal", publicName: "Removal", isSignal: true, isRequired: false, transformFunction: null }, RemovalCondition: { classPropertyName: "RemovalCondition", publicName: "RemovalCondition", isSignal: true, isRequired: false, transformFunction: null }, RowClassAssigner: { classPropertyName: "RowClassAssigner", publicName: "RowClassAssigner", isSignal: false, isRequired: false, transformFunction: null }, _HidePaging: { classPropertyName: "_HidePaging", publicName: "HidePaging", isSignal: true, isRequired: false, transformFunction: null }, _HidePagingCount: { classPropertyName: "_HidePagingCount", publicName: "HidePagingCount", isSignal: true, isRequired: false, transformFunction: null }, _HidePagingButtons: { classPropertyName: "_HidePagingButtons", publicName: "HidePagingButtons", isSignal: true, isRequired: false, transformFunction: null }, _AllSearch: { classPropertyName: "_AllSearch", publicName: "AllSearch", isSignal: true, isRequired: false, transformFunction: null }, _PagingStyle: { classPropertyName: "_PagingStyle", publicName: "PagingStyle", isSignal: true, isRequired: false, transformFunction: null }, _ArraymodeItemsPerPage: { classPropertyName: "_ArraymodeItemsPerPage", publicName: "ArraymodeItemsPerPage", isSignal: true, isRequired: false, transformFunction: null }, _UseArrayModePaging: { classPropertyName: "_UseArrayModePaging", publicName: "UseArrayModePaging", isSignal: true, isRequired: false, transformFunction: null }, CountLabel: { classPropertyName: "CountLabel", publicName: "CountLabel", isSignal: true, isRequired: false, transformFunction: null }, Height: { classPropertyName: "Height", publicName: "Height", isSignal: true, isRequired: false, transformFunction: null }, MaxHeight: { classPropertyName: "MaxHeight", publicName: "MaxHeight", isSignal: true, isRequired: false, transformFunction: null }, EmptySpaceBackgroundColor: { classPropertyName: "EmptySpaceBackgroundColor", publicName: "EmptySpaceBackgroundColor", isSignal: true, isRequired: false, transformFunction: null }, HighCellDensity: { classPropertyName: "HighCellDensity", publicName: "HighCellDensity", isSignal: true, isRequired: false, transformFunction: null }, HeaderHidden: { classPropertyName: "HeaderHidden", publicName: "HeaderHidden", isSignal: true, isRequired: false, transformFunction: null }, BodyHidden: { classPropertyName: "BodyHidden", publicName: "BodyHidden", isSignal: true, isRequired: false, transformFunction: null }, ShowLoadingOnBootstrap: { classPropertyName: "ShowLoadingOnBootstrap", publicName: "ShowLoadingOnBootstrap", isSignal: true, isRequired: false, transformFunction: null }, _DefaultAlignment: { classPropertyName: "_DefaultAlignment", publicName: "DefaultAlignment", isSignal: true, isRequired: false, transformFunction: null }, _TableClass: { classPropertyName: "_TableClass", publicName: "TableClass", isSignal: true, isRequired: false, transformFunction: null }, _ContainerClass: { classPropertyName: "_ContainerClass", publicName: "ContainerClass", isSignal: true, isRequired: false, transformFunction: null }, EsTableHandledSearch: { classPropertyName: "EsTableHandledSearch", publicName: "EsTableHandledSearch", isSignal: true, isRequired: false, transformFunction: null }, SearchThrottle: { classPropertyName: "SearchThrottle", publicName: "SearchThrottle", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsResizable: { classPropertyName: "_ColumnsResizable", publicName: "ColumnsResizable", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsPinnable: { classPropertyName: "_ColumnsPinnable", publicName: "ColumnsPinnable", isSignal: true, isRequired: false, transformFunction: null }, _HiddenColumns: { classPropertyName: "_HiddenColumns", publicName: "HiddenColumns", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsOrdering: { classPropertyName: "_ColumnsOrdering", publicName: "ColumnsOrdering", isSignal: true, isRequired: false, transformFunction: null }, _Export: { classPropertyName: "_Export", publicName: "Export", isSignal: true, isRequired: false, transformFunction: null }, XLSXExport: { classPropertyName: "XLSXExport", publicName: "XLSXExport", isSignal: true, isRequired: false, transformFunction: null }, CSVExport: { classPropertyName: "CSVExport", publicName: "CSVExport", isSignal: true, isRequired: false, transformFunction: null }, ExportFileName: { classPropertyName: "ExportFileName", publicName: "ExportFileName", isSignal: true, isRequired: false, transformFunction: null }, ExportOnlyVisibleColumns: { classPropertyName: "ExportOnlyVisibleColumns", publicName: "ExportOnlyVisibleColumns", isSignal: true, isRequired: false, transformFunction: null }, ExportFunction: { classPropertyName: "ExportFunction", publicName: "ExportFunction", isSignal: false, isRequired: false, transformFunction: null }, CornerMenuOptions: { classPropertyName: "CornerMenuOptions", publicName: "CornerMenuOptions", isSignal: true, isRequired: false, transformFunction: null }, DynamicOperations: { classPropertyName: "DynamicOperations", publicName: "DynamicOperations", isSignal: true, isRequired: false, transformFunction: null }, _DynamicRowColumnsDefinition: { classPropertyName: "_DynamicRowColumnsDefinition", publicName: "DynamicRowColumnsDefinition", isSignal: true, isRequired: false, transformFunction: null }, Hierarchy: { classPropertyName: "Hierarchy", publicName: "Hierarchy", isSignal: true, isRequired: false, transformFunction: null }, _ParentKey: { classPropertyName: "_ParentKey", publicName: "ParentKey", isSignal: true, isRequired: false, transformFunction: null }, _OwnKey: { classPropertyName: "_OwnKey", publicName: "OwnKey", isSignal: true, isRequired: false, transformFunction: null }, _AutoSortHierarchy: { classPropertyName: "_AutoSortHierarchy", publicName: "AutoSortHierarchy", isSignal: true, isRequired: false, transformFunction: null }, StartsExpanded: { classPropertyName: "StartsExpanded", publicName: "StartsExpanded", isSignal: true, isRequired: false, transformFunction: null }, CascadeSelection: { classPropertyName: "CascadeSelection", publicName: "CascadeSelection", isSignal: true, isRequired: false, transformFunction: null }, _SavePreferences: { classPropertyName: "_SavePreferences", publicName: "SavePreferences", isSignal: true, isRequired: false, transformFunction: null }, Name: { classPropertyName: "Name", publicName: "Name", isSignal: true, isRequired: false, transformFunction: null }, _RowGroupingPagingStyle: { classPropertyName: "_RowGroupingPagingStyle", publicName: "RowGroupingPagingStyle", isSignal: true, isRequired: false, transformFunction: null }, _ShowItemGroupsColumns: { classPropertyName: "_ShowItemGroupsColumns", publicName: "ShowItemGroupsColumns", isSignal: true, isRequired: false, transformFunction: null }, Editable: { classPropertyName: "Editable", publicName: "Editable", isSignal: true, isRequired: false, transformFunction: null }, RangeSelection: { classPropertyName: "RangeSelection", publicName: "RangeSelection", isSignal: true, isRequired: false, transformFunction: null }, ItemSourceProperty: { classPropertyName: "ItemSourceProperty", publicName: "ItemSourceProperty", isSignal: true, isRequired: false, transformFunction: null }, HasHeaderGroup: { classPropertyName: "HasHeaderGroup", publicName: "HasHeaderGroup", isSignal: true, isRequired: false, transformFunction: null }, HasSecondaryHeaderGroup: { classPropertyName: "HasSecondaryHeaderGroup", publicName: "HasSecondaryHeaderGroup", isSignal: true, isRequired: false, transformFunction: null }, SearchView: { classPropertyName: "SearchView", publicName: "SearchView", isSignal: true, isRequired: false, transformFunction: null }, _AutoUpdate: { classPropertyName: "_AutoUpdate", publicName: "AutoUpdate", isSignal: true, isRequired: false, transformFunction: null }, EsThTdProvider: { classPropertyName: "EsThTdProvider", publicName: "EsThTdProvider", isSignal: false, isRequired: false, transformFunction: null }, globalCheck: { classPropertyName: "globalCheck", publicName: "globalCheck", isSignal: true, isRequired: false, transformFunction: null }, autoUpdate: { classPropertyName: "autoUpdate", publicName: "autoUpdate", isSignal: true, isRequired: false, transformFunction: null }, seconds: { classPropertyName: "seconds", publicName: "seconds", isSignal: true, isRequired: false, transformFunction: null }, researchInProgress: { classPropertyName: "researchInProgress", publicName: "researchInProgress", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onOrderChanged: "onOrderChanged", onSearchRequest: "onSearchRequest", onSelectionChanged: "onSelectionChanged", onRemoval: "onRemoval", onAbortRemoval: "onAbortRemoval", onModelChange: "onModelChange", onOpenContextMenu: "onOpenContextMenu", onCornerAction: "onCornerAction", onDynamicOperation: "onDynamicOperation", globalCheck: "globalCheckChange", autoUpdate: "autoUpdateChange", seconds: "secondsChange", researchInProgress: "researchInProgressChange" }, host: { listeners: { "document:mouseup": "onResizeEnd()", "document:copy": "onDocCopy($event)", "document:paste": "onDocPaste($event)", "document:click": "onDocClick()", "window:resize": "onViewportResize()", "document:mousemove": "onResizeMove($event)" }, properties: { "class.est2": "this.hostClass", "class.est2--dense": "this.denseClass" } }, queries: [{ propertyName: "headerRef", first: true, predicate: ["header"], descendants: true }, { propertyName: "bodyRef", first: true, predicate: ["body"], descendants: true }, { propertyName: "thDirectives", predicate: EsThDirective }, { propertyName: "tdDirectives", predicate: EsTdDirective }, { propertyName: "editorDirectives", predicate: EsTdEditorDirective }, { propertyName: "thTdProviders", predicate: ThTdProvider }], viewQueries: [{ propertyName: "tableEmptyMenu", first: true, predicate: ["emptyMenu"], descendants: true, static: true }, { propertyName: "theadRef", first: true, predicate: ["theadRef"], descendants: true }, { propertyName: "dialogBackdropRef", first: true, predicate: ["dialogBackdrop"], descendants: true }], ngImport: i0, template: "@if (view()) {\n <div class=\"est2-wrap {{ ContainerClass() }}\"\n [style.height]=\"Height()\"\n [style.background-color]=\"EmptySpaceBackgroundColor() || null\">\n\n <!-- Auto-aggiornamento: toggle + intervallo (in alto a destra) -->\n @if (AutoUpdate()) {\n <div class=\"est2-autoupdate\">\n <label class=\"est2-autoupdate__label\">\n {{ 'Update every' | localize : lc }}\n <input type=\"text\" maxlength=\"3\" class=\"est2-autoupdate__secs\"\n [ngModel]=\"seconds()\" (ngModelChange)=\"seconds.set($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n (change)=\"autoUpdateChanged()\" />\n {{ 'second/s' | localize : lc }}\n </label>\n <label class=\"est2-switch\" [title]=\"'Toggle auto-update' | localize : lc\">\n <input type=\"checkbox\" [ngModel]=\"autoUpdate()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"autoUpdate.set($event); autoUpdateChanged()\" />\n <span class=\"est2-switch__slider\"></span>\n </label>\n </div>\n }\n\n <!-- Pager superiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'top') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Host POSIZIONATO dello scroller: \u00E8 l'ancora di tutti gli overlay che devono\n coprire la TABELLA (barra di selezione, overlay di caricamento). Senza di esso\n erano ancorati a `.est2-wrap` e con [AutoUpdate] o il pager in alto finivano\n sopra quei controlli invece che sopra l'header. -->\n <div class=\"est2-scroll-host\">\n\n <!-- Barra \"seleziona tutto\" (visibile solo con selezione multipla attiva e righe presenti) -->\n @if (Selection() && !SingleSelection() && hasSelection) {\n <div class=\"est2-selectbar\"\n [class.est2-selectbar--inset]=\"chromeWidth() > 0\"\n [style.height.px]=\"selbarHeight() ? selbarHeight() + 1 : null\"\n [style.right.px]=\"chromeWidth() || null\">\n @if (allSelected) {\n <span>{{ 'All the' | localize : lc }} <strong>{{ selectedCount }}</strong> {{ 'elements are selected' | localize : lc }}</span>\n } @else {\n <span><strong>{{ selectedCount }}</strong> {{ (selectedCount === 1 ? 'element selected' : 'elements selected') | localize : lc }}</span>\n @if (canSelectEverything) {\n <span class=\"est2-link\" (click)=\"selectEverything()\">{{ 'Select all' | localize : lc }} {{ totalCount() }} {{ 'elements' | localize : lc }}</span>\n }\n }\n <span class=\"est2-selectbar__spacer\"></span>\n <span class=\"est2-link\" (click)=\"clearSelection()\">{{ 'Reset selection' | localize : lc }}</span>\n </div>\n }\n\n <div class=\"est2-scroll\" [style.max-height.px]=\"MaxHeight()\">\n <table class=\"est2-table {{ TableClass() }}\"\n [class.est2-table--range]=\"rangeActive()\"\n [class.est2-table--dragging]=\"rangeDragging()\"\n (mousedown)=\"onGridMouseDown($event)\"\n (mouseover)=\"onGridMouseOver($event)\">\n\n <!-- ================= HEADER ================= -->\n @if (!HeaderHidden()) {\n <thead #theadRef>\n <!-- Righe di header-group multi-livello (dall'alto verso il basso) -->\n @if (hasHeaderGroups()) {\n @for (grow of headerGroupRows(); track $index) {\n <tr class=\"est2-hgroup-row\">\n @if (Selection()) { <th class=\"est2-col-min est2-selcol\" [class.est2-pinned]=\"hasPinned()\" [style.left.px]=\"hasPinned() ? 0 : null\"></th> }\n @for (op of DynamicOperations(); track op.id) { <th class=\"est2-col-min\"></th> }\n @for (cell of grow; track cell.id; let gi = $index) {\n <th [attr.colspan]=\"cell.span\"\n [attr.data-groupid]=\"cell.isGroup ? cell.id : null\"\n [class.est2-hgroup]=\"cell.isGroup\"\n [class.est2-pinned]=\"gi < pinnedCount()\"\n [style.left.px]=\"gi < pinnedCount() ? pinnedLeftPx(gi) : null\"\n class=\"est2-hgroup-cell\">\n @if (cell.isGroup) {\n @if (cell.template) {\n <ng-container *ngTemplateOutlet=\"cell.template\"></ng-container>\n } @else {\n {{ cell.label }}\n }\n }\n </th>\n }\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n @if (hasChrome()) { <th class=\"est2-col-min est2-chrome-col\"></th> }\n </tr>\n }\n }\n <tr>\n <!-- Colonna di selezione -->\n @if (Selection()) {\n <th class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"globalCheck()\"\n [indeterminate]=\"selectionIndeterminate\"\n [disabled]=\"SelectionDisabled()\"\n (change)=\"toggleAll()\"\n [attr.aria-label]=\"'Select all rows' | localize : lc\" />\n }\n </th>\n }\n\n <!-- Header da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- intestazioni vuote per le operazioni dinamiche -->\n @for (op of DynamicOperations(); track op.id) {\n <th class=\"est2-col-min\"></th>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let ci = $index) {\n @let hs = colStyles()[ci];\n <th [attr.data-colid]=\"col.id\"\n [class]=\"col.headerClass\"\n [class.est2-th--orderable]=\"OrderByColumn() && col.orderable\"\n [class.est2-col-min]=\"col.header?.thShrink\"\n [class.est2-col-groupstart]=\"hs.groupStart\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"hs.left\"\n [style.width.px]=\"hs.width\"\n [style.min-width.px]=\"hs.width\"\n [style.max-width.px]=\"hs.width\"\n [style.text-align]=\"col.alignment\"\n [style.background-color]=\"col.headerBg || null\"\n (click)=\"toggleSort(col)\">\n <span class=\"est2-th__inner\">\n @if (col.header?.Template) {\n <ng-container *ngTemplateOutlet=\"col.header!.Template!; context: col.multiProp != null ? { $implicit: col.headerText } : null\"></ng-container>\n } @else {\n {{ col.headerText }}\n }\n @if (OrderByColumn() && col.orderable && orderOf(col.id)) {\n <span class=\"est2-sort est2-sort--active\"\n [class.est2-sort--desc]=\"orderOf(col.id) === 'DESC'\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6 15l6-6 6 6\"/></svg>\n </span>\n @if (orderIndex(col.id) > 0 && MultipleOrderingDirectives()) {\n <span class=\"est2-sort__badge\">{{ orderIndex(col.id) }}</span>\n }\n }\n <!-- Indicatore/toggle di pin (visibile se pinnata o all'hover) -->\n @if (ColumnsPinnable() && col.multiProp == null && !col.fixed) {\n <button type=\"button\" class=\"est2-pinbtn\"\n [class.est2-pinbtn--on]=\"col.pinned\"\n [title]=\"(col.pinned ? 'Unlock column' : 'Lock column to the left') | localize : lc\"\n (click)=\"togglePin(col, $event)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n </span>\n <!-- Handle di ridimensionamento (colonne pinnate, gated da ColumnsResizable) -->\n @if (col.pinned || ColumnsResizable()) {\n <span class=\"est2-resize-handle\" [title]=\"'Drag to resize' | localize : lc\"\n (mousedown)=\"startColumnResize(col, $event)\"\n (click)=\"$event.stopPropagation()\"></span>\n }\n </th>\n }\n }\n <!-- Header da template semplice -->\n @else if (headerRef) {\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\n }\n\n <!-- Colonna rimozione -->\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n <!-- Colonna chrome (export / gestione colonne / menu) -->\n @if (hasChrome()) {\n <th class=\"est2-col-min est2-chrome-th est2-chrome-col\">\n <div class=\"est2-chrome\">\n <!-- I pannelli dei menu NON vivono qui: sono renderizzati a fondo\n componente e posizionati `fixed`, altrimenti l'`overflow:auto`\n di `.est2-scroll` li taglierebbe su tabelle basse. -->\n @if (Export()) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Export' | localize : lc\" (click)=\"$event.stopPropagation(); toggleExportMenu($event)\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><path d=\"M7 10l5 5 5-5\"/><path d=\"M12 15V3\"/></svg>\n </button>\n }\n @if (HiddenColumns() || ColumnsOrdering()) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Columns' | localize : lc\" (click)=\"$event.stopPropagation(); openColumnsDialog()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><path d=\"M9 3v18\"/><path d=\"M15 3v18\"/></svg>\n </button>\n }\n @if (CornerMenuOptions().length > 0) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Options' | localize : lc\" (click)=\"$event.stopPropagation(); toggleCornerMenu($event)\">\u22EE</button>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n }\n\n <!-- ================= BODY ================= -->\n @if (!BodyHidden()) {\n <tbody>\n <!-- Valori invarianti per l'intero corpo: senza questi verrebbero\n ricalcolati riga\u00D7colonna volte a ogni ciclo di change-detection. -->\n @let rng = rangeActive();\n @let rect = rangeRect();\n @let errs = hasCellErrors();\n @for (item of boundSource(); track trackRow($index, item); let ri = $index) {\n @if ((!grouped() && !Hierarchy()) || item._visible) {\n <tr [class]=\"rowClass(item)\"\n [class.est2-row--selected]=\"item._selected\"\n [class.est2-row--removed]=\"item.removed || item.deleted\"\n [class.est2-row--group]=\"item._group\"\n [class.est2-row--clickable]=\"Selection() || item._group\"\n [contextMenu]=\"ContextMenu || emptyMenu\"\n [contextMenuSubject]=\"item\"\n (click)=\"handleRowClick(item, $event)\">\n\n <!-- Cella di selezione -->\n @if (Selection()) {\n <td class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (item._group) {\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"groupSelectionState(item) === 'all'\"\n [indeterminate]=\"groupSelectionState(item) === 'some'\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection(item)\"\n [attr.aria-label]=\"'Select group' | localize : lc\" />\n }\n } @else {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"item._selected\"\n [indeterminate]=\"hierarchyIndeterminate(item)\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(item)\"\n [attr.aria-label]=\"'Select row' | localize : lc\" />\n }\n </td>\n }\n\n <!-- Celle da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- Operazioni dinamiche (icone a sinistra) -->\n @for (op of DynamicOperations(); track op.id) {\n <td class=\"est2-col-min est2-op-cell\">\n @if (!item._group && operationVisible(op, item)) {\n <span class=\"est2-op\" [class]=\"op.iconClass || ''\" [title]=\"op.title\"\n (click)=\"$event.stopPropagation(); dynamicOperation(item, op.id)\">{{ op.text }}</span>\n }\n </td>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let first = $first, ci = $index) {\n @let cs = colStyles()[ci];\n @let insel = rng && inRange(ri, ci);\n @let editing = isEditing(ri, ci);\n <td [class]=\"col.cssClass\"\n [style.text-align]=\"col.alignment\"\n [style.color]=\"cellColor(item, col, 'fore')\"\n [style.background-color]=\"cellColor(item, col, 'back')\"\n [class.est2-nowrap]=\"!col.wrap\"\n [class.est2-col-groupstart]=\"cs.groupStart\"\n [class.est2-pinned]=\"col.pinned\"\n [class.est2-fixedw]=\"cs.width != null\"\n [style.left.px]=\"cs.left\"\n [style.width.px]=\"cs.width\"\n [style.min-width.px]=\"cs.width\"\n [style.max-width.px]=\"cs.width\"\n [class.est2-td--group-key]=\"item._group && item.column === col.id\"\n [attr.data-r]=\"rng && !item._group ? ri : null\"\n [attr.data-c]=\"rng && !item._group ? ci : null\"\n [class.est2-cell-sel]=\"insel\"\n [class.est2-cell-sel-t]=\"insel && ri === rect!.top\"\n [class.est2-cell-sel-b]=\"insel && ri === rect!.bottom\"\n [class.est2-cell-sel-l]=\"insel && ci === rect!.left\"\n [class.est2-cell-sel-r]=\"insel && ci === rect!.right\"\n [class.est2-cell-editing]=\"editing\"\n [class.est2-cell-invalid]=\"errs && !!cellError(item, col)\"\n [attr.data-error]=\"errs ? (cellError(item, col) || null) : null\"\n (dblclick)=\"onCellDblClick(item, col, ri, ci)\">\n @if (editing) {\n @if (editorFor(col); as edTpl) {\n <ng-container *ngTemplateOutlet=\"edTpl; context: editorContext(item, col)\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"defaultEditor; context: { $implicit: item, col: col }\"></ng-container>\n }\n } @else if (item._group) {\n @if (item.column === col.id) {\n <span class=\"est2-group-key\" [style.padding-left.px]=\"groupIndent(item)\">\n <span class=\"est2-group-chevron\" [class.est2-group-chevron--open]=\"item._expanded\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n {{ groupCellDisplay(item, col) }}\n </span>\n } @else {\n {{ groupCellDisplay(item, col) }}\n }\n } @else {\n <!-- Navigatore albero nella prima colonna -->\n @if (Hierarchy() && first) {\n <span class=\"est2-hier-lead\" [style.padding-left.px]=\"hierarchyIndent(item)\">\n @if (item.parent) {\n <span class=\"est2-group-chevron est2-hier-toggle\" [class.est2-group-chevron--open]=\"item._expanded\"\n (click)=\"$event.stopPropagation(); toggleHierarchyNode(item)\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-hier-toggle\"></span>\n }\n </span>\n }\n @if (itemCellHidden(col)) {\n <!-- colonna di gruppo nascosta sulla riga-oggetto -->\n } @else if (col.multiProp != null) {\n @if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: multiCell(item, col) }\"></ng-container>\n } @else {\n {{ multiCell(item, col)?.value }}\n }\n } @else if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: item }\"></ng-container>\n } @else if (col.routePath) {\n <a class=\"est2-link\" [routerLink]=\"routerLinkFor(item, col)\">{{ cellValue(item, col) }}</a>\n } @else if (col.propAccessor != null) {\n {{ reportCellDisplay(item, col) }}\n } @else if (col.type === 'enum') {\n {{ (cellValue(item, col) | est2_lookup : col.source).description }}\n } @else {\n {{ cellValue(item, col) | est2_format : col.type : col.format : locale }}\n }\n }\n </td>\n }\n }\n <!-- Celle da template semplice -->\n @else if (bodyRef) {\n <ng-container *ngTemplateOutlet=\"bodyRef; context: { $implicit: item }\"></ng-container>\n }\n\n <!-- Rimozione (non sulle righe-gruppo) -->\n @if (Removal()) {\n <td class=\"est2-col-min\">\n @if (!item._group && canRemove(item)) {\n @if (item.removed || item.deleted) {\n <button type=\"button\" class=\"est2-rowaction\" [title]=\"'Restore' | localize : lc\" (click)=\"abortRemoval(item)\">\u21BA</button>\n } @else {\n <button type=\"button\" class=\"est2-rowaction est2-rowaction--danger\" [title]=\"'Remove' | localize : lc\" (click)=\"removeItem(item)\">\u2715</button>\n }\n }\n </td>\n }\n <!-- Chrome -->\n @if (hasChrome()) { <td class=\"est2-col-min est2-chrome-col\"></td> }\n </tr>\n }\n } @empty {\n <tr>\n <td class=\"est2-empty\" [attr.colspan]=\"totalColspan()\">{{ 'No elements to display' | localize : lc }}</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\n\n <!-- Overlay di caricamento: FUORI dallo scroller, cos\u00EC copre il viewport della\n tabella senza scorrere col contenuto e senza essere bucato dalle celle sticky -->\n @if (researchInProgress() || (firstBind() && ShowLoadingOnBootstrap())) {\n <div class=\"est2-loading\">\n <span class=\"est2-spinner\"></span>\n <span>{{ 'Loading\u2026' | localize : lc }}</span>\n </div>\n }\n\n </div>\n\n <!-- Pager inferiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Menu del chrome (export / opzioni). Renderizzati FUORI da `.est2-scroll` e\n posizionati `fixed` sulle coordinate del bottone che li ha aperti: cos\u00EC non\n vengono tagliati dall'`overflow:auto` dello scroller su tabelle basse, e\n restano dentro `.est2` (i token `--est-*` continuano a ereditare). -->\n @if (exportMenuOpen() && menuAnchor(); as anchor) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\"\n [style.top.px]=\"anchor.top\" [style.right.px]=\"anchor.right\">\n @if (CSVExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">{{ 'Export CSV' | localize : lc }}</button> }\n @if (XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('XLSX')\">{{ 'Export Excel (XLSX)' | localize : lc }}</button> }\n @if (!CSVExport() && !XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">{{ 'Export CSV' | localize : lc }}</button> }\n </div>\n }\n @if (cornerMenuOpen() && menuAnchor(); as anchor) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\"\n [style.top.px]=\"anchor.top\" [style.right.px]=\"anchor.right\">\n @for (opt of CornerMenuOptions(); track opt.id) {\n <button type=\"button\" class=\"est2-menu-item\" (click)=\"cornerAction(opt.id); closeChromeMenus()\">{{ opt.description }}</button>\n }\n </div>\n }\n\n <!-- Avviso transitorio (es. incolla con dimensioni incompatibili) -->\n @if (notice()) {\n <div class=\"est2-toast\" role=\"alert\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/></svg>\n <span>{{ notice() }}</span>\n </div>\n }\n\n <!-- Dialog visibilit\u00E0 / ordine colonne -->\n @if (columnsDialogOpen()) {\n <div class=\"est2-dialog-backdrop\" #dialogBackdrop\n [class.est2-dialog-backdrop--embedded]=\"embedded\"\n (click)=\"closeColumnsDialog()\">\n <div class=\"est2-dialog\" (click)=\"$event.stopPropagation()\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"est2-dialog__head\">\n <span>\n @if (HiddenColumns() && ColumnsOrdering()) { {{ 'Columns visibility and order' | localize : lc }} }\n @else if (HiddenColumns()) { {{ 'Columns visibility' | localize : lc }} }\n @else { {{ 'Columns order' | localize : lc }} }\n </span>\n <button type=\"button\" class=\"est2-dialog__close\" (click)=\"closeColumnsDialog()\" [attr.aria-label]=\"'Close' | localize : lc\">\u2715</button>\n </div>\n\n @if (HiddenColumns()) {\n <div class=\"est2-dialog__tools\">\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(true)\">{{ 'Show all' | localize : lc }}</button>\n <span class=\"est2-dialog__sep\">\u00B7</span>\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(false)\">{{ 'Hide all' | localize : lc }}</button>\n </div>\n }\n\n <ul class=\"est2-collist\">\n @for (c of dialogCols(); track c.id; let i = $index) {\n <li class=\"est2-collist__row\"\n [attr.draggable]=\"ColumnsOrdering() && canReorder(c) ? true : null\"\n [class.est2-collist__row--drag]=\"ColumnsOrdering() && canReorder(c)\"\n [class.est2-collist__row--locked]=\"!canReorder(c)\"\n [class.est2-collist__row--dragging]=\"dragIndex() === i\"\n [class.est2-collist__row--drop-above]=\"dragOverIndex() === i && dragIndex() !== null && dragIndex()! > i\"\n [class.est2-collist__row--drop-below]=\"dragOverIndex() === i && dragIndex() !== null && dragIndex()! < i\"\n (dragstart)=\"dialogDragStart(i, $event)\"\n (dragover)=\"dialogDragOver(i, $event)\"\n (drop)=\"dialogDrop(i, $event)\"\n (dragend)=\"dialogDragEnd()\">\n @if (ColumnsOrdering()) {\n @if (canReorder(c)) {\n <span class=\"est2-collist__grip\" [title]=\"'Drag to reorder' | localize : lc\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"currentColor\"><circle cx=\"9\" cy=\"6\" r=\"1.6\"/><circle cx=\"15\" cy=\"6\" r=\"1.6\"/><circle cx=\"9\" cy=\"12\" r=\"1.6\"/><circle cx=\"15\" cy=\"12\" r=\"1.6\"/><circle cx=\"9\" cy=\"18\" r=\"1.6\"/><circle cx=\"15\" cy=\"18\" r=\"1.6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-collist__grip est2-collist__grip--locked\"\n [title]=\"(c.fixed ? 'Fixed column: cannot be moved' : 'Column locked to the left: cannot be moved') | localize : lc\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"4\" y=\"11\" width=\"16\" height=\"10\" rx=\"2\"/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"/></svg>\n </span>\n }\n }\n @if (HiddenColumns()) {\n <label class=\"est2-collist__vis\" [title]=\"c.fixed ? ('Fixed column: always visible' | localize : lc) : ''\">\n <input type=\"checkbox\" class=\"est2-check\" [checked]=\"c.visible\" [disabled]=\"c.fixed\" (change)=\"dialogToggle(i)\" />\n </label>\n }\n <span class=\"est2-collist__label\">\n @if (c.tmpl) {\n <!-- colonna non renderizzata (Visible:false / nascosta): il testo\n header non esiste nel DOM, quindi rendo il template dell'`*th` -->\n @if (c.prefix) { <span class=\"est2-collist__path\">{{ c.prefix }}</span> }\n <ng-container *ngTemplateOutlet=\"c.tmpl; context: c.tmplCtx\"></ng-container>\n } @else {\n {{ c.label }}\n }\n </span>\n @if (ColumnsPinnable()) {\n <button type=\"button\" class=\"est2-iconbtn est2-collist__pin\" [class.est2-collist__pin--on]=\"c.pinned\"\n [disabled]=\"c.grouped || c.fixed\"\n [title]=\"(c.fixed ? 'Fixed columns cannot be locked' : (c.grouped ? 'Grouped columns cannot be locked' : (c.pinned ? 'Unlock' : 'Lock to the left'))) | localize : lc\"\n (click)=\"dialogTogglePin(i)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n @if (ColumnsOrdering()) {\n <span class=\"est2-collist__ord\">\n <button type=\"button\" class=\"est2-iconbtn\" [title]=\"'Up' | localize : lc\" (click)=\"dialogMove(i, -1)\"\n [disabled]=\"i === 0 || !canReorder(c) || !canReorder(dialogCols()[i - 1])\">\u2191</button>\n <button type=\"button\" class=\"est2-iconbtn\" [title]=\"'Down' | localize : lc\" (click)=\"dialogMove(i, 1)\"\n [disabled]=\"i === dialogCols().length - 1 || !canReorder(c) || !canReorder(dialogCols()[i + 1])\">\u2193</button>\n </span>\n }\n </li>\n }\n </ul>\n\n <div class=\"est2-dialog__foot\">\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"resetColumnsDialog()\">{{ 'Reset' | localize : lc }}</button>\n <span class=\"est2-dialog__spacer\"></span>\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"closeColumnsDialog()\">{{ 'Cancel' | localize : lc }}</button>\n <button type=\"button\" class=\"est2-btn est2-btn--primary\" (click)=\"applyColumnsDialog()\">{{ 'Apply' | localize : lc }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n}\n\n<!-- Template pager riutilizzabile sopra/sotto -->\n<ng-template #pager>\n @if (!HidePaging() && !grouped()) {\n <es-table2-pager\n [page]=\"currentPage()\"\n [pages]=\"totalPages()\"\n [total]=\"totalCount()\"\n [locale]=\"locale\"\n [itemsPerPage]=\"viewMode() ? (view()?.itemsperpageoverride ?? 15) : ArraymodeItemsPerPage()\"\n [countLabel]=\"CountLabel()\"\n [showCount]=\"!HidePagingCount()\"\n [showButtons]=\"!HidePagingButtons()\"\n [showPagingOptions]=\"!HidePagingButtons()\"\n [allowAll]=\"AllSearch()\"\n (pageChange)=\"goToPage($event)\"\n (itemsPerPageChange)=\"changeItemsPerPage($event)\">\n </es-table2-pager>\n }\n</ng-template>\n\n<!-- Editor di cella di default (usato quando il consumer non fornisce un `*editor`) -->\n<ng-template #defaultEditor let-item let-col=\"col\">\n @switch (col.type) {\n @case ('enum') {\n <select class=\"est2-editor-input\"\n [value]=\"editDraft\"\n (change)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\">\n @for (o of col.source || []; track o.id) {\n <option [value]=\"o.id\" [selected]=\"o.id == editDraft\">{{ o.description }}</option>\n }\n </select>\n }\n @case ('boolean') {\n <input type=\"checkbox\" class=\"est2-editor-input est2-check\"\n [checked]=\"editDraft === true || editDraft === 'true'\"\n (change)=\"editDraft = $any($event.target).checked; commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\" />\n }\n @default {\n <input class=\"est2-editor-input\"\n [type]=\"editorInputType(col.type)\"\n [value]=\"editDraft\"\n (input)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\" />\n }\n }\n</ng-template>\n\n<!-- Menu di default (nessuna operazione) usato quando il consumer non passa [ContextMenu] -->\n<context-menu #emptyMenu>\n <ng-template contextMenuItem [passive]=\"true\"><em>{{ 'No operations available\u2026' | localize : lc }}</em></ng-template>\n</context-menu>\n", styles: [".est2{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent);--est-radius: 10px;--est-radius-sm: 6px;--est-radius-pill: 999px;--est-gap: 8px;--est-cell-py: 6px;--est-cell-px: 12px;--est-row-h: 33px;--est-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--est-fs: 13px;--est-fs-sm: 12px;--est-fw-head: 700;--est-transition: .14s cubic-bezier(.4, 0, .2, 1);--est-bg-zebra: color-mix(in srgb, var(--est-fg) 3.5%, var(--est-bg));--est-z-menu: 1000;--est-z-modal: 1010;--est-z-toast: 1020;font-family:var(--est-font);font-size:var(--est-fs);color:var(--est-fg);position:relative;display:block}@media(prefers-color-scheme:dark){.est2{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}}.est2.est2--dark{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}.est2.est2--light{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent)}.est2.est2--dense{--est-cell-py: 3px;--est-cell-px: 9px;--est-row-h: 27px;--est-fs: 12.5px}.est2 *,.est2 *:before,.est2 *:after{box-sizing:border-box}.est2 .est2-scroll{position:relative;width:100%;overflow:auto;border:1px solid var(--est-border);border-radius:var(--est-radius);background:var(--est-bg);-webkit-overflow-scrolling:touch}.est2 table.est2-table{width:100%;border-collapse:separate;border-spacing:0;background:var(--est-bg)}.est2 thead th{position:sticky;top:0;z-index:3;background:var(--est-bg-subtle);color:var(--est-fg);font-weight:var(--est-fw-head);font-size:var(--est-fs);text-align:left;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);box-shadow:var(--est-shadow-sticky);-webkit-user-select:none;user-select:none}.est2 thead tr.est2-hgroup-row th{font-size:var(--est-fs-sm);font-weight:700;color:var(--est-fg-muted);text-align:center;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);background:var(--est-bg-subtle);border-bottom:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th.est2-hgroup{color:var(--est-fg);border-left:1px solid var(--est-border);border-right:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th:not(.est2-hgroup){background:var(--est-bg-subtle);border-bottom-color:transparent}.est2 thead tr:last-child th.est2-col-groupstart,.est2 tbody td.est2-col-groupstart{border-left:1px solid var(--est-border)}.est2 tbody td{padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);color:var(--est-fg);vertical-align:middle;background:transparent}.est2 tbody tr:nth-child(2n) td{background:var(--est-bg-zebra)}.est2 tbody tr:nth-child(2n) td.est2-pinned{background:var(--est-bg-zebra)}.est2 th.est2-pinned,.est2 td.est2-pinned{position:sticky;background:var(--est-bg);box-shadow:1px 0 0 var(--est-border)}.est2 .est2-resize-handle{position:absolute;top:0;right:-3px;width:10px;height:100%;cursor:col-resize;z-index:2;touch-action:none;-webkit-user-select:none;user-select:none}.est2 .est2-resize-handle:after{content:\"\";position:absolute;top:28%;bottom:28%;right:3px;width:2px;border-radius:2px;background:color-mix(in srgb,var(--est-fg) 30%,transparent);transition:background var(--est-transition),top var(--est-transition),bottom var(--est-transition)}.est2 .est2-resize-handle:hover:after{background:var(--est-accent);top:15%;bottom:15%}.est2 .est2-resize-handle:active:after{background:var(--est-accent);top:6%;bottom:6%}.est2 td.est2-fixedw{overflow:hidden;text-overflow:ellipsis}.est2 td.est2-cell-invalid{background:color-mix(in srgb,var(--est-danger) 10%,var(--est-bg));box-shadow:inset 0 0 0 1px var(--est-danger);color:var(--est-danger)}.est2 .est2-selcol{width:44px;min-width:44px;max-width:44px}.est2 td.est2-pinned{z-index:3}.est2 thead th.est2-pinned,.est2 thead tr.est2-hgroup-row th.est2-pinned{z-index:6;background:var(--est-bg-subtle)}.est2 tbody tr:hover td.est2-pinned{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-pinned{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-pinned{background:var(--est-bg-subtle)}.est2 th.est2-chrome-col,.est2 td.est2-chrome-col{position:sticky;right:0;box-shadow:-1px 0 0 var(--est-border)}.est2 thead th.est2-chrome-col{z-index:16;background:var(--est-bg-subtle)}.est2 td.est2-chrome-col{z-index:4;background:var(--est-bg)}.est2 tbody tr:nth-child(2n) td.est2-chrome-col{background:var(--est-bg-zebra)}.est2 tbody tr:hover td.est2-chrome-col{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-chrome-col{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-chrome-col{background:var(--est-bg-subtle)}.est2 .est2-pinbtn{display:inline-flex;align-items:center;justify-content:center;margin-left:4px;padding:2px;border:none;background:transparent;color:var(--est-fg-faint);border-radius:var(--est-radius-sm);cursor:pointer;opacity:0;transition:opacity var(--est-transition),color var(--est-transition),background var(--est-transition)}.est2 thead th:hover .est2-pinbtn{opacity:.7}.est2 .est2-pinbtn:hover{background:var(--est-bg-hover);color:var(--est-fg);opacity:1}.est2 .est2-pinbtn--on{opacity:1;color:var(--est-accent);transform:rotate(0)}.est2 thead th:hover .est2-pinbtn--on{opacity:1}.est2 .est2-collist__pin.est2-collist__pin--on{color:var(--est-accent);border-color:var(--est-accent)}.est2 tbody tr{height:var(--est-row-h);transition:background var(--est-transition)}.est2 tbody tr:last-child td{border-bottom:none}.est2 tbody tr:hover td{background:var(--est-bg-hover)}.est2 tbody tr.est2-row--selected td{background:var(--est-bg-selected)}.est2 tbody tr.est2-row--clickable{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--removed td{text-decoration:line-through;color:var(--est-fg-faint)}.est2 .est2-table--range tbody td[data-r]{cursor:cell}.est2 .est2-table--dragging,.est2 .est2-table--dragging tbody td{-webkit-user-select:none;user-select:none}.est2 tbody td.est2-cell-sel{background:color-mix(in srgb,var(--est-accent) 14%,transparent)}.est2 tbody td.est2-cell-sel-t{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l{box-shadow:inset 2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-r{box-shadow:inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b{box-shadow:inset 0 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 0 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px -2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-editing{padding:2px 6px}.est2 .est2-editor-input{width:100%;box-sizing:border-box;height:calc(var(--est-row-h) - 8px);padding:2px 6px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1.5px solid var(--est-accent);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-editor-input:focus-visible{box-shadow:var(--est-ring)}.est2 input.est2-editor-input[type=checkbox]{width:16px;height:16px}.est2 .est2-autoupdate{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding:4px 2px 8px;font-size:var(--est-fs-sm);color:var(--est-fg-muted)}.est2 .est2-autoupdate__label{display:inline-flex;align-items:center;gap:6px}.est2 .est2-autoupdate__secs{width:44px;text-align:center;padding:3px 4px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-autoupdate__secs:focus-visible{box-shadow:var(--est-ring);border-color:var(--est-accent)}.est2 .est2-switch{position:relative;display:inline-flex;width:38px;height:20px;cursor:pointer}.est2 .est2-switch input{position:absolute;opacity:0;width:0;height:0}.est2 .est2-switch__slider{flex:1;border-radius:var(--est-radius-pill);background:var(--est-border-strong);transition:background var(--est-transition)}.est2 .est2-switch__slider:before{content:\"\";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px #00000040;transition:transform var(--est-transition)}.est2 .est2-switch input:checked+.est2-switch__slider{background:var(--est-accent)}.est2 .est2-switch input:checked+.est2-switch__slider:before{transform:translate(18px)}.est2 .est2-switch input:focus-visible+.est2-switch__slider{box-shadow:var(--est-ring)}.est2 .est2-toast{position:fixed;left:50%;bottom:24px;transform:translate(-50%);z-index:var(--est-z-toast);pointer-events:none;display:inline-flex;align-items:center;gap:8px;max-width:min(560px,100vw - 24px);padding:8px 14px;font-size:13px;font-weight:500;color:#fff;background:#b91c1c;border-radius:var(--est-radius);box-shadow:0 6px 20px #00000040;animation:est2-toast-in .16s ease-out}.est2 .est2-toast svg{flex:0 0 auto}@keyframes est2-toast-in{0%{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%)}}@media(prefers-reduced-motion:reduce){.est2 .est2-toast{animation:none}}.est2 tbody tr.est2-row--group{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--group td{background:var(--est-bg-subtle);font-weight:600;color:var(--est-fg);border-bottom:1px solid var(--est-border)}.est2 tbody tr.est2-row--group:hover td{background:var(--est-bg-hover)}.est2 .est2-td--group-key{color:var(--est-fg)}.est2 .est2-group-key{display:inline-flex;align-items:center;gap:6px}.est2 .est2-group-chevron{display:inline-flex;color:var(--est-fg-muted);transition:transform var(--est-transition)}.est2 .est2-group-chevron--open{transform:rotate(90deg)}.est2 .est2-hier-lead{display:inline-flex;align-items:center;vertical-align:middle;margin-right:4px}.est2 .est2-hier-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none}.est2 .est2-group-chevron.est2-hier-toggle{cursor:pointer;border-radius:var(--est-radius-sm);transition:transform var(--est-transition),background var(--est-transition),color var(--est-transition)}.est2 .est2-group-chevron.est2-hier-toggle:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 th.est2-th--orderable{cursor:pointer;transition:color var(--est-transition)}.est2 th.est2-th--orderable:hover{color:var(--est-fg)}.est2 .est2-th__inner{display:inline-flex;align-items:center;gap:6px}.est2 .est2-sort{display:inline-flex;width:14px;height:14px;opacity:.35;transition:opacity var(--est-transition),transform var(--est-transition)}.est2 .est2-sort--active{opacity:1;color:var(--est-accent)}.est2 .est2-sort--desc{transform:rotate(180deg)}.est2 .est2-sort__badge{font-size:9px;font-weight:700;color:var(--est-accent);margin-left:2px}.est2 .est2-check{appearance:none;width:16px;height:16px;border:1.5px solid var(--est-border-strong);border-radius:var(--est-radius-sm);background:var(--est-bg);cursor:pointer;position:relative;transition:border-color var(--est-transition),background var(--est-transition);vertical-align:middle;flex:none}.est2 .est2-check:hover{border-color:var(--est-accent)}.est2 .est2-check:checked{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:checked:after{content:\"\";position:absolute;left:4.5px;top:1.5px;width:4px;height:8px;border:solid var(--est-accent-fg);border-width:0 2px 2px 0;transform:rotate(45deg)}.est2 .est2-check:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2 .est2-check:disabled{opacity:.45;cursor:not-allowed}.est2 .est2-check:disabled:hover{border-color:var(--est-border-strong)}.est2 .est2-check:indeterminate{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:indeterminate:after{content:\"\";position:absolute;left:3px;top:6px;width:8px;height:2px;background:var(--est-accent-fg);transform:none;border:none}.est2 th.est2-col-min,.est2 td.est2-col-min{width:1%;white-space:nowrap}.est2 .est2-wrap,.est2 .est2-scroll-host{position:relative}.est2 .est2-selectbar{position:absolute;top:0;left:0;right:0;z-index:15;display:flex;align-items:center;gap:12px;padding:9px 14px;font-size:var(--est-fs-sm);color:var(--est-fg);background:var(--est-bg-subtle);border:none;border-radius:var(--est-radius) var(--est-radius) 0 0;box-shadow:inset 3px 0 0 var(--est-accent)}.est2 .est2-selectbar--inset{border-top-right-radius:0}.est2 .est2-selectbar strong{color:var(--est-fg);font-weight:700}.est2 .est2-selectbar__spacer{flex:1 1 auto}.est2 .est2-link{color:var(--est-accent);cursor:pointer;font-weight:600}.est2 .est2-link:hover{text-decoration:underline}.est2 .est2-rowaction{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);border:none;background:transparent;color:var(--est-fg-faint);cursor:pointer;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-rowaction:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-rowaction--danger:hover{color:var(--est-danger)}.est2 .est2-op-cell{text-align:center}.est2 .est2-op{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:26px;padding:0 6px;border-radius:var(--est-radius-sm);color:var(--est-accent);cursor:pointer;font-size:var(--est-fs-sm);transition:background var(--est-transition)}.est2 .est2-op:hover{background:var(--est-accent-weak)}.est2 .est2-loading{position:absolute;inset:0;border-radius:var(--est-radius);z-index:20;display:flex;align-items:center;justify-content:center;gap:10px;background:color-mix(in srgb,var(--est-bg) 70%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);color:var(--est-fg-muted);font-size:var(--est-fs-sm)}.est2 .est2-spinner{width:16px;height:16px;border:2px solid var(--est-border-strong);border-top-color:var(--est-accent);border-radius:50%;animation:est2-spin .7s linear infinite}@keyframes est2-spin{to{transform:rotate(360deg)}}.est2 .est2-nowrap{white-space:nowrap}.est2 .est2-cornermenu{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);cursor:pointer;color:var(--est-fg-muted);transition:background var(--est-transition)}.est2 .est2-cornermenu:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-chrome-th{position:relative}.est2 .est2-chrome{display:inline-flex;align-items:center;gap:2px}.est2 .est2-chrome-wrap{position:relative;display:inline-flex}.est2 .est2-chrome-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer;font-size:16px;line-height:1;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-chrome-btn:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-menu{position:fixed;z-index:var(--est-z-menu);min-width:180px;padding:4px;background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 8px 24px #0000002e;display:flex;flex-direction:column}.est2 .est2-menu-item{display:block;width:100%;padding:8px 10px;border:none;background:transparent;text-align:left;font:inherit;color:var(--est-fg);border-radius:var(--est-radius-sm);cursor:pointer}.est2 .est2-menu-item:hover{background:var(--est-bg-hover)}.est2 .est2-dialog-backdrop{position:fixed;inset:0;z-index:var(--est-z-modal);display:flex;align-items:center;justify-content:center;padding:16px}.est2 .est2-dialog-backdrop:before{content:\"\";position:absolute;inset:0;background-color:#000;opacity:.5}.est2 .est2-dialog{position:relative}.est2 .est2-dialog-backdrop--embedded{--est-embed-offset: 110px;padding-top:5%;margin-left:calc(-1 * var(--est-embed-offset));width:calc(100% + var(--est-embed-offset));overflow:hidden}.est2 .est2-dialog-backdrop--embedded .est2-dialog{max-height:600px}.est2 .est2-dialog{width:520px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);display:flex;flex-direction:column;background:var(--est-bg);color:var(--est-fg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 16px 48px #0000004d;overflow:hidden}.est2 .est2-dialog__head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;font-weight:700;border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__close{border:none;background:transparent;cursor:pointer;color:var(--est-fg-muted);font-size:15px;line-height:1;padding:4px;border-radius:var(--est-radius-sm)}.est2 .est2-dialog__close:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-dialog__tools{padding:8px 14px;font-size:var(--est-fs-sm);border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__tools .est2-link{border:none;background:none;padding:0;font:inherit;font-weight:600}.est2 .est2-dialog__sep{margin:0 6px;color:var(--est-fg-faint)}.est2 .est2-collist{list-style:none;margin:0;padding:6px;overflow-y:auto;flex:1 1 auto;min-height:0}.est2 .est2-collist__row{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:var(--est-radius-sm)}.est2 .est2-collist__row:hover{background:var(--est-bg-hover)}.est2 .est2-collist__row--drag{cursor:grab}.est2 .est2-collist__row--drag:active{cursor:grabbing}.est2 .est2-collist__row--dragging{opacity:.45;background:var(--est-bg-hover)}.est2 .est2-collist__row--drop-above{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 .est2-collist__row--drop-below{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 .est2-collist__grip{display:inline-flex;align-items:center;justify-content:center;color:var(--est-fg-faint);cursor:grab;flex:0 0 auto}.est2 .est2-collist__grip:active{cursor:grabbing}.est2 .est2-collist__row--drag:hover .est2-collist__grip{color:var(--est-fg-muted)}.est2 .est2-collist__grip--locked{color:var(--est-fg-faint);opacity:.55;cursor:default}.est2 .est2-collist__row--locked .est2-collist__label{color:var(--est-fg-muted)}.est2 .est2-collist__vis{display:inline-flex}.est2 .est2-collist__label{flex:1 1 auto}.est2 .est2-collist__path{color:var(--est-fg-faint);margin-right:4px}.est2 .est2-collist__ord{display:inline-flex;gap:4px}.est2 .est2-iconbtn{width:26px;height:26px;border:1px solid var(--est-border);background:var(--est-bg);border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer}.est2 .est2-iconbtn:hover:not(:disabled){background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-iconbtn:disabled{opacity:.4;cursor:default}.est2 .est2-dialog__foot{display:flex;align-items:center;gap:8px;padding:12px 14px;border-top:1px solid var(--est-border)}.est2 .est2-dialog__spacer{flex:1 1 auto}.est2 .est2-btn{padding:7px 14px;border-radius:var(--est-radius-sm);font:inherit;font-weight:600;cursor:pointer;border:1px solid transparent}.est2 .est2-btn--ghost{background:transparent;color:var(--est-fg);border-color:var(--est-border)}.est2 .est2-btn--ghost:hover{background:var(--est-bg-hover)}.est2 .est2-btn--primary{background:var(--est-accent);color:var(--est-accent-fg)}.est2 .est2-btn--primary:hover{filter:brightness(1.05)}.est2 .est2-empty{padding:48px 16px;text-align:center;color:var(--est-fg-faint);font-size:var(--est-fs-sm)}.ngx-contextmenu{--ctx-bg: #ffffff;--ctx-fg: #1a1d24;--ctx-muted: #626b7a;--ctx-border: #e6e9ef;--ctx-hover: #f2f4f7;--ctx-accent: #4f46e5;--ctx-shadow: 0 10px 28px -8px rgba(16, 24, 40, .22), 0 2px 8px -3px rgba(16, 24, 40, .14);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.ngx-contextmenu .dropdown-menu{display:block;min-width:200px;margin:0;padding:6px;list-style:none;background:var(--ctx-bg);border:1px solid var(--ctx-border);border-radius:12px;box-shadow:var(--ctx-shadow);animation:est2-ctx-in .12s cubic-bezier(.16,1,.3,1)}.ngx-contextmenu li{list-style:none;margin:0}.ngx-contextmenu li>a{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:7px;color:var(--ctx-fg);font-size:13.5px;line-height:1.2;text-decoration:none;cursor:pointer;white-space:nowrap;transition:background .12s ease,color .12s ease}.ngx-contextmenu li>a:hover,.ngx-contextmenu li>a:focus{background:var(--ctx-hover);color:var(--ctx-fg);text-decoration:none;outline:none}.ngx-contextmenu li.divider,.ngx-contextmenu li[role=separator]{height:1px;margin:6px 8px;padding:0;background:var(--ctx-border)}.ngx-contextmenu li.disabled>a,.ngx-contextmenu li[aria-disabled=true]>a{color:var(--ctx-muted);opacity:.55;pointer-events:none}@media(prefers-color-scheme:dark){.ngx-contextmenu{--ctx-bg: #1e222b;--ctx-fg: #e7eaf0;--ctx-muted: #9aa3b2;--ctx-border: #2a2f3a;--ctx-hover: #232733;--ctx-accent: #7c74ff;--ctx-shadow: 0 12px 30px -8px rgba(0, 0, 0, .6), 0 2px 8px -3px rgba(0, 0, 0, .5)}}@keyframes est2-ctx-in{0%{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@media(prefers-reduced-motion:reduce){.ngx-contextmenu .dropdown-menu{animation:none}}\n"], dependencies: [{ kind: "directive", type: i8.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.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.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i9.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i12.ContextMenuAttachDirective, selector: "[contextMenu]", inputs: ["contextMenuSubject", "contextMenu"] }, { kind: "component", type: i12.ContextMenuComponent, selector: "context-menu", inputs: ["menuClass", "autoFocus", "useBootstrap4", "disabled"], outputs: ["close", "open"] }, { kind: "directive", type: i12.ContextMenuItemDirective, selector: "[contextMenuItem]", inputs: ["subMenu", "divider", "enabled", "passive", "visible"], outputs: ["execute"] }, { kind: "component", type: EsTable2PagerComponent, selector: "es-table2-pager", inputs: ["page", "pages", "total", "itemsPerPage", "countLabel", "locale", "showCount", "showButtons", "showPagingOptions", "allowAll"], outputs: ["pageChange", "itemsPerPageChange"] }, { kind: "pipe", type: i3.LocalizePipe, name: "localize" }, { kind: "pipe", type: Est2FormatPipe, name: "est2_format" }, { kind: "pipe", type: Est2LookupPipe, name: "est2_lookup" }], viewProviders: [{ provide: LocalizationService, useClass: EsTable2Loc }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
9888
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: EsTable2Component, isStandalone: false, selector: "es-table2", inputs: { ContextMenu: { classPropertyName: "ContextMenu", publicName: "ContextMenu", isSignal: false, isRequired: false, transformFunction: null }, _Selection: { classPropertyName: "_Selection", publicName: "Selection", isSignal: true, isRequired: false, transformFunction: null }, SingleSelection: { classPropertyName: "SingleSelection", publicName: "SingleSelection", isSignal: true, isRequired: false, transformFunction: null }, SelectionDisabled: { classPropertyName: "SelectionDisabled", publicName: "SelectionDisabled", isSignal: true, isRequired: false, transformFunction: null }, _SelectAll: { classPropertyName: "_SelectAll", publicName: "SelectAll", isSignal: true, isRequired: false, transformFunction: null }, SelectionKey: { classPropertyName: "SelectionKey", publicName: "SelectionKey", isSignal: true, isRequired: false, transformFunction: null }, _UseSelectionCache: { classPropertyName: "_UseSelectionCache", publicName: "UseSelectionCache", isSignal: true, isRequired: false, transformFunction: null }, _ShiftClick: { classPropertyName: "_ShiftClick", publicName: "ShiftClick", isSignal: true, isRequired: false, transformFunction: null }, _OrderByColumn: { classPropertyName: "_OrderByColumn", publicName: "OrderByColumn", isSignal: true, isRequired: false, transformFunction: null }, MultipleOrderingDirectives: { classPropertyName: "MultipleOrderingDirectives", publicName: "MultipleOrderingDirectives", isSignal: true, isRequired: false, transformFunction: null }, Removal: { classPropertyName: "Removal", publicName: "Removal", isSignal: true, isRequired: false, transformFunction: null }, RemovalCondition: { classPropertyName: "RemovalCondition", publicName: "RemovalCondition", isSignal: true, isRequired: false, transformFunction: null }, RowClassAssigner: { classPropertyName: "RowClassAssigner", publicName: "RowClassAssigner", isSignal: false, isRequired: false, transformFunction: null }, _HidePaging: { classPropertyName: "_HidePaging", publicName: "HidePaging", isSignal: true, isRequired: false, transformFunction: null }, _HidePagingCount: { classPropertyName: "_HidePagingCount", publicName: "HidePagingCount", isSignal: true, isRequired: false, transformFunction: null }, _HidePagingButtons: { classPropertyName: "_HidePagingButtons", publicName: "HidePagingButtons", isSignal: true, isRequired: false, transformFunction: null }, _AllSearch: { classPropertyName: "_AllSearch", publicName: "AllSearch", isSignal: true, isRequired: false, transformFunction: null }, _PagingStyle: { classPropertyName: "_PagingStyle", publicName: "PagingStyle", isSignal: true, isRequired: false, transformFunction: null }, _ArraymodeItemsPerPage: { classPropertyName: "_ArraymodeItemsPerPage", publicName: "ArraymodeItemsPerPage", isSignal: true, isRequired: false, transformFunction: null }, _UseArrayModePaging: { classPropertyName: "_UseArrayModePaging", publicName: "UseArrayModePaging", isSignal: true, isRequired: false, transformFunction: null }, CountLabel: { classPropertyName: "CountLabel", publicName: "CountLabel", isSignal: true, isRequired: false, transformFunction: null }, Height: { classPropertyName: "Height", publicName: "Height", isSignal: true, isRequired: false, transformFunction: null }, MaxHeight: { classPropertyName: "MaxHeight", publicName: "MaxHeight", isSignal: true, isRequired: false, transformFunction: null }, VirtualScroll: { classPropertyName: "VirtualScroll", publicName: "VirtualScroll", isSignal: true, isRequired: false, transformFunction: null }, VirtualRowHeight: { classPropertyName: "VirtualRowHeight", publicName: "VirtualRowHeight", isSignal: true, isRequired: false, transformFunction: null }, EmptySpaceBackgroundColor: { classPropertyName: "EmptySpaceBackgroundColor", publicName: "EmptySpaceBackgroundColor", isSignal: true, isRequired: false, transformFunction: null }, HighCellDensity: { classPropertyName: "HighCellDensity", publicName: "HighCellDensity", isSignal: true, isRequired: false, transformFunction: null }, HeaderHidden: { classPropertyName: "HeaderHidden", publicName: "HeaderHidden", isSignal: true, isRequired: false, transformFunction: null }, BodyHidden: { classPropertyName: "BodyHidden", publicName: "BodyHidden", isSignal: true, isRequired: false, transformFunction: null }, ShowLoadingOnBootstrap: { classPropertyName: "ShowLoadingOnBootstrap", publicName: "ShowLoadingOnBootstrap", isSignal: true, isRequired: false, transformFunction: null }, _DefaultAlignment: { classPropertyName: "_DefaultAlignment", publicName: "DefaultAlignment", isSignal: true, isRequired: false, transformFunction: null }, _TableClass: { classPropertyName: "_TableClass", publicName: "TableClass", isSignal: true, isRequired: false, transformFunction: null }, _ContainerClass: { classPropertyName: "_ContainerClass", publicName: "ContainerClass", isSignal: true, isRequired: false, transformFunction: null }, EsTableHandledSearch: { classPropertyName: "EsTableHandledSearch", publicName: "EsTableHandledSearch", isSignal: true, isRequired: false, transformFunction: null }, SearchThrottle: { classPropertyName: "SearchThrottle", publicName: "SearchThrottle", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsResizable: { classPropertyName: "_ColumnsResizable", publicName: "ColumnsResizable", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsPinnable: { classPropertyName: "_ColumnsPinnable", publicName: "ColumnsPinnable", isSignal: true, isRequired: false, transformFunction: null }, _HiddenColumns: { classPropertyName: "_HiddenColumns", publicName: "HiddenColumns", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsOrdering: { classPropertyName: "_ColumnsOrdering", publicName: "ColumnsOrdering", isSignal: true, isRequired: false, transformFunction: null }, _Export: { classPropertyName: "_Export", publicName: "Export", isSignal: true, isRequired: false, transformFunction: null }, XLSXExport: { classPropertyName: "XLSXExport", publicName: "XLSXExport", isSignal: true, isRequired: false, transformFunction: null }, CSVExport: { classPropertyName: "CSVExport", publicName: "CSVExport", isSignal: true, isRequired: false, transformFunction: null }, ExportFileName: { classPropertyName: "ExportFileName", publicName: "ExportFileName", isSignal: true, isRequired: false, transformFunction: null }, ExportOnlyVisibleColumns: { classPropertyName: "ExportOnlyVisibleColumns", publicName: "ExportOnlyVisibleColumns", isSignal: true, isRequired: false, transformFunction: null }, ExportFunction: { classPropertyName: "ExportFunction", publicName: "ExportFunction", isSignal: false, isRequired: false, transformFunction: null }, CornerMenuOptions: { classPropertyName: "CornerMenuOptions", publicName: "CornerMenuOptions", isSignal: true, isRequired: false, transformFunction: null }, DynamicOperations: { classPropertyName: "DynamicOperations", publicName: "DynamicOperations", isSignal: true, isRequired: false, transformFunction: null }, _DynamicRowColumnsDefinition: { classPropertyName: "_DynamicRowColumnsDefinition", publicName: "DynamicRowColumnsDefinition", isSignal: true, isRequired: false, transformFunction: null }, Hierarchy: { classPropertyName: "Hierarchy", publicName: "Hierarchy", isSignal: true, isRequired: false, transformFunction: null }, _ParentKey: { classPropertyName: "_ParentKey", publicName: "ParentKey", isSignal: true, isRequired: false, transformFunction: null }, _OwnKey: { classPropertyName: "_OwnKey", publicName: "OwnKey", isSignal: true, isRequired: false, transformFunction: null }, _AutoSortHierarchy: { classPropertyName: "_AutoSortHierarchy", publicName: "AutoSortHierarchy", isSignal: true, isRequired: false, transformFunction: null }, StartsExpanded: { classPropertyName: "StartsExpanded", publicName: "StartsExpanded", isSignal: true, isRequired: false, transformFunction: null }, CascadeSelection: { classPropertyName: "CascadeSelection", publicName: "CascadeSelection", isSignal: true, isRequired: false, transformFunction: null }, _SavePreferences: { classPropertyName: "_SavePreferences", publicName: "SavePreferences", isSignal: true, isRequired: false, transformFunction: null }, Name: { classPropertyName: "Name", publicName: "Name", isSignal: true, isRequired: false, transformFunction: null }, _RowGroupingPagingStyle: { classPropertyName: "_RowGroupingPagingStyle", publicName: "RowGroupingPagingStyle", isSignal: true, isRequired: false, transformFunction: null }, _ShowItemGroupsColumns: { classPropertyName: "_ShowItemGroupsColumns", publicName: "ShowItemGroupsColumns", isSignal: true, isRequired: false, transformFunction: null }, Editable: { classPropertyName: "Editable", publicName: "Editable", isSignal: true, isRequired: false, transformFunction: null }, RangeSelection: { classPropertyName: "RangeSelection", publicName: "RangeSelection", isSignal: true, isRequired: false, transformFunction: null }, ItemSourceProperty: { classPropertyName: "ItemSourceProperty", publicName: "ItemSourceProperty", isSignal: true, isRequired: false, transformFunction: null }, HasHeaderGroup: { classPropertyName: "HasHeaderGroup", publicName: "HasHeaderGroup", isSignal: true, isRequired: false, transformFunction: null }, HasSecondaryHeaderGroup: { classPropertyName: "HasSecondaryHeaderGroup", publicName: "HasSecondaryHeaderGroup", isSignal: true, isRequired: false, transformFunction: null }, SearchView: { classPropertyName: "SearchView", publicName: "SearchView", isSignal: true, isRequired: false, transformFunction: null }, _AutoUpdate: { classPropertyName: "_AutoUpdate", publicName: "AutoUpdate", isSignal: true, isRequired: false, transformFunction: null }, EsThTdProvider: { classPropertyName: "EsThTdProvider", publicName: "EsThTdProvider", isSignal: false, isRequired: false, transformFunction: null }, globalCheck: { classPropertyName: "globalCheck", publicName: "globalCheck", isSignal: true, isRequired: false, transformFunction: null }, autoUpdate: { classPropertyName: "autoUpdate", publicName: "autoUpdate", isSignal: true, isRequired: false, transformFunction: null }, seconds: { classPropertyName: "seconds", publicName: "seconds", isSignal: true, isRequired: false, transformFunction: null }, researchInProgress: { classPropertyName: "researchInProgress", publicName: "researchInProgress", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onOrderChanged: "onOrderChanged", onSearchRequest: "onSearchRequest", onSelectionChanged: "onSelectionChanged", onRemoval: "onRemoval", onAbortRemoval: "onAbortRemoval", onModelChange: "onModelChange", onOpenContextMenu: "onOpenContextMenu", onCornerAction: "onCornerAction", onDynamicOperation: "onDynamicOperation", globalCheck: "globalCheckChange", autoUpdate: "autoUpdateChange", seconds: "secondsChange", researchInProgress: "researchInProgressChange" }, host: { listeners: { "document:mouseup": "onResizeEnd()", "document:copy": "onDocCopy($event)", "document:paste": "onDocPaste($event)", "document:click": "onDocClick()", "window:resize": "onViewportResize()", "document:mousemove": "onResizeMove($event)" }, properties: { "class.est2": "this.hostClass", "class.est2--dense": "this.denseClass" } }, queries: [{ propertyName: "headerRef", first: true, predicate: ["header"], descendants: true }, { propertyName: "bodyRef", first: true, predicate: ["body"], descendants: true }, { propertyName: "thDirectives", predicate: EsThDirective }, { propertyName: "tdDirectives", predicate: EsTdDirective }, { propertyName: "editorDirectives", predicate: EsTdEditorDirective }, { propertyName: "thTdProviders", predicate: ThTdProvider }], viewQueries: [{ propertyName: "tableEmptyMenu", first: true, predicate: ["emptyMenu"], descendants: true, static: true }, { propertyName: "theadRef", first: true, predicate: ["theadRef"], descendants: true }, { propertyName: "scrollRefEl", first: true, predicate: ["scrollRef"], descendants: true }, { propertyName: "dialogBackdropRef", first: true, predicate: ["dialogBackdrop"], descendants: true }], ngImport: i0, template: "@if (view()) {\n <div class=\"est2-wrap {{ ContainerClass() }}\"\n [style.height]=\"Height()\"\n [style.background-color]=\"EmptySpaceBackgroundColor() || null\">\n\n <!-- Auto-aggiornamento: toggle + intervallo (in alto a destra) -->\n @if (AutoUpdate()) {\n <div class=\"est2-autoupdate\">\n <label class=\"est2-autoupdate__label\">\n {{ 'Update every' | localize : lc }}\n <input type=\"text\" maxlength=\"3\" class=\"est2-autoupdate__secs\"\n [ngModel]=\"seconds()\" (ngModelChange)=\"seconds.set($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n (change)=\"autoUpdateChanged()\" />\n {{ 'second/s' | localize : lc }}\n </label>\n <label class=\"est2-switch\" [title]=\"'Toggle auto-update' | localize : lc\">\n <input type=\"checkbox\" [ngModel]=\"autoUpdate()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"autoUpdate.set($event); autoUpdateChanged()\" />\n <span class=\"est2-switch__slider\"></span>\n </label>\n </div>\n }\n\n <!-- Pager superiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'top') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Host POSIZIONATO dello scroller: \u00E8 l'ancora di tutti gli overlay che devono\n coprire la TABELLA (barra di selezione, overlay di caricamento). Senza di esso\n erano ancorati a `.est2-wrap` e con [AutoUpdate] o il pager in alto finivano\n sopra quei controlli invece che sopra l'header. -->\n <div class=\"est2-scroll-host\">\n\n <!-- Barra \"seleziona tutto\" (visibile solo con selezione multipla attiva e righe presenti) -->\n @if (Selection() && !SingleSelection() && hasSelection) {\n <div class=\"est2-selectbar\"\n [class.est2-selectbar--inset]=\"chromeWidth() > 0\"\n [style.height.px]=\"selbarHeight() ? selbarHeight() + 1 : null\"\n [style.right.px]=\"chromeWidth() || null\">\n @if (allSelected) {\n <span>{{ 'All the' | localize : lc }} <strong>{{ selectedCount }}</strong> {{ 'elements are selected' | localize : lc }}</span>\n } @else {\n <span><strong>{{ selectedCount }}</strong> {{ (selectedCount === 1 ? 'element selected' : 'elements selected') | localize : lc }}</span>\n @if (canSelectEverything) {\n <span class=\"est2-link\" (click)=\"selectEverything()\">{{ 'Select all' | localize : lc }} {{ totalCount() }} {{ 'elements' | localize : lc }}</span>\n }\n }\n <span class=\"est2-selectbar__spacer\"></span>\n <span class=\"est2-link\" (click)=\"clearSelection()\">{{ 'Reset selection' | localize : lc }}</span>\n </div>\n }\n\n <div class=\"est2-scroll\" #scrollRef [style.max-height.px]=\"MaxHeight()\" (scroll)=\"onScrollerScroll($event)\">\n <table class=\"est2-table {{ TableClass() }}\"\n [class.est2-table--range]=\"rangeActive()\"\n [class.est2-table--dragging]=\"rangeDragging()\"\n (mousedown)=\"onGridMouseDown($event)\"\n (mouseover)=\"onGridMouseOver($event)\">\n\n <!-- ================= HEADER ================= -->\n @if (!HeaderHidden()) {\n <thead #theadRef>\n <!-- Righe di header-group multi-livello (dall'alto verso il basso) -->\n @if (hasHeaderGroups()) {\n @for (grow of headerGroupRows(); track $index) {\n <tr class=\"est2-hgroup-row\">\n @if (Selection()) { <th class=\"est2-col-min est2-selcol\" [class.est2-pinned]=\"hasPinned()\" [style.left.px]=\"hasPinned() ? 0 : null\"></th> }\n @for (op of DynamicOperations(); track op.id) { <th class=\"est2-col-min\"></th> }\n @for (cell of grow; track cell.id; let gi = $index) {\n <th [attr.colspan]=\"cell.span\"\n [attr.data-groupid]=\"cell.isGroup ? cell.id : null\"\n [class.est2-hgroup]=\"cell.isGroup\"\n [class.est2-pinned]=\"gi < pinnedCount()\"\n [style.left.px]=\"gi < pinnedCount() ? pinnedLeftPx(gi) : null\"\n class=\"est2-hgroup-cell\">\n @if (cell.isGroup) {\n @if (cell.template) {\n <ng-container *ngTemplateOutlet=\"cell.template\"></ng-container>\n } @else {\n {{ cell.label }}\n }\n }\n </th>\n }\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n @if (hasChrome()) { <th class=\"est2-col-min est2-chrome-col\"></th> }\n </tr>\n }\n }\n <tr>\n <!-- Colonna di selezione -->\n @if (Selection()) {\n <th class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"globalCheck()\"\n [indeterminate]=\"selectionIndeterminate\"\n [disabled]=\"SelectionDisabled()\"\n (change)=\"toggleAll()\"\n [attr.aria-label]=\"'Select all rows' | localize : lc\" />\n }\n </th>\n }\n\n <!-- Header da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- intestazioni vuote per le operazioni dinamiche -->\n @for (op of DynamicOperations(); track op.id) {\n <th class=\"est2-col-min\"></th>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let ci = $index) {\n @let hs = colStyles()[ci];\n <th [attr.data-colid]=\"col.id\"\n [class]=\"col.headerClass\"\n [class.est2-th--orderable]=\"OrderByColumn() && col.orderable\"\n [class.est2-col-min]=\"col.header?.thShrink\"\n [class.est2-col-groupstart]=\"hs.groupStart\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"hs.left\"\n [style.width.px]=\"hs.width\"\n [style.min-width.px]=\"hs.width\"\n [style.max-width.px]=\"hs.width\"\n [style.text-align]=\"col.alignment\"\n [style.background-color]=\"col.headerBg || null\"\n (click)=\"toggleSort(col)\">\n <span class=\"est2-th__inner\">\n @if (col.header?.Template) {\n <ng-container *ngTemplateOutlet=\"col.header!.Template!; context: col.multiProp != null ? { $implicit: col.headerText } : null\"></ng-container>\n } @else {\n {{ col.headerText }}\n }\n @if (OrderByColumn() && col.orderable && orderOf(col.id)) {\n <span class=\"est2-sort est2-sort--active\"\n [class.est2-sort--desc]=\"orderOf(col.id) === 'DESC'\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6 15l6-6 6 6\"/></svg>\n </span>\n @if (orderIndex(col.id) > 0 && MultipleOrderingDirectives()) {\n <span class=\"est2-sort__badge\">{{ orderIndex(col.id) }}</span>\n }\n }\n <!-- Indicatore/toggle di pin (visibile se pinnata o all'hover) -->\n @if (ColumnsPinnable() && col.multiProp == null && !col.fixed) {\n <button type=\"button\" class=\"est2-pinbtn\"\n [class.est2-pinbtn--on]=\"col.pinned\"\n [title]=\"(col.pinned ? 'Unlock column' : 'Lock column to the left') | localize : lc\"\n (click)=\"togglePin(col, $event)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n </span>\n <!-- Handle di ridimensionamento (colonne pinnate, gated da ColumnsResizable) -->\n @if (col.pinned || ColumnsResizable()) {\n <span class=\"est2-resize-handle\" [title]=\"'Drag to resize' | localize : lc\"\n (mousedown)=\"startColumnResize(col, $event)\"\n (click)=\"$event.stopPropagation()\"></span>\n }\n </th>\n }\n }\n <!-- Header da template semplice -->\n @else if (headerRef) {\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\n }\n\n <!-- Colonna rimozione -->\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n <!-- Colonna chrome (export / gestione colonne / menu) -->\n @if (hasChrome()) {\n <th class=\"est2-col-min est2-chrome-th est2-chrome-col\">\n <div class=\"est2-chrome\">\n <!-- I pannelli dei menu NON vivono qui: sono renderizzati a fondo\n componente e posizionati `fixed`, altrimenti l'`overflow:auto`\n di `.est2-scroll` li taglierebbe su tabelle basse. -->\n @if (Export()) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Export' | localize : lc\" (click)=\"$event.stopPropagation(); toggleExportMenu($event)\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><path d=\"M7 10l5 5 5-5\"/><path d=\"M12 15V3\"/></svg>\n </button>\n }\n @if (HiddenColumns() || ColumnsOrdering()) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Columns' | localize : lc\" (click)=\"$event.stopPropagation(); openColumnsDialog()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><path d=\"M9 3v18\"/><path d=\"M15 3v18\"/></svg>\n </button>\n }\n @if (CornerMenuOptions().length > 0) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Options' | localize : lc\" (click)=\"$event.stopPropagation(); toggleCornerMenu($event)\">\u22EE</button>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n }\n\n <!-- ================= BODY ================= -->\n @if (!BodyHidden()) {\n <tbody>\n <!-- Valori invarianti per l'intero corpo: senza questi verrebbero\n ricalcolati riga\u00D7colonna volte a ogni ciclo di change-detection. -->\n @let rng = rangeActive();\n @let rect = rangeRect();\n @let errs = hasCellErrors();\n @let vw = virtualWindow();\n @if (vw && vw.padTop > 0) {\n <tr class=\"est2-vspacer\" aria-hidden=\"true\"><td [attr.colspan]=\"totalColspan()\" [style.height.px]=\"vw.padTop\"></td></tr>\n }\n @for (item of renderedRows(); track trackRow($index, item); let vi = $index) {\n <!-- indice ASSOLUTO: range, editing e data-r ragionano su boundSource() -->\n @let ri = vStart() + vi;\n @if ((!grouped() && !Hierarchy()) || item._visible) {\n <tr [class]=\"rowClass(item)\"\n [class.est2-row--zebra]=\"vw && (ri % 2 === 1)\"\n [class.est2-row--selected]=\"item._selected\"\n [class.est2-row--removed]=\"item.removed || item.deleted\"\n [class.est2-row--group]=\"item._group\"\n [class.est2-row--clickable]=\"Selection() || item._group\"\n [contextMenu]=\"ContextMenu || emptyMenu\"\n [contextMenuSubject]=\"item\"\n (click)=\"handleRowClick(item, $event)\">\n\n <!-- Cella di selezione -->\n @if (Selection()) {\n <td class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (item._group) {\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"groupSelectionState(item) === 'all'\"\n [indeterminate]=\"groupSelectionState(item) === 'some'\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection(item)\"\n [attr.aria-label]=\"'Select group' | localize : lc\" />\n }\n } @else {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"item._selected\"\n [indeterminate]=\"hierarchyIndeterminate(item)\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(item)\"\n [attr.aria-label]=\"'Select row' | localize : lc\" />\n }\n </td>\n }\n\n <!-- Celle da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- Operazioni dinamiche (icone a sinistra) -->\n @for (op of DynamicOperations(); track op.id) {\n <td class=\"est2-col-min est2-op-cell\">\n @if (!item._group && operationVisible(op, item)) {\n <span class=\"est2-op\" [class]=\"op.iconClass || ''\" [title]=\"op.title\"\n (click)=\"$event.stopPropagation(); dynamicOperation(item, op.id)\">{{ op.text }}</span>\n }\n </td>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let first = $first, ci = $index) {\n @let cs = colStyles()[ci];\n @let insel = rng && inRange(ri, ci);\n @let editing = isEditing(ri, ci);\n <td [class]=\"col.cssClass\"\n [style.text-align]=\"col.alignment\"\n [style.color]=\"cellColor(item, col, 'fore')\"\n [style.background-color]=\"cellColor(item, col, 'back')\"\n [class.est2-nowrap]=\"!col.wrap\"\n [class.est2-col-groupstart]=\"cs.groupStart\"\n [class.est2-pinned]=\"col.pinned\"\n [class.est2-fixedw]=\"cs.width != null\"\n [style.left.px]=\"cs.left\"\n [style.width.px]=\"cs.width\"\n [style.min-width.px]=\"cs.width\"\n [style.max-width.px]=\"cs.width\"\n [class.est2-td--group-key]=\"item._group && item.column === col.id\"\n [attr.data-r]=\"rng && !item._group ? ri : null\"\n [attr.data-c]=\"rng && !item._group ? ci : null\"\n [class.est2-cell-sel]=\"insel\"\n [class.est2-cell-sel-t]=\"insel && ri === rect!.top\"\n [class.est2-cell-sel-b]=\"insel && ri === rect!.bottom\"\n [class.est2-cell-sel-l]=\"insel && ci === rect!.left\"\n [class.est2-cell-sel-r]=\"insel && ci === rect!.right\"\n [class.est2-cell-editing]=\"editing\"\n [class.est2-cell-invalid]=\"errs && !!cellError(item, col)\"\n [attr.data-error]=\"errs ? (cellError(item, col) || null) : null\"\n (dblclick)=\"onCellDblClick(item, col, ri, ci)\">\n @if (editing) {\n @if (editorFor(col); as edTpl) {\n <ng-container *ngTemplateOutlet=\"edTpl; context: editorContext(item, col)\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"defaultEditor; context: { $implicit: item, col: col }\"></ng-container>\n }\n } @else if (item._group) {\n @if (item.column === col.id) {\n <span class=\"est2-group-key\" [style.padding-left.px]=\"groupIndent(item)\">\n <span class=\"est2-group-chevron\" [class.est2-group-chevron--open]=\"item._expanded\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n {{ groupCellDisplay(item, col) }}\n </span>\n } @else {\n {{ groupCellDisplay(item, col) }}\n }\n } @else {\n <!-- Navigatore albero nella prima colonna -->\n @if (Hierarchy() && first) {\n <span class=\"est2-hier-lead\" [style.padding-left.px]=\"hierarchyIndent(item)\">\n @if (item.parent) {\n <span class=\"est2-group-chevron est2-hier-toggle\" [class.est2-group-chevron--open]=\"item._expanded\"\n (click)=\"$event.stopPropagation(); toggleHierarchyNode(item)\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-hier-toggle\"></span>\n }\n </span>\n }\n @if (itemCellHidden(col)) {\n <!-- colonna di gruppo nascosta sulla riga-oggetto -->\n } @else if (col.multiProp != null) {\n @if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: multiCell(item, col) }\"></ng-container>\n } @else {\n {{ multiCell(item, col)?.value }}\n }\n } @else if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: item }\"></ng-container>\n } @else if (col.routePath) {\n <a class=\"est2-link\" [routerLink]=\"routerLinkFor(item, col)\">{{ cellValue(item, col) }}</a>\n } @else if (col.propAccessor != null) {\n {{ reportCellDisplay(item, col) }}\n } @else if (col.type === 'enum') {\n {{ (cellValue(item, col) | est2_lookup : col.source).description }}\n } @else {\n {{ cellValue(item, col) | est2_format : col.type : col.format : locale }}\n }\n }\n </td>\n }\n }\n <!-- Celle da template semplice -->\n @else if (bodyRef) {\n <ng-container *ngTemplateOutlet=\"bodyRef; context: { $implicit: item }\"></ng-container>\n }\n\n <!-- Rimozione (non sulle righe-gruppo) -->\n @if (Removal()) {\n <td class=\"est2-col-min\">\n @if (!item._group && canRemove(item)) {\n @if (item.removed || item.deleted) {\n <button type=\"button\" class=\"est2-rowaction\" [title]=\"'Restore' | localize : lc\" (click)=\"abortRemoval(item)\">\u21BA</button>\n } @else {\n <button type=\"button\" class=\"est2-rowaction est2-rowaction--danger\" [title]=\"'Remove' | localize : lc\" (click)=\"removeItem(item)\">\u2715</button>\n }\n }\n </td>\n }\n <!-- Chrome -->\n @if (hasChrome()) { <td class=\"est2-col-min est2-chrome-col\"></td> }\n </tr>\n }\n } @empty {\n <tr>\n <td class=\"est2-empty\" [attr.colspan]=\"totalColspan()\">{{ 'No elements to display' | localize : lc }}</td>\n </tr>\n }\n @if (vw && vw.padBottom > 0) {\n <tr class=\"est2-vspacer\" aria-hidden=\"true\"><td [attr.colspan]=\"totalColspan()\" [style.height.px]=\"vw.padBottom\"></td></tr>\n }\n </tbody>\n }\n </table>\n </div>\n\n <!-- Overlay di caricamento: FUORI dallo scroller, cos\u00EC copre il viewport della\n tabella senza scorrere col contenuto e senza essere bucato dalle celle sticky -->\n @if (researchInProgress() || (firstBind() && ShowLoadingOnBootstrap())) {\n <div class=\"est2-loading\">\n <span class=\"est2-spinner\"></span>\n <span>{{ 'Loading\u2026' | localize : lc }}</span>\n </div>\n }\n\n </div>\n\n <!-- Pager inferiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Menu del chrome (export / opzioni). Renderizzati FUORI da `.est2-scroll` e\n posizionati `fixed` sulle coordinate del bottone che li ha aperti: cos\u00EC non\n vengono tagliati dall'`overflow:auto` dello scroller su tabelle basse, e\n restano dentro `.est2` (i token `--est-*` continuano a ereditare). -->\n @if (exportMenuOpen() && menuAnchor(); as anchor) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\"\n [style.top.px]=\"anchor.top\" [style.right.px]=\"anchor.right\">\n @if (CSVExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">{{ 'Export CSV' | localize : lc }}</button> }\n @if (XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('XLSX')\">{{ 'Export Excel (XLSX)' | localize : lc }}</button> }\n @if (!CSVExport() && !XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">{{ 'Export CSV' | localize : lc }}</button> }\n </div>\n }\n @if (cornerMenuOpen() && menuAnchor(); as anchor) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\"\n [style.top.px]=\"anchor.top\" [style.right.px]=\"anchor.right\">\n @for (opt of CornerMenuOptions(); track opt.id) {\n <button type=\"button\" class=\"est2-menu-item\" (click)=\"cornerAction(opt.id); closeChromeMenus()\">{{ opt.description }}</button>\n }\n </div>\n }\n\n <!-- Avviso transitorio (es. incolla con dimensioni incompatibili) -->\n @if (notice()) {\n <div class=\"est2-toast\" role=\"alert\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/></svg>\n <span>{{ notice() }}</span>\n </div>\n }\n\n <!-- Dialog visibilit\u00E0 / ordine colonne -->\n @if (columnsDialogOpen()) {\n <div class=\"est2-dialog-backdrop\" #dialogBackdrop\n [class.est2-dialog-backdrop--embedded]=\"embedded\"\n (click)=\"closeColumnsDialog()\">\n <div class=\"est2-dialog\" (click)=\"$event.stopPropagation()\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"est2-dialog__head\">\n <span>\n @if (HiddenColumns() && ColumnsOrdering()) { {{ 'Columns visibility and order' | localize : lc }} }\n @else if (HiddenColumns()) { {{ 'Columns visibility' | localize : lc }} }\n @else { {{ 'Columns order' | localize : lc }} }\n </span>\n <button type=\"button\" class=\"est2-dialog__close\" (click)=\"closeColumnsDialog()\" [attr.aria-label]=\"'Close' | localize : lc\">\u2715</button>\n </div>\n\n @if (HiddenColumns()) {\n <div class=\"est2-dialog__tools\">\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(true)\">{{ 'Show all' | localize : lc }}</button>\n <span class=\"est2-dialog__sep\">\u00B7</span>\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(false)\">{{ 'Hide all' | localize : lc }}</button>\n </div>\n }\n\n <ul class=\"est2-collist\">\n @for (c of dialogCols(); track c.id; let i = $index) {\n <li class=\"est2-collist__row\"\n [attr.draggable]=\"ColumnsOrdering() && canReorder(c) ? true : null\"\n [class.est2-collist__row--drag]=\"ColumnsOrdering() && canReorder(c)\"\n [class.est2-collist__row--locked]=\"!canReorder(c)\"\n [class.est2-collist__row--dragging]=\"dragIndex() === i\"\n [class.est2-collist__row--drop-above]=\"dragOverIndex() === i && dragIndex() !== null && dragIndex()! > i\"\n [class.est2-collist__row--drop-below]=\"dragOverIndex() === i && dragIndex() !== null && dragIndex()! < i\"\n (dragstart)=\"dialogDragStart(i, $event)\"\n (dragover)=\"dialogDragOver(i, $event)\"\n (drop)=\"dialogDrop(i, $event)\"\n (dragend)=\"dialogDragEnd()\">\n @if (ColumnsOrdering()) {\n @if (canReorder(c)) {\n <span class=\"est2-collist__grip\" [title]=\"'Drag to reorder' | localize : lc\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"currentColor\"><circle cx=\"9\" cy=\"6\" r=\"1.6\"/><circle cx=\"15\" cy=\"6\" r=\"1.6\"/><circle cx=\"9\" cy=\"12\" r=\"1.6\"/><circle cx=\"15\" cy=\"12\" r=\"1.6\"/><circle cx=\"9\" cy=\"18\" r=\"1.6\"/><circle cx=\"15\" cy=\"18\" r=\"1.6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-collist__grip est2-collist__grip--locked\"\n [title]=\"(c.fixed ? 'Fixed column: cannot be moved' : 'Column locked to the left: cannot be moved') | localize : lc\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"4\" y=\"11\" width=\"16\" height=\"10\" rx=\"2\"/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"/></svg>\n </span>\n }\n }\n @if (HiddenColumns()) {\n <label class=\"est2-collist__vis\" [title]=\"c.fixed ? ('Fixed column: always visible' | localize : lc) : ''\">\n <input type=\"checkbox\" class=\"est2-check\" [checked]=\"c.visible\" [disabled]=\"c.fixed\" (change)=\"dialogToggle(i)\" />\n </label>\n }\n <span class=\"est2-collist__label\">\n @if (c.tmpl) {\n <!-- colonna non renderizzata (Visible:false / nascosta): il testo\n header non esiste nel DOM, quindi rendo il template dell'`*th` -->\n @if (c.prefix) { <span class=\"est2-collist__path\">{{ c.prefix }}</span> }\n <ng-container *ngTemplateOutlet=\"c.tmpl; context: c.tmplCtx\"></ng-container>\n } @else {\n {{ c.label }}\n }\n </span>\n @if (ColumnsPinnable()) {\n <button type=\"button\" class=\"est2-iconbtn est2-collist__pin\" [class.est2-collist__pin--on]=\"c.pinned\"\n [disabled]=\"c.grouped || c.fixed\"\n [title]=\"(c.fixed ? 'Fixed columns cannot be locked' : (c.grouped ? 'Grouped columns cannot be locked' : (c.pinned ? 'Unlock' : 'Lock to the left'))) | localize : lc\"\n (click)=\"dialogTogglePin(i)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n @if (ColumnsOrdering()) {\n <span class=\"est2-collist__ord\">\n <button type=\"button\" class=\"est2-iconbtn\" [title]=\"'Up' | localize : lc\" (click)=\"dialogMove(i, -1)\"\n [disabled]=\"i === 0 || !canReorder(c) || !canReorder(dialogCols()[i - 1])\">\u2191</button>\n <button type=\"button\" class=\"est2-iconbtn\" [title]=\"'Down' | localize : lc\" (click)=\"dialogMove(i, 1)\"\n [disabled]=\"i === dialogCols().length - 1 || !canReorder(c) || !canReorder(dialogCols()[i + 1])\">\u2193</button>\n </span>\n }\n </li>\n }\n </ul>\n\n <div class=\"est2-dialog__foot\">\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"resetColumnsDialog()\">{{ 'Reset' | localize : lc }}</button>\n <span class=\"est2-dialog__spacer\"></span>\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"closeColumnsDialog()\">{{ 'Cancel' | localize : lc }}</button>\n <button type=\"button\" class=\"est2-btn est2-btn--primary\" (click)=\"applyColumnsDialog()\">{{ 'Apply' | localize : lc }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n}\n\n<!-- Template pager riutilizzabile sopra/sotto -->\n<ng-template #pager>\n @if (!HidePaging() && !grouped()) {\n <es-table2-pager\n [page]=\"currentPage()\"\n [pages]=\"totalPages()\"\n [total]=\"totalCount()\"\n [locale]=\"locale\"\n [itemsPerPage]=\"viewMode() ? (view()?.itemsperpageoverride ?? 15) : ArraymodeItemsPerPage()\"\n [countLabel]=\"CountLabel()\"\n [showCount]=\"!HidePagingCount()\"\n [showButtons]=\"!HidePagingButtons()\"\n [showPagingOptions]=\"!HidePagingButtons()\"\n [allowAll]=\"AllSearch()\"\n (pageChange)=\"goToPage($event)\"\n (itemsPerPageChange)=\"changeItemsPerPage($event)\">\n </es-table2-pager>\n }\n</ng-template>\n\n<!-- Editor di cella di default (usato quando il consumer non fornisce un `*editor`) -->\n<ng-template #defaultEditor let-item let-col=\"col\">\n @switch (col.type) {\n @case ('enum') {\n <select class=\"est2-editor-input\"\n [value]=\"editDraft\"\n (change)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\">\n @for (o of col.source || []; track o.id) {\n <option [value]=\"o.id\" [selected]=\"o.id == editDraft\">{{ o.description }}</option>\n }\n </select>\n }\n @case ('boolean') {\n <input type=\"checkbox\" class=\"est2-editor-input est2-check\"\n [checked]=\"editDraft === true || editDraft === 'true'\"\n (change)=\"editDraft = $any($event.target).checked; commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\" />\n }\n @default {\n <input class=\"est2-editor-input\"\n [type]=\"editorInputType(col.type)\"\n [value]=\"editDraft\"\n (input)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\" />\n }\n }\n</ng-template>\n\n<!-- Menu di default (nessuna operazione) usato quando il consumer non passa [ContextMenu] -->\n<context-menu #emptyMenu>\n <ng-template contextMenuItem [passive]=\"true\"><em>{{ 'No operations available\u2026' | localize : lc }}</em></ng-template>\n</context-menu>\n", styles: [".est2{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent);--est-radius: 10px;--est-radius-sm: 6px;--est-radius-pill: 999px;--est-gap: 8px;--est-cell-py: 6px;--est-cell-px: 12px;--est-row-h: 33px;--est-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--est-fs: 13px;--est-fs-sm: 12px;--est-fw-head: 700;--est-transition: .14s cubic-bezier(.4, 0, .2, 1);--est-bg-zebra: color-mix(in srgb, var(--est-fg) 3.5%, var(--est-bg));--est-z-menu: 1000;--est-z-modal: 1010;--est-z-toast: 1020;font-family:var(--est-font);font-size:var(--est-fs);color:var(--est-fg);position:relative;display:block}@media(prefers-color-scheme:dark){.est2{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}}.est2.est2--dark{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}.est2.est2--light{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent)}.est2.est2--dense{--est-cell-py: 3px;--est-cell-px: 9px;--est-row-h: 27px;--est-fs: 12.5px}.est2 *,.est2 *:before,.est2 *:after{box-sizing:border-box}.est2 .est2-scroll{position:relative;width:100%;overflow:auto;border:1px solid var(--est-border);border-radius:var(--est-radius);background:var(--est-bg);-webkit-overflow-scrolling:touch}.est2 table.est2-table{width:100%;border-collapse:separate;border-spacing:0;background:var(--est-bg)}.est2 thead th{position:sticky;top:0;z-index:3;background:var(--est-bg-subtle);color:var(--est-fg);font-weight:var(--est-fw-head);font-size:var(--est-fs);text-align:left;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);box-shadow:var(--est-shadow-sticky);-webkit-user-select:none;user-select:none}.est2 thead tr.est2-hgroup-row th{font-size:var(--est-fs-sm);font-weight:700;color:var(--est-fg-muted);text-align:center;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);background:var(--est-bg-subtle);border-bottom:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th.est2-hgroup{color:var(--est-fg);border-left:1px solid var(--est-border);border-right:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th:not(.est2-hgroup){background:var(--est-bg-subtle);border-bottom-color:transparent}.est2 thead tr:last-child th.est2-col-groupstart,.est2 tbody td.est2-col-groupstart{border-left:1px solid var(--est-border)}.est2 tbody td{padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);color:var(--est-fg);vertical-align:middle;background:transparent}.est2 tbody tr:nth-child(2n) td{background:var(--est-bg-zebra)}.est2 tbody tr:nth-child(2n) td.est2-pinned{background:var(--est-bg-zebra)}.est2 tbody tr.est2-row--zebra td,.est2 tbody tr.est2-row--zebra td.est2-pinned{background:var(--est-bg-zebra)}.est2 tbody tr.est2-vspacer td{padding:0;border:none;background:transparent}.est2 tbody tr.est2-vspacer:hover td{background:transparent}.est2 th.est2-pinned,.est2 td.est2-pinned{position:sticky;background:var(--est-bg);box-shadow:1px 0 0 var(--est-border)}.est2 .est2-resize-handle{position:absolute;top:0;right:-3px;width:10px;height:100%;cursor:col-resize;z-index:2;touch-action:none;-webkit-user-select:none;user-select:none}.est2 .est2-resize-handle:after{content:\"\";position:absolute;top:28%;bottom:28%;right:3px;width:2px;border-radius:2px;background:color-mix(in srgb,var(--est-fg) 30%,transparent);transition:background var(--est-transition),top var(--est-transition),bottom var(--est-transition)}.est2 .est2-resize-handle:hover:after{background:var(--est-accent);top:15%;bottom:15%}.est2 .est2-resize-handle:active:after{background:var(--est-accent);top:6%;bottom:6%}.est2 td.est2-fixedw{overflow:hidden;text-overflow:ellipsis}.est2 td.est2-cell-invalid{background:color-mix(in srgb,var(--est-danger) 10%,var(--est-bg));box-shadow:inset 0 0 0 1px var(--est-danger);color:var(--est-danger)}.est2 .est2-selcol{width:44px;min-width:44px;max-width:44px}.est2 td.est2-pinned{z-index:3}.est2 thead th.est2-pinned,.est2 thead tr.est2-hgroup-row th.est2-pinned{z-index:6;background:var(--est-bg-subtle)}.est2 tbody tr:hover td.est2-pinned{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-pinned{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-pinned{background:var(--est-bg-subtle)}.est2 th.est2-chrome-col,.est2 td.est2-chrome-col{position:sticky;right:0;box-shadow:-1px 0 0 var(--est-border)}.est2 thead th.est2-chrome-col{z-index:16;background:var(--est-bg-subtle)}.est2 td.est2-chrome-col{z-index:4;background:var(--est-bg)}.est2 tbody tr:nth-child(2n) td.est2-chrome-col{background:var(--est-bg-zebra)}.est2 tbody tr:hover td.est2-chrome-col{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-chrome-col{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-chrome-col{background:var(--est-bg-subtle)}.est2 .est2-pinbtn{display:inline-flex;align-items:center;justify-content:center;margin-left:4px;padding:2px;border:none;background:transparent;color:var(--est-fg-faint);border-radius:var(--est-radius-sm);cursor:pointer;opacity:0;transition:opacity var(--est-transition),color var(--est-transition),background var(--est-transition)}.est2 thead th:hover .est2-pinbtn{opacity:.7}.est2 .est2-pinbtn:hover{background:var(--est-bg-hover);color:var(--est-fg);opacity:1}.est2 .est2-pinbtn--on{opacity:1;color:var(--est-accent);transform:rotate(0)}.est2 thead th:hover .est2-pinbtn--on{opacity:1}.est2 .est2-collist__pin.est2-collist__pin--on{color:var(--est-accent);border-color:var(--est-accent)}.est2 tbody tr{height:var(--est-row-h);transition:background var(--est-transition)}.est2 tbody tr:last-child td{border-bottom:none}.est2 tbody tr:hover td{background:var(--est-bg-hover)}.est2 tbody tr.est2-row--selected td{background:var(--est-bg-selected)}.est2 tbody tr.est2-row--clickable{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--removed td{text-decoration:line-through;color:var(--est-fg-faint)}.est2 .est2-table--range tbody td[data-r]{cursor:cell}.est2 .est2-table--dragging,.est2 .est2-table--dragging tbody td{-webkit-user-select:none;user-select:none}.est2 tbody td.est2-cell-sel{background:color-mix(in srgb,var(--est-accent) 14%,transparent)}.est2 tbody td.est2-cell-sel-t{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l{box-shadow:inset 2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-r{box-shadow:inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b{box-shadow:inset 0 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 0 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px -2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-editing{padding:2px 6px}.est2 .est2-editor-input{width:100%;box-sizing:border-box;height:calc(var(--est-row-h) - 8px);padding:2px 6px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1.5px solid var(--est-accent);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-editor-input:focus-visible{box-shadow:var(--est-ring)}.est2 input.est2-editor-input[type=checkbox]{width:16px;height:16px}.est2 .est2-autoupdate{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding:4px 2px 8px;font-size:var(--est-fs-sm);color:var(--est-fg-muted)}.est2 .est2-autoupdate__label{display:inline-flex;align-items:center;gap:6px}.est2 .est2-autoupdate__secs{width:44px;text-align:center;padding:3px 4px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-autoupdate__secs:focus-visible{box-shadow:var(--est-ring);border-color:var(--est-accent)}.est2 .est2-switch{position:relative;display:inline-flex;width:38px;height:20px;cursor:pointer}.est2 .est2-switch input{position:absolute;opacity:0;width:0;height:0}.est2 .est2-switch__slider{flex:1;border-radius:var(--est-radius-pill);background:var(--est-border-strong);transition:background var(--est-transition)}.est2 .est2-switch__slider:before{content:\"\";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px #00000040;transition:transform var(--est-transition)}.est2 .est2-switch input:checked+.est2-switch__slider{background:var(--est-accent)}.est2 .est2-switch input:checked+.est2-switch__slider:before{transform:translate(18px)}.est2 .est2-switch input:focus-visible+.est2-switch__slider{box-shadow:var(--est-ring)}.est2 .est2-toast{position:fixed;left:50%;bottom:24px;transform:translate(-50%);z-index:var(--est-z-toast);pointer-events:none;display:inline-flex;align-items:center;gap:8px;max-width:min(560px,100vw - 24px);padding:8px 14px;font-size:13px;font-weight:500;color:#fff;background:#b91c1c;border-radius:var(--est-radius);box-shadow:0 6px 20px #00000040;animation:est2-toast-in .16s ease-out}.est2 .est2-toast svg{flex:0 0 auto}@keyframes est2-toast-in{0%{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%)}}@media(prefers-reduced-motion:reduce){.est2 .est2-toast{animation:none}}.est2 tbody tr.est2-row--group{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--group td{background:var(--est-bg-subtle);font-weight:600;color:var(--est-fg);border-bottom:1px solid var(--est-border)}.est2 tbody tr.est2-row--group:hover td{background:var(--est-bg-hover)}.est2 .est2-td--group-key{color:var(--est-fg)}.est2 .est2-group-key{display:inline-flex;align-items:center;gap:6px}.est2 .est2-group-chevron{display:inline-flex;color:var(--est-fg-muted);transition:transform var(--est-transition)}.est2 .est2-group-chevron--open{transform:rotate(90deg)}.est2 .est2-hier-lead{display:inline-flex;align-items:center;vertical-align:middle;margin-right:4px}.est2 .est2-hier-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none}.est2 .est2-group-chevron.est2-hier-toggle{cursor:pointer;border-radius:var(--est-radius-sm);transition:transform var(--est-transition),background var(--est-transition),color var(--est-transition)}.est2 .est2-group-chevron.est2-hier-toggle:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 th.est2-th--orderable{cursor:pointer;transition:color var(--est-transition)}.est2 th.est2-th--orderable:hover{color:var(--est-fg)}.est2 .est2-th__inner{display:inline-flex;align-items:center;gap:6px}.est2 .est2-sort{display:inline-flex;width:14px;height:14px;opacity:.35;transition:opacity var(--est-transition),transform var(--est-transition)}.est2 .est2-sort--active{opacity:1;color:var(--est-accent)}.est2 .est2-sort--desc{transform:rotate(180deg)}.est2 .est2-sort__badge{font-size:9px;font-weight:700;color:var(--est-accent);margin-left:2px}.est2 .est2-check{appearance:none;width:16px;height:16px;border:1.5px solid var(--est-border-strong);border-radius:var(--est-radius-sm);background:var(--est-bg);cursor:pointer;position:relative;transition:border-color var(--est-transition),background var(--est-transition);vertical-align:middle;flex:none}.est2 .est2-check:hover{border-color:var(--est-accent)}.est2 .est2-check:checked{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:checked:after{content:\"\";position:absolute;left:4.5px;top:1.5px;width:4px;height:8px;border:solid var(--est-accent-fg);border-width:0 2px 2px 0;transform:rotate(45deg)}.est2 .est2-check:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2 .est2-check:disabled{opacity:.45;cursor:not-allowed}.est2 .est2-check:disabled:hover{border-color:var(--est-border-strong)}.est2 .est2-check:indeterminate{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:indeterminate:after{content:\"\";position:absolute;left:3px;top:6px;width:8px;height:2px;background:var(--est-accent-fg);transform:none;border:none}.est2 th.est2-col-min,.est2 td.est2-col-min{width:1%;white-space:nowrap}.est2 .est2-wrap,.est2 .est2-scroll-host{position:relative}.est2 .est2-selectbar{position:absolute;top:0;left:0;right:0;z-index:15;display:flex;align-items:center;gap:12px;padding:9px 14px;font-size:var(--est-fs-sm);color:var(--est-fg);background:var(--est-bg-subtle);border:none;border-radius:var(--est-radius) var(--est-radius) 0 0;box-shadow:inset 3px 0 0 var(--est-accent)}.est2 .est2-selectbar--inset{border-top-right-radius:0}.est2 .est2-selectbar strong{color:var(--est-fg);font-weight:700}.est2 .est2-selectbar__spacer{flex:1 1 auto}.est2 .est2-link{color:var(--est-accent);cursor:pointer;font-weight:600}.est2 .est2-link:hover{text-decoration:underline}.est2 .est2-rowaction{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);border:none;background:transparent;color:var(--est-fg-faint);cursor:pointer;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-rowaction:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-rowaction--danger:hover{color:var(--est-danger)}.est2 .est2-op-cell{text-align:center}.est2 .est2-op{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:26px;padding:0 6px;border-radius:var(--est-radius-sm);color:var(--est-accent);cursor:pointer;font-size:var(--est-fs-sm);transition:background var(--est-transition)}.est2 .est2-op:hover{background:var(--est-accent-weak)}.est2 .est2-loading{position:absolute;inset:0;border-radius:var(--est-radius);z-index:20;display:flex;align-items:center;justify-content:center;gap:10px;background:color-mix(in srgb,var(--est-bg) 70%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);color:var(--est-fg-muted);font-size:var(--est-fs-sm)}.est2 .est2-spinner{width:16px;height:16px;border:2px solid var(--est-border-strong);border-top-color:var(--est-accent);border-radius:50%;animation:est2-spin .7s linear infinite}@keyframes est2-spin{to{transform:rotate(360deg)}}.est2 .est2-nowrap{white-space:nowrap}.est2 .est2-cornermenu{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);cursor:pointer;color:var(--est-fg-muted);transition:background var(--est-transition)}.est2 .est2-cornermenu:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-chrome-th{position:relative}.est2 .est2-chrome{display:inline-flex;align-items:center;gap:2px}.est2 .est2-chrome-wrap{position:relative;display:inline-flex}.est2 .est2-chrome-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer;font-size:16px;line-height:1;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-chrome-btn:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-menu{position:fixed;z-index:var(--est-z-menu);min-width:180px;padding:4px;background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 8px 24px #0000002e;display:flex;flex-direction:column}.est2 .est2-menu-item{display:block;width:100%;padding:8px 10px;border:none;background:transparent;text-align:left;font:inherit;color:var(--est-fg);border-radius:var(--est-radius-sm);cursor:pointer}.est2 .est2-menu-item:hover{background:var(--est-bg-hover)}.est2 .est2-dialog-backdrop{position:fixed;inset:0;z-index:var(--est-z-modal);display:flex;align-items:center;justify-content:center;padding:16px}.est2 .est2-dialog-backdrop:before{content:\"\";position:absolute;inset:0;background-color:#000;opacity:.5}.est2 .est2-dialog{position:relative}.est2 .est2-dialog-backdrop--embedded{--est-embed-offset: 110px;padding-top:5%;margin-left:calc(-1 * var(--est-embed-offset));width:calc(100% + var(--est-embed-offset));overflow:hidden}.est2 .est2-dialog-backdrop--embedded .est2-dialog{max-height:600px}.est2 .est2-dialog{width:520px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);display:flex;flex-direction:column;background:var(--est-bg);color:var(--est-fg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 16px 48px #0000004d;overflow:hidden}.est2 .est2-dialog__head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;font-weight:700;border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__close{border:none;background:transparent;cursor:pointer;color:var(--est-fg-muted);font-size:15px;line-height:1;padding:4px;border-radius:var(--est-radius-sm)}.est2 .est2-dialog__close:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-dialog__tools{padding:8px 14px;font-size:var(--est-fs-sm);border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__tools .est2-link{border:none;background:none;padding:0;font:inherit;font-weight:600}.est2 .est2-dialog__sep{margin:0 6px;color:var(--est-fg-faint)}.est2 .est2-collist{list-style:none;margin:0;padding:6px;overflow-y:auto;flex:1 1 auto;min-height:0}.est2 .est2-collist__row{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:var(--est-radius-sm)}.est2 .est2-collist__row:hover{background:var(--est-bg-hover)}.est2 .est2-collist__row--drag{cursor:grab}.est2 .est2-collist__row--drag:active{cursor:grabbing}.est2 .est2-collist__row--dragging{opacity:.45;background:var(--est-bg-hover)}.est2 .est2-collist__row--drop-above{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 .est2-collist__row--drop-below{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 .est2-collist__grip{display:inline-flex;align-items:center;justify-content:center;color:var(--est-fg-faint);cursor:grab;flex:0 0 auto}.est2 .est2-collist__grip:active{cursor:grabbing}.est2 .est2-collist__row--drag:hover .est2-collist__grip{color:var(--est-fg-muted)}.est2 .est2-collist__grip--locked{color:var(--est-fg-faint);opacity:.55;cursor:default}.est2 .est2-collist__row--locked .est2-collist__label{color:var(--est-fg-muted)}.est2 .est2-collist__vis{display:inline-flex}.est2 .est2-collist__label{flex:1 1 auto}.est2 .est2-collist__path{color:var(--est-fg-faint);margin-right:4px}.est2 .est2-collist__ord{display:inline-flex;gap:4px}.est2 .est2-iconbtn{width:26px;height:26px;border:1px solid var(--est-border);background:var(--est-bg);border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer}.est2 .est2-iconbtn:hover:not(:disabled){background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-iconbtn:disabled{opacity:.4;cursor:default}.est2 .est2-dialog__foot{display:flex;align-items:center;gap:8px;padding:12px 14px;border-top:1px solid var(--est-border)}.est2 .est2-dialog__spacer{flex:1 1 auto}.est2 .est2-btn{padding:7px 14px;border-radius:var(--est-radius-sm);font:inherit;font-weight:600;cursor:pointer;border:1px solid transparent}.est2 .est2-btn--ghost{background:transparent;color:var(--est-fg);border-color:var(--est-border)}.est2 .est2-btn--ghost:hover{background:var(--est-bg-hover)}.est2 .est2-btn--primary{background:var(--est-accent);color:var(--est-accent-fg)}.est2 .est2-btn--primary:hover{filter:brightness(1.05)}.est2 .est2-empty{padding:48px 16px;text-align:center;color:var(--est-fg-faint);font-size:var(--est-fs-sm)}.ngx-contextmenu{--ctx-bg: #ffffff;--ctx-fg: #1a1d24;--ctx-muted: #626b7a;--ctx-border: #e6e9ef;--ctx-hover: #f2f4f7;--ctx-accent: #4f46e5;--ctx-shadow: 0 10px 28px -8px rgba(16, 24, 40, .22), 0 2px 8px -3px rgba(16, 24, 40, .14);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.ngx-contextmenu .dropdown-menu{display:block;min-width:200px;margin:0;padding:6px;list-style:none;background:var(--ctx-bg);border:1px solid var(--ctx-border);border-radius:12px;box-shadow:var(--ctx-shadow);animation:est2-ctx-in .12s cubic-bezier(.16,1,.3,1)}.ngx-contextmenu li{list-style:none;margin:0}.ngx-contextmenu li>a{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:7px;color:var(--ctx-fg);font-size:13.5px;line-height:1.2;text-decoration:none;cursor:pointer;white-space:nowrap;transition:background .12s ease,color .12s ease}.ngx-contextmenu li>a:hover,.ngx-contextmenu li>a:focus{background:var(--ctx-hover);color:var(--ctx-fg);text-decoration:none;outline:none}.ngx-contextmenu li.divider,.ngx-contextmenu li[role=separator]{height:1px;margin:6px 8px;padding:0;background:var(--ctx-border)}.ngx-contextmenu li.disabled>a,.ngx-contextmenu li[aria-disabled=true]>a{color:var(--ctx-muted);opacity:.55;pointer-events:none}@media(prefers-color-scheme:dark){.ngx-contextmenu{--ctx-bg: #1e222b;--ctx-fg: #e7eaf0;--ctx-muted: #9aa3b2;--ctx-border: #2a2f3a;--ctx-hover: #232733;--ctx-accent: #7c74ff;--ctx-shadow: 0 12px 30px -8px rgba(0, 0, 0, .6), 0 2px 8px -3px rgba(0, 0, 0, .5)}}@keyframes est2-ctx-in{0%{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@media(prefers-reduced-motion:reduce){.ngx-contextmenu .dropdown-menu{animation:none}}\n"], dependencies: [{ kind: "directive", type: i8.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.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.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i9.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i12.ContextMenuAttachDirective, selector: "[contextMenu]", inputs: ["contextMenuSubject", "contextMenu"] }, { kind: "component", type: i12.ContextMenuComponent, selector: "context-menu", inputs: ["menuClass", "autoFocus", "useBootstrap4", "disabled"], outputs: ["close", "open"] }, { kind: "directive", type: i12.ContextMenuItemDirective, selector: "[contextMenuItem]", inputs: ["subMenu", "divider", "enabled", "passive", "visible"], outputs: ["execute"] }, { kind: "component", type: EsTable2PagerComponent, selector: "es-table2-pager", inputs: ["page", "pages", "total", "itemsPerPage", "countLabel", "locale", "showCount", "showButtons", "showPagingOptions", "allowAll"], outputs: ["pageChange", "itemsPerPageChange"] }, { kind: "pipe", type: i3.LocalizePipe, name: "localize" }, { kind: "pipe", type: Est2FormatPipe, name: "est2_format" }, { kind: "pipe", type: Est2LookupPipe, name: "est2_lookup" }], viewProviders: [{ provide: LocalizationService, useClass: EsTable2Loc }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
9585
9889
|
}
|
|
9586
9890
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: EsTable2Component, decorators: [{
|
|
9587
9891
|
type: Component,
|
|
9588
|
-
args: [{ selector: 'es-table2', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, viewProviders: [{ provide: LocalizationService, useClass: EsTable2Loc }], template: "@if (view()) {\n <div class=\"est2-wrap {{ ContainerClass() }}\"\n [style.height]=\"Height()\"\n [style.background-color]=\"EmptySpaceBackgroundColor() || null\">\n\n <!-- Auto-aggiornamento: toggle + intervallo (in alto a destra) -->\n @if (AutoUpdate()) {\n <div class=\"est2-autoupdate\">\n <label class=\"est2-autoupdate__label\">\n {{ 'Update every' | localize : lc }}\n <input type=\"text\" maxlength=\"3\" class=\"est2-autoupdate__secs\"\n [ngModel]=\"seconds()\" (ngModelChange)=\"seconds.set($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n (change)=\"autoUpdateChanged()\" />\n {{ 'second/s' | localize : lc }}\n </label>\n <label class=\"est2-switch\" [title]=\"'Toggle auto-update' | localize : lc\">\n <input type=\"checkbox\" [ngModel]=\"autoUpdate()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"autoUpdate.set($event); autoUpdateChanged()\" />\n <span class=\"est2-switch__slider\"></span>\n </label>\n </div>\n }\n\n <!-- Pager superiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'top') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Host POSIZIONATO dello scroller: \u00E8 l'ancora di tutti gli overlay che devono\n coprire la TABELLA (barra di selezione, overlay di caricamento). Senza di esso\n erano ancorati a `.est2-wrap` e con [AutoUpdate] o il pager in alto finivano\n sopra quei controlli invece che sopra l'header. -->\n <div class=\"est2-scroll-host\">\n\n <!-- Barra \"seleziona tutto\" (visibile solo con selezione multipla attiva e righe presenti) -->\n @if (Selection() && !SingleSelection() && hasSelection) {\n <div class=\"est2-selectbar\"\n [class.est2-selectbar--inset]=\"chromeWidth() > 0\"\n [style.height.px]=\"selbarHeight() ? selbarHeight() + 1 : null\"\n [style.right.px]=\"chromeWidth() || null\">\n @if (allSelected) {\n <span>{{ 'All the' | localize : lc }} <strong>{{ selectedCount }}</strong> {{ 'elements are selected' | localize : lc }}</span>\n } @else {\n <span><strong>{{ selectedCount }}</strong> {{ (selectedCount === 1 ? 'element selected' : 'elements selected') | localize : lc }}</span>\n @if (canSelectEverything) {\n <span class=\"est2-link\" (click)=\"selectEverything()\">{{ 'Select all' | localize : lc }} {{ totalCount() }} {{ 'elements' | localize : lc }}</span>\n }\n }\n <span class=\"est2-selectbar__spacer\"></span>\n <span class=\"est2-link\" (click)=\"clearSelection()\">{{ 'Reset selection' | localize : lc }}</span>\n </div>\n }\n\n <div class=\"est2-scroll\" [style.max-height.px]=\"MaxHeight()\">\n <table class=\"est2-table {{ TableClass() }}\"\n [class.est2-table--range]=\"rangeActive()\"\n [class.est2-table--dragging]=\"rangeDragging()\"\n (mousedown)=\"onGridMouseDown($event)\"\n (mouseover)=\"onGridMouseOver($event)\">\n\n <!-- ================= HEADER ================= -->\n @if (!HeaderHidden()) {\n <thead #theadRef>\n <!-- Righe di header-group multi-livello (dall'alto verso il basso) -->\n @if (hasHeaderGroups()) {\n @for (grow of headerGroupRows(); track $index) {\n <tr class=\"est2-hgroup-row\">\n @if (Selection()) { <th class=\"est2-col-min est2-selcol\" [class.est2-pinned]=\"hasPinned()\" [style.left.px]=\"hasPinned() ? 0 : null\"></th> }\n @for (op of DynamicOperations(); track op.id) { <th class=\"est2-col-min\"></th> }\n @for (cell of grow; track cell.id; let gi = $index) {\n <th [attr.colspan]=\"cell.span\"\n [attr.data-groupid]=\"cell.isGroup ? cell.id : null\"\n [class.est2-hgroup]=\"cell.isGroup\"\n [class.est2-pinned]=\"gi < pinnedCount()\"\n [style.left.px]=\"gi < pinnedCount() ? pinnedLeftPx(gi) : null\"\n class=\"est2-hgroup-cell\">\n @if (cell.isGroup) {\n @if (cell.template) {\n <ng-container *ngTemplateOutlet=\"cell.template\"></ng-container>\n } @else {\n {{ cell.label }}\n }\n }\n </th>\n }\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n @if (hasChrome()) { <th class=\"est2-col-min est2-chrome-col\"></th> }\n </tr>\n }\n }\n <tr>\n <!-- Colonna di selezione -->\n @if (Selection()) {\n <th class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"globalCheck()\"\n [indeterminate]=\"selectionIndeterminate\"\n [disabled]=\"SelectionDisabled()\"\n (change)=\"toggleAll()\"\n [attr.aria-label]=\"'Select all rows' | localize : lc\" />\n }\n </th>\n }\n\n <!-- Header da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- intestazioni vuote per le operazioni dinamiche -->\n @for (op of DynamicOperations(); track op.id) {\n <th class=\"est2-col-min\"></th>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let ci = $index) {\n @let hs = colStyles()[ci];\n <th [attr.data-colid]=\"col.id\"\n [class]=\"col.headerClass\"\n [class.est2-th--orderable]=\"OrderByColumn() && col.orderable\"\n [class.est2-col-min]=\"col.header?.thShrink\"\n [class.est2-col-groupstart]=\"hs.groupStart\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"hs.left\"\n [style.width.px]=\"hs.width\"\n [style.min-width.px]=\"hs.width\"\n [style.max-width.px]=\"hs.width\"\n [style.text-align]=\"col.alignment\"\n [style.background-color]=\"col.headerBg || null\"\n (click)=\"toggleSort(col)\">\n <span class=\"est2-th__inner\">\n @if (col.header?.Template) {\n <ng-container *ngTemplateOutlet=\"col.header!.Template!; context: col.multiProp != null ? { $implicit: col.headerText } : null\"></ng-container>\n } @else {\n {{ col.headerText }}\n }\n @if (OrderByColumn() && col.orderable && orderOf(col.id)) {\n <span class=\"est2-sort est2-sort--active\"\n [class.est2-sort--desc]=\"orderOf(col.id) === 'DESC'\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6 15l6-6 6 6\"/></svg>\n </span>\n @if (orderIndex(col.id) > 0 && MultipleOrderingDirectives()) {\n <span class=\"est2-sort__badge\">{{ orderIndex(col.id) }}</span>\n }\n }\n <!-- Indicatore/toggle di pin (visibile se pinnata o all'hover) -->\n @if (ColumnsPinnable() && col.multiProp == null && !col.fixed) {\n <button type=\"button\" class=\"est2-pinbtn\"\n [class.est2-pinbtn--on]=\"col.pinned\"\n [title]=\"(col.pinned ? 'Unlock column' : 'Lock column to the left') | localize : lc\"\n (click)=\"togglePin(col, $event)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n </span>\n <!-- Handle di ridimensionamento (colonne pinnate, gated da ColumnsResizable) -->\n @if (col.pinned || ColumnsResizable()) {\n <span class=\"est2-resize-handle\" [title]=\"'Drag to resize' | localize : lc\"\n (mousedown)=\"startColumnResize(col, $event)\"\n (click)=\"$event.stopPropagation()\"></span>\n }\n </th>\n }\n }\n <!-- Header da template semplice -->\n @else if (headerRef) {\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\n }\n\n <!-- Colonna rimozione -->\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n <!-- Colonna chrome (export / gestione colonne / menu) -->\n @if (hasChrome()) {\n <th class=\"est2-col-min est2-chrome-th est2-chrome-col\">\n <div class=\"est2-chrome\">\n <!-- I pannelli dei menu NON vivono qui: sono renderizzati a fondo\n componente e posizionati `fixed`, altrimenti l'`overflow:auto`\n di `.est2-scroll` li taglierebbe su tabelle basse. -->\n @if (Export()) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Export' | localize : lc\" (click)=\"$event.stopPropagation(); toggleExportMenu($event)\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><path d=\"M7 10l5 5 5-5\"/><path d=\"M12 15V3\"/></svg>\n </button>\n }\n @if (HiddenColumns() || ColumnsOrdering()) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Columns' | localize : lc\" (click)=\"$event.stopPropagation(); openColumnsDialog()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><path d=\"M9 3v18\"/><path d=\"M15 3v18\"/></svg>\n </button>\n }\n @if (CornerMenuOptions().length > 0) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Options' | localize : lc\" (click)=\"$event.stopPropagation(); toggleCornerMenu($event)\">\u22EE</button>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n }\n\n <!-- ================= BODY ================= -->\n @if (!BodyHidden()) {\n <tbody>\n <!-- Valori invarianti per l'intero corpo: senza questi verrebbero\n ricalcolati riga\u00D7colonna volte a ogni ciclo di change-detection. -->\n @let rng = rangeActive();\n @let rect = rangeRect();\n @let errs = hasCellErrors();\n @for (item of boundSource(); track trackRow($index, item); let ri = $index) {\n @if ((!grouped() && !Hierarchy()) || item._visible) {\n <tr [class]=\"rowClass(item)\"\n [class.est2-row--selected]=\"item._selected\"\n [class.est2-row--removed]=\"item.removed || item.deleted\"\n [class.est2-row--group]=\"item._group\"\n [class.est2-row--clickable]=\"Selection() || item._group\"\n [contextMenu]=\"ContextMenu || emptyMenu\"\n [contextMenuSubject]=\"item\"\n (click)=\"handleRowClick(item, $event)\">\n\n <!-- Cella di selezione -->\n @if (Selection()) {\n <td class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (item._group) {\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"groupSelectionState(item) === 'all'\"\n [indeterminate]=\"groupSelectionState(item) === 'some'\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection(item)\"\n [attr.aria-label]=\"'Select group' | localize : lc\" />\n }\n } @else {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"item._selected\"\n [indeterminate]=\"hierarchyIndeterminate(item)\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(item)\"\n [attr.aria-label]=\"'Select row' | localize : lc\" />\n }\n </td>\n }\n\n <!-- Celle da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- Operazioni dinamiche (icone a sinistra) -->\n @for (op of DynamicOperations(); track op.id) {\n <td class=\"est2-col-min est2-op-cell\">\n @if (!item._group && operationVisible(op, item)) {\n <span class=\"est2-op\" [class]=\"op.iconClass || ''\" [title]=\"op.title\"\n (click)=\"$event.stopPropagation(); dynamicOperation(item, op.id)\">{{ op.text }}</span>\n }\n </td>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let first = $first, ci = $index) {\n @let cs = colStyles()[ci];\n @let insel = rng && inRange(ri, ci);\n @let editing = isEditing(ri, ci);\n <td [class]=\"col.cssClass\"\n [style.text-align]=\"col.alignment\"\n [style.color]=\"cellColor(item, col, 'fore')\"\n [style.background-color]=\"cellColor(item, col, 'back')\"\n [class.est2-nowrap]=\"!col.wrap\"\n [class.est2-col-groupstart]=\"cs.groupStart\"\n [class.est2-pinned]=\"col.pinned\"\n [class.est2-fixedw]=\"cs.width != null\"\n [style.left.px]=\"cs.left\"\n [style.width.px]=\"cs.width\"\n [style.min-width.px]=\"cs.width\"\n [style.max-width.px]=\"cs.width\"\n [class.est2-td--group-key]=\"item._group && item.column === col.id\"\n [attr.data-r]=\"rng && !item._group ? ri : null\"\n [attr.data-c]=\"rng && !item._group ? ci : null\"\n [class.est2-cell-sel]=\"insel\"\n [class.est2-cell-sel-t]=\"insel && ri === rect!.top\"\n [class.est2-cell-sel-b]=\"insel && ri === rect!.bottom\"\n [class.est2-cell-sel-l]=\"insel && ci === rect!.left\"\n [class.est2-cell-sel-r]=\"insel && ci === rect!.right\"\n [class.est2-cell-editing]=\"editing\"\n [class.est2-cell-invalid]=\"errs && !!cellError(item, col)\"\n [attr.data-error]=\"errs ? (cellError(item, col) || null) : null\"\n (dblclick)=\"onCellDblClick(item, col, ri, ci)\">\n @if (editing) {\n @if (editorFor(col); as edTpl) {\n <ng-container *ngTemplateOutlet=\"edTpl; context: editorContext(item, col)\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"defaultEditor; context: { $implicit: item, col: col }\"></ng-container>\n }\n } @else if (item._group) {\n @if (item.column === col.id) {\n <span class=\"est2-group-key\" [style.padding-left.px]=\"groupIndent(item)\">\n <span class=\"est2-group-chevron\" [class.est2-group-chevron--open]=\"item._expanded\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n {{ groupCellDisplay(item, col) }}\n </span>\n } @else {\n {{ groupCellDisplay(item, col) }}\n }\n } @else {\n <!-- Navigatore albero nella prima colonna -->\n @if (Hierarchy() && first) {\n <span class=\"est2-hier-lead\" [style.padding-left.px]=\"hierarchyIndent(item)\">\n @if (item.parent) {\n <span class=\"est2-group-chevron est2-hier-toggle\" [class.est2-group-chevron--open]=\"item._expanded\"\n (click)=\"$event.stopPropagation(); toggleHierarchyNode(item)\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-hier-toggle\"></span>\n }\n </span>\n }\n @if (itemCellHidden(col)) {\n <!-- colonna di gruppo nascosta sulla riga-oggetto -->\n } @else if (col.multiProp != null) {\n @if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: multiCell(item, col) }\"></ng-container>\n } @else {\n {{ multiCell(item, col)?.value }}\n }\n } @else if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: item }\"></ng-container>\n } @else if (col.routePath) {\n <a class=\"est2-link\" [routerLink]=\"routerLinkFor(item, col)\">{{ cellValue(item, col) }}</a>\n } @else if (col.propAccessor != null) {\n {{ reportCellDisplay(item, col) }}\n } @else if (col.type === 'enum') {\n {{ (cellValue(item, col) | est2_lookup : col.source).description }}\n } @else {\n {{ cellValue(item, col) | est2_format : col.type : col.format : locale }}\n }\n }\n </td>\n }\n }\n <!-- Celle da template semplice -->\n @else if (bodyRef) {\n <ng-container *ngTemplateOutlet=\"bodyRef; context: { $implicit: item }\"></ng-container>\n }\n\n <!-- Rimozione (non sulle righe-gruppo) -->\n @if (Removal()) {\n <td class=\"est2-col-min\">\n @if (!item._group && canRemove(item)) {\n @if (item.removed || item.deleted) {\n <button type=\"button\" class=\"est2-rowaction\" [title]=\"'Restore' | localize : lc\" (click)=\"abortRemoval(item)\">\u21BA</button>\n } @else {\n <button type=\"button\" class=\"est2-rowaction est2-rowaction--danger\" [title]=\"'Remove' | localize : lc\" (click)=\"removeItem(item)\">\u2715</button>\n }\n }\n </td>\n }\n <!-- Chrome -->\n @if (hasChrome()) { <td class=\"est2-col-min est2-chrome-col\"></td> }\n </tr>\n }\n } @empty {\n <tr>\n <td class=\"est2-empty\" [attr.colspan]=\"totalColspan()\">{{ 'No elements to display' | localize : lc }}</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\n\n <!-- Overlay di caricamento: FUORI dallo scroller, cos\u00EC copre il viewport della\n tabella senza scorrere col contenuto e senza essere bucato dalle celle sticky -->\n @if (researchInProgress() || (firstBind() && ShowLoadingOnBootstrap())) {\n <div class=\"est2-loading\">\n <span class=\"est2-spinner\"></span>\n <span>{{ 'Loading\u2026' | localize : lc }}</span>\n </div>\n }\n\n </div>\n\n <!-- Pager inferiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Menu del chrome (export / opzioni). Renderizzati FUORI da `.est2-scroll` e\n posizionati `fixed` sulle coordinate del bottone che li ha aperti: cos\u00EC non\n vengono tagliati dall'`overflow:auto` dello scroller su tabelle basse, e\n restano dentro `.est2` (i token `--est-*` continuano a ereditare). -->\n @if (exportMenuOpen() && menuAnchor(); as anchor) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\"\n [style.top.px]=\"anchor.top\" [style.right.px]=\"anchor.right\">\n @if (CSVExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">{{ 'Export CSV' | localize : lc }}</button> }\n @if (XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('XLSX')\">{{ 'Export Excel (XLSX)' | localize : lc }}</button> }\n @if (!CSVExport() && !XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">{{ 'Export CSV' | localize : lc }}</button> }\n </div>\n }\n @if (cornerMenuOpen() && menuAnchor(); as anchor) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\"\n [style.top.px]=\"anchor.top\" [style.right.px]=\"anchor.right\">\n @for (opt of CornerMenuOptions(); track opt.id) {\n <button type=\"button\" class=\"est2-menu-item\" (click)=\"cornerAction(opt.id); closeChromeMenus()\">{{ opt.description }}</button>\n }\n </div>\n }\n\n <!-- Avviso transitorio (es. incolla con dimensioni incompatibili) -->\n @if (notice()) {\n <div class=\"est2-toast\" role=\"alert\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/></svg>\n <span>{{ notice() }}</span>\n </div>\n }\n\n <!-- Dialog visibilit\u00E0 / ordine colonne -->\n @if (columnsDialogOpen()) {\n <div class=\"est2-dialog-backdrop\" #dialogBackdrop\n [class.est2-dialog-backdrop--embedded]=\"embedded\"\n (click)=\"closeColumnsDialog()\">\n <div class=\"est2-dialog\" (click)=\"$event.stopPropagation()\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"est2-dialog__head\">\n <span>\n @if (HiddenColumns() && ColumnsOrdering()) { {{ 'Columns visibility and order' | localize : lc }} }\n @else if (HiddenColumns()) { {{ 'Columns visibility' | localize : lc }} }\n @else { {{ 'Columns order' | localize : lc }} }\n </span>\n <button type=\"button\" class=\"est2-dialog__close\" (click)=\"closeColumnsDialog()\" [attr.aria-label]=\"'Close' | localize : lc\">\u2715</button>\n </div>\n\n @if (HiddenColumns()) {\n <div class=\"est2-dialog__tools\">\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(true)\">{{ 'Show all' | localize : lc }}</button>\n <span class=\"est2-dialog__sep\">\u00B7</span>\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(false)\">{{ 'Hide all' | localize : lc }}</button>\n </div>\n }\n\n <ul class=\"est2-collist\">\n @for (c of dialogCols(); track c.id; let i = $index) {\n <li class=\"est2-collist__row\"\n [attr.draggable]=\"ColumnsOrdering() && canReorder(c) ? true : null\"\n [class.est2-collist__row--drag]=\"ColumnsOrdering() && canReorder(c)\"\n [class.est2-collist__row--locked]=\"!canReorder(c)\"\n [class.est2-collist__row--dragging]=\"dragIndex() === i\"\n [class.est2-collist__row--drop-above]=\"dragOverIndex() === i && dragIndex() !== null && dragIndex()! > i\"\n [class.est2-collist__row--drop-below]=\"dragOverIndex() === i && dragIndex() !== null && dragIndex()! < i\"\n (dragstart)=\"dialogDragStart(i, $event)\"\n (dragover)=\"dialogDragOver(i, $event)\"\n (drop)=\"dialogDrop(i, $event)\"\n (dragend)=\"dialogDragEnd()\">\n @if (ColumnsOrdering()) {\n @if (canReorder(c)) {\n <span class=\"est2-collist__grip\" [title]=\"'Drag to reorder' | localize : lc\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"currentColor\"><circle cx=\"9\" cy=\"6\" r=\"1.6\"/><circle cx=\"15\" cy=\"6\" r=\"1.6\"/><circle cx=\"9\" cy=\"12\" r=\"1.6\"/><circle cx=\"15\" cy=\"12\" r=\"1.6\"/><circle cx=\"9\" cy=\"18\" r=\"1.6\"/><circle cx=\"15\" cy=\"18\" r=\"1.6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-collist__grip est2-collist__grip--locked\"\n [title]=\"(c.fixed ? 'Fixed column: cannot be moved' : 'Column locked to the left: cannot be moved') | localize : lc\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"4\" y=\"11\" width=\"16\" height=\"10\" rx=\"2\"/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"/></svg>\n </span>\n }\n }\n @if (HiddenColumns()) {\n <label class=\"est2-collist__vis\" [title]=\"c.fixed ? ('Fixed column: always visible' | localize : lc) : ''\">\n <input type=\"checkbox\" class=\"est2-check\" [checked]=\"c.visible\" [disabled]=\"c.fixed\" (change)=\"dialogToggle(i)\" />\n </label>\n }\n <span class=\"est2-collist__label\">\n @if (c.tmpl) {\n <!-- colonna non renderizzata (Visible:false / nascosta): il testo\n header non esiste nel DOM, quindi rendo il template dell'`*th` -->\n @if (c.prefix) { <span class=\"est2-collist__path\">{{ c.prefix }}</span> }\n <ng-container *ngTemplateOutlet=\"c.tmpl; context: c.tmplCtx\"></ng-container>\n } @else {\n {{ c.label }}\n }\n </span>\n @if (ColumnsPinnable()) {\n <button type=\"button\" class=\"est2-iconbtn est2-collist__pin\" [class.est2-collist__pin--on]=\"c.pinned\"\n [disabled]=\"c.grouped || c.fixed\"\n [title]=\"(c.fixed ? 'Fixed columns cannot be locked' : (c.grouped ? 'Grouped columns cannot be locked' : (c.pinned ? 'Unlock' : 'Lock to the left'))) | localize : lc\"\n (click)=\"dialogTogglePin(i)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n @if (ColumnsOrdering()) {\n <span class=\"est2-collist__ord\">\n <button type=\"button\" class=\"est2-iconbtn\" [title]=\"'Up' | localize : lc\" (click)=\"dialogMove(i, -1)\"\n [disabled]=\"i === 0 || !canReorder(c) || !canReorder(dialogCols()[i - 1])\">\u2191</button>\n <button type=\"button\" class=\"est2-iconbtn\" [title]=\"'Down' | localize : lc\" (click)=\"dialogMove(i, 1)\"\n [disabled]=\"i === dialogCols().length - 1 || !canReorder(c) || !canReorder(dialogCols()[i + 1])\">\u2193</button>\n </span>\n }\n </li>\n }\n </ul>\n\n <div class=\"est2-dialog__foot\">\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"resetColumnsDialog()\">{{ 'Reset' | localize : lc }}</button>\n <span class=\"est2-dialog__spacer\"></span>\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"closeColumnsDialog()\">{{ 'Cancel' | localize : lc }}</button>\n <button type=\"button\" class=\"est2-btn est2-btn--primary\" (click)=\"applyColumnsDialog()\">{{ 'Apply' | localize : lc }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n}\n\n<!-- Template pager riutilizzabile sopra/sotto -->\n<ng-template #pager>\n @if (!HidePaging() && !grouped()) {\n <es-table2-pager\n [page]=\"currentPage()\"\n [pages]=\"totalPages()\"\n [total]=\"totalCount()\"\n [locale]=\"locale\"\n [itemsPerPage]=\"viewMode() ? (view()?.itemsperpageoverride ?? 15) : ArraymodeItemsPerPage()\"\n [countLabel]=\"CountLabel()\"\n [showCount]=\"!HidePagingCount()\"\n [showButtons]=\"!HidePagingButtons()\"\n [showPagingOptions]=\"!HidePagingButtons()\"\n [allowAll]=\"AllSearch()\"\n (pageChange)=\"goToPage($event)\"\n (itemsPerPageChange)=\"changeItemsPerPage($event)\">\n </es-table2-pager>\n }\n</ng-template>\n\n<!-- Editor di cella di default (usato quando il consumer non fornisce un `*editor`) -->\n<ng-template #defaultEditor let-item let-col=\"col\">\n @switch (col.type) {\n @case ('enum') {\n <select class=\"est2-editor-input\"\n [value]=\"editDraft\"\n (change)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\">\n @for (o of col.source || []; track o.id) {\n <option [value]=\"o.id\" [selected]=\"o.id == editDraft\">{{ o.description }}</option>\n }\n </select>\n }\n @case ('boolean') {\n <input type=\"checkbox\" class=\"est2-editor-input est2-check\"\n [checked]=\"editDraft === true || editDraft === 'true'\"\n (change)=\"editDraft = $any($event.target).checked; commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\" />\n }\n @default {\n <input class=\"est2-editor-input\"\n [type]=\"editorInputType(col.type)\"\n [value]=\"editDraft\"\n (input)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\" />\n }\n }\n</ng-template>\n\n<!-- Menu di default (nessuna operazione) usato quando il consumer non passa [ContextMenu] -->\n<context-menu #emptyMenu>\n <ng-template contextMenuItem [passive]=\"true\"><em>{{ 'No operations available\u2026' | localize : lc }}</em></ng-template>\n</context-menu>\n", styles: [".est2{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent);--est-radius: 10px;--est-radius-sm: 6px;--est-radius-pill: 999px;--est-gap: 8px;--est-cell-py: 6px;--est-cell-px: 12px;--est-row-h: 33px;--est-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--est-fs: 13px;--est-fs-sm: 12px;--est-fw-head: 700;--est-transition: .14s cubic-bezier(.4, 0, .2, 1);--est-bg-zebra: color-mix(in srgb, var(--est-fg) 3.5%, var(--est-bg));--est-z-menu: 1000;--est-z-modal: 1010;--est-z-toast: 1020;font-family:var(--est-font);font-size:var(--est-fs);color:var(--est-fg);position:relative;display:block}@media(prefers-color-scheme:dark){.est2{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}}.est2.est2--dark{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}.est2.est2--light{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent)}.est2.est2--dense{--est-cell-py: 3px;--est-cell-px: 9px;--est-row-h: 27px;--est-fs: 12.5px}.est2 *,.est2 *:before,.est2 *:after{box-sizing:border-box}.est2 .est2-scroll{position:relative;width:100%;overflow:auto;border:1px solid var(--est-border);border-radius:var(--est-radius);background:var(--est-bg);-webkit-overflow-scrolling:touch}.est2 table.est2-table{width:100%;border-collapse:separate;border-spacing:0;background:var(--est-bg)}.est2 thead th{position:sticky;top:0;z-index:3;background:var(--est-bg-subtle);color:var(--est-fg);font-weight:var(--est-fw-head);font-size:var(--est-fs);text-align:left;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);box-shadow:var(--est-shadow-sticky);-webkit-user-select:none;user-select:none}.est2 thead tr.est2-hgroup-row th{font-size:var(--est-fs-sm);font-weight:700;color:var(--est-fg-muted);text-align:center;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);background:var(--est-bg-subtle);border-bottom:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th.est2-hgroup{color:var(--est-fg);border-left:1px solid var(--est-border);border-right:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th:not(.est2-hgroup){background:var(--est-bg-subtle);border-bottom-color:transparent}.est2 thead tr:last-child th.est2-col-groupstart,.est2 tbody td.est2-col-groupstart{border-left:1px solid var(--est-border)}.est2 tbody td{padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);color:var(--est-fg);vertical-align:middle;background:transparent}.est2 tbody tr:nth-child(2n) td{background:var(--est-bg-zebra)}.est2 tbody tr:nth-child(2n) td.est2-pinned{background:var(--est-bg-zebra)}.est2 th.est2-pinned,.est2 td.est2-pinned{position:sticky;background:var(--est-bg);box-shadow:1px 0 0 var(--est-border)}.est2 .est2-resize-handle{position:absolute;top:0;right:-3px;width:10px;height:100%;cursor:col-resize;z-index:2;touch-action:none;-webkit-user-select:none;user-select:none}.est2 .est2-resize-handle:after{content:\"\";position:absolute;top:28%;bottom:28%;right:3px;width:2px;border-radius:2px;background:color-mix(in srgb,var(--est-fg) 30%,transparent);transition:background var(--est-transition),top var(--est-transition),bottom var(--est-transition)}.est2 .est2-resize-handle:hover:after{background:var(--est-accent);top:15%;bottom:15%}.est2 .est2-resize-handle:active:after{background:var(--est-accent);top:6%;bottom:6%}.est2 td.est2-fixedw{overflow:hidden;text-overflow:ellipsis}.est2 td.est2-cell-invalid{background:color-mix(in srgb,var(--est-danger) 10%,var(--est-bg));box-shadow:inset 0 0 0 1px var(--est-danger);color:var(--est-danger)}.est2 .est2-selcol{width:44px;min-width:44px;max-width:44px}.est2 td.est2-pinned{z-index:3}.est2 thead th.est2-pinned,.est2 thead tr.est2-hgroup-row th.est2-pinned{z-index:6;background:var(--est-bg-subtle)}.est2 tbody tr:hover td.est2-pinned{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-pinned{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-pinned{background:var(--est-bg-subtle)}.est2 th.est2-chrome-col,.est2 td.est2-chrome-col{position:sticky;right:0;box-shadow:-1px 0 0 var(--est-border)}.est2 thead th.est2-chrome-col{z-index:16;background:var(--est-bg-subtle)}.est2 td.est2-chrome-col{z-index:4;background:var(--est-bg)}.est2 tbody tr:nth-child(2n) td.est2-chrome-col{background:var(--est-bg-zebra)}.est2 tbody tr:hover td.est2-chrome-col{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-chrome-col{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-chrome-col{background:var(--est-bg-subtle)}.est2 .est2-pinbtn{display:inline-flex;align-items:center;justify-content:center;margin-left:4px;padding:2px;border:none;background:transparent;color:var(--est-fg-faint);border-radius:var(--est-radius-sm);cursor:pointer;opacity:0;transition:opacity var(--est-transition),color var(--est-transition),background var(--est-transition)}.est2 thead th:hover .est2-pinbtn{opacity:.7}.est2 .est2-pinbtn:hover{background:var(--est-bg-hover);color:var(--est-fg);opacity:1}.est2 .est2-pinbtn--on{opacity:1;color:var(--est-accent);transform:rotate(0)}.est2 thead th:hover .est2-pinbtn--on{opacity:1}.est2 .est2-collist__pin.est2-collist__pin--on{color:var(--est-accent);border-color:var(--est-accent)}.est2 tbody tr{height:var(--est-row-h);transition:background var(--est-transition)}.est2 tbody tr:last-child td{border-bottom:none}.est2 tbody tr:hover td{background:var(--est-bg-hover)}.est2 tbody tr.est2-row--selected td{background:var(--est-bg-selected)}.est2 tbody tr.est2-row--clickable{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--removed td{text-decoration:line-through;color:var(--est-fg-faint)}.est2 .est2-table--range tbody td[data-r]{cursor:cell}.est2 .est2-table--dragging,.est2 .est2-table--dragging tbody td{-webkit-user-select:none;user-select:none}.est2 tbody td.est2-cell-sel{background:color-mix(in srgb,var(--est-accent) 14%,transparent)}.est2 tbody td.est2-cell-sel-t{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l{box-shadow:inset 2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-r{box-shadow:inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b{box-shadow:inset 0 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 0 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px -2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-editing{padding:2px 6px}.est2 .est2-editor-input{width:100%;box-sizing:border-box;height:calc(var(--est-row-h) - 8px);padding:2px 6px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1.5px solid var(--est-accent);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-editor-input:focus-visible{box-shadow:var(--est-ring)}.est2 input.est2-editor-input[type=checkbox]{width:16px;height:16px}.est2 .est2-autoupdate{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding:4px 2px 8px;font-size:var(--est-fs-sm);color:var(--est-fg-muted)}.est2 .est2-autoupdate__label{display:inline-flex;align-items:center;gap:6px}.est2 .est2-autoupdate__secs{width:44px;text-align:center;padding:3px 4px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-autoupdate__secs:focus-visible{box-shadow:var(--est-ring);border-color:var(--est-accent)}.est2 .est2-switch{position:relative;display:inline-flex;width:38px;height:20px;cursor:pointer}.est2 .est2-switch input{position:absolute;opacity:0;width:0;height:0}.est2 .est2-switch__slider{flex:1;border-radius:var(--est-radius-pill);background:var(--est-border-strong);transition:background var(--est-transition)}.est2 .est2-switch__slider:before{content:\"\";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px #00000040;transition:transform var(--est-transition)}.est2 .est2-switch input:checked+.est2-switch__slider{background:var(--est-accent)}.est2 .est2-switch input:checked+.est2-switch__slider:before{transform:translate(18px)}.est2 .est2-switch input:focus-visible+.est2-switch__slider{box-shadow:var(--est-ring)}.est2 .est2-toast{position:fixed;left:50%;bottom:24px;transform:translate(-50%);z-index:var(--est-z-toast);pointer-events:none;display:inline-flex;align-items:center;gap:8px;max-width:min(560px,100vw - 24px);padding:8px 14px;font-size:13px;font-weight:500;color:#fff;background:#b91c1c;border-radius:var(--est-radius);box-shadow:0 6px 20px #00000040;animation:est2-toast-in .16s ease-out}.est2 .est2-toast svg{flex:0 0 auto}@keyframes est2-toast-in{0%{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%)}}@media(prefers-reduced-motion:reduce){.est2 .est2-toast{animation:none}}.est2 tbody tr.est2-row--group{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--group td{background:var(--est-bg-subtle);font-weight:600;color:var(--est-fg);border-bottom:1px solid var(--est-border)}.est2 tbody tr.est2-row--group:hover td{background:var(--est-bg-hover)}.est2 .est2-td--group-key{color:var(--est-fg)}.est2 .est2-group-key{display:inline-flex;align-items:center;gap:6px}.est2 .est2-group-chevron{display:inline-flex;color:var(--est-fg-muted);transition:transform var(--est-transition)}.est2 .est2-group-chevron--open{transform:rotate(90deg)}.est2 .est2-hier-lead{display:inline-flex;align-items:center;vertical-align:middle;margin-right:4px}.est2 .est2-hier-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none}.est2 .est2-group-chevron.est2-hier-toggle{cursor:pointer;border-radius:var(--est-radius-sm);transition:transform var(--est-transition),background var(--est-transition),color var(--est-transition)}.est2 .est2-group-chevron.est2-hier-toggle:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 th.est2-th--orderable{cursor:pointer;transition:color var(--est-transition)}.est2 th.est2-th--orderable:hover{color:var(--est-fg)}.est2 .est2-th__inner{display:inline-flex;align-items:center;gap:6px}.est2 .est2-sort{display:inline-flex;width:14px;height:14px;opacity:.35;transition:opacity var(--est-transition),transform var(--est-transition)}.est2 .est2-sort--active{opacity:1;color:var(--est-accent)}.est2 .est2-sort--desc{transform:rotate(180deg)}.est2 .est2-sort__badge{font-size:9px;font-weight:700;color:var(--est-accent);margin-left:2px}.est2 .est2-check{appearance:none;width:16px;height:16px;border:1.5px solid var(--est-border-strong);border-radius:var(--est-radius-sm);background:var(--est-bg);cursor:pointer;position:relative;transition:border-color var(--est-transition),background var(--est-transition);vertical-align:middle;flex:none}.est2 .est2-check:hover{border-color:var(--est-accent)}.est2 .est2-check:checked{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:checked:after{content:\"\";position:absolute;left:4.5px;top:1.5px;width:4px;height:8px;border:solid var(--est-accent-fg);border-width:0 2px 2px 0;transform:rotate(45deg)}.est2 .est2-check:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2 .est2-check:disabled{opacity:.45;cursor:not-allowed}.est2 .est2-check:disabled:hover{border-color:var(--est-border-strong)}.est2 .est2-check:indeterminate{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:indeterminate:after{content:\"\";position:absolute;left:3px;top:6px;width:8px;height:2px;background:var(--est-accent-fg);transform:none;border:none}.est2 th.est2-col-min,.est2 td.est2-col-min{width:1%;white-space:nowrap}.est2 .est2-wrap,.est2 .est2-scroll-host{position:relative}.est2 .est2-selectbar{position:absolute;top:0;left:0;right:0;z-index:15;display:flex;align-items:center;gap:12px;padding:9px 14px;font-size:var(--est-fs-sm);color:var(--est-fg);background:var(--est-bg-subtle);border:none;border-radius:var(--est-radius) var(--est-radius) 0 0;box-shadow:inset 3px 0 0 var(--est-accent)}.est2 .est2-selectbar--inset{border-top-right-radius:0}.est2 .est2-selectbar strong{color:var(--est-fg);font-weight:700}.est2 .est2-selectbar__spacer{flex:1 1 auto}.est2 .est2-link{color:var(--est-accent);cursor:pointer;font-weight:600}.est2 .est2-link:hover{text-decoration:underline}.est2 .est2-rowaction{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);border:none;background:transparent;color:var(--est-fg-faint);cursor:pointer;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-rowaction:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-rowaction--danger:hover{color:var(--est-danger)}.est2 .est2-op-cell{text-align:center}.est2 .est2-op{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:26px;padding:0 6px;border-radius:var(--est-radius-sm);color:var(--est-accent);cursor:pointer;font-size:var(--est-fs-sm);transition:background var(--est-transition)}.est2 .est2-op:hover{background:var(--est-accent-weak)}.est2 .est2-loading{position:absolute;inset:0;border-radius:var(--est-radius);z-index:20;display:flex;align-items:center;justify-content:center;gap:10px;background:color-mix(in srgb,var(--est-bg) 70%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);color:var(--est-fg-muted);font-size:var(--est-fs-sm)}.est2 .est2-spinner{width:16px;height:16px;border:2px solid var(--est-border-strong);border-top-color:var(--est-accent);border-radius:50%;animation:est2-spin .7s linear infinite}@keyframes est2-spin{to{transform:rotate(360deg)}}.est2 .est2-nowrap{white-space:nowrap}.est2 .est2-cornermenu{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);cursor:pointer;color:var(--est-fg-muted);transition:background var(--est-transition)}.est2 .est2-cornermenu:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-chrome-th{position:relative}.est2 .est2-chrome{display:inline-flex;align-items:center;gap:2px}.est2 .est2-chrome-wrap{position:relative;display:inline-flex}.est2 .est2-chrome-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer;font-size:16px;line-height:1;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-chrome-btn:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-menu{position:fixed;z-index:var(--est-z-menu);min-width:180px;padding:4px;background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 8px 24px #0000002e;display:flex;flex-direction:column}.est2 .est2-menu-item{display:block;width:100%;padding:8px 10px;border:none;background:transparent;text-align:left;font:inherit;color:var(--est-fg);border-radius:var(--est-radius-sm);cursor:pointer}.est2 .est2-menu-item:hover{background:var(--est-bg-hover)}.est2 .est2-dialog-backdrop{position:fixed;inset:0;z-index:var(--est-z-modal);display:flex;align-items:center;justify-content:center;padding:16px}.est2 .est2-dialog-backdrop:before{content:\"\";position:absolute;inset:0;background-color:#000;opacity:.5}.est2 .est2-dialog{position:relative}.est2 .est2-dialog-backdrop--embedded{--est-embed-offset: 110px;padding-top:5%;margin-left:calc(-1 * var(--est-embed-offset));width:calc(100% + var(--est-embed-offset));overflow:hidden}.est2 .est2-dialog-backdrop--embedded .est2-dialog{max-height:600px}.est2 .est2-dialog{width:520px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);display:flex;flex-direction:column;background:var(--est-bg);color:var(--est-fg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 16px 48px #0000004d;overflow:hidden}.est2 .est2-dialog__head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;font-weight:700;border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__close{border:none;background:transparent;cursor:pointer;color:var(--est-fg-muted);font-size:15px;line-height:1;padding:4px;border-radius:var(--est-radius-sm)}.est2 .est2-dialog__close:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-dialog__tools{padding:8px 14px;font-size:var(--est-fs-sm);border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__tools .est2-link{border:none;background:none;padding:0;font:inherit;font-weight:600}.est2 .est2-dialog__sep{margin:0 6px;color:var(--est-fg-faint)}.est2 .est2-collist{list-style:none;margin:0;padding:6px;overflow-y:auto;flex:1 1 auto;min-height:0}.est2 .est2-collist__row{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:var(--est-radius-sm)}.est2 .est2-collist__row:hover{background:var(--est-bg-hover)}.est2 .est2-collist__row--drag{cursor:grab}.est2 .est2-collist__row--drag:active{cursor:grabbing}.est2 .est2-collist__row--dragging{opacity:.45;background:var(--est-bg-hover)}.est2 .est2-collist__row--drop-above{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 .est2-collist__row--drop-below{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 .est2-collist__grip{display:inline-flex;align-items:center;justify-content:center;color:var(--est-fg-faint);cursor:grab;flex:0 0 auto}.est2 .est2-collist__grip:active{cursor:grabbing}.est2 .est2-collist__row--drag:hover .est2-collist__grip{color:var(--est-fg-muted)}.est2 .est2-collist__grip--locked{color:var(--est-fg-faint);opacity:.55;cursor:default}.est2 .est2-collist__row--locked .est2-collist__label{color:var(--est-fg-muted)}.est2 .est2-collist__vis{display:inline-flex}.est2 .est2-collist__label{flex:1 1 auto}.est2 .est2-collist__path{color:var(--est-fg-faint);margin-right:4px}.est2 .est2-collist__ord{display:inline-flex;gap:4px}.est2 .est2-iconbtn{width:26px;height:26px;border:1px solid var(--est-border);background:var(--est-bg);border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer}.est2 .est2-iconbtn:hover:not(:disabled){background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-iconbtn:disabled{opacity:.4;cursor:default}.est2 .est2-dialog__foot{display:flex;align-items:center;gap:8px;padding:12px 14px;border-top:1px solid var(--est-border)}.est2 .est2-dialog__spacer{flex:1 1 auto}.est2 .est2-btn{padding:7px 14px;border-radius:var(--est-radius-sm);font:inherit;font-weight:600;cursor:pointer;border:1px solid transparent}.est2 .est2-btn--ghost{background:transparent;color:var(--est-fg);border-color:var(--est-border)}.est2 .est2-btn--ghost:hover{background:var(--est-bg-hover)}.est2 .est2-btn--primary{background:var(--est-accent);color:var(--est-accent-fg)}.est2 .est2-btn--primary:hover{filter:brightness(1.05)}.est2 .est2-empty{padding:48px 16px;text-align:center;color:var(--est-fg-faint);font-size:var(--est-fs-sm)}.ngx-contextmenu{--ctx-bg: #ffffff;--ctx-fg: #1a1d24;--ctx-muted: #626b7a;--ctx-border: #e6e9ef;--ctx-hover: #f2f4f7;--ctx-accent: #4f46e5;--ctx-shadow: 0 10px 28px -8px rgba(16, 24, 40, .22), 0 2px 8px -3px rgba(16, 24, 40, .14);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.ngx-contextmenu .dropdown-menu{display:block;min-width:200px;margin:0;padding:6px;list-style:none;background:var(--ctx-bg);border:1px solid var(--ctx-border);border-radius:12px;box-shadow:var(--ctx-shadow);animation:est2-ctx-in .12s cubic-bezier(.16,1,.3,1)}.ngx-contextmenu li{list-style:none;margin:0}.ngx-contextmenu li>a{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:7px;color:var(--ctx-fg);font-size:13.5px;line-height:1.2;text-decoration:none;cursor:pointer;white-space:nowrap;transition:background .12s ease,color .12s ease}.ngx-contextmenu li>a:hover,.ngx-contextmenu li>a:focus{background:var(--ctx-hover);color:var(--ctx-fg);text-decoration:none;outline:none}.ngx-contextmenu li.divider,.ngx-contextmenu li[role=separator]{height:1px;margin:6px 8px;padding:0;background:var(--ctx-border)}.ngx-contextmenu li.disabled>a,.ngx-contextmenu li[aria-disabled=true]>a{color:var(--ctx-muted);opacity:.55;pointer-events:none}@media(prefers-color-scheme:dark){.ngx-contextmenu{--ctx-bg: #1e222b;--ctx-fg: #e7eaf0;--ctx-muted: #9aa3b2;--ctx-border: #2a2f3a;--ctx-hover: #232733;--ctx-accent: #7c74ff;--ctx-shadow: 0 12px 30px -8px rgba(0, 0, 0, .6), 0 2px 8px -3px rgba(0, 0, 0, .5)}}@keyframes est2-ctx-in{0%{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@media(prefers-reduced-motion:reduce){.ngx-contextmenu .dropdown-menu{animation:none}}\n"] }]
|
|
9892
|
+
args: [{ selector: 'es-table2', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, viewProviders: [{ provide: LocalizationService, useClass: EsTable2Loc }], template: "@if (view()) {\n <div class=\"est2-wrap {{ ContainerClass() }}\"\n [style.height]=\"Height()\"\n [style.background-color]=\"EmptySpaceBackgroundColor() || null\">\n\n <!-- Auto-aggiornamento: toggle + intervallo (in alto a destra) -->\n @if (AutoUpdate()) {\n <div class=\"est2-autoupdate\">\n <label class=\"est2-autoupdate__label\">\n {{ 'Update every' | localize : lc }}\n <input type=\"text\" maxlength=\"3\" class=\"est2-autoupdate__secs\"\n [ngModel]=\"seconds()\" (ngModelChange)=\"seconds.set($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n (change)=\"autoUpdateChanged()\" />\n {{ 'second/s' | localize : lc }}\n </label>\n <label class=\"est2-switch\" [title]=\"'Toggle auto-update' | localize : lc\">\n <input type=\"checkbox\" [ngModel]=\"autoUpdate()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"autoUpdate.set($event); autoUpdateChanged()\" />\n <span class=\"est2-switch__slider\"></span>\n </label>\n </div>\n }\n\n <!-- Pager superiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'top') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Host POSIZIONATO dello scroller: \u00E8 l'ancora di tutti gli overlay che devono\n coprire la TABELLA (barra di selezione, overlay di caricamento). Senza di esso\n erano ancorati a `.est2-wrap` e con [AutoUpdate] o il pager in alto finivano\n sopra quei controlli invece che sopra l'header. -->\n <div class=\"est2-scroll-host\">\n\n <!-- Barra \"seleziona tutto\" (visibile solo con selezione multipla attiva e righe presenti) -->\n @if (Selection() && !SingleSelection() && hasSelection) {\n <div class=\"est2-selectbar\"\n [class.est2-selectbar--inset]=\"chromeWidth() > 0\"\n [style.height.px]=\"selbarHeight() ? selbarHeight() + 1 : null\"\n [style.right.px]=\"chromeWidth() || null\">\n @if (allSelected) {\n <span>{{ 'All the' | localize : lc }} <strong>{{ selectedCount }}</strong> {{ 'elements are selected' | localize : lc }}</span>\n } @else {\n <span><strong>{{ selectedCount }}</strong> {{ (selectedCount === 1 ? 'element selected' : 'elements selected') | localize : lc }}</span>\n @if (canSelectEverything) {\n <span class=\"est2-link\" (click)=\"selectEverything()\">{{ 'Select all' | localize : lc }} {{ totalCount() }} {{ 'elements' | localize : lc }}</span>\n }\n }\n <span class=\"est2-selectbar__spacer\"></span>\n <span class=\"est2-link\" (click)=\"clearSelection()\">{{ 'Reset selection' | localize : lc }}</span>\n </div>\n }\n\n <div class=\"est2-scroll\" #scrollRef [style.max-height.px]=\"MaxHeight()\" (scroll)=\"onScrollerScroll($event)\">\n <table class=\"est2-table {{ TableClass() }}\"\n [class.est2-table--range]=\"rangeActive()\"\n [class.est2-table--dragging]=\"rangeDragging()\"\n (mousedown)=\"onGridMouseDown($event)\"\n (mouseover)=\"onGridMouseOver($event)\">\n\n <!-- ================= HEADER ================= -->\n @if (!HeaderHidden()) {\n <thead #theadRef>\n <!-- Righe di header-group multi-livello (dall'alto verso il basso) -->\n @if (hasHeaderGroups()) {\n @for (grow of headerGroupRows(); track $index) {\n <tr class=\"est2-hgroup-row\">\n @if (Selection()) { <th class=\"est2-col-min est2-selcol\" [class.est2-pinned]=\"hasPinned()\" [style.left.px]=\"hasPinned() ? 0 : null\"></th> }\n @for (op of DynamicOperations(); track op.id) { <th class=\"est2-col-min\"></th> }\n @for (cell of grow; track cell.id; let gi = $index) {\n <th [attr.colspan]=\"cell.span\"\n [attr.data-groupid]=\"cell.isGroup ? cell.id : null\"\n [class.est2-hgroup]=\"cell.isGroup\"\n [class.est2-pinned]=\"gi < pinnedCount()\"\n [style.left.px]=\"gi < pinnedCount() ? pinnedLeftPx(gi) : null\"\n class=\"est2-hgroup-cell\">\n @if (cell.isGroup) {\n @if (cell.template) {\n <ng-container *ngTemplateOutlet=\"cell.template\"></ng-container>\n } @else {\n {{ cell.label }}\n }\n }\n </th>\n }\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n @if (hasChrome()) { <th class=\"est2-col-min est2-chrome-col\"></th> }\n </tr>\n }\n }\n <tr>\n <!-- Colonna di selezione -->\n @if (Selection()) {\n <th class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"globalCheck()\"\n [indeterminate]=\"selectionIndeterminate\"\n [disabled]=\"SelectionDisabled()\"\n (change)=\"toggleAll()\"\n [attr.aria-label]=\"'Select all rows' | localize : lc\" />\n }\n </th>\n }\n\n <!-- Header da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- intestazioni vuote per le operazioni dinamiche -->\n @for (op of DynamicOperations(); track op.id) {\n <th class=\"est2-col-min\"></th>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let ci = $index) {\n @let hs = colStyles()[ci];\n <th [attr.data-colid]=\"col.id\"\n [class]=\"col.headerClass\"\n [class.est2-th--orderable]=\"OrderByColumn() && col.orderable\"\n [class.est2-col-min]=\"col.header?.thShrink\"\n [class.est2-col-groupstart]=\"hs.groupStart\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"hs.left\"\n [style.width.px]=\"hs.width\"\n [style.min-width.px]=\"hs.width\"\n [style.max-width.px]=\"hs.width\"\n [style.text-align]=\"col.alignment\"\n [style.background-color]=\"col.headerBg || null\"\n (click)=\"toggleSort(col)\">\n <span class=\"est2-th__inner\">\n @if (col.header?.Template) {\n <ng-container *ngTemplateOutlet=\"col.header!.Template!; context: col.multiProp != null ? { $implicit: col.headerText } : null\"></ng-container>\n } @else {\n {{ col.headerText }}\n }\n @if (OrderByColumn() && col.orderable && orderOf(col.id)) {\n <span class=\"est2-sort est2-sort--active\"\n [class.est2-sort--desc]=\"orderOf(col.id) === 'DESC'\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6 15l6-6 6 6\"/></svg>\n </span>\n @if (orderIndex(col.id) > 0 && MultipleOrderingDirectives()) {\n <span class=\"est2-sort__badge\">{{ orderIndex(col.id) }}</span>\n }\n }\n <!-- Indicatore/toggle di pin (visibile se pinnata o all'hover) -->\n @if (ColumnsPinnable() && col.multiProp == null && !col.fixed) {\n <button type=\"button\" class=\"est2-pinbtn\"\n [class.est2-pinbtn--on]=\"col.pinned\"\n [title]=\"(col.pinned ? 'Unlock column' : 'Lock column to the left') | localize : lc\"\n (click)=\"togglePin(col, $event)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n </span>\n <!-- Handle di ridimensionamento (colonne pinnate, gated da ColumnsResizable) -->\n @if (col.pinned || ColumnsResizable()) {\n <span class=\"est2-resize-handle\" [title]=\"'Drag to resize' | localize : lc\"\n (mousedown)=\"startColumnResize(col, $event)\"\n (click)=\"$event.stopPropagation()\"></span>\n }\n </th>\n }\n }\n <!-- Header da template semplice -->\n @else if (headerRef) {\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\n }\n\n <!-- Colonna rimozione -->\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n <!-- Colonna chrome (export / gestione colonne / menu) -->\n @if (hasChrome()) {\n <th class=\"est2-col-min est2-chrome-th est2-chrome-col\">\n <div class=\"est2-chrome\">\n <!-- I pannelli dei menu NON vivono qui: sono renderizzati a fondo\n componente e posizionati `fixed`, altrimenti l'`overflow:auto`\n di `.est2-scroll` li taglierebbe su tabelle basse. -->\n @if (Export()) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Export' | localize : lc\" (click)=\"$event.stopPropagation(); toggleExportMenu($event)\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><path d=\"M7 10l5 5 5-5\"/><path d=\"M12 15V3\"/></svg>\n </button>\n }\n @if (HiddenColumns() || ColumnsOrdering()) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Columns' | localize : lc\" (click)=\"$event.stopPropagation(); openColumnsDialog()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><path d=\"M9 3v18\"/><path d=\"M15 3v18\"/></svg>\n </button>\n }\n @if (CornerMenuOptions().length > 0) {\n <button type=\"button\" class=\"est2-chrome-btn\" [title]=\"'Options' | localize : lc\" (click)=\"$event.stopPropagation(); toggleCornerMenu($event)\">\u22EE</button>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n }\n\n <!-- ================= BODY ================= -->\n @if (!BodyHidden()) {\n <tbody>\n <!-- Valori invarianti per l'intero corpo: senza questi verrebbero\n ricalcolati riga\u00D7colonna volte a ogni ciclo di change-detection. -->\n @let rng = rangeActive();\n @let rect = rangeRect();\n @let errs = hasCellErrors();\n @let vw = virtualWindow();\n @if (vw && vw.padTop > 0) {\n <tr class=\"est2-vspacer\" aria-hidden=\"true\"><td [attr.colspan]=\"totalColspan()\" [style.height.px]=\"vw.padTop\"></td></tr>\n }\n @for (item of renderedRows(); track trackRow($index, item); let vi = $index) {\n <!-- indice ASSOLUTO: range, editing e data-r ragionano su boundSource() -->\n @let ri = vStart() + vi;\n @if ((!grouped() && !Hierarchy()) || item._visible) {\n <tr [class]=\"rowClass(item)\"\n [class.est2-row--zebra]=\"vw && (ri % 2 === 1)\"\n [class.est2-row--selected]=\"item._selected\"\n [class.est2-row--removed]=\"item.removed || item.deleted\"\n [class.est2-row--group]=\"item._group\"\n [class.est2-row--clickable]=\"Selection() || item._group\"\n [contextMenu]=\"ContextMenu || emptyMenu\"\n [contextMenuSubject]=\"item\"\n (click)=\"handleRowClick(item, $event)\">\n\n <!-- Cella di selezione -->\n @if (Selection()) {\n <td class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (item._group) {\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"groupSelectionState(item) === 'all'\"\n [indeterminate]=\"groupSelectionState(item) === 'some'\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection(item)\"\n [attr.aria-label]=\"'Select group' | localize : lc\" />\n }\n } @else {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"item._selected\"\n [indeterminate]=\"hierarchyIndeterminate(item)\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(item)\"\n [attr.aria-label]=\"'Select row' | localize : lc\" />\n }\n </td>\n }\n\n <!-- Celle da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- Operazioni dinamiche (icone a sinistra) -->\n @for (op of DynamicOperations(); track op.id) {\n <td class=\"est2-col-min est2-op-cell\">\n @if (!item._group && operationVisible(op, item)) {\n <span class=\"est2-op\" [class]=\"op.iconClass || ''\" [title]=\"op.title\"\n (click)=\"$event.stopPropagation(); dynamicOperation(item, op.id)\">{{ op.text }}</span>\n }\n </td>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let first = $first, ci = $index) {\n @let cs = colStyles()[ci];\n @let insel = rng && inRange(ri, ci);\n @let editing = isEditing(ri, ci);\n <td [class]=\"col.cssClass\"\n [style.text-align]=\"col.alignment\"\n [style.color]=\"cellColor(item, col, 'fore')\"\n [style.background-color]=\"cellColor(item, col, 'back')\"\n [class.est2-nowrap]=\"!col.wrap\"\n [class.est2-col-groupstart]=\"cs.groupStart\"\n [class.est2-pinned]=\"col.pinned\"\n [class.est2-fixedw]=\"cs.width != null\"\n [style.left.px]=\"cs.left\"\n [style.width.px]=\"cs.width\"\n [style.min-width.px]=\"cs.width\"\n [style.max-width.px]=\"cs.width\"\n [class.est2-td--group-key]=\"item._group && item.column === col.id\"\n [attr.data-r]=\"rng && !item._group ? ri : null\"\n [attr.data-c]=\"rng && !item._group ? ci : null\"\n [class.est2-cell-sel]=\"insel\"\n [class.est2-cell-sel-t]=\"insel && ri === rect!.top\"\n [class.est2-cell-sel-b]=\"insel && ri === rect!.bottom\"\n [class.est2-cell-sel-l]=\"insel && ci === rect!.left\"\n [class.est2-cell-sel-r]=\"insel && ci === rect!.right\"\n [class.est2-cell-editing]=\"editing\"\n [class.est2-cell-invalid]=\"errs && !!cellError(item, col)\"\n [attr.data-error]=\"errs ? (cellError(item, col) || null) : null\"\n (dblclick)=\"onCellDblClick(item, col, ri, ci)\">\n @if (editing) {\n @if (editorFor(col); as edTpl) {\n <ng-container *ngTemplateOutlet=\"edTpl; context: editorContext(item, col)\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"defaultEditor; context: { $implicit: item, col: col }\"></ng-container>\n }\n } @else if (item._group) {\n @if (item.column === col.id) {\n <span class=\"est2-group-key\" [style.padding-left.px]=\"groupIndent(item)\">\n <span class=\"est2-group-chevron\" [class.est2-group-chevron--open]=\"item._expanded\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n {{ groupCellDisplay(item, col) }}\n </span>\n } @else {\n {{ groupCellDisplay(item, col) }}\n }\n } @else {\n <!-- Navigatore albero nella prima colonna -->\n @if (Hierarchy() && first) {\n <span class=\"est2-hier-lead\" [style.padding-left.px]=\"hierarchyIndent(item)\">\n @if (item.parent) {\n <span class=\"est2-group-chevron est2-hier-toggle\" [class.est2-group-chevron--open]=\"item._expanded\"\n (click)=\"$event.stopPropagation(); toggleHierarchyNode(item)\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-hier-toggle\"></span>\n }\n </span>\n }\n @if (itemCellHidden(col)) {\n <!-- colonna di gruppo nascosta sulla riga-oggetto -->\n } @else if (col.multiProp != null) {\n @if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: multiCell(item, col) }\"></ng-container>\n } @else {\n {{ multiCell(item, col)?.value }}\n }\n } @else if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: item }\"></ng-container>\n } @else if (col.routePath) {\n <a class=\"est2-link\" [routerLink]=\"routerLinkFor(item, col)\">{{ cellValue(item, col) }}</a>\n } @else if (col.propAccessor != null) {\n {{ reportCellDisplay(item, col) }}\n } @else if (col.type === 'enum') {\n {{ (cellValue(item, col) | est2_lookup : col.source).description }}\n } @else {\n {{ cellValue(item, col) | est2_format : col.type : col.format : locale }}\n }\n }\n </td>\n }\n }\n <!-- Celle da template semplice -->\n @else if (bodyRef) {\n <ng-container *ngTemplateOutlet=\"bodyRef; context: { $implicit: item }\"></ng-container>\n }\n\n <!-- Rimozione (non sulle righe-gruppo) -->\n @if (Removal()) {\n <td class=\"est2-col-min\">\n @if (!item._group && canRemove(item)) {\n @if (item.removed || item.deleted) {\n <button type=\"button\" class=\"est2-rowaction\" [title]=\"'Restore' | localize : lc\" (click)=\"abortRemoval(item)\">\u21BA</button>\n } @else {\n <button type=\"button\" class=\"est2-rowaction est2-rowaction--danger\" [title]=\"'Remove' | localize : lc\" (click)=\"removeItem(item)\">\u2715</button>\n }\n }\n </td>\n }\n <!-- Chrome -->\n @if (hasChrome()) { <td class=\"est2-col-min est2-chrome-col\"></td> }\n </tr>\n }\n } @empty {\n <tr>\n <td class=\"est2-empty\" [attr.colspan]=\"totalColspan()\">{{ 'No elements to display' | localize : lc }}</td>\n </tr>\n }\n @if (vw && vw.padBottom > 0) {\n <tr class=\"est2-vspacer\" aria-hidden=\"true\"><td [attr.colspan]=\"totalColspan()\" [style.height.px]=\"vw.padBottom\"></td></tr>\n }\n </tbody>\n }\n </table>\n </div>\n\n <!-- Overlay di caricamento: FUORI dallo scroller, cos\u00EC copre il viewport della\n tabella senza scorrere col contenuto e senza essere bucato dalle celle sticky -->\n @if (researchInProgress() || (firstBind() && ShowLoadingOnBootstrap())) {\n <div class=\"est2-loading\">\n <span class=\"est2-spinner\"></span>\n <span>{{ 'Loading\u2026' | localize : lc }}</span>\n </div>\n }\n\n </div>\n\n <!-- Pager inferiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Menu del chrome (export / opzioni). Renderizzati FUORI da `.est2-scroll` e\n posizionati `fixed` sulle coordinate del bottone che li ha aperti: cos\u00EC non\n vengono tagliati dall'`overflow:auto` dello scroller su tabelle basse, e\n restano dentro `.est2` (i token `--est-*` continuano a ereditare). -->\n @if (exportMenuOpen() && menuAnchor(); as anchor) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\"\n [style.top.px]=\"anchor.top\" [style.right.px]=\"anchor.right\">\n @if (CSVExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">{{ 'Export CSV' | localize : lc }}</button> }\n @if (XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('XLSX')\">{{ 'Export Excel (XLSX)' | localize : lc }}</button> }\n @if (!CSVExport() && !XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">{{ 'Export CSV' | localize : lc }}</button> }\n </div>\n }\n @if (cornerMenuOpen() && menuAnchor(); as anchor) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\"\n [style.top.px]=\"anchor.top\" [style.right.px]=\"anchor.right\">\n @for (opt of CornerMenuOptions(); track opt.id) {\n <button type=\"button\" class=\"est2-menu-item\" (click)=\"cornerAction(opt.id); closeChromeMenus()\">{{ opt.description }}</button>\n }\n </div>\n }\n\n <!-- Avviso transitorio (es. incolla con dimensioni incompatibili) -->\n @if (notice()) {\n <div class=\"est2-toast\" role=\"alert\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/></svg>\n <span>{{ notice() }}</span>\n </div>\n }\n\n <!-- Dialog visibilit\u00E0 / ordine colonne -->\n @if (columnsDialogOpen()) {\n <div class=\"est2-dialog-backdrop\" #dialogBackdrop\n [class.est2-dialog-backdrop--embedded]=\"embedded\"\n (click)=\"closeColumnsDialog()\">\n <div class=\"est2-dialog\" (click)=\"$event.stopPropagation()\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"est2-dialog__head\">\n <span>\n @if (HiddenColumns() && ColumnsOrdering()) { {{ 'Columns visibility and order' | localize : lc }} }\n @else if (HiddenColumns()) { {{ 'Columns visibility' | localize : lc }} }\n @else { {{ 'Columns order' | localize : lc }} }\n </span>\n <button type=\"button\" class=\"est2-dialog__close\" (click)=\"closeColumnsDialog()\" [attr.aria-label]=\"'Close' | localize : lc\">\u2715</button>\n </div>\n\n @if (HiddenColumns()) {\n <div class=\"est2-dialog__tools\">\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(true)\">{{ 'Show all' | localize : lc }}</button>\n <span class=\"est2-dialog__sep\">\u00B7</span>\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(false)\">{{ 'Hide all' | localize : lc }}</button>\n </div>\n }\n\n <ul class=\"est2-collist\">\n @for (c of dialogCols(); track c.id; let i = $index) {\n <li class=\"est2-collist__row\"\n [attr.draggable]=\"ColumnsOrdering() && canReorder(c) ? true : null\"\n [class.est2-collist__row--drag]=\"ColumnsOrdering() && canReorder(c)\"\n [class.est2-collist__row--locked]=\"!canReorder(c)\"\n [class.est2-collist__row--dragging]=\"dragIndex() === i\"\n [class.est2-collist__row--drop-above]=\"dragOverIndex() === i && dragIndex() !== null && dragIndex()! > i\"\n [class.est2-collist__row--drop-below]=\"dragOverIndex() === i && dragIndex() !== null && dragIndex()! < i\"\n (dragstart)=\"dialogDragStart(i, $event)\"\n (dragover)=\"dialogDragOver(i, $event)\"\n (drop)=\"dialogDrop(i, $event)\"\n (dragend)=\"dialogDragEnd()\">\n @if (ColumnsOrdering()) {\n @if (canReorder(c)) {\n <span class=\"est2-collist__grip\" [title]=\"'Drag to reorder' | localize : lc\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"currentColor\"><circle cx=\"9\" cy=\"6\" r=\"1.6\"/><circle cx=\"15\" cy=\"6\" r=\"1.6\"/><circle cx=\"9\" cy=\"12\" r=\"1.6\"/><circle cx=\"15\" cy=\"12\" r=\"1.6\"/><circle cx=\"9\" cy=\"18\" r=\"1.6\"/><circle cx=\"15\" cy=\"18\" r=\"1.6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-collist__grip est2-collist__grip--locked\"\n [title]=\"(c.fixed ? 'Fixed column: cannot be moved' : 'Column locked to the left: cannot be moved') | localize : lc\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"4\" y=\"11\" width=\"16\" height=\"10\" rx=\"2\"/><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"/></svg>\n </span>\n }\n }\n @if (HiddenColumns()) {\n <label class=\"est2-collist__vis\" [title]=\"c.fixed ? ('Fixed column: always visible' | localize : lc) : ''\">\n <input type=\"checkbox\" class=\"est2-check\" [checked]=\"c.visible\" [disabled]=\"c.fixed\" (change)=\"dialogToggle(i)\" />\n </label>\n }\n <span class=\"est2-collist__label\">\n @if (c.tmpl) {\n <!-- colonna non renderizzata (Visible:false / nascosta): il testo\n header non esiste nel DOM, quindi rendo il template dell'`*th` -->\n @if (c.prefix) { <span class=\"est2-collist__path\">{{ c.prefix }}</span> }\n <ng-container *ngTemplateOutlet=\"c.tmpl; context: c.tmplCtx\"></ng-container>\n } @else {\n {{ c.label }}\n }\n </span>\n @if (ColumnsPinnable()) {\n <button type=\"button\" class=\"est2-iconbtn est2-collist__pin\" [class.est2-collist__pin--on]=\"c.pinned\"\n [disabled]=\"c.grouped || c.fixed\"\n [title]=\"(c.fixed ? 'Fixed columns cannot be locked' : (c.grouped ? 'Grouped columns cannot be locked' : (c.pinned ? 'Unlock' : 'Lock to the left'))) | localize : lc\"\n (click)=\"dialogTogglePin(i)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n @if (ColumnsOrdering()) {\n <span class=\"est2-collist__ord\">\n <button type=\"button\" class=\"est2-iconbtn\" [title]=\"'Up' | localize : lc\" (click)=\"dialogMove(i, -1)\"\n [disabled]=\"i === 0 || !canReorder(c) || !canReorder(dialogCols()[i - 1])\">\u2191</button>\n <button type=\"button\" class=\"est2-iconbtn\" [title]=\"'Down' | localize : lc\" (click)=\"dialogMove(i, 1)\"\n [disabled]=\"i === dialogCols().length - 1 || !canReorder(c) || !canReorder(dialogCols()[i + 1])\">\u2193</button>\n </span>\n }\n </li>\n }\n </ul>\n\n <div class=\"est2-dialog__foot\">\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"resetColumnsDialog()\">{{ 'Reset' | localize : lc }}</button>\n <span class=\"est2-dialog__spacer\"></span>\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"closeColumnsDialog()\">{{ 'Cancel' | localize : lc }}</button>\n <button type=\"button\" class=\"est2-btn est2-btn--primary\" (click)=\"applyColumnsDialog()\">{{ 'Apply' | localize : lc }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n}\n\n<!-- Template pager riutilizzabile sopra/sotto -->\n<ng-template #pager>\n @if (!HidePaging() && !grouped()) {\n <es-table2-pager\n [page]=\"currentPage()\"\n [pages]=\"totalPages()\"\n [total]=\"totalCount()\"\n [locale]=\"locale\"\n [itemsPerPage]=\"viewMode() ? (view()?.itemsperpageoverride ?? 15) : ArraymodeItemsPerPage()\"\n [countLabel]=\"CountLabel()\"\n [showCount]=\"!HidePagingCount()\"\n [showButtons]=\"!HidePagingButtons()\"\n [showPagingOptions]=\"!HidePagingButtons()\"\n [allowAll]=\"AllSearch()\"\n (pageChange)=\"goToPage($event)\"\n (itemsPerPageChange)=\"changeItemsPerPage($event)\">\n </es-table2-pager>\n }\n</ng-template>\n\n<!-- Editor di cella di default (usato quando il consumer non fornisce un `*editor`) -->\n<ng-template #defaultEditor let-item let-col=\"col\">\n @switch (col.type) {\n @case ('enum') {\n <select class=\"est2-editor-input\"\n [value]=\"editDraft\"\n (change)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\">\n @for (o of col.source || []; track o.id) {\n <option [value]=\"o.id\" [selected]=\"o.id == editDraft\">{{ o.description }}</option>\n }\n </select>\n }\n @case ('boolean') {\n <input type=\"checkbox\" class=\"est2-editor-input est2-check\"\n [checked]=\"editDraft === true || editDraft === 'true'\"\n (change)=\"editDraft = $any($event.target).checked; commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\" />\n }\n @default {\n <input class=\"est2-editor-input\"\n [type]=\"editorInputType(col.type)\"\n [value]=\"editDraft\"\n (input)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\" />\n }\n }\n</ng-template>\n\n<!-- Menu di default (nessuna operazione) usato quando il consumer non passa [ContextMenu] -->\n<context-menu #emptyMenu>\n <ng-template contextMenuItem [passive]=\"true\"><em>{{ 'No operations available\u2026' | localize : lc }}</em></ng-template>\n</context-menu>\n", styles: [".est2{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent);--est-radius: 10px;--est-radius-sm: 6px;--est-radius-pill: 999px;--est-gap: 8px;--est-cell-py: 6px;--est-cell-px: 12px;--est-row-h: 33px;--est-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--est-fs: 13px;--est-fs-sm: 12px;--est-fw-head: 700;--est-transition: .14s cubic-bezier(.4, 0, .2, 1);--est-bg-zebra: color-mix(in srgb, var(--est-fg) 3.5%, var(--est-bg));--est-z-menu: 1000;--est-z-modal: 1010;--est-z-toast: 1020;font-family:var(--est-font);font-size:var(--est-fs);color:var(--est-fg);position:relative;display:block}@media(prefers-color-scheme:dark){.est2{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}}.est2.est2--dark{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}.est2.est2--light{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent)}.est2.est2--dense{--est-cell-py: 3px;--est-cell-px: 9px;--est-row-h: 27px;--est-fs: 12.5px}.est2 *,.est2 *:before,.est2 *:after{box-sizing:border-box}.est2 .est2-scroll{position:relative;width:100%;overflow:auto;border:1px solid var(--est-border);border-radius:var(--est-radius);background:var(--est-bg);-webkit-overflow-scrolling:touch}.est2 table.est2-table{width:100%;border-collapse:separate;border-spacing:0;background:var(--est-bg)}.est2 thead th{position:sticky;top:0;z-index:3;background:var(--est-bg-subtle);color:var(--est-fg);font-weight:var(--est-fw-head);font-size:var(--est-fs);text-align:left;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);box-shadow:var(--est-shadow-sticky);-webkit-user-select:none;user-select:none}.est2 thead tr.est2-hgroup-row th{font-size:var(--est-fs-sm);font-weight:700;color:var(--est-fg-muted);text-align:center;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);background:var(--est-bg-subtle);border-bottom:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th.est2-hgroup{color:var(--est-fg);border-left:1px solid var(--est-border);border-right:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th:not(.est2-hgroup){background:var(--est-bg-subtle);border-bottom-color:transparent}.est2 thead tr:last-child th.est2-col-groupstart,.est2 tbody td.est2-col-groupstart{border-left:1px solid var(--est-border)}.est2 tbody td{padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);color:var(--est-fg);vertical-align:middle;background:transparent}.est2 tbody tr:nth-child(2n) td{background:var(--est-bg-zebra)}.est2 tbody tr:nth-child(2n) td.est2-pinned{background:var(--est-bg-zebra)}.est2 tbody tr.est2-row--zebra td,.est2 tbody tr.est2-row--zebra td.est2-pinned{background:var(--est-bg-zebra)}.est2 tbody tr.est2-vspacer td{padding:0;border:none;background:transparent}.est2 tbody tr.est2-vspacer:hover td{background:transparent}.est2 th.est2-pinned,.est2 td.est2-pinned{position:sticky;background:var(--est-bg);box-shadow:1px 0 0 var(--est-border)}.est2 .est2-resize-handle{position:absolute;top:0;right:-3px;width:10px;height:100%;cursor:col-resize;z-index:2;touch-action:none;-webkit-user-select:none;user-select:none}.est2 .est2-resize-handle:after{content:\"\";position:absolute;top:28%;bottom:28%;right:3px;width:2px;border-radius:2px;background:color-mix(in srgb,var(--est-fg) 30%,transparent);transition:background var(--est-transition),top var(--est-transition),bottom var(--est-transition)}.est2 .est2-resize-handle:hover:after{background:var(--est-accent);top:15%;bottom:15%}.est2 .est2-resize-handle:active:after{background:var(--est-accent);top:6%;bottom:6%}.est2 td.est2-fixedw{overflow:hidden;text-overflow:ellipsis}.est2 td.est2-cell-invalid{background:color-mix(in srgb,var(--est-danger) 10%,var(--est-bg));box-shadow:inset 0 0 0 1px var(--est-danger);color:var(--est-danger)}.est2 .est2-selcol{width:44px;min-width:44px;max-width:44px}.est2 td.est2-pinned{z-index:3}.est2 thead th.est2-pinned,.est2 thead tr.est2-hgroup-row th.est2-pinned{z-index:6;background:var(--est-bg-subtle)}.est2 tbody tr:hover td.est2-pinned{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-pinned{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-pinned{background:var(--est-bg-subtle)}.est2 th.est2-chrome-col,.est2 td.est2-chrome-col{position:sticky;right:0;box-shadow:-1px 0 0 var(--est-border)}.est2 thead th.est2-chrome-col{z-index:16;background:var(--est-bg-subtle)}.est2 td.est2-chrome-col{z-index:4;background:var(--est-bg)}.est2 tbody tr:nth-child(2n) td.est2-chrome-col{background:var(--est-bg-zebra)}.est2 tbody tr:hover td.est2-chrome-col{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-chrome-col{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-chrome-col{background:var(--est-bg-subtle)}.est2 .est2-pinbtn{display:inline-flex;align-items:center;justify-content:center;margin-left:4px;padding:2px;border:none;background:transparent;color:var(--est-fg-faint);border-radius:var(--est-radius-sm);cursor:pointer;opacity:0;transition:opacity var(--est-transition),color var(--est-transition),background var(--est-transition)}.est2 thead th:hover .est2-pinbtn{opacity:.7}.est2 .est2-pinbtn:hover{background:var(--est-bg-hover);color:var(--est-fg);opacity:1}.est2 .est2-pinbtn--on{opacity:1;color:var(--est-accent);transform:rotate(0)}.est2 thead th:hover .est2-pinbtn--on{opacity:1}.est2 .est2-collist__pin.est2-collist__pin--on{color:var(--est-accent);border-color:var(--est-accent)}.est2 tbody tr{height:var(--est-row-h);transition:background var(--est-transition)}.est2 tbody tr:last-child td{border-bottom:none}.est2 tbody tr:hover td{background:var(--est-bg-hover)}.est2 tbody tr.est2-row--selected td{background:var(--est-bg-selected)}.est2 tbody tr.est2-row--clickable{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--removed td{text-decoration:line-through;color:var(--est-fg-faint)}.est2 .est2-table--range tbody td[data-r]{cursor:cell}.est2 .est2-table--dragging,.est2 .est2-table--dragging tbody td{-webkit-user-select:none;user-select:none}.est2 tbody td.est2-cell-sel{background:color-mix(in srgb,var(--est-accent) 14%,transparent)}.est2 tbody td.est2-cell-sel-t{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l{box-shadow:inset 2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-r{box-shadow:inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b{box-shadow:inset 0 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 0 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px -2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-editing{padding:2px 6px}.est2 .est2-editor-input{width:100%;box-sizing:border-box;height:calc(var(--est-row-h) - 8px);padding:2px 6px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1.5px solid var(--est-accent);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-editor-input:focus-visible{box-shadow:var(--est-ring)}.est2 input.est2-editor-input[type=checkbox]{width:16px;height:16px}.est2 .est2-autoupdate{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding:4px 2px 8px;font-size:var(--est-fs-sm);color:var(--est-fg-muted)}.est2 .est2-autoupdate__label{display:inline-flex;align-items:center;gap:6px}.est2 .est2-autoupdate__secs{width:44px;text-align:center;padding:3px 4px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-autoupdate__secs:focus-visible{box-shadow:var(--est-ring);border-color:var(--est-accent)}.est2 .est2-switch{position:relative;display:inline-flex;width:38px;height:20px;cursor:pointer}.est2 .est2-switch input{position:absolute;opacity:0;width:0;height:0}.est2 .est2-switch__slider{flex:1;border-radius:var(--est-radius-pill);background:var(--est-border-strong);transition:background var(--est-transition)}.est2 .est2-switch__slider:before{content:\"\";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px #00000040;transition:transform var(--est-transition)}.est2 .est2-switch input:checked+.est2-switch__slider{background:var(--est-accent)}.est2 .est2-switch input:checked+.est2-switch__slider:before{transform:translate(18px)}.est2 .est2-switch input:focus-visible+.est2-switch__slider{box-shadow:var(--est-ring)}.est2 .est2-toast{position:fixed;left:50%;bottom:24px;transform:translate(-50%);z-index:var(--est-z-toast);pointer-events:none;display:inline-flex;align-items:center;gap:8px;max-width:min(560px,100vw - 24px);padding:8px 14px;font-size:13px;font-weight:500;color:#fff;background:#b91c1c;border-radius:var(--est-radius);box-shadow:0 6px 20px #00000040;animation:est2-toast-in .16s ease-out}.est2 .est2-toast svg{flex:0 0 auto}@keyframes est2-toast-in{0%{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%)}}@media(prefers-reduced-motion:reduce){.est2 .est2-toast{animation:none}}.est2 tbody tr.est2-row--group{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--group td{background:var(--est-bg-subtle);font-weight:600;color:var(--est-fg);border-bottom:1px solid var(--est-border)}.est2 tbody tr.est2-row--group:hover td{background:var(--est-bg-hover)}.est2 .est2-td--group-key{color:var(--est-fg)}.est2 .est2-group-key{display:inline-flex;align-items:center;gap:6px}.est2 .est2-group-chevron{display:inline-flex;color:var(--est-fg-muted);transition:transform var(--est-transition)}.est2 .est2-group-chevron--open{transform:rotate(90deg)}.est2 .est2-hier-lead{display:inline-flex;align-items:center;vertical-align:middle;margin-right:4px}.est2 .est2-hier-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none}.est2 .est2-group-chevron.est2-hier-toggle{cursor:pointer;border-radius:var(--est-radius-sm);transition:transform var(--est-transition),background var(--est-transition),color var(--est-transition)}.est2 .est2-group-chevron.est2-hier-toggle:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 th.est2-th--orderable{cursor:pointer;transition:color var(--est-transition)}.est2 th.est2-th--orderable:hover{color:var(--est-fg)}.est2 .est2-th__inner{display:inline-flex;align-items:center;gap:6px}.est2 .est2-sort{display:inline-flex;width:14px;height:14px;opacity:.35;transition:opacity var(--est-transition),transform var(--est-transition)}.est2 .est2-sort--active{opacity:1;color:var(--est-accent)}.est2 .est2-sort--desc{transform:rotate(180deg)}.est2 .est2-sort__badge{font-size:9px;font-weight:700;color:var(--est-accent);margin-left:2px}.est2 .est2-check{appearance:none;width:16px;height:16px;border:1.5px solid var(--est-border-strong);border-radius:var(--est-radius-sm);background:var(--est-bg);cursor:pointer;position:relative;transition:border-color var(--est-transition),background var(--est-transition);vertical-align:middle;flex:none}.est2 .est2-check:hover{border-color:var(--est-accent)}.est2 .est2-check:checked{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:checked:after{content:\"\";position:absolute;left:4.5px;top:1.5px;width:4px;height:8px;border:solid var(--est-accent-fg);border-width:0 2px 2px 0;transform:rotate(45deg)}.est2 .est2-check:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2 .est2-check:disabled{opacity:.45;cursor:not-allowed}.est2 .est2-check:disabled:hover{border-color:var(--est-border-strong)}.est2 .est2-check:indeterminate{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:indeterminate:after{content:\"\";position:absolute;left:3px;top:6px;width:8px;height:2px;background:var(--est-accent-fg);transform:none;border:none}.est2 th.est2-col-min,.est2 td.est2-col-min{width:1%;white-space:nowrap}.est2 .est2-wrap,.est2 .est2-scroll-host{position:relative}.est2 .est2-selectbar{position:absolute;top:0;left:0;right:0;z-index:15;display:flex;align-items:center;gap:12px;padding:9px 14px;font-size:var(--est-fs-sm);color:var(--est-fg);background:var(--est-bg-subtle);border:none;border-radius:var(--est-radius) var(--est-radius) 0 0;box-shadow:inset 3px 0 0 var(--est-accent)}.est2 .est2-selectbar--inset{border-top-right-radius:0}.est2 .est2-selectbar strong{color:var(--est-fg);font-weight:700}.est2 .est2-selectbar__spacer{flex:1 1 auto}.est2 .est2-link{color:var(--est-accent);cursor:pointer;font-weight:600}.est2 .est2-link:hover{text-decoration:underline}.est2 .est2-rowaction{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);border:none;background:transparent;color:var(--est-fg-faint);cursor:pointer;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-rowaction:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-rowaction--danger:hover{color:var(--est-danger)}.est2 .est2-op-cell{text-align:center}.est2 .est2-op{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:26px;padding:0 6px;border-radius:var(--est-radius-sm);color:var(--est-accent);cursor:pointer;font-size:var(--est-fs-sm);transition:background var(--est-transition)}.est2 .est2-op:hover{background:var(--est-accent-weak)}.est2 .est2-loading{position:absolute;inset:0;border-radius:var(--est-radius);z-index:20;display:flex;align-items:center;justify-content:center;gap:10px;background:color-mix(in srgb,var(--est-bg) 70%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);color:var(--est-fg-muted);font-size:var(--est-fs-sm)}.est2 .est2-spinner{width:16px;height:16px;border:2px solid var(--est-border-strong);border-top-color:var(--est-accent);border-radius:50%;animation:est2-spin .7s linear infinite}@keyframes est2-spin{to{transform:rotate(360deg)}}.est2 .est2-nowrap{white-space:nowrap}.est2 .est2-cornermenu{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);cursor:pointer;color:var(--est-fg-muted);transition:background var(--est-transition)}.est2 .est2-cornermenu:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-chrome-th{position:relative}.est2 .est2-chrome{display:inline-flex;align-items:center;gap:2px}.est2 .est2-chrome-wrap{position:relative;display:inline-flex}.est2 .est2-chrome-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer;font-size:16px;line-height:1;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-chrome-btn:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-menu{position:fixed;z-index:var(--est-z-menu);min-width:180px;padding:4px;background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 8px 24px #0000002e;display:flex;flex-direction:column}.est2 .est2-menu-item{display:block;width:100%;padding:8px 10px;border:none;background:transparent;text-align:left;font:inherit;color:var(--est-fg);border-radius:var(--est-radius-sm);cursor:pointer}.est2 .est2-menu-item:hover{background:var(--est-bg-hover)}.est2 .est2-dialog-backdrop{position:fixed;inset:0;z-index:var(--est-z-modal);display:flex;align-items:center;justify-content:center;padding:16px}.est2 .est2-dialog-backdrop:before{content:\"\";position:absolute;inset:0;background-color:#000;opacity:.5}.est2 .est2-dialog{position:relative}.est2 .est2-dialog-backdrop--embedded{--est-embed-offset: 110px;padding-top:5%;margin-left:calc(-1 * var(--est-embed-offset));width:calc(100% + var(--est-embed-offset));overflow:hidden}.est2 .est2-dialog-backdrop--embedded .est2-dialog{max-height:600px}.est2 .est2-dialog{width:520px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);display:flex;flex-direction:column;background:var(--est-bg);color:var(--est-fg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 16px 48px #0000004d;overflow:hidden}.est2 .est2-dialog__head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;font-weight:700;border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__close{border:none;background:transparent;cursor:pointer;color:var(--est-fg-muted);font-size:15px;line-height:1;padding:4px;border-radius:var(--est-radius-sm)}.est2 .est2-dialog__close:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-dialog__tools{padding:8px 14px;font-size:var(--est-fs-sm);border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__tools .est2-link{border:none;background:none;padding:0;font:inherit;font-weight:600}.est2 .est2-dialog__sep{margin:0 6px;color:var(--est-fg-faint)}.est2 .est2-collist{list-style:none;margin:0;padding:6px;overflow-y:auto;flex:1 1 auto;min-height:0}.est2 .est2-collist__row{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:var(--est-radius-sm)}.est2 .est2-collist__row:hover{background:var(--est-bg-hover)}.est2 .est2-collist__row--drag{cursor:grab}.est2 .est2-collist__row--drag:active{cursor:grabbing}.est2 .est2-collist__row--dragging{opacity:.45;background:var(--est-bg-hover)}.est2 .est2-collist__row--drop-above{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 .est2-collist__row--drop-below{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 .est2-collist__grip{display:inline-flex;align-items:center;justify-content:center;color:var(--est-fg-faint);cursor:grab;flex:0 0 auto}.est2 .est2-collist__grip:active{cursor:grabbing}.est2 .est2-collist__row--drag:hover .est2-collist__grip{color:var(--est-fg-muted)}.est2 .est2-collist__grip--locked{color:var(--est-fg-faint);opacity:.55;cursor:default}.est2 .est2-collist__row--locked .est2-collist__label{color:var(--est-fg-muted)}.est2 .est2-collist__vis{display:inline-flex}.est2 .est2-collist__label{flex:1 1 auto}.est2 .est2-collist__path{color:var(--est-fg-faint);margin-right:4px}.est2 .est2-collist__ord{display:inline-flex;gap:4px}.est2 .est2-iconbtn{width:26px;height:26px;border:1px solid var(--est-border);background:var(--est-bg);border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer}.est2 .est2-iconbtn:hover:not(:disabled){background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-iconbtn:disabled{opacity:.4;cursor:default}.est2 .est2-dialog__foot{display:flex;align-items:center;gap:8px;padding:12px 14px;border-top:1px solid var(--est-border)}.est2 .est2-dialog__spacer{flex:1 1 auto}.est2 .est2-btn{padding:7px 14px;border-radius:var(--est-radius-sm);font:inherit;font-weight:600;cursor:pointer;border:1px solid transparent}.est2 .est2-btn--ghost{background:transparent;color:var(--est-fg);border-color:var(--est-border)}.est2 .est2-btn--ghost:hover{background:var(--est-bg-hover)}.est2 .est2-btn--primary{background:var(--est-accent);color:var(--est-accent-fg)}.est2 .est2-btn--primary:hover{filter:brightness(1.05)}.est2 .est2-empty{padding:48px 16px;text-align:center;color:var(--est-fg-faint);font-size:var(--est-fs-sm)}.ngx-contextmenu{--ctx-bg: #ffffff;--ctx-fg: #1a1d24;--ctx-muted: #626b7a;--ctx-border: #e6e9ef;--ctx-hover: #f2f4f7;--ctx-accent: #4f46e5;--ctx-shadow: 0 10px 28px -8px rgba(16, 24, 40, .22), 0 2px 8px -3px rgba(16, 24, 40, .14);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.ngx-contextmenu .dropdown-menu{display:block;min-width:200px;margin:0;padding:6px;list-style:none;background:var(--ctx-bg);border:1px solid var(--ctx-border);border-radius:12px;box-shadow:var(--ctx-shadow);animation:est2-ctx-in .12s cubic-bezier(.16,1,.3,1)}.ngx-contextmenu li{list-style:none;margin:0}.ngx-contextmenu li>a{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:7px;color:var(--ctx-fg);font-size:13.5px;line-height:1.2;text-decoration:none;cursor:pointer;white-space:nowrap;transition:background .12s ease,color .12s ease}.ngx-contextmenu li>a:hover,.ngx-contextmenu li>a:focus{background:var(--ctx-hover);color:var(--ctx-fg);text-decoration:none;outline:none}.ngx-contextmenu li.divider,.ngx-contextmenu li[role=separator]{height:1px;margin:6px 8px;padding:0;background:var(--ctx-border)}.ngx-contextmenu li.disabled>a,.ngx-contextmenu li[aria-disabled=true]>a{color:var(--ctx-muted);opacity:.55;pointer-events:none}@media(prefers-color-scheme:dark){.ngx-contextmenu{--ctx-bg: #1e222b;--ctx-fg: #e7eaf0;--ctx-muted: #9aa3b2;--ctx-border: #2a2f3a;--ctx-hover: #232733;--ctx-accent: #7c74ff;--ctx-shadow: 0 12px 30px -8px rgba(0, 0, 0, .6), 0 2px 8px -3px rgba(0, 0, 0, .5)}}@keyframes est2-ctx-in{0%{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@media(prefers-reduced-motion:reduce){.ngx-contextmenu .dropdown-menu{animation:none}}\n"] }]
|
|
9589
9893
|
}], ctorParameters: () => [{ type: i1.NgControl, decorators: [{
|
|
9590
9894
|
type: Self
|
|
9591
9895
|
}, {
|
|
@@ -9633,9 +9937,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
9633
9937
|
}], theadRef: [{
|
|
9634
9938
|
type: ViewChild,
|
|
9635
9939
|
args: ['theadRef']
|
|
9636
|
-
}], _Selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "Selection", required: false }] }], SingleSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "SingleSelection", required: false }] }], SelectionDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "SelectionDisabled", required: false }] }], _SelectAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "SelectAll", required: false }] }], _UseSelectionCache: [{ type: i0.Input, args: [{ isSignal: true, alias: "UseSelectionCache", required: false }] }], _ShiftClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "ShiftClick", required: false }] }], _OrderByColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "OrderByColumn", required: false }] }], MultipleOrderingDirectives: [{ type: i0.Input, args: [{ isSignal: true, alias: "MultipleOrderingDirectives", required: false }] }], Removal: [{ type: i0.Input, args: [{ isSignal: true, alias: "Removal", required: false }] }], RemovalCondition: [{ type: i0.Input, args: [{ isSignal: true, alias: "RemovalCondition", required: false }] }], RowClassAssigner: [{
|
|
9940
|
+
}], _Selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "Selection", required: false }] }], SingleSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "SingleSelection", required: false }] }], SelectionDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "SelectionDisabled", required: false }] }], _SelectAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "SelectAll", required: false }] }], SelectionKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "SelectionKey", required: false }] }], _UseSelectionCache: [{ type: i0.Input, args: [{ isSignal: true, alias: "UseSelectionCache", required: false }] }], _ShiftClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "ShiftClick", required: false }] }], _OrderByColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "OrderByColumn", required: false }] }], MultipleOrderingDirectives: [{ type: i0.Input, args: [{ isSignal: true, alias: "MultipleOrderingDirectives", required: false }] }], Removal: [{ type: i0.Input, args: [{ isSignal: true, alias: "Removal", required: false }] }], RemovalCondition: [{ type: i0.Input, args: [{ isSignal: true, alias: "RemovalCondition", required: false }] }], RowClassAssigner: [{
|
|
9637
9941
|
type: Input
|
|
9638
|
-
}], _HidePaging: [{ type: i0.Input, args: [{ isSignal: true, alias: "HidePaging", required: false }] }], _HidePagingCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "HidePagingCount", required: false }] }], _HidePagingButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "HidePagingButtons", required: false }] }], _AllSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "AllSearch", required: false }] }], _PagingStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "PagingStyle", required: false }] }], _ArraymodeItemsPerPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "ArraymodeItemsPerPage", required: false }] }], _UseArrayModePaging: [{ type: i0.Input, args: [{ isSignal: true, alias: "UseArrayModePaging", required: false }] }], CountLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "CountLabel", required: false }] }], Height: [{ type: i0.Input, args: [{ isSignal: true, alias: "Height", required: false }] }], MaxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "MaxHeight", required: false }] }], EmptySpaceBackgroundColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "EmptySpaceBackgroundColor", required: false }] }], HighCellDensity: [{ type: i0.Input, args: [{ isSignal: true, alias: "HighCellDensity", required: false }] }], HeaderHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "HeaderHidden", required: false }] }], BodyHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "BodyHidden", required: false }] }], ShowLoadingOnBootstrap: [{ type: i0.Input, args: [{ isSignal: true, alias: "ShowLoadingOnBootstrap", required: false }] }], _DefaultAlignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "DefaultAlignment", required: false }] }], _TableClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "TableClass", required: false }] }], _ContainerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "ContainerClass", required: false }] }], EsTableHandledSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "EsTableHandledSearch", required: false }] }], SearchThrottle: [{ type: i0.Input, args: [{ isSignal: true, alias: "SearchThrottle", required: false }] }], _ColumnsResizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "ColumnsResizable", required: false }] }], _ColumnsPinnable: [{ type: i0.Input, args: [{ isSignal: true, alias: "ColumnsPinnable", required: false }] }], _HiddenColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "HiddenColumns", required: false }] }], _ColumnsOrdering: [{ type: i0.Input, args: [{ isSignal: true, alias: "ColumnsOrdering", required: false }] }], _Export: [{ type: i0.Input, args: [{ isSignal: true, alias: "Export", required: false }] }], XLSXExport: [{ type: i0.Input, args: [{ isSignal: true, alias: "XLSXExport", required: false }] }], CSVExport: [{ type: i0.Input, args: [{ isSignal: true, alias: "CSVExport", required: false }] }], ExportFileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "ExportFileName", required: false }] }], ExportOnlyVisibleColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "ExportOnlyVisibleColumns", required: false }] }], ExportFunction: [{
|
|
9942
|
+
}], _HidePaging: [{ type: i0.Input, args: [{ isSignal: true, alias: "HidePaging", required: false }] }], _HidePagingCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "HidePagingCount", required: false }] }], _HidePagingButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "HidePagingButtons", required: false }] }], _AllSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "AllSearch", required: false }] }], _PagingStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "PagingStyle", required: false }] }], _ArraymodeItemsPerPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "ArraymodeItemsPerPage", required: false }] }], _UseArrayModePaging: [{ type: i0.Input, args: [{ isSignal: true, alias: "UseArrayModePaging", required: false }] }], CountLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "CountLabel", required: false }] }], Height: [{ type: i0.Input, args: [{ isSignal: true, alias: "Height", required: false }] }], MaxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "MaxHeight", required: false }] }], VirtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "VirtualScroll", required: false }] }], VirtualRowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "VirtualRowHeight", required: false }] }], EmptySpaceBackgroundColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "EmptySpaceBackgroundColor", required: false }] }], HighCellDensity: [{ type: i0.Input, args: [{ isSignal: true, alias: "HighCellDensity", required: false }] }], HeaderHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "HeaderHidden", required: false }] }], BodyHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "BodyHidden", required: false }] }], ShowLoadingOnBootstrap: [{ type: i0.Input, args: [{ isSignal: true, alias: "ShowLoadingOnBootstrap", required: false }] }], _DefaultAlignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "DefaultAlignment", required: false }] }], _TableClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "TableClass", required: false }] }], _ContainerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "ContainerClass", required: false }] }], EsTableHandledSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "EsTableHandledSearch", required: false }] }], SearchThrottle: [{ type: i0.Input, args: [{ isSignal: true, alias: "SearchThrottle", required: false }] }], _ColumnsResizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "ColumnsResizable", required: false }] }], _ColumnsPinnable: [{ type: i0.Input, args: [{ isSignal: true, alias: "ColumnsPinnable", required: false }] }], _HiddenColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "HiddenColumns", required: false }] }], _ColumnsOrdering: [{ type: i0.Input, args: [{ isSignal: true, alias: "ColumnsOrdering", required: false }] }], _Export: [{ type: i0.Input, args: [{ isSignal: true, alias: "Export", required: false }] }], XLSXExport: [{ type: i0.Input, args: [{ isSignal: true, alias: "XLSXExport", required: false }] }], CSVExport: [{ type: i0.Input, args: [{ isSignal: true, alias: "CSVExport", required: false }] }], ExportFileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "ExportFileName", required: false }] }], ExportOnlyVisibleColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "ExportOnlyVisibleColumns", required: false }] }], ExportFunction: [{
|
|
9639
9943
|
type: Input
|
|
9640
9944
|
}], CornerMenuOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "CornerMenuOptions", required: false }] }], DynamicOperations: [{ type: i0.Input, args: [{ isSignal: true, alias: "DynamicOperations", required: false }] }], _DynamicRowColumnsDefinition: [{ type: i0.Input, args: [{ isSignal: true, alias: "DynamicRowColumnsDefinition", required: false }] }], Hierarchy: [{ type: i0.Input, args: [{ isSignal: true, alias: "Hierarchy", required: false }] }], _ParentKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "ParentKey", required: false }] }], _OwnKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "OwnKey", required: false }] }], _AutoSortHierarchy: [{ type: i0.Input, args: [{ isSignal: true, alias: "AutoSortHierarchy", required: false }] }], StartsExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "StartsExpanded", required: false }] }], CascadeSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "CascadeSelection", required: false }] }], _SavePreferences: [{ type: i0.Input, args: [{ isSignal: true, alias: "SavePreferences", required: false }] }], Name: [{ type: i0.Input, args: [{ isSignal: true, alias: "Name", required: false }] }], _RowGroupingPagingStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "RowGroupingPagingStyle", required: false }] }], _ShowItemGroupsColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "ShowItemGroupsColumns", required: false }] }], Editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "Editable", required: false }] }], RangeSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "RangeSelection", required: false }] }], ItemSourceProperty: [{ type: i0.Input, args: [{ isSignal: true, alias: "ItemSourceProperty", required: false }] }], HasHeaderGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "HasHeaderGroup", required: false }] }], HasSecondaryHeaderGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "HasSecondaryHeaderGroup", required: false }] }], SearchView: [{ type: i0.Input, args: [{ isSignal: true, alias: "SearchView", required: false }] }], _AutoUpdate: [{ type: i0.Input, args: [{ isSignal: true, alias: "AutoUpdate", required: false }] }], EsThTdProvider: [{
|
|
9641
9945
|
type: Input
|
|
@@ -9665,6 +9969,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
9665
9969
|
}], denseClass: [{
|
|
9666
9970
|
type: HostBinding,
|
|
9667
9971
|
args: ['class.est2--dense']
|
|
9972
|
+
}], scrollRefEl: [{
|
|
9973
|
+
type: ViewChild,
|
|
9974
|
+
args: ['scrollRef']
|
|
9668
9975
|
}], onDocMouseUp: [{
|
|
9669
9976
|
type: HostListener,
|
|
9670
9977
|
args: ['document:mouseup']
|