@esfaenza/es-table 11.2.21 → 11.2.22-beta4
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/bundles/esfaenza-es-table.umd.js +2262 -562
- package/bundles/esfaenza-es-table.umd.js.map +1 -1
- package/bundles/esfaenza-es-table.umd.min.js +2 -2
- package/bundles/esfaenza-es-table.umd.min.js.map +1 -1
- package/esfaenza-es-table.d.ts +5 -5
- package/esfaenza-es-table.metadata.json +1 -1
- package/esm2015/esfaenza-es-table.js +6 -6
- package/esm2015/lib/directives/es_td.directive.js +2 -4
- package/esm2015/lib/directives/es_th.directive.js +23 -7
- package/esm2015/lib/domain/externals/classes/CornerMenuOption.js +4 -0
- package/esm2015/lib/domain/externals/classes/EsTableColumnsDefinition.js +31 -0
- package/esm2015/lib/domain/externals/classes/EsTableOperationDefinition.js +22 -0
- package/esm2015/lib/domain/externals/classes/appsearch/AppOrdering.js +16 -0
- package/esm2015/lib/domain/externals/classes/appsearch/AppSearch.js +35 -0
- package/esm2015/lib/domain/externals/classes/appsearch/GenericItem.js +11 -0
- package/esm2015/lib/domain/externals/classes/appsearch/Group.js +17 -0
- package/esm2015/lib/domain/externals/classes/appsearch/GroupAggregation.js +16 -0
- package/esm2015/lib/domain/externals/classes/appsearch/GroupFilter.js +14 -0
- package/esm2015/lib/domain/externals/classes/appsearch/GroupOrAggregation.js +16 -0
- package/esm2015/lib/domain/externals/classes/appsearch/ItemsSelection.js +23 -0
- package/esm2015/lib/domain/externals/classes/report/ReportColumn.js +4 -0
- package/esm2015/lib/domain/externals/classes/report/ReportDefinition.js +4 -0
- package/esm2015/lib/domain/externals/classes/report/ReportOrder.js +4 -0
- package/esm2015/lib/domain/externals/classes/report/ReportParam.js +4 -0
- package/esm2015/lib/domain/externals/classes/report/ReportResult.js +4 -0
- package/esm2015/lib/domain/externals/classes/report/ReportRow.js +4 -0
- package/esm2015/lib/domain/externals/index.js +18 -0
- package/esm2015/lib/domain/index.js +3 -16
- package/esm2015/lib/domain/internals/classes/CacheTriptic.js +16 -0
- package/esm2015/lib/domain/internals/classes/EsTableColumn.js +24 -0
- package/esm2015/lib/domain/internals/classes/GroupPager.js +21 -0
- package/esm2015/lib/domain/internals/classes/GroupRouteFragment.js +17 -0
- package/esm2015/lib/domain/internals/classes/ThAggregation.js +16 -0
- package/esm2015/lib/domain/internals/index.js +6 -0
- package/esm2015/lib/es-table.module.js +9 -4
- package/esm2015/lib/es_table.component.js +1829 -343
- package/esm2015/lib/es_table.component.loc.js +6 -7
- package/esm2015/lib/es_td.component.js +28 -43
- package/esm2015/lib/es_th.component.js +16 -44
- package/esm2015/lib/models/EsTableDefaultable.js +4 -0
- package/esm2015/lib/models/EsTableModuleConfig.js +2 -4
- package/esm2015/lib/pager/table_pager.component.js +48 -26
- package/esm2015/lib/pager/table_pager.component.loc.js +5 -7
- package/esm2015/lib/tokens.js +6 -4
- package/esm2015/public-api.js +3 -2
- package/fesm2015/esfaenza-es-table.js +2145 -553
- package/fesm2015/esfaenza-es-table.js.map +1 -1
- package/lib/directives/es_td.directive.d.ts +1 -3
- package/lib/directives/es_th.directive.d.ts +18 -5
- package/lib/domain/externals/classes/CornerMenuOption.d.ts +7 -0
- package/lib/domain/{classes → externals/classes}/EsTableColumnsDefinition.d.ts +5 -7
- package/lib/domain/{classes → externals/classes}/EsTableOperationDefinition.d.ts +1 -3
- package/lib/domain/{classes → externals/classes/appsearch}/AppOrdering.d.ts +0 -0
- package/lib/domain/externals/classes/appsearch/AppSearch.d.ts +67 -0
- package/lib/domain/externals/classes/appsearch/GenericItem.d.ts +13 -0
- package/lib/domain/externals/classes/appsearch/Group.d.ts +17 -0
- package/lib/domain/externals/classes/appsearch/GroupAggregation.d.ts +14 -0
- package/lib/domain/externals/classes/appsearch/GroupFilter.d.ts +12 -0
- package/lib/domain/externals/classes/appsearch/GroupOrAggregation.d.ts +14 -0
- package/lib/domain/externals/classes/appsearch/ItemsSelection.d.ts +22 -0
- package/lib/domain/externals/classes/report/ReportColumn.d.ts +15 -0
- package/lib/domain/externals/classes/report/ReportDefinition.d.ts +24 -0
- package/lib/domain/externals/classes/report/ReportOrder.d.ts +7 -0
- package/lib/domain/externals/classes/report/ReportParam.d.ts +40 -0
- package/lib/domain/externals/classes/report/ReportResult.d.ts +12 -0
- package/lib/domain/externals/classes/report/ReportRow.d.ts +5 -0
- package/lib/domain/externals/index.d.ts +17 -0
- package/lib/domain/index.d.ts +2 -15
- package/lib/domain/internals/classes/CacheTriptic.d.ts +14 -0
- package/lib/domain/{classes → internals/classes}/EsTableColumn.d.ts +6 -4
- package/lib/domain/internals/classes/GroupPager.d.ts +22 -0
- package/lib/domain/internals/classes/GroupRouteFragment.d.ts +15 -0
- package/lib/domain/internals/classes/ThAggregation.d.ts +14 -0
- package/lib/domain/internals/index.d.ts +5 -0
- package/lib/es_table.component.d.ts +456 -62
- package/lib/es_table.component.loc.d.ts +2 -6
- package/lib/es_td.component.d.ts +14 -36
- package/lib/es_th.component.d.ts +21 -61
- package/lib/models/EsTableDefaultable.d.ts +19 -0
- package/lib/models/EsTableModuleConfig.d.ts +8 -7
- package/lib/pager/table_pager.component.d.ts +27 -30
- package/lib/pager/table_pager.component.loc.d.ts +2 -6
- package/lib/tokens.d.ts +6 -3
- package/package.json +2 -1
- package/public-api.d.ts +2 -1
- package/esm2015/lib/domain/classes/AppOrdering.js +0 -16
- package/esm2015/lib/domain/classes/AppSearch.js +0 -35
- package/esm2015/lib/domain/classes/CornerMenuOption.js +0 -6
- package/esm2015/lib/domain/classes/EsTableColumn.js +0 -22
- package/esm2015/lib/domain/classes/EsTableColumnsDefinition.js +0 -31
- package/esm2015/lib/domain/classes/EsTableOperationDefinition.js +0 -24
- package/esm2015/lib/domain/classes/GenericItem.js +0 -15
- package/esm2015/lib/domain/classes/IAppSearch.js +0 -2
- package/esm2015/lib/domain/classes/ItemsSelection.js +0 -25
- package/esm2015/lib/domain/classes/ReportColumn.js +0 -6
- package/esm2015/lib/domain/classes/ReportDefinition.js +0 -6
- package/esm2015/lib/domain/classes/ReportOrder.js +0 -6
- package/esm2015/lib/domain/classes/ReportParam.js +0 -6
- package/esm2015/lib/domain/classes/ReportResult.js +0 -6
- package/esm2015/lib/domain/classes/ReportRow.js +0 -6
- package/lib/domain/classes/AppSearch.d.ts +0 -76
- package/lib/domain/classes/CornerMenuOption.d.ts +0 -13
- package/lib/domain/classes/GenericItem.d.ts +0 -25
- package/lib/domain/classes/IAppSearch.d.ts +0 -67
- package/lib/domain/classes/ItemsSelection.d.ts +0 -27
- package/lib/domain/classes/ReportColumn.d.ts +0 -29
- package/lib/domain/classes/ReportDefinition.d.ts +0 -46
- package/lib/domain/classes/ReportOrder.d.ts +0 -13
- package/lib/domain/classes/ReportParam.d.ts +0 -76
- package/lib/domain/classes/ReportResult.d.ts +0 -22
- package/lib/domain/classes/ReportRow.d.ts +0 -9
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
2
|
import { Component, ChangeDetectionStrategy, ElementRef, Renderer2, ViewContainerRef, Input, EventEmitter, Output, ViewChild, HostListener, Directive, TemplateRef, InjectionToken, Injectable, Optional, Inject, ViewEncapsulation, Self, ChangeDetectorRef, ContentChildren, forwardRef, ContentChild, NgModule } from '@angular/core';
|
|
3
3
|
import { NgControl, FormsModule } from '@angular/forms';
|
|
4
|
-
import { HashingService, UtilityService, ExportService, MessageService } from '@esfaenza/extensions';
|
|
4
|
+
import { HashingService, UtilityService, ExportService, DateService, MessageService } from '@esfaenza/extensions';
|
|
5
5
|
import { LocalizationService, LocalizationModule } from '@esfaenza/localizations';
|
|
6
6
|
import { PreferencesService } from '@esfaenza/preferences';
|
|
7
7
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
8
8
|
import { CommonModule } from '@angular/common';
|
|
9
9
|
import { RouterModule } from '@angular/router';
|
|
10
|
+
import { MatSelectModule } from '@angular/material/select';
|
|
11
|
+
import { MatInputModule } from '@angular/material/input';
|
|
10
12
|
import { ModalModule } from 'ngx-bootstrap/modal';
|
|
11
13
|
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
|
12
14
|
import { CsvModule } from '@ctrl/ngx-csv';
|
|
@@ -63,9 +65,7 @@ class AppSearch {
|
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
/**
|
|
67
|
-
* Classe che identifica una colonna. Utilizzata in modalità "Colonne dinamiche"
|
|
68
|
-
*/
|
|
68
|
+
/** Classe che identifica una colonna. Utilizzata in modalità "Colonne dinamiche" */
|
|
69
69
|
class EsTableColumnsDefinition {
|
|
70
70
|
/**
|
|
71
71
|
* Costruttore
|
|
@@ -80,8 +80,9 @@ class EsTableColumnsDefinition {
|
|
|
80
80
|
* @param {boolean} visible Visibilità o meno della colonna
|
|
81
81
|
* @param {string} clss Classe da applicare sia ai TD che ai TH relativi a questa colonna
|
|
82
82
|
* @param {boolean} orderable Indica se la colonna è ordinabile o no (nel senso ASC / DESC / NONE)
|
|
83
|
+
* @param {boolean} headerWraps Indica se il testo dell'header dev'essere wrappato all'interno del th. Di default no.
|
|
83
84
|
*/
|
|
84
|
-
constructor(description, propertyName, routePath = null, routeParameterProperties = null, dataOrder = null, columnOrder = null, visible = true, clss = null, orderable = true) {
|
|
85
|
+
constructor(description, propertyName, routePath = null, routeParameterProperties = null, dataOrder = null, columnOrder = null, visible = true, clss = null, orderable = true, headerWraps = false) {
|
|
85
86
|
this.description = description;
|
|
86
87
|
this.propertyName = propertyName;
|
|
87
88
|
this.routePath = routePath;
|
|
@@ -91,69 +92,50 @@ class EsTableColumnsDefinition {
|
|
|
91
92
|
this.visible = visible;
|
|
92
93
|
this.clss = clss;
|
|
93
94
|
this.orderable = orderable;
|
|
95
|
+
this.headerWraps = headerWraps;
|
|
94
96
|
}
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
/**
|
|
98
|
-
* Classe che definisce un oggetto generico come lista di proprietà-valore
|
|
99
|
-
*/
|
|
99
|
+
/** Classe che definisce un oggetto generico come lista di proprietà-valore */
|
|
100
100
|
class GenericItem {
|
|
101
|
-
/**
|
|
102
|
-
* @ignore
|
|
103
|
-
*/
|
|
101
|
+
/** @ignore */
|
|
104
102
|
constructor() {
|
|
105
103
|
this._selected = false;
|
|
106
104
|
this._rowClass = null;
|
|
107
|
-
this.
|
|
105
|
+
this._hash = null;
|
|
108
106
|
this.properties = {};
|
|
109
107
|
}
|
|
110
108
|
}
|
|
111
109
|
|
|
112
|
-
/**
|
|
113
|
-
* Indica un'opzione cliccabile nel Corner Menù della tabella (il menù richiamabile dai 3 pallini verticli in alto a destra)
|
|
114
|
-
*/
|
|
110
|
+
/** Indica un'opzione cliccabile nel Corner Menù della tabella (il menù richiamabile dai 3 pallini verticli in alto a destra) */
|
|
115
111
|
class CornerMenuOption {
|
|
116
112
|
}
|
|
117
113
|
|
|
118
|
-
/**
|
|
119
|
-
* Definizione generica di un report che può o no disporre di paginazione/export e la cui richiesta è basata su uno o più parametri
|
|
120
|
-
*/
|
|
114
|
+
/** Definizione generica di un report che può o no disporre di paginazione/export e la cui richiesta è basata su uno o più parametri */
|
|
121
115
|
class ReportDefinition {
|
|
122
116
|
}
|
|
123
117
|
|
|
124
|
-
/**
|
|
125
|
-
* Classe che identifica una direttiva di ordinamento per un report
|
|
126
|
-
*/
|
|
118
|
+
/** Classe che identifica una direttiva di ordinamento per un report */
|
|
127
119
|
class ReportOrder {
|
|
128
120
|
}
|
|
129
121
|
|
|
130
|
-
/**
|
|
131
|
-
* Classe che rappresenta una colonna di un report
|
|
132
|
-
*/
|
|
122
|
+
/** Classe che rappresenta una colonna di un report */
|
|
133
123
|
class ReportColumn {
|
|
134
124
|
}
|
|
135
125
|
|
|
136
|
-
/**
|
|
137
|
-
* Classe che rappresenta una lista di oggetti generati da un report
|
|
138
|
-
*/
|
|
126
|
+
/** Classe che rappresenta una lista di oggetti generati da un report */
|
|
139
127
|
class ReportResult {
|
|
140
128
|
}
|
|
141
129
|
|
|
142
|
-
/**
|
|
143
|
-
* Classe che rappresenta i valori delle proprietà di un oggetto Report
|
|
144
|
-
*/
|
|
130
|
+
/** Classe che rappresenta i valori delle proprietà di un oggetto Report */
|
|
145
131
|
class ReportRow {
|
|
146
132
|
}
|
|
147
133
|
|
|
148
|
-
/**
|
|
149
|
-
* Classe che identifica un parametro generico per un report
|
|
150
|
-
*/
|
|
134
|
+
/** Classe che identifica un parametro generico per un report */
|
|
151
135
|
class ReportParam {
|
|
152
136
|
}
|
|
153
137
|
|
|
154
|
-
/**
|
|
155
|
-
* Indica operazioni dinamiche generiche che possono essere effettuate per riga. Appaiono come colonne extra sul lato sinistro della tabella
|
|
156
|
-
*/
|
|
138
|
+
/** Indica operazioni dinamiche generiche che possono essere effettuate per riga. Appaiono come colonne extra sul lato sinistro della tabella */
|
|
157
139
|
class EsTableOperationDefinition {
|
|
158
140
|
/**
|
|
159
141
|
* Costruttore
|
|
@@ -175,9 +157,109 @@ class EsTableOperationDefinition {
|
|
|
175
157
|
}
|
|
176
158
|
}
|
|
177
159
|
|
|
178
|
-
/**
|
|
179
|
-
|
|
180
|
-
|
|
160
|
+
/** Identifica una selezione applicabile agli oggetti presentati in una tabella */
|
|
161
|
+
class ItemsSelection {
|
|
162
|
+
/**
|
|
163
|
+
* Costruttore
|
|
164
|
+
*
|
|
165
|
+
* @param {T[]} selected Oggetti da considerare selezionati
|
|
166
|
+
*/
|
|
167
|
+
constructor(selected) {
|
|
168
|
+
/** Indica se tutti gli elementi sono da considerarsi selezionati (anche quelli di altre pagine) */
|
|
169
|
+
this.all = false;
|
|
170
|
+
/** Se **all** è **true**, indica gli elementi da escludere, altrimenti è insensato */
|
|
171
|
+
this.exclusions = [];
|
|
172
|
+
/** Se **all** è **true**, indica i gruppi da escludere, altrimenti è insensato */
|
|
173
|
+
this.group_exclusions = [];
|
|
174
|
+
this.count = selected.length;
|
|
175
|
+
this.items = selected;
|
|
176
|
+
this.all = false;
|
|
177
|
+
this.exclusions = [];
|
|
178
|
+
this.groups = [];
|
|
179
|
+
this.group_exclusions = [];
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Classe che rappresenta un Gruppo con le proprie aggregazioni */
|
|
184
|
+
class Group {
|
|
185
|
+
/**
|
|
186
|
+
* Costruttore
|
|
187
|
+
*
|
|
188
|
+
* @param {string} column ID della colonna raggruppata
|
|
189
|
+
* @param {number} count Numero di elementi raggruppati sotto questa colonna
|
|
190
|
+
* @param {string} value Valore del Gruppo
|
|
191
|
+
*/
|
|
192
|
+
constructor(column, count, value) {
|
|
193
|
+
this.column = column;
|
|
194
|
+
this.count = count;
|
|
195
|
+
this.value = value;
|
|
196
|
+
this.aggregations = [];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Classe che rappresenta un'aggregazione */
|
|
201
|
+
class GroupAggregation {
|
|
202
|
+
/**
|
|
203
|
+
* Costruttore
|
|
204
|
+
*
|
|
205
|
+
* @param {string} column ID della colonna aggregata
|
|
206
|
+
* @param {'min' | 'max' | 'sum' } aggregation Aggregazione da effettuare su questa colonna
|
|
207
|
+
* @param {string} value Valore dell'aggregazione
|
|
208
|
+
*/
|
|
209
|
+
constructor(column, aggregation, value) {
|
|
210
|
+
this.column = column;
|
|
211
|
+
this.aggregation = aggregation;
|
|
212
|
+
this.value = value;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Classe che rappresenta un filtro su un gruppo */
|
|
217
|
+
class GroupFilter {
|
|
218
|
+
/**
|
|
219
|
+
* Costruttore
|
|
220
|
+
*
|
|
221
|
+
* @param {string} column ID della colonna gruppata per cui si richiede di filtrare
|
|
222
|
+
* @param {string} value Valore del gruppo su questa **column** per cui si richiede di filtrare
|
|
223
|
+
*/
|
|
224
|
+
constructor(column, value) {
|
|
225
|
+
this.column = column;
|
|
226
|
+
this.value = value;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Classe che rappresenta o un gruppo o una aggregazione su una colonna. Usata solo internamente */
|
|
231
|
+
class GroupOrAggregation {
|
|
232
|
+
/**
|
|
233
|
+
* Costruttore
|
|
234
|
+
*
|
|
235
|
+
* @param {string} column Colonna su cui è presente o un gruppo o un'aggregazione
|
|
236
|
+
* @param {'min' | 'max' | 'sum' } aggregation Aggregazione presente sulla **column**. Se questo campo è nullo significa che è un gruppo.
|
|
237
|
+
* @param {'string' | 'date' | 'number'} datatype Tipo di dati contenuto nella colonna **column** se non c'è alcuna aggregazione è inutile, pertanto non sarà valorizzato
|
|
238
|
+
*/
|
|
239
|
+
constructor(column, aggregation, datatype) {
|
|
240
|
+
this.column = column;
|
|
241
|
+
this.aggregation = aggregation;
|
|
242
|
+
this.datatype = datatype;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Rappresenta un trittico formato da un array e due cache relative a tale array per un accesso estremamente veloce per tutte le operazioni del caso */
|
|
247
|
+
class CacheTriptic {
|
|
248
|
+
/**
|
|
249
|
+
* Costruttore
|
|
250
|
+
*
|
|
251
|
+
* @param {Map<string, any>} cache Cache Chiave-Oggetto
|
|
252
|
+
* @param {Map<string, number>} index_cache Cache Indice-Oggetto
|
|
253
|
+
* @param {any[]} array Array contenente gli oggetti
|
|
254
|
+
*/
|
|
255
|
+
constructor(cache, index_cache, array) {
|
|
256
|
+
this.cache = cache;
|
|
257
|
+
this.index_cache = index_cache;
|
|
258
|
+
this.array = array;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Definizione di una colonna, utilizzato nella dialog che permette di modificare le posizioni e le visibilità */
|
|
181
263
|
class EsTableColumn {
|
|
182
264
|
/**
|
|
183
265
|
* Costruttore
|
|
@@ -186,66 +268,89 @@ class EsTableColumn {
|
|
|
186
268
|
* @param {string} description Descrizione (Header)
|
|
187
269
|
* @param {boolean} visible Indica se di default mostrarla o meno
|
|
188
270
|
* @param {boolean} fixed Indica se è una colonna fixed
|
|
271
|
+
* @param {boolean} pinned Indica se è una colonna pinnata
|
|
272
|
+
* @param {number} pinnedWidth Indica la dimensione da assegnare a questa colonna quando è pinnata
|
|
189
273
|
* @param {TemplateRef<any>} template Indica il template da usare per mostrare il testo dell'Header
|
|
190
274
|
*/
|
|
191
|
-
constructor(id, description, visible, fixed, template) {
|
|
275
|
+
constructor(id, description, visible, fixed, pinned, pinnedWidth, template) {
|
|
192
276
|
this.id = id;
|
|
193
277
|
this.description = description;
|
|
194
278
|
this.visible = visible;
|
|
195
279
|
this.fixed = fixed;
|
|
280
|
+
this.pinned = pinned;
|
|
281
|
+
this.pinnedWidth = pinnedWidth;
|
|
196
282
|
this.template = template;
|
|
197
283
|
}
|
|
198
284
|
}
|
|
199
285
|
|
|
200
|
-
/**
|
|
201
|
-
|
|
202
|
-
*/
|
|
203
|
-
class ItemsSelection {
|
|
286
|
+
/** Classe che rappresenta un separatore da inserire fra gli oggetti dell'es-table per le operazioni di paginazione dei raggruppamenti per riga */
|
|
287
|
+
class GroupPager {
|
|
204
288
|
/**
|
|
205
289
|
* Costruttore
|
|
206
290
|
*
|
|
207
|
-
* @param {
|
|
291
|
+
* @param {number} groupLevel Livello del gruppo a cui questo separatore fa riferimento
|
|
292
|
+
* @param {string} parentKey Chiave del gruppo parent se esiste
|
|
293
|
+
* @param {AppSearch<any>} view Vista di ricerca collegata a questo elemento
|
|
294
|
+
* @param {'groups' | 'items'} searches Indica che cosa cerca questo separatore, se sottogruppi o oggetti
|
|
208
295
|
*/
|
|
209
|
-
constructor(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
this.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
this.exclusions = [];
|
|
218
|
-
this.count = selected.length;
|
|
219
|
-
this.items = selected;
|
|
220
|
-
this.all = false;
|
|
221
|
-
this.exclusions = [];
|
|
296
|
+
constructor(_grouplevel, _thisRoute, _parent, view, searches) {
|
|
297
|
+
this._grouplevel = _grouplevel;
|
|
298
|
+
this._thisRoute = _thisRoute;
|
|
299
|
+
this._parent = _parent;
|
|
300
|
+
this.view = view;
|
|
301
|
+
this.searches = searches;
|
|
302
|
+
this._sep = true;
|
|
303
|
+
this.buttons = [];
|
|
222
304
|
}
|
|
223
305
|
}
|
|
224
306
|
|
|
225
|
-
//Angular
|
|
226
307
|
/**
|
|
227
|
-
*
|
|
308
|
+
* Classe che rappresenta un singolo frammento di route di un elemento gruppo o non. Un array di questi indica tutte le colonne di gruppo con i loro valori
|
|
309
|
+
* per arrivare ad una ricerca su sottogruppi o elementi relativi
|
|
228
310
|
*/
|
|
229
|
-
class
|
|
311
|
+
class GroupRouteFragment {
|
|
230
312
|
/**
|
|
231
|
-
*
|
|
313
|
+
* Costruttore
|
|
314
|
+
*
|
|
315
|
+
* @param {string} column Colonna di raggruppamento
|
|
316
|
+
* @param {string} value Valore della colonna di raggruppamento
|
|
317
|
+
*/
|
|
318
|
+
constructor(column, value) {
|
|
319
|
+
this.column = column;
|
|
320
|
+
this.value = value;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** Classe rappresentante una singola aggregazione effettuata su una colonna */
|
|
325
|
+
class ThAggregation {
|
|
326
|
+
/**
|
|
327
|
+
* Costruttore
|
|
328
|
+
*
|
|
329
|
+
* @param {'min' | 'max' | 'sum'} func Funzione di aggergazione, può essere **min**, **max** o **sum**
|
|
330
|
+
* @param {string} format Formato richiesto per il valore dell'aggregazione
|
|
331
|
+
* @param {string} match Match intero del pezzo di testo da cui si è estrapolata l'aggregazione, da rimpiazzare col valore calcolato
|
|
232
332
|
*/
|
|
333
|
+
constructor(func, format, match) {
|
|
334
|
+
this.func = func;
|
|
335
|
+
this.format = format;
|
|
336
|
+
this.match = match;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
//Angular
|
|
341
|
+
/** Componente rappresentante una singola cella del body della tabella */
|
|
342
|
+
class EsTd {
|
|
343
|
+
/** @ignore */
|
|
233
344
|
constructor(myself, renderer, _viewContainer, sanitizer) {
|
|
234
345
|
this.myself = myself;
|
|
235
346
|
this.renderer = renderer;
|
|
236
347
|
this._viewContainer = _viewContainer;
|
|
237
348
|
this.sanitizer = sanitizer;
|
|
238
|
-
/**
|
|
239
|
-
* Id della cella, dev'essere lo stesso della colonna **EsTh** relativa
|
|
240
|
-
*/
|
|
349
|
+
/** Id della cella, dev'essere lo stesso della colonna **EsTh** relativa */
|
|
241
350
|
this.ID = "";
|
|
242
|
-
/**
|
|
243
|
-
* Valore da mostrare all'interno della cella. Se omesso verrà proiettato il contenuto dal template in cui è stata usata
|
|
244
|
-
*/
|
|
351
|
+
/** Valore da mostrare all'interno della cella. Se omesso verrà proiettato il contenuto dal template in cui è stata usata */
|
|
245
352
|
this.Display = null;
|
|
246
|
-
/**
|
|
247
|
-
* Template Angular da istanziare per questo TD
|
|
248
|
-
*/
|
|
353
|
+
/** Template Angular da istanziare per questo TD */
|
|
249
354
|
this.Template = null;
|
|
250
355
|
}
|
|
251
356
|
/**
|
|
@@ -270,13 +375,18 @@ class EsTd {
|
|
|
270
375
|
this._Visible = true;
|
|
271
376
|
return this._Visible;
|
|
272
377
|
}
|
|
273
|
-
/**
|
|
274
|
-
* @ignore
|
|
275
|
-
*/
|
|
378
|
+
/** @ignore */
|
|
276
379
|
ngAfterViewInit() {
|
|
277
380
|
// Se è Internal significa che è gestita internamente da ES-TABLE quindi evito di fare sti due passaggi di lettura del DOM
|
|
278
381
|
if (this.Internal)
|
|
279
382
|
return;
|
|
383
|
+
// L'hash è calcolato dalla ES-table in fase di binding
|
|
384
|
+
this.Context = this.Context || this.getTemplateContext()._hash;
|
|
385
|
+
this.Content = this.Display === null || this.Display === "" ? this.sanitizer.bypassSecurityTrustHtml(this.myself.nativeElement.innerHTML) : this.sanitizer.bypassSecurityTrustHtml(this.Display);
|
|
386
|
+
this.Class = this.myself.nativeElement.className.replace("app-display-none", "");
|
|
387
|
+
}
|
|
388
|
+
/** Ottiene il contesto della view su cui è istanziato il componente */
|
|
389
|
+
getTemplateContext() {
|
|
280
390
|
// NGBUG: (<any>this._viewContainer)._view non esiste più in IVY: https://stackoverflow.com/questions/60398827/getting-the-context-of-the-template-inside-of-which-my-component-has-been-render
|
|
281
391
|
let vc = this._viewContainer;
|
|
282
392
|
let context;
|
|
@@ -289,34 +399,23 @@ class EsTd {
|
|
|
289
399
|
context = vc._view.viewContainerParent.context.$implicit;
|
|
290
400
|
else
|
|
291
401
|
context = vc._view.context.$implicit;
|
|
402
|
+
if (context)
|
|
403
|
+
return context;
|
|
292
404
|
// Se non ho ancora trovato il contesto probabilmente sono in IVY e devo fare dei lookup un po' incasinati per beccarlo
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
let iitem = item[ii];
|
|
305
|
-
if (iitem && iitem.$implicit && !iitem.ngIf) {
|
|
306
|
-
context = iitem.$implicit;
|
|
307
|
-
break;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
405
|
+
var array = this._viewContainer._hostLView;
|
|
406
|
+
for (let i = 0; i < array.length; i++) {
|
|
407
|
+
let item = array[i];
|
|
408
|
+
if (item && item.$implicit && !item.ngIf)
|
|
409
|
+
return item.$implicit;
|
|
410
|
+
// Second level search for the real context in case the first one we find is an ngIf
|
|
411
|
+
if (item && item.length && item.length > 0) {
|
|
412
|
+
for (let ii = 0; ii < item.length; ii++) {
|
|
413
|
+
let iitem = item[ii];
|
|
414
|
+
if (iitem && iitem.$implicit && !iitem.ngIf)
|
|
415
|
+
return iitem.$implicit;
|
|
310
416
|
}
|
|
311
|
-
if (context)
|
|
312
|
-
break;
|
|
313
417
|
}
|
|
314
418
|
}
|
|
315
|
-
// Calcolato dalla ES-table in fase di binding
|
|
316
|
-
let hash = context.hash;
|
|
317
|
-
this.Context = hash;
|
|
318
|
-
this.Content = this.Display === null || this.Display === "" ? this.sanitizer.bypassSecurityTrustHtml(this.myself.nativeElement.innerHTML) : this.sanitizer.bypassSecurityTrustHtml(this.Display);
|
|
319
|
-
this.Class = this.myself.nativeElement.className.replace("app-display-none", "");
|
|
320
419
|
}
|
|
321
420
|
}
|
|
322
421
|
EsTd.decorators = [
|
|
@@ -338,27 +437,20 @@ EsTd.propDecorators = {
|
|
|
338
437
|
RouterLink: [{ type: Input }],
|
|
339
438
|
Display: [{ type: Input }],
|
|
340
439
|
Template: [{ type: Input }],
|
|
440
|
+
Context: [{ type: Input }],
|
|
341
441
|
Visible: [{ type: Input }]
|
|
342
442
|
};
|
|
343
443
|
|
|
344
444
|
//Angular
|
|
345
|
-
/**
|
|
346
|
-
* Componente rappresentante una Colonna della tabella
|
|
347
|
-
*/
|
|
445
|
+
/** Componente rappresentante una Colonna della tabella */
|
|
348
446
|
class EsTh {
|
|
349
|
-
/**
|
|
350
|
-
* @ignore
|
|
351
|
-
*/
|
|
447
|
+
/** @ignore */
|
|
352
448
|
constructor(myself, renderer) {
|
|
353
449
|
this.myself = myself;
|
|
354
450
|
this.renderer = renderer;
|
|
355
|
-
/**
|
|
356
|
-
* Dizionario di mappatura con ordinamento attuale e ordinamento successivo per gestire i passaggi di stato
|
|
357
|
-
*/
|
|
451
|
+
/** Dizionario di mappatura con ordinamento attuale e ordinamento successivo per gestire i passaggi di stato */
|
|
358
452
|
this.orderNext = { "NONE": "DESC", "DESC": "ASC", "ASC": null };
|
|
359
|
-
/**
|
|
360
|
-
* Indica se si sta effettuando un'operazione di resize su questa colonna
|
|
361
|
-
*/
|
|
453
|
+
/** Indica se si sta effettuando un'operazione di resize su questa colonna */
|
|
362
454
|
this.resizingThis = false;
|
|
363
455
|
/**
|
|
364
456
|
* Storicizza l'offset di partenza del resize dell'elemento HTML per poter calcolare la nuova dimensione richiesta durente il resize
|
|
@@ -366,21 +458,13 @@ class EsTh {
|
|
|
366
458
|
* nuova width = startOffset + posizione X del mouse
|
|
367
459
|
*/
|
|
368
460
|
this.startOffset = null;
|
|
369
|
-
/**
|
|
370
|
-
* Id della colonna, dev'essere lo stesso per tutti gli **EsTd** relativi
|
|
371
|
-
*/
|
|
461
|
+
/** Id della colonna, dev'essere lo stesso per tutti gli **EsTd** relativi */
|
|
372
462
|
this.ID = "";
|
|
373
|
-
/**
|
|
374
|
-
* Indica se questa colonna è ordinabile o meno
|
|
375
|
-
*/
|
|
463
|
+
/** Indica se questa colonna è ordinabile o meno */
|
|
376
464
|
this.Orderable = true;
|
|
377
|
-
/**
|
|
378
|
-
* Valore da mostrare all'interno della colonna. Se omesso verrà proiettato il contenuto dal template in cui è stata usata
|
|
379
|
-
*/
|
|
465
|
+
/** Valore da mostrare all'interno della colonna. Se omesso verrà proiettato il contenuto dal template in cui è stata usata */
|
|
380
466
|
this.Display = "";
|
|
381
|
-
/**
|
|
382
|
-
* Indica se le dimnsioni di questa colonna sono modificabili o meno
|
|
383
|
-
*/
|
|
467
|
+
/** Indica se le dimnsioni di questa colonna sono modificabili o meno */
|
|
384
468
|
this.Resizable = false;
|
|
385
469
|
/**
|
|
386
470
|
* Indica se sta venendo eseguita una operazione di ricerca o meno, serve per evitare l'esecuzione di eventuale codice che potrebbe dare fastidio
|
|
@@ -391,18 +475,12 @@ class EsTh {
|
|
|
391
475
|
this.Wrap = false;
|
|
392
476
|
/** Indica se la colonna è fixed, cioè se non può né essere nascosta, né riposizionata. Solo le prime colonne possono essere Fixed */
|
|
393
477
|
this.Fixed = false;
|
|
394
|
-
/**
|
|
395
|
-
* Template Angular da istanziare per questo TH
|
|
396
|
-
*/
|
|
478
|
+
/** Template Angular da istanziare per questo TH */
|
|
397
479
|
this.Template = null;
|
|
398
|
-
/**
|
|
399
|
-
* Evento emesso al cambio di ordinamento effettuato su questa colonna
|
|
400
|
-
*/
|
|
480
|
+
/** Evento emesso al cambio di ordinamento effettuato su questa colonna */
|
|
401
481
|
this.onOrderChange = new EventEmitter();
|
|
402
|
-
/**
|
|
403
|
-
|
|
404
|
-
*/
|
|
405
|
-
this.Referenced = false;
|
|
482
|
+
/** Impostato dall'**EsTable**, per controllare che ci sia almeno un TD che utilizzi quest'header */
|
|
483
|
+
this._referenced = false;
|
|
406
484
|
}
|
|
407
485
|
/**
|
|
408
486
|
* Imposta la visibilità o meno della colonna, si traduce nell'applicazione o rimozione della classe **app-display-none**
|
|
@@ -426,9 +504,7 @@ class EsTh {
|
|
|
426
504
|
this._Visible = true;
|
|
427
505
|
return this._Visible;
|
|
428
506
|
}
|
|
429
|
-
/**
|
|
430
|
-
* @ignore
|
|
431
|
-
*/
|
|
507
|
+
/** @ignore */
|
|
432
508
|
ngAfterViewInit() {
|
|
433
509
|
//Assegnare direttamente il content è più veloce che passare dal native element per qualche motivo
|
|
434
510
|
this.Description = this.Display === null || this.Display === "" ? this.content.nativeElement.innerText : this.Display;
|
|
@@ -437,9 +513,7 @@ class EsTh {
|
|
|
437
513
|
if (this.Resizable)
|
|
438
514
|
this.renderer.addClass(this.myself.nativeElement, "app-relative");
|
|
439
515
|
}
|
|
440
|
-
/**
|
|
441
|
-
* Gestisce la modifica dell'ordinamento qualora venisse cliccato su questa colonna
|
|
442
|
-
*/
|
|
516
|
+
/** Gestisce la modifica dell'ordinamento qualora venisse cliccato su questa colonna */
|
|
443
517
|
setupNextOrderAndNotify() {
|
|
444
518
|
if (!this.ID) {
|
|
445
519
|
console.log("Attempt to order a column without ID. Operation ignored");
|
|
@@ -466,9 +540,7 @@ class EsTh {
|
|
|
466
540
|
this.resizingThis = true;
|
|
467
541
|
this.startOffset = this.myself.nativeElement.offsetWidth - ev.pageX;
|
|
468
542
|
}
|
|
469
|
-
/**
|
|
470
|
-
* Listener per la fine dell'operazione di resize
|
|
471
|
-
*/
|
|
543
|
+
/** Listener per la fine dell'operazione di resize */
|
|
472
544
|
onMouseUp() {
|
|
473
545
|
if (!this.Resizable)
|
|
474
546
|
return;
|
|
@@ -518,9 +590,7 @@ EsTh.propDecorators = {
|
|
|
518
590
|
onMouseMove: [{ type: HostListener, args: ['window:mousemove.out-zone', ['$event'],] }]
|
|
519
591
|
};
|
|
520
592
|
|
|
521
|
-
/**
|
|
522
|
-
* Direttiva per la dichiarazione snella di un EsTd da emettere per ogni elemento, data una colonna
|
|
523
|
-
*/
|
|
593
|
+
/** Direttiva per la dichiarazione snella di un EsTd da emettere per ogni elemento, data una colonna */
|
|
524
594
|
class EsTdDirective {
|
|
525
595
|
/**
|
|
526
596
|
* @ignore
|
|
@@ -548,23 +618,31 @@ EsTdDirective.propDecorators = {
|
|
|
548
618
|
tdClass: [{ type: Input }]
|
|
549
619
|
};
|
|
550
620
|
|
|
551
|
-
/**
|
|
552
|
-
* Direttiva per la dichiarazione snella di un EsTh da emettere come header
|
|
553
|
-
*/
|
|
621
|
+
/** Direttiva per la dichiarazione snella di un EsTh da emettere come header */
|
|
554
622
|
class EsThDirective {
|
|
555
623
|
/**
|
|
556
624
|
* @ignore
|
|
557
625
|
*/
|
|
558
626
|
constructor(Template) {
|
|
559
627
|
this.Template = Template;
|
|
628
|
+
/** Variabile interna all'interno della quale viene raccolta la cache delle aggregazioni specificate in thAggregation */
|
|
629
|
+
this._thAggregations = null;
|
|
560
630
|
/** Variabile interna che indica il fatto che questo componente è una direttiva. Serve per disambigualrlo dell'EsThComponent */
|
|
561
631
|
this._directive = true;
|
|
632
|
+
/** Variabile interna impostata dall'**EsTable**, per controllare che ci sia almeno un TD che utilizzi quest'header */
|
|
633
|
+
this._referenced = false;
|
|
562
634
|
/** Id della colonna, dev'essere lo stesso per tutti i **td** relativi */
|
|
563
635
|
this.th = "";
|
|
636
|
+
/** Indica se la colonna è pinnata o no */
|
|
637
|
+
this.thPinned = false;
|
|
638
|
+
/** Indica le dimensioni che deve avere questa colonna quando viene pinnata, senza questo tutte le colonne mi collasserebbero l'una sull'altra */
|
|
639
|
+
this.thPinnedWidth = 150;
|
|
564
640
|
/** Indicazione sulla visibilità della colonna */
|
|
565
641
|
this.thVisible = true;
|
|
566
642
|
/** Indica se la colonna è fixed, cioè se non può né essere nascosta, né riposizionata. Solo le prime colonne possono essere Fixed */
|
|
567
643
|
this.thFixed = false;
|
|
644
|
+
/** Indica che la colonna è sotto ad un raggruppamento padre, con questo nome nel **th** */
|
|
645
|
+
this.thParent = "";
|
|
568
646
|
/** Indica se questa colonna è ordinabile o meno */
|
|
569
647
|
this.thOrderable = true;
|
|
570
648
|
/** Indica se il testo presente in questo Header può andare a capo o meno, di default non può */
|
|
@@ -573,8 +651,10 @@ class EsThDirective {
|
|
|
573
651
|
this.thResizable = false;
|
|
574
652
|
/** Equivalente dell'NgIf sul th */
|
|
575
653
|
this.thIf = true;
|
|
576
|
-
/**
|
|
577
|
-
this.
|
|
654
|
+
/** Indica che bisogna fare un raggruppamento su questa colonna */
|
|
655
|
+
this.thGroup = false;
|
|
656
|
+
/** Indica che bisogna fare una aggregazione su questa colonna, a fronte di almeno un altra con un raggruppamento */
|
|
657
|
+
this.thAggregation = null;
|
|
578
658
|
}
|
|
579
659
|
}
|
|
580
660
|
EsThDirective.decorators = [
|
|
@@ -585,30 +665,37 @@ EsThDirective.ctorParameters = () => [
|
|
|
585
665
|
];
|
|
586
666
|
EsThDirective.propDecorators = {
|
|
587
667
|
th: [{ type: Input }],
|
|
668
|
+
thPinned: [{ type: Input }],
|
|
669
|
+
thPinnedWidth: [{ type: Input }],
|
|
588
670
|
thVisible: [{ type: Input }],
|
|
589
671
|
thFixed: [{ type: Input }],
|
|
672
|
+
thParent: [{ type: Input }],
|
|
590
673
|
thOrder: [{ type: Input }],
|
|
591
674
|
thOrderable: [{ type: Input }],
|
|
592
675
|
thWrap: [{ type: Input }],
|
|
593
676
|
thResizable: [{ type: Input }],
|
|
594
677
|
thClass: [{ type: Input }],
|
|
595
|
-
|
|
678
|
+
thGroupClass: [{ type: Input }],
|
|
679
|
+
thIf: [{ type: Input }],
|
|
680
|
+
thGroup: [{ type: Input }],
|
|
681
|
+
thAggregation: [{ type: Input }]
|
|
596
682
|
};
|
|
597
683
|
|
|
598
|
-
/**
|
|
599
|
-
|
|
600
|
-
*/
|
|
601
|
-
const
|
|
684
|
+
/** Token che indica il locale da utilizzare all'interno del componente. Supportati solo "it-IT" ed "en-US" */
|
|
685
|
+
const EST_LOCALE = new InjectionToken('EST_LOCALE');
|
|
686
|
+
/** Token che indica se emettere log a console o meno */
|
|
687
|
+
const EST_DEBUG = new InjectionToken('EST_DEBUG');
|
|
688
|
+
/** Token che indica i default da assegnare agli Input */
|
|
689
|
+
const EST_DEFAULTS = new InjectionToken('EST_DEFAULTS');
|
|
602
690
|
|
|
603
|
-
/**
|
|
604
|
-
* Classe di localizzazione per il componente **EsTableComponent**
|
|
605
|
-
*/
|
|
691
|
+
/** Classe di localizzazione per il componente **EsTableComponent** */
|
|
606
692
|
class EsTableLoc extends LocalizationService {
|
|
607
|
-
/**
|
|
608
|
-
* @ignore
|
|
609
|
-
*/
|
|
693
|
+
/** @ignore */
|
|
610
694
|
constructor(LOC_LOCALE) {
|
|
611
695
|
super(LOC_LOCALE !== null && LOC_LOCALE !== void 0 ? LOC_LOCALE : 'it-IT');
|
|
696
|
+
super.set("en->it", "All", ["Tutto"]);
|
|
697
|
+
super.set("en->it", "Groups", ["Gruppi"]);
|
|
698
|
+
super.set("en->it", "Cannot export an empty dataset", ["Impossibile esportare un dataset vuoto"]);
|
|
612
699
|
super.set("en->it", "Performing Table bootstrap", ["Sto caricando la Tabella"]);
|
|
613
700
|
super.set("en->it", "Update every", ["Aggiorna ogni"]);
|
|
614
701
|
super.set("en->it", "second/s", ["secondo/i"]);
|
|
@@ -633,25 +720,31 @@ EsTableLoc.ctorParameters = () => [
|
|
|
633
720
|
{ type: String, decorators: [{ type: Optional }, { type: Inject, args: [EST_LOCALE,] }] }
|
|
634
721
|
];
|
|
635
722
|
|
|
723
|
+
/** Raccolta di tutti gli Input dell'EsTable a cui può essere logicamente sensato assegnare default per progetto */
|
|
724
|
+
class EsTableDefaultable {
|
|
725
|
+
}
|
|
726
|
+
|
|
636
727
|
/** Componente che permette di rappresentare una griglia di valori */
|
|
637
728
|
class EsTableComponent {
|
|
638
729
|
/** @ignore */
|
|
639
|
-
constructor(ngControl, prefService, lc, cdr, hashExts, utiExts, expExts) {
|
|
730
|
+
constructor(ngControl, prefService, deafults, locale, lc, cdr, hashExts, utiExts, expExts, dateExts, msgExts) {
|
|
731
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
640
732
|
this.ngControl = ngControl;
|
|
641
733
|
this.prefService = prefService;
|
|
734
|
+
this.deafults = deafults;
|
|
735
|
+
this.locale = locale;
|
|
642
736
|
this.lc = lc;
|
|
643
737
|
this.cdr = cdr;
|
|
644
738
|
this.hashExts = hashExts;
|
|
645
739
|
this.utiExts = utiExts;
|
|
646
740
|
this.expExts = expExts;
|
|
741
|
+
this.dateExts = dateExts;
|
|
742
|
+
this.msgExts = msgExts;
|
|
647
743
|
/** View finale su cui bindarsi lato Frontend, il tipo può essere IAppSearch<any> (per la **viewMode**), any[] (per l'**arrayMode**) e ReportDefinition per la **reportMode** */
|
|
648
744
|
this.View = null;
|
|
649
745
|
/** Indica se l'es-table deve mostrare il check globale nell'header per fare il "seleziona tutto" */
|
|
650
746
|
this.globalCheck = false;
|
|
651
|
-
/**
|
|
652
|
-
* Tiene da conto l'ultimo elemento selezionato in modo da fare ragionamenti del tipo
|
|
653
|
-
* "Ho selezionato questo, l'ultimo selezionato era **lastSelected**, devo selezionare tutti quelli in mezzo", ad esempio per la selezione multipla
|
|
654
|
-
*/
|
|
747
|
+
/** Tiene da conto l'ultimo elemento selezionato in modo da poter effettuare il SHIFT+CLICK */
|
|
655
748
|
this.lastSelected = null;
|
|
656
749
|
/** Conteggio interno per il numero di elementi selezionati */
|
|
657
750
|
this.selectedObjects = 0;
|
|
@@ -690,6 +783,10 @@ class EsTableComponent {
|
|
|
690
783
|
this.RowTHs = null;
|
|
691
784
|
/** Modello di appoggio temporaneo per i **RowTHs** */
|
|
692
785
|
this.TMPRowTHs = null;
|
|
786
|
+
/** Modello di appoggio temporaneo per i **RowThGroups** */
|
|
787
|
+
this.TMPRowThGroups = null;
|
|
788
|
+
/** Modello rappresentante un singolo header group della tabella. Questa lista è già ordinata e pronta per essere utilizzata in ngFor */
|
|
789
|
+
this.RowThGroups = null;
|
|
693
790
|
/** Cache per i routerLink generati nelle tabelle dinamiche */
|
|
694
791
|
this.DynamicTableRouterLinkCache = {};
|
|
695
792
|
/**
|
|
@@ -736,7 +833,11 @@ class EsTableComponent {
|
|
|
736
833
|
* @deprecated Utilizzare l'Input **Template** delle es-td e assegnare un template con tutti i binding che si vuole ai click
|
|
737
834
|
*/
|
|
738
835
|
this.CustomCellActionsOn = '';
|
|
739
|
-
/**
|
|
836
|
+
/**
|
|
837
|
+
* Serve per decidere di lanciare o meno il **event.stopPropagation()** al termine della gestione dell'evento
|
|
838
|
+
*
|
|
839
|
+
* @deprecated Utilizzare l'Input **Template** delle es-td e assegnare un template con tutti i binding che si vuole ai click
|
|
840
|
+
*/
|
|
740
841
|
this.CellActionPropagates = true;
|
|
741
842
|
/**
|
|
742
843
|
* Decide se utilizzare o meno le CustomCells. Impostandolo a **true** l'es-table diventa in grado di gestire nativamente:
|
|
@@ -752,14 +853,14 @@ class EsTableComponent {
|
|
|
752
853
|
this.UseCustomCells = null;
|
|
753
854
|
/** Permette di impostare l'altezza massima della tabella. Se null la dimensione si adatta al numero di elementi attualmente in visualizzazione */
|
|
754
855
|
this.MaxHeight = null;
|
|
755
|
-
/** Classi da applicare
|
|
756
|
-
this.
|
|
856
|
+
/** Classi da applicare al contenitore della tabella */
|
|
857
|
+
this.ContainerClass = null;
|
|
757
858
|
/** Permette o meno l'export in formato XLSX */
|
|
758
859
|
this.XLSXExport = null;
|
|
759
860
|
/** Permette o meno l'export in formato CSV */
|
|
760
861
|
this.CSVExport = true;
|
|
761
862
|
/** Permette di visualizzare o meno l'opzione di paginazione "Tutti" */
|
|
762
|
-
this.AllSearch =
|
|
863
|
+
this.AllSearch = null;
|
|
763
864
|
/** Diminuisce gli spazi fra una cella e l'altra, e internamente il padding del font in modo da presentare molti più dati in un'unica pagina */
|
|
764
865
|
this.HighCellDensity = null;
|
|
765
866
|
/** Abilita o meno la possibilità di selezionare oggetti */
|
|
@@ -778,8 +879,6 @@ class EsTableComponent {
|
|
|
778
879
|
this.Export = null;
|
|
779
880
|
/** Indica se permettere la selezione multipla Windows-like cliccando un oggetto e facendo poi Shift + click su un oggetto successivo */
|
|
780
881
|
this.ShiftClick = null;
|
|
781
|
-
/** Mostra o nasconde le informazioni di paginazione, sia i pulsanti, sia il selettore degli oggetti per pagina */
|
|
782
|
-
this.ShowPaging = true;
|
|
783
882
|
/** Indica se nascondere o mostrare il componente di paginazione */
|
|
784
883
|
this.HidePaging = null;
|
|
785
884
|
/** Indica se nascondere o mostrare il conteggio degli elementi trovati */
|
|
@@ -791,12 +890,10 @@ class EsTableComponent {
|
|
|
791
890
|
/** Nome dell'esportazione generata da questa tabella */
|
|
792
891
|
this.ExportFileName = 'Export.csv';
|
|
793
892
|
/** Classe (HTML) di default della tabella */
|
|
794
|
-
this.TableClass =
|
|
795
|
-
/**
|
|
796
|
-
this.CountLabel = this.lc.loc('Found objects');
|
|
797
|
-
/** Indica la presenza di raggruppamenti a livello di header */
|
|
893
|
+
this.TableClass = null;
|
|
894
|
+
/** @deprecated Indica la presenza di raggruppamenti a livello di header */
|
|
798
895
|
this.HasHeaderGroup = null;
|
|
799
|
-
/** Indica la presenza di raggruppamenti a livello del raggruppamento precedentemente esistente, chiaramente è insensata senza **HasHeaderGroup** */
|
|
896
|
+
/** @deprecated Indica la presenza di raggruppamenti a livello del raggruppamento precedentemente esistente, chiaramente è insensata senza **HasHeaderGroup** */
|
|
800
897
|
this.HasSecondaryHeaderGroup = null;
|
|
801
898
|
/** Utilizzato per dividere la sorgente in modalità EndlessScroll */
|
|
802
899
|
this.SliceSize = 100;
|
|
@@ -828,11 +925,7 @@ class EsTableComponent {
|
|
|
828
925
|
this.HiddenColumns = null;
|
|
829
926
|
/** Permette di riordinare le colonne in base alle impostazioni effettuate dal Menù contestuale in alto a destra */
|
|
830
927
|
this.ColumnsOrdering = null;
|
|
831
|
-
/**
|
|
832
|
-
* Eventuale supporto alle ricerche applicate alla modalità Array
|
|
833
|
-
*
|
|
834
|
-
* @deprecated Utilizzato solo per un caso particolare del Metering
|
|
835
|
-
*/
|
|
928
|
+
/** Eventuale supporto alle ricerche applicate alla modalità Array */
|
|
836
929
|
this.SearchView = null;
|
|
837
930
|
/** Abilita o disabilita il sistema che permette di selezionare tutti gli elementi nella vista */
|
|
838
931
|
this.SelectAll = null;
|
|
@@ -852,6 +945,10 @@ class EsTableComponent {
|
|
|
852
945
|
this.StartsExpanded = true;
|
|
853
946
|
/** Indica se effettuare il salvataggio delle preferenze di ricerca */
|
|
854
947
|
this.SavePreferences = null;
|
|
948
|
+
/** Indica dove visualizzare le informazioni di paginazione, se sopra, sotto o in entrambi */
|
|
949
|
+
this.PagingStyle = null;
|
|
950
|
+
/** Indica dove visualizzare le informazioni di paginazione, se sopra, sotto o in entrambi */
|
|
951
|
+
this.RowGroupingPagingStyle = null;
|
|
855
952
|
/**
|
|
856
953
|
* Sorgente dati secondaria
|
|
857
954
|
*
|
|
@@ -865,12 +962,19 @@ class EsTableComponent {
|
|
|
865
962
|
*/
|
|
866
963
|
this.TertiarySource = null;
|
|
867
964
|
/** Indica se utilizzare la cache di selezione che permette di mantenere gli stati di selezione dei vari oggetti navigando da una pagina all'altra */
|
|
868
|
-
this.UseSelectionCache =
|
|
965
|
+
this.UseSelectionCache = null;
|
|
966
|
+
/** Permette di decidere se, in modalità raggruppamento, mostrare o meno il valore delle colonne di gruppo negli oggetti finali. Di default sono nascosti */
|
|
967
|
+
this.ShowItemGroupsColumns = null;
|
|
869
968
|
/** Evento che viene richiamato al cambio di oridnamento di una colonna */
|
|
870
969
|
this.onOrderChanged = new EventEmitter();
|
|
871
970
|
/**
|
|
872
971
|
* Evento che viene richiamato quando l'es-table ritiene sia necessario ri-effettuare la ricerca.
|
|
873
|
-
* Il booleano dell'evento indica se viene suggerito di resettare la pagina o meno
|
|
972
|
+
* Il booleano dell'evento indica se viene suggerito di resettare la pagina o meno.
|
|
973
|
+
*
|
|
974
|
+
* Solo in caso venga utilizzata la modalità a raggruppamenti di righe può succedere che l'es-table passi un intero AppSearch come parametro di ricerca,
|
|
975
|
+
* in quel caso l'applicazione ricevente dovrà onorare la richiesta spedendo al backand l'oggetto di ricerca AS-IS
|
|
976
|
+
*
|
|
977
|
+
* il tipo dell'Emitter invece di essere [boolean | AppSearch<any>] è stato impostato a "any" per evitare problemi di retrocompatibilità
|
|
874
978
|
*/
|
|
875
979
|
this.onSearchRequest = new EventEmitter();
|
|
876
980
|
/** Evento che parte ad ogni modifica di "checkaggio" in forma di comodo array. Espone l'oggetto con lo stato di check attuale */
|
|
@@ -893,19 +997,91 @@ class EsTableComponent {
|
|
|
893
997
|
/** Numero di pagine (durante la paginazione in modalità Array) */
|
|
894
998
|
this.arraymodePages = 1;
|
|
895
999
|
/** Oggetti per ogni pagina (durante la paginazione in modalità Array) */
|
|
896
|
-
this.ArraymodeItemsPerPage =
|
|
1000
|
+
this.ArraymodeItemsPerPage = null;
|
|
1001
|
+
/** Colonne da visualizzare in modalità array */
|
|
1002
|
+
this.arrayColumns = [];
|
|
1003
|
+
/** Ordine delle colonne da visualizzare in modalità array */
|
|
1004
|
+
this.arrayColumnOrdering = [];
|
|
1005
|
+
/** Ordinamenti ASC-DESC sulle colonne in modalità array */
|
|
1006
|
+
this.arrayOrders = [];
|
|
897
1007
|
/**
|
|
898
1008
|
* Variabile che serve a gestire il momento in cui l'es-table aggiorna la paginazione (pulsanti ecc).
|
|
899
1009
|
* Essendo operazioni comunque costose le effettuo solo su binding esterni, non su rewrite generati internamente
|
|
900
1010
|
*/
|
|
901
1011
|
this.internalWriteCall = false;
|
|
902
|
-
/**
|
|
903
|
-
|
|
1012
|
+
/**
|
|
1013
|
+
* Cache che conterrà tutte le ricerche effettuate su gruppi diversi dal primo e su elementi contenuti nei gruppi.
|
|
1014
|
+
* In caso di cambi di ordinamento delle colonne diverse dalla prima tutte le chiamate fatte dal secondo livello in poi devono essere rieseguite secondo la seguente logica:
|
|
1015
|
+
*
|
|
1016
|
+
*
|
|
1017
|
+
* **Cambio ordinamento sul primo gruppo**: reload completo, non mi occupo di ripulire gli elementi bindati in alcun modo
|
|
1018
|
+
*
|
|
1019
|
+
* **Cambio ordinamento sulla colonna relativa all'N-esimo gruppo**: reload completo del contenuto dei gruppi precedenti, ripulendo precedentemente
|
|
1020
|
+
* tutti gli elementi con **_grouplevel** = N
|
|
1021
|
+
*
|
|
1022
|
+
* **Cambio ordinamento su una colonna non raggruppata**: reload completo per tutti i gruppi finali aperti, devo precedentemente ripulire tutti gli elementi con **_item** = true
|
|
1023
|
+
*
|
|
1024
|
+
* Altri eventi non dovrebbero rappresentare problemi:
|
|
1025
|
+
* - Selezione: non cambia nulla
|
|
1026
|
+
* - Paginazione: cambia a livello root quindi viene ricaricato tutto comunque, stesso vale per le paginazioni interne
|
|
1027
|
+
*/
|
|
1028
|
+
this.groupSearchRequestsCache = [];
|
|
1029
|
+
/** Variabile d'appoggio per capire se c'è bisogno di ri-effettuare una ricerca o meno */
|
|
1030
|
+
this.ResearchNeeded = false;
|
|
1031
|
+
/** Colonne visibili della vista attuale. Valorizzato di default al numero massimo di colonne supportate dalla tabella per le casistiche in assenza di custom cells */
|
|
1032
|
+
this.Columns = { Visibile: 100, VisibleUnpinned: 100, Global: 100 };
|
|
1033
|
+
/** In caso di Row Grouping qui viene salvata la vista principale dei gruppi base */
|
|
1034
|
+
this.MainGroupView = null;
|
|
1035
|
+
/** Conteggio base degli oggetti. In modalità normale viene resettato ad ogni nuova View inserita, in modalità RowGrouping viene resettato solo ad una nuova View di livello "0" */
|
|
1036
|
+
this.BaseItemsCount = null;
|
|
1037
|
+
/** Cache per salvare per ogni chiave di ogni gruppo chi è il gruppo rappresentato */
|
|
1038
|
+
this.rgGroupCache = new Map();
|
|
1039
|
+
/** Cache per salvare per ogni chiave di ogni gruppo chi sono gli oggetti sottostanti, non dei sottogruppi */
|
|
1040
|
+
this.rgItemCache = new Map();
|
|
1041
|
+
/** Cache per salvare per ogni chiave di ogni gruppo chi sono gli oggetti sottostanti, non dei sottogruppi */
|
|
1042
|
+
this.rgChildGroupsCache = new Map();
|
|
1043
|
+
/** Cache di selezione Hash - Oggetto per la variabile **items** dell'itemSelector. Facilita le operazioni di lookup via hash*/
|
|
1044
|
+
this.itemsCache = new Map();
|
|
1045
|
+
/** Cache di selezione Hash - Oggetto per la variabile **groups** dell'itemSelector. Facilita le operazioni di lookup via hash */
|
|
1046
|
+
this.groupsCache = new Map();
|
|
1047
|
+
/** Cache di selezione Hash - Oggetto per la variabile **exclusions** dell'itemSelector. Facilita le operazioni di lookup via hash */
|
|
1048
|
+
this.exclusionsCache = new Map();
|
|
1049
|
+
/** Cache di selezione Hash - Oggetto per la variabile **group_exclusions** dell'itemSelector. Facilita le operazioni di lookup via hash */
|
|
1050
|
+
this.group_exclusionsCache = new Map();
|
|
1051
|
+
/** Cache di selezione Hash - Oggetto per la variabile **items** dell'itemSelector. Facilita le operazioni di lookup via indice*/
|
|
1052
|
+
this.i_itemsCache = new Map();
|
|
1053
|
+
/** Cache di selezione Hash - Oggetto per la variabile **groups** dell'itemSelector. Facilita le operazioni di lookup via indice */
|
|
1054
|
+
this.i_groupsCache = new Map();
|
|
1055
|
+
/** Cache di selezione Hash - Oggetto per la variabile **exclusions** dell'itemSelector. Facilita le operazioni di lookup via indice */
|
|
1056
|
+
this.i_exclusionsCache = new Map();
|
|
1057
|
+
/** Cache di selezione Hash - Oggetto per la variabile **group_exclusions** dell'itemSelector. Facilita le operazioni di lookup via indice */
|
|
1058
|
+
this.i_group_exclusionsCache = new Map();
|
|
1059
|
+
/** Indica se nonostante siamo in modalità array sono stati individuati dei gruppi. In tal caso es-table si comporta da pseudo backend ed effettua le aggregazioni e raggruppamenti completamente lato client */
|
|
1060
|
+
this.ArrayGrouping = false;
|
|
1061
|
+
this.PagerOptions = { PagerCount: null, ShowCount: true, ShowPaging: true, UsesView: true, View: null, Ready: false, Searches: 'items' };
|
|
904
1062
|
/** @ignore */
|
|
905
1063
|
this.propagateChange = (_) => { };
|
|
906
1064
|
if (ngControl)
|
|
907
1065
|
ngControl.valueAccessor = this;
|
|
1066
|
+
// Assegnazione per tutti gli Input di default
|
|
1067
|
+
this.ColumnsResizable = this.InputOrDefault(this.ColumnsResizable, (_a = this.deafults) === null || _a === void 0 ? void 0 : _a.ColumnsResizable);
|
|
1068
|
+
this.AutoUpdate = this.InputOrDefault(this.AutoUpdate, (_b = this.deafults) === null || _b === void 0 ? void 0 : _b.AutoUpdate);
|
|
1069
|
+
this.AllSearch = this.InputOrDefault(this.AllSearch, (_c = this.deafults) === null || _c === void 0 ? void 0 : _c.AllSearch, true);
|
|
1070
|
+
this.Export = this.InputOrDefault(this.Export, (_d = this.deafults) === null || _d === void 0 ? void 0 : _d.Export);
|
|
1071
|
+
this.HidePaging = this.InputOrDefault(this.HidePaging, (_e = this.deafults) === null || _e === void 0 ? void 0 : _e.HidePaging, false);
|
|
1072
|
+
this.HidePagingCount = this.InputOrDefault(this.HidePagingCount, (_f = this.deafults) === null || _f === void 0 ? void 0 : _f.HidePagingCount);
|
|
1073
|
+
this.HidePagingButtons = this.InputOrDefault(this.HidePagingButtons, (_g = this.deafults) === null || _g === void 0 ? void 0 : _g.HidePagingButtons);
|
|
1074
|
+
this.ContainerClass = this.InputOrDefault(this.ContainerClass, (_h = this.deafults) === null || _h === void 0 ? void 0 : _h.ContainerClass, '');
|
|
1075
|
+
this.TableClass = this.InputOrDefault(this.TableClass, (_j = this.deafults) === null || _j === void 0 ? void 0 : _j.TableClass, 'table table-striped table-hover table-sm');
|
|
1076
|
+
this.Selection = this.InputOrDefault(this.Selection, (_k = this.deafults) === null || _k === void 0 ? void 0 : _k.Selection);
|
|
1077
|
+
this.SavePreferences = this.InputOrDefault(this.SavePreferences, (_l = this.deafults) === null || _l === void 0 ? void 0 : _l.SavePreferences);
|
|
1078
|
+
this.PagingStyle = this.InputOrDefault(this.PagingStyle, (_m = this.deafults) === null || _m === void 0 ? void 0 : _m.PagingStyle, 'bottom');
|
|
1079
|
+
this.RowGroupingPagingStyle = this.InputOrDefault(this.RowGroupingPagingStyle, (_o = this.deafults) === null || _o === void 0 ? void 0 : _o.RowGroupingPagingStyle, 'left');
|
|
1080
|
+
this.UseSelectionCache = this.InputOrDefault(this.UseSelectionCache, (_p = this.deafults) === null || _p === void 0 ? void 0 : _p.UseSelectionCache, true);
|
|
1081
|
+
this.ShowItemGroupsColumns = this.InputOrDefault(this.ShowItemGroupsColumns, (_q = this.deafults) === null || _q === void 0 ? void 0 : _q.ShowItemGroupsColumns, false);
|
|
1082
|
+
this.ArraymodeItemsPerPage = this.InputOrDefault(this.ArraymodeItemsPerPage, (_r = this.deafults) === null || _r === void 0 ? void 0 : _r.ArraymodeItemsPerPage, 15);
|
|
908
1083
|
}
|
|
1084
|
+
// #region Ciclo di vita ES-Table - Inizializzazioni
|
|
909
1085
|
/** @ignore */
|
|
910
1086
|
ngOnInit() {
|
|
911
1087
|
//Per poter cambiare il layout in base al livello gerarchico il componente deva avere il pieno controllo di ogni cella,
|
|
@@ -914,6 +1090,9 @@ class EsTableComponent {
|
|
|
914
1090
|
throw "Es-table error: Per poter utilizzare l'es-table con [Hierarchy]=\"true\" è richiesto anche [UseCustomCells]=\"true\"";
|
|
915
1091
|
// click destro su una riga con selezione attiva: Tiro fuori il context menu e selezione l'elemento corrente
|
|
916
1092
|
this.ctxMenuSubscription = (this.ContextMenu || this.tableEmptyMenu).open.subscribe(t => {
|
|
1093
|
+
// Gruppi va bene, oggetti pure, ma separatori fra gruppi proprio no...
|
|
1094
|
+
if (t.item._sep)
|
|
1095
|
+
return;
|
|
917
1096
|
let shouldEmit = !t.item._selected;
|
|
918
1097
|
t.item._selected = true;
|
|
919
1098
|
var itemSelection = this.handleItemsSelection([t.item]);
|
|
@@ -941,6 +1120,26 @@ class EsTableComponent {
|
|
|
941
1120
|
this.ShiftClick = true;
|
|
942
1121
|
}
|
|
943
1122
|
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Se l'Input è null (valore non settato) vede se c'è un default con cui valorizzarlo. Se non c'è utilizza il valore di fallback (qualora fornito)
|
|
1125
|
+
*
|
|
1126
|
+
* @param {T} inputValue Valore dell'Input
|
|
1127
|
+
* @param {T} defaultValue Valore di default impostato da configurazione
|
|
1128
|
+
* @param {T} fallbackValue Valore dell'Input per quando non è stato assegnato dal programmatore e non ha un default
|
|
1129
|
+
*/
|
|
1130
|
+
InputOrDefault(inputValue, defaultValue, fallbackValue) {
|
|
1131
|
+
// Input valorizzato dal programmatore
|
|
1132
|
+
if (inputValue != null && inputValue != undefined)
|
|
1133
|
+
return inputValue;
|
|
1134
|
+
// Input valorizzato da configurazione globale
|
|
1135
|
+
if (defaultValue != null && defaultValue != undefined)
|
|
1136
|
+
return defaultValue;
|
|
1137
|
+
//Input non valorizzato da niente e da nessuno
|
|
1138
|
+
if (fallbackValue != null && fallbackValue != undefined)
|
|
1139
|
+
return fallbackValue;
|
|
1140
|
+
// I casi in cui si arriva qui sono i casi di Input che di default va bene che siano nulli e che nessuno si caga
|
|
1141
|
+
return null;
|
|
1142
|
+
}
|
|
944
1143
|
/** @ignore */
|
|
945
1144
|
ngOnDestroy() {
|
|
946
1145
|
if (this.ctxMenuSubscription)
|
|
@@ -954,6 +1153,7 @@ class EsTableComponent {
|
|
|
954
1153
|
this.arrayPulsanti = this.getPagesArray(6, this.SearchView.page, this.SearchView.pages || 1);
|
|
955
1154
|
});
|
|
956
1155
|
}
|
|
1156
|
+
// #endregion
|
|
957
1157
|
// #region Implementazione ControlValueAccessor ignorabile
|
|
958
1158
|
/** @ignore */
|
|
959
1159
|
registerOnChange(fn) { this.propagateChange = fn; }
|
|
@@ -964,6 +1164,7 @@ class EsTableComponent {
|
|
|
964
1164
|
// #endregion
|
|
965
1165
|
/** @ignore */
|
|
966
1166
|
writeValue(obj) {
|
|
1167
|
+
var _a;
|
|
967
1168
|
this.View = obj ? obj : null;
|
|
968
1169
|
// Mi è arrivata l'AppSearch quindi di sicuro non ho una ricerca in progress
|
|
969
1170
|
this.researchInProgress = false;
|
|
@@ -996,10 +1197,11 @@ class EsTableComponent {
|
|
|
996
1197
|
else if (this.View && this.View instanceof AppSearch) {
|
|
997
1198
|
// Se cambia l'oggetto intero significa che ho rimandato la ricerca
|
|
998
1199
|
this.setMode('view');
|
|
1200
|
+
let firstItemGroupOrNoGrouping = (((_a = this.View.requestedgroups) === null || _a === void 0 ? void 0 : _a.length) || 0) == 0;
|
|
999
1201
|
// Se vengo da una ricerca interna mantengo lo stato di selezione precedente (quindi su cambio pagina, cambio ipp, ecc...)
|
|
1000
1202
|
// se invece l'utente ha fatto una ricerca lui (quindi cambiando filtri), secco le info di selezione
|
|
1001
|
-
if (!this.View.selection || !this.View.internalsearchrequest || !this.UseSelectionCache) {
|
|
1002
|
-
this.
|
|
1203
|
+
if (!this.View.selection || (!this.View.internalsearchrequest && firstItemGroupOrNoGrouping) || !this.UseSelectionCache) {
|
|
1204
|
+
this.clearSelectionCaches();
|
|
1003
1205
|
this.View.selection = new ItemsSelection([]);
|
|
1004
1206
|
this.onSelectionChanged.emit(this.View.selection);
|
|
1005
1207
|
}
|
|
@@ -1018,55 +1220,136 @@ class EsTableComponent {
|
|
|
1018
1220
|
}
|
|
1019
1221
|
}
|
|
1020
1222
|
}
|
|
1021
|
-
|
|
1223
|
+
// La paginazione devo farla solamente quando richiedo o un gruppo principale (se sono in row grouping) o se non richiedo gruppi (in tutti lgi altri casi)
|
|
1224
|
+
if (firstItemGroupOrNoGrouping)
|
|
1225
|
+
this.arrayPulsanti = this.getPagesArray(6, this.View.page, this.View.pages || 1);
|
|
1022
1226
|
}
|
|
1023
1227
|
else if (this.View && (this.View.length != null && this.View.length != undefined)) {
|
|
1024
1228
|
this.setMode('array');
|
|
1025
1229
|
if (!this.UseSelectionCache || !this.arraymodeSelection) {
|
|
1026
|
-
this.
|
|
1230
|
+
this.clearSelectionCaches();
|
|
1027
1231
|
this.arraymodeSelection = new ItemsSelection([]);
|
|
1028
1232
|
;
|
|
1029
1233
|
this.onSelectionChanged.emit(this.arraymodeSelection);
|
|
1030
1234
|
}
|
|
1235
|
+
// Recupero Preference
|
|
1236
|
+
if (this.SavePreferences) {
|
|
1237
|
+
if (!this.ngControl.name)
|
|
1238
|
+
console.error("Non posso utilizzare le preference senza avere un 'name' per questa tabella");
|
|
1239
|
+
else if (!this.prefService)
|
|
1240
|
+
console.error("Non posso utilizzare le preference senza che il pacchetto @esfaenza/preferences sia installato");
|
|
1241
|
+
else {
|
|
1242
|
+
var prefs = this.prefService.retrieve(this.ngControl.name);
|
|
1243
|
+
if (prefs) {
|
|
1244
|
+
this.arrayColumns = prefs.columns;
|
|
1245
|
+
this.arrayColumnOrdering = prefs.column_ordering;
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1031
1249
|
if (this.SearchView)
|
|
1032
1250
|
this.arrayPulsanti = this.getPagesArray(6, this.SearchView.page, this.SearchView.pages || 1);
|
|
1033
1251
|
}
|
|
1034
|
-
if (this.View && !(this.View instanceof ReportDefinition))
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1252
|
+
if (this.View && !(this.View instanceof ReportDefinition))
|
|
1253
|
+
this.finalizeContext();
|
|
1254
|
+
this.postBoundSourceCalculation();
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Successivamente al bind del nuovo input questa funzione si occupa di finalizzare tutti i parametri di funzionamento dell'es-table
|
|
1258
|
+
* in base a Input - Modello, e qualsiasi altra cosa possa servire
|
|
1259
|
+
*/
|
|
1260
|
+
finalizeContext() {
|
|
1261
|
+
let viewCasted = this.View;
|
|
1262
|
+
/*
|
|
1263
|
+
*Uso la tecnica di EndlessScroll se la variabile relativa è attiva e se
|
|
1264
|
+
* 1) Ho un Array, oppure
|
|
1265
|
+
* 2) Ho un AppSearch che sta cercando con paginazione "Tutto", oppure
|
|
1266
|
+
* 3) Ho un AppSearch che sta cercando con paginazione diversa da "Tutto" ma con la variabile EndlessScrollOnlyForAll a false
|
|
1267
|
+
*/
|
|
1268
|
+
let isAppSearchWithIppMax = this.viewMode && viewCasted.itemsperpageoverride == this.defaultAllPageOverride;
|
|
1269
|
+
let isAppSearchNoMaxIpp = this.viewMode && viewCasted.itemsperpageoverride != this.defaultAllPageOverride;
|
|
1270
|
+
this.UseEndlessscroll = this.EndlessScroll && (this.arrayMode || isAppSearchWithIppMax || (isAppSearchNoMaxIpp && !this.EndlessScrollOnlyForAll));
|
|
1271
|
+
let hasRowGroups = (viewCasted.groupings && viewCasted.groupings.filter(t => !t.aggregation).length > 0) || (this.arrayMode && this.EsThsDirective.some(t => t.thGroup));
|
|
1272
|
+
// Se ho dei gruppi in modalità array devo sistemare un po' di variabili che diventano insensate
|
|
1273
|
+
if (this.arrayMode) {
|
|
1274
|
+
if (hasRowGroups)
|
|
1275
|
+
this.UseArrayModePaging = false;
|
|
1276
|
+
}
|
|
1277
|
+
// Riempimento della TMPBoundSource con gli oggetti che verranno poi mostrati ad interfaccia
|
|
1278
|
+
if (this.UseEndlessscroll && !hasRowGroups) {
|
|
1279
|
+
this.addedSlices = [];
|
|
1280
|
+
this.boundSubSources = this.getItemSlices();
|
|
1281
|
+
let firstSub = this.boundSubSources[0];
|
|
1282
|
+
this.TMPBoundSource = firstSub ? firstSub : [];
|
|
1283
|
+
if (firstSub)
|
|
1284
|
+
this.addedSlices.push(0);
|
|
1285
|
+
}
|
|
1286
|
+
else
|
|
1287
|
+
this.TMPBoundSource = this.getItemsByMode(false, !this.internalWriteCall);
|
|
1288
|
+
// Se ho una gerarchia, assegno i livelli gerarchici alla TMPBoundSource
|
|
1289
|
+
if (this.Hierarchy && !hasRowGroups)
|
|
1290
|
+
this.assignHierarchyLevels(this.TMPBoundSource);
|
|
1291
|
+
// L'hashing degli oggetti lo faccio a prescindere
|
|
1292
|
+
this.calculateHash(this.TMPBoundSource);
|
|
1293
|
+
// Assegno a una variabile mia l'eventuale override per la classe della riga
|
|
1294
|
+
// Se poi sono in modalità gerarchica inietto anche la classe per la configurazione del livello della riga
|
|
1295
|
+
if ((this.TMPBoundSource && this.RowClassAssigner) || this.Hierarchy) {
|
|
1296
|
+
for (let i = 0; i < this.TMPBoundSource.length; i++) {
|
|
1297
|
+
let item = this.TMPBoundSource[i];
|
|
1298
|
+
item._rowClass = this.RowClassAssigner ? this.RowClassAssigner(item) : "";
|
|
1299
|
+
item._rowClass += this.Hierarchy ? " est-row-lvl-" + item._level : "";
|
|
1051
1300
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
/** Genera le informzioni di paginazione per la vista globale dell'es-table */
|
|
1304
|
+
setupPagingInformations() {
|
|
1305
|
+
this.PagerOptions.ShowCount = !this.HidePagingCount;
|
|
1306
|
+
if (this.arrayMode && this.UseArrayModePaging && !this.SearchView) {
|
|
1307
|
+
this.PagerOptions.PagerCount = this.View.length || 0;
|
|
1308
|
+
this.PagerOptions.ShowPaging = !this.HidePaging && this.View.length > 10;
|
|
1309
|
+
this.PagerOptions.View = this.View;
|
|
1310
|
+
this.PagerOptions.UsesView = false;
|
|
1311
|
+
}
|
|
1312
|
+
else if (this.arrayMode && (!this.UseArrayModePaging || this.SearchView)) {
|
|
1313
|
+
if (this.SearchView) {
|
|
1314
|
+
this.PagerOptions.View = this.SearchView;
|
|
1315
|
+
this.PagerOptions.PagerCount = this.SearchView.objectcount || 0;
|
|
1065
1316
|
}
|
|
1317
|
+
else
|
|
1318
|
+
this.PagerOptions.PagerCount = this.View.length || 0;
|
|
1319
|
+
this.PagerOptions.ShowCount = this.PagerOptions.ShowCount || (this.View && this.View.length) || (this.SearchView && this.SearchView.objectcount && this.SearchView.objectcount != -1);
|
|
1066
1320
|
}
|
|
1067
|
-
this.
|
|
1321
|
+
else if (this.viewMode) {
|
|
1322
|
+
let tmpView = this.MainGroupView || this.View;
|
|
1323
|
+
let count = (tmpView === null || tmpView === void 0 ? void 0 : tmpView.groupcount) || (tmpView === null || tmpView === void 0 ? void 0 : tmpView.objectcount);
|
|
1324
|
+
this.PagerOptions.Searches = (tmpView === null || tmpView === void 0 ? void 0 : tmpView.groupcount) != null && (tmpView === null || tmpView === void 0 ? void 0 : tmpView.groupcount) != undefined ? 'groups' : 'items';
|
|
1325
|
+
this.PagerOptions.PagerCount = count || 0;
|
|
1326
|
+
this.PagerOptions.View = tmpView;
|
|
1327
|
+
this.PagerOptions.ShowCount = this.PagerOptions.ShowCount || (tmpView && count && count != -1);
|
|
1328
|
+
this.PagerOptions.ShowPaging = !this.HidePaging;
|
|
1329
|
+
}
|
|
1330
|
+
else if (this.reportMode) {
|
|
1331
|
+
let rvc = this.ReportValues.count;
|
|
1332
|
+
this.PagerOptions.View = this.View;
|
|
1333
|
+
this.PagerOptions.PagerCount = rvc && rvc == -1 ? this.ReportValues.rows.length : rvc && rvc > 0 ? this.ReportValues.count : 0;
|
|
1334
|
+
this.PagerOptions.ShowCount = this.PagerOptions.ShowCount || (this.View && this.View.objectcount && this.View.objectcount != -1);
|
|
1335
|
+
this.PagerOptions.ShowPaging = !this.HidePaging && this.View.pagingavailable;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Ripulisce le cache di selezione
|
|
1340
|
+
*
|
|
1341
|
+
* @todo: SELECTION
|
|
1342
|
+
*/
|
|
1343
|
+
clearSelectionCaches() {
|
|
1344
|
+
this.itemsCache.clear();
|
|
1345
|
+
this.groupsCache.clear();
|
|
1346
|
+
this.exclusionsCache.clear();
|
|
1347
|
+
this.group_exclusionsCache.clear();
|
|
1348
|
+
this.i_itemsCache.clear();
|
|
1349
|
+
this.i_groupsCache.clear();
|
|
1350
|
+
this.i_exclusionsCache.clear();
|
|
1351
|
+
this.i_group_exclusionsCache.clear();
|
|
1068
1352
|
}
|
|
1069
|
-
// #region Gestione retrieve degli oggetti da mostrare in tabella, considerando eventuali Endless Scrolls
|
|
1070
1353
|
/**
|
|
1071
1354
|
* In base alla modalità specificata (ArrayMode, ViewMode, ecc...) questo metodo recupera l'array di oggetti da bindare ad interfaccia
|
|
1072
1355
|
*
|
|
@@ -1075,6 +1358,8 @@ class EsTableComponent {
|
|
|
1075
1358
|
* @param {boolean} allIfPossible [false] Indica se prendere tutti gli oggetti quaora possibile, usato solo in ArrayMode
|
|
1076
1359
|
*
|
|
1077
1360
|
* @returns {any[]} Lista degli oggetti su cui effettuare il bind lato interfaccia
|
|
1361
|
+
*
|
|
1362
|
+
* @todo: ITEMS
|
|
1078
1363
|
*/
|
|
1079
1364
|
getItemsByMode(onlyselected = false, refreshPaging = false, allIfPossible = false) {
|
|
1080
1365
|
let items = [];
|
|
@@ -1082,6 +1367,8 @@ class EsTableComponent {
|
|
|
1082
1367
|
items = this.getViewItemsBySource();
|
|
1083
1368
|
}
|
|
1084
1369
|
else if (this.arrayMode) {
|
|
1370
|
+
this.View.forEach(itm => { itm._item = true; });
|
|
1371
|
+
// Se faccio dei raggruppamenti ignoro la paginazione
|
|
1085
1372
|
if (this.UseArrayModePaging && !allIfPossible) {
|
|
1086
1373
|
// Se sono in modalità array ma la ricerca dipende da una view devo riallineare gli itemperpage
|
|
1087
1374
|
if (this.SearchView)
|
|
@@ -1100,19 +1387,64 @@ class EsTableComponent {
|
|
|
1100
1387
|
return items.filter(t => t._selected);
|
|
1101
1388
|
return items;
|
|
1102
1389
|
}
|
|
1103
|
-
/** @ignore */
|
|
1104
|
-
getViewItemsBySource() {
|
|
1105
|
-
return this.SecondarySource ? this.View.items2 : this.TertiarySource ? this.View.items3 : this.View.items;
|
|
1106
|
-
}
|
|
1107
1390
|
/**
|
|
1108
|
-
*
|
|
1391
|
+
* @ignore
|
|
1109
1392
|
*
|
|
1110
|
-
* @
|
|
1393
|
+
* @todo: ITEMS
|
|
1111
1394
|
*/
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1395
|
+
getViewItemsBySource() {
|
|
1396
|
+
var _a, _b;
|
|
1397
|
+
let castedView = this.View;
|
|
1398
|
+
let groupKeys = castedView.groupings ? castedView.groupings.filter(t => !t.aggregation).length : 0;
|
|
1399
|
+
//Gruppi intermedi
|
|
1400
|
+
if ((((_a = castedView.requestedgroups) === null || _a === void 0 ? void 0 : _a.length) != groupKeys || ((_b = castedView.requestedgroups) === null || _b === void 0 ? void 0 : _b.length) == 0) && groupKeys > 0) {
|
|
1401
|
+
let ret = castedView.groups;
|
|
1402
|
+
ret.forEach(itm => {
|
|
1403
|
+
// Setto variabile interna per capire che questo è in realtà un gruppo
|
|
1404
|
+
itm._group = true;
|
|
1405
|
+
// Le informazioni passate come lista le metto dentro a una cache per velocizzarne l'accesso quando devo tirare fuori il display della proprietà
|
|
1406
|
+
this.cacheAggregations(itm);
|
|
1407
|
+
});
|
|
1408
|
+
return ret;
|
|
1409
|
+
}
|
|
1410
|
+
else {
|
|
1411
|
+
let ret = this.SecondarySource ? this.View.items2 : this.TertiarySource ? this.View.items3 : this.View.items;
|
|
1412
|
+
// Setto variabile interna per specificare che questo è un elemento normale, non un gruppo o altro
|
|
1413
|
+
ret.forEach(itm => { itm._item = true; });
|
|
1414
|
+
return ret;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Helper per effettuare il caching delle aggregazioni. Le sposta da una lista di **GroupAggregation** a una **<Map<string, Map<string, string>>**
|
|
1419
|
+
*
|
|
1420
|
+
* @todo: ROWGROUPING
|
|
1421
|
+
*/
|
|
1422
|
+
cacheAggregations(group) {
|
|
1423
|
+
group._aggregationsCache = new Map();
|
|
1424
|
+
let castedAgCache = group._aggregationsCache;
|
|
1425
|
+
for (let i = 0; i < group.aggregations.length; i++) {
|
|
1426
|
+
let agg = group.aggregations[i];
|
|
1427
|
+
if (castedAgCache.has(agg.column))
|
|
1428
|
+
castedAgCache.get(agg.column).set(agg.aggregation, agg.value);
|
|
1429
|
+
else {
|
|
1430
|
+
let tmp = new Map();
|
|
1431
|
+
tmp.set(agg.aggregation, agg.value);
|
|
1432
|
+
castedAgCache.set(agg.column, tmp);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Metodo che prende tutti gli oggetti di cui dispone divisi in bucket da 100 elementi
|
|
1438
|
+
*
|
|
1439
|
+
* @returns {any[][]} Matrice di array Nx100
|
|
1440
|
+
*
|
|
1441
|
+
* @todo: ITEMS
|
|
1442
|
+
*/
|
|
1443
|
+
getItemSlices() {
|
|
1444
|
+
// Se sono qui di sicuro non ho rowgrouping
|
|
1445
|
+
let items = this.getItemsByMode();
|
|
1446
|
+
if (!items)
|
|
1447
|
+
return [];
|
|
1116
1448
|
let arrayBy100 = [];
|
|
1117
1449
|
let slices = Math.ceil(items.length / this.SliceSize);
|
|
1118
1450
|
for (let i = 0; i < slices; i++) {
|
|
@@ -1143,8 +1475,6 @@ class EsTableComponent {
|
|
|
1143
1475
|
}
|
|
1144
1476
|
}
|
|
1145
1477
|
}
|
|
1146
|
-
// #endregion
|
|
1147
|
-
// #region Gestione di tutto il ciclo di vita post binding oggetti
|
|
1148
1478
|
/**
|
|
1149
1479
|
* Metodo lanciato dopo che la sorgente dati è stata correttamente bindata, si occupa di ricalcolare tutto ciò che serve
|
|
1150
1480
|
* all'es-table per renderizzare i valori da mostrare
|
|
@@ -1154,113 +1484,444 @@ class EsTableComponent {
|
|
|
1154
1484
|
this.RowContexts = [];
|
|
1155
1485
|
this.OrderDirectives = [];
|
|
1156
1486
|
this.lastSelectedItemID = null;
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
this.
|
|
1162
|
-
|
|
1163
|
-
if (this.viewMode && this.UseCustomCells) {
|
|
1164
|
-
let view = this.View;
|
|
1165
|
-
let ths = this.EsThs && this.EsThs.length > 0 ? this.EsThs.toArray() : this.EsThsDirective && this.EsThsDirective.length > 0 ? this.EsThsDirective.toArray() : [];
|
|
1166
|
-
let tds = this.EsTds && this.EsTds.length > 0 ? this.EsTds.toArray() : this.EsTdsDirective && this.EsTdsDirective.length > 0 ? this.EsTdsDirective.toArray() : [];
|
|
1167
|
-
// N.B: Rispettare l'ordine di queste 3 macrocategorie è VITALE
|
|
1168
|
-
// ************************************* Sistemazioni di TH, TD, e visibilità varie *************************************
|
|
1169
|
-
this.alignColumnsIfLoadedView(view); // Se sto caricando una View da hotpotato (quindi con savedstate = true) riallineo la visibilità delle colonne e il loro ordine.
|
|
1170
|
-
this.refreshColumnsVisibility(ths, tds, view); // Lavoro sui TH ed eventualmente modifico la visibilità anche dei TD.
|
|
1171
|
-
this.alignHeadersOrdering(ths, view); // Allineo gli ordinamenti agli header
|
|
1172
|
-
this.reviewColumnsList(ths); // Aggiorna la lista delle colonne da mostrare nella dialog per ordinamento ecc
|
|
1173
|
-
// ************************************* Generazione binding per righe e colonne *************************************
|
|
1174
|
-
this.evaluateRowThs(ths); // Raccolgo i TH
|
|
1175
|
-
this.evaluateRowTds(ths, tds); // Raccolgo i TD in contesti separati, un contesto per ogni item
|
|
1176
|
-
// ************************************* Ultimi aggiustmaenti dei binding *************************************
|
|
1177
|
-
this.generateDefaultOrder(view); // Genero le direttive di ordinamento, che siano default o derivanti dalla AppSearch
|
|
1178
|
-
this.applyOrdering(view, true); // Applico l'ordinamento sulle colonne (non ASC DESC, ma "prima questa o quella colonna")
|
|
1179
|
-
this.MoveTemporaryVariablesToRealOnes(); // Collego TH e TD aggiustati fino ad ora alle variabili di Binding HTML
|
|
1180
|
-
this.evaluateSelection(view.items, view.selection); // Riallineo le info di selezione degli elementi della View
|
|
1181
|
-
}
|
|
1182
|
-
else if (this.viewMode && !this.UseCustomCells) {
|
|
1183
|
-
// Riallineo le info di selezione degli elementi della View
|
|
1184
|
-
let view = this.View;
|
|
1185
|
-
this.evaluateSelection(view.items, view.selection);
|
|
1186
|
-
}
|
|
1187
|
-
else if (this.arrayMode) {
|
|
1188
|
-
// Riallineo le info di selezione degli elementi dell'array
|
|
1189
|
-
this.arrayModeEvaluateSelection(this.View);
|
|
1190
|
-
}
|
|
1191
|
-
// Collego gli oggetti da mostrare
|
|
1192
|
-
this.boundSource = this.TMPBoundSource;
|
|
1193
|
-
// Per essere sicuro che dopo un bind di oggetti la es-table aggiorni la grafica
|
|
1194
|
-
this.cdr.markForCheck();
|
|
1195
|
-
this.FirstBind = false;
|
|
1196
|
-
});
|
|
1487
|
+
if (this.EsThsDirective && this.EsThsDirective.length > 0 && this.EsTdsDirective && this.EsTdsDirective.length > 0)
|
|
1488
|
+
this.internalPostBoundSource();
|
|
1489
|
+
else {
|
|
1490
|
+
this.cdr.detectChanges();
|
|
1491
|
+
setTimeout(() => { this.internalPostBoundSource(); });
|
|
1492
|
+
}
|
|
1197
1493
|
}
|
|
1198
1494
|
/**
|
|
1199
|
-
*
|
|
1495
|
+
* Per poter distinguere le chiamate a questo metodo: Dopo il setTimeout se uso gli EsTd/EsTh vecchi, senza il setTimeout se uso le nuove direttive
|
|
1200
1496
|
*/
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
this.
|
|
1497
|
+
internalPostBoundSource() {
|
|
1498
|
+
let View = this.View;
|
|
1499
|
+
let ths = this.EsThs && this.EsThs.length > 0 ? this.EsThs.toArray() : this.EsThsDirective && this.EsThsDirective.length > 0 ? this.EsThsDirective.toArray() : [];
|
|
1500
|
+
let tds = this.EsTds && this.EsTds.length > 0 ? this.EsTds.toArray() : this.EsTdsDirective && this.EsTdsDirective.length > 0 ? this.EsTdsDirective.toArray() : [];
|
|
1501
|
+
// Se non ho colonne dinamiche ma sono in modalità dinamica (lo capisco perché c'è una view piena di genericitem) metto il default delle colonne
|
|
1502
|
+
this.eventuallyReviewDynamicColumns();
|
|
1503
|
+
this.bindDisplayToLoadedItemsOrGroups(View);
|
|
1504
|
+
// Questo dev'essere per forza lanciato dopo **bindDisplayToLoadedItemsOrGroups** dato che è lì che alcune cose vengono valorizzate
|
|
1505
|
+
this.setupPagingInformations();
|
|
1506
|
+
// Molte cose sono ovviamente disponibili solo in modalità View
|
|
1507
|
+
if ((this.viewMode || this.arrayMode) && this.UseCustomCells) {
|
|
1508
|
+
let view = this.viewMode ? View : null;
|
|
1509
|
+
let itemsAndGroups = this.viewMode ? [...(view.items || []), ...(view.groups || [])] : View;
|
|
1510
|
+
let si = this.viewMode ? view.selection : this.arraymodeSelection;
|
|
1511
|
+
// N.B: Rispettare l'ordine di queste 3 macrocategorie è VITALE
|
|
1512
|
+
// ************************************* Sistemazioni di TH, TD, e visibilità varie *************************************
|
|
1513
|
+
let hI = this.evaluateHeadersGroupingInfos(ths); // Prepassaggio per tirare fuori tutte le info utili sugli headers in modo da non ricacolarseli sempre dopo
|
|
1514
|
+
if (this.arrayMode) { // In modalità array non ho un backend...
|
|
1515
|
+
this.arrayModeReviewOrderings(); // ... quindi gli ordinamenti li devo fare lato client, e ...
|
|
1516
|
+
this.arrayModeReviewGroupings(hI.leafs); // ... i raggruppamenti li devo fare lato client
|
|
1517
|
+
}
|
|
1518
|
+
this.reviewColumnsList(hI.leafs); // Aggiorna la lista delle colonne da mostrare nella dialog per ordinamento ecc
|
|
1519
|
+
this.moveFixedColumnsAtTheBeginning(hI.leafs, tds); // Sposto tutte le cose fixed all'inizio in modo che la creazione di th e td sia più snella (Utilizza le ColumnsList, quindi dev'essere richiamata PIRMA di reviewColumnsList)
|
|
1520
|
+
this.alignHeadersOrdering(hI.leafs, view); // Allineo gli ordinamenti agli header
|
|
1521
|
+
this.alignColumnsIfLoadedView(view); // Se sto caricando una View da hotpotato (quindi con savedstate = true) riallineo la visibilità delle colonne e il loro ordine.
|
|
1522
|
+
this.refreshColumnsVisibility(hI.leafs, tds, view); // Lavoro sui TH ed eventualmente modifico la visibilità anche dei TD.
|
|
1523
|
+
this.evaluatePinnedColumnsWidth(); // Se sono presenti colonne pinnate valuta la dimensione del contenitore
|
|
1524
|
+
this.generateDefaultOrder(hI.leafs, view); // Genero le direttive di ordinamento, che siano default o derivanti dalla AppSearch
|
|
1525
|
+
this.evaluateHeaderGroups(hI); // Valuto i raggruppamenti degli header se presenti
|
|
1526
|
+
// ************************************* Generazione binding per righe e colonne *************************************
|
|
1527
|
+
this.evaluateRowThs(hI.leafs); // Raccolgo i TH
|
|
1528
|
+
this.evaluateRowTds(hI.leafs, tds); // Raccolgo i TD in contesti separati, un contesto per ogni item o gruppo
|
|
1529
|
+
// ************************************* Ultimi aggiustmaenti dei binding *************************************
|
|
1530
|
+
this.applyOrdering(view, true); // Applico l'ordinamento sulle colonne (non ASC DESC, ma "prima questa o quella colonna")
|
|
1531
|
+
this.MoveTemporaryVariablesToRealOnes(); // Collego TH e TD aggiustati fino ad ora alle variabili di Binding HTML
|
|
1532
|
+
this.evaluateSelection(itemsAndGroups, si); // Riallineo le info di selezione degli elementi della View
|
|
1533
|
+
if (this.ResearchNeeded) {
|
|
1534
|
+
this.changed();
|
|
1535
|
+
this.emitSearchRequest(false);
|
|
1536
|
+
this.ResearchNeeded = false;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
else if ((this.viewMode || this.arrayMode) && !this.UseCustomCells) {
|
|
1540
|
+
// Riallineo le info di selezione degli elementi della View
|
|
1541
|
+
let items = this.viewMode ? View.items : View;
|
|
1542
|
+
let si = this.viewMode ? View.selection : this.arraymodeSelection;
|
|
1543
|
+
this.evaluateSelection(items, si);
|
|
1544
|
+
}
|
|
1545
|
+
// Per essere sicuro che dopo un bind di oggetti la es-table aggiorni la grafica
|
|
1546
|
+
this.cdr.markForCheck();
|
|
1547
|
+
this.FirstBind = false;
|
|
1204
1548
|
}
|
|
1205
1549
|
/**
|
|
1206
|
-
*
|
|
1550
|
+
* Se in modalità array applica gli ordinamenti ASC-DESC delle colonne
|
|
1207
1551
|
*
|
|
1208
|
-
* @
|
|
1209
|
-
* @param {ItemsSelection<any>} selectionItem Oggetti di selezione derivante dalla view o dall'oggetto per Array
|
|
1552
|
+
* @todo: INTERNALDB
|
|
1210
1553
|
*/
|
|
1211
|
-
|
|
1212
|
-
if (
|
|
1554
|
+
arrayModeReviewOrderings() {
|
|
1555
|
+
if (this.arrayOrders.length > 0)
|
|
1556
|
+
this.arrayOrders.forEach(t => {
|
|
1557
|
+
this.boundSource = this.boundSource.sort((a, b) => (a[t.id] > b[t.id] ? 1 : -1) * (t.order == 'DESC' ? -1 : 1));
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
/**
|
|
1561
|
+
* Se in modalità array applica i raggruppamenti definiti lato row-grouping
|
|
1562
|
+
*
|
|
1563
|
+
* @param {ths: EsTh[] | EsThDirective[]} ths Header
|
|
1564
|
+
*
|
|
1565
|
+
* @todo: ROW GROUPING
|
|
1566
|
+
*/
|
|
1567
|
+
arrayModeReviewGroupings(ths) {
|
|
1568
|
+
if (ths.length == 0)
|
|
1213
1569
|
return;
|
|
1214
|
-
this.
|
|
1570
|
+
if (this.isEsTh(ths[0]))
|
|
1571
|
+
return;
|
|
1572
|
+
let headerGroups = [];
|
|
1573
|
+
let headerAggregations = [];
|
|
1574
|
+
for (let i = 0; i < ths.length; i++) {
|
|
1575
|
+
let th = ths[i];
|
|
1576
|
+
if (th.thGroup)
|
|
1577
|
+
headerGroups.push(new Group(th.th, 0, ""));
|
|
1578
|
+
else if (th.thAggregation)
|
|
1579
|
+
headerAggregations = [...headerAggregations, ...this.getGroupAggregations(th)];
|
|
1580
|
+
}
|
|
1581
|
+
if (headerGroups.length > 0) {
|
|
1582
|
+
// Pulizia delle cache
|
|
1583
|
+
this.rgGroupCache.clear();
|
|
1584
|
+
this.rgItemCache.clear();
|
|
1585
|
+
this.rgChildGroupsCache.clear();
|
|
1586
|
+
this.ArrayGrouping = true;
|
|
1587
|
+
this.boundSource = this.getGroupsRecursive(headerGroups, 0, this.boundSource, headerAggregations, null);
|
|
1588
|
+
}
|
|
1215
1589
|
}
|
|
1216
1590
|
/**
|
|
1217
|
-
*
|
|
1591
|
+
* Data la definizione dei gruppi da generare da una lista di oggetti, suddivide gli oggetti passati in gruppi e sottogruppi
|
|
1592
|
+
*
|
|
1593
|
+
* @param {Group[]} grps Definizione dei gruppi
|
|
1594
|
+
* @param {number} currentIndex Indice di elaborazione. Al livello 0 ho tutti gli oggetti e devo generare i primi gruppi, a livello 1 ho tutti i gruppi principali e devo
|
|
1595
|
+
* elaborare i sottogruppi, e così via ricorsivamente...
|
|
1596
|
+
* @param {any[]} items Oggetti da raggruppare
|
|
1597
|
+
* @param {GroupOrAggregation[]} aggregations Info di aggregazione
|
|
1598
|
+
* @param {any} parent Riferimento al gruppo padre
|
|
1218
1599
|
*
|
|
1219
|
-
* @
|
|
1600
|
+
* @todo: INTERNALDB
|
|
1220
1601
|
*/
|
|
1221
|
-
|
|
1222
|
-
|
|
1602
|
+
getGroupsRecursive(grps, currentIndex, items, aggregations, parent) {
|
|
1603
|
+
// Se l'indice è 0 devo sicuramente nascondere tutti gli oggetti. Solo i gruppi saranno visualizzati
|
|
1604
|
+
if (currentIndex == 0)
|
|
1605
|
+
items.forEach(i => i._visible = false);
|
|
1606
|
+
let grp = grps[currentIndex];
|
|
1607
|
+
let ret = [];
|
|
1608
|
+
let last = grps.length == currentIndex + 1;
|
|
1609
|
+
let groups = this.groupBy(items, grp.column);
|
|
1610
|
+
for (let prop in groups) {
|
|
1611
|
+
let itms = groups[prop];
|
|
1612
|
+
let gp = new Group(grp.column, itms.length, prop);
|
|
1613
|
+
gp.aggregations = this.generateAggregations(itms, aggregations);
|
|
1614
|
+
let anygp = gp;
|
|
1615
|
+
anygp._group = true;
|
|
1616
|
+
anygp._expanded = false;
|
|
1617
|
+
if (!parent) {
|
|
1618
|
+
anygp._thisRoute = [{ column: gp.column, value: gp.value }];
|
|
1619
|
+
anygp._thisKey = gp.value;
|
|
1620
|
+
anygp._grouplevel = 0;
|
|
1621
|
+
}
|
|
1622
|
+
else {
|
|
1623
|
+
anygp._parent = parent._thisKey;
|
|
1624
|
+
anygp._parentRoute = parent._thisRoute;
|
|
1625
|
+
anygp._thisRoute = [...parent._thisRoute, { column: gp.column, value: gp.value }];
|
|
1626
|
+
anygp._thisKey = parent._thisKey + gp.value;
|
|
1627
|
+
anygp._grouplevel = parent._grouplevel + 1;
|
|
1628
|
+
}
|
|
1629
|
+
// Pusho il gruppo, tutti i gruppi del livello sotto, o gli item se io sono l'ultimo gruppo.
|
|
1630
|
+
// La visibilità è solo per il gruppo a livello 0, tutti gli altri gruppi saranno mostrati o nascosti di conseguenza
|
|
1631
|
+
if (currentIndex == 0)
|
|
1632
|
+
anygp._visible = true;
|
|
1633
|
+
this.calculateHash([anygp]);
|
|
1634
|
+
this.cacheAggregations(anygp);
|
|
1635
|
+
// Aggiungo il gruppo padre
|
|
1636
|
+
ret.push(anygp);
|
|
1637
|
+
this.rgGroupCache.set(anygp._thisKey, anygp);
|
|
1638
|
+
if (!last) {
|
|
1639
|
+
//Dal gruppo padre, se non è l'ultimo gruppo della catena, calcolo ricorsivamente tutta la catena sotto
|
|
1640
|
+
let subGroupsAndItems = this.getGroupsRecursive(grps, currentIndex + 1, itms, aggregations, anygp);
|
|
1641
|
+
let childgroups = subGroupsAndItems.filter(t => t._group && t._parent == anygp._thisKey);
|
|
1642
|
+
anygp._groupscount = childgroups.length;
|
|
1643
|
+
// Aggiungo la catena del gruppo sotto, aggiungendo alla cache solo i gruppi padre
|
|
1644
|
+
ret.push(...subGroupsAndItems);
|
|
1645
|
+
this.rgChildGroupsCache.set(anygp._thisKey, childgroups);
|
|
1646
|
+
}
|
|
1647
|
+
else {
|
|
1648
|
+
// Al gruppo padre, se è l'ultimo assegno tutte le foglie assegnandogli anche la chiave del gruppo
|
|
1649
|
+
itms.forEach(i => i._thisKey = anygp._thisKey);
|
|
1650
|
+
ret.push(...itms);
|
|
1651
|
+
this.rgItemCache.set(anygp._thisKey, itms);
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
return ret;
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* Data una lista di oggetti genera le aggregazioni specificate. Si considera di avere tutti gli oggetti
|
|
1658
|
+
*
|
|
1659
|
+
* @param {any[]} items Oggetti di cui calcolare le aggregazione
|
|
1660
|
+
* @param {GroupOrAggregation[]} aggregations Aggergazioni da generare
|
|
1661
|
+
*
|
|
1662
|
+
* @todo: INTERNALDB
|
|
1663
|
+
*/
|
|
1664
|
+
generateAggregations(items, aggregations) {
|
|
1665
|
+
let rets = [];
|
|
1666
|
+
let aggregationValue = "", feField = null, stringAgg = null, dateAgg = null, numberAgg = null;
|
|
1667
|
+
for (let i = 0; i < aggregations.length; i++) {
|
|
1668
|
+
let agg = aggregations[i];
|
|
1669
|
+
feField = agg.column;
|
|
1670
|
+
if (!feField)
|
|
1671
|
+
continue;
|
|
1672
|
+
switch (agg.datatype) {
|
|
1673
|
+
case 'string':
|
|
1674
|
+
stringAgg = items.map(i => i[feField].toString());
|
|
1675
|
+
break;
|
|
1676
|
+
case 'date':
|
|
1677
|
+
dateAgg = items.map(i => new Date(i[feField]).getTime());
|
|
1678
|
+
break;
|
|
1679
|
+
case 'number':
|
|
1680
|
+
numberAgg = items.map(i => parseFloat(i[feField]));
|
|
1681
|
+
break;
|
|
1682
|
+
}
|
|
1683
|
+
switch (agg.aggregation) {
|
|
1684
|
+
case 'max':
|
|
1685
|
+
switch (agg.datatype) {
|
|
1686
|
+
case 'string':
|
|
1687
|
+
aggregationValue = stringAgg.sort().reverse()[0];
|
|
1688
|
+
break;
|
|
1689
|
+
case 'date':
|
|
1690
|
+
aggregationValue = new Date(Math.max(...dateAgg)).toString();
|
|
1691
|
+
break;
|
|
1692
|
+
case 'number':
|
|
1693
|
+
aggregationValue = Math.max(...numberAgg).toString();
|
|
1694
|
+
break;
|
|
1695
|
+
}
|
|
1696
|
+
break;
|
|
1697
|
+
case 'min':
|
|
1698
|
+
switch (agg.datatype) {
|
|
1699
|
+
case 'string':
|
|
1700
|
+
aggregationValue = stringAgg.sort()[0];
|
|
1701
|
+
break;
|
|
1702
|
+
case 'date':
|
|
1703
|
+
aggregationValue = new Date(Math.min(...dateAgg)).toString();
|
|
1704
|
+
break;
|
|
1705
|
+
case 'number':
|
|
1706
|
+
aggregationValue = Math.min(...numberAgg).toString();
|
|
1707
|
+
break;
|
|
1708
|
+
}
|
|
1709
|
+
break;
|
|
1710
|
+
case 'sum':
|
|
1711
|
+
switch (agg.datatype) {
|
|
1712
|
+
case 'string':
|
|
1713
|
+
aggregationValue = stringAgg.join(", ");
|
|
1714
|
+
break;
|
|
1715
|
+
case 'date':
|
|
1716
|
+
aggregationValue = "";
|
|
1717
|
+
break;
|
|
1718
|
+
case 'number':
|
|
1719
|
+
aggregationValue = numberAgg.reduce((pre, curr) => pre + curr, 0).toString();
|
|
1720
|
+
break;
|
|
1721
|
+
}
|
|
1722
|
+
break;
|
|
1723
|
+
}
|
|
1724
|
+
rets.push(new GroupAggregation(agg.column, agg.aggregation, aggregationValue));
|
|
1725
|
+
}
|
|
1726
|
+
return rets;
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* Data una lista di oggetti effettua dei raggruppamenti in base alla proprietà **field**, restituendo un oggetto del tipo { Gruppo1: oggetti[], Gruppo2: oggetti[], ecc... }
|
|
1730
|
+
*
|
|
1731
|
+
* @param {any[]} array Lista degli oggetti da raggruppare
|
|
1732
|
+
* @param {string} field Campo su cui effettuare i raggruppamenti
|
|
1733
|
+
*
|
|
1734
|
+
* @returns {{ [id: string]: any[] }} Dizionario dei gruppi
|
|
1735
|
+
*
|
|
1736
|
+
* @todo: INTERNALDB
|
|
1737
|
+
*/
|
|
1738
|
+
groupBy(array, field) {
|
|
1739
|
+
let ret = {};
|
|
1740
|
+
for (let i = 0; i < array.length; i++) {
|
|
1741
|
+
let x = array[i];
|
|
1742
|
+
(ret[x[field]] = ret[x[field]] || []).push(x);
|
|
1743
|
+
}
|
|
1744
|
+
return ret;
|
|
1745
|
+
}
|
|
1746
|
+
;
|
|
1747
|
+
/**
|
|
1748
|
+
* Effettua il binding degli oggetti pervenuti da questa chiamata con gli oggetti effettivamente da graficare
|
|
1749
|
+
*
|
|
1750
|
+
* @param {any} view View da cui sono arrivati gli oggetti. Può essere o un array se sono in **arrayMode** o una AppSearch<T> se sono in **viewMode**
|
|
1751
|
+
*/
|
|
1752
|
+
bindDisplayToLoadedItemsOrGroups(view) {
|
|
1753
|
+
var _a, _b;
|
|
1754
|
+
if (this.TMPBoundSource.length == 0) {
|
|
1755
|
+
this.BaseItemsCount = 0;
|
|
1223
1756
|
return;
|
|
1224
|
-
|
|
1757
|
+
}
|
|
1758
|
+
if (this.arrayMode || !this.UseCustomCells) {
|
|
1759
|
+
this.boundSource = this.TMPBoundSource;
|
|
1760
|
+
this.BaseItemsCount = (view === null || view === void 0 ? void 0 : view.objectcount) || view.length;
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1763
|
+
let groupingKeys = ((_b = (_a = view.groupings) === null || _a === void 0 ? void 0 : _a.filter(t => !t.aggregation)) === null || _b === void 0 ? void 0 : _b.length) || 0;
|
|
1764
|
+
if (groupingKeys == 0) {
|
|
1765
|
+
this.boundSource = this.TMPBoundSource;
|
|
1766
|
+
this.BaseItemsCount = view.objectcount;
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
this.handleNewDataOnRowGrouping(view, groupingKeys);
|
|
1225
1770
|
}
|
|
1226
1771
|
/**
|
|
1227
|
-
*
|
|
1772
|
+
* In modalità rowgrouping quando mi arriva un nuovo blocco di oggetti devo aggiungerlo alla vista attuale:
|
|
1228
1773
|
*
|
|
1229
|
-
*
|
|
1230
|
-
*
|
|
1774
|
+
* 1) Se non viene richiesto il dettaglio di alcun gruppo significa che devo considerare mi siano arrivati tutti i gruppi principali
|
|
1775
|
+
* 2) Se viene richiesto il dettaglio di un gruppo diverso dall'ultimo devo aggiungere dopo al gruppo cliccato la lista dei sottogruppi
|
|
1776
|
+
* 2) Se viene richiesto il dettaglio dell'ultimo gruppo devo aggiungere dopo al gruppo cliccato la lista degli oggetti
|
|
1777
|
+
*
|
|
1778
|
+
* @param {any} view AppSearch<T> da cui sono arrivati gli oggetti
|
|
1779
|
+
* @param {number} groupingKeys Livelli di raggruppamento da aspettarsi sui dati
|
|
1780
|
+
*
|
|
1781
|
+
* @todo: ROWGROUPING
|
|
1231
1782
|
*/
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
itm.
|
|
1244
|
-
|
|
1783
|
+
handleNewDataOnRowGrouping(view, groupingKeys) {
|
|
1784
|
+
var _a, _b;
|
|
1785
|
+
// 1) Se non viene richiesto il dettaglio di alcun gruppo significa che la chiamata restituisce la lista paginata dei gruppi principali.
|
|
1786
|
+
// Li tratto come se fosse una qualsiasi altra query paginata su N elementi
|
|
1787
|
+
if ((((_a = view.requestedgroups) === null || _a === void 0 ? void 0 : _a.length) || 0) == 0) {
|
|
1788
|
+
this.boundSource = this.TMPBoundSource;
|
|
1789
|
+
this.rgGroupCache = new Map();
|
|
1790
|
+
this.rgItemCache = new Map();
|
|
1791
|
+
this.rgChildGroupsCache = new Map();
|
|
1792
|
+
this.TMPBoundSource.forEach(itm => {
|
|
1793
|
+
itm._thisRoute = itm._group ? [{ column: itm.column, value: itm.value }] : [];
|
|
1794
|
+
itm._thisKey = itm._group ? itm.value : null;
|
|
1795
|
+
itm._grouplevel = 0;
|
|
1796
|
+
this.rgGroupCache.set(itm._thisKey, itm);
|
|
1797
|
+
});
|
|
1798
|
+
// Resetto la ricerca alla cache di questa "sessione"
|
|
1799
|
+
let firstItem = this.TMPBoundSource[0];
|
|
1800
|
+
this.MainGroupView = Object.assign({}, view);
|
|
1801
|
+
this.groupSearchRequestsCache = [{ path: '', route: [{ column: firstItem.column, value: firstItem.value }], view: this.MainGroupView, group_column: this.TMPBoundSource[0].column }];
|
|
1802
|
+
this.BaseItemsCount = view.objectcount;
|
|
1245
1803
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1804
|
+
else {
|
|
1805
|
+
// 2) Se viene richiesto il dettaglio di un qualsiasi gruppo diverso dall'ultimo vuol dire che devo aggiungere
|
|
1806
|
+
// dopo al gruppo che ho cliccato la lista dei gruppi tirata fuori questa volta (intermediateGroup = true)
|
|
1807
|
+
/*
|
|
1808
|
+
* GruppoA GruppoA
|
|
1809
|
+
* GruppoB GruppoB
|
|
1810
|
+
* GruppoC <- Clicco qui GruppoC
|
|
1811
|
+
* GruppoD GruppoC1
|
|
1812
|
+
* GruppoE GruppoC2
|
|
1813
|
+
* GruppoD
|
|
1814
|
+
* GruppoE
|
|
1815
|
+
*/
|
|
1816
|
+
// 3) se i gruppi richiesti dalla view sono uguali ai gruppi presenti vuol dire che sto prendendo gli oggetti veri e propri, sono in
|
|
1817
|
+
// view.items e quindi in TMPBoundSource, ho inoltre le informazioni di paginazione **per il singolo sottogruppo** (intermediateGroup = false)
|
|
1818
|
+
/*
|
|
1819
|
+
* GruppoA GruppoA
|
|
1820
|
+
* GruppoC1 GruppoC1
|
|
1821
|
+
* GruppoB GruppoB
|
|
1822
|
+
* GruppoC GruppoC
|
|
1823
|
+
* GruppoC1 <-- Clicco qui GruppoC1
|
|
1824
|
+
* Oggetto1
|
|
1825
|
+
* Oggetto2
|
|
1826
|
+
* Oggetto3
|
|
1827
|
+
* GruppoC2 GruppoC2
|
|
1828
|
+
* GruppoD GruppoD
|
|
1829
|
+
* GruppoE GruppoE
|
|
1830
|
+
*/
|
|
1831
|
+
let intermediateGroup = view.requestedgroups.length != groupingKeys;
|
|
1832
|
+
let items = this.boundSource;
|
|
1833
|
+
let insertIndex = 0;
|
|
1834
|
+
let groupKey = "";
|
|
1835
|
+
let groupRoute = [];
|
|
1836
|
+
// Navigo la stuttura dei gruppi ignorando ricorsivamente tutti gli indici fino ai gruppi che mi interessano in modo da non beccare il primo "GruppoC1" del caso sopra
|
|
1837
|
+
for (let i = 0; i < view.requestedgroups.length; i++) {
|
|
1838
|
+
let rg = view.requestedgroups[i];
|
|
1839
|
+
groupKey += rg.value;
|
|
1840
|
+
groupRoute.push({ column: rg.column, value: rg.value });
|
|
1841
|
+
insertIndex = items.findIndex((t, i) => i >= insertIndex && t._group && t.column == rg.column && t.value == rg.value);
|
|
1842
|
+
}
|
|
1843
|
+
let itemsCacheReference;
|
|
1844
|
+
let childGroupsCacheReference;
|
|
1845
|
+
// Se non è un gruppo intermedio devo ripulire la cache del gruppo su cui ho attualmente cliccato. Gli oggetti saranno riaggiunti dopo
|
|
1846
|
+
if (!intermediateGroup) {
|
|
1847
|
+
this.rgItemCache.set(groupKey, []);
|
|
1848
|
+
itemsCacheReference = this.rgItemCache.get(groupKey);
|
|
1849
|
+
}
|
|
1850
|
+
else {
|
|
1851
|
+
// Se invece è un gruppo intermedio devo ripulire sia tutti i child group ricorsivamente, sia tutti gli item
|
|
1852
|
+
for (let key of this.rgChildGroupsCache.keys())
|
|
1853
|
+
if (key.startsWith(groupKey))
|
|
1854
|
+
this.rgChildGroupsCache.delete(key);
|
|
1855
|
+
for (let key of this.rgItemCache.keys())
|
|
1856
|
+
if (key.startsWith(groupKey))
|
|
1857
|
+
this.rgItemCache.delete(key);
|
|
1858
|
+
this.rgChildGroupsCache.set(groupKey, []);
|
|
1859
|
+
childGroupsCacheReference = this.rgChildGroupsCache.get(groupKey);
|
|
1860
|
+
}
|
|
1861
|
+
// Assegno un livello ai valori che arrivano da usare per formattare la parte grafica. Il primo gruppo cliccato sarà a livello 1,
|
|
1862
|
+
// il secondo sarà a livello 2 e così via...
|
|
1863
|
+
// Li marco inoltre con il parent in modo da poter eliminare i vecchi qualora servisse
|
|
1864
|
+
this.TMPBoundSource.forEach(itm => {
|
|
1865
|
+
itm._parent = groupKey;
|
|
1866
|
+
itm._parentRoute = groupRoute;
|
|
1867
|
+
itm._thisRoute = itm._group ? [...groupRoute, new GroupRouteFragment(itm.column, itm.value)] : [];
|
|
1868
|
+
itm._thisKey = itm._group ? groupKey + itm.value : groupKey;
|
|
1869
|
+
// Per le ricerca intermedie metto i gruppi nella cache dei gruppi
|
|
1870
|
+
if (intermediateGroup) {
|
|
1871
|
+
itm._grouplevel = view.requestedgroups.length;
|
|
1872
|
+
this.rgGroupCache.set(itm._thisKey, itm);
|
|
1873
|
+
childGroupsCacheReference.push(itm);
|
|
1874
|
+
}
|
|
1875
|
+
else {
|
|
1876
|
+
// Metto anche gli oggetti nella cache non ricorsiva
|
|
1877
|
+
itemsCacheReference.push(itm);
|
|
1878
|
+
}
|
|
1879
|
+
});
|
|
1880
|
+
// Elimino gli oggetti vecchi
|
|
1881
|
+
// 1) Ricerca intermedia, stato salvato - Elimino tutti gli item e tutti i gruppi la cui route è più lunga della corrente, tutti gli item relativi alla path corrente, e tutte
|
|
1882
|
+
// le cache di ricerca effettuate su una path più profonda dell'attuale
|
|
1883
|
+
// 2) Ricerca finale o ricerca intermedia senza stato salvato - Elimino tutti gli item relativi alla path corrente
|
|
1884
|
+
// Per "stato salvato" si intendono ricerche vecchie salvate per poter essere rieffettuate in caso di ordinamenti su colonne di interesse
|
|
1885
|
+
if (intermediateGroup && view.savedstate) {
|
|
1886
|
+
this.boundSource = this.boundSource.filter(t => !(t._item || t._thisRoute.length > groupRoute.length));
|
|
1887
|
+
this.groupSearchRequestsCache = this.groupSearchRequestsCache.filter(t => !(t.route.length > groupRoute.length));
|
|
1888
|
+
}
|
|
1889
|
+
this.boundSource = this.boundSource.filter(t => !(t._parent == groupKey));
|
|
1890
|
+
let thisGroup = this.boundSource[insertIndex];
|
|
1891
|
+
if (intermediateGroup)
|
|
1892
|
+
thisGroup._groupscount = (_b = this.View) === null || _b === void 0 ? void 0 : _b.groupcount;
|
|
1893
|
+
// Li sostituisco coi nuovi di questa ricerca
|
|
1894
|
+
this.boundSource.splice(insertIndex + 1, 0, ...this.TMPBoundSource);
|
|
1895
|
+
// Aggiungo un separatore alla fine o all'inizio di questi gruppi che dovrà occuparsi di caricare ALTRI gruppi o oggetti (se sono all'ultimo gruppo)
|
|
1896
|
+
let addLast = false;
|
|
1897
|
+
this.boundSource.splice(insertIndex + 1 + (addLast ? this.TMPBoundSource.length : 0), 0, this.getGroupSeparator(view, groupKey, groupRoute, view.requestedgroups.length, intermediateGroup ? 'groups' : 'items'));
|
|
1898
|
+
// Aggiungo la ricerca alla cache di questa "sessione"
|
|
1899
|
+
let toAdd = { path: groupKey, route: groupRoute, view: Object.assign({}, view), group_column: intermediateGroup ? this.TMPBoundSource[0].column : '' };
|
|
1900
|
+
let prev = this.groupSearchRequestsCache.findIndex(t => t.path == toAdd.path && t.group_column == toAdd.group_column);
|
|
1901
|
+
if (prev == -1)
|
|
1902
|
+
this.groupSearchRequestsCache.push(toAdd);
|
|
1903
|
+
else
|
|
1904
|
+
this.groupSearchRequestsCache.splice(prev, 1, toAdd);
|
|
1257
1905
|
}
|
|
1258
1906
|
}
|
|
1907
|
+
/**
|
|
1908
|
+
* Metodo richiamato solo quando **TMPRowTDs** e **TMPRowTHs** sono completamente generati ed aggiustati. Serve per collegarli alle variabili usate lato binding HTML
|
|
1909
|
+
*/
|
|
1910
|
+
MoveTemporaryVariablesToRealOnes() {
|
|
1911
|
+
this.RowTDs = this.TMPRowTDs;
|
|
1912
|
+
this.RowTHs = this.TMPRowTHs;
|
|
1913
|
+
this.RowThGroups = this.TMPRowThGroups ? this.TMPRowThGroups.reverse() : null;
|
|
1914
|
+
this.Columns.Visibile = this.RowTHs.filter(t => t.Visible).length;
|
|
1915
|
+
this.Columns.VisibleUnpinned = this.RowTHs.filter(t => t.Visible && !t.Pinned).length;
|
|
1916
|
+
this.Columns.Global = this.Columns.VisibleUnpinned + (this.HasPinnedColumns ? 1 : 0) + (this.Selection ? 1 : 0) + (this.Removal ? 1 : 0) + (this.Export || this.HiddenColumns || this.ColumnsOrdering || this.CornerMenuOptions ? 1 : 0);
|
|
1917
|
+
}
|
|
1259
1918
|
/**
|
|
1260
1919
|
* Permette di selezionare o deselezionare in maniera arbitraria degli oggetti
|
|
1261
1920
|
*
|
|
1262
1921
|
* @param {any[]} items Oggetti da selezionare o deselezionare
|
|
1263
1922
|
* @param {boolean} select **true** per selezionarli, **false** per non toccarli
|
|
1923
|
+
*
|
|
1924
|
+
* @todo: SELECTION
|
|
1264
1925
|
*/
|
|
1265
1926
|
setSelectionStatus(items, select) {
|
|
1266
1927
|
this.handleItemsSelection(items, select);
|
|
@@ -1294,7 +1955,7 @@ class EsTableComponent {
|
|
|
1294
1955
|
* @param {EsTh[] | EsThDirective[]} ths Colonne della tabella
|
|
1295
1956
|
*/
|
|
1296
1957
|
reviewColumnsList(ths) {
|
|
1297
|
-
this.
|
|
1958
|
+
this.TMPColumnsList = [];
|
|
1298
1959
|
if (ths.length == 0)
|
|
1299
1960
|
return;
|
|
1300
1961
|
// Appena il contentChildren è valorizzato scorro tutti gli header
|
|
@@ -1308,18 +1969,99 @@ class EsTableComponent {
|
|
|
1308
1969
|
// Salvo le informazioni dell'header per far parte della lista da cui scegliere quali colonne visualizzare/nascondere
|
|
1309
1970
|
// Di default la visibilità è quella impostata nel componente
|
|
1310
1971
|
if (this.HiddenColumns || th.Visible)
|
|
1311
|
-
this.
|
|
1972
|
+
this.TMPColumnsList.push(new EsTableColumn(th.ID, th.Description, th.Visible, th.Fixed, null, null, null));
|
|
1312
1973
|
}
|
|
1313
1974
|
else {
|
|
1975
|
+
let column = th.th;
|
|
1314
1976
|
// Se non ho un id il th è considerato inerte
|
|
1315
|
-
if (!
|
|
1977
|
+
if (!column)
|
|
1316
1978
|
continue;
|
|
1317
1979
|
// Salvo le informazioni dell'header per far parte della lista da cui scegliere quali colonne visualizzare/nascondere
|
|
1318
1980
|
// Di default la visibilità è quella impostata nel componente
|
|
1319
|
-
if (this.HiddenColumns || th.thVisible)
|
|
1320
|
-
this.ColumnsList.
|
|
1981
|
+
if (this.HiddenColumns || th.thVisible) {
|
|
1982
|
+
let previouslyPinned = !this.ColumnsList || this.ColumnsList.length == 0 || !this.ColumnsList.find(t => t.id == column) ? null : this.ColumnsList.find(t => t.id == column).pinned;
|
|
1983
|
+
this.TMPColumnsList.push(new EsTableColumn(column, null, th.thVisible, (th.thFixed || th.thGroup), previouslyPinned == null ? th.thPinned : previouslyPinned, th.thPinnedWidth, th.Template));
|
|
1984
|
+
}
|
|
1321
1985
|
}
|
|
1322
1986
|
}
|
|
1987
|
+
this.ColumnsList = [];
|
|
1988
|
+
this.TMPColumnsList.forEach(c => { this.ColumnsList.push(Object.assign({}, c)); });
|
|
1989
|
+
}
|
|
1990
|
+
/**
|
|
1991
|
+
* Prende i th e i td in modalità diretive e li ordina in base a se ci sono colonne fixed o meno
|
|
1992
|
+
*/
|
|
1993
|
+
moveFixedColumnsAtTheBeginning(ths, tds) {
|
|
1994
|
+
let thsCache = {};
|
|
1995
|
+
let fixeds = 0, pinneds = 0;
|
|
1996
|
+
let columnsCache = {};
|
|
1997
|
+
let columnsIndexCache = {};
|
|
1998
|
+
// Creo la cache delle colonne
|
|
1999
|
+
for (let coli = 0; coli < this.ColumnsList.length; coli++) {
|
|
2000
|
+
let col = this.ColumnsList[coli];
|
|
2001
|
+
columnsCache[col.id] = col;
|
|
2002
|
+
}
|
|
2003
|
+
// Sposto tutti gli header fixed o pinned all'inizio
|
|
2004
|
+
for (let i = 0; i < ths.length; i++) {
|
|
2005
|
+
let th = ths[i];
|
|
2006
|
+
if (this.isEsTh(th)) {
|
|
2007
|
+
thsCache[th.ID] = th;
|
|
2008
|
+
if (th.Fixed) {
|
|
2009
|
+
if (i != pinneds + fixeds)
|
|
2010
|
+
this.arrayMove(ths, i, pinneds + fixeds);
|
|
2011
|
+
fixeds++;
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
else {
|
|
2015
|
+
thsCache[th.th] = th;
|
|
2016
|
+
// Riassegno sempre per ripulire valori di partenza o per aggiornarli in caso di modifiche utente
|
|
2017
|
+
th.thPinned = (!columnsCache[th.th] && th.thPinned) || (columnsCache[th.th] && columnsCache[th.th].pinned);
|
|
2018
|
+
if (th.thPinned) {
|
|
2019
|
+
if (i != pinneds)
|
|
2020
|
+
this.arrayMove(ths, i, pinneds);
|
|
2021
|
+
pinneds++;
|
|
2022
|
+
}
|
|
2023
|
+
//In questo caso sono informazioni statiche invece, non modificabili dall'utente, quindi non mi dò preoccupazioni
|
|
2024
|
+
if (th.thFixed || th.thGroup) {
|
|
2025
|
+
if (i != pinneds + fixeds)
|
|
2026
|
+
this.arrayMove(ths, i, pinneds + fixeds);
|
|
2027
|
+
fixeds++;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
if (this.isEsTh(ths[0]) || this.isEsTd(tds[0]))
|
|
2032
|
+
return;
|
|
2033
|
+
// Cache degli indici per riposizionare i td come i th
|
|
2034
|
+
for (let i = 0; i < ths.length; i++)
|
|
2035
|
+
columnsIndexCache[ths[i].th] = i;
|
|
2036
|
+
// Riordino le celle per fargli mantenere la stessa struttura dei th
|
|
2037
|
+
let newTds = new Array(ths.length);
|
|
2038
|
+
for (let i = 0; i < tds.length; i++) {
|
|
2039
|
+
let item = tds[i];
|
|
2040
|
+
newTds[columnsIndexCache[item.td]] = item;
|
|
2041
|
+
}
|
|
2042
|
+
this.HasPinnedColumns = pinneds > 0;
|
|
2043
|
+
}
|
|
2044
|
+
/**
|
|
2045
|
+
* In base alla configurazione delle colonne calcola le dimenioni delle colonne pinnate
|
|
2046
|
+
*/
|
|
2047
|
+
evaluatePinnedColumnsWidth() {
|
|
2048
|
+
if (!this.HasPinnedColumns)
|
|
2049
|
+
return;
|
|
2050
|
+
this.PinnedContainerWidth = 0;
|
|
2051
|
+
for (let i = 0; i < this.ColumnsList.length; i++) {
|
|
2052
|
+
let col = this.ColumnsList[i];
|
|
2053
|
+
if (col.pinned && col.visible)
|
|
2054
|
+
this.PinnedContainerWidth += col.pinnedWidth;
|
|
2055
|
+
}
|
|
2056
|
+
this.PinnedContainerWidth += this.Selection ? 25 : 0;
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Helper per spostare un oggetto di un array da un indice all'altro, in place
|
|
2060
|
+
*/
|
|
2061
|
+
arrayMove(array, oldI, newI) {
|
|
2062
|
+
if (newI > array.length - 1 || oldI > array.length - 1 || newI < 0 || oldI < 0)
|
|
2063
|
+
throw "Gli indici passati non fanno riferimento a una posizione dell'array. Length: " + array.length + " Old:" + oldI + " New: " + newI;
|
|
2064
|
+
array.splice(newI, 0, array.splice(oldI, 1)[0]);
|
|
1323
2065
|
}
|
|
1324
2066
|
/**
|
|
1325
2067
|
* Terminato il binding delle colonne da **reviewColumnsList** e della **View** dal **writeValue** questo metodo si occupa
|
|
@@ -1328,14 +2070,19 @@ class EsTableComponent {
|
|
|
1328
2070
|
* @param {AppSearch<any>} view AppSearch da utilizzare per questa operazione
|
|
1329
2071
|
*/
|
|
1330
2072
|
alignColumnsIfLoadedView(view) {
|
|
1331
|
-
let emitChanged = view.savedstate;
|
|
2073
|
+
let emitChanged = this.viewMode && view.savedstate;
|
|
1332
2074
|
let newColset = [];
|
|
1333
2075
|
if (!this.ColumnsList || this.ColumnsList.length == 0)
|
|
1334
2076
|
return;
|
|
2077
|
+
let columns = this.viewMode ? view.columns : this.arrayColumns;
|
|
1335
2078
|
this.ColumnsList.forEach(c => {
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
2079
|
+
// Se la colonna è pinnata mi arriva col simoleon
|
|
2080
|
+
let exCl = columns.filter(cc => cc.replace('§', '') == c.id);
|
|
2081
|
+
// Se la colonna è pinnata aggiorno l'informazione nella view
|
|
2082
|
+
if (exCl.length == 1)
|
|
2083
|
+
c.pinned = exCl[0].startsWith('§');
|
|
2084
|
+
// Se l'appsearch viene da uno stato precedente, uso le informazioni sulle colonne che ha dentro, altrimenti sovrascrivo tutto **
|
|
2085
|
+
if (c.visible && columns.length == 0)
|
|
1339
2086
|
newColset.push(c.id);
|
|
1340
2087
|
// Se ho una colonna lato AppSearch e nella ColumnList non è visibile, allineo all'AppSearch
|
|
1341
2088
|
else if (exCl.length == 1 && !c.visible)
|
|
@@ -1345,21 +2092,22 @@ class EsTableComponent {
|
|
|
1345
2092
|
c.visible = false;
|
|
1346
2093
|
});
|
|
1347
2094
|
// Non ho colonne nella appsearch, vuol dire che sono al primo binding
|
|
1348
|
-
if (
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
2095
|
+
if (columns.length == 0) {
|
|
2096
|
+
if (this.viewMode)
|
|
2097
|
+
view.columns = newColset;
|
|
2098
|
+
else
|
|
2099
|
+
this.arrayColumns = newColset;
|
|
2100
|
+
}
|
|
2101
|
+
if ((this.viewMode && view.savedstate) && this.ColumnsOrdering && view.column_ordering.length > 0) {
|
|
1352
2102
|
// Scorro gli ordinamenti che avevo salvato e ricreo la ColumnsList in base a loro
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
newColList.push(c);
|
|
1357
|
-
});
|
|
1358
|
-
});
|
|
2103
|
+
let newColList = [];
|
|
2104
|
+
view.column_ordering.forEach(co => { this.ColumnsList.forEach(c => { if (c.id == co)
|
|
2105
|
+
newColList.push(c); }); });
|
|
1359
2106
|
this.ColumnsList = newColList;
|
|
1360
2107
|
}
|
|
1361
2108
|
// In ogni caso questo non mi serve più, lo resetto **
|
|
1362
|
-
|
|
2109
|
+
if (this.viewMode)
|
|
2110
|
+
view.savedstate = false;
|
|
1363
2111
|
if (emitChanged)
|
|
1364
2112
|
this.changed();
|
|
1365
2113
|
}
|
|
@@ -1370,20 +2118,22 @@ class EsTableComponent {
|
|
|
1370
2118
|
* @param {'DESC' | 'ASC'} order Nuovo ordine selezionato per la colonna
|
|
1371
2119
|
*/
|
|
1372
2120
|
thOrderChanged(id, order) {
|
|
1373
|
-
if (!this.viewMode) {
|
|
1374
|
-
console.warn('Order changed on a table not in viewMode. Operation not supported');
|
|
2121
|
+
if (!this.viewMode && !this.arrayMode) {
|
|
2122
|
+
console.warn('Order changed on a table not in viewMode or Array mode. Operation not supported');
|
|
1375
2123
|
return;
|
|
1376
2124
|
}
|
|
1377
2125
|
if (!this.OrderByColumn)
|
|
1378
2126
|
return;
|
|
1379
|
-
let
|
|
2127
|
+
let orders = this.viewMode ? this.View.orders : this.arrayOrders;
|
|
1380
2128
|
let orderToAdd = true;
|
|
1381
2129
|
let orderToRemove = null;
|
|
1382
2130
|
// Se per qualche motivo il costruttore non è passato (cache tarpate o simila) fixo
|
|
1383
|
-
if (!
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
2131
|
+
if (!orders && this.viewMode)
|
|
2132
|
+
this.View.orders = [];
|
|
2133
|
+
else if (!orders && this.arrayMode)
|
|
2134
|
+
this.arrayOrders = [];
|
|
2135
|
+
for (let i = 0; i < orders.length; i++) {
|
|
2136
|
+
let t = orders[i];
|
|
1387
2137
|
if (t.id == id) {
|
|
1388
2138
|
if (order) {
|
|
1389
2139
|
t.order = order;
|
|
@@ -1394,27 +2144,46 @@ class EsTableComponent {
|
|
|
1394
2144
|
}
|
|
1395
2145
|
}
|
|
1396
2146
|
if (orderToRemove != null) {
|
|
1397
|
-
|
|
2147
|
+
orders.splice(orderToRemove, 1);
|
|
1398
2148
|
}
|
|
1399
2149
|
else if (orderToAdd) {
|
|
1400
2150
|
if (this.MultipleOrderingDirectives)
|
|
1401
|
-
|
|
1402
|
-
else
|
|
1403
|
-
|
|
2151
|
+
orders.push(new AppOrdering(id, order));
|
|
2152
|
+
else {
|
|
2153
|
+
if (this.viewMode)
|
|
2154
|
+
this.View.orders = [new AppOrdering(id, order)];
|
|
2155
|
+
else if (this.arrayMode)
|
|
2156
|
+
this.arrayOrders = [new AppOrdering(id, order)];
|
|
2157
|
+
}
|
|
1404
2158
|
}
|
|
1405
2159
|
this.onOrderChanged.emit({ id, order });
|
|
1406
|
-
this.
|
|
2160
|
+
if (this.viewMode) {
|
|
2161
|
+
if (this.groupSearchRequestsCache.length > 0)
|
|
2162
|
+
this.emitRowGroupingSearches(id, orders);
|
|
2163
|
+
else
|
|
2164
|
+
this.emitSearchRequest(false);
|
|
2165
|
+
}
|
|
2166
|
+
else if (this.arrayMode)
|
|
2167
|
+
this.internalWriteValue();
|
|
1407
2168
|
}
|
|
1408
2169
|
/**
|
|
1409
2170
|
* Metodo da chiamare ogni volta che si vuole dare evidenza all'esterno del bisogno di rieffettuare la ricerca
|
|
2171
|
+
*
|
|
2172
|
+
* @param {boolean} resetsPage Indica al listener che deve resettare il numero di pagina
|
|
2173
|
+
* @param {AppSearch<any>} viewOverride Override della view da emettere per questa ricerca
|
|
1410
2174
|
*/
|
|
1411
|
-
emitSearchRequest(
|
|
1412
|
-
if (this.viewMode) {
|
|
2175
|
+
emitSearchRequest(resetsPage, viewOverride) {
|
|
2176
|
+
if (this.viewMode && !viewOverride) {
|
|
1413
2177
|
this.View.internalsearchrequest = true;
|
|
1414
2178
|
this.changed();
|
|
1415
2179
|
}
|
|
2180
|
+
if (viewOverride) {
|
|
2181
|
+
if (resetsPage)
|
|
2182
|
+
viewOverride.page = 1;
|
|
2183
|
+
viewOverride.internalsearchrequest = true;
|
|
2184
|
+
}
|
|
1416
2185
|
this.researchInProgress = true;
|
|
1417
|
-
this.onSearchRequest.emit(
|
|
2186
|
+
this.onSearchRequest.emit(viewOverride ? viewOverride : resetsPage);
|
|
1418
2187
|
}
|
|
1419
2188
|
/**
|
|
1420
2189
|
* In base alla visibilità registrata nelle **ColumnsList** questo metodo si occupa di prendere tutti i **EsThs** ed **EsTds** relativi e nasonderli/mostrarli
|
|
@@ -1426,16 +2195,19 @@ class EsTableComponent {
|
|
|
1426
2195
|
* @param {AppSearch<any>} view AppSearch da utilizzare per questa operazione
|
|
1427
2196
|
*/
|
|
1428
2197
|
refreshColumnsVisibility(ths, tds, view) {
|
|
1429
|
-
let columnsCache = {};
|
|
1430
2198
|
let newColset = [];
|
|
1431
2199
|
let fixedThs = {};
|
|
2200
|
+
let columnsCache = {};
|
|
1432
2201
|
for (let coli = 0; coli < this.ColumnsList.length; coli++) {
|
|
1433
2202
|
let col = this.ColumnsList[coli];
|
|
1434
2203
|
columnsCache[col.id] = col;
|
|
1435
2204
|
if (col.visible)
|
|
1436
|
-
newColset.push(col.id);
|
|
2205
|
+
newColset.push((col.pinned ? "§" : "") + col.id);
|
|
1437
2206
|
}
|
|
1438
|
-
view
|
|
2207
|
+
if (view)
|
|
2208
|
+
view.columns = newColset;
|
|
2209
|
+
else
|
|
2210
|
+
this.arrayColumns = newColset;
|
|
1439
2211
|
// Da qui in poi devono essere eseguiti SOLO in fase di writeValue quindi devo assicurarmi di passarli null in tutti i passaggi diversi da quello
|
|
1440
2212
|
if (ths) {
|
|
1441
2213
|
// Definisco se la colonna è visibile in base alla sua rappresentazione locale in ColumnsList
|
|
@@ -1448,7 +2220,7 @@ class EsTableComponent {
|
|
|
1448
2220
|
}
|
|
1449
2221
|
else {
|
|
1450
2222
|
th.thVisible = th.thFixed || (columnsCache[th.th] ? columnsCache[th.th].visible : th.thVisible);
|
|
1451
|
-
if (th.thFixed)
|
|
2223
|
+
if (th.thFixed || th.thGroup)
|
|
1452
2224
|
fixedThs[th.th] = true;
|
|
1453
2225
|
}
|
|
1454
2226
|
}
|
|
@@ -1465,18 +2237,6 @@ class EsTableComponent {
|
|
|
1465
2237
|
}
|
|
1466
2238
|
this.changed();
|
|
1467
2239
|
}
|
|
1468
|
-
/**
|
|
1469
|
-
*
|
|
1470
|
-
*/
|
|
1471
|
-
isEsTd(td) {
|
|
1472
|
-
return !td._directive;
|
|
1473
|
-
}
|
|
1474
|
-
/**
|
|
1475
|
-
*
|
|
1476
|
-
*/
|
|
1477
|
-
isEsTh(th) {
|
|
1478
|
-
return !th._directive;
|
|
1479
|
-
}
|
|
1480
2240
|
/**
|
|
1481
2241
|
* Allinea gli ordinamenti dati fra le **EsThs** e le informazioni all'interno della View bindata
|
|
1482
2242
|
*
|
|
@@ -1484,30 +2244,28 @@ class EsTableComponent {
|
|
|
1484
2244
|
* @param {EsTh[] | EsThDirective[]} ths Colonne della tabella
|
|
1485
2245
|
*/
|
|
1486
2246
|
alignHeadersOrdering(ths, view) {
|
|
1487
|
-
let
|
|
2247
|
+
let orders = view ? view.orders : this.arrayOrders;
|
|
1488
2248
|
for (let i = 0; i < ths.length; i++) {
|
|
1489
2249
|
let th = ths[i];
|
|
1490
2250
|
if (this.isEsTh(th)) {
|
|
1491
2251
|
th.Order = null;
|
|
1492
2252
|
// Assegno tutti gli ordinamenti che mi vengono da AppSearch. Sono i più importanti. Non faccio cache o cose strano perché tanto questa
|
|
1493
2253
|
// variabile sarà sempre massimo 3 elementi
|
|
1494
|
-
for (let i = 0; i <
|
|
1495
|
-
let or =
|
|
2254
|
+
for (let i = 0; i < orders.length; i++) {
|
|
2255
|
+
let or = orders[i];
|
|
1496
2256
|
if (or.id == th.ID)
|
|
1497
2257
|
th.Order = or.order;
|
|
1498
2258
|
}
|
|
1499
2259
|
}
|
|
1500
2260
|
else {
|
|
1501
2261
|
th.thOrder = null;
|
|
1502
|
-
for (let i = 0; i <
|
|
1503
|
-
let or =
|
|
2262
|
+
for (let i = 0; i < orders.length; i++) {
|
|
2263
|
+
let or = orders[i];
|
|
1504
2264
|
if (or.id == th.th)
|
|
1505
2265
|
th.thOrder = or.order;
|
|
1506
2266
|
}
|
|
1507
2267
|
}
|
|
1508
2268
|
}
|
|
1509
|
-
if (researchNeeded)
|
|
1510
|
-
this.emitSearchRequest(false);
|
|
1511
2269
|
}
|
|
1512
2270
|
/**
|
|
1513
2271
|
* Partendo dagli **EsTds** bindati genera, all'interno del dizionario **TMPRowTDs** tutti i contesti dei vari oggetti.
|
|
@@ -1523,6 +2281,11 @@ class EsTableComponent {
|
|
|
1523
2281
|
if (tds.length == 0)
|
|
1524
2282
|
return;
|
|
1525
2283
|
let thsCache = {};
|
|
2284
|
+
let columnsCache = {};
|
|
2285
|
+
for (let coli = 0; coli < this.ColumnsList.length; coli++) {
|
|
2286
|
+
let col = this.ColumnsList[coli];
|
|
2287
|
+
columnsCache[col.id] = col;
|
|
2288
|
+
}
|
|
1526
2289
|
for (let i = 0; i < ths.length; i++) {
|
|
1527
2290
|
let th = ths[i];
|
|
1528
2291
|
thsCache[this.isEsTh(th) ? th.ID : th.th] = th;
|
|
@@ -1535,11 +2298,11 @@ class EsTableComponent {
|
|
|
1535
2298
|
if (this.isEsTd(td)) {
|
|
1536
2299
|
let th = thsCache[td.ID];
|
|
1537
2300
|
if (!!th)
|
|
1538
|
-
th.
|
|
2301
|
+
th._referenced = true;
|
|
1539
2302
|
else
|
|
1540
2303
|
throw "ID dell'oggeto EsTd non compatibile con gli ID dicharati negli EsTh: " + td.ID;
|
|
1541
|
-
let isFixed = (this.isEsTh(th) && th.Fixed) || (!this.isEsTh(th) && th.thFixed);
|
|
1542
|
-
let itemToAdd = { ID: td.ID, Visible: td.Visible, Class: td.Class, Content: td.Content, RouterLink: td.RouterLink, Template: td.Template };
|
|
2304
|
+
let isFixed = (this.isEsTh(th) && th.Fixed) || (!this.isEsTh(th) && (th.thFixed || th.thGroup));
|
|
2305
|
+
let itemToAdd = { GroupAggregation: false, GroupHeader: false, Wraps: true, ID: td.ID, Visible: td.Visible, Class: td.Class, Content: td.Content, RouterLink: td.RouterLink, Template: td.Template };
|
|
1543
2306
|
let ctx = td.Context;
|
|
1544
2307
|
if (this.TMPRowTDs[ctx]) {
|
|
1545
2308
|
if (isFixed)
|
|
@@ -1554,22 +2317,27 @@ class EsTableComponent {
|
|
|
1554
2317
|
}
|
|
1555
2318
|
}
|
|
1556
2319
|
else {
|
|
1557
|
-
for (let i = 0; i < this.
|
|
1558
|
-
let
|
|
2320
|
+
for (let i = 0; i < this.boundSource.length; i++) {
|
|
2321
|
+
let item = this.boundSource[i];
|
|
2322
|
+
let ctx = item._hash;
|
|
1559
2323
|
let key = td.td;
|
|
1560
2324
|
let th = thsCache[td.td];
|
|
1561
2325
|
if (!!th)
|
|
1562
|
-
th.
|
|
2326
|
+
th._referenced = true;
|
|
1563
2327
|
else
|
|
1564
2328
|
throw "ID dell'oggeto EsTd non compatibile con gli ID dicharati negli EsTh: " + td.td;
|
|
1565
|
-
if (td.tdIf) {
|
|
1566
|
-
let
|
|
1567
|
-
let
|
|
2329
|
+
if (td.tdIf || (!this.isEsTh(th) && th.thGroup)) {
|
|
2330
|
+
let thCasted = th;
|
|
2331
|
+
let isFixed = (this.isEsTh(th) && th.Fixed) || (!this.isEsTh(th) && (th.thFixed || th.thGroup || th.thPinned));
|
|
2332
|
+
let itemToAdd = item._item ?
|
|
2333
|
+
{ LeftBorder: thCasted._lbord, RightBorder: thCasted._rbord, ID: key, Pinned: columnsCache[td.td].pinned, PinnedWidth: thCasted.thPinnedWidth, GroupHeader: false, GroupAggregation: false, Visible: columnsCache[td.td].visible, Wraps: false, Class: td.tdClass, Template: thCasted.thGroup && !this.ShowItemGroupsColumns ? null : td.Template } :
|
|
2334
|
+
{ LeftBorder: thCasted._lbord, RightBorder: thCasted._rbord, ID: key, Pinned: columnsCache[td.td].pinned, PinnedWidth: thCasted.thPinnedWidth, GroupHeader: thCasted.thGroup, GroupAggregation: !!thCasted.thAggregation, Visible: columnsCache[td.td].visible, Wraps: false, Class: thCasted.thGroupClass || '', Content: this.getGroupCellDisplay(item, key, th) };
|
|
1568
2335
|
if (this.TMPRowTDs[ctx]) {
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
2336
|
+
// Non serve più grazie al metodo **oveFixedColumnsAtTheBeginning**
|
|
2337
|
+
//if (isFixed)
|
|
2338
|
+
// this.TMPRowTDs[ctx].splice(0 + (contextFixeds[ctx]++), 0, itemToAdd);
|
|
2339
|
+
//else
|
|
2340
|
+
this.TMPRowTDs[ctx].push(itemToAdd);
|
|
1573
2341
|
}
|
|
1574
2342
|
else {
|
|
1575
2343
|
this.RowContexts.push(ctx);
|
|
@@ -1586,7 +2354,7 @@ class EsTableComponent {
|
|
|
1586
2354
|
var errs = [];
|
|
1587
2355
|
for (let i = 0; i < ths.length; i++) {
|
|
1588
2356
|
let th = ths[i];
|
|
1589
|
-
if (!th.
|
|
2357
|
+
if (!th._referenced)
|
|
1590
2358
|
errs.push(this.isEsTh(th) ? th.ID : th.th);
|
|
1591
2359
|
}
|
|
1592
2360
|
if (errs.length > 0) {
|
|
@@ -1606,78 +2374,444 @@ class EsTableComponent {
|
|
|
1606
2374
|
evaluateRowThs(ths) {
|
|
1607
2375
|
if (ths.length == 0)
|
|
1608
2376
|
return;
|
|
2377
|
+
let columnsListCache = {};
|
|
2378
|
+
let castedView = this.View;
|
|
2379
|
+
let groupingsUndefined = this.viewMode && (castedView && !castedView.groupings || castedView.groupings.length == 0);
|
|
2380
|
+
for (let i = 0; i < this.ColumnsList.length; i++) {
|
|
2381
|
+
let itm = this.ColumnsList[i];
|
|
2382
|
+
columnsListCache[itm.id] = itm;
|
|
2383
|
+
}
|
|
1609
2384
|
this.TMPRowTHs = [];
|
|
1610
2385
|
let fixed = 0;
|
|
1611
2386
|
for (let i = 0; i < ths.length; i++) {
|
|
1612
2387
|
let th = ths[i];
|
|
1613
2388
|
let toAdd;
|
|
1614
2389
|
if (this.isEsTh(th)) {
|
|
1615
|
-
toAdd = {
|
|
2390
|
+
toAdd = { Pinned: false, ID: th.ID, Visible: th.Visible, Class: th.Class, Order: th.Order, Orderable: th.Orderable, Template: null, Content: th.Description, Wrap: false };
|
|
1616
2391
|
if (th.Fixed)
|
|
1617
2392
|
this.TMPRowTHs.splice(0 + (fixed++), 0, toAdd);
|
|
1618
2393
|
else
|
|
1619
2394
|
this.TMPRowTHs.push(toAdd);
|
|
1620
2395
|
}
|
|
1621
|
-
else if (th.thIf) {
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
this.
|
|
2396
|
+
else if (th.thIf || th.thGroup) {
|
|
2397
|
+
let thClass = (th.thClass || '') + (th.thGroup ? " est-col-min" : "");
|
|
2398
|
+
toAdd = { Pinned: columnsListCache[th.th].pinned, PinnedWidth: th.thPinnedWidth, ID: th.th, Visible: th.thVisible, Class: thClass, Order: th.thOrder, Orderable: th.thOrderable, Template: th.Template, Content: null, Wrap: false, LeftBorder: th._lbord, RightBorder: th._rbord };
|
|
2399
|
+
this.TMPRowTHs.push(toAdd);
|
|
2400
|
+
// Se ho un modello che deve funzionare a rowgrouping ma non è ancora stata effettuata nessuna ricerca sui gruppi principali (groupingsUndefined)
|
|
2401
|
+
// li genero e mando la prima ricerca che dev'essere spedita al backend per il primo caricamento dei gruppi
|
|
2402
|
+
if (groupingsUndefined && (th.thAggregation || th.thGroup)) {
|
|
2403
|
+
let groupAggregations = this.getGroupAggregations(th);
|
|
2404
|
+
if (!castedView.groupings)
|
|
2405
|
+
castedView.groupings = groupAggregations;
|
|
2406
|
+
else
|
|
2407
|
+
castedView.groupings.push(...groupAggregations);
|
|
2408
|
+
this.ResearchNeeded = true;
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
evaluateHeadersGroupingInfos(ths) {
|
|
2414
|
+
// Pregiro per trovare i parent
|
|
2415
|
+
let parentsCache = {};
|
|
2416
|
+
let thsCache = {};
|
|
2417
|
+
for (let i = 0; i < ths.length; i++) {
|
|
2418
|
+
let th = ths[i];
|
|
2419
|
+
if (this.isEsTh(th))
|
|
2420
|
+
continue;
|
|
2421
|
+
thsCache[th.th] = th;
|
|
2422
|
+
if (th.thParent && !parentsCache[th.thParent])
|
|
2423
|
+
parentsCache[th.thParent] = true;
|
|
2424
|
+
}
|
|
2425
|
+
// Secondo giro per beccare il livello massimo e la lista di foglie (th senza parent)
|
|
2426
|
+
let hMaxLevel = 0;
|
|
2427
|
+
let leafs = [];
|
|
2428
|
+
for (let i = 0; i < ths.length; i++) {
|
|
2429
|
+
let th = ths[i];
|
|
2430
|
+
if (this.isEsTh(th)) {
|
|
2431
|
+
leafs.push(th);
|
|
2432
|
+
continue;
|
|
2433
|
+
}
|
|
2434
|
+
// Se sono una foglia vedo quanti livelli ci sono sopra
|
|
2435
|
+
if (!parentsCache[th.th]) {
|
|
2436
|
+
leafs.push(th);
|
|
2437
|
+
let tmp = this.jumpsToFinalParent(th, thsCache);
|
|
2438
|
+
hMaxLevel = tmp > hMaxLevel ? tmp : hMaxLevel;
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
return { leafs: leafs, groupingLevel: hMaxLevel, parentsCache: parentsCache, thsCache: thsCache };
|
|
2442
|
+
}
|
|
2443
|
+
/**
|
|
2444
|
+
* Genera gli header groups da una lista di info sui th all'interno della variabile **TMPRowThGroups**
|
|
2445
|
+
*/
|
|
2446
|
+
evaluateHeaderGroups(infos) {
|
|
2447
|
+
if (infos.groupingLevel == 0)
|
|
2448
|
+
return;
|
|
2449
|
+
// Giro 2.5, creo l'output dei raggruppamenti per header in modo da non dovermi preoccupare di celle non inizializzate
|
|
2450
|
+
let expandedGroups = [];
|
|
2451
|
+
let visibleUnpinnedLeafs = infos.leafs.filter((t) => t.thVisible && !t.thPinned);
|
|
2452
|
+
for (let l = 0; l < infos.groupingLevel; l++) {
|
|
2453
|
+
expandedGroups.push([]);
|
|
2454
|
+
for (let i = 0; i < visibleUnpinnedLeafs.length; i++)
|
|
2455
|
+
expandedGroups[l].push("");
|
|
2456
|
+
}
|
|
2457
|
+
// Ordino le foglie in base agli ordinamenti delle colonne
|
|
2458
|
+
let orderedLeafs = [];
|
|
2459
|
+
for (let i = 0; i < this.OrderDirectives.length; i++) {
|
|
2460
|
+
let leaf = infos.thsCache[this.OrderDirectives[i]];
|
|
2461
|
+
if (leaf.thVisible && !leaf.thPinned)
|
|
2462
|
+
orderedLeafs.push(leaf);
|
|
2463
|
+
}
|
|
2464
|
+
// Terzo giro per creare l'array group con tutti i riferimenti del caso
|
|
2465
|
+
let currentParent = "";
|
|
2466
|
+
for (let i = 0; i < orderedLeafs.length; i++) {
|
|
2467
|
+
let refTh = orderedLeafs[i];
|
|
2468
|
+
let prevTh = i - 1 >= 0 ? orderedLeafs[i - 1] : null;
|
|
2469
|
+
// Parent diverso da prima, metto il bordo a sinistra e a destra della cella precedente (se c'è)
|
|
2470
|
+
// All'ultimo giro metto il bordo a destra. Tutto questo lo rieseguo per ogni cella in modo da ripulire eventuali a cui avevo assegnato tag precedentemente
|
|
2471
|
+
refTh._lbord = refTh.thParent != currentParent;
|
|
2472
|
+
refTh._rbord = visibleUnpinnedLeafs.length == i + 1;
|
|
2473
|
+
if (prevTh)
|
|
2474
|
+
prevTh._rbord = refTh.thParent != currentParent;
|
|
2475
|
+
currentParent = refTh.thParent;
|
|
2476
|
+
// Per ogni gruppo srotolo il parent nella matrice dei raggruppamenti
|
|
2477
|
+
for (let l = 0; l < infos.groupingLevel; l++) {
|
|
2478
|
+
let parent = refTh.thParent;
|
|
2479
|
+
if (parent && !refTh.thPinned) {
|
|
2480
|
+
expandedGroups[l][i] = parent;
|
|
2481
|
+
refTh = infos.thsCache[parent];
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
// Quarto giro per compattarlo nell'elemento finale su cui bindarmi
|
|
2486
|
+
currentParent = "";
|
|
2487
|
+
let currentSpan = 0;
|
|
2488
|
+
this.TMPRowThGroups = [];
|
|
2489
|
+
for (let l = 0; l < expandedGroups.length; l++) {
|
|
2490
|
+
let levelArray = [];
|
|
2491
|
+
this.TMPRowThGroups.push(levelArray);
|
|
2492
|
+
if (this.Selection || this.HasPinnedColumns)
|
|
2493
|
+
levelArray.push({ Span: 1, Template: null, Pinned: this.HasPinnedColumns });
|
|
2494
|
+
for (let h = 0; h < expandedGroups[l].length; h++) {
|
|
2495
|
+
let item = expandedGroups[l][h];
|
|
2496
|
+
if (item == currentParent)
|
|
2497
|
+
currentSpan++;
|
|
2498
|
+
else {
|
|
2499
|
+
if (currentSpan > 0)
|
|
2500
|
+
levelArray.push({ Span: currentSpan, Template: (currentParent ? infos.thsCache[currentParent].Template : null), Borders: !!currentParent });
|
|
2501
|
+
currentSpan = 1;
|
|
2502
|
+
currentParent = item;
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
// Ultima aggiunta che altrimenti mi rimarrebbe in cache
|
|
2506
|
+
levelArray.push({ Span: currentSpan, Template: (currentParent ? infos.thsCache[currentParent].Template : null), Borders: !!currentParent });
|
|
2507
|
+
if (this.Removal)
|
|
2508
|
+
levelArray.push({ Span: 1, Template: null });
|
|
2509
|
+
if (this.Export || this.HiddenColumns || this.ColumnsOrdering || this.CornerMenuOptions)
|
|
2510
|
+
levelArray.push({ Span: 1, Template: null });
|
|
2511
|
+
currentSpan = 0;
|
|
2512
|
+
currentParent = "";
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
/**
|
|
2516
|
+
* Calcola il numero di salti da un header foglia all'ultimo parent della catena
|
|
2517
|
+
*/
|
|
2518
|
+
jumpsToFinalParent(th, thsCache) {
|
|
2519
|
+
let jumps = 0;
|
|
2520
|
+
let parent = null;
|
|
2521
|
+
do {
|
|
2522
|
+
parent = th.thParent;
|
|
2523
|
+
if (parent)
|
|
2524
|
+
jumps++;
|
|
2525
|
+
th = thsCache[parent];
|
|
2526
|
+
} while (parent);
|
|
2527
|
+
return jumps;
|
|
2528
|
+
}
|
|
2529
|
+
/**
|
|
2530
|
+
* Data una direttiva EsTh restituisce la lista delle aggregazioni richiesta per questa colonna o il gruppo che rappresenta
|
|
2531
|
+
*
|
|
2532
|
+
* @param {EsThDirective} th Direttiva
|
|
2533
|
+
*
|
|
2534
|
+
* @returns {GroupOrAggregation[]} Lista dei gruppi o aggregazioni relativi alla Direttiva passata
|
|
2535
|
+
*/
|
|
2536
|
+
getGroupAggregations(th) {
|
|
2537
|
+
let ret = [];
|
|
2538
|
+
// Es: '{min:dd/MM/yyyy} - {max:dd/MM/yyyy}'
|
|
2539
|
+
if (th.thAggregation) {
|
|
2540
|
+
this.getEsThDirectiveListOfAggregations(th).forEach((agg) => {
|
|
2541
|
+
let isdate = agg.format && ['small', 'long', 'verylong'].includes(agg.format);
|
|
2542
|
+
let isnumber = agg.format && agg.format.startsWith("F") && !Number.isNaN(agg.format.charAt(1)) && agg.format.length == 2;
|
|
2543
|
+
if (!isdate && !isnumber && agg.format)
|
|
2544
|
+
throw "Le aggergazioni supportate dall'es-table sono solo 'small', 'long', 'verylong' per le date e 'F0-9' per i numeri";
|
|
2545
|
+
ret.push(new GroupOrAggregation(th.th, agg.func, isdate ? 'date' : isnumber ? 'number' : 'string'));
|
|
2546
|
+
});
|
|
2547
|
+
}
|
|
2548
|
+
else if (th.thGroup)
|
|
2549
|
+
ret.push(new GroupOrAggregation(th.th, null));
|
|
2550
|
+
return ret;
|
|
2551
|
+
}
|
|
2552
|
+
/**
|
|
2553
|
+
* Data una direttiva con un formato restituisce tutte le coppie Funzione di Aggregazione - Formato
|
|
2554
|
+
*
|
|
2555
|
+
* @param {EsThDirective} th Direttiva EsTh di cui calcolare le funzioni di aggregazione usate
|
|
2556
|
+
*
|
|
2557
|
+
* @returns {{ func: string, format: string }[]} Lista delle funzioni di aggregazione rilevate
|
|
2558
|
+
*/
|
|
2559
|
+
getEsThDirectiveListOfAggregations(th) {
|
|
2560
|
+
if (!th.thAggregation)
|
|
2561
|
+
return [];
|
|
2562
|
+
// Se ho già effettuato questo calcolo per questo th restituisco la versione in cache
|
|
2563
|
+
if (th._thAggregations)
|
|
2564
|
+
return th._thAggregations;
|
|
2565
|
+
let ret = [];
|
|
2566
|
+
let display = th.thAggregation;
|
|
2567
|
+
var matches = display.match(/{[a-zA-Z0-9\/:]*}/gi);
|
|
2568
|
+
if (!matches)
|
|
2569
|
+
return [];
|
|
2570
|
+
matches.forEach(m => {
|
|
2571
|
+
let split = m.split(":");
|
|
2572
|
+
let func = m, format = "";
|
|
2573
|
+
if (split.length > 0) {
|
|
2574
|
+
// Escludo primo e ultimo carattere (le graffe)
|
|
2575
|
+
func = split[0].substr(1);
|
|
2576
|
+
format = split[1].substr(0, split[1].length - 1);
|
|
2577
|
+
}
|
|
2578
|
+
ret.push({ func: func, format: format, match: m });
|
|
2579
|
+
});
|
|
2580
|
+
th._thAggregations = ret;
|
|
2581
|
+
return ret;
|
|
2582
|
+
}
|
|
2583
|
+
/**
|
|
2584
|
+
* Metodo che genera l'ordine di default delle colonne
|
|
2585
|
+
*
|
|
2586
|
+
* @param {AppSearch<any>} view AppSearch da utilizzare per questa operazione
|
|
2587
|
+
*/
|
|
2588
|
+
generateDefaultOrder(ths, view) {
|
|
2589
|
+
if (ths.length == 0)
|
|
2590
|
+
return;
|
|
2591
|
+
let orderings = this.viewMode ? view.column_ordering : this.arrayColumnOrdering;
|
|
2592
|
+
// Genero ordinamento di default da 0 fino a dove deve arrivare. Situazione attuale senza hotpotato
|
|
2593
|
+
if (!orderings || orderings.length == 0) {
|
|
2594
|
+
for (let i = 0; i < ths.length; i++) {
|
|
2595
|
+
let th = ths[i];
|
|
2596
|
+
let order = this.isEsTh(th) ? th.ID : th.th;
|
|
2597
|
+
this.OrderDirectives.push(order);
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
else
|
|
2601
|
+
this.OrderDirectives = orderings;
|
|
2602
|
+
}
|
|
2603
|
+
/**
|
|
2604
|
+
* Applica l'ordine specificato alle varie colonne
|
|
2605
|
+
*
|
|
2606
|
+
* @param {AppSearch<any>} view AppSearch da utilizzare per questa operazione
|
|
2607
|
+
* @param {boolean} finalize Se **true** significa che non mi aspetto di dover effettuare altre operazioni e posso renderizzare la situazione in base ai RowContext
|
|
2608
|
+
* Senza finalize significa che mi aspetto altre operazioni che prima o poi richiameranno questa funzione col finalize.
|
|
2609
|
+
*
|
|
2610
|
+
* Ad esempio, una volta selezionato ordinamento fisico/logico delle colonne so che parte un altra ricerca che mi rivalorizzerà da "writeValue", che già chiama questa funzione.
|
|
2611
|
+
* Mettendo solo la chiamata da "writeValue" come "finalizzante" mi assicuro che smanattamenti a frontend non causino flickering fino a quando non servono
|
|
2612
|
+
*/
|
|
2613
|
+
applyOrdering(view, finalize) {
|
|
2614
|
+
// Genero ordinamento per gli header
|
|
2615
|
+
let newHeaders = [];
|
|
2616
|
+
// Se devo finalizzare aggancio tutte le variabili di bind
|
|
2617
|
+
if (finalize) {
|
|
2618
|
+
this.OrderDirectives.forEach(o => {
|
|
2619
|
+
let heaedrItem = this.TMPRowTHs.filter(t => t.ID == o)[0];
|
|
2620
|
+
if (heaedrItem)
|
|
2621
|
+
newHeaders.push(heaedrItem);
|
|
2622
|
+
});
|
|
2623
|
+
this.TMPRowTHs = newHeaders;
|
|
2624
|
+
// Genero ordinamento per le celle
|
|
2625
|
+
for (let i = 0; i < this.RowContexts.length; i++) {
|
|
2626
|
+
let context = this.TMPRowTDs[this.RowContexts[i]];
|
|
2627
|
+
let newContext = [];
|
|
2628
|
+
this.OrderDirectives.forEach(o => {
|
|
2629
|
+
let contextItem = context.filter(t => t.ID == o)[0];
|
|
2630
|
+
newContext.push(contextItem);
|
|
2631
|
+
});
|
|
2632
|
+
this.TMPRowTDs[this.RowContexts[i]] = newContext;
|
|
1629
2633
|
}
|
|
1630
2634
|
}
|
|
2635
|
+
if (this.viewMode)
|
|
2636
|
+
view.column_ordering = this.OrderDirectives;
|
|
2637
|
+
else
|
|
2638
|
+
this.arrayColumnOrdering = this.OrderDirectives;
|
|
2639
|
+
this.changed();
|
|
2640
|
+
}
|
|
2641
|
+
// #endregion
|
|
2642
|
+
// #region Gestione raggruppamenti per riga
|
|
2643
|
+
/**
|
|
2644
|
+
* Ottiene un elemento di separazione fra Gruppi che serve per paginare le ricerche all'interno di ogni singolo gruppo
|
|
2645
|
+
*
|
|
2646
|
+
* @param {AppSearch<any>} view View utilizzata per la ricerca. Me ne salvo i parametri nel separatore attuale dato che ne ho bisogno per caricare altri elementi
|
|
2647
|
+
* facenti riferimento allo stesso contesto
|
|
2648
|
+
* @param {string} parent Parent path che rappresenta a quale gruppo è affibbiato questo separatore
|
|
2649
|
+
* @param {GroupRouteFragment[]} route Route path che rappresenta a quale gruppo è affibbiato questo separatore
|
|
2650
|
+
* @param {number} level Livello del gruppo di cui questo elemento è separatore, viene usato per applicare la classe "est-lvl-{{level}}"
|
|
2651
|
+
*
|
|
2652
|
+
* @returns {any} Elemento di separazione contenente tutti i bind per presentare una paginazione sotto questo gruppo lato interfaccia
|
|
2653
|
+
*/
|
|
2654
|
+
getGroupSeparator(view, parent, route, level, searches) {
|
|
2655
|
+
let item = new GroupPager(level, route, parent, Object.assign({}, view), searches);
|
|
2656
|
+
item.buttons = this.getPagesArray(6, view.page, view.pages);
|
|
2657
|
+
this.calculateHash([item]);
|
|
2658
|
+
return item;
|
|
2659
|
+
}
|
|
2660
|
+
/**
|
|
2661
|
+
* Sposta la ricerca di una pagina in avanti (o indietro)
|
|
2662
|
+
*
|
|
2663
|
+
* @param {number} page Numero di pagine da aggiungere (o sottrarre, se negativo) alla pagina attuale
|
|
2664
|
+
* @param {any} pager Elemento di separazione su cui è effettuata la ricerca
|
|
2665
|
+
*/
|
|
2666
|
+
addToPageGroup(page, pager) {
|
|
2667
|
+
this.goToPageGroup(pager.view.page + page, pager);
|
|
2668
|
+
}
|
|
2669
|
+
/**
|
|
2670
|
+
* Sposta la ricerca alla pagina specificata
|
|
2671
|
+
*
|
|
2672
|
+
* @param {number} page Pagina a cui navigare
|
|
2673
|
+
* @param {any} pager Elemento di separazione su cui è effettuata la ricerca
|
|
2674
|
+
*/
|
|
2675
|
+
goToPageGroup(page, pager) {
|
|
2676
|
+
let appSearchElement = pager.view;
|
|
2677
|
+
if (page === 0 || page > appSearchElement.pages)
|
|
2678
|
+
return;
|
|
2679
|
+
appSearchElement.page = page;
|
|
2680
|
+
pager.buttons = this.getPagesArray(6, appSearchElement.page, appSearchElement.pages);
|
|
2681
|
+
this.emitSearchRequest(false, appSearchElement);
|
|
2682
|
+
}
|
|
2683
|
+
/**
|
|
2684
|
+
* Data una colonna effettua la riemissione di tutte le ricerche relative.
|
|
2685
|
+
*
|
|
2686
|
+
* Es. Ho 2 campi di gruppo e ho espanso fino a vedere i valori fino ad un livello qualsiasi.
|
|
2687
|
+
* Clicco l'ordinamento sul secondo gruppo.
|
|
2688
|
+
* Tutte le ricerche relative ai primi gruppi devono essere rieseguite. Quando i risultati arriveranno ci penserà il metodo **bindDisplayToLoadedItemsOrGroups**
|
|
2689
|
+
* a tagliare via gli oggetti non più visualizzati
|
|
2690
|
+
*
|
|
2691
|
+
* @param {string} column Colonna su cui si è effettuata un'operazione di ordinamento
|
|
2692
|
+
* @param {AppOrdering[]} orderings Direttive di ordinamento da applicare alle varie sottoricerche
|
|
2693
|
+
*
|
|
2694
|
+
* @todo: Testare
|
|
2695
|
+
*/
|
|
2696
|
+
emitRowGroupingSearches(column, orderings) {
|
|
2697
|
+
// Per tutte le ricerche intermedie che devo rivalutare le re-emitto in modo da aggiornargli i dati
|
|
2698
|
+
var meaningfulAppSearches = this.groupSearchRequestsCache.filter(t => t.group_column == column).map(t => t.view);
|
|
2699
|
+
// Se non ne trovo significa che ho fatto l'ordinamento o sugli item, o su colonne relative a un sottogruppo non caricato
|
|
2700
|
+
if (!meaningfulAppSearches || meaningfulAppSearches.length == 0)
|
|
2701
|
+
meaningfulAppSearches = this.groupSearchRequestsCache.filter(t => !t.group_column).map(t => t.view);
|
|
2702
|
+
// Se non ne trovo qui significa che sto ordinando su colonne relative a un sottogruppo non caricato
|
|
2703
|
+
if (!meaningfulAppSearches || meaningfulAppSearches.length == 0)
|
|
2704
|
+
return;
|
|
2705
|
+
meaningfulAppSearches.forEach(as => {
|
|
2706
|
+
// Ovviamente gli oridnamenti devono essere quelli appena generati
|
|
2707
|
+
as.orders = orderings;
|
|
2708
|
+
as.savedstate = true;
|
|
2709
|
+
this.emitSearchRequest(false, as);
|
|
2710
|
+
});
|
|
2711
|
+
}
|
|
2712
|
+
/**
|
|
2713
|
+
* Helper che calcola il contenuto di una cella relativa a un gruppo riga, tenendo conto del formato delle eventuali aggregazioni
|
|
2714
|
+
*
|
|
2715
|
+
* @param {Group} grp Gruppo di cui mostrare le celle
|
|
2716
|
+
* @param {string} cell Cella attuale di cui calcolare il testo
|
|
2717
|
+
* @param {EsThDirective} header Header relativo alla cella attuale, utilizzata per identificare le informazioni di aggregazione
|
|
2718
|
+
*
|
|
2719
|
+
* @returns {string} Testo finale calcolato per la **cell** corrente, in base alle aggregazioni di **header**
|
|
2720
|
+
*/
|
|
2721
|
+
getGroupCellDisplay(grp, cell, header) {
|
|
2722
|
+
if (grp._sep)
|
|
2723
|
+
return "";
|
|
2724
|
+
let display = header.thAggregation;
|
|
2725
|
+
if (grp.column == cell) {
|
|
2726
|
+
let groupsPart = grp._groupscount ? " - " + grp._groupscount + " " + this.lc.loc("Groups") : "";
|
|
2727
|
+
return grp.value + " (" + grp.count + groupsPart + ")";
|
|
2728
|
+
}
|
|
2729
|
+
else {
|
|
2730
|
+
let agg = grp._aggregationsCache.get(cell);
|
|
2731
|
+
if (!agg)
|
|
2732
|
+
return "";
|
|
2733
|
+
this.getEsThDirectiveListOfAggregations(header).forEach((itm) => {
|
|
2734
|
+
display = display.replace(itm.match, this.formatAggregationValue(agg.get(itm.func), itm.format));
|
|
2735
|
+
});
|
|
2736
|
+
return display;
|
|
2737
|
+
}
|
|
1631
2738
|
}
|
|
1632
2739
|
/**
|
|
1633
|
-
*
|
|
2740
|
+
* Gestisce i click sulla tabella solo per le righe a gruppo.
|
|
2741
|
+
* O rimuove gli elementi attualmente presenti o carica il contenuto del gruppo
|
|
1634
2742
|
*
|
|
1635
|
-
* @param {
|
|
2743
|
+
* @param {any} group Gruppo bindato su cui si è effettuato il click
|
|
2744
|
+
*
|
|
2745
|
+
* @returns {boolean} **true** se l'operaizone è andata a buon fine, **false** altrimenti
|
|
1636
2746
|
*/
|
|
1637
|
-
|
|
1638
|
-
|
|
2747
|
+
handleGroupClick(group) {
|
|
2748
|
+
let casted = this.View;
|
|
2749
|
+
let anyG = group;
|
|
2750
|
+
anyG._expanded = !anyG._expanded;
|
|
2751
|
+
// Sono in modalità raggruppamento virtuale da array: Espandere significa rendere visibili tutti gli oggetti relativi a questo gruppo, viceversa il contrarre
|
|
2752
|
+
if (this.ArrayGrouping) {
|
|
2753
|
+
let allRelatives = this.boundSource.filter(t => (t._group && ((anyG._expanded && t._parent == anyG._thisKey) || (!anyG._expanded && t._parent && t._parent.startsWith(anyG._thisKey)))) ||
|
|
2754
|
+
(t._item && ((anyG._expanded && t._thisKey == anyG._thisKey) || (!anyG._expanded && t._thisKey.startsWith(anyG._thisKey)))));
|
|
2755
|
+
allRelatives.forEach(t => { t._visible = anyG._expanded; if (t._group)
|
|
2756
|
+
t._expanded = false; });
|
|
1639
2757
|
return;
|
|
1640
|
-
// Genero ordinamento di default da 0 fino a dove deve arrivare. Situazione attuale senza hotpotato
|
|
1641
|
-
if (!view.column_ordering || view.column_ordering.length == 0) {
|
|
1642
|
-
for (let i = 0; i < this.TMPRowTHs.length; i++)
|
|
1643
|
-
this.OrderDirectives.push(this.TMPRowTHs[i].ID);
|
|
1644
2758
|
}
|
|
1645
|
-
|
|
1646
|
-
|
|
2759
|
+
if (anyG._expanded) {
|
|
2760
|
+
// Resetto ipp
|
|
2761
|
+
casted.itemsperpageoverride = 15;
|
|
2762
|
+
if (!casted.requestedgroups)
|
|
2763
|
+
casted.requestedgroups = [new GroupFilter(group.column, group.value)];
|
|
2764
|
+
else {
|
|
2765
|
+
let level = anyG._grouplevel;
|
|
2766
|
+
// se il gruppo cliccato non ha un livello è il primo gruppo, quindi ordinamento unico
|
|
2767
|
+
// altrimenti devo rimuovere tutti i filtri su livelli superiori al level cliccato e aggiungere il level cliccato
|
|
2768
|
+
if (!level)
|
|
2769
|
+
casted.requestedgroups = [new GroupFilter(group.column, group.value)];
|
|
2770
|
+
else {
|
|
2771
|
+
casted.requestedgroups = [];
|
|
2772
|
+
anyG._parentRoute.forEach((step) => {
|
|
2773
|
+
casted.requestedgroups.push(new GroupFilter(step.column, step.value));
|
|
2774
|
+
});
|
|
2775
|
+
casted.requestedgroups.push(new GroupFilter(group.column, group.value));
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
this.changed();
|
|
2779
|
+
this.emitSearchRequest(true);
|
|
2780
|
+
}
|
|
2781
|
+
else {
|
|
2782
|
+
let path = (anyG._parent || '') + group.value;
|
|
2783
|
+
// Se ho chiuso un gruppo non mi serve rieffettuare ricerce, mi basta eliminare dagli oggetti bindati tutti gli elementi sottostanti a quel gruppo
|
|
2784
|
+
this.boundSource = this.boundSource.filter(t => !t._parent || !t._parent.startsWith(path));
|
|
2785
|
+
// devo però anche rimuovere eventuali cache relative
|
|
2786
|
+
this.groupSearchRequestsCache = this.groupSearchRequestsCache.filter(t => t.path != path);
|
|
2787
|
+
}
|
|
2788
|
+
return true;
|
|
1647
2789
|
}
|
|
1648
2790
|
/**
|
|
1649
|
-
*
|
|
2791
|
+
* Funzione che dato un valore lo formatta in base al tipo
|
|
1650
2792
|
*
|
|
1651
|
-
* @param {
|
|
1652
|
-
* @param {
|
|
1653
|
-
* Senza finalize significa che mi aspetto altre operazioni che prima o poi richiameranno questa funzione col finalize.
|
|
2793
|
+
* @param {string} value Valore che generalemnte può essere una data o un numero
|
|
2794
|
+
* @param {string} fromat Formato su cui formattare il valore. Può essere ad esempio "small", "long" "verylong" per le date o F{0-9} per i numeri decimali
|
|
1654
2795
|
*
|
|
1655
|
-
*
|
|
1656
|
-
* Mettendo solo la chiamata da "writeValue" come "finalizzante" mi assicuro che smanattamenti a frontend non causino flickering fino a quando non servono
|
|
2796
|
+
* @returns {string} Valore dell'aggregazione formattato come si deve
|
|
1657
2797
|
*/
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
if (
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
for (let i = 0; i < this.RowContexts.length; i++) {
|
|
1670
|
-
let context = this.TMPRowTDs[this.RowContexts[i]];
|
|
1671
|
-
let newContext = [];
|
|
1672
|
-
this.OrderDirectives.forEach(o => {
|
|
1673
|
-
let contextItem = context.filter(t => t.ID == o)[0];
|
|
1674
|
-
newContext.push(contextItem);
|
|
1675
|
-
});
|
|
1676
|
-
this.TMPRowTDs[this.RowContexts[i]] = newContext;
|
|
1677
|
-
}
|
|
2798
|
+
formatAggregationValue(value, format) {
|
|
2799
|
+
if (!format)
|
|
2800
|
+
return value;
|
|
2801
|
+
let isNumber = !Number.isNaN(value) && (!format || format.startsWith("F"));
|
|
2802
|
+
if (isNumber && format.startsWith("F") && !Number.isNaN(format.substr(1)))
|
|
2803
|
+
return parseFloat(value).toFixed(parseInt(format.substr(1)));
|
|
2804
|
+
let date = null;
|
|
2805
|
+
// Alcune versione di extensions rischiano di crashare con cose non date... è stato risolto dopo quindi questo try - catch in realtà
|
|
2806
|
+
// torna utile solo con versioni vecchie/deprecate della libreria @esfaenza/extensions
|
|
2807
|
+
try {
|
|
2808
|
+
date = this.dateExts.getDateConvertion(value);
|
|
1678
2809
|
}
|
|
1679
|
-
|
|
1680
|
-
|
|
2810
|
+
catch (_a) { }
|
|
2811
|
+
if (date)
|
|
2812
|
+
return this.dateExts.getFormatted(date, format == 'small', format == 'verylong');
|
|
2813
|
+
// Qui ci finisco sia per input che non sono né date né numeri, sia per formati non riconosciuti
|
|
2814
|
+
return value;
|
|
1681
2815
|
}
|
|
1682
2816
|
// #endregion
|
|
1683
2817
|
// #region Gestione Operaizoni dialog ordinamento/visibilità colonne
|
|
@@ -1688,7 +2822,7 @@ class EsTableComponent {
|
|
|
1688
2822
|
*/
|
|
1689
2823
|
sendUp(columnItem) {
|
|
1690
2824
|
let itemIndex = this.TMPColumnsList.indexOf(columnItem);
|
|
1691
|
-
if (this.TMPColumnsList[itemIndex - 1].fixed)
|
|
2825
|
+
if (this.TMPColumnsList[itemIndex - 1].fixed || this.TMPColumnsList[itemIndex - 1].pinned)
|
|
1692
2826
|
return;
|
|
1693
2827
|
this.utiExts.swap(this.TMPColumnsList, itemIndex, itemIndex - 1);
|
|
1694
2828
|
// Non posso fare JSON.parse(JSON.stringify(this.ColumnsList)) perché contiene riferimenti a TemplateRef
|
|
@@ -1709,6 +2843,25 @@ class EsTableComponent {
|
|
|
1709
2843
|
this.TMPColumnsList.forEach(c => { tmp.push(Object.assign({}, c)); });
|
|
1710
2844
|
this.TMPColumnsList = tmp;
|
|
1711
2845
|
}
|
|
2846
|
+
/**
|
|
2847
|
+
* All'interno della dialog "Ordinamento e Visibilità Colonne" pinna la colonna specificata
|
|
2848
|
+
*
|
|
2849
|
+
* @param {EsTableColumn} columnItem Colonna da spostare
|
|
2850
|
+
*/
|
|
2851
|
+
pinOrUnpinColumn(columnItem) {
|
|
2852
|
+
let itemIndex = this.TMPColumnsList.indexOf(columnItem);
|
|
2853
|
+
// Sposto la colonna alla fine di tutte quelle pinnate. La cosa funziona in entrambi sensi:
|
|
2854
|
+
// 1) Se sto pinnando, devo metterla come ultima pinnata
|
|
2855
|
+
// 2) Se sto spinnando devo metterla come prima non pinnata
|
|
2856
|
+
// Coincidenza vuole che il punto 1 e 2 siano equivalenti
|
|
2857
|
+
for (let i = 0; i < this.TMPColumnsList.length; i++) {
|
|
2858
|
+
if (!this.TMPColumnsList[i].pinned) {
|
|
2859
|
+
this.arrayMove(this.TMPColumnsList, itemIndex, i);
|
|
2860
|
+
break;
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
columnItem.pinned = !columnItem.pinned;
|
|
2864
|
+
}
|
|
1712
2865
|
/**
|
|
1713
2866
|
* All'interno della dialog "Ordinamento e Visibilità Colonne" inverte le impostazioni di visibilità della colonna
|
|
1714
2867
|
*
|
|
@@ -1767,12 +2920,12 @@ class EsTableComponent {
|
|
|
1767
2920
|
// Non permetto di non selezionare nulla
|
|
1768
2921
|
if (this.TMPColumnsList.every(t => !t.visible))
|
|
1769
2922
|
return false;
|
|
1770
|
-
let castedView = this.View;
|
|
2923
|
+
let castedView = this.viewMode ? this.View : null;
|
|
1771
2924
|
this.ColumnsList = [];
|
|
1772
2925
|
this.TMPColumnsList.forEach(c => { this.ColumnsList.push(Object.assign({}, c)); });
|
|
1773
2926
|
this.refreshColumnOrdering();
|
|
1774
|
-
this.refreshColumnsVisibility(null, null, castedView);
|
|
1775
2927
|
this.applyOrdering(castedView, false);
|
|
2928
|
+
this.refreshColumnsVisibility(null, null, castedView);
|
|
1776
2929
|
//Salvo le preferences di questa view
|
|
1777
2930
|
//Di default registro ordinamento e visibilità delle colonne nella vista. Solo le cose di UI
|
|
1778
2931
|
if (this.SavePreferences) {
|
|
@@ -1784,11 +2937,17 @@ class EsTableComponent {
|
|
|
1784
2937
|
console.error("Non posso utilizzare le preference senza che il pacchetto @esfaenza/preferences sia installato");
|
|
1785
2938
|
return false;
|
|
1786
2939
|
}
|
|
1787
|
-
|
|
2940
|
+
let columns = this.arrayMode ? this.arrayColumns : castedView.columns;
|
|
2941
|
+
let columnsOrderings = this.arrayMode ? this.arrayColumnOrdering : castedView.column_ordering;
|
|
2942
|
+
var toStore = { columns: JSON.parse(JSON.stringify(columns)), column_ordering: JSON.parse(JSON.stringify(columnsOrderings)) };
|
|
1788
2943
|
this.prefService.store(this.ngControl.name, toStore);
|
|
1789
2944
|
}
|
|
2945
|
+
// Rieseguo l'ultima ricerca bindata alla tabella
|
|
1790
2946
|
// Mi assicuro di farlo dopo l'espansione del changed o rischio che la ricerca mi ridia colonne che in realtà non esistono
|
|
1791
|
-
|
|
2947
|
+
if (this.viewMode)
|
|
2948
|
+
setTimeout(() => { this.emitSearchRequest(false); });
|
|
2949
|
+
else if (this.arrayMode)
|
|
2950
|
+
setTimeout(() => { this.internalWriteValue(); });
|
|
1792
2951
|
// Lo vorrei mettere lato template ma no
|
|
1793
2952
|
this.lastSelectedItemID = null;
|
|
1794
2953
|
return true;
|
|
@@ -1797,7 +2956,8 @@ class EsTableComponent {
|
|
|
1797
2956
|
* Sul click nella checkbox di selezione globale si scorrono tutte le colonne e si impostano al valore della check globale
|
|
1798
2957
|
*/
|
|
1799
2958
|
globalColVisCheckChanged() {
|
|
1800
|
-
this.TMPColumnsList.forEach(t => { t.
|
|
2959
|
+
this.TMPColumnsList.forEach(t => { if (!t.fixed)
|
|
2960
|
+
t.visible = this.globalColVisCheck; });
|
|
1801
2961
|
}
|
|
1802
2962
|
// #endregion
|
|
1803
2963
|
// #region Gestione data source gerarchici
|
|
@@ -1845,9 +3005,9 @@ class EsTableComponent {
|
|
|
1845
3005
|
let obj = objs[i];
|
|
1846
3006
|
// Se la parentKey non è valorizzata, questo è il livello 0 (1... perché gli 0 son perciolosi)
|
|
1847
3007
|
if (!obj[this.ParentKey] && levelToAssign == 1) {
|
|
1848
|
-
obj.
|
|
1849
|
-
obj.
|
|
1850
|
-
obj.
|
|
3008
|
+
obj._level = 1;
|
|
3009
|
+
obj._visible = true;
|
|
3010
|
+
obj._expanded = this.StartsExpanded;
|
|
1851
3011
|
assigned++;
|
|
1852
3012
|
continue;
|
|
1853
3013
|
}
|
|
@@ -1857,13 +3017,13 @@ class EsTableComponent {
|
|
|
1857
3017
|
for (let p = 0; p < objs.length; p++) {
|
|
1858
3018
|
let possibleParent = objs[p];
|
|
1859
3019
|
// Trovato il parent dell'item, assegno all'item il livello giusto
|
|
1860
|
-
if (possibleParent[this.OwnKey] == obj[this.ParentKey] && possibleParent.
|
|
1861
|
-
obj.
|
|
3020
|
+
if (possibleParent[this.OwnKey] == obj[this.ParentKey] && possibleParent._level == levelToAssign - 1) {
|
|
3021
|
+
obj._level = levelToAssign;
|
|
1862
3022
|
// So che questo item ha un parent. Ribadisco che il parent è espanso in base alle impostazione e stessa logica
|
|
1863
3023
|
// per la visibilità del figlio
|
|
1864
|
-
possibleParent.
|
|
3024
|
+
possibleParent._expanded = this.StartsExpanded;
|
|
1865
3025
|
possibleParent.parent = true;
|
|
1866
|
-
obj.
|
|
3026
|
+
obj._visible = this.StartsExpanded;
|
|
1867
3027
|
assigned++;
|
|
1868
3028
|
break;
|
|
1869
3029
|
}
|
|
@@ -1882,12 +3042,12 @@ class EsTableComponent {
|
|
|
1882
3042
|
let obj = this.boundSource[i];
|
|
1883
3043
|
// Trovo il parent con quell'id e lo espando
|
|
1884
3044
|
if (obj[this.OwnKey] == key) {
|
|
1885
|
-
obj.
|
|
3045
|
+
obj._expanded = true;
|
|
1886
3046
|
for (let ic = 0; ic < this.boundSource.length; ic++) {
|
|
1887
3047
|
let child = this.boundSource[ic];
|
|
1888
3048
|
// Trovo tutti i child di quel parent e li rendo visibili
|
|
1889
3049
|
if (child[this.ParentKey] == key)
|
|
1890
|
-
child.
|
|
3050
|
+
child._visible = true;
|
|
1891
3051
|
}
|
|
1892
3052
|
return;
|
|
1893
3053
|
}
|
|
@@ -1903,7 +3063,7 @@ class EsTableComponent {
|
|
|
1903
3063
|
let obj = this.boundSource[i];
|
|
1904
3064
|
// Trovo il parent con quell'id e lo collasso
|
|
1905
3065
|
if (obj[this.OwnKey] == key) {
|
|
1906
|
-
obj.
|
|
3066
|
+
obj._expanded = false;
|
|
1907
3067
|
// Collasso/nascondo tutti i child del parent
|
|
1908
3068
|
this.collapseChildOfParent(key);
|
|
1909
3069
|
return;
|
|
@@ -1921,23 +3081,113 @@ class EsTableComponent {
|
|
|
1921
3081
|
// Trovo tutti i child di quel parent e li rendo invisibili. Se il child trovato è a sua volta un parent,
|
|
1922
3082
|
// lo collasso e vado in ricorsione sui figli
|
|
1923
3083
|
if (child[this.ParentKey] == parentKey && !child.parent)
|
|
1924
|
-
child.
|
|
3084
|
+
child._visible = false;
|
|
1925
3085
|
else if (child[this.ParentKey] == parentKey && child.parent) {
|
|
1926
|
-
child.
|
|
1927
|
-
child.
|
|
3086
|
+
child._expanded = false;
|
|
3087
|
+
child._visible = false;
|
|
1928
3088
|
this.collapseChildOfParent(child[this.OwnKey]);
|
|
1929
3089
|
}
|
|
1930
3090
|
}
|
|
1931
3091
|
}
|
|
1932
3092
|
// #endregion
|
|
1933
3093
|
// #region Gestione Selezione
|
|
3094
|
+
/**
|
|
3095
|
+
* Valuta quali elementi devono essere marcati come selezionati nella vista attuale. Si basa sull'oggetto **selection** interno all'AppSearch
|
|
3096
|
+
*
|
|
3097
|
+
* @param {any[]} items Oggetti di cui valutare la selezione
|
|
3098
|
+
* @param {ItemsSelection<any>} selectionItem Oggetti di selezione derivante dalla view o dall'oggetto per Array
|
|
3099
|
+
*/
|
|
3100
|
+
evaluateSelection(items, selectionItem) {
|
|
3101
|
+
if (!selectionItem)
|
|
3102
|
+
return;
|
|
3103
|
+
this.handleSelectionEvaluation(items, selectionItem);
|
|
3104
|
+
}
|
|
3105
|
+
/**
|
|
3106
|
+
* Implementazione agnostica della valutazione delle selezioni degli oggetti. Richiede gli oggetti della vista attuale e l'itemSelector
|
|
3107
|
+
*
|
|
3108
|
+
* @param {any[]} items Oggetti di cui aggiornare lo stato di selezione
|
|
3109
|
+
* @param {ItemsSelection<any>} selectionItem Oggetto contenente lo stato attuale di selezione
|
|
3110
|
+
*/
|
|
3111
|
+
handleSelectionEvaluation(items, selectionItem) {
|
|
3112
|
+
for (let i = 0; i < items.length; i++) {
|
|
3113
|
+
let itm = items[i];
|
|
3114
|
+
let hash = itm._hash;
|
|
3115
|
+
let itemGroup = itm._group ? null : this.getItemGroup(itm);
|
|
3116
|
+
// Reidrato la cache di selezione coi nuovi oggetti altrimenti non riuscirei a beccare gli indici giusti
|
|
3117
|
+
// Dopodiché la uso per calcolare istantaneamente se gli oggetti sono selezionati o no
|
|
3118
|
+
this.rehidrateCache(itm);
|
|
3119
|
+
if (itm._item) {
|
|
3120
|
+
if (selectionItem.all)
|
|
3121
|
+
itm._selected = !this.exclusionsCache.has(hash) && ((!this.groupsCache.has(itemGroup === null || itemGroup === void 0 ? void 0 : itemGroup._hash) && this.itemsCache.has(hash)) || !this.group_exclusionsCache.has(itemGroup === null || itemGroup === void 0 ? void 0 : itemGroup._hash));
|
|
3122
|
+
else
|
|
3123
|
+
itm._selected = !this.exclusionsCache.has(hash) && (this.groupsCache.has(itemGroup === null || itemGroup === void 0 ? void 0 : itemGroup._hash) || this.itemsCache.has(hash) || (this.parentTreeStatus(itemGroup) == 'included' && !this.group_exclusionsCache.has(itemGroup === null || itemGroup === void 0 ? void 0 : itemGroup._hash)));
|
|
3124
|
+
}
|
|
3125
|
+
else if (itm._group) {
|
|
3126
|
+
if (selectionItem.all)
|
|
3127
|
+
itm._selected = !this.group_exclusionsCache.has(hash) && this.parentTreeStatus(itm) != 'excluded';
|
|
3128
|
+
else
|
|
3129
|
+
itm._selected = this.groupsCache.has(hash) || (this.parentTreeStatus(itm) == 'included' && !this.group_exclusionsCache.has(hash));
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3132
|
+
// Se tutti gli oggetti di questa pagina sono solezionati allora posso mettere il global check a true
|
|
3133
|
+
// Se sono in situazione di all-select anche metto la global checkbox, nonostante ci possano essere delle esclusioni
|
|
3134
|
+
this.globalCheck = this.boundSource.filter(t => t._group || t._item).every(t => t._selected);
|
|
3135
|
+
this.canSelectAll = selectionItem.count > 0 && this.SelectAll;
|
|
3136
|
+
// Potrebbe cambiare qualora qualcuno inserisse dati a manazza in modalità Array e desse il refresh manuale alla tabella
|
|
3137
|
+
// Comunque costa 0 quindi mi permetto di refreshare
|
|
3138
|
+
if (this.arrayMode) {
|
|
3139
|
+
let prevSelected = this.selectedObjects;
|
|
3140
|
+
this.finalizeSelectionInformations(selectionItem);
|
|
3141
|
+
if (this.selectedObjects != prevSelected)
|
|
3142
|
+
this.onSelectionChanged.emit(selectionItem);
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
/**
|
|
3146
|
+
* Dato un oggetto trova la cella di cache in cui è registrato e aggiorna il contenuto
|
|
3147
|
+
*
|
|
3148
|
+
* @param {any} item Oggetto da aggiornare
|
|
3149
|
+
*/
|
|
3150
|
+
rehidrateCache(item) {
|
|
3151
|
+
let ctx = item._hash;
|
|
3152
|
+
if (this.itemsCache.has(ctx))
|
|
3153
|
+
this.itemsCache.set(ctx, item);
|
|
3154
|
+
if (this.group_exclusionsCache.has(ctx))
|
|
3155
|
+
this.group_exclusionsCache.set(ctx, item);
|
|
3156
|
+
if (this.groupsCache.has(ctx))
|
|
3157
|
+
this.groupsCache.set(ctx, item);
|
|
3158
|
+
if (this.exclusionsCache.has(ctx))
|
|
3159
|
+
this.exclusionsCache.set(ctx, item);
|
|
3160
|
+
}
|
|
3161
|
+
/**
|
|
3162
|
+
* Dato un gruppo controlla ricorsivamente l'albero di cui fa parte se c'è stata una inclusione o esclusione diretta
|
|
3163
|
+
*
|
|
3164
|
+
* @param {any} grp Gruppo da controllare
|
|
3165
|
+
*
|
|
3166
|
+
* @returns {'none' | 'excluded' | 'included'}
|
|
3167
|
+
* 'none' se non ci sono informazioni su inclusioni o esclusioni
|
|
3168
|
+
* 'included' se il gruppo controllato è stato incluso in maniera esplicita dall'albero dei gruppi padri
|
|
3169
|
+
* 'excluded' se il gruppo controllato è stato escluso in maniera esplicita dall'albero dei gruppi padri
|
|
3170
|
+
*/
|
|
3171
|
+
parentTreeStatus(grp) {
|
|
3172
|
+
if (!grp)
|
|
3173
|
+
return 'none';
|
|
3174
|
+
let parentGroup = this.rgGroupCache.get(grp._parent);
|
|
3175
|
+
if (!parentGroup)
|
|
3176
|
+
return 'none';
|
|
3177
|
+
if (this.group_exclusionsCache.has(parentGroup._hash))
|
|
3178
|
+
return 'excluded';
|
|
3179
|
+
if (this.groupsCache.has(parentGroup._hash))
|
|
3180
|
+
return 'included';
|
|
3181
|
+
return this.parentTreeStatus(parentGroup);
|
|
3182
|
+
}
|
|
1934
3183
|
/**
|
|
1935
3184
|
* Gestisce la selezione globale degli oggetti, sia per pagina che a livello di **SelectAll**
|
|
1936
3185
|
*
|
|
1937
3186
|
* @param {boolean} forcedVal Valore forzato di check da assegnare agli oggetti
|
|
1938
3187
|
*/
|
|
1939
3188
|
globalCheckChanged(forcedVal = null) {
|
|
1940
|
-
|
|
3189
|
+
// Prendo tutti gli elementi presenti in questa vista. Se ho gruppi prendo solo i gruppi a livello 0, altrimenti prendo tutti gli oggetti per selezionarli
|
|
3190
|
+
let items = this.boundSource.find(t => t._group) ? this.boundSource.filter(t => t._group && !t._parent) : this.boundSource;
|
|
1941
3191
|
var itemSelection = this.handleItemsSelection(items, forcedVal, this.globalCheck);
|
|
1942
3192
|
this.changed();
|
|
1943
3193
|
this.onSelectionChanged.emit(itemSelection);
|
|
@@ -1954,14 +3204,14 @@ class EsTableComponent {
|
|
|
1954
3204
|
* @returns {ItemsSelection<any>} Oggetto di selezione aggiornato con le informazioni sull'ultima operazione effettuata
|
|
1955
3205
|
*/
|
|
1956
3206
|
handleItemsSelection(items, forcedVal = null, globalCheck = null) {
|
|
1957
|
-
var _a, _b;
|
|
1958
|
-
let
|
|
3207
|
+
var _a, _b, _c;
|
|
3208
|
+
let si = ((_a = this.View) === null || _a === void 0 ? void 0 : _a.selection) || this.arraymodeSelection;
|
|
1959
3209
|
// Se sono in modalità di selezione singola e devo selezionare un'oggetto, per prima cosa devo deselezionare tutti gli altri
|
|
1960
|
-
if (this.SingleSelection && ((_b = items[0]) === null || _b === void 0 ? void 0 : _b._selected)) {
|
|
3210
|
+
if (this.SingleSelection && ((_b = items[0]) === null || _b === void 0 ? void 0 : _b._selected) && !((_c = items[0]) === null || _c === void 0 ? void 0 : _c._group)) {
|
|
1961
3211
|
if (items.length > 1 && forcedVal == null)
|
|
1962
3212
|
throw "Tentativo di selezionare o deselezionare più di un elemento con SingleSelection attivo";
|
|
1963
3213
|
if (items.length == 1 && forcedVal == null) {
|
|
1964
|
-
|
|
3214
|
+
si = this.handleItemsSelection(this.boundSource.filter(t => !t._group), false, null);
|
|
1965
3215
|
items[0]._selected = true;
|
|
1966
3216
|
}
|
|
1967
3217
|
}
|
|
@@ -1971,59 +3221,343 @@ class EsTableComponent {
|
|
|
1971
3221
|
// Se dev'essere overridato il valore di check effettuo l'override o col valore forzato o col valore globale
|
|
1972
3222
|
if (toChange && !item.locked)
|
|
1973
3223
|
item._selected = forcedVal != null ? forcedVal : this.globalCheck;
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
3224
|
+
// Se il valore non dev'essere variato e vengo da una selezione globale semplicemente evito di effettuare operaizoni inutili. L'item/gruppo è già nello stato giusto
|
|
3225
|
+
if (!toChange && globalCheck != null)
|
|
3226
|
+
continue;
|
|
3227
|
+
let allSelection = si.all;
|
|
3228
|
+
let isGroup = item._group;
|
|
3229
|
+
let isSelection = item._selected;
|
|
3230
|
+
let itemGroup = null, allItems = null, selectedItems = null, unselectedItems = null, allGroups = null, selectedGroups = null, unselectedGroups = null, parentGroupSelected = null, parentGroupUnselected = null;
|
|
3231
|
+
if (isGroup) {
|
|
3232
|
+
let pts = this.parentTreeStatus(item);
|
|
3233
|
+
parentGroupSelected = pts == 'included';
|
|
3234
|
+
parentGroupUnselected = pts == 'excluded';
|
|
3235
|
+
allItems = this.getGroupItems(si, item, null, true);
|
|
3236
|
+
selectedItems = this.getGroupItems(si, item, 'selected', true, allItems);
|
|
3237
|
+
unselectedItems = this.getGroupItems(si, item, 'unselected', true, allItems);
|
|
3238
|
+
allGroups = this.getGroupChildGroups(si, item, null, true);
|
|
3239
|
+
selectedGroups = this.getGroupChildGroups(si, item, 'selected', true, allGroups);
|
|
3240
|
+
unselectedGroups = this.getGroupChildGroups(si, item, 'unselected', true, allGroups);
|
|
1987
3241
|
}
|
|
1988
3242
|
else {
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
// Oggetto selezionato: lo aggiungo alla selezione attuale
|
|
1993
|
-
this.selOrDeselCache[item.hash] = item;
|
|
1994
|
-
selectionItem.items.push(item);
|
|
1995
|
-
}
|
|
1996
|
-
else if (!item._selected && this.selOrDeselCache[item.hash]) {
|
|
1997
|
-
// Oggetto deselezionato: lo rimuovo dalla selezione attuale
|
|
1998
|
-
selectionItem.items.splice(selectionItem.items.indexOf(this.selOrDeselCache[item.hash]), 1);
|
|
1999
|
-
delete this.selOrDeselCache[item.hash];
|
|
2000
|
-
}
|
|
3243
|
+
itemGroup = this.getItemGroup(item);
|
|
3244
|
+
parentGroupSelected = itemGroup == null ? null : itemGroup._selected;
|
|
3245
|
+
parentGroupUnselected = itemGroup == null ? null : !itemGroup._selected;
|
|
2001
3246
|
}
|
|
3247
|
+
if (!this.ArrayGrouping)
|
|
3248
|
+
this.performSelectionOperations(si, item, allSelection, isGroup, isSelection, selectedItems, selectedGroups, unselectedItems, unselectedGroups, allItems, allGroups, parentGroupSelected, parentGroupUnselected);
|
|
3249
|
+
else
|
|
3250
|
+
this.performSimpleSelectionOperations(si, item, isGroup, isSelection, itemGroup, selectedItems, unselectedItems, allItems, allGroups);
|
|
2002
3251
|
}
|
|
2003
3252
|
// Imposto il check globale in base a se tutti gli elementi sono selezionati o meno.
|
|
2004
3253
|
// Evito di fare queste operazioni se la selezione deriva proprio dal global Check
|
|
2005
|
-
// Non è ottimizzatissimo mettere 2 some ma scrivere questo codice a for sono tipo 25 righe....
|
|
2006
3254
|
if (globalCheck == null)
|
|
2007
|
-
this.globalCheck = !
|
|
2008
|
-
this.finalizeSelectionInformations(
|
|
2009
|
-
return
|
|
3255
|
+
this.globalCheck = !this.boundSource.some(t => !t._selected && !t._sep);
|
|
3256
|
+
this.finalizeSelectionInformations(si);
|
|
3257
|
+
return si;
|
|
3258
|
+
}
|
|
3259
|
+
/**
|
|
3260
|
+
* Dato L'oggetto di selezione, l'oggetto da selezionare/deselezionare e tutti i parametri del caso effettua le operazioni che servono.
|
|
3261
|
+
*
|
|
3262
|
+
* Logica semplificata rispetto all'originale **performSelectionOperations** per lavorare in una modalità in cui tutti gli elementi sono caricati (**ArrayGrouping** = true)
|
|
3263
|
+
*/
|
|
3264
|
+
performSimpleSelectionOperations(base, item, group, sel, itm_group, sel_itm, desel_itm, all_itms, all_grps) {
|
|
3265
|
+
let tripticItem = this.getTriptic('item', base);
|
|
3266
|
+
if (group) {
|
|
3267
|
+
if (sel) {
|
|
3268
|
+
all_grps.forEach(gr => { gr._selected = true; });
|
|
3269
|
+
if (desel_itm)
|
|
3270
|
+
desel_itm.forEach(el => { el._selected = true; this.addItem(el, tripticItem); });
|
|
3271
|
+
}
|
|
3272
|
+
else {
|
|
3273
|
+
all_grps.forEach(gr => { gr._selected = false; });
|
|
3274
|
+
if (sel_itm)
|
|
3275
|
+
sel_itm.forEach(el => { el._selected = false; this.removeItem(el, tripticItem); });
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3278
|
+
else {
|
|
3279
|
+
if (sel) {
|
|
3280
|
+
this.addItem(item, tripticItem);
|
|
3281
|
+
if (itm_group && all_itms && all_itms.every(t => t._selected))
|
|
3282
|
+
this.selectGroup(itm_group);
|
|
3283
|
+
}
|
|
3284
|
+
else {
|
|
3285
|
+
this.removeItem(item, tripticItem);
|
|
3286
|
+
if (itm_group)
|
|
3287
|
+
itm_group._selected = false;
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
/**
|
|
3292
|
+
* Helper per selezionare un gruppo e, ricorsivamente, se tutti i gruppi sottostanti al parent sono selezionati, selezionare i gruppi padri
|
|
3293
|
+
*
|
|
3294
|
+
* @param {any} group Gruppo da selezionare
|
|
3295
|
+
*/
|
|
3296
|
+
selectGroup(group) {
|
|
3297
|
+
group._selected = true;
|
|
3298
|
+
let parent = this.getGroupParent(group);
|
|
3299
|
+
if (parent && this.getGroupChildGroups(null, parent, null, true).every(t => t._selected))
|
|
3300
|
+
this.selectGroup(parent);
|
|
3301
|
+
}
|
|
3302
|
+
/**
|
|
3303
|
+
* Dato L'oggetto di selezione, l'oggetto da selezionare/deselezionare e tutti i parametri del caso effettua le operazioni che servono.
|
|
3304
|
+
*
|
|
3305
|
+
* La logica di questa funzione è nata essenzialmente da spam di trial & error ed è stata testata solo fino a due livelli di raggruppamento,
|
|
3306
|
+
* qualsiasi cosa vada oltre non è 100% detto che funzioni...
|
|
3307
|
+
*/
|
|
3308
|
+
performSelectionOperations(base, item, all, group, sel, sel_itm, sel_grp, desel_itm, desel_grp, all_itms, all_grps, parent_incl, parent_excl) {
|
|
3309
|
+
let tripticGroup = this.getTriptic('group', base);
|
|
3310
|
+
let tripticItem = this.getTriptic('item', base);
|
|
3311
|
+
let tripticExcl = this.getTriptic('exclusion', base);
|
|
3312
|
+
let tripticgrpExcl = this.getTriptic('group_exclusion', base);
|
|
3313
|
+
if (group) {
|
|
3314
|
+
if (sel) {
|
|
3315
|
+
if (all || parent_incl)
|
|
3316
|
+
this.removeItem(item, tripticgrpExcl);
|
|
3317
|
+
else
|
|
3318
|
+
this.addItem(item, tripticGroup);
|
|
3319
|
+
if (sel_itm)
|
|
3320
|
+
sel_itm.forEach(el => this.removeItem(el, tripticItem));
|
|
3321
|
+
if (sel_grp)
|
|
3322
|
+
sel_grp.forEach(gr => this.removeItem(gr, tripticGroup));
|
|
3323
|
+
if (all_itms)
|
|
3324
|
+
all_itms.forEach(el => { el._selected = true; this.removeItem(el, tripticExcl); });
|
|
3325
|
+
if (all_grps)
|
|
3326
|
+
all_grps.forEach(gr => { gr._selected = true; this.removeItem(gr, tripticgrpExcl); });
|
|
3327
|
+
}
|
|
3328
|
+
else {
|
|
3329
|
+
if (all || parent_incl)
|
|
3330
|
+
this.addItem(item, tripticgrpExcl);
|
|
3331
|
+
else
|
|
3332
|
+
this.removeItem(item, tripticGroup);
|
|
3333
|
+
if (desel_itm)
|
|
3334
|
+
desel_itm.forEach(el => this.removeItem(el, tripticExcl));
|
|
3335
|
+
if (desel_grp)
|
|
3336
|
+
desel_grp.forEach(gr => this.removeItem(gr, tripticExcl));
|
|
3337
|
+
if (all_itms)
|
|
3338
|
+
all_itms.forEach(el => { el._selected = false; this.removeItem(el, tripticItem); });
|
|
3339
|
+
if (all_grps)
|
|
3340
|
+
all_grps.forEach(gr => { gr._selected = false; this.removeItem(gr, tripticGroup); });
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
else {
|
|
3344
|
+
if (sel) {
|
|
3345
|
+
if ((parent_excl == null && all) || parent_incl)
|
|
3346
|
+
this.removeItem(item, tripticExcl);
|
|
3347
|
+
else
|
|
3348
|
+
this.addItem(item, tripticItem);
|
|
3349
|
+
}
|
|
3350
|
+
else {
|
|
3351
|
+
if (parent_excl || (!all && parent_excl == null))
|
|
3352
|
+
this.removeItem(item, tripticItem);
|
|
3353
|
+
else
|
|
3354
|
+
this.addItem(item, tripticExcl);
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
/**
|
|
3359
|
+
* Helper per evitare di riscrivere ogni santa volta array.splice(array.indexof(item), 1);
|
|
3360
|
+
*/
|
|
3361
|
+
removeItem(item, triptic) {
|
|
3362
|
+
let index = triptic.index_cache.get(item._hash);
|
|
3363
|
+
if (index != null) {
|
|
3364
|
+
triptic.cache.delete(item._hash);
|
|
3365
|
+
triptic.index_cache.delete(item._hash);
|
|
3366
|
+
triptic.array[index] = null;
|
|
3367
|
+
}
|
|
3368
|
+
return !!index;
|
|
3369
|
+
}
|
|
3370
|
+
/**
|
|
3371
|
+
* Helper per evitare di riscrivere ogni santa volta array.push(item); e la gestione della
|
|
3372
|
+
*/
|
|
3373
|
+
addItem(item, triptic) {
|
|
3374
|
+
if (triptic.index_cache.get(item._hash) == null) {
|
|
3375
|
+
let i = triptic.array.push(item) - 1;
|
|
3376
|
+
triptic.cache.set(item._hash, item);
|
|
3377
|
+
triptic.index_cache.set(item._hash, i);
|
|
3378
|
+
return true;
|
|
3379
|
+
}
|
|
3380
|
+
return false;
|
|
3381
|
+
}
|
|
3382
|
+
/**
|
|
3383
|
+
* Ottiene il trittico di selezione: L'array degli oggetti e le due cache
|
|
3384
|
+
*/
|
|
3385
|
+
getTriptic(subject, base) {
|
|
3386
|
+
switch (subject) {
|
|
3387
|
+
case 'group':
|
|
3388
|
+
return new CacheTriptic(this.groupsCache, this.i_groupsCache, base.groups);
|
|
3389
|
+
case 'item':
|
|
3390
|
+
return new CacheTriptic(this.itemsCache, this.i_itemsCache, base.items);
|
|
3391
|
+
case 'group_exclusion':
|
|
3392
|
+
return new CacheTriptic(this.group_exclusionsCache, this.i_group_exclusionsCache, base.group_exclusions);
|
|
3393
|
+
case 'exclusion':
|
|
3394
|
+
return new CacheTriptic(this.exclusionsCache, this.i_exclusionsCache, base.exclusions);
|
|
3395
|
+
}
|
|
3396
|
+
}
|
|
3397
|
+
/**
|
|
3398
|
+
* Dato un oggetto restituisce il gruppo di cui fa parte, se esiste
|
|
3399
|
+
*
|
|
3400
|
+
* @param {any} item Oggetto di cui trovare il gruppo
|
|
3401
|
+
*/
|
|
3402
|
+
getItemGroup(item) {
|
|
3403
|
+
let parent = this.rgGroupCache.get(item._thisKey);
|
|
3404
|
+
if (parent)
|
|
3405
|
+
return parent;
|
|
3406
|
+
return null;
|
|
3407
|
+
}
|
|
3408
|
+
/**
|
|
3409
|
+
* Data la chiave di un gruppo restituisce tutti gli oggetti con quella chiave
|
|
3410
|
+
*
|
|
3411
|
+
* @param {any} group Chiave da cercare
|
|
3412
|
+
* @param {'selected' | 'unselected'} status Stato degli elementi, selezionati o no
|
|
3413
|
+
* @param {boolean} recursive Indica se cercare solo gli elementi direttamente collegati o se prendere anche quelli dei gruppi figli
|
|
3414
|
+
*
|
|
3415
|
+
* @returns {any[]} Oggetti di tipo **_item** facenti capo alla chiave **groupKey**
|
|
3416
|
+
*/
|
|
3417
|
+
getGroupItems(sel, group, status, recursive = false, allbase = null) {
|
|
3418
|
+
let items = [];
|
|
3419
|
+
if (allbase)
|
|
3420
|
+
items = allbase;
|
|
3421
|
+
else {
|
|
3422
|
+
if (recursive) {
|
|
3423
|
+
// In modalità ricorsiva prendo gli oggetti di tutte le chiavi simili che trovo
|
|
3424
|
+
for (let key of this.rgItemCache.keys())
|
|
3425
|
+
if (key.startsWith(group._thisKey))
|
|
3426
|
+
items.push(...this.rgItemCache.get(key));
|
|
3427
|
+
}
|
|
3428
|
+
else
|
|
3429
|
+
items = this.rgItemCache.get(group._thisKey);
|
|
3430
|
+
}
|
|
3431
|
+
items = items.filter(t => !status || (t._selected && status == 'selected') || (!t._selected && status == 'unselected'));
|
|
3432
|
+
// Non trovo nessun oggetto, però magari di oggetti ne ho all'interno dell'oggetto di selezione.
|
|
3433
|
+
// Questo può essere vero solo se NON sono in modalità array, in caso contrario gli oggetti li devo per forza avere tutti
|
|
3434
|
+
if (items.length != 0 || !sel || this.arrayMode)
|
|
3435
|
+
return items;
|
|
3436
|
+
if (status == 'unselected')
|
|
3437
|
+
items = sel.exclusions.filter(t => t != null &&
|
|
3438
|
+
(!recursive && t._thisKey == group._thisKey) ||
|
|
3439
|
+
(recursive && t._thisKey.startsWith(group._thisKey)));
|
|
3440
|
+
else if (status == 'selected')
|
|
3441
|
+
items = sel.items.filter(t => t != null &&
|
|
3442
|
+
(!recursive && t._thisKey == group._thisKey) ||
|
|
3443
|
+
(recursive && t._thisKey.startsWith(group._thisKey)));
|
|
3444
|
+
return items;
|
|
3445
|
+
}
|
|
3446
|
+
/**
|
|
3447
|
+
* Data la chiave di un gruppo restituisce tutti gli oggetti con quella chiave
|
|
3448
|
+
*
|
|
3449
|
+
* @param {any} group Gruppo di cui cercare il parent
|
|
3450
|
+
*
|
|
3451
|
+
* @returns {any} Oggetto di tipo **_group** rappresentante il parent del **group** attuale
|
|
3452
|
+
*/
|
|
3453
|
+
getGroupParent(group) {
|
|
3454
|
+
let parent = this.rgGroupCache.get(group._parent);
|
|
3455
|
+
if (parent)
|
|
3456
|
+
return parent;
|
|
3457
|
+
return null;
|
|
3458
|
+
}
|
|
3459
|
+
/**
|
|
3460
|
+
* Data la chiave di un gruppo restituisce tutti i gruppi figli
|
|
3461
|
+
*
|
|
3462
|
+
* @param {string} group Gruppo che rappresenta il padre di cui cercare i figli
|
|
3463
|
+
* @param {'selected' | 'unselected'} status Stato dei gruppi, selezionati o no
|
|
3464
|
+
* @param {boolean} recursive Indica se cercare solo i gruppi direttamente collegati o se prendere anche quelli dei gruppi figli
|
|
3465
|
+
*
|
|
3466
|
+
* @returns {any[]} Oggetti di tipo **_group** facenti capo alla chiave **groupKey**
|
|
3467
|
+
*/
|
|
3468
|
+
getGroupChildGroups(sel, group, status, recursive = false, allbase = null) {
|
|
3469
|
+
let thisGroup = this.rgGroupCache.get(group._thisKey);
|
|
3470
|
+
let items = [];
|
|
3471
|
+
if (allbase)
|
|
3472
|
+
items = allbase;
|
|
3473
|
+
else {
|
|
3474
|
+
if (recursive) {
|
|
3475
|
+
// In modalità ricorsiva prendo gli oggetti di tutte le chiavi simili che trovo
|
|
3476
|
+
for (let key of this.rgChildGroupsCache.keys())
|
|
3477
|
+
if (key.startsWith(group._thisKey))
|
|
3478
|
+
items.push(...this.rgChildGroupsCache.get(key));
|
|
3479
|
+
}
|
|
3480
|
+
else
|
|
3481
|
+
items = this.rgChildGroupsCache.get(group._thisKey);
|
|
3482
|
+
}
|
|
3483
|
+
items = items.filter(t => !status || (t._selected && status == 'selected') || (!t._selected && status == 'unselected'));
|
|
3484
|
+
// Non trovo nessun oggetto, però magari di oggetti ne ho all'interno dell'oggetto di selezione
|
|
3485
|
+
if (items.length != 0 || !sel)
|
|
3486
|
+
return items;
|
|
3487
|
+
if (status == 'unselected')
|
|
3488
|
+
items = sel.group_exclusions.filter((t) => t != null && ((!recursive && t._thisRoute.length == thisGroup._thisRoute.length + 1 && t._thisRoute.startsWith(group._thisKey)) ||
|
|
3489
|
+
(recursive && t._thisKey.startsWith(group._thisKey))));
|
|
3490
|
+
else
|
|
3491
|
+
items = sel.groups.filter((t) => t != null && ((!recursive && t._thisRoute.length == thisGroup._thisRoute.length + 1 && t._thisRoute.startsWith(group._thisKey)) ||
|
|
3492
|
+
(recursive && t._thisKey.startsWith(group._thisKey))));
|
|
3493
|
+
return items;
|
|
2010
3494
|
}
|
|
2011
3495
|
/**
|
|
2012
3496
|
* Finalizza le informazioni di selezione del **ItemsSelection** corrente
|
|
2013
3497
|
*/
|
|
2014
3498
|
finalizeSelectionInformations(selectionItem) {
|
|
3499
|
+
// Dato che le delete sono logiche dato che tengo la cache degli indici devo renderle fisiche
|
|
3500
|
+
let tmpGrp = [], tmpItems = [], tmpExcl = [], tmpGrpExcl = [];
|
|
3501
|
+
let grpRemoved = false, itemsRemoved = false, exclRemoved = false, grpExclRemoved = false;
|
|
3502
|
+
for (let i = 0; i < selectionItem.items.length; i++)
|
|
3503
|
+
if (selectionItem.items[i] != null)
|
|
3504
|
+
tmpItems.push(selectionItem.items[i]);
|
|
3505
|
+
else
|
|
3506
|
+
itemsRemoved = true;
|
|
3507
|
+
for (let i = 0; i < selectionItem.groups.length; i++)
|
|
3508
|
+
if (selectionItem.groups[i] != null)
|
|
3509
|
+
tmpGrp.push(selectionItem.groups[i]);
|
|
3510
|
+
else
|
|
3511
|
+
grpRemoved = true;
|
|
3512
|
+
for (let i = 0; i < selectionItem.exclusions.length; i++)
|
|
3513
|
+
if (selectionItem.exclusions[i] != null)
|
|
3514
|
+
tmpExcl.push(selectionItem.exclusions[i]);
|
|
3515
|
+
else
|
|
3516
|
+
exclRemoved = true;
|
|
3517
|
+
for (let i = 0; i < selectionItem.group_exclusions.length; i++)
|
|
3518
|
+
if (selectionItem.group_exclusions[i] != null)
|
|
3519
|
+
tmpGrpExcl.push(selectionItem.group_exclusions[i]);
|
|
3520
|
+
else
|
|
3521
|
+
grpExclRemoved = true;
|
|
3522
|
+
selectionItem.items = tmpItems;
|
|
3523
|
+
selectionItem.group_exclusions = tmpGrpExcl;
|
|
3524
|
+
selectionItem.exclusions = tmpExcl;
|
|
3525
|
+
selectionItem.groups = tmpGrp;
|
|
3526
|
+
// Le cache degli indici potrebbero avere buchi, risolvo
|
|
3527
|
+
if (grpRemoved)
|
|
3528
|
+
this.i_groupsCache = this.compactIndexMap(this.i_groupsCache);
|
|
3529
|
+
if (itemsRemoved)
|
|
3530
|
+
this.i_itemsCache = this.compactIndexMap(this.i_itemsCache);
|
|
3531
|
+
if (exclRemoved)
|
|
3532
|
+
this.i_exclusionsCache = this.compactIndexMap(this.i_exclusionsCache);
|
|
3533
|
+
if (grpExclRemoved)
|
|
3534
|
+
this.i_group_exclusionsCache = this.compactIndexMap(this.i_group_exclusionsCache);
|
|
3535
|
+
// Poi riprendo a fare tutto in normalità
|
|
2015
3536
|
selectionItem.count = this.evaluateSelected();
|
|
2016
3537
|
// Se ho fatto selezione "all" ma poi mi sono messo a togliere tutti gli elementi fino a rimanerne 0 resetto l'oggetto di selezione
|
|
2017
|
-
if (selectionItem.count == 0
|
|
3538
|
+
if (selectionItem.count == 0) {
|
|
3539
|
+
this.boundSource.forEach(t => t._selected = false);
|
|
2018
3540
|
selectionItem.all = false;
|
|
2019
3541
|
selectionItem.exclusions = [];
|
|
2020
3542
|
selectionItem.items = [];
|
|
3543
|
+
selectionItem.groups = [];
|
|
3544
|
+
selectionItem.group_exclusions = [];
|
|
2021
3545
|
// Ripulisco la cache altrimenti mi rimane piena di tutte le esclusioni
|
|
2022
|
-
this.
|
|
3546
|
+
this.clearSelectionCaches();
|
|
2023
3547
|
}
|
|
2024
3548
|
// Se la possibilità di fare "Seleziona tutto" è abilitata allora la considero appena mi viene selezionato qualcosa
|
|
2025
3549
|
this.canSelectAll = selectionItem.count > 0 && this.SelectAll;
|
|
2026
3550
|
}
|
|
3551
|
+
/**
|
|
3552
|
+
* Compatta una cache di indici
|
|
3553
|
+
*/
|
|
3554
|
+
compactIndexMap(map) {
|
|
3555
|
+
let index = 0;
|
|
3556
|
+
let ret = new Map();
|
|
3557
|
+
for (let key of map.keys())
|
|
3558
|
+
ret.set(key, index++);
|
|
3559
|
+
return ret;
|
|
3560
|
+
}
|
|
2027
3561
|
/**
|
|
2028
3562
|
* Gestisce i click sulla tabella, gestendo eventualmente anche gli Shift + Click per selezionare un range di oggetti
|
|
2029
3563
|
*
|
|
@@ -2042,7 +3576,7 @@ class EsTableComponent {
|
|
|
2042
3576
|
let selecteditems = [];
|
|
2043
3577
|
if (event.shiftKey && this.ShiftClick && !this.SingleSelection) {
|
|
2044
3578
|
let startSelecting = false;
|
|
2045
|
-
let items = this.
|
|
3579
|
+
let items = this.boundSource.filter(t => !t._group && !t._sep);
|
|
2046
3580
|
for (let i = 0; i < items.length; i++) {
|
|
2047
3581
|
let t = items[i];
|
|
2048
3582
|
if (startSelecting) {
|
|
@@ -2075,8 +3609,10 @@ class EsTableComponent {
|
|
|
2075
3609
|
*/
|
|
2076
3610
|
evaluateSelected() {
|
|
2077
3611
|
var _a;
|
|
2078
|
-
let
|
|
2079
|
-
|
|
3612
|
+
let si = ((_a = this.View) === null || _a === void 0 ? void 0 : _a.selection) || this.arraymodeSelection;
|
|
3613
|
+
let excByGroup = si.group_exclusions.reduce((prev, curr) => prev + curr.count, 0);
|
|
3614
|
+
let incByGroup = si.groups.reduce((prev, curr) => prev + curr.count, 0);
|
|
3615
|
+
this.selectedObjects = (si.all ? this.BaseItemsCount : incByGroup) - excByGroup + si.items.length - si.exclusions.length;
|
|
2080
3616
|
return this.selectedObjects;
|
|
2081
3617
|
}
|
|
2082
3618
|
/**
|
|
@@ -2084,9 +3620,11 @@ class EsTableComponent {
|
|
|
2084
3620
|
*/
|
|
2085
3621
|
selectAllOrResetSelection() {
|
|
2086
3622
|
let selectionItem = this.View.selection || this.arraymodeSelection;
|
|
2087
|
-
this.
|
|
3623
|
+
this.clearSelectionCaches();
|
|
2088
3624
|
selectionItem.all = !selectionItem.all;
|
|
2089
3625
|
selectionItem.exclusions = [];
|
|
3626
|
+
selectionItem.groups = [];
|
|
3627
|
+
selectionItem.group_exclusions = [];
|
|
2090
3628
|
selectionItem.items = [];
|
|
2091
3629
|
// Ripulisco gli stati UI di selezione globale se l'ho disattivata
|
|
2092
3630
|
if (!selectionItem.all) {
|
|
@@ -2096,7 +3634,7 @@ class EsTableComponent {
|
|
|
2096
3634
|
this.finalizeSelectionInformations(selectionItem);
|
|
2097
3635
|
this.onSelectionChanged.emit(selectionItem);
|
|
2098
3636
|
// Dopo aver resettato direttamente il solo oggetto this.View.selection devo anche riallineare a tutti gli oggetti bindati
|
|
2099
|
-
this.evaluateSelection(this.
|
|
3637
|
+
this.evaluateSelection(this.boundSource, selectionItem);
|
|
2100
3638
|
}
|
|
2101
3639
|
// #endregion
|
|
2102
3640
|
// #region Gestione Paginazione
|
|
@@ -2106,9 +3644,9 @@ class EsTableComponent {
|
|
|
2106
3644
|
* @param {number} page Numero di pagine da aggiungere (o sottrarre, se negativo) alla pagina attuale
|
|
2107
3645
|
*/
|
|
2108
3646
|
addToPage(page) {
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
this.goToPage((this.SearchView ||
|
|
3647
|
+
var _a;
|
|
3648
|
+
let view = this.MainGroupView ? this.MainGroupView : this.View;
|
|
3649
|
+
this.goToPage((((_a = (this.SearchView || view)) === null || _a === void 0 ? void 0 : _a.page) || 0) + page);
|
|
2112
3650
|
}
|
|
2113
3651
|
/**
|
|
2114
3652
|
* Sposta la ricerca alla pagina specificata
|
|
@@ -2116,21 +3654,35 @@ class EsTableComponent {
|
|
|
2116
3654
|
* @param {number} page Pagina a cui navigare
|
|
2117
3655
|
*/
|
|
2118
3656
|
goToPage(page) {
|
|
2119
|
-
|
|
3657
|
+
let view = this.MainGroupView ? this.MainGroupView : this.View;
|
|
3658
|
+
if (!view.page || !view.pages)
|
|
2120
3659
|
return;
|
|
2121
|
-
let appSearchElement = this.SearchView ||
|
|
3660
|
+
let appSearchElement = this.SearchView || view;
|
|
2122
3661
|
if (page === 0 || page > appSearchElement.pages)
|
|
2123
3662
|
return;
|
|
2124
3663
|
appSearchElement.page = page;
|
|
2125
3664
|
this.arrayPulsanti = this.getPagesArray(6, appSearchElement.page, appSearchElement.pages);
|
|
2126
|
-
this.
|
|
3665
|
+
let hasGroupings = !!this.MainGroupView;
|
|
3666
|
+
this.emitSearchRequest(false, hasGroupings ? view : null);
|
|
2127
3667
|
}
|
|
2128
3668
|
/**
|
|
2129
3669
|
* Evento richiamato sul cambio della paginazione. Verrà richiamato l'evento **emitSearchRequest**
|
|
2130
3670
|
* per comunicare al componente che utilizza questa tabella che i dati sono da aggiornare
|
|
2131
3671
|
*/
|
|
2132
|
-
onItemsPerPageChanged() {
|
|
2133
|
-
this.
|
|
3672
|
+
onItemsPerPageChanged(newIpp) {
|
|
3673
|
+
this.PagerOptions.View.itemsperpageoverride = newIpp;
|
|
3674
|
+
this.changed();
|
|
3675
|
+
if (this.MainGroupView)
|
|
3676
|
+
this.emitSearchRequest(true, this.MainGroupView);
|
|
3677
|
+
else
|
|
3678
|
+
this.emitSearchRequest(true);
|
|
3679
|
+
}
|
|
3680
|
+
/**
|
|
3681
|
+
* Evento richiamato sul cambio della paginazione. Verrà richiamato l'evento **emitSearchRequest** con la vista del separatore
|
|
3682
|
+
*/
|
|
3683
|
+
onGroupItemsPerPageChanged(pager, newIpp) {
|
|
3684
|
+
pager.view.itemsperpageoverride = newIpp;
|
|
3685
|
+
this.emitSearchRequest(true, pager.view);
|
|
2134
3686
|
}
|
|
2135
3687
|
// #endregion
|
|
2136
3688
|
// #region Gestione Export
|
|
@@ -2148,6 +3700,10 @@ class EsTableComponent {
|
|
|
2148
3700
|
this.ExportFunction((data, cancel = false) => {
|
|
2149
3701
|
if (cancel)
|
|
2150
3702
|
return;
|
|
3703
|
+
if (data.length == 0) {
|
|
3704
|
+
this.msgExts.simpleWarning(this.lc.loc("Cannot export an empty dataset"));
|
|
3705
|
+
return;
|
|
3706
|
+
}
|
|
2151
3707
|
this.setupExport(data);
|
|
2152
3708
|
this.cdr.detectChanges();
|
|
2153
3709
|
setTimeout(() => { this.exportDownloader.nativeElement.click(); });
|
|
@@ -2273,12 +3829,12 @@ class EsTableComponent {
|
|
|
2273
3829
|
* @returns {any} Router link generato in base al parametri
|
|
2274
3830
|
*/
|
|
2275
3831
|
generateRouterLink(path, parameterProps, item) {
|
|
2276
|
-
if (this.DynamicTableRouterLinkCache[item.
|
|
2277
|
-
return this.DynamicTableRouterLinkCache[item.
|
|
3832
|
+
if (this.DynamicTableRouterLinkCache[item._hash + path]) {
|
|
3833
|
+
return this.DynamicTableRouterLinkCache[item._hash + path];
|
|
2278
3834
|
}
|
|
2279
3835
|
else {
|
|
2280
3836
|
let link = this.getRouterLink(path, parameterProps, item);
|
|
2281
|
-
this.DynamicTableRouterLinkCache[item.
|
|
3837
|
+
this.DynamicTableRouterLinkCache[item._hash + path] = link;
|
|
2282
3838
|
return link;
|
|
2283
3839
|
}
|
|
2284
3840
|
}
|
|
@@ -2376,6 +3932,14 @@ class EsTableComponent {
|
|
|
2376
3932
|
}
|
|
2377
3933
|
// #endregion
|
|
2378
3934
|
// #region Metodi di utilità
|
|
3935
|
+
/** Helper che identifica se il td attuale è di tipo **EsTd**. In caso contrario è da considerarsi **EsTdDirective** */
|
|
3936
|
+
isEsTd(td) {
|
|
3937
|
+
return !td._directive;
|
|
3938
|
+
}
|
|
3939
|
+
/** Helper che identifica se il th attuale è di tipo **EsTh**. In caso contrario è da considerarsi **EsThDirective** */
|
|
3940
|
+
isEsTh(th) {
|
|
3941
|
+
return !th._directive;
|
|
3942
|
+
}
|
|
2379
3943
|
/** Impostazione modalità dell'EsTable */
|
|
2380
3944
|
setMode(mode) {
|
|
2381
3945
|
this.viewMode = mode == 'view';
|
|
@@ -2388,7 +3952,8 @@ class EsTableComponent {
|
|
|
2388
3952
|
}
|
|
2389
3953
|
}
|
|
2390
3954
|
/**
|
|
2391
|
-
* Helper per effettuare chiamate interne di allineamento alla funzione **writeValue**,
|
|
3955
|
+
* Helper per effettuare chiamate interne di allineamento alla funzione **writeValue**,
|
|
3956
|
+
* impostando prima **internalWriteCall** in modo da non effettuare operazioni inutili
|
|
2392
3957
|
*/
|
|
2393
3958
|
internalWriteValue() {
|
|
2394
3959
|
this.internalWriteCall = true;
|
|
@@ -2452,11 +4017,13 @@ class EsTableComponent {
|
|
|
2452
4017
|
for (let i = 0; i < items.length; i++) {
|
|
2453
4018
|
let item = items[i];
|
|
2454
4019
|
// Prima di calcolare l'hash rimuovo le proprietà interne prima che mi scompensino i calcoli successivi
|
|
2455
|
-
|
|
2456
|
-
delete
|
|
2457
|
-
|
|
4020
|
+
let tmp = Object.assign({}, items[i]);
|
|
4021
|
+
delete tmp._selected;
|
|
4022
|
+
delete tmp._visible;
|
|
4023
|
+
delete tmp._hash;
|
|
4024
|
+
let hash = this.hashExts.hashObject(tmp);
|
|
2458
4025
|
usedHashesCache[hash] = usedHashesCache[hash] ? usedHashesCache[hash] + 1 : 1;
|
|
2459
|
-
item.
|
|
4026
|
+
item._hash = hash + (usedHashesCache[hash] > 1 ? "_" + usedHashesCache[hash] : "");
|
|
2460
4027
|
}
|
|
2461
4028
|
}
|
|
2462
4029
|
/**
|
|
@@ -2484,18 +4051,22 @@ EsTableComponent.decorators = [
|
|
|
2484
4051
|
viewProviders: [{ provide: LocalizationService, useClass: EsTableLoc }],
|
|
2485
4052
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2486
4053
|
encapsulation: ViewEncapsulation.None,
|
|
2487
|
-
template: "<!-- Patacchino di autoaggiornamento -->\r\n<div class=\"w-100\" *ngIf=\"AutoUpdate\">\r\n <div class=\"pull-right\">\r\n {{'Update every' | localize : lc}} <input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control est-custom-input\" type=\"text\" [(ngModel)]=\"seconds\" /> {{'second/s' | localize : lc}}\r\n </div>\r\n <div class=\"pull-right m-t-2\">\r\n <label class=\"est-switch\">\r\n <input type=\"checkbox\" [(ngModel)]=\"autoUpdate\" (ngModelChange)=\"autoUpdateChanged();\" />\r\n <div class=\"est-slider round\"></div>\r\n </label>\r\n </div>\r\n</div>\r\n\r\n<!--\r\nI TH sono contenuto statico, questo significa che senza condizione per RowTHs arriverebbero sia qui sia nell ng-container dell'header in fase non inizializzata, duplicando fisicamente le colonne.\r\nPer ovviare al problema, questo pezzo lo faccio apparire solo se ci sono gi\u00E0 dei RowTHs, quindi su valorizzazione della View succeder\u00E0:\r\n1) appaiono i th nell' ng-container dell'header, e NON qui\r\n2) i TH vengono presi, elaborati e trasformati in RowTHs\r\n3) l'ng-container dell'header sparisce (per la condizione !UseCustomCells || !RowTHs) e qui appaiono i nuovi TH (che poi sono gli stessi di prima che girano)\r\n4) Vengono presi i nuovi TH da qui e trasformati a loro volta in RowTHs\r\n-->\r\n<div hidden *ngIf=\"UseCustomCells && RowTHs\">\r\n <ng-container *ngIf=\"View\">\r\n <!--Qui invece ci sono tutti i TH-->\r\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\r\n </ng-container>\r\n</div>\r\n\r\n<!--\r\nQuesta parte \u00E8 un po' pi\u00F9 semplice del sopra. Infatti i TD vengono s\u00EC bindati in entrambi i punti (qui e nell'ng-container del body), ma avr\u00F2 le TD statiche prima di generare la TMPBoundSource.\r\nQuesto significa che il workflow di binding sar\u00E0:\r\n1) Appaiono i TD statici nel body e NON qui, perch\u00E9 i TMPBoundSource non sono ancora stati emessi\r\n2) Contemporaneamente all'emissione dei TMPBoundSource vengono anche emessi i RowTds\r\n3) Considerando il punto 2, al giro dopo appariranno i TD qui, perch\u00E9 \u00E8 stata generata la TMPBoundSource, e spariranno contemporaneamente dall'ng-container del body (per la condizione !UseCustomCells || !RowTDs)\r\n-->\r\n<div hidden *ngIf=\"UseCustomCells && bodyRef\">\r\n <ng-container *ngIf=\"View\">\r\n <!--Tutti i TD che dopo verranno presi ed elaborati internamente-->\r\n <ng-container *ngFor=\"let item of TMPBoundSource\">\r\n <ng-container *ngTemplateOutlet=\"bodyRef; context : {$implicit: item}\"></ng-container>\r\n </ng-container>\r\n </ng-container>\r\n</div>\r\n\r\n<ng-container *ngIf=\"View\">\r\n <div *ngIf=\"FirstBind && ShowLoadingOnBootstrap\" class=\"est-loading-box\">\r\n <div class=\"est-loading-content\">\r\n <span class=\"fa fa-spinner fa-spin\"></span> {{'Performing Table bootstrap' | localize: lc}}...\r\n </div>\r\n </div>\r\n\r\n <div class=\"table-responsive datatable {{Class}}\" [class.est-scrollable]=\"UseEndlessscroll\" (scroll)=\"UseEndlessscroll && onScroll($event)\" [style.max-height.px]=\"MaxHeight\">\r\n <table class=\"{{ TableClass }}\" [class.est-high-density]=\"HighCellDensity\">\r\n <thead [hidden]=\"HeaderHidden || FirstBind\">\r\n\r\n <!-- Aggiungo il pezzo che gestisce la selezione di tutto se attivo da config -->\r\n <tr *ngIf=\"SelectAll\">\r\n <th colspan=\"42\" [class.est-hidden]=\"!canSelectAll && !(View?.selection || arraymodeSelection).all\">\r\n <span>{{ (selectedObjects || 0).toString() + ' ' + ((selectedObjects == 1 ? 'Object Selected' : 'Objects Selected') | localize : lc) }}</span> \r\n <span class=\"app-link app-inline\" (click)=\"selectAllOrResetSelection()\">{{ (View?.selection || arraymodeSelection).all ? ('Reset Selection' | localize : lc) : ('Select Everything' | localize : lc)}}</span>\r\n </th>\r\n </tr>\r\n\r\n <!-- Blocco header group -->\r\n <tr *ngIf=\"HasHeaderGroup\">\r\n <ng-container *ngTemplateOutlet=\"headerGroupRef\"></ng-container>\r\n <th *ngIf=\"Export\"></th>\r\n </tr>\r\n\r\n <!-- Blocco header group secondario -->\r\n <tr *ngIf=\"HasSecondaryHeaderGroup\">\r\n <ng-container *ngTemplateOutlet=\"secondaryHeaderGroupRef\"></ng-container>\r\n <th *ngIf=\"Export\"></th>\r\n </tr>\r\n\r\n <!-- Blocco effettivo degli header -->\r\n <tr>\r\n <!-- Aggiungo una checkbox se la selezione \u00E8 attiva -->\r\n <th class=\"est-col-min\" *ngIf=\"Selection\">\r\n <input *ngIf=\"!SingleSelection\" class=\"est-pointer\" type=\"checkbox\" [disabled]=\"SelectionDisabled\" [(ngModel)]=\"globalCheck\" [ngModelOptions]=\"{'standalone': true}\" (ngModelChange)=\"globalCheckChanged();\">\r\n </th>\r\n\r\n <!-- Header che valgono per view mode e array mode -->\r\n <ng-container *ngIf=\"(viewMode || arrayMode)\">\r\n\r\n <!-- In una tabella base prendo semplicemente i th scritti dall'utente nell'HTML -->\r\n <ng-container *ngIf=\"(!UseCustomCells || !RowTHs) && !DynamicRowColumnsDefinition\">\r\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\r\n </ng-container>\r\n\r\n <!-- Se ho un modello dinamico dell'oggetto creo le colonne in base alle propriet\u00E0 -->\r\n <ng-container *ngIf=\"(!UseCustomCells || !RowTHs) && DynamicRowColumnsDefinition\">\r\n <ng-container *ngFor=\"let operation of DynamicOperations\">\r\n <th class=\"est-col-min est-no-side-padding\"></th>\r\n </ng-container>\r\n \r\n <ng-container *ngFor=\"let rowHeader of DynamicRowColumnsDefinition\">\r\n <ng-container *ngIf=\"rowHeader.visible\">\r\n <th *ngIf=\"OrderByColumn\" es-th=\"{{rowHeader.propertyName}}\" class=\"{{UserDefinedDynamicCols ? rowHeader.clss : ' est-nowrap'}}\" [Order]=\"rowHeader.dataOrder\" [Resizable]=\"ColumnsResizable\" [Orderable]=\"rowHeader.orderable\" [OrderBy]=\"OrderByColumn\" [SearchInProgress]=\"!!researchInProgress\" (onOrderChange)=\"thOrderChanged(rowHeader.propertyName, $event)\">{{rowHeader.description}}</th>\r\n <th *ngIf=\"!OrderByColumn\" es-th=\"{{rowHeader.propertyName}}\" class=\"{{UserDefinedDynamicCols ? rowHeader.clss : ' est-nowrap'}}\" [Order]=\"rowHeader.dataOrder\" [Resizable]=\"ColumnsResizable\" [Orderable]=\"rowHeader.orderable\" [OrderBy]=\"OrderByColumn\">{{rowHeader.description}}</th>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <!-- Se non ho un modello dinamico ma invece delle celle custom, genero gli header in base ai row th -->\r\n <ng-container *ngIf=\"UseCustomCells && RowTHs\">\r\n <ng-container *ngFor=\"let rowHeader of RowTHs\">\r\n <ng-container *ngIf=\"rowHeader && rowHeader.Visible\">\r\n <th es-th=\"{{rowHeader.ID}}\" class=\"{{rowHeader.Class}}{{rowHeader.Wrap ? '' : ' est-nowrap'}}\" [Order]=\"rowHeader.Order\" [Resizable]=\"ColumnsResizable\" [Orderable]=\"rowHeader.Orderable\" [OrderBy]=\"OrderByColumn\" [SearchInProgress]=\"!!researchInProgress\" (onOrderChange)=\"OrderByColumn && thOrderChanged(rowHeader.ID, $event)\">\r\n <ng-container *ngIf=\"rowHeader.Template\">\r\n <ng-container *ngTemplateOutlet=\"rowHeader.Template;\"></ng-container>\r\n </ng-container>\r\n <ng-container *ngIf=\"!rowHeader.Template\">\r\n {{rowHeader.Content}}\r\n </ng-container>\r\n </th>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <!--Casistica in cui ho il setup proveniente da un report. Gli header sono definiti da come \u00E8 fatto il report-->\r\n <ng-container *ngIf=\"reportMode\">\r\n <th [style.color]=\"clm.color\" *ngFor=\"let clm of ReportValues.columns\" class=\"app-no-selection app-pointer est-nowrap\" (click)=\"setupNextOrderAndSearch(clm)\">\r\n {{clm.description}}<span class=\"fa\" [class.fa-chevron-down]=\"clm.order == 'DESC'\" [class.fa-chevron-up]=\"clm.order == 'ASC'\"></span>\r\n </th>\r\n </ng-container>\r\n\r\n <!--Per l'eliminazione mi serve un header aggiuntivo-->\r\n <th *ngIf=\"Removal\" [class.app-right-10]=\"Export || HiddenColumns\" class=\"est-col-min app-sticky-last-column\"><span class=\"fa fa-trash\"></span></th>\r\n\r\n <!--Per l'esportazione mi serve l'header extra da cui faccio uscire i 3 pallocchi-->\r\n <th *ngIf=\"Export || HiddenColumns || ColumnsOrdering || CornerMenuOptions\" class=\"app-table-dotted-menu app-sticky-last-column est-col-min text-sm-center\">\r\n \r\n <!-- Link nascosto che serve a scaricare il file -->\r\n <a *ngIf=\"headers\" hidden #exportDownloader csvLink [data]=\"data\" [headers]=\"headers\" [delimiter]=\"';'\" [filename]=\"ExportFileName\"></a>\r\n\r\n <!-- Blocco con i 3 pallocchi che tira fuori il context menu delle operazioni -->\r\n <div class=\"btn-group\" container=\"body\" placement=\"bottom right\" dropdown #dropdown=\"bs-dropdown\" [autoClose]=\"true\">\r\n <span dropdownToggle class=\"fa fa-ellipsis-v app-fs-18 app-pointer app-padding-3\"></span>\r\n\r\n <div *dropdownMenu class=\"dropdown-menu dropdown-menu-right app-bring-to-front-strong\">\r\n <div class=\"est-pointer\">\r\n <a class=\"dropdown-item\" *ngIf=\"(HiddenColumns || ColumnsOrdering)\" (click)=\"resetColumnVisSelection(); changeColumnVisibilityModal.show();\">\r\n <ng-container *ngIf=\"!HiddenColumns && ColumnsOrdering\">\r\n {{'Columns Order' | localize : lc}}\r\n </ng-container>\r\n <ng-container *ngIf=\"HiddenColumns && !ColumnsOrdering\">\r\n {{'Columns Visibility' | localize : lc}}\r\n </ng-container>\r\n <ng-container *ngIf=\"HiddenColumns && ColumnsOrdering\">\r\n {{'Columns Visibility and Order' | localize : lc}}\r\n </ng-container>\r\n </a>\r\n <a class=\"dropdown-item\" *ngIf=\"Export && CSVExport\" (click)=\"tryExport('CSV')\">{{'Export View' | localize : lc}} (CSV)</a>\r\n <a class=\"dropdown-item\" *ngIf=\"Export && XLSXExport\" (click)=\"tryExport('XLSX')\">{{'Export View' | localize : lc}} (XLSX)</a>\r\n <a class=\"dropdown-item\" *ngFor=\"let option of CornerMenuOptions\" (click)=\"cornerActionClicked(option.id)\">{{option.description}}</a>\r\n </div>\r\n </div>\r\n </div>\r\n </th>\r\n </tr>\r\n </thead>\r\n \r\n <!-- Valido per modalit\u00E0 View o Array. Se sono in report mode il body \u00E8 creato in altro modo -->\r\n <tbody [hidden]=\"BodyHidden || FirstBind\" *ngIf=\"(arrayMode || viewMode)\">\r\n <!--Con selection attiva richiamo il template che gestisce il context menu-->\r\n <ng-container *ngIf=\"Selection\">\r\n <ng-container *ngTemplateOutlet=\"TBodySelection; context: { $implicit: { selDisabled: arrayMode ? false : SelectionDisabled, sel: Selection }}\"></ng-container>\r\n </ng-container>\r\n\r\n <!--Senza selection richiamo il template che NON gestisce il context menu-->\r\n <ng-container *ngIf=\"!Selection\">\r\n <ng-container *ngTemplateOutlet=\"TBody\"></ng-container>\r\n </ng-container>\r\n </tbody>\r\n\r\n <!-- Per la modalit\u00E0 a report c'\u00E8 un body particolare semi-dinamico -->\r\n <tbody [hidden]=\"BodyHidden\" *ngIf=\"reportMode\">\r\n <tr *ngFor=\"let row of ReportValues.rows; let even = even;\">\r\n <td class=\"est-nowrap\" *ngFor=\"let val of row.values\">{{val}}</td>\r\n <td class=\"app-sticky-last-column{{even && !Hierarchy ? '-alt' : ''}}\"></td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <ng-container *ngIf=\"ShowPaging && !FirstBind\">\r\n\r\n <!-- Paginatore dove appare la count e le opzioni di paginazione -->\r\n <div class=\"pull-left m-t-min-3\">\r\n <ng-container *ngIf=\"viewMode\">\r\n <ng-container *ngTemplateOutlet=\"pagerSelector; context: { $implicit: { ShowCount: !HidePagingCount || (View && View.objectcount && View.objectcount != -1), ShowPaging: !HidePaging, View: View, UsesView: true }}\"></ng-container>\r\n </ng-container>\r\n <ng-container *ngIf=\"arrayMode && (!UseArrayModePaging || SearchView)\">\r\n <ng-container *ngTemplateOutlet=\"pagerSelector; context: { $implicit: { ShowCount: !HidePagingCount || (View && View.length) || (SearchView && SearchView.objectcount && SearchView.objectcount != -1), ShowPaging: !HidePaging && SearchView, View: SearchView, SecondaryView: View, UsesView: true }}\"></ng-container>\r\n </ng-container>\r\n <ng-container *ngIf=\"arrayMode && (UseArrayModePaging && !SearchView)\">\r\n <ng-container *ngTemplateOutlet=\"pagerSelector; context: { $implicit: { ShowCount: !HidePagingCount, ShowPaging: !HidePaging && View.length > 10, View: View, UsesView: false }}\"></ng-container>\r\n </ng-container>\r\n <ng-container *ngIf=\"reportMode\">\r\n <ng-container *ngTemplateOutlet=\"pagerSelector; context: { $implicit: { ShowCount: !HidePagingCount || (View && View.objectcount && View.objectcount != -1), ShowPaging: View.pagingavailable, MightBeNoPaging: true, View: View, Report: ReportValues, UsesView: true }}\"></ng-container>\r\n </ng-container>\r\n </div>\r\n \r\n <!-- Pulsanti avanti-indietro di paginazione -->\r\n <div class=\"pull-right btn-toolbar\" *ngIf=\"ShowPaging && !HidePagingButtons\">\r\n <ng-container *ngIf=\"(!reportMode || View?.pagingavailable) && (!arrayMode || SearchView)\">\r\n <ng-container *ngTemplateOutlet=\"pagingButtons; context: { $implicit: { ATP: addToPage.bind(this), GTP: goToPage.bind(this), Array: arrayPulsanti }}\"></ng-container>\r\n </ng-container>\r\n <ng-container *ngIf=\"arrayMode && UseArrayModePaging && !SearchView\">\r\n <ng-container *ngTemplateOutlet=\"pagingButtons; context: { $implicit: { ATP: arrayAddToPage.bind(this), GTP: arrayGoToPage.bind(this), Array: arrayPulsanti }}\"></ng-container>\r\n </ng-container>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n </ng-container>\r\n</ng-container>\r\n\r\n<!-- Template che contiene i pulsanti per cambiare pagina -->\r\n<ng-template #pagingButtons let-options>\r\n <a class=\"btn app-white-button app-no-margin\" (click)=\"options.ATP(-1)\"><span class=\"fa fa-chevron-left\"></span></a>\r\n <div *ngIf=\"options.Array\" class=\"app-inline\">\r\n <a *ngFor=\"let p of options.Array\" class=\"btn {{p.cssClass}} app-no-margin\" (click)=\"options.GTP(p.val)\">{{p.val}}</a>\r\n </div>\r\n <a class=\"btn app-white-button app-no-margin\" (click)=\"options.ATP(1)\"><span class=\"fa fa-chevron-right\"></span></a>\r\n</ng-template>\r\n\r\n<!-- Template che mostra le informazioni base di paginazione: conteggio oggetti, paginazione attuale e pulsanti per cambiarla -->\r\n<ng-template #pagerSelector let-options>\r\n <div *ngIf=\"options.ShowCount\">\r\n {{ CountLabel }}: \r\n <strong *ngIf=\"options.UsesView && !options.Report\">\r\n {{ options.View?.objectcount ? options.View.objectcount : options.SecondaryView && options.SecondaryView.length ? options.SecondaryView.length : \"0\" }}\r\n </strong>\r\n <strong *ngIf=\"!options.UsesView && !options.Report\">\r\n {{ options.View.length ? options.View.length : \"0\" }}\r\n </strong>\r\n <strong *ngIf=\"options.Report\">\r\n {{ options.Report.count && options.Report.count == -1 ? options.Report.rows.length : options.Report.count && options.Report.count > 0 ? options.Report.count : 0 }}\r\n </strong>\r\n </div>\r\n <div *ngIf=\"options.ShowPaging\">\r\n <app-paging *ngIf=\"!options.UsesView\" [Hidden]=\"!options.View || options.View.length == 0\" [WarnOnAll]=\"false\" [CurrentPageSize]=\"ArraymodeItemsPerPage\" (pagingSelected)=\"refreshPaging($event)\"></app-paging>\r\n <app-paging *ngIf=\"options.UsesView\" [AllSearch]=\"AllSearch\" [DefaultAll]=\"defaultAllPageOverride\" [View]=\"options.View\" (pagingSelected)=\"options.View.itemsperpageoverride = $event; changed(); onItemsPerPageChanged();\"></app-paging>\r\n </div>\r\n <div *ngIf=\"options.MightBeNoPaging && !options.ShowPaging\">\r\n <em>{{'Paging options are not available for this report' | localize: lc}}</em>\r\n </div>\r\n</ng-template>\r\n\r\n<!-- Questi due template rappresentano effettivamente il body della tabella. essendo il tr l'unica cosa che davvero cambia, il resto \u00E8 templatizzato -->\r\n<ng-template #TBodySelection let-templateOptions>\r\n <ng-container *ngFor=\"let item of boundSource; let even = even; let i=index;\">\r\n <tr *ngIf=\"item.visible || !Hierarchy\" \r\n [class]=\"item._rowClass ? item._rowClass : ''\" [class.est-line-through]=\"item.removed || item.deleted\" [class.est-pointer]=\"!item.locked\" [class.est-white-selected]=\"item._selected && !item.locked\"\r\n [contextMenu]=\"!item.locked ? (ContextMenu || emptyMenu) : emptyMenu\" [contextMenuSubject]=\"item\"\r\n (click)=\"!item.locked && handleClick($event, item)\">\r\n \r\n <td *ngIf=\"!item.locked\"><input type=\"checkbox\" [disabled]=\"templateOptions.selDisabled\" [class.est-pointer]=\"!item.locked\" [(ngModel)]=\"item._selected\" name=\"check{{i}}\"></td>\r\n <td *ngIf=\"item.locked\"></td>\r\n\r\n <ng-container *ngTemplateOutlet=\"basicColumns; context: { $implicit: item }\"></ng-container>\r\n <ng-container *ngTemplateOutlet=\"dynamicColumns; context: { $implicit: item }\"></ng-container>\r\n <ng-container *ngTemplateOutlet=\"customCells; context: { $implicit: item }\"></ng-container>\r\n <ng-container *ngTemplateOutlet=\"bodyDeleteAndExport; context: { $implicit: { even: even, item: item }}\"></ng-container>\r\n\r\n </tr>\r\n </ng-container>\r\n</ng-template> \r\n\r\n<ng-template #TBody>\r\n <ng-container *ngFor=\"let item of boundSource; let even = even;\">\r\n <tr *ngIf=\"item.visible || !Hierarchy\" [class]=\"item._rowClass ? item._rowClass : ''\" [class.est-line-through]=\"item.removed || item.deleted\">\r\n\r\n <ng-container *ngTemplateOutlet=\"basicColumns; context: { $implicit: item }\"></ng-container>\r\n <ng-container *ngTemplateOutlet=\"dynamicColumns; context: { $implicit: item }\"></ng-container>\r\n <ng-container *ngTemplateOutlet=\"customCells; context: { $implicit: item }\"></ng-container>\r\n <ng-container *ngTemplateOutlet=\"bodyDeleteAndExport; context: { $implicit: { even: even, item: item }}\"></ng-container>\r\n\r\n </tr>\r\n </ng-container>\r\n</ng-template>\r\n\r\n<!-- Questo template contiene la print condizionale su tabelle semplici, con header e body scritti a manazza -->\r\n<ng-template #basicColumns let-item>\r\n <ng-container *ngIf=\"(!UseCustomCells || !RowTDs) && !DynamicRowColumnsDefinition\">\r\n <ng-container *ngTemplateOutlet=\"bodyRef; context : {$implicit: item}\"></ng-container>\r\n </ng-container>\r\n</ng-template>\r\n\r\n<!-- Questo template contiene la print condizionale su tabelle definite in maniera dinamica dal modello -->\r\n<ng-template #dynamicColumns let-item>\r\n <ng-container *ngIf=\"(!UseCustomCells || !RowTDs) && DynamicRowColumnsDefinition\">\r\n <ng-container *ngFor=\"let operation of DynamicOperations; let first = first; let last = last;\">\r\n <ng-container *ngIf=\"!operation.conditionField || (item.properties[operation.conditionField] == operation.conditionValue)\">\r\n <td [class.est-no-right-padding]=\"last\" [class.est-no-left-padding]=\"!first\" class=\"est-col-min\"><span title=\"{{operation.title}}\" class=\"{{operation.iconClass}} app-pointer\" (click)=\"dynamicOperation(item, operation.id)\">{{operation.text}}</span></td>\r\n </ng-container>\r\n <ng-container *ngIf=\"operation.conditionField && (item.properties[operation.conditionField] != operation.conditionValue)\">\r\n <td class=\"est-col-min est-no-side-padding\"></td>\r\n </ng-container>\r\n </ng-container>\r\n <ng-container *ngFor=\"let rowItem of DynamicRowColumnsDefinition\">\r\n <ng-container *ngIf=\"rowItem.routePath && rowItem.visible\">\r\n <td es-td=\"{{rowItem.propertyName}}\" class=\"{{UserDefinedDynamicCols ? rowItem.clss : 'est-nowrap'}}\" [Internal]=\"false\">\r\n <a [routerLink]=\"generateRouterLink(rowItem.routePath, rowItem.routeParameterProperties, item)\" class=\"app-link\" [innerHTML]=\"item.properties[rowItem.propertyName]\"></a>\r\n </td>\r\n </ng-container>\r\n <ng-container *ngIf=\"!rowItem.routePath && rowItem.visible\">\r\n <ng-container *ngTemplateOutlet=\"findEsTd(rowItem.propertyName) || defaultEsTd; context: { $implicit: item.properties[rowItem.propertyName], rowItem : rowItem, item : item }\"> </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n</ng-template>\r\n\r\n<ng-template #defaultEsTd let-value let-rowItem='rowItem' let-item='item'>\r\n <td es-td=\"{{rowItem.propertyName}}\" class=\"{{UserDefinedDynamicCols ? rowItem.clss : 'est-nowrap'}}\"\r\n [class.app-pointer]=\"UseCustomCellActions && CustomCellActionsOn.indexOf('$' + rowItem.propertyName + '$') != -1\"\r\n (click)=\"cellClicked(rowItem.propertyName, item) && !CellActionPropagates && $event.stopPropagation()\"\r\n [Internal]=\"false\">\r\n {{value}}\r\n </td>\r\n</ng-template>\r\n\r\n<!-- Questo template contiene la print condizionale delle celle custom se configurate -->\r\n<ng-template #customCells let-item>\r\n <ng-container *ngIf=\"UseCustomCells && RowTDs\">\r\n <ng-container *ngFor=\"let rowItem of RowTDs[item.hash]; let i = index\">\r\n <ng-container *ngIf=\"rowItem\">\r\n\r\n <ng-container *ngIf=\"!bodyRef && rowItem.Visible\">\r\n <td es-td=\"{{rowItem.ID}}\" class=\"{{rowItem.Class}}\" [class.est-nowrap]=\"Hierarchy\" [Internal]=\"true\">\r\n <ng-container *ngIf=\"rowItem.Template\">\r\n <ng-container *ngTemplateOutlet=\"rowItem.Template; context: { $implicit: item }\"></ng-container>\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"rowItem.RouterLink && rowItem.Visible && bodyRef\">\r\n <td es-td=\"{{rowItem.ID}}\" class=\"{{rowItem.Class}}\" [class.est-nowrap]=\"Hierarchy\" [Internal]=\"true\">\r\n <ng-container *ngIf=\"Hierarchy && i == 0\">\r\n <span *ngIf=\"!item.parent\" class=\"fa fa-chevron-down\" style=\"visibility:hidden\"></span>\r\n <span *ngIf=\"item.parent && item.expanded\" class=\"fa fa-chevron-down est-pointer app-no-selection\" (click)=\"collapseParent(item[this.OwnKey])\"></span>\r\n <span *ngIf=\"item.parent && !item.expanded\" class=\"fa fa-chevron-up est-pointer app-no-selection\" (click)=\"expandParent(item[this.OwnKey])\"></span>\r\n \r\n </ng-container>\r\n <a [routerLink]='rowItem.RouterLink' class=\"app-link\" [innerHTML]=\"rowItem.Content\"></a>\r\n </td>\r\n </ng-container>\r\n <ng-container *ngIf=\"!rowItem.RouterLink && rowItem.Visible && bodyRef\">\r\n <td es-td=\"{{rowItem.ID}}\" class=\"{{rowItem.Class}}\" [class.est-nowrap]=\"Hierarchy\" [class.app-pointer]=\"UseCustomCellActions && CustomCellActionsOn.indexOf('$' + $any(rowItem).ID + '$') != -1\" (click)=\"cellClicked(rowItem.ID, item) && !CellActionPropagates && $event.stopPropagation()\" [Internal]=\"true\">\r\n <ng-container *ngIf=\"Hierarchy && i == 0\">\r\n <span *ngIf=\"!item.parent\" class=\"fa fa-chevron-down\" style=\"visibility:hidden\"></span>\r\n <span *ngIf=\"item.parent && item.expanded\" class=\"fa fa-chevron-down est-pointer app-no-selection\" (click)=\"collapseParent(item[this.OwnKey])\"></span>\r\n <span *ngIf=\"item.parent && !item.expanded\" class=\"fa fa-chevron-up est-pointer app-no-selection\" (click)=\"expandParent(item[this.OwnKey])\"></span>\r\n \r\n </ng-container>\r\n <ng-container *ngIf=\"rowItem.Template\">\r\n <ng-container *ngTemplateOutlet=\"rowItem.Template; context: { $implicit: item }\"></ng-container>\r\n </ng-container>\r\n <span *ngIf=\"!rowItem.Template\" [innerHTML]=\"rowItem.Content\"></span>\r\n </td>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n</ng-template>\r\n\r\n<!-- Questo template contiene i pulsanti di eliminazione/undo eliminazione ed esportazione che vanno in fondo ad un record edlla tabella -->\r\n<ng-template #bodyDeleteAndExport let-options>\r\n <ng-container *ngIf=\"Removal && !RemovalCondition\">\r\n <td class=\"app-sticky-last-column{{options.even? '-alt' : ''}} {{Export || HiddenColumns || CornerMenuOptions ? 'est-right-10' : ''}}\" *ngIf=\"!(options.item.removed || options.item.deleted)\"><span class=\"fa fa-remove app-pointer text-danger\" [hidden]=\"options.item.removable != undefined && !options.item.removable\" (click)=\"onRemoval.emit(options.item)\"></span></td>\r\n <td class=\"app-sticky-last-column{{options.even? '-alt' : ''}} {{Export || HiddenColumns || CornerMenuOptions ? 'est-right-10' : ''}}\" *ngIf=\"(options.item.removed || options.item.deleted)\"><span class=\"fa fa-undo text-warning app-pointer\" (click)=\"onAbortRemoval.emit(options.item)\"></span></td>\r\n </ng-container>\r\n <ng-container *ngIf=\"Removal && RemovalCondition\">\r\n <td class=\"app-sticky-last-column{{options.even? '-alt' : ''}} {{Export || HiddenColumns || CornerMenuOptions ? 'est-right-10' : ''}}\" *ngIf=\"!(options.item.removed || options.item.deleted) && options.item[RemovalCondition]\"><span class=\"fa fa-remove app-pointer text-danger\" [hidden]=\"options.item.removable != undefined && !options.item.removable\" (click)=\"onRemoval.emit(options.item)\"></span></td>\r\n <td class=\"app-sticky-last-column{{options.even? '-alt' : ''}} {{Export || HiddenColumns || CornerMenuOptions ? 'est-right-10' : ''}}\" *ngIf=\"(options.item.removed || options.item.deleted) && options.item[RemovalCondition]\"><span class=\"fa fa-undo text-warning app-pointer\" (click)=\"onAbortRemoval.emit(options.item)\"></span></td>\r\n <td class=\"app-sticky-last-column{{options.even? '-alt' : ''}} {{Export || HiddenColumns || CornerMenuOptions ? 'est-right-10' : ''}}\" *ngIf=\"!options.item[RemovalCondition]\"><span class=\"fa fa-remove app-hidden-view\"></span></td>\r\n </ng-container>\r\n <td *ngIf=\"Export || HiddenColumns || CornerMenuOptions\" class=\"app-sticky-last-column{{options.even && !Hierarchy ? '-alt' : ''}}\"></td>\r\n</ng-template>\r\n\r\n<!-- Context menu vuoto default per tutte le tabella che non ce l'hanno, in modo che al click destro appaia \"nessuna op disponibile\" -->\r\n<context-menu #emptyMenu>\r\n <ng-template contextMenuItem>\r\n <span>\r\n <em>{{'No operations available' | localize : lc}}...</em>\r\n </span>\r\n </ng-template>\r\n</context-menu>\r\n\r\n<!-- Modal per cambiare posizione e visibilit\u00E0 delle colonne dell'es-table -->\r\n<div bsModal #changeColumnVisibilityModal=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <div class=\"modal-dialog modal-lg\">\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h5 class=\"modal-title pull-left\">\r\n <ng-container *ngIf=\"!HiddenColumns && ColumnsOrdering\">\r\n {{'Columns Order' | localize : lc}}\r\n </ng-container>\r\n <ng-container *ngIf=\"HiddenColumns && !ColumnsOrdering\">\r\n {{'Columns Visibility' | localize : lc}}\r\n </ng-container>\r\n <ng-container *ngIf=\"HiddenColumns && ColumnsOrdering\">\r\n {{'Columns Visibility and Order' | localize : lc}}\r\n </ng-container>\r\n </h5>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"changeColumnVisibilityModal.hide();\" aria-label=\"Close\">\r\n <span aria-hidden=\"true\">×</span>\r\n </button>\r\n </div>\r\n <div class=\"modal-body\">\r\n <div *ngIf=\"!TMPColumnsList || TMPColumnsList.length == 0\" class=\"card card-info app-padding-10 app-margin-bottom-0\">\r\n {{'There are no columns configured to be hidden/shown in this view' | localize : lc}}\r\n </div>\r\n <div *ngIf=\"TMPColumnsList && TMPColumnsList.length > 0\" style=\"max-height:500px; overflow-y:auto\">\r\n <!--Aaaaaaah la tristezza... qui mi servirebbe l'es-table per facilitare la selezione multipla ecc... peccato che se la linko qui entro in un loop impressionante-->\r\n <table class=\"table table-striped table-sm app-margin-bottom-0\">\r\n <thead>\r\n <tr>\r\n <th class=\"est-col-min\" *ngIf=\"HiddenColumns\">\r\n <input class=\"est-pointer\" type=\"checkbox\" [(ngModel)]=\"globalColVisCheck\" [ngModelOptions]=\"{'standalone': true}\" (ngModelChange)=\"globalColVisCheckChanged();\">\r\n </th>\r\n <th class=\"est-col-min\" *ngIf=\"ColumnsOrdering\"></th>\r\n <th class=\"est-col-min est-nowrap\">{{'Column Name' | localize : lc}}</th>\r\n <!--Filler-->\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let item of TMPColumnsList; let i = index; let last = last\" class=\"est-pointer\" [class.est-white-selected]=\"lastSelectedItemID == item.id\" [class.est-no-selection]=\"!item.visible\" (click)=\"columnClicked(item);\">\r\n <td *ngIf=\"HiddenColumns\">\r\n <input type=\"checkbox\" [class.est-hidden-view]=\"item.fixed\" class=\"est-pointer\" [(ngModel)]=\"item.visible\" name=\"visible{{i}}\" (ngModelChange)=\"updateGlobalColVisCheck();\" />\r\n </td>\r\n <td class=\"est-nowrap\" *ngIf=\"ColumnsOrdering\">\r\n <span class=\"fa fa-arrow-up\" [class.est-hidden-view]=\"item.fixed\" (click)=\"lastSelectedItemID = item.id; i != 0 && !item.fixed && sendUp(item); $event.stopPropagation();\"></span>\r\n <span class=\"fa fa-arrow-down\" [class.est-hidden-view]=\"item.fixed\" (click)=\"lastSelectedItemID = item.id; !last && !item.fixed && sendDown(item); $event.stopPropagation();\"></span>\r\n </td>\r\n <td class=\"est-nowrap\">\r\n <ng-container *ngIf=\"item.template\">\r\n <ng-container *ngTemplateOutlet=\"item.template\"></ng-container>\r\n </ng-container>\r\n <ng-container *ngIf=\"!item.template\">{{item.description}}</ng-container>\r\n </td>\r\n <!--Filler-->\r\n <td></td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-secondary app-margin-right-10\" (click)=\"lastSelectedItemID = null; changeColumnVisibilityModal.hide();\">{{'Close' | localize : lc}}</button>\r\n <button type=\"button\" [disabled]=\"!TMPColumnsList || TMPColumnsList.length == 0\" class=\"btn btn-primary\" (click)=\"confirmColumnVisibilitySelection() && changeColumnVisibilityModal.hide()\">{{'Confirm' | localize : lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>",
|
|
2488
|
-
styles: [".est-loading-box{height:200px;text-align:center;position:relative;background:#ccc}.est-loading-content{margin:0;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:35px}.est-scrollable{max-height:600px;overflow:auto}.est-pointer{cursor:pointer}.est-high-density td,.est-high-density th{padding:0 .2rem}.est-no-selection{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-ms-user-select:none}.est-hidden-view{visibility:hidden}.est-nowrap{white-space:nowrap}.est-white-selected{background-color:#ddd!important}.est-line-through{text-decoration:line-through}.est-no-side-padding{padding-left:0;padding-right:0}.est-no-left-padding,.est-no-right-padding{padding-left:0}.est-col-min{width:1px}.est-switch{position:relative;display:inline-block;width:30px;height:17px;margin-bottom:0;margin-right:5px;margin-left:5px}.est-switch input{display:none}.est-slider{cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc}.est-slider,.est-slider:before{position:absolute;transition:.4s}.est-slider:before{content:\"\";height:13px;width:13px;left:3px;bottom:2px;background-color:#fff}input:checked+.est-slider{background-color:#2196f3}input:focus+.est-slider{box-shadow:0 0 1px #2196f3}input:checked+.est-slider:before{transform:translateX(11px)}.est-slider.round{border-radius:10px}.est-slider.round:before{border-radius:50%}.est-custom-input{width:30px;display:inline;padding:1px;height:20px}.est-row-lvl-1 td:first-child{padding-left:5px}.est-row-lvl-2 td:first-child{padding-left:20px}.est-row-lvl-3 td:first-child{padding-left:35px}.est-row-lvl-4 td:first-child{padding-left:50px}.est-row-lvl-5 td:first-child{padding-left:65px}.est-row-lvl-6 td:first-child{padding-left:80px}.est-row-lvl-7 td:first-child{padding-left:95px}.est-row-lvl-8 td:first-child{padding-left:110px}.est-row-lvl-9 td:first-child{padding-left:125px}.est-row-lvl-10 td:first-child{padding-left:140px}.est-row-lvl-11 td:first-child{padding-left:155px}.est-row-lvl-12 td:first-child{padding-left:170px}.est-row-lvl-13 td:first-child{padding-left:185px}.est-row-lvl-14 td:first-child{padding-left:200px}.est-row-lvl-15 td:first-child{padding-left:215px}.est-row-lvl-16 td:first-child{padding-left:230px}.est-row-lvl-17 td:first-child{padding-left:245px}.est-row-lvl-18 td:first-child{padding-left:260px}.est-row-lvl-19 td:first-child{padding-left:275px}.est-row-lvl-20 td:first-child{padding-left:290px}.est-row-lvl-21 td:first-child{padding-left:305px}.est-row-lvl-22 td:first-child{padding-left:320px}.est-row-lvl-23 td:first-child{padding-left:335px}.est-row-lvl-24 td:first-child{padding-left:350px}.est-row-lvl-25 td:first-child{padding-left:365px}.est-row-lvl-26 td:first-child{padding-left:380px}.est-row-lvl-27 td:first-child{padding-left:395px}.est-row-lvl-28 td:first-child{padding-left:410px}.est-row-lvl-29 td:first-child{padding-left:425px}.est-row-lvl-30 td:first-child{padding-left:440px}.est-row-lvl-31 td:first-child{padding-left:455px}.est-row-lvl-32 td:first-child{padding-left:470px}.est-row-lvl-33 td:first-child{padding-left:485px}.est-row-lvl-34 td:first-child{padding-left:500px}.est-row-lvl-35 td:first-child{padding-left:515px}.est-row-lvl-36 td:first-child{padding-left:530px}.est-row-lvl-37 td:first-child{padding-left:545px}.est-row-lvl-38 td:first-child{padding-left:560px}.est-row-lvl-39 td:first-child{padding-left:575px}.est-row-lvl-40 td:first-child{padding-left:590px}.est-row-lvl-41 td:first-child{padding-left:605px}.est-row-lvl-42 td:first-child{padding-left:620px}.est-row-lvl-43 td:first-child{padding-left:635px}.est-row-lvl-44 td:first-child{padding-left:650px}.est-row-lvl-45 td:first-child{padding-left:665px}.est-row-lvl-46 td:first-child{padding-left:680px}.est-row-lvl-47 td:first-child{padding-left:695px}.est-row-lvl-48 td:first-child{padding-left:710px}.est-row-lvl-49 td:first-child{padding-left:725px}.est-row-lvl-50 td:first-child{padding-left:740px}.est-row-lvl-51 td:first-child{padding-left:755px}.est-row-lvl-52 td:first-child{padding-left:770px}.est-row-lvl-53 td:first-child{padding-left:785px}.est-row-lvl-54 td:first-child{padding-left:800px}.est-row-lvl-55 td:first-child{padding-left:815px}.est-row-lvl-56 td:first-child{padding-left:830px}.est-row-lvl-57 td:first-child{padding-left:845px}.est-row-lvl-58 td:first-child{padding-left:860px}.est-row-lvl-59 td:first-child{padding-left:875px}.est-row-lvl-60 td:first-child{padding-left:890px}.est-row-lvl-61 td:first-child{padding-left:905px}.est-row-lvl-62 td:first-child{padding-left:920px}.est-row-lvl-63 td:first-child{padding-left:935px}.est-row-lvl-64 td:first-child{padding-left:950px}.est-row-lvl-65 td:first-child{padding-left:965px}.est-row-lvl-66 td:first-child{padding-left:980px}.est-row-lvl-67 td:first-child{padding-left:995px}.est-row-lvl-68 td:first-child{padding-left:1010px}.est-row-lvl-69 td:first-child{padding-left:1025px}.est-row-lvl-70 td:first-child{padding-left:1040px}.est-row-lvl-71 td:first-child{padding-left:1055px}.est-row-lvl-72 td:first-child{padding-left:1070px}.est-row-lvl-73 td:first-child{padding-left:1085px}.est-row-lvl-74 td:first-child{padding-left:1100px}.est-row-lvl-75 td:first-child{padding-left:1115px}.est-row-lvl-76 td:first-child{padding-left:1130px}.est-row-lvl-77 td:first-child{padding-left:1145px}.est-row-lvl-78 td:first-child{padding-left:1160px}.est-row-lvl-79 td:first-child{padding-left:1175px}.est-row-lvl-80 td:first-child{padding-left:1190px}.est-row-lvl-81 td:first-child{padding-left:1205px}.est-row-lvl-82 td:first-child{padding-left:1220px}.est-row-lvl-83 td:first-child{padding-left:1235px}.est-row-lvl-84 td:first-child{padding-left:1250px}.est-row-lvl-85 td:first-child{padding-left:1265px}.est-row-lvl-86 td:first-child{padding-left:1280px}.est-row-lvl-87 td:first-child{padding-left:1295px}.est-row-lvl-88 td:first-child{padding-left:1310px}.est-row-lvl-89 td:first-child{padding-left:1325px}.est-row-lvl-90 td:first-child{padding-left:1340px}.est-row-lvl-91 td:first-child{padding-left:1355px}.est-row-lvl-92 td:first-child{padding-left:1370px}.est-row-lvl-93 td:first-child{padding-left:1385px}.est-row-lvl-94 td:first-child{padding-left:1400px}.est-row-lvl-95 td:first-child{padding-left:1415px}.est-row-lvl-96 td:first-child{padding-left:1430px}.est-row-lvl-97 td:first-child{padding-left:1445px}.est-row-lvl-98 td:first-child{padding-left:1460px}.est-row-lvl-99 td:first-child{padding-left:1475px}.est-right-10{right:10px}.est-hidden{visibility:hidden}"]
|
|
4054
|
+
template: "<!-- Patacchino di autoaggiornamento -->\r\n<div class=\"w-100\" *ngIf=\"AutoUpdate\">\r\n <div class=\"pull-right\">\r\n {{'Update every' | localize : lc}} <input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control est-custom-input\" type=\"text\" [(ngModel)]=\"seconds\" /> {{'second/s' | localize : lc}}\r\n </div>\r\n <div class=\"pull-right m-t-2\">\r\n <label class=\"est-switch\">\r\n <input type=\"checkbox\" [(ngModel)]=\"autoUpdate\" (ngModelChange)=\"autoUpdateChanged();\" />\r\n <div class=\"est-slider round\"></div>\r\n </label>\r\n </div>\r\n</div>\r\n\r\n<!--\r\nI TH sono contenuto statico, questo significa che senza condizione per RowTHs arriverebbero sia qui sia nell ng-container dell'header in fase non inizializzata, duplicando fisicamente le colonne.\r\nPer ovviare al problema, questo pezzo lo faccio apparire solo se ci sono gi\u00E0 dei RowTHs, quindi su valorizzazione della View succeder\u00E0:\r\n1) appaiono i th nell' ng-container dell'header, e NON qui\r\n2) i TH vengono presi, elaborati e trasformati in RowTHs\r\n3) l'ng-container dell'header sparisce (per la condizione !UseCustomCells || !RowTHs) e qui appaiono i nuovi TH (che poi sono gli stessi di prima che girano)\r\n4) Vengono presi i nuovi TH da qui e trasformati a loro volta in RowTHs\r\n-->\r\n<div hidden *ngIf=\"UseCustomCells && RowTHs\">\r\n <ng-container *ngIf=\"View\">\r\n <!--Qui invece ci sono tutti i TH-->\r\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\r\n </ng-container>\r\n</div>\r\n\r\n<!--\r\nQuesta parte \u00E8 un po' pi\u00F9 semplice del sopra. Infatti i TD vengono s\u00EC bindati in entrambi i punti (qui e nell'ng-container del body), ma avr\u00F2 le TD statiche prima di generare la TMPBoundSource.\r\nQuesto significa che il workflow di binding sar\u00E0:\r\n1) Appaiono i TD statici nel body e NON qui, perch\u00E9 i TMPBoundSource non sono ancora stati emessi\r\n2) Contemporaneamente all'emissione dei TMPBoundSource vengono anche emessi i RowTds\r\n3) Considerando il punto 2, al giro dopo appariranno i TD qui, perch\u00E9 \u00E8 stata generata la TMPBoundSource, e spariranno contemporaneamente dall'ng-container del body (per la condizione !UseCustomCells || !RowTDs)\r\n-->\r\n<div hidden *ngIf=\"UseCustomCells && bodyRef\">\r\n <ng-container *ngIf=\"View\">\r\n <!--Tutti i TD che dopo verranno presi ed elaborati internamente-->\r\n <ng-container *ngFor=\"let item of TMPBoundSource\">\r\n <ng-container *ngTemplateOutlet=\"bodyRef; context : {$implicit: item}\"></ng-container>\r\n </ng-container>\r\n </ng-container>\r\n</div>\r\n\r\n<ng-container *ngIf=\"View\">\r\n <div *ngIf=\"FirstBind && ShowLoadingOnBootstrap\" class=\"est-loading-box\">\r\n <div class=\"est-loading-content\">\r\n <span class=\"fa fa-spinner fa-spin\"></span> {{'Performing Table bootstrap' | localize: lc}}...\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"PagingStyle == 'both' || PagingStyle == 'top'\">\r\n <ng-container *ngTemplateOutlet=\"pagingElement\"></ng-container>\r\n </div>\r\n\r\n <div class=\"table-responsive datatable {{ContainerClass}}\" [class.est-scrollable]=\"UseEndlessscroll\" (scroll)=\"UseEndlessscroll && onScroll($event)\" [style.max-height.px]=\"MaxHeight\">\r\n <table class=\"{{ TableClass }} est-margin-bottom-10\" [class.est-high-density]=\"HighCellDensity\">\r\n <thead [hidden]=\"HeaderHidden || FirstBind\">\r\n <!-- Aggiungo il pezzo che gestisce la selezione di tutto se attivo da config -->\r\n <tr *ngIf=\"SelectAll\">\r\n <th class=\"est-no-selection\" [attr.colspan]=\"Columns.Global\" [class.est-hidden]=\"!canSelectAll && !(View?.selection || arraymodeSelection).all\">\r\n <span>{{ ((selectedObjects || 0) | number : '0.0-0' : locale) + ' ' + ((selectedObjects == 1 ? 'Object Selected' : 'Objects Selected') | localize : lc) }}</span> \r\n <span class=\"est-link est-inline\" (click)=\"selectAllOrResetSelection()\">{{ (View?.selection || arraymodeSelection).all ? ('Reset Selection' | localize : lc) : ('Select Everything' | localize : lc)}}</span>\r\n </th>\r\n </tr>\r\n\r\n <!-- Blocco header group -->\r\n <ng-container *ngIf=\"RowThGroups\">\r\n <tr *ngFor=\"let level of RowThGroups\">\r\n <th *ngFor=\"let cell of level\" [attr.colspan]=\"cell.Span\" \r\n [class.est-pinned-header]=\"cell.Pinned\" [class.est-col-min]=\"cell.Pinned\"\r\n [class.est-ltab-border]=\"cell.Borders\" [class.est-rtab-border]=\"cell.Borders\"\r\n class=\"est-text-center\">\r\n <ng-container *ngIf=\"cell.Pinned; Else: cell.Template\">\r\n <div class=\"est-pinned-border est-cell-group-padding\"></div>\r\n </ng-container>\r\n </th>\r\n </tr>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"!RowThGroups\">\r\n <tr *ngIf=\"headerGroupRef\">\r\n <ng-container *ngTemplateOutlet=\"headerGroupRef\"></ng-container>\r\n <th *ngIf=\"Export\"></th>\r\n </tr>\r\n \r\n <!-- Blocco header group secondario -->\r\n <tr *ngIf=\"secondaryHeaderGroupRef\">\r\n <ng-container *ngTemplateOutlet=\"secondaryHeaderGroupRef\"></ng-container>\r\n <th *ngIf=\"Export\"></th>\r\n </tr>\r\n </ng-container>\r\n\r\n <!-- Blocco effettivo degli header -->\r\n <tr>\r\n <!-- Aggiungo una checkbox se la selezione \u00E8 attiva -->\r\n <th class=\"est-col-min\" *ngIf=\"Selection && !HasPinnedColumns\">\r\n <input *ngIf=\"!SingleSelection\" class=\"est-pointer\" type=\"checkbox\" [disabled]=\"SelectionDisabled\" [(ngModel)]=\"globalCheck\" [ngModelOptions]=\"{'standalone': true}\" (ngModelChange)=\"globalCheckChanged();\">\r\n </th>\r\n\r\n <!-- Header che valgono per view mode e array mode -->\r\n <ng-container *ngIf=\"(viewMode || arrayMode)\">\r\n\r\n <!-- In una tabella base prendo semplicemente i th scritti dall'utente nell'HTML -->\r\n <ng-container *ngIf=\"(!UseCustomCells || !RowTHs) && !DynamicRowColumnsDefinition\">\r\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\r\n </ng-container>\r\n\r\n <!-- Se ho un modello dinamico dell'oggetto creo le colonne in base alle propriet\u00E0 -->\r\n <ng-container *ngIf=\"(!UseCustomCells || !RowTHs) && DynamicRowColumnsDefinition\">\r\n <th *ngFor=\"let operation of DynamicOperations\" class=\"est-col-min est-no-side-padding\"></th>\r\n \r\n <ng-container *ngFor=\"let rowHeader of DynamicRowColumnsDefinition\">\r\n <ng-container *ngIf=\"rowHeader.visible\">\r\n <th *ngIf=\"OrderByColumn\" es-th=\"{{rowHeader.propertyName}}\" class=\"{{UserDefinedDynamicCols ? ((rowHeader.clss || '') + (rowHeader.headerWraps ? '' : ' est-nowrap')) : ' est-nowrap'}}\" [Order]=\"rowHeader.dataOrder\" [Resizable]=\"ColumnsResizable\" [Orderable]=\"rowHeader.orderable\" [OrderBy]=\"OrderByColumn\" [SearchInProgress]=\"!!researchInProgress\" (onOrderChange)=\"thOrderChanged(rowHeader.propertyName, $event)\">{{rowHeader.description}}</th>\r\n <th *ngIf=\"!OrderByColumn\" es-th=\"{{rowHeader.propertyName}}\" class=\"{{UserDefinedDynamicCols ? ((rowHeader.clss || '') + (rowHeader.headerWraps ? '' : ' est-nowrap')) : ' est-nowrap'}}\" [Order]=\"rowHeader.dataOrder\" [Resizable]=\"ColumnsResizable\" [Orderable]=\"rowHeader.orderable\" [OrderBy]=\"OrderByColumn\">{{rowHeader.description}}</th>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <!-- Se non ho un modello dinamico ma invece delle celle custom, genero gli header in base ai row th -->\r\n <ng-container *ngIf=\"UseCustomCells && RowTHs\">\r\n <th *ngIf=\"HasPinnedColumns\" class=\"est-pinned-header est-col-min\">\r\n <div [style.width.px]=\"PinnedContainerWidth\" class=\"est-pinned-border\">\r\n <th class=\"est-col-min est-no-border\" *ngIf=\"Selection\">\r\n <input *ngIf=\"!SingleSelection\" class=\"est-pointer\" type=\"checkbox\" [disabled]=\"SelectionDisabled\" [(ngModel)]=\"globalCheck\" [ngModelOptions]=\"{'standalone': true}\" (ngModelChange)=\"globalCheckChanged();\">\r\n </th>\r\n <ng-container *ngFor=\"let rowHeader of RowTHs\">\r\n <th *ngIf=\"rowHeader && rowHeader.Visible && rowHeader.Pinned\" [style.width.px]=\"rowHeader.PinnedWidth\" es-th=\"{{rowHeader.ID}}\" [class.est-no-border]=\"true\" [class.est-nowrap]=\"!rowHeader.Wrap\" class=\"{{rowHeader.Class || ''}}\" [Order]=\"rowHeader.Order\" [Resizable]=\"ColumnsResizable\" [Orderable]=\"rowHeader.Orderable\" [OrderBy]=\"OrderByColumn\" [SearchInProgress]=\"!!researchInProgress\" (onOrderChange)=\"OrderByColumn && thOrderChanged(rowHeader.ID, $event)\">\r\n <ng-container *ngIf=\"rowHeader.Template\"><ng-container *ngTemplateOutlet=\"rowHeader.Template;\"></ng-container></ng-container>\r\n <span *ngIf=\"!rowHeader.Template\">{{rowHeader.Content}}</span>\r\n </th>\r\n </ng-container>\r\n </div>\r\n </th>\r\n <ng-container *ngFor=\"let rowHeader of RowTHs\">\r\n <th *ngIf=\"rowHeader && rowHeader.Visible && !rowHeader.Pinned\" es-th=\"{{rowHeader.ID}}\" [class.est-ltab-border]=\"rowHeader.LeftBorder\" [class.est-rtab-border]=\"rowHeader.RightBorder\" [class.est-nowrap]=\"!rowHeader.Wrap\" class=\"{{rowHeader.Class || ''}}\" [Order]=\"rowHeader.Order\" [Resizable]=\"ColumnsResizable\" [Orderable]=\"rowHeader.Orderable\" [OrderBy]=\"OrderByColumn\" [SearchInProgress]=\"!!researchInProgress\" (onOrderChange)=\"OrderByColumn && thOrderChanged(rowHeader.ID, $event)\">\r\n <ng-container *ngIf=\"rowHeader.Template\"><ng-container *ngTemplateOutlet=\"rowHeader.Template;\"></ng-container></ng-container>\r\n <span *ngIf=\"!rowHeader.Template\">{{rowHeader.Content}}</span>\r\n </th>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <!--Casistica in cui ho il setup proveniente da un report. Gli header sono definiti da come \u00E8 fatto il report-->\r\n <ng-container *ngIf=\"reportMode\">\r\n <th [style.color]=\"clm.color\" *ngFor=\"let clm of ReportValues.columns\" class=\"est-no-selection est-pointer est-nowrap\" (click)=\"setupNextOrderAndSearch(clm)\">\r\n {{clm.description}}<span class=\"fa\" [class.fa-chevron-down]=\"clm.order == 'DESC'\" [class.fa-chevron-up]=\"clm.order == 'ASC'\"></span>\r\n </th>\r\n </ng-container>\r\n\r\n <!--Per l'eliminazione mi serve un header aggiuntivo-->\r\n <th *ngIf=\"Removal\" [class.est-right-10]=\"Export || HiddenColumns\" class=\"est-col-min est-sticky-last-column\"><span class=\"fa fa-trash\"></span></th>\r\n\r\n <!--Per l'esportazione mi serve l'header extra da cui faccio uscire i 3 pallocchi-->\r\n <th *ngIf=\"Export || HiddenColumns || ColumnsOrdering || CornerMenuOptions\" class=\"est-table-dotted-menu est-sticky-last-column est-col-min text-sm-center\">\r\n \r\n <!-- Link nascosto che serve a scaricare il file -->\r\n <a *ngIf=\"headers\" hidden #exportDownloader csvLink [data]=\"data\" [headers]=\"headers\" [delimiter]=\"';'\" [filename]=\"ExportFileName\"></a>\r\n\r\n <!-- Blocco con i 3 pallocchi che tira fuori il context menu delle operazioni -->\r\n <div class=\"btn-group\" container=\"body\" placement=\"bottom right\" dropdown #dropdown=\"bs-dropdown\" [autoClose]=\"true\">\r\n <span dropdownToggle class=\"fa fa-ellipsis-v est-fs-18 est-pointer est-padding-3\"></span>\r\n\r\n <div *dropdownMenu class=\"dropdown-menu dropdown-menu-right est-bring-to-front-strong\">\r\n <div class=\"est-pointer\">\r\n <a class=\"dropdown-item\" *ngIf=\"HiddenColumns || ColumnsOrdering\" (click)=\"resetColumnVisSelection(); changeColumnVisibilityModal.show();\">\r\n <ng-container *ngIf=\"!HiddenColumns && ColumnsOrdering\">\r\n {{'Columns Order' | localize : lc}}\r\n </ng-container>\r\n <ng-container *ngIf=\"HiddenColumns && !ColumnsOrdering\">\r\n {{'Columns Visibility' | localize : lc}}\r\n </ng-container>\r\n <ng-container *ngIf=\"HiddenColumns && ColumnsOrdering\">\r\n {{'Columns Visibility and Order' | localize : lc}}\r\n </ng-container>\r\n </a>\r\n <a class=\"dropdown-item\" *ngIf=\"Export && CSVExport\" (click)=\"tryExport('CSV')\">{{'Export View' | localize : lc}} (CSV)</a>\r\n <a class=\"dropdown-item\" *ngIf=\"Export && XLSXExport\" (click)=\"tryExport('XLSX')\">{{'Export View' | localize : lc}} (XLSX)</a>\r\n <a class=\"dropdown-item\" *ngFor=\"let option of CornerMenuOptions\" (click)=\"cornerActionClicked(option.id)\">{{option.description}}</a>\r\n </div>\r\n </div>\r\n </div>\r\n </th>\r\n </tr>\r\n </thead>\r\n \r\n <!-- Valido per modalit\u00E0 View o Array. Se sono in report mode il body \u00E8 creato in altro modo -->\r\n <tbody [hidden]=\"BodyHidden || FirstBind\" *ngIf=\"(arrayMode || viewMode)\">\r\n <!--Con selection attiva richiamo il template che gestisce il context menu-->\r\n <ng-container *ngIf=\"Selection\">\r\n <ng-container *ngTemplateOutlet=\"TBodySelection; context: { $implicit: { selDisabled: arrayMode ? false : SelectionDisabled, sel: Selection }}\"></ng-container>\r\n </ng-container>\r\n\r\n <!--Senza selection richiamo il template che NON gestisce il context menu-->\r\n <ng-container *ngIf=\"!Selection\">\r\n <ng-container *ngTemplateOutlet=\"TBody\"></ng-container>\r\n </ng-container>\r\n </tbody>\r\n\r\n <!-- Per la modalit\u00E0 a report c'\u00E8 un body particolare semi-dinamico -->\r\n <tbody [hidden]=\"BodyHidden\" *ngIf=\"reportMode\">\r\n <tr *ngFor=\"let row of ReportValues.rows; let even = even;\">\r\n <td class=\"est-nowrap\" *ngFor=\"let val of row.values\">{{val}}</td>\r\n <td class=\"est-sticky-last-column{{even && !Hierarchy ? '-alt' : ''}}\"></td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <div *ngIf=\"PagingStyle == 'both' || PagingStyle == 'bottom'\">\r\n <ng-container *ngTemplateOutlet=\"pagingElement\"></ng-container>\r\n </div>\r\n</ng-container>\r\n\r\n<!-- Template che contiene tutte le info di paginazione in modo da poterlo replicare anche sopra -->\r\n<ng-template #pagingElement>\r\n <ng-container *ngIf=\"!FirstBind\">\r\n <!-- Pulsanti avanti-indietro di paginazione -->\r\n <div *ngIf=\"PagerOptions.ShowPaging && !HidePagingButtons\" class=\"pull-right btn-toolbar\">\r\n <ng-container *ngIf=\"(!reportMode || View?.pagingavailable) && (!arrayMode || SearchView)\">\r\n <ng-container *ngTemplateOutlet=\"pagingButtons; context: { $implicit: { ATP: addToPage.bind(this), GTP: goToPage.bind(this), Array: arrayPulsanti }}\"></ng-container>\r\n </ng-container>\r\n <ng-container *ngIf=\"arrayMode && UseArrayModePaging && !SearchView\">\r\n <ng-container *ngTemplateOutlet=\"pagingButtons; context: { $implicit: { ATP: arrayAddToPage.bind(this), GTP: arrayGoToPage.bind(this), Array: arrayPulsanti }}\"></ng-container>\r\n </ng-container>\r\n </div>\r\n <!-- Paginatore dove appare la count e le opzioni di paginazione -->\r\n <div class=\"pull-right m-t-min-3 est-margin-right-50\">\r\n <div *ngIf=\"PagerOptions.ShowPaging && (PagerOptions.PagerCount > 10 || reportMode && View.pagingavailable)\">\r\n <app-paging *ngIf=\"!PagerOptions.UsesView\" [ShowCount]=\"PagerOptions.ShowCount\" [PagerCount]=\"PagerOptions.PagerCount\" [WarnOnAll]=\"false\" [CurrentPageSize]=\"ArraymodeItemsPerPage\" (pagingSelected)=\"refreshPaging($event)\"></app-paging>\r\n <app-paging *ngIf=\"PagerOptions.UsesView\" [ShowCount]=\"PagerOptions.ShowCount\" [PagerCount]=\"PagerOptions.PagerCount\" [GroupMode]=\"PagerOptions.Searches == 'groups'\" [AllSearch]=\"AllSearch\" [View]=\"PagerOptions.View\" (pagingSelected)=\"onItemsPerPageChanged($event);\"></app-paging>\r\n </div>\r\n <div *ngIf=\"reportMode && !PagerOptions.ShowPaging\"><em>{{'Paging options are not available for this report' | localize: lc}}</em></div>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n </ng-container>\r\n</ng-template>\r\n\r\n<!-- Template che contiene i pulsanti per cambiare pagina -->\r\n<ng-template #pagingButtons let-options>\r\n <a class=\"btn\" class=\"est-page-prev app-pointer\" (click)=\"options.ATP(-1, options.separator)\">\r\n <span class=\"fa fa-chevron-left\"></span>\r\n </a>\r\n <div *ngIf=\"options.Array\" class=\"est-inline\">\r\n <a *ngFor=\"let p of options.Array\" class=\"btn est-page-sel {{p.cssClass}}\" (click)=\"options.GTP(p.val, options.separator)\">{{p.val}}</a>\r\n </div>\r\n <a class=\"btn\" class=\"est-page-next app-pointer\" (click)=\"options.ATP(1, options.separator)\">\r\n <span class=\"fa fa-chevron-right\"></span>\r\n </a>\r\n</ng-template>\r\n\r\n<!-- Questi due template rappresentano effettivamente il body della tabella. essendo il tr l'unica cosa che davvero cambia, il resto \u00E8 templatizzato -->\r\n<ng-template #TBodySelection let-templateOptions>\r\n <ng-container *ngFor=\"let item of boundSource; let even = even; let i=index;\">\r\n <tr *ngIf=\"item._visible || (!Hierarchy && !ArrayGrouping)\" \r\n [class]=\"item._rowClass ? item._rowClass : ''\" \r\n [class.est-line-through]=\"item.removed || item.deleted\" \r\n [class.est-pointer]=\"!item.locked\" \r\n [class.est-white-selected]=\"item._selected && !item.locked\"\r\n [class.est-rg]=\"item._group\"\r\n [class.est-rg-sep]=\"item._sep\"\r\n [contextMenu]=\"!item.locked ? (ContextMenu || emptyMenu) : emptyMenu\" [contextMenuSubject]=\"item\"\r\n (click)=\"(!item.locked && !item._sep && !item._group && handleClick($event, item)) || item._group && handleGroupClick(item)\">\r\n\r\n <td *ngIf=\"!item.locked && !item._sep && !HasPinnedColumns\">\r\n <input type=\"checkbox\" \r\n [disabled]=\"templateOptions.selDisabled\" \r\n [class.est-pointer]=\"!item.locked\"\r\n [(ngModel)]=\"item._selected\" name=\"check{{i}}\" \r\n (click)=\"$event.stopPropagation(); handleClick($event, item);\">\r\n </td>\r\n <td *ngIf=\"(item.locked || item._sep) && !HasPinnedColumns\"></td>\r\n\r\n <ng-container *ngIf=\"item._sep\"><ng-container *ngTemplateOutlet=\"groupPager; context: { $implicit: item }\"></ng-container> </ng-container>\r\n\r\n <ng-container *ngIf=\"!item._sep\">\r\n <ng-container *ngTemplateOutlet=\"basicColumns; context: { $implicit: item }\"></ng-container>\r\n <ng-container *ngTemplateOutlet=\"dynamicColumns; context: { $implicit: item }\"></ng-container>\r\n <ng-container *ngTemplateOutlet=\"customCells; context: { $implicit: item, templateOptions: templateOptions }\"></ng-container>\r\n </ng-container>\r\n <ng-container *ngTemplateOutlet=\"bodyDeleteAndExport; context: { $implicit: { even: even, item: item }}\"></ng-container>\r\n </tr>\r\n </ng-container>\r\n</ng-template>\r\n\r\n<ng-template #TBody>\r\n <ng-container *ngFor=\"let item of boundSource; let even = even;\">\r\n <tr *ngIf=\"item._visible || !Hierarchy\" \r\n [class]=\"item._rowClass ? item._rowClass : ''\" \r\n [class.est-line-through]=\"item.removed || item.deleted\"\r\n [class.est-rg]=\"item._group\"\r\n [class.est-rg-sep]=\"item._sep\"\r\n (click)=\"item._group && handleGroupClick(item)\">\r\n\r\n <ng-container *ngIf=\"item._sep\"><ng-container *ngTemplateOutlet=\"groupPager; context: { $implicit: item }\"></ng-container></ng-container>\r\n\r\n <ng-container *ngIf=\"!item._sep\">\r\n <ng-container *ngTemplateOutlet=\"basicColumns; context: { $implicit: item }\"></ng-container>\r\n <ng-container *ngTemplateOutlet=\"dynamicColumns; context: { $implicit: item }\"></ng-container>\r\n <ng-container *ngTemplateOutlet=\"customCells; context: { $implicit: item }\"></ng-container>\r\n </ng-container>\r\n <ng-container *ngTemplateOutlet=\"bodyDeleteAndExport; context: { $implicit: { even: even, item: item }}\"></ng-container>\r\n </tr>\r\n </ng-container>\r\n</ng-template>\r\n\r\n<ng-template #groupPager let-item>\r\n <td *ngIf=\"HasPinnedColumns\"></td>\r\n <td *ngIf=\"item._grouplevel > 1\" [attr.colspan]=\"item._grouplevel-1\"></td>\r\n <td [attr.colspan]=\"Columns.VisibleUnpinned - (item._grouplevel > 0 ? item._grouplevel - 1 : 0)\">\r\n <div class=\"est-rg-sep-flex-right\" *ngIf=\"RowGroupingPagingStyle == 'right'\">\r\n <div class=\"est-rg-page\"><ng-container *ngTemplateOutlet=\"pagingButtons; context: { $implicit: { separator: item, ATP: addToPageGroup.bind(this), GTP: goToPageGroup.bind(this), Array: item.buttons }}\"></ng-container></div>\r\n <div class=\"est-rg-ipp\"><app-paging [AllSearch]=\"AllSearch\" [GroupMode]=\"item.searches == 'groups'\" [PagerCount]=\"item.searches == 'groups' ? item.view.groupcount : item.view.objectcount\" [View]=\"item.view\" (pagingSelected)=\"onGroupItemsPerPageChanged(item, $event);\"></app-paging></div>\r\n </div>\r\n\r\n <div class=\"est-rg-sep-flex-left\" *ngIf=\"RowGroupingPagingStyle == 'left'\">\r\n <div class=\"est-rg-ipp\"><app-paging [AllSearch]=\"AllSearch\" [GroupMode]=\"item.searches == 'groups'\" [PagerCount]=\"item.searches == 'groups' ? item.view.groupcount : item.view.objectcount\" [View]=\"item.view\" (pagingSelected)=\"onGroupItemsPerPageChanged(item, $event);\"></app-paging></div>\r\n <div class=\"est-rg-page\"><ng-container *ngTemplateOutlet=\"pagingButtons; context: { $implicit: { separator: item, ATP: addToPageGroup.bind(this), GTP: goToPageGroup.bind(this), Array: item.buttons }}\"></ng-container></div>\r\n </div>\r\n </td>\r\n</ng-template>\r\n\r\n<!-- Questo template contiene la print condizionale su tabelle semplici, con header e body scritti a manazza -->\r\n<ng-template #basicColumns let-item>\r\n <ng-container *ngIf=\"(!UseCustomCells || !RowTDs) && !DynamicRowColumnsDefinition\">\r\n <ng-container *ngTemplateOutlet=\"bodyRef; context : {$implicit: item}\"></ng-container>\r\n </ng-container>\r\n</ng-template>\r\n\r\n<!-- Questo template contiene la print condizionale su tabelle definite in maniera dinamica dal modello -->\r\n<ng-template #dynamicColumns let-item>\r\n <ng-container *ngIf=\"(!UseCustomCells || !RowTDs) && DynamicRowColumnsDefinition\">\r\n <ng-container *ngFor=\"let operation of DynamicOperations; let first = first; let last = last;\">\r\n <ng-container *ngIf=\"!operation.conditionField || (item.properties[operation.conditionField] == operation.conditionValue)\">\r\n <td [class.est-no-right-padding]=\"last\" [class.est-no-left-padding]=\"!first\" class=\"est-col-min\"><span title=\"{{operation.title}}\" class=\"{{operation.iconClass}} est-pointer\" (click)=\"dynamicOperation(item, operation.id)\">{{operation.text}}</span></td>\r\n </ng-container>\r\n <ng-container *ngIf=\"operation.conditionField && (item.properties[operation.conditionField] != operation.conditionValue)\">\r\n <td class=\"est-col-min est-no-side-padding\"></td>\r\n </ng-container>\r\n </ng-container>\r\n <ng-container *ngFor=\"let rowItem of DynamicRowColumnsDefinition\">\r\n <ng-container *ngIf=\"rowItem.routePath && rowItem.visible\">\r\n <td es-td=\"{{rowItem.propertyName}}\" class=\"{{UserDefinedDynamicCols ? rowItem.clss : 'est-nowrap'}}\" [Internal]=\"false\" [Context]=\"item._hash\">\r\n <a [routerLink]=\"generateRouterLink(rowItem.routePath, rowItem.routeParameterProperties, item)\" class=\"est-link\" [innerHTML]=\"item.properties[rowItem.propertyName]\"></a>\r\n </td>\r\n </ng-container>\r\n <ng-container *ngIf=\"!rowItem.routePath && rowItem.visible\">\r\n <ng-container *ngTemplateOutlet=\"findEsTd(rowItem.propertyName) || defaultEsTd; context: { $implicit: item.properties[rowItem.propertyName], rowItem : rowItem, item : item }\"> </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n</ng-template>\r\n\r\n<ng-template #defaultEsTd let-value let-rowItem='rowItem' let-item='item'>\r\n <td es-td=\"{{rowItem.propertyName}}\" class=\"{{UserDefinedDynamicCols ? rowItem.clss : 'est-nowrap'}}\"\r\n [class.est-pointer]=\"UseCustomCellActions && CustomCellActionsOn.indexOf('$' + rowItem.propertyName + '$') != -1\"\r\n (click)=\"cellClicked(rowItem.propertyName, item) && !CellActionPropagates && $event.stopPropagation()\"\r\n [Internal]=\"false\" [Context]=\"item._hash\">\r\n {{value}}\r\n </td>\r\n</ng-template>\r\n\r\n<!-- Questo template contiene la print condizionale delle celle custom se configurate -->\r\n<ng-template #customCells let-item let-opt=\"templateOptions\">\r\n <ng-container *ngIf=\"UseCustomCells && RowTDs\">\r\n\r\n <td *ngIf=\"HasPinnedColumns\" class=\"est-pinned-body est-col-min\" [class.est-white-selected]=\"item._selected\">\r\n <div [style.width.px]=\"PinnedContainerWidth\" class=\"est-pinned-border\">\r\n <td *ngIf=\"!item.locked && !item._sep && Selection\" class=\"est-no-border est-col-min\">\r\n <input type=\"checkbox\" [disabled]=\"opt.selDisabled\" [class.est-pointer]=\"!item.locked\" [(ngModel)]=\"item._selected\" name=\"check{{item._hash}}\" (click)=\"$event.stopPropagation(); handleClick($event, item);\">\r\n </td>\r\n <td class=\"est-no-border est-col-min\" *ngIf=\"(item.locked || item._sep) && Selection\"></td>\r\n\r\n <ng-container *ngFor=\"let rowItem of RowTDs[item._hash]; let i = index\">\r\n <td *ngIf=\"rowItem && rowItem.Pinned\" [style.width.px]=\"rowItem.PinnedWidth\" es-td=\"{{rowItem.ID}}\" class=\"{{rowItem.Class}}\" [class.est-no-border]=\"true\" [class.est-rg-hdr]=\"rowItem.GroupHeader\" [class.est-rg-agg]=\"rowItem.GroupAggregation\" \r\n [class.est-nowrap]=\"Hierarchy || !rowItem.Wraps\" [Internal]=\"true\">\r\n <ng-container *ngIf=\"Hierarchy && i == 0\"><ng-container *ngTemplateOutlet=\"HierarchyNavigator; context: { $implicit: item }\"></ng-container></ng-container>\r\n <ng-container *ngIf=\"rowItem.Template\"><ng-container *ngTemplateOutlet=\"rowItem.Template; context: { $implicit: item }\"></ng-container></ng-container>\r\n <span *ngIf=\"!rowItem.Template\">{{rowItem.Content}}</span>\r\n </td>\r\n </ng-container>\r\n </div>\r\n </td>\r\n\r\n <ng-container *ngFor=\"let rowItem of RowTDs[item._hash]; let i = index\">\r\n <ng-container *ngIf=\"rowItem && !rowItem.Pinned\">\r\n\r\n <!-- Casistica senza bodyRef, quindi con direttive per i td -->\r\n <ng-container *ngIf=\"!bodyRef && rowItem.Visible\">\r\n <td es-td=\"{{rowItem.ID}}\" class=\"{{rowItem.Class}}\" [class.est-ltab-border]=\"rowItem.LeftBorder\" [class.est-rtab-border]=\"rowItem.RightBorder\" [class.est-rg-hdr]=\"rowItem.GroupHeader\" [class.est-rg-agg]=\"rowItem.GroupAggregation\" \r\n [class.est-nowrap]=\"Hierarchy || !rowItem.Wraps\" [Internal]=\"true\">\r\n <ng-container *ngIf=\"Hierarchy && i == 0\"><ng-container *ngTemplateOutlet=\"HierarchyNavigator; context: { $implicit: item }\"></ng-container></ng-container>\r\n <ng-container *ngIf=\"rowItem.Template\"><ng-container *ngTemplateOutlet=\"rowItem.Template; context: { $implicit: item }\"></ng-container></ng-container>\r\n <span *ngIf=\"!rowItem.Template\">{{rowItem.Content}}</span>\r\n </td>\r\n </ng-container>\r\n\r\n <!-- Casistica bodyRef, quindi con componenti per i td (RouterLink) DEPRECATO -->\r\n <ng-container *ngIf=\"rowItem.RouterLink && rowItem.Visible && bodyRef\">\r\n <td es-td=\"{{rowItem.ID}}\" class=\"{{rowItem.Class}}\" [class.est-nowrap]=\"Hierarchy || !rowItem.Wraps\" [Internal]=\"true\">\r\n <ng-container *ngIf=\"Hierarchy && i == 0\">\r\n <ng-container *ngTemplateOutlet=\"HierarchyNavigator; context: { $implicit: item }\"></ng-container>\r\n </ng-container>\r\n <a [routerLink]='rowItem.RouterLink' class=\"est-link\" [innerHTML]=\"rowItem.Content\"></a>\r\n </td>\r\n </ng-container>\r\n\r\n <!-- Casistica bodyRef, quindi con componenti per i td (NON RouterLink) DEPRECATO -->\r\n <ng-container *ngIf=\"!rowItem.RouterLink && rowItem.Visible && bodyRef\">\r\n <td es-td=\"{{rowItem.ID}}\" class=\"{{rowItem.Class}}\" [class.est-nowrap]=\"Hierarchy || !rowItem.Wraps\" [class.est-pointer]=\"UseCustomCellActions && CustomCellActionsOn.indexOf('$' + $any(rowItem).ID + '$') != -1\" (click)=\"cellClicked(rowItem.ID, item) && !CellActionPropagates && $event.stopPropagation()\" [Internal]=\"true\">\r\n <ng-container *ngIf=\"Hierarchy && i == 0\">\r\n <ng-container *ngTemplateOutlet=\"HierarchyNavigator; context: { $implicit: item }\"></ng-container>\r\n </ng-container>\r\n <ng-container *ngIf=\"rowItem.Template\">\r\n <ng-container *ngTemplateOutlet=\"rowItem.Template; context: { $implicit: item }\"></ng-container>\r\n </ng-container>\r\n <span *ngIf=\"!rowItem.Template\" [innerHTML]=\"rowItem.Content\"></span>\r\n </td>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n</ng-template>\r\n\r\n<ng-template #HierarchyNavigator let-item>\r\n <span *ngIf=\"!item.parent\" class=\"fa fa-chevron-down\" style=\"visibility:hidden\"></span>\r\n <span *ngIf=\"item.parent && item._expanded\" class=\"fa fa-chevron-down est-pointer est-no-selection\" (click)=\"collapseParent(item[this.OwnKey])\"></span>\r\n <span *ngIf=\"item.parent && !item._expanded\" class=\"fa fa-chevron-up est-pointer est-no-selection\" (click)=\"expandParent(item[this.OwnKey])\"></span>\r\n \r\n</ng-template>\r\n\r\n<!-- Questo template contiene i pulsanti di eliminazione/undo eliminazione ed esportazione che vanno in fondo ad un record edlla tabella -->\r\n<ng-template #bodyDeleteAndExport let-options>\r\n <ng-container *ngIf=\"Removal && !RemovalCondition\">\r\n <td class=\"est-sticky-last-column{{options.even? '-alt' : ''}} {{Export || HiddenColumns || CornerMenuOptions ? 'est-right-10' : ''}}\" *ngIf=\"!(options.item.removed || options.item.deleted)\"><span class=\"fa fa-remove est-pointer text-danger\" [hidden]=\"options.item.removable != undefined && !options.item.removable\" (click)=\"onRemoval.emit(options.item)\"></span></td>\r\n <td class=\"est-sticky-last-column{{options.even? '-alt' : ''}} {{Export || HiddenColumns || CornerMenuOptions ? 'est-right-10' : ''}}\" *ngIf=\"(options.item.removed || options.item.deleted)\"><span class=\"fa fa-undo text-warning est-pointer\" (click)=\"onAbortRemoval.emit(options.item)\"></span></td>\r\n </ng-container>\r\n <ng-container *ngIf=\"Removal && RemovalCondition\">\r\n <td class=\"est-sticky-last-column{{options.even? '-alt' : ''}} {{Export || HiddenColumns || CornerMenuOptions ? 'est-right-10' : ''}}\" *ngIf=\"!(options.item.removed || options.item.deleted) && options.item[RemovalCondition]\"><span class=\"fa fa-remove est-pointer text-danger\" [hidden]=\"options.item.removable != undefined && !options.item.removable\" (click)=\"onRemoval.emit(options.item)\"></span></td>\r\n <td class=\"est-sticky-last-column{{options.even? '-alt' : ''}} {{Export || HiddenColumns || CornerMenuOptions ? 'est-right-10' : ''}}\" *ngIf=\"(options.item.removed || options.item.deleted) && options.item[RemovalCondition]\"><span class=\"fa fa-undo text-warning est-pointer\" (click)=\"onAbortRemoval.emit(options.item)\"></span></td>\r\n <td class=\"est-sticky-last-column{{options.even? '-alt' : ''}} {{Export || HiddenColumns || CornerMenuOptions ? 'est-right-10' : ''}}\" *ngIf=\"!options.item[RemovalCondition]\"><span class=\"fa fa-remove est-hidden-view\"></span></td>\r\n </ng-container>\r\n <td *ngIf=\"Export || HiddenColumns || CornerMenuOptions\" class=\"est-sticky-last-column{{options.even && !Hierarchy ? '-alt' : ''}}\"></td>\r\n</ng-template>\r\n\r\n<!-- Context menu vuoto default per tutte le tabella che non ce l'hanno, in modo che al click destro appaia \"nessuna op disponibile\" -->\r\n<context-menu #emptyMenu>\r\n <ng-template contextMenuItem>\r\n <span>\r\n <em>{{'No operations available' | localize : lc}}...</em>\r\n </span>\r\n </ng-template>\r\n</context-menu>\r\n\r\n<!-- Modal per cambiare posizione e visibilit\u00E0 delle colonne dell'es-table -->\r\n<div bsModal #changeColumnVisibilityModal=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <div class=\"modal-dialog modal-lg\">\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h5 class=\"modal-title pull-left\">\r\n <ng-container *ngIf=\"!HiddenColumns && ColumnsOrdering\">\r\n {{'Columns Order' | localize : lc}}\r\n </ng-container>\r\n <ng-container *ngIf=\"HiddenColumns && !ColumnsOrdering\">\r\n {{'Columns Visibility' | localize : lc}}\r\n </ng-container>\r\n <ng-container *ngIf=\"HiddenColumns && ColumnsOrdering\">\r\n {{'Columns Visibility and Order' | localize : lc}}\r\n </ng-container>\r\n </h5>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"changeColumnVisibilityModal.hide();\" aria-label=\"Close\">\r\n <span aria-hidden=\"true\">×</span>\r\n </button>\r\n </div>\r\n <div class=\"modal-body\">\r\n <div *ngIf=\"!TMPColumnsList || TMPColumnsList.length == 0\" class=\"card card-info est-padding-10 est-margin-bottom-0\">\r\n {{'There are no columns configured to be hidden/shown in this view' | localize : lc}}\r\n </div>\r\n <div *ngIf=\"TMPColumnsList && TMPColumnsList.length > 0\" style=\"max-height:500px; overflow-y:auto\">\r\n <!--Aaaaaaah la tristezza... qui mi servirebbe l'es-table per facilitare la selezione multipla ecc... peccato che se la linko qui entro in un loop impressionante-->\r\n <table class=\"table table-striped table-sm est-margin-bottom-0\">\r\n <thead>\r\n <tr>\r\n <th class=\"est-col-min\" *ngIf=\"HiddenColumns\">\r\n <input class=\"est-pointer\" type=\"checkbox\" [(ngModel)]=\"globalColVisCheck\" [ngModelOptions]=\"{'standalone': true}\" (ngModelChange)=\"globalColVisCheckChanged();\">\r\n </th>\r\n <th class=\"est-col-min\" *ngIf=\"ColumnsOrdering\"></th>\r\n <th class=\"est-col-min est-nowrap\">{{'Column Name' | localize : lc}}</th>\r\n <!--Filler-->\r\n <th></th>\r\n <!-- Pinner -->\r\n <th class=\"est-col-min\"></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let item of TMPColumnsList; let i = index; let last = last\" class=\"est-pointer\" [class.est-white-selected]=\"lastSelectedItemID == item.id\" [class.est-no-selection]=\"!item.visible\">\r\n <td *ngIf=\"HiddenColumns\">\r\n <input type=\"checkbox\" [class.est-hidden-view]=\"item.fixed\" class=\"est-pointer\" [(ngModel)]=\"item.visible\" name=\"visible{{i}}\" (ngModelChange)=\"updateGlobalColVisCheck();\" />\r\n </td>\r\n <td class=\"est-nowrap\" *ngIf=\"ColumnsOrdering\">\r\n <span class=\"fa fa-arrow-up\" [class.est-hidden-view]=\"item.fixed || item.pinned\" (click)=\"lastSelectedItemID = item.id; i != 0 && !item.fixed && sendUp(item); $event.stopPropagation();\"></span>\r\n <span class=\"fa fa-arrow-down\" [class.est-hidden-view]=\"item.fixed || item.pinned\" (click)=\"lastSelectedItemID = item.id; !last && !item.fixed && sendDown(item); $event.stopPropagation();\"></span>\r\n </td>\r\n <td class=\"est-nowrap\" (click)=\"columnClicked(item);\">\r\n <ng-container *ngIf=\"item.template\">\r\n <ng-container *ngTemplateOutlet=\"item.template\"></ng-container>\r\n </ng-container>\r\n <ng-container *ngIf=\"!item.template\">{{item.description}}</ng-container>\r\n </td>\r\n <!--Filler-->\r\n <td (click)=\"columnClicked(item);\"></td>\r\n <!-- Pinner -->\r\n <td><span *ngIf=\"!item.fixed\" class=\"fa fa-thumb-tack\" [class.text-success]=\"item.pinned\" (click)=\"pinOrUnpinColumn(item)\"></span></td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-secondary est-margin-right-10\" (click)=\"lastSelectedItemID = null; changeColumnVisibilityModal.hide();\">{{'Close' | localize : lc}}</button>\r\n <button type=\"button\" [disabled]=\"!TMPColumnsList || TMPColumnsList.length == 0\" class=\"btn btn-primary\" (click)=\"confirmColumnVisibilitySelection() && changeColumnVisibilityModal.hide()\">{{'Confirm' | localize : lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>",
|
|
4055
|
+
styles: [".est-loading-box{height:200px;text-align:center;position:relative;background:#ccc}.est-loading-content{margin:0;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:35px}.est-scrollable{max-height:600px;overflow:auto}.est-pointer{cursor:pointer}.est-high-density td,.est-high-density th{padding:0 .2rem}.est-no-selection{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-ms-user-select:none}.est-hidden-view{visibility:hidden}.est-no-border{border:none!important}.est-nowrap{white-space:nowrap}.est-white-selected{background-color:#ddd!important}.est-line-through{text-decoration:line-through}.est-no-side-padding{padding-left:0;padding-right:0}.est-no-left-padding,.est-no-right-padding{padding-left:0}.est-col-min{width:1px}.est-margin-bottom-0{margin-bottom:0!important}.est-margin-right-10{margin-right:10px!important}.est-right-10{right:10px!important}.est-table-dotted-menu{padding:0 0 2px!important;color:#999}.est-fs-18{font-size:18px}.est-fs-14{font-size:14px}.est-padding-3{padding:3px!important}.est-page-container{position:relative}.est-bring-to-front-strong{z-index:99999999!important}.est-switch{position:relative;display:inline-block;width:30px;height:17px;margin-bottom:0;margin-right:5px;margin-left:5px}.est-switch input{display:none}.est-slider{cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc}.est-slider,.est-slider:before{position:absolute;transition:.4s}.est-slider:before{content:\"\";height:13px;width:13px;left:3px;bottom:2px;background-color:#fff}input:checked+.est-slider{background-color:#2196f3}input:focus+.est-slider{box-shadow:0 0 1px #2196f3}input:checked+.est-slider:before{transform:translateX(11px)}.est-slider.round{border-radius:10px}.est-slider.round:before{border-radius:50%}.est-custom-input{width:30px;display:inline;padding:1px;height:20px}.est-row-lvl-1 td:first-child{padding-left:5px}.est-row-lvl-2 td:first-child{padding-left:20px}.est-row-lvl-3 td:first-child{padding-left:35px}.est-row-lvl-4 td:first-child{padding-left:50px}.est-row-lvl-5 td:first-child{padding-left:65px}.est-row-lvl-6 td:first-child{padding-left:80px}.est-row-lvl-7 td:first-child{padding-left:95px}.est-row-lvl-8 td:first-child{padding-left:110px}.est-row-lvl-9 td:first-child{padding-left:125px}.est-row-lvl-10 td:first-child{padding-left:140px}.est-row-lvl-11 td:first-child{padding-left:155px}.est-row-lvl-12 td:first-child{padding-left:170px}.est-row-lvl-13 td:first-child{padding-left:185px}.est-row-lvl-14 td:first-child{padding-left:200px}.est-row-lvl-15 td:first-child{padding-left:215px}.est-row-lvl-16 td:first-child{padding-left:230px}.est-row-lvl-17 td:first-child{padding-left:245px}.est-row-lvl-18 td:first-child{padding-left:260px}.est-row-lvl-19 td:first-child{padding-left:275px}.est-row-lvl-20 td:first-child{padding-left:290px}.est-row-lvl-21 td:first-child{padding-left:305px}.est-row-lvl-22 td:first-child{padding-left:320px}.est-row-lvl-23 td:first-child{padding-left:335px}.est-row-lvl-24 td:first-child{padding-left:350px}.est-row-lvl-25 td:first-child{padding-left:365px}.est-row-lvl-26 td:first-child{padding-left:380px}.est-row-lvl-27 td:first-child{padding-left:395px}.est-row-lvl-28 td:first-child{padding-left:410px}.est-row-lvl-29 td:first-child{padding-left:425px}.est-row-lvl-30 td:first-child{padding-left:440px}.est-row-lvl-31 td:first-child{padding-left:455px}.est-row-lvl-32 td:first-child{padding-left:470px}.est-row-lvl-33 td:first-child{padding-left:485px}.est-row-lvl-34 td:first-child{padding-left:500px}.est-row-lvl-35 td:first-child{padding-left:515px}.est-row-lvl-36 td:first-child{padding-left:530px}.est-row-lvl-37 td:first-child{padding-left:545px}.est-row-lvl-38 td:first-child{padding-left:560px}.est-row-lvl-39 td:first-child{padding-left:575px}.est-row-lvl-40 td:first-child{padding-left:590px}.est-row-lvl-41 td:first-child{padding-left:605px}.est-row-lvl-42 td:first-child{padding-left:620px}.est-row-lvl-43 td:first-child{padding-left:635px}.est-row-lvl-44 td:first-child{padding-left:650px}.est-row-lvl-45 td:first-child{padding-left:665px}.est-row-lvl-46 td:first-child{padding-left:680px}.est-row-lvl-47 td:first-child{padding-left:695px}.est-row-lvl-48 td:first-child{padding-left:710px}.est-row-lvl-49 td:first-child{padding-left:725px}.est-row-lvl-50 td:first-child{padding-left:740px}.est-row-lvl-51 td:first-child{padding-left:755px}.est-row-lvl-52 td:first-child{padding-left:770px}.est-row-lvl-53 td:first-child{padding-left:785px}.est-row-lvl-54 td:first-child{padding-left:800px}.est-row-lvl-55 td:first-child{padding-left:815px}.est-row-lvl-56 td:first-child{padding-left:830px}.est-row-lvl-57 td:first-child{padding-left:845px}.est-row-lvl-58 td:first-child{padding-left:860px}.est-row-lvl-59 td:first-child{padding-left:875px}.est-row-lvl-60 td:first-child{padding-left:890px}.est-row-lvl-61 td:first-child{padding-left:905px}.est-row-lvl-62 td:first-child{padding-left:920px}.est-row-lvl-63 td:first-child{padding-left:935px}.est-row-lvl-64 td:first-child{padding-left:950px}.est-row-lvl-65 td:first-child{padding-left:965px}.est-row-lvl-66 td:first-child{padding-left:980px}.est-row-lvl-67 td:first-child{padding-left:995px}.est-row-lvl-68 td:first-child{padding-left:1010px}.est-row-lvl-69 td:first-child{padding-left:1025px}.est-row-lvl-70 td:first-child{padding-left:1040px}.est-row-lvl-71 td:first-child{padding-left:1055px}.est-row-lvl-72 td:first-child{padding-left:1070px}.est-row-lvl-73 td:first-child{padding-left:1085px}.est-row-lvl-74 td:first-child{padding-left:1100px}.est-row-lvl-75 td:first-child{padding-left:1115px}.est-row-lvl-76 td:first-child{padding-left:1130px}.est-row-lvl-77 td:first-child{padding-left:1145px}.est-row-lvl-78 td:first-child{padding-left:1160px}.est-row-lvl-79 td:first-child{padding-left:1175px}.est-row-lvl-80 td:first-child{padding-left:1190px}.est-row-lvl-81 td:first-child{padding-left:1205px}.est-row-lvl-82 td:first-child{padding-left:1220px}.est-row-lvl-83 td:first-child{padding-left:1235px}.est-row-lvl-84 td:first-child{padding-left:1250px}.est-row-lvl-85 td:first-child{padding-left:1265px}.est-row-lvl-86 td:first-child{padding-left:1280px}.est-row-lvl-87 td:first-child{padding-left:1295px}.est-row-lvl-88 td:first-child{padding-left:1310px}.est-row-lvl-89 td:first-child{padding-left:1325px}.est-row-lvl-90 td:first-child{padding-left:1340px}.est-row-lvl-91 td:first-child{padding-left:1355px}.est-row-lvl-92 td:first-child{padding-left:1370px}.est-row-lvl-93 td:first-child{padding-left:1385px}.est-row-lvl-94 td:first-child{padding-left:1400px}.est-row-lvl-95 td:first-child{padding-left:1415px}.est-row-lvl-96 td:first-child{padding-left:1430px}.est-row-lvl-97 td:first-child{padding-left:1445px}.est-row-lvl-98 td:first-child{padding-left:1460px}.est-row-lvl-99 td:first-child{padding-left:1475px}.est-right-10{right:10px}.est-hidden{visibility:hidden}.est-padding-10{padding:10px!important}.est-margin-right-50{margin-right:50px}.est-page-sel{color:#000;margin-left:3px;margin-right:3px;padding:0 5px;font-size:inherit;border:none;border-radius:15px}.est-page-next,.est-page-prev{color:#000;font-size:inherit;padding:3px 0 0}.est-pinned-header{background-color:#fff;left:0;top:0;position:sticky;z-index:1;border-bottom:1px solid #dee2e6!important;padding:0!important}.est-pinned-border{border-right:2px solid #dee2e6!important}.est-cell-padding{padding:.3rem}.est-pinned-body{background-color:#fff;left:0;position:sticky;z-index:1;border-top:1px solid #dee2e6!important;padding:0!important}.est-inline{display:inline!important}.est-inline-block{display:inline-block!important}.est-link{color:#0275d8!important;cursor:pointer;text-decoration:none;display:block}.est-link:hover{color:#23527c!important;cursor:pointer;text-decoration:underline!important}.est-sticky-last-column{right:-1px;position:sticky;z-index:0;background-color:#fff}.est-sticky-last-column-alt{right:-1px;position:sticky;z-index:0;background-color:#f2f2f2}.est-ltab-border{border-left:2px solid #bbb}.est-rtab-border{border-right:2px solid #bbb}.est-cell-group-padding{padding:calc(.3rem + 1px);position:absolute;top:0;left:0;height:100%;width:100%}.est-margin-bottom-10{margin-bottom:10px}.est-text-center{text-align:center}.est-rg-sep-flex-right{display:flex;flex-direction:row-reverse;width:100%;margin:-5px}.est-rg-sep-flex-left{display:flex;flex-direction:row;width:100%;margin:-5px}.est-rg-hdr{font-weight:700}.est-rg-agg{font-style:italic}.est-rg{background-color:hsla(0,0%,46.7%,.4666666666666667)!important}.est-rg-sep{font-size:12px;padding-right:20px!important;background-color:hsla(0,0%,73.3%,.7333333333333333)!important}.est-rg-ipp{text-align:left;display:inline-flex;margin-right:25px}.est-rg-page{text-align:right;display:inline-flex;font-size:inherit;padding-top:5px}"]
|
|
2489
4056
|
},] }
|
|
2490
4057
|
];
|
|
2491
4058
|
EsTableComponent.ctorParameters = () => [
|
|
2492
4059
|
{ type: NgControl, decorators: [{ type: Self }, { type: Optional }] },
|
|
2493
4060
|
{ type: PreferencesService, decorators: [{ type: Optional }] },
|
|
4061
|
+
{ type: EsTableDefaultable, decorators: [{ type: Optional }, { type: Inject, args: [EST_DEFAULTS,] }] },
|
|
4062
|
+
{ type: String, decorators: [{ type: Optional }, { type: Inject, args: [EST_LOCALE,] }] },
|
|
2494
4063
|
{ type: LocalizationService },
|
|
2495
4064
|
{ type: ChangeDetectorRef },
|
|
2496
4065
|
{ type: HashingService },
|
|
2497
4066
|
{ type: UtilityService },
|
|
2498
|
-
{ type: ExportService }
|
|
4067
|
+
{ type: ExportService },
|
|
4068
|
+
{ type: DateService },
|
|
4069
|
+
{ type: MessageService }
|
|
2499
4070
|
];
|
|
2500
4071
|
EsTableComponent.propDecorators = {
|
|
2501
4072
|
EsTdsDirective: [{ type: ContentChildren, args: [EsTdDirective,] }],
|
|
@@ -2514,7 +4085,7 @@ EsTableComponent.propDecorators = {
|
|
|
2514
4085
|
CellActionPropagates: [{ type: Input }],
|
|
2515
4086
|
UseCustomCells: [{ type: Input }],
|
|
2516
4087
|
MaxHeight: [{ type: Input }],
|
|
2517
|
-
|
|
4088
|
+
ContainerClass: [{ type: Input }],
|
|
2518
4089
|
XLSXExport: [{ type: Input }],
|
|
2519
4090
|
CSVExport: [{ type: Input }],
|
|
2520
4091
|
AllSearch: [{ type: Input }],
|
|
@@ -2525,14 +4096,12 @@ EsTableComponent.propDecorators = {
|
|
|
2525
4096
|
RemovalCondition: [{ type: Input }],
|
|
2526
4097
|
Export: [{ type: Input }],
|
|
2527
4098
|
ShiftClick: [{ type: Input }],
|
|
2528
|
-
ShowPaging: [{ type: Input }],
|
|
2529
4099
|
HidePaging: [{ type: Input }],
|
|
2530
4100
|
HidePagingCount: [{ type: Input }],
|
|
2531
4101
|
HidePagingButtons: [{ type: Input }],
|
|
2532
4102
|
ContextMenu: [{ type: Input }],
|
|
2533
4103
|
ExportFileName: [{ type: Input }],
|
|
2534
4104
|
TableClass: [{ type: Input }],
|
|
2535
|
-
CountLabel: [{ type: Input }],
|
|
2536
4105
|
ExportFunction: [{ type: Input }],
|
|
2537
4106
|
HasHeaderGroup: [{ type: Input }],
|
|
2538
4107
|
HasSecondaryHeaderGroup: [{ type: Input }],
|
|
@@ -2558,9 +4127,12 @@ EsTableComponent.propDecorators = {
|
|
|
2558
4127
|
OwnKey: [{ type: Input }],
|
|
2559
4128
|
StartsExpanded: [{ type: Input }],
|
|
2560
4129
|
SavePreferences: [{ type: Input }],
|
|
4130
|
+
PagingStyle: [{ type: Input }],
|
|
4131
|
+
RowGroupingPagingStyle: [{ type: Input }],
|
|
2561
4132
|
SecondarySource: [{ type: Input }],
|
|
2562
4133
|
TertiarySource: [{ type: Input }],
|
|
2563
4134
|
UseSelectionCache: [{ type: Input }],
|
|
4135
|
+
ShowItemGroupsColumns: [{ type: Input }],
|
|
2564
4136
|
onOrderChanged: [{ type: Output }],
|
|
2565
4137
|
onSearchRequest: [{ type: Output }],
|
|
2566
4138
|
onSelectionChanged: [{ type: Output }],
|
|
@@ -2574,22 +4146,18 @@ EsTableComponent.propDecorators = {
|
|
|
2574
4146
|
ArraymodeItemsPerPage: [{ type: Input }]
|
|
2575
4147
|
};
|
|
2576
4148
|
|
|
2577
|
-
/**
|
|
2578
|
-
* Modello di configurazione per L'EsTable
|
|
2579
|
-
*/
|
|
4149
|
+
/** Modello di configurazione per L'EsTable */
|
|
2580
4150
|
class EsTableModuleConfig {
|
|
2581
4151
|
}
|
|
2582
4152
|
|
|
2583
|
-
/**
|
|
2584
|
-
* Classe di localizzazione per il componente **TablePagerComponent**
|
|
2585
|
-
*/
|
|
4153
|
+
/** Classe di localizzazione per il componente **TablePagerComponent** */
|
|
2586
4154
|
class TablePagerLoc extends LocalizationService {
|
|
2587
|
-
/**
|
|
2588
|
-
* @ignore
|
|
2589
|
-
*/
|
|
4155
|
+
/** @ignore */
|
|
2590
4156
|
constructor(LOC_LOCALE) {
|
|
2591
4157
|
super(LOC_LOCALE !== null && LOC_LOCALE !== void 0 ? LOC_LOCALE : 'it-IT');
|
|
2592
4158
|
super.set("en->it", "All", ["Tutto"]);
|
|
4159
|
+
super.set("en->it", "Shown Elements", ["Elementi visualizzati"]);
|
|
4160
|
+
super.set("en->it", "Shown Groups", ["Gruppi visualizzati"]);
|
|
2593
4161
|
super.set("en->it", "Are you sure you want to retrieve all results?", ["Si è sicuri di voler caricare tutti i risultati?"]);
|
|
2594
4162
|
super.set("en->it", "This might slow down the page and possibly crash the entire application", ["L'operazione potrebbe rallentare la pagina fino al crash dell'applicazione"]);
|
|
2595
4163
|
}
|
|
@@ -2602,32 +4170,35 @@ TablePagerLoc.ctorParameters = () => [
|
|
|
2602
4170
|
];
|
|
2603
4171
|
|
|
2604
4172
|
// Angular
|
|
2605
|
-
/**
|
|
2606
|
-
* Componente che si occupa della paginazione di una tabella
|
|
2607
|
-
*/
|
|
4173
|
+
/** Componente che si occupa della paginazione di una tabella */
|
|
2608
4174
|
class TablePagerComponent {
|
|
2609
|
-
/**
|
|
2610
|
-
|
|
2611
|
-
*/
|
|
2612
|
-
constructor(msgExts, lc) {
|
|
4175
|
+
/** @ignore */
|
|
4176
|
+
constructor(msgExts, lc, cdr, locale) {
|
|
2613
4177
|
this.msgExts = msgExts;
|
|
2614
4178
|
this.lc = lc;
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
4179
|
+
this.cdr = cdr;
|
|
4180
|
+
this.locale = locale;
|
|
4181
|
+
/** Indica se deve mostrare un warning quando si cercano di solezionare come elementi da visualizzare "Tutti" */
|
|
2618
4182
|
this.WarnOnAll = true;
|
|
2619
|
-
/**
|
|
2620
|
-
* Indica se dare la possibilità o meno di selezionare "Tutti" nelle opzioni di paginazione
|
|
2621
|
-
*/
|
|
4183
|
+
/** Indica se dare la possibilità o meno di selezionare "Tutti" nelle opzioni di paginazione */
|
|
2622
4184
|
this.AllSearch = true;
|
|
2623
|
-
/**
|
|
2624
|
-
* Placeholder che identifica il "Tutti"
|
|
2625
|
-
*/
|
|
4185
|
+
/** Placeholder che identifica il "Tutti" */
|
|
2626
4186
|
this.DefaultAll = 999999;
|
|
2627
|
-
/**
|
|
2628
|
-
|
|
2629
|
-
|
|
4187
|
+
/** Indica se attivare la modalità gruppo con stili più snelli per apparire sotto ai raggruppamenti */
|
|
4188
|
+
this.GroupMode = false;
|
|
4189
|
+
/** Indica se utilizzare il conteggio dei gruppi o degli oggetti */
|
|
4190
|
+
this.GroupCount = false;
|
|
4191
|
+
/** Indica se visualizzare il numero totale di oggeti presenti */
|
|
4192
|
+
this.ShowCount = true;
|
|
4193
|
+
/** Output invocato quando il numero di elementi per pagina viene modificato da un click utente */
|
|
2630
4194
|
this.pagingSelected = new EventEmitter();
|
|
4195
|
+
/** Opzioni di paginazione */
|
|
4196
|
+
this.PagingOptions = [10, 15, 30, 45, 100];
|
|
4197
|
+
}
|
|
4198
|
+
ngOnInit() {
|
|
4199
|
+
this.Model = this.View ? this.View.itemsperpageoverride : this.CurrentPageSize;
|
|
4200
|
+
if (this.AllSearch)
|
|
4201
|
+
this.PagingOptions.push(this.DefaultAll);
|
|
2631
4202
|
}
|
|
2632
4203
|
/**
|
|
2633
4204
|
* Funzione richiamata dal template quando un utente clicca su un numero di paginazione.
|
|
@@ -2638,30 +4209,48 @@ class TablePagerComponent {
|
|
|
2638
4209
|
*/
|
|
2639
4210
|
choice(pageSize) {
|
|
2640
4211
|
if (pageSize == this.DefaultAll && this.WarnOnAll) {
|
|
2641
|
-
this.msgExts.simpleWarningWithChoice(this.lc.loc("Are you sure you want to retrieve all results?"), this.lc.loc("This might slow down the page and possibly crash the entire application"), () => { this.pagingSelected.emit(pageSize); })
|
|
4212
|
+
this.msgExts.simpleWarningWithChoice(this.lc.loc("Are you sure you want to retrieve all results?"), this.lc.loc("This might slow down the page and possibly crash the entire application"), () => { this.pagingSelected.emit(pageSize); this.Model = pageSize; }, () => {
|
|
4213
|
+
// Dio solo sa perché mi tocca fare sta roba... qui dentro per qualche motivo la CD non prende
|
|
4214
|
+
let prevModel = this.Model;
|
|
4215
|
+
this.Model = null;
|
|
4216
|
+
this.cdr.detectChanges();
|
|
4217
|
+
this.Model = prevModel;
|
|
4218
|
+
this.cdr.detectChanges();
|
|
4219
|
+
});
|
|
2642
4220
|
}
|
|
2643
|
-
else
|
|
4221
|
+
else {
|
|
2644
4222
|
this.pagingSelected.emit(pageSize);
|
|
4223
|
+
this.Model = pageSize;
|
|
4224
|
+
}
|
|
2645
4225
|
}
|
|
2646
4226
|
}
|
|
2647
4227
|
TablePagerComponent.decorators = [
|
|
2648
4228
|
{ type: Component, args: [{
|
|
2649
4229
|
selector: "app-paging",
|
|
2650
4230
|
viewProviders: [{ provide: LocalizationService, useClass: TablePagerLoc }],
|
|
2651
|
-
template: "
|
|
4231
|
+
template: "<ng-container *ngIf=\"!Hidden\">\r\n <span class=\"est-fs-14\"> {{(GroupMode ? 'Shown Groups' : 'Shown Elements') | localize : lc}}: </span>\r\n <mat-form-field [appearance]=\"'legacy'\" class=\"mat-paginator-page-size-select est-fs-14 est-ipp-bold\" *ngIf=\"Model\">\r\n <select matNativeControl [ngModel]=\"Model\" name=\"input\" (ngModelChange)=\"choice($event)\">\r\n <ng-container *ngFor=\"let pOpt of PagingOptions\">\r\n <option *ngIf=\"pOpt == DefaultAll || PagerCount > pOpt\" [value]=\"pOpt\">{{ pOpt == DefaultAll ? ('All' | localize : lc) : pOpt.toString()}}</option>\r\n </ng-container>\r\n </select>\r\n </mat-form-field>\r\n <span class=\"est-fs-14 est-ipp-bold\" *ngIf=\"ShowCount\"> / {{PagerCount | number : '0.0-0' : locale}}\r\n </span>\r\n</ng-container>",
|
|
4232
|
+
encapsulation: ViewEncapsulation.None,
|
|
4233
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
4234
|
+
styles: [".est-ipp-sel,.est-ipp-sel-all,.est-rg-ipp-sel,.est-rg-ipp-sel-all{color:#0275d8!important;cursor:pointer;text-decoration:none;display:block;display:inline}.est-ipp-bold{font-weight:700}.mat-paginator-page-size-select{margin:6px 4px 0;width:50px}.mat-paginator-page-size-select .mat-form-field-wrapper{height:52px!important;margin-top:-15px!important;padding:0!important}.mat-form-field-type-mat-native-select .mat-form-field-infix:after{margin-top:-5.5px!important}"]
|
|
2652
4235
|
},] }
|
|
2653
4236
|
];
|
|
2654
4237
|
TablePagerComponent.ctorParameters = () => [
|
|
2655
4238
|
{ type: MessageService },
|
|
2656
|
-
{ type: LocalizationService }
|
|
4239
|
+
{ type: LocalizationService },
|
|
4240
|
+
{ type: ChangeDetectorRef },
|
|
4241
|
+
{ type: String, decorators: [{ type: Optional }, { type: Inject, args: [EST_LOCALE,] }] }
|
|
2657
4242
|
];
|
|
2658
4243
|
TablePagerComponent.propDecorators = {
|
|
2659
4244
|
CurrentPageSize: [{ type: Input }],
|
|
2660
4245
|
View: [{ type: Input }],
|
|
2661
|
-
Hidden: [{ type: Input }],
|
|
2662
4246
|
WarnOnAll: [{ type: Input }],
|
|
2663
4247
|
AllSearch: [{ type: Input }],
|
|
2664
4248
|
DefaultAll: [{ type: Input }],
|
|
4249
|
+
GroupMode: [{ type: Input }],
|
|
4250
|
+
GroupCount: [{ type: Input }],
|
|
4251
|
+
ShowCount: [{ type: Input }],
|
|
4252
|
+
PagerCount: [{ type: Input }],
|
|
4253
|
+
Hidden: [{ type: Input }],
|
|
2665
4254
|
pagingSelected: [{ type: Output }]
|
|
2666
4255
|
};
|
|
2667
4256
|
|
|
@@ -2670,7 +4259,8 @@ class EsTableModule {
|
|
|
2670
4259
|
return {
|
|
2671
4260
|
ngModule: EsTableModule,
|
|
2672
4261
|
providers: [
|
|
2673
|
-
{ provide: EST_LOCALE, useValue: (config === null || config === void 0 ? void 0 : config.locale) || 'it-IT' }
|
|
4262
|
+
{ provide: EST_LOCALE, useValue: (config === null || config === void 0 ? void 0 : config.locale) || 'it-IT' },
|
|
4263
|
+
{ provide: EST_DEBUG, useValue: (config === null || config === void 0 ? void 0 : config.debugMode) || false }
|
|
2674
4264
|
]
|
|
2675
4265
|
};
|
|
2676
4266
|
}
|
|
@@ -2685,7 +4275,9 @@ EsTableModule.decorators = [
|
|
|
2685
4275
|
ModalModule,
|
|
2686
4276
|
BsDropdownModule,
|
|
2687
4277
|
CsvModule,
|
|
2688
|
-
ContextMenuModule
|
|
4278
|
+
ContextMenuModule,
|
|
4279
|
+
MatSelectModule,
|
|
4280
|
+
MatInputModule
|
|
2689
4281
|
],
|
|
2690
4282
|
declarations: [EsTh, EsTd, EsTableComponent, EsTdDirective, EsThDirective, TablePagerComponent],
|
|
2691
4283
|
providers: [UtilityService, ExportService, HashingService, MessageService],
|
|
@@ -2701,5 +4293,5 @@ EsTableModule.decorators = [
|
|
|
2701
4293
|
* Generated bundle index. Do not edit.
|
|
2702
4294
|
*/
|
|
2703
4295
|
|
|
2704
|
-
export { AppOrdering, AppSearch, CornerMenuOption,
|
|
4296
|
+
export { AppOrdering, AppSearch, CornerMenuOption, EsTableColumnsDefinition, EsTableComponent, EsTableDefaultable, EsTableModule, EsTableModuleConfig, EsTableOperationDefinition, EsTd, EsTh, GenericItem, Group, GroupAggregation, GroupFilter, GroupOrAggregation, ItemsSelection, ReportColumn, ReportDefinition, ReportOrder, ReportParam, ReportResult, ReportRow, EsTableLoc as ɵa, EST_LOCALE as ɵb, EST_DEBUG as ɵc, EST_DEFAULTS as ɵd, EsTdDirective as ɵe, EsThDirective as ɵf, TablePagerComponent as ɵg, TablePagerLoc as ɵh };
|
|
2705
4297
|
//# sourceMappingURL=esfaenza-es-table.js.map
|