@esfaenza/es-table 11.2.20 → 11.2.22-beta3

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.
Files changed (111) hide show
  1. package/bundles/esfaenza-es-table.umd.js +1881 -539
  2. package/bundles/esfaenza-es-table.umd.js.map +1 -1
  3. package/bundles/esfaenza-es-table.umd.min.js +2 -2
  4. package/bundles/esfaenza-es-table.umd.min.js.map +1 -1
  5. package/esfaenza-es-table.d.ts +5 -5
  6. package/esfaenza-es-table.metadata.json +1 -1
  7. package/esm2015/esfaenza-es-table.js +6 -6
  8. package/esm2015/lib/directives/es_td.directive.js +2 -4
  9. package/esm2015/lib/directives/es_th.directive.js +17 -8
  10. package/esm2015/lib/domain/externals/classes/CornerMenuOption.js +4 -0
  11. package/esm2015/lib/domain/externals/classes/EsTableColumnsDefinition.js +31 -0
  12. package/esm2015/lib/domain/externals/classes/EsTableOperationDefinition.js +22 -0
  13. package/esm2015/lib/domain/externals/classes/appsearch/AppOrdering.js +16 -0
  14. package/esm2015/lib/domain/externals/classes/appsearch/AppSearch.js +35 -0
  15. package/esm2015/lib/domain/externals/classes/appsearch/GenericItem.js +11 -0
  16. package/esm2015/lib/domain/externals/classes/appsearch/Group.js +17 -0
  17. package/esm2015/lib/domain/externals/classes/appsearch/GroupAggregation.js +16 -0
  18. package/esm2015/lib/domain/externals/classes/appsearch/GroupFilter.js +14 -0
  19. package/esm2015/lib/domain/externals/classes/appsearch/GroupOrAggregation.js +16 -0
  20. package/esm2015/lib/domain/externals/classes/appsearch/ItemsSelection.js +23 -0
  21. package/esm2015/lib/domain/externals/classes/report/ReportColumn.js +4 -0
  22. package/esm2015/lib/domain/externals/classes/report/ReportDefinition.js +4 -0
  23. package/esm2015/lib/domain/externals/classes/report/ReportOrder.js +4 -0
  24. package/esm2015/lib/domain/externals/classes/report/ReportParam.js +4 -0
  25. package/esm2015/lib/domain/externals/classes/report/ReportResult.js +4 -0
  26. package/esm2015/lib/domain/externals/classes/report/ReportRow.js +4 -0
  27. package/esm2015/lib/domain/externals/index.js +18 -0
  28. package/esm2015/lib/domain/index.js +3 -16
  29. package/esm2015/lib/domain/internals/classes/CacheTriptic.js +16 -0
  30. package/esm2015/lib/domain/internals/classes/EsTableColumn.js +24 -0
  31. package/esm2015/lib/domain/internals/classes/GroupPager.js +21 -0
  32. package/esm2015/lib/domain/internals/classes/GroupRouteFragment.js +17 -0
  33. package/esm2015/lib/domain/internals/classes/ThAggregation.js +16 -0
  34. package/esm2015/lib/domain/internals/index.js +6 -0
  35. package/esm2015/lib/es-table.module.js +9 -4
  36. package/esm2015/lib/es_table.component.js +1496 -323
  37. package/esm2015/lib/es_table.component.loc.js +4 -7
  38. package/esm2015/lib/es_td.component.js +9 -20
  39. package/esm2015/lib/es_th.component.js +16 -44
  40. package/esm2015/lib/models/EsTableDefaultable.js +4 -0
  41. package/esm2015/lib/models/EsTableModuleConfig.js +2 -4
  42. package/esm2015/lib/pager/table_pager.component.js +48 -26
  43. package/esm2015/lib/pager/table_pager.component.loc.js +5 -7
  44. package/esm2015/lib/tokens.js +6 -4
  45. package/esm2015/public-api.js +3 -2
  46. package/fesm2015/esfaenza-es-table.js +1762 -510
  47. package/fesm2015/esfaenza-es-table.js.map +1 -1
  48. package/lib/directives/es_td.directive.d.ts +1 -3
  49. package/lib/directives/es_th.directive.d.ts +14 -7
  50. package/lib/domain/externals/classes/CornerMenuOption.d.ts +7 -0
  51. package/lib/domain/{classes → externals/classes}/EsTableColumnsDefinition.d.ts +2 -6
  52. package/lib/domain/{classes → externals/classes}/EsTableOperationDefinition.d.ts +1 -3
  53. package/lib/domain/{classes → externals/classes/appsearch}/AppOrdering.d.ts +0 -0
  54. package/lib/domain/externals/classes/appsearch/AppSearch.d.ts +67 -0
  55. package/lib/domain/externals/classes/appsearch/GenericItem.d.ts +13 -0
  56. package/lib/domain/externals/classes/appsearch/Group.d.ts +17 -0
  57. package/lib/domain/externals/classes/appsearch/GroupAggregation.d.ts +14 -0
  58. package/lib/domain/externals/classes/appsearch/GroupFilter.d.ts +12 -0
  59. package/lib/domain/externals/classes/appsearch/GroupOrAggregation.d.ts +14 -0
  60. package/lib/domain/externals/classes/appsearch/ItemsSelection.d.ts +22 -0
  61. package/lib/domain/externals/classes/report/ReportColumn.d.ts +15 -0
  62. package/lib/domain/externals/classes/report/ReportDefinition.d.ts +24 -0
  63. package/lib/domain/externals/classes/report/ReportOrder.d.ts +7 -0
  64. package/lib/domain/externals/classes/report/ReportParam.d.ts +40 -0
  65. package/lib/domain/externals/classes/report/ReportResult.d.ts +12 -0
  66. package/lib/domain/externals/classes/report/ReportRow.d.ts +5 -0
  67. package/lib/domain/externals/index.d.ts +17 -0
  68. package/lib/domain/index.d.ts +2 -15
  69. package/lib/domain/internals/classes/CacheTriptic.d.ts +14 -0
  70. package/lib/domain/{classes → internals/classes}/EsTableColumn.d.ts +6 -4
  71. package/lib/domain/internals/classes/GroupPager.d.ts +22 -0
  72. package/lib/domain/internals/classes/GroupRouteFragment.d.ts +15 -0
  73. package/lib/domain/internals/classes/ThAggregation.d.ts +14 -0
  74. package/lib/domain/internals/index.d.ts +5 -0
  75. package/lib/es_table.component.d.ts +346 -51
  76. package/lib/es_table.component.loc.d.ts +2 -6
  77. package/lib/es_td.component.d.ts +13 -36
  78. package/lib/es_th.component.d.ts +21 -61
  79. package/lib/models/EsTableDefaultable.d.ts +19 -0
  80. package/lib/models/EsTableModuleConfig.d.ts +8 -7
  81. package/lib/pager/table_pager.component.d.ts +27 -30
  82. package/lib/pager/table_pager.component.loc.d.ts +2 -6
  83. package/lib/tokens.d.ts +6 -3
  84. package/package.json +2 -1
  85. package/public-api.d.ts +2 -1
  86. package/esm2015/lib/domain/classes/AppOrdering.js +0 -16
  87. package/esm2015/lib/domain/classes/AppSearch.js +0 -56
  88. package/esm2015/lib/domain/classes/CornerMenuOption.js +0 -6
  89. package/esm2015/lib/domain/classes/EsTableColumn.js +0 -22
  90. package/esm2015/lib/domain/classes/EsTableColumnsDefinition.js +0 -33
  91. package/esm2015/lib/domain/classes/EsTableOperationDefinition.js +0 -24
  92. package/esm2015/lib/domain/classes/GenericItem.js +0 -15
  93. package/esm2015/lib/domain/classes/IAppSearch.js +0 -2
  94. package/esm2015/lib/domain/classes/ItemsSelection.js +0 -25
  95. package/esm2015/lib/domain/classes/ReportColumn.js +0 -6
  96. package/esm2015/lib/domain/classes/ReportDefinition.js +0 -6
  97. package/esm2015/lib/domain/classes/ReportOrder.js +0 -6
  98. package/esm2015/lib/domain/classes/ReportParam.js +0 -6
  99. package/esm2015/lib/domain/classes/ReportResult.js +0 -6
  100. package/esm2015/lib/domain/classes/ReportRow.js +0 -6
  101. package/lib/domain/classes/AppSearch.d.ts +0 -110
  102. package/lib/domain/classes/CornerMenuOption.d.ts +0 -13
  103. package/lib/domain/classes/GenericItem.d.ts +0 -25
  104. package/lib/domain/classes/IAppSearch.d.ts +0 -67
  105. package/lib/domain/classes/ItemsSelection.d.ts +0 -27
  106. package/lib/domain/classes/ReportColumn.d.ts +0 -29
  107. package/lib/domain/classes/ReportDefinition.d.ts +0 -46
  108. package/lib/domain/classes/ReportOrder.d.ts +0 -13
  109. package/lib/domain/classes/ReportParam.d.ts +0 -76
  110. package/lib/domain/classes/ReportResult.d.ts +0 -22
  111. package/lib/domain/classes/ReportRow.d.ts +0 -9
@@ -7,6 +7,8 @@ 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';
@@ -61,32 +63,9 @@ class AppSearch {
61
63
  this.column_ordering = [];
62
64
  this.savedstate = false;
63
65
  }
64
- }
65
- class Group {
66
- constructor(column, value) {
67
- this.column = column;
68
- this.value = value;
69
- this.aggregations = [];
70
- }
71
- }
72
- class GroupAggregation {
73
- }
74
- class GroupFilter {
75
- constructor(column, value) {
76
- this.column = column;
77
- this.value = value;
78
- }
79
- }
80
- class GroupOrAggregation {
81
- constructor(column, aggregation) {
82
- this.column = column;
83
- this.aggregation = aggregation;
84
- }
85
66
  }
86
67
 
87
- /**
88
- * Classe che identifica una colonna. Utilizzata in modalità "Colonne dinamiche"
89
- */
68
+ /** Classe che identifica una colonna. Utilizzata in modalità "Colonne dinamiche" */
90
69
  class EsTableColumnsDefinition {
91
70
  /**
92
71
  * Costruttore
@@ -117,66 +96,46 @@ class EsTableColumnsDefinition {
117
96
  }
118
97
  }
119
98
 
120
- /**
121
- * Classe che definisce un oggetto generico come lista di proprietà-valore
122
- */
99
+ /** Classe che definisce un oggetto generico come lista di proprietà-valore */
123
100
  class GenericItem {
124
- /**
125
- * @ignore
126
- */
101
+ /** @ignore */
127
102
  constructor() {
128
103
  this._selected = false;
129
104
  this._rowClass = null;
130
- this.hash = null;
105
+ this._hash = null;
131
106
  this.properties = {};
132
107
  }
133
108
  }
134
109
 
135
- /**
136
- * Indica un'opzione cliccabile nel Corner Menù della tabella (il menù richiamabile dai 3 pallini verticli in alto a destra)
137
- */
110
+ /** Indica un'opzione cliccabile nel Corner Menù della tabella (il menù richiamabile dai 3 pallini verticli in alto a destra) */
138
111
  class CornerMenuOption {
139
112
  }
140
113
 
141
- /**
142
- * Definizione generica di un report che può o no disporre di paginazione/export e la cui richiesta è basata su uno o più parametri
143
- */
114
+ /** Definizione generica di un report che può o no disporre di paginazione/export e la cui richiesta è basata su uno o più parametri */
144
115
  class ReportDefinition {
145
116
  }
146
117
 
147
- /**
148
- * Classe che identifica una direttiva di ordinamento per un report
149
- */
118
+ /** Classe che identifica una direttiva di ordinamento per un report */
150
119
  class ReportOrder {
151
120
  }
152
121
 
153
- /**
154
- * Classe che rappresenta una colonna di un report
155
- */
122
+ /** Classe che rappresenta una colonna di un report */
156
123
  class ReportColumn {
157
124
  }
158
125
 
159
- /**
160
- * Classe che rappresenta una lista di oggetti generati da un report
161
- */
126
+ /** Classe che rappresenta una lista di oggetti generati da un report */
162
127
  class ReportResult {
163
128
  }
164
129
 
165
- /**
166
- * Classe che rappresenta i valori delle proprietà di un oggetto Report
167
- */
130
+ /** Classe che rappresenta i valori delle proprietà di un oggetto Report */
168
131
  class ReportRow {
169
132
  }
170
133
 
171
- /**
172
- * Classe che identifica un parametro generico per un report
173
- */
134
+ /** Classe che identifica un parametro generico per un report */
174
135
  class ReportParam {
175
136
  }
176
137
 
177
- /**
178
- * Indica operazioni dinamiche generiche che possono essere effettuate per riga. Appaiono come colonne extra sul lato sinistro della tabella
179
- */
138
+ /** Indica operazioni dinamiche generiche che possono essere effettuate per riga. Appaiono come colonne extra sul lato sinistro della tabella */
180
139
  class EsTableOperationDefinition {
181
140
  /**
182
141
  * Costruttore
@@ -198,9 +157,109 @@ class EsTableOperationDefinition {
198
157
  }
199
158
  }
200
159
 
201
- /**
202
- * Definizione di una colonna
203
- */
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à */
204
263
  class EsTableColumn {
205
264
  /**
206
265
  * Costruttore
@@ -209,66 +268,89 @@ class EsTableColumn {
209
268
  * @param {string} description Descrizione (Header)
210
269
  * @param {boolean} visible Indica se di default mostrarla o meno
211
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
212
273
  * @param {TemplateRef<any>} template Indica il template da usare per mostrare il testo dell'Header
213
274
  */
214
- constructor(id, description, visible, fixed, template) {
275
+ constructor(id, description, visible, fixed, pinned, pinnedWidth, template) {
215
276
  this.id = id;
216
277
  this.description = description;
217
278
  this.visible = visible;
218
279
  this.fixed = fixed;
280
+ this.pinned = pinned;
281
+ this.pinnedWidth = pinnedWidth;
219
282
  this.template = template;
220
283
  }
221
284
  }
222
285
 
223
- /**
224
- * Identifica una selezione applicabile agli oggetti presentati in una tabella
225
- */
226
- 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 {
227
288
  /**
228
289
  * Costruttore
229
290
  *
230
- * @param {T[]} selected Oggetti da considerare selezionati
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
231
295
  */
232
- constructor(selected) {
233
- /**
234
- * Indica se tutti gli elementi sono da considerarsi selezionati (anche quelli di altre pagine)
235
- */
236
- this.all = false;
237
- /**
238
- * Se **all** è **true**, indica gli elementi da escludere, altrimenti è insensato
239
- */
240
- this.exclusions = [];
241
- this.count = selected.length;
242
- this.items = selected;
243
- this.all = false;
244
- 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 = [];
245
304
  }
246
305
  }
247
306
 
248
- //Angular
249
307
  /**
250
- * Componente rappresentante una singola cella del body della tabella
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
251
310
  */
252
- class EsTd {
311
+ class GroupRouteFragment {
253
312
  /**
254
- * @ignore
313
+ * Costruttore
314
+ *
315
+ * @param {string} column Colonna di raggruppamento
316
+ * @param {string} value Valore della colonna di raggruppamento
255
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
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 */
256
344
  constructor(myself, renderer, _viewContainer, sanitizer) {
257
345
  this.myself = myself;
258
346
  this.renderer = renderer;
259
347
  this._viewContainer = _viewContainer;
260
348
  this.sanitizer = sanitizer;
261
- /**
262
- * Id della cella, dev'essere lo stesso della colonna **EsTh** relativa
263
- */
349
+ /** Id della cella, dev'essere lo stesso della colonna **EsTh** relativa */
264
350
  this.ID = "";
265
- /**
266
- * Valore da mostrare all'interno della cella. Se omesso verrà proiettato il contenuto dal template in cui è stata usata
267
- */
351
+ /** Valore da mostrare all'interno della cella. Se omesso verrà proiettato il contenuto dal template in cui è stata usata */
268
352
  this.Display = null;
269
- /**
270
- * Template Angular da istanziare per questo TD
271
- */
353
+ /** Template Angular da istanziare per questo TD */
272
354
  this.Template = null;
273
355
  }
274
356
  /**
@@ -293,18 +375,17 @@ class EsTd {
293
375
  this._Visible = true;
294
376
  return this._Visible;
295
377
  }
296
- /**
297
- * @ignore
298
- */
378
+ /** @ignore */
299
379
  ngAfterViewInit() {
300
380
  // Se è Internal significa che è gestita internamente da ES-TABLE quindi evito di fare sti due passaggi di lettura del DOM
301
381
  if (this.Internal)
302
382
  return;
303
383
  // L'hash è calcolato dalla ES-table in fase di binding
304
- this.Context = this.Context || this.getTemplateContext().hash;
384
+ this.Context = this.Context || this.getTemplateContext()._hash;
305
385
  this.Content = this.Display === null || this.Display === "" ? this.sanitizer.bypassSecurityTrustHtml(this.myself.nativeElement.innerHTML) : this.sanitizer.bypassSecurityTrustHtml(this.Display);
306
386
  this.Class = this.myself.nativeElement.className.replace("app-display-none", "");
307
387
  }
388
+ /** Ottiene il contesto della view su cui è istanziato il componente */
308
389
  getTemplateContext() {
309
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
310
391
  let vc = this._viewContainer;
@@ -361,23 +442,15 @@ EsTd.propDecorators = {
361
442
  };
362
443
 
363
444
  //Angular
364
- /**
365
- * Componente rappresentante una Colonna della tabella
366
- */
445
+ /** Componente rappresentante una Colonna della tabella */
367
446
  class EsTh {
368
- /**
369
- * @ignore
370
- */
447
+ /** @ignore */
371
448
  constructor(myself, renderer) {
372
449
  this.myself = myself;
373
450
  this.renderer = renderer;
374
- /**
375
- * Dizionario di mappatura con ordinamento attuale e ordinamento successivo per gestire i passaggi di stato
376
- */
451
+ /** Dizionario di mappatura con ordinamento attuale e ordinamento successivo per gestire i passaggi di stato */
377
452
  this.orderNext = { "NONE": "DESC", "DESC": "ASC", "ASC": null };
378
- /**
379
- * Indica se si sta effettuando un'operazione di resize su questa colonna
380
- */
453
+ /** Indica se si sta effettuando un'operazione di resize su questa colonna */
381
454
  this.resizingThis = false;
382
455
  /**
383
456
  * Storicizza l'offset di partenza del resize dell'elemento HTML per poter calcolare la nuova dimensione richiesta durente il resize
@@ -385,21 +458,13 @@ class EsTh {
385
458
  * nuova width = startOffset + posizione X del mouse
386
459
  */
387
460
  this.startOffset = null;
388
- /**
389
- * Id della colonna, dev'essere lo stesso per tutti gli **EsTd** relativi
390
- */
461
+ /** Id della colonna, dev'essere lo stesso per tutti gli **EsTd** relativi */
391
462
  this.ID = "";
392
- /**
393
- * Indica se questa colonna è ordinabile o meno
394
- */
463
+ /** Indica se questa colonna è ordinabile o meno */
395
464
  this.Orderable = true;
396
- /**
397
- * Valore da mostrare all'interno della colonna. Se omesso verrà proiettato il contenuto dal template in cui è stata usata
398
- */
465
+ /** Valore da mostrare all'interno della colonna. Se omesso verrà proiettato il contenuto dal template in cui è stata usata */
399
466
  this.Display = "";
400
- /**
401
- * Indica se le dimnsioni di questa colonna sono modificabili o meno
402
- */
467
+ /** Indica se le dimnsioni di questa colonna sono modificabili o meno */
403
468
  this.Resizable = false;
404
469
  /**
405
470
  * Indica se sta venendo eseguita una operazione di ricerca o meno, serve per evitare l'esecuzione di eventuale codice che potrebbe dare fastidio
@@ -410,18 +475,12 @@ class EsTh {
410
475
  this.Wrap = false;
411
476
  /** Indica se la colonna è fixed, cioè se non può né essere nascosta, né riposizionata. Solo le prime colonne possono essere Fixed */
412
477
  this.Fixed = false;
413
- /**
414
- * Template Angular da istanziare per questo TH
415
- */
478
+ /** Template Angular da istanziare per questo TH */
416
479
  this.Template = null;
417
- /**
418
- * Evento emesso al cambio di ordinamento effettuato su questa colonna
419
- */
480
+ /** Evento emesso al cambio di ordinamento effettuato su questa colonna */
420
481
  this.onOrderChange = new EventEmitter();
421
- /**
422
- * Impostato dall'**EsTable**, per controllare che ci sia almeno un TD che utilizzi quest'header
423
- */
424
- this.Referenced = false;
482
+ /** Impostato dall'**EsTable**, per controllare che ci sia almeno un TD che utilizzi quest'header */
483
+ this._referenced = false;
425
484
  }
426
485
  /**
427
486
  * Imposta la visibilità o meno della colonna, si traduce nell'applicazione o rimozione della classe **app-display-none**
@@ -445,9 +504,7 @@ class EsTh {
445
504
  this._Visible = true;
446
505
  return this._Visible;
447
506
  }
448
- /**
449
- * @ignore
450
- */
507
+ /** @ignore */
451
508
  ngAfterViewInit() {
452
509
  //Assegnare direttamente il content è più veloce che passare dal native element per qualche motivo
453
510
  this.Description = this.Display === null || this.Display === "" ? this.content.nativeElement.innerText : this.Display;
@@ -456,9 +513,7 @@ class EsTh {
456
513
  if (this.Resizable)
457
514
  this.renderer.addClass(this.myself.nativeElement, "app-relative");
458
515
  }
459
- /**
460
- * Gestisce la modifica dell'ordinamento qualora venisse cliccato su questa colonna
461
- */
516
+ /** Gestisce la modifica dell'ordinamento qualora venisse cliccato su questa colonna */
462
517
  setupNextOrderAndNotify() {
463
518
  if (!this.ID) {
464
519
  console.log("Attempt to order a column without ID. Operation ignored");
@@ -485,9 +540,7 @@ class EsTh {
485
540
  this.resizingThis = true;
486
541
  this.startOffset = this.myself.nativeElement.offsetWidth - ev.pageX;
487
542
  }
488
- /**
489
- * Listener per la fine dell'operazione di resize
490
- */
543
+ /** Listener per la fine dell'operazione di resize */
491
544
  onMouseUp() {
492
545
  if (!this.Resizable)
493
546
  return;
@@ -537,9 +590,7 @@ EsTh.propDecorators = {
537
590
  onMouseMove: [{ type: HostListener, args: ['window:mousemove.out-zone', ['$event'],] }]
538
591
  };
539
592
 
540
- /**
541
- * Direttiva per la dichiarazione snella di un EsTd da emettere per ogni elemento, data una colonna
542
- */
593
+ /** Direttiva per la dichiarazione snella di un EsTd da emettere per ogni elemento, data una colonna */
543
594
  class EsTdDirective {
544
595
  /**
545
596
  * @ignore
@@ -567,23 +618,31 @@ EsTdDirective.propDecorators = {
567
618
  tdClass: [{ type: Input }]
568
619
  };
569
620
 
570
- /**
571
- * Direttiva per la dichiarazione snella di un EsTh da emettere come header
572
- */
621
+ /** Direttiva per la dichiarazione snella di un EsTh da emettere come header */
573
622
  class EsThDirective {
574
623
  /**
575
624
  * @ignore
576
625
  */
577
626
  constructor(Template) {
578
627
  this.Template = Template;
628
+ /** Variabile interna all'interno della quale viene raccolta la cache delle aggregazioni specificate in thAggregation */
629
+ this._thAggregations = null;
579
630
  /** Variabile interna che indica il fatto che questo componente è una direttiva. Serve per disambigualrlo dell'EsThComponent */
580
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;
581
634
  /** Id della colonna, dev'essere lo stesso per tutti i **td** relativi */
582
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;
583
640
  /** Indicazione sulla visibilità della colonna */
584
641
  this.thVisible = true;
585
642
  /** Indica se la colonna è fixed, cioè se non può né essere nascosta, né riposizionata. Solo le prime colonne possono essere Fixed */
586
643
  this.thFixed = false;
644
+ /** Indica che la colonna è sotto ad un raggruppamento padre, con questo nome nel **th** */
645
+ this.thParent = "";
587
646
  /** Indica se questa colonna è ordinabile o meno */
588
647
  this.thOrderable = true;
589
648
  /** Indica se il testo presente in questo Header può andare a capo o meno, di default non può */
@@ -592,12 +651,10 @@ class EsThDirective {
592
651
  this.thResizable = false;
593
652
  /** Equivalente dell'NgIf sul th */
594
653
  this.thIf = true;
595
- /** @ignore Sperimentale: Indica che bisogna fare un raggruppamento su questa colonna */
654
+ /** Indica che bisogna fare un raggruppamento su questa colonna */
596
655
  this.thGroup = false;
597
- /** @ignore Sperimentale: Indica che bisogna fare una aggregazione su questa colonna, a fronte di almeno un altra con un raggruppamento */
656
+ /** Indica che bisogna fare una aggregazione su questa colonna, a fronte di almeno un altra con un raggruppamento */
598
657
  this.thAggregation = null;
599
- /** Impostato dall'**EsTable**, per controllare che ci sia almeno un TD che utilizzi quest'header */
600
- this.Referenced = false;
601
658
  }
602
659
  }
603
660
  EsThDirective.decorators = [
@@ -608,8 +665,11 @@ EsThDirective.ctorParameters = () => [
608
665
  ];
609
666
  EsThDirective.propDecorators = {
610
667
  th: [{ type: Input }],
668
+ thPinned: [{ type: Input }],
669
+ thPinnedWidth: [{ type: Input }],
611
670
  thVisible: [{ type: Input }],
612
671
  thFixed: [{ type: Input }],
672
+ thParent: [{ type: Input }],
613
673
  thOrder: [{ type: Input }],
614
674
  thOrderable: [{ type: Input }],
615
675
  thWrap: [{ type: Input }],
@@ -621,21 +681,20 @@ EsThDirective.propDecorators = {
621
681
  thAggregation: [{ type: Input }]
622
682
  };
623
683
 
624
- /**
625
- * Token che indica il locale da utilizzare all'interno del componente. Supportati solo "it-IT" ed "en-US"
626
- */
627
- const EST_LOCALE = new InjectionToken('EST_LOCALE');
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');
628
690
 
629
- /**
630
- * Classe di localizzazione per il componente **EsTableComponent**
631
- */
691
+ /** Classe di localizzazione per il componente **EsTableComponent** */
632
692
  class EsTableLoc extends LocalizationService {
633
- /**
634
- * @ignore
635
- */
693
+ /** @ignore */
636
694
  constructor(LOC_LOCALE) {
637
695
  super(LOC_LOCALE !== null && LOC_LOCALE !== void 0 ? LOC_LOCALE : 'it-IT');
638
696
  super.set("en->it", "All", ["Tutto"]);
697
+ super.set("en->it", "Groups", ["Gruppi"]);
639
698
  super.set("en->it", "Cannot export an empty dataset", ["Impossibile esportare un dataset vuoto"]);
640
699
  super.set("en->it", "Performing Table bootstrap", ["Sto caricando la Tabella"]);
641
700
  super.set("en->it", "Update every", ["Aggiorna ogni"]);
@@ -661,12 +720,19 @@ EsTableLoc.ctorParameters = () => [
661
720
  { type: String, decorators: [{ type: Optional }, { type: Inject, args: [EST_LOCALE,] }] }
662
721
  ];
663
722
 
723
+ /** Raccolta di tutti gli Input dell'EsTable a cui può essere logicamente sensato assegnare default per progetto */
724
+ class EsTableDefaultable {
725
+ }
726
+
664
727
  /** Componente che permette di rappresentare una griglia di valori */
665
728
  class EsTableComponent {
666
729
  /** @ignore */
667
- constructor(ngControl, prefService, lc, cdr, hashExts, utiExts, expExts, dateExts, msgExts) {
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;
668
732
  this.ngControl = ngControl;
669
733
  this.prefService = prefService;
734
+ this.deafults = deafults;
735
+ this.locale = locale;
670
736
  this.lc = lc;
671
737
  this.cdr = cdr;
672
738
  this.hashExts = hashExts;
@@ -678,10 +744,7 @@ class EsTableComponent {
678
744
  this.View = null;
679
745
  /** Indica se l'es-table deve mostrare il check globale nell'header per fare il "seleziona tutto" */
680
746
  this.globalCheck = false;
681
- /**
682
- * Tiene da conto l'ultimo elemento selezionato in modo da fare ragionamenti del tipo
683
- * "Ho selezionato questo, l'ultimo selezionato era **lastSelected**, devo selezionare tutti quelli in mezzo", ad esempio per la selezione multipla
684
- */
747
+ /** Tiene da conto l'ultimo elemento selezionato in modo da poter effettuare il SHIFT+CLICK */
685
748
  this.lastSelected = null;
686
749
  /** Conteggio interno per il numero di elementi selezionati */
687
750
  this.selectedObjects = 0;
@@ -720,6 +783,10 @@ class EsTableComponent {
720
783
  this.RowTHs = null;
721
784
  /** Modello di appoggio temporaneo per i **RowTHs** */
722
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;
723
790
  /** Cache per i routerLink generati nelle tabelle dinamiche */
724
791
  this.DynamicTableRouterLinkCache = {};
725
792
  /**
@@ -786,14 +853,14 @@ class EsTableComponent {
786
853
  this.UseCustomCells = null;
787
854
  /** Permette di impostare l'altezza massima della tabella. Se null la dimensione si adatta al numero di elementi attualmente in visualizzazione */
788
855
  this.MaxHeight = null;
789
- /** Classi da applicare alla tabella oltre a quelle gestite autonomamente dalla libreria */
790
- this.Class = '';
856
+ /** Classi da applicare al contenitore della tabella */
857
+ this.ContainerClass = null;
791
858
  /** Permette o meno l'export in formato XLSX */
792
859
  this.XLSXExport = null;
793
860
  /** Permette o meno l'export in formato CSV */
794
861
  this.CSVExport = true;
795
862
  /** Permette di visualizzare o meno l'opzione di paginazione "Tutti" */
796
- this.AllSearch = true;
863
+ this.AllSearch = null;
797
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 */
798
865
  this.HighCellDensity = null;
799
866
  /** Abilita o meno la possibilità di selezionare oggetti */
@@ -812,8 +879,6 @@ class EsTableComponent {
812
879
  this.Export = null;
813
880
  /** Indica se permettere la selezione multipla Windows-like cliccando un oggetto e facendo poi Shift + click su un oggetto successivo */
814
881
  this.ShiftClick = null;
815
- /** Mostra o nasconde le informazioni di paginazione, sia i pulsanti, sia il selettore degli oggetti per pagina */
816
- this.ShowPaging = true;
817
882
  /** Indica se nascondere o mostrare il componente di paginazione */
818
883
  this.HidePaging = null;
819
884
  /** Indica se nascondere o mostrare il conteggio degli elementi trovati */
@@ -825,12 +890,10 @@ class EsTableComponent {
825
890
  /** Nome dell'esportazione generata da questa tabella */
826
891
  this.ExportFileName = 'Export.csv';
827
892
  /** Classe (HTML) di default della tabella */
828
- this.TableClass = 'table table-striped table-hover table-sm';
829
- /** Testo da visualizzare nel conteggio. Di default: "Oggetti selezionati" */
830
- this.CountLabel = this.lc.loc('Found objects');
831
- /** Indica la presenza di raggruppamenti a livello di header */
893
+ this.TableClass = null;
894
+ /** @deprecated Indica la presenza di raggruppamenti a livello di header */
832
895
  this.HasHeaderGroup = null;
833
- /** 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** */
834
897
  this.HasSecondaryHeaderGroup = null;
835
898
  /** Utilizzato per dividere la sorgente in modalità EndlessScroll */
836
899
  this.SliceSize = 100;
@@ -862,11 +925,7 @@ class EsTableComponent {
862
925
  this.HiddenColumns = null;
863
926
  /** Permette di riordinare le colonne in base alle impostazioni effettuate dal Menù contestuale in alto a destra */
864
927
  this.ColumnsOrdering = null;
865
- /**
866
- * Eventuale supporto alle ricerche applicate alla modalità Array
867
- *
868
- * @deprecated Utilizzato solo per un caso particolare del Metering
869
- */
928
+ /** Eventuale supporto alle ricerche applicate alla modalità Array */
870
929
  this.SearchView = null;
871
930
  /** Abilita o disabilita il sistema che permette di selezionare tutti gli elementi nella vista */
872
931
  this.SelectAll = null;
@@ -886,6 +945,10 @@ class EsTableComponent {
886
945
  this.StartsExpanded = true;
887
946
  /** Indica se effettuare il salvataggio delle preferenze di ricerca */
888
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;
889
952
  /**
890
953
  * Sorgente dati secondaria
891
954
  *
@@ -899,7 +962,9 @@ class EsTableComponent {
899
962
  */
900
963
  this.TertiarySource = null;
901
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 */
902
- this.UseSelectionCache = true;
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;
903
968
  /** Evento che viene richiamato al cambio di oridnamento di una colonna */
904
969
  this.onOrderChanged = new EventEmitter();
905
970
  /**
@@ -932,32 +997,91 @@ class EsTableComponent {
932
997
  /** Numero di pagine (durante la paginazione in modalità Array) */
933
998
  this.arraymodePages = 1;
934
999
  /** Oggetti per ogni pagina (durante la paginazione in modalità Array) */
935
- this.ArraymodeItemsPerPage = 15;
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 = [];
936
1007
  /**
937
1008
  * Variabile che serve a gestire il momento in cui l'es-table aggiorna la paginazione (pulsanti ecc).
938
1009
  * Essendo operazioni comunque costose le effettuo solo su binding esterni, non su rewrite generati internamente
939
1010
  */
940
1011
  this.internalWriteCall = false;
941
- /** Cache di selezione Hash - Oggetto */
942
- this.selOrDeselCache = {};
943
1012
  /**
944
- * Variabile d'appoggio per capire se c'è bisogno di ri-effettuare una ricerca o meno
945
- */
946
- this.ResearchNeeded = false;
947
- /**
948
- * Variabile da usare nei "colspan" quando si vuole dire "Tutte le colonne". 42 è un numero magico che mi serve per non calcolare questa variabile quando mi serve.
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
+ *
949
1016
  *
950
- * Di base dovrebbe essere la somma dei RowTH con l'aggiunta di tutti gli Header extra in base alle situazioni. Dato che diventa una logica deficiente me la cavo così
1017
+ * **Cambio ordinamento sul primo gruppo**: reload completo, non mi occupo di ripulire gli elementi bindati in alcun modo
951
1018
  *
952
- * Se in una tabella ci sono meno di 42 colonne il colspan si ferma comunque alla fine, se invece ce ne sono di più... beh bisogna allungare sto numero
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
953
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
954
1027
  */
955
- this.allColumns = "42";
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' };
956
1062
  /** @ignore */
957
1063
  this.propagateChange = (_) => { };
958
1064
  if (ngControl)
959
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);
960
1083
  }
1084
+ // #region Ciclo di vita ES-Table - Inizializzazioni
961
1085
  /** @ignore */
962
1086
  ngOnInit() {
963
1087
  //Per poter cambiare il layout in base al livello gerarchico il componente deva avere il pieno controllo di ogni cella,
@@ -966,6 +1090,9 @@ class EsTableComponent {
966
1090
  throw "Es-table error: Per poter utilizzare l'es-table con [Hierarchy]=\"true\" è richiesto anche [UseCustomCells]=\"true\"";
967
1091
  // click destro su una riga con selezione attiva: Tiro fuori il context menu e selezione l'elemento corrente
968
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;
969
1096
  let shouldEmit = !t.item._selected;
970
1097
  t.item._selected = true;
971
1098
  var itemSelection = this.handleItemsSelection([t.item]);
@@ -993,6 +1120,26 @@ class EsTableComponent {
993
1120
  this.ShiftClick = true;
994
1121
  }
995
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
+ }
996
1143
  /** @ignore */
997
1144
  ngOnDestroy() {
998
1145
  if (this.ctxMenuSubscription)
@@ -1006,6 +1153,7 @@ class EsTableComponent {
1006
1153
  this.arrayPulsanti = this.getPagesArray(6, this.SearchView.page, this.SearchView.pages || 1);
1007
1154
  });
1008
1155
  }
1156
+ // #endregion
1009
1157
  // #region Implementazione ControlValueAccessor ignorabile
1010
1158
  /** @ignore */
1011
1159
  registerOnChange(fn) { this.propagateChange = fn; }
@@ -1016,6 +1164,7 @@ class EsTableComponent {
1016
1164
  // #endregion
1017
1165
  /** @ignore */
1018
1166
  writeValue(obj) {
1167
+ var _a;
1019
1168
  this.View = obj ? obj : null;
1020
1169
  // Mi è arrivata l'AppSearch quindi di sicuro non ho una ricerca in progress
1021
1170
  this.researchInProgress = false;
@@ -1048,10 +1197,11 @@ class EsTableComponent {
1048
1197
  else if (this.View && this.View instanceof AppSearch) {
1049
1198
  // Se cambia l'oggetto intero significa che ho rimandato la ricerca
1050
1199
  this.setMode('view');
1200
+ let firstItemGroupOrNoGrouping = (((_a = this.View.requestedgroups) === null || _a === void 0 ? void 0 : _a.length) || 0) == 0;
1051
1201
  // Se vengo da una ricerca interna mantengo lo stato di selezione precedente (quindi su cambio pagina, cambio ipp, ecc...)
1052
1202
  // se invece l'utente ha fatto una ricerca lui (quindi cambiando filtri), secco le info di selezione
1053
- if (!this.View.selection || !this.View.internalsearchrequest || !this.UseSelectionCache) {
1054
- this.selOrDeselCache = {};
1203
+ if (!this.View.selection || (!this.View.internalsearchrequest && firstItemGroupOrNoGrouping) || !this.UseSelectionCache) {
1204
+ this.clearSelectionCaches();
1055
1205
  this.View.selection = new ItemsSelection([]);
1056
1206
  this.onSelectionChanged.emit(this.View.selection);
1057
1207
  }
@@ -1070,56 +1220,136 @@ class EsTableComponent {
1070
1220
  }
1071
1221
  }
1072
1222
  }
1073
- this.arrayPulsanti = this.getPagesArray(6, this.View.page, this.View.pages || 1);
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);
1074
1226
  }
1075
1227
  else if (this.View && (this.View.length != null && this.View.length != undefined)) {
1076
1228
  this.setMode('array');
1077
1229
  if (!this.UseSelectionCache || !this.arraymodeSelection) {
1078
- this.selOrDeselCache = {};
1230
+ this.clearSelectionCaches();
1079
1231
  this.arraymodeSelection = new ItemsSelection([]);
1080
1232
  ;
1081
1233
  this.onSelectionChanged.emit(this.arraymodeSelection);
1082
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
+ }
1083
1249
  if (this.SearchView)
1084
1250
  this.arrayPulsanti = this.getPagesArray(6, this.SearchView.page, this.SearchView.pages || 1);
1085
1251
  }
1086
- if (this.View && !(this.View instanceof ReportDefinition)) {
1087
- /*
1088
- *Uso la tecnica di EndlessScroll se la variabile relativa è attiva e se
1089
- * 1) Ho un Array, oppure
1090
- * 2) Ho un AppSearch che sta cercando con paginazione "Tutto", oppure
1091
- * 3) Ho un AppSearch che sta cercando con paginazione diversa da "Tutto" ma con la variabile EndlessScrollOnlyForAll a false
1092
- */
1093
- let viewCasted = this.View;
1094
- let hasRowGroups = viewCasted.groupings && viewCasted.groupings.filter(t => !t.aggregation).length > 0;
1095
- let isAppSearchWithIppMax = this.viewMode && viewCasted.itemsperpageoverride == this.defaultAllPageOverride;
1096
- let isAppSearchNoMaxIpp = this.viewMode && viewCasted.itemsperpageoverride != this.defaultAllPageOverride;
1097
- this.UseEndlessscroll = this.EndlessScroll && (this.arrayMode || isAppSearchWithIppMax || (isAppSearchNoMaxIpp && !this.EndlessScrollOnlyForAll));
1098
- if (this.UseEndlessscroll && !hasRowGroups) {
1099
- this.addedSlices = [];
1100
- this.boundSubSources = this.getItemSlices();
1101
- this.TMPBoundSource = this.boundSubSources[0] ? this.boundSubSources[0] : [];
1102
- if (this.boundSubSources[0])
1103
- this.addedSlices.push(0);
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 : "";
1104
1300
  }
1105
- else
1106
- this.TMPBoundSource = this.getItemsByMode(false, !this.internalWriteCall);
1107
- if (this.Hierarchy && !hasRowGroups)
1108
- this.assignHierarchyLevels(this.TMPBoundSource);
1109
- this.calculateHash(this.TMPBoundSource);
1110
- // Assegno a una variabile mia l'eventuale override per la classe della riga
1111
- // Se poi sono in modalità gerarchica inietto anche la classe per la configurazione del livello della riga
1112
- if ((this.TMPBoundSource && this.RowClassAssigner) || this.Hierarchy) {
1113
- for (let i = 0; i < this.TMPBoundSource.length; i++) {
1114
- let item = this.TMPBoundSource[i];
1115
- item._rowClass = this.RowClassAssigner ? this.RowClassAssigner(item) : "";
1116
- item._rowClass += this.Hierarchy ? " est-row-lvl-" + item.level : "";
1117
- }
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;
1118
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);
1320
+ }
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;
1119
1336
  }
1120
- this.postBoundSourceCalculation();
1121
1337
  }
1122
- // #region Gestione retrieve degli oggetti da mostrare in tabella, considerando eventuali Endless Scrolls
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();
1352
+ }
1123
1353
  /**
1124
1354
  * In base alla modalità specificata (ArrayMode, ViewMode, ecc...) questo metodo recupera l'array di oggetti da bindare ad interfaccia
1125
1355
  *
@@ -1128,6 +1358,8 @@ class EsTableComponent {
1128
1358
  * @param {boolean} allIfPossible [false] Indica se prendere tutti gli oggetti quaora possibile, usato solo in ArrayMode
1129
1359
  *
1130
1360
  * @returns {any[]} Lista degli oggetti su cui effettuare il bind lato interfaccia
1361
+ *
1362
+ * @todo: ITEMS
1131
1363
  */
1132
1364
  getItemsByMode(onlyselected = false, refreshPaging = false, allIfPossible = false) {
1133
1365
  let items = [];
@@ -1135,6 +1367,8 @@ class EsTableComponent {
1135
1367
  items = this.getViewItemsBySource();
1136
1368
  }
1137
1369
  else if (this.arrayMode) {
1370
+ this.View.forEach(itm => { itm._item = true; });
1371
+ // Se faccio dei raggruppamenti ignoro la paginazione
1138
1372
  if (this.UseArrayModePaging && !allIfPossible) {
1139
1373
  // Se sono in modalità array ma la ricerca dipende da una view devo riallineare gli itemperpage
1140
1374
  if (this.SearchView)
@@ -1153,7 +1387,11 @@ class EsTableComponent {
1153
1387
  return items.filter(t => t._selected);
1154
1388
  return items;
1155
1389
  }
1156
- /** @ignore */
1390
+ /**
1391
+ * @ignore
1392
+ *
1393
+ * @todo: ITEMS
1394
+ */
1157
1395
  getViewItemsBySource() {
1158
1396
  var _a, _b;
1159
1397
  let castedView = this.View;
@@ -1161,8 +1399,12 @@ class EsTableComponent {
1161
1399
  //Gruppi intermedi
1162
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) {
1163
1401
  let ret = castedView.groups;
1164
- // Setto variabile interna per capire che questo è in realtà un gruppo
1165
- ret.forEach(itm => { itm._group = true; });
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
+ });
1166
1408
  return ret;
1167
1409
  }
1168
1410
  else {
@@ -1172,10 +1414,31 @@ class EsTableComponent {
1172
1414
  return ret;
1173
1415
  }
1174
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
+ }
1175
1436
  /**
1176
1437
  * Metodo che prende tutti gli oggetti di cui dispone divisi in bucket da 100 elementi
1177
1438
  *
1178
1439
  * @returns {any[][]} Matrice di array Nx100
1440
+ *
1441
+ * @todo: ITEMS
1179
1442
  */
1180
1443
  getItemSlices() {
1181
1444
  // Se sono qui di sicuro non ho rowgrouping
@@ -1212,8 +1475,6 @@ class EsTableComponent {
1212
1475
  }
1213
1476
  }
1214
1477
  }
1215
- // #endregion
1216
- // #region Gestione di tutto il ciclo di vita post binding oggetti
1217
1478
  /**
1218
1479
  * Metodo lanciato dopo che la sorgente dati è stata correttamente bindata, si occupa di ricalcolare tutto ciò che serve
1219
1480
  * all'es-table per renderizzare i valori da mostrare
@@ -1223,69 +1484,322 @@ class EsTableComponent {
1223
1484
  this.RowContexts = [];
1224
1485
  this.OrderDirectives = [];
1225
1486
  this.lastSelectedItemID = null;
1226
- // Set timeout e basta funzionerebbe per la modalità JIT, ma per AOT servono sia quello che detectChanges
1227
- this.cdr.detectChanges();
1228
- setTimeout(() => {
1229
- // Se non ho colonne dinamiche ma sono in modalità dinamica (lo capisco perché c'è una view piena di genericitem) metto il default delle colonne
1230
- this.eventuallyReviewDynamicColumns();
1231
- this.bindDisplayToLoadedItemsOrGroups();
1232
- // Molte cose sono ovviamente disponibili solo in modalità View
1233
- if (this.viewMode && this.UseCustomCells) {
1234
- let view = this.View;
1235
- let ths = this.EsThs && this.EsThs.length > 0 ? this.EsThs.toArray() : this.EsThsDirective && this.EsThsDirective.length > 0 ? this.EsThsDirective.toArray() : [];
1236
- let tds = this.EsTds && this.EsTds.length > 0 ? this.EsTds.toArray() : this.EsTdsDirective && this.EsTdsDirective.length > 0 ? this.EsTdsDirective.toArray() : [];
1237
- // N.B: Rispettare l'ordine di queste 3 macrocategorie è VITALE
1238
- // ************************************* Sistemazioni di TH, TD, e visibilità varie *************************************
1239
- this.alignColumnsIfLoadedView(view); // Se sto caricando una View da hotpotato (quindi con savedstate = true) riallineo la visibilità delle colonne e il loro ordine.
1240
- this.refreshColumnsVisibility(ths, tds, view); // Lavoro sui TH ed eventualmente modifico la visibilità anche dei TD.
1241
- this.alignHeadersOrdering(ths, view); // Allineo gli ordinamenti agli header
1242
- this.reviewColumnsList(ths); // Aggiorna la lista delle colonne da mostrare nella dialog per ordinamento ecc
1243
- // ************************************* Generazione binding per righe e colonne *************************************
1244
- this.evaluateRowThs(ths); // Raccolgo i TH
1245
- this.evaluateRowTds(ths, tds); // Raccolgo i TD in contesti separati, un contesto per ogni item o gruppo
1246
- // ************************************* Ultimi aggiustmaenti dei binding *************************************
1247
- this.generateDefaultOrder(view); // Genero le direttive di ordinamento, che siano default o derivanti dalla AppSearch
1248
- this.applyOrdering(view, true); // Applico l'ordinamento sulle colonne (non ASC DESC, ma "prima questa o quella colonna")
1249
- this.MoveTemporaryVariablesToRealOnes(); // Collego TH e TD aggiustati fino ad ora alle variabili di Binding HTML
1250
- this.evaluateSelection(view.items, view.selection); // Riallineo le info di selezione degli elementi della View
1251
- if (this.ResearchNeeded) {
1252
- this.changed();
1253
- this.emitSearchRequest(false);
1254
- this.ResearchNeeded = false;
1255
- }
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
+ }
1493
+ }
1494
+ /**
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
1496
+ */
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
1256
1517
  }
1257
- else if (this.viewMode && !this.UseCustomCells) {
1258
- // Riallineo le info di selezione degli elementi della View
1259
- let view = this.View;
1260
- this.evaluateSelection(view.items, view.selection);
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;
1261
1537
  }
1262
- else if (this.arrayMode)
1263
- this.arrayModeEvaluateSelection(this.View);
1264
- // Per essere sicuro che dopo un bind di oggetti la es-table aggiorni la grafica
1265
- this.cdr.markForCheck();
1266
- this.FirstBind = false;
1267
- });
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;
1268
1548
  }
1269
- bindDisplayToLoadedItemsOrGroups() {
1270
- var _a, _b, _c;
1271
- if (this.TMPBoundSource.length == 0)
1549
+ /**
1550
+ * Se in modalità array applica gli ordinamenti ASC-DESC delle colonne
1551
+ *
1552
+ * @todo: INTERNALDB
1553
+ */
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)
1272
1569
  return;
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
+ }
1589
+ }
1590
+ /**
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
1599
+ *
1600
+ * @todo: INTERNALDB
1601
+ */
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;
1756
+ return;
1757
+ }
1273
1758
  if (this.arrayMode || !this.UseCustomCells) {
1274
1759
  this.boundSource = this.TMPBoundSource;
1760
+ this.BaseItemsCount = (view === null || view === void 0 ? void 0 : view.objectcount) || view.length;
1275
1761
  return;
1276
1762
  }
1277
- let view = this.View;
1278
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;
1279
1764
  if (groupingKeys == 0) {
1280
1765
  this.boundSource = this.TMPBoundSource;
1766
+ this.BaseItemsCount = view.objectcount;
1281
1767
  return;
1282
1768
  }
1769
+ this.handleNewDataOnRowGrouping(view, groupingKeys);
1770
+ }
1771
+ /**
1772
+ * In modalità rowgrouping quando mi arriva un nuovo blocco di oggetti devo aggiungerlo alla vista attuale:
1773
+ *
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
1782
+ */
1783
+ handleNewDataOnRowGrouping(view, groupingKeys) {
1784
+ var _a, _b;
1283
1785
  // 1) Se non viene richiesto il dettaglio di alcun gruppo significa che la chiamata restituisce la lista paginata dei gruppi principali.
1284
1786
  // Li tratto come se fosse una qualsiasi altra query paginata su N elementi
1285
- if ((((_c = view.requestedgroups) === null || _c === void 0 ? void 0 : _c.length) || 0) == 0) {
1787
+ if ((((_a = view.requestedgroups) === null || _a === void 0 ? void 0 : _a.length) || 0) == 0) {
1286
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
+ });
1287
1798
  // Resetto la ricerca alla cache di questa "sessione"
1288
- this.groupSearchRequestsCache = [{ path: '', view: view }];
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;
1289
1803
  }
1290
1804
  else {
1291
1805
  // 2) Se viene richiesto il dettaglio di un qualsiasi gruppo diverso dall'ultimo vuol dire che devo aggiungere
@@ -1326,22 +1840,68 @@ class EsTableComponent {
1326
1840
  groupRoute.push({ column: rg.column, value: rg.value });
1327
1841
  insertIndex = items.findIndex((t, i) => i >= insertIndex && t._group && t.column == rg.column && t.value == rg.value);
1328
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
+ }
1329
1861
  // Assegno un livello ai valori che arrivano da usare per formattare la parte grafica. Il primo gruppo cliccato sarà a livello 1,
1330
1862
  // il secondo sarà a livello 2 e così via...
1331
1863
  // Li marco inoltre con il parent in modo da poter eliminare i vecchi qualora servisse
1332
1864
  this.TMPBoundSource.forEach(itm => {
1333
1865
  itm._parent = groupKey;
1334
1866
  itm._parentRoute = groupRoute;
1335
- if (intermediateGroup)
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) {
1336
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
+ }
1337
1879
  });
1338
- //Elimino gli oggetti vecchi qui dentro e li sostituisco coi nuovi di questa ricerca
1339
- this.boundSource = this.boundSource.filter(t => t._parent != groupKey);
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
1340
1894
  this.boundSource.splice(insertIndex + 1, 0, ...this.TMPBoundSource);
1341
- // Aggiungo un separatore alla fine di questi gruppi che dovrà occuparsi di caricare ALTRI gruppi
1342
- this.boundSource.splice(insertIndex + 1 + this.TMPBoundSource.length, 0, this.getGroupSeparator(view, groupKey, view.requestedgroups.length));
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'));
1343
1898
  // Aggiungo la ricerca alla cache di questa "sessione"
1344
- this.groupSearchRequestsCache.push({ path: groupKey, view: view });
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);
1345
1905
  }
1346
1906
  }
1347
1907
  /**
@@ -1350,6 +1910,22 @@ class EsTableComponent {
1350
1910
  MoveTemporaryVariablesToRealOnes() {
1351
1911
  this.RowTDs = this.TMPRowTDs;
1352
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
+ }
1918
+ /**
1919
+ * Permette di selezionare o deselezionare in maniera arbitraria degli oggetti
1920
+ *
1921
+ * @param {any[]} items Oggetti da selezionare o deselezionare
1922
+ * @param {boolean} select **true** per selezionarli, **false** per non toccarli
1923
+ *
1924
+ * @todo: SELECTION
1925
+ */
1926
+ setSelectionStatus(items, select) {
1927
+ this.handleItemsSelection(items, select);
1928
+ this.cdr.markForCheck();
1353
1929
  }
1354
1930
  /**
1355
1931
  * Se non ho l'Input **DynamicRowColumnsDefinition** in modalità dinamica lo riempio con il default nome della colonna = testo della colonna
@@ -1379,7 +1955,7 @@ class EsTableComponent {
1379
1955
  * @param {EsTh[] | EsThDirective[]} ths Colonne della tabella
1380
1956
  */
1381
1957
  reviewColumnsList(ths) {
1382
- this.ColumnsList = [];
1958
+ this.TMPColumnsList = [];
1383
1959
  if (ths.length == 0)
1384
1960
  return;
1385
1961
  // Appena il contentChildren è valorizzato scorro tutti gli header
@@ -1393,18 +1969,99 @@ class EsTableComponent {
1393
1969
  // Salvo le informazioni dell'header per far parte della lista da cui scegliere quali colonne visualizzare/nascondere
1394
1970
  // Di default la visibilità è quella impostata nel componente
1395
1971
  if (this.HiddenColumns || th.Visible)
1396
- this.ColumnsList.push(new EsTableColumn(th.ID, th.Description, th.Visible, th.Fixed, null));
1972
+ this.TMPColumnsList.push(new EsTableColumn(th.ID, th.Description, th.Visible, th.Fixed, null, null, null));
1397
1973
  }
1398
1974
  else {
1975
+ let column = th.th;
1399
1976
  // Se non ho un id il th è considerato inerte
1400
- if (!th.th)
1977
+ if (!column)
1401
1978
  continue;
1402
1979
  // Salvo le informazioni dell'header per far parte della lista da cui scegliere quali colonne visualizzare/nascondere
1403
1980
  // Di default la visibilità è quella impostata nel componente
1404
- if (this.HiddenColumns || th.thVisible)
1405
- this.ColumnsList.push(new EsTableColumn(th.th, null, th.thVisible, th.thFixed, th.Template));
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
+ }
1985
+ }
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
+ }
1406
2029
  }
1407
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]);
1408
2065
  }
1409
2066
  /**
1410
2067
  * Terminato il binding delle colonne da **reviewColumnsList** e della **View** dal **writeValue** questo metodo si occupa
@@ -1413,14 +2070,19 @@ class EsTableComponent {
1413
2070
  * @param {AppSearch<any>} view AppSearch da utilizzare per questa operazione
1414
2071
  */
1415
2072
  alignColumnsIfLoadedView(view) {
1416
- let emitChanged = view.savedstate;
2073
+ let emitChanged = this.viewMode && view.savedstate;
1417
2074
  let newColset = [];
1418
2075
  if (!this.ColumnsList || this.ColumnsList.length == 0)
1419
2076
  return;
2077
+ let columns = this.viewMode ? view.columns : this.arrayColumns;
1420
2078
  this.ColumnsList.forEach(c => {
1421
- let exCl = view.columns.filter(cc => cc == c.id);
1422
- // Se l'appsearch viene da uno stato precedente, uso le informaizoni sulle colonne che ha dentro, altrimenti sovrascrivo tutto **
1423
- if (c.visible && view.columns.length == 0)
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)
1424
2086
  newColset.push(c.id);
1425
2087
  // Se ho una colonna lato AppSearch e nella ColumnList non è visibile, allineo all'AppSearch
1426
2088
  else if (exCl.length == 1 && !c.visible)
@@ -1430,21 +2092,22 @@ class EsTableComponent {
1430
2092
  c.visible = false;
1431
2093
  });
1432
2094
  // Non ho colonne nella appsearch, vuol dire che sono al primo binding
1433
- if (view.columns.length == 0)
1434
- view.columns = newColset;
1435
- if (view.savedstate && this.ColumnsOrdering && view.column_ordering.length > 0) {
1436
- let newColList = [];
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) {
1437
2102
  // Scorro gli ordinamenti che avevo salvato e ricreo la ColumnsList in base a loro
1438
- view.column_ordering.forEach(co => {
1439
- this.ColumnsList.forEach(c => {
1440
- if (c.id == co)
1441
- newColList.push(c);
1442
- });
1443
- });
2103
+ let newColList = [];
2104
+ view.column_ordering.forEach(co => { this.ColumnsList.forEach(c => { if (c.id == co)
2105
+ newColList.push(c); }); });
1444
2106
  this.ColumnsList = newColList;
1445
2107
  }
1446
2108
  // In ogni caso questo non mi serve più, lo resetto **
1447
- view.savedstate = false;
2109
+ if (this.viewMode)
2110
+ view.savedstate = false;
1448
2111
  if (emitChanged)
1449
2112
  this.changed();
1450
2113
  }
@@ -1455,20 +2118,22 @@ class EsTableComponent {
1455
2118
  * @param {'DESC' | 'ASC'} order Nuovo ordine selezionato per la colonna
1456
2119
  */
1457
2120
  thOrderChanged(id, order) {
1458
- if (!this.viewMode) {
1459
- 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');
1460
2123
  return;
1461
2124
  }
1462
2125
  if (!this.OrderByColumn)
1463
2126
  return;
1464
- let appSearch = this.View;
2127
+ let orders = this.viewMode ? this.View.orders : this.arrayOrders;
1465
2128
  let orderToAdd = true;
1466
2129
  let orderToRemove = null;
1467
2130
  // Se per qualche motivo il costruttore non è passato (cache tarpate o simila) fixo
1468
- if (!appSearch.orders)
1469
- appSearch.orders = [];
1470
- for (let i = 0; i < appSearch.orders.length; i++) {
1471
- let t = appSearch.orders[i];
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];
1472
2137
  if (t.id == id) {
1473
2138
  if (order) {
1474
2139
  t.order = order;
@@ -1479,19 +2144,27 @@ class EsTableComponent {
1479
2144
  }
1480
2145
  }
1481
2146
  if (orderToRemove != null) {
1482
- appSearch.orders.splice(orderToRemove, 1);
2147
+ orders.splice(orderToRemove, 1);
1483
2148
  }
1484
2149
  else if (orderToAdd) {
1485
2150
  if (this.MultipleOrderingDirectives)
1486
- appSearch.orders.push(new AppOrdering(id, order));
1487
- else
1488
- appSearch.orders = [new AppOrdering(id, order)];
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
+ }
1489
2158
  }
1490
2159
  this.onOrderChanged.emit({ id, order });
1491
- if (this.groupSearchRequestsCache.length > 0)
1492
- this.emitRowGroupingSearches(id, appSearch.orders);
1493
- else
1494
- this.emitSearchRequest(false);
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();
1495
2168
  }
1496
2169
  /**
1497
2170
  * Metodo da chiamare ogni volta che si vuole dare evidenza all'esterno del bisogno di rieffettuare la ricerca
@@ -1504,6 +2177,11 @@ class EsTableComponent {
1504
2177
  this.View.internalsearchrequest = true;
1505
2178
  this.changed();
1506
2179
  }
2180
+ if (viewOverride) {
2181
+ if (resetsPage)
2182
+ viewOverride.page = 1;
2183
+ viewOverride.internalsearchrequest = true;
2184
+ }
1507
2185
  this.researchInProgress = true;
1508
2186
  this.onSearchRequest.emit(viewOverride ? viewOverride : resetsPage);
1509
2187
  }
@@ -1517,16 +2195,19 @@ class EsTableComponent {
1517
2195
  * @param {AppSearch<any>} view AppSearch da utilizzare per questa operazione
1518
2196
  */
1519
2197
  refreshColumnsVisibility(ths, tds, view) {
1520
- let columnsCache = {};
1521
2198
  let newColset = [];
1522
2199
  let fixedThs = {};
2200
+ let columnsCache = {};
1523
2201
  for (let coli = 0; coli < this.ColumnsList.length; coli++) {
1524
2202
  let col = this.ColumnsList[coli];
1525
2203
  columnsCache[col.id] = col;
1526
2204
  if (col.visible)
1527
- newColset.push(col.id);
2205
+ newColset.push((col.pinned ? "§" : "") + col.id);
1528
2206
  }
1529
- view.columns = newColset;
2207
+ if (view)
2208
+ view.columns = newColset;
2209
+ else
2210
+ this.arrayColumns = newColset;
1530
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
1531
2212
  if (ths) {
1532
2213
  // Definisco se la colonna è visibile in base alla sua rappresentazione locale in ColumnsList
@@ -1539,7 +2220,7 @@ class EsTableComponent {
1539
2220
  }
1540
2221
  else {
1541
2222
  th.thVisible = th.thFixed || (columnsCache[th.th] ? columnsCache[th.th].visible : th.thVisible);
1542
- if (th.thFixed)
2223
+ if (th.thFixed || th.thGroup)
1543
2224
  fixedThs[th.th] = true;
1544
2225
  }
1545
2226
  }
@@ -1563,22 +2244,23 @@ class EsTableComponent {
1563
2244
  * @param {EsTh[] | EsThDirective[]} ths Colonne della tabella
1564
2245
  */
1565
2246
  alignHeadersOrdering(ths, view) {
2247
+ let orders = view ? view.orders : this.arrayOrders;
1566
2248
  for (let i = 0; i < ths.length; i++) {
1567
2249
  let th = ths[i];
1568
2250
  if (this.isEsTh(th)) {
1569
2251
  th.Order = null;
1570
2252
  // Assegno tutti gli ordinamenti che mi vengono da AppSearch. Sono i più importanti. Non faccio cache o cose strano perché tanto questa
1571
2253
  // variabile sarà sempre massimo 3 elementi
1572
- for (let i = 0; i < view.orders.length; i++) {
1573
- let or = view.orders[i];
2254
+ for (let i = 0; i < orders.length; i++) {
2255
+ let or = orders[i];
1574
2256
  if (or.id == th.ID)
1575
2257
  th.Order = or.order;
1576
2258
  }
1577
2259
  }
1578
2260
  else {
1579
2261
  th.thOrder = null;
1580
- for (let i = 0; i < view.orders.length; i++) {
1581
- let or = view.orders[i];
2262
+ for (let i = 0; i < orders.length; i++) {
2263
+ let or = orders[i];
1582
2264
  if (or.id == th.th)
1583
2265
  th.thOrder = or.order;
1584
2266
  }
@@ -1599,6 +2281,11 @@ class EsTableComponent {
1599
2281
  if (tds.length == 0)
1600
2282
  return;
1601
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
+ }
1602
2289
  for (let i = 0; i < ths.length; i++) {
1603
2290
  let th = ths[i];
1604
2291
  thsCache[this.isEsTh(th) ? th.ID : th.th] = th;
@@ -1611,10 +2298,10 @@ class EsTableComponent {
1611
2298
  if (this.isEsTd(td)) {
1612
2299
  let th = thsCache[td.ID];
1613
2300
  if (!!th)
1614
- th.Referenced = true;
2301
+ th._referenced = true;
1615
2302
  else
1616
2303
  throw "ID dell'oggeto EsTd non compatibile con gli ID dicharati negli EsTh: " + td.ID;
1617
- let isFixed = (this.isEsTh(th) && th.Fixed) || (!this.isEsTh(th) && th.thFixed);
2304
+ let isFixed = (this.isEsTh(th) && th.Fixed) || (!this.isEsTh(th) && (th.thFixed || th.thGroup));
1618
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 };
1619
2306
  let ctx = td.Context;
1620
2307
  if (this.TMPRowTDs[ctx]) {
@@ -1632,24 +2319,25 @@ class EsTableComponent {
1632
2319
  else {
1633
2320
  for (let i = 0; i < this.boundSource.length; i++) {
1634
2321
  let item = this.boundSource[i];
1635
- let ctx = item.hash;
2322
+ let ctx = item._hash;
1636
2323
  let key = td.td;
1637
2324
  let th = thsCache[td.td];
1638
2325
  if (!!th)
1639
- th.Referenced = true;
2326
+ th._referenced = true;
1640
2327
  else
1641
2328
  throw "ID dell'oggeto EsTd non compatibile con gli ID dicharati negli EsTh: " + td.td;
1642
2329
  if (td.tdIf || (!this.isEsTh(th) && th.thGroup)) {
1643
2330
  let thCasted = th;
1644
- let isFixed = (this.isEsTh(th) && th.Fixed) || (!this.isEsTh(th) && th.thFixed);
2331
+ let isFixed = (this.isEsTh(th) && th.Fixed) || (!this.isEsTh(th) && (th.thFixed || th.thGroup || th.thPinned));
1645
2332
  let itemToAdd = item._item ?
1646
- { ID: key, GroupHeader: false, GroupAggregation: false, Visible: td.tdVisible, Wraps: true, Class: td.tdClass, Template: td.Template } :
1647
- { ID: key, GroupHeader: thCasted.thGroup, GroupAggregation: !!thCasted.thAggregation, Visible: true, Wraps: false, Class: thCasted.thGroupClass || '', Content: this.getGroupCellDisplay(item, key, th) };
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) };
1648
2335
  if (this.TMPRowTDs[ctx]) {
1649
- if (isFixed)
1650
- this.TMPRowTDs[ctx].splice(0 + (contextFixeds[ctx]++), 0, itemToAdd);
1651
- else
1652
- this.TMPRowTDs[ctx].push(itemToAdd);
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);
1653
2341
  }
1654
2342
  else {
1655
2343
  this.RowContexts.push(ctx);
@@ -1666,7 +2354,7 @@ class EsTableComponent {
1666
2354
  var errs = [];
1667
2355
  for (let i = 0; i < ths.length; i++) {
1668
2356
  let th = ths[i];
1669
- if (!th.Referenced)
2357
+ if (!th._referenced)
1670
2358
  errs.push(this.isEsTh(th) ? th.ID : th.th);
1671
2359
  }
1672
2360
  if (errs.length > 0) {
@@ -1686,29 +2374,31 @@ class EsTableComponent {
1686
2374
  evaluateRowThs(ths) {
1687
2375
  if (ths.length == 0)
1688
2376
  return;
2377
+ let columnsListCache = {};
1689
2378
  let castedView = this.View;
1690
- let groupingsUndefined = !castedView.groupings || castedView.groupings.length == 0;
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
+ }
1691
2384
  this.TMPRowTHs = [];
1692
2385
  let fixed = 0;
1693
2386
  for (let i = 0; i < ths.length; i++) {
1694
2387
  let th = ths[i];
1695
2388
  let toAdd;
1696
2389
  if (this.isEsTh(th)) {
1697
- toAdd = { Fixed: th.Fixed, ID: th.ID, Visible: th.Visible, Class: th.Class, Order: th.Order, Orderable: th.Orderable, Template: null, Content: th.Description, Wrap: false };
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 };
1698
2391
  if (th.Fixed)
1699
2392
  this.TMPRowTHs.splice(0 + (fixed++), 0, toAdd);
1700
2393
  else
1701
2394
  this.TMPRowTHs.push(toAdd);
1702
2395
  }
1703
2396
  else if (th.thIf || th.thGroup) {
1704
- // Mentre inserisco mi assicuro di mettere l'elemento per bene in ordine in base alla proprietà "Fixed". Tutte le colonne Fixed devono finire all'inizio
1705
- // (Questo probabilmente diventerà il comportamento di default anche per le colonne "Pinned")
1706
2397
  let thClass = (th.thClass || '') + (th.thGroup ? " est-col-min" : "");
1707
- toAdd = { Fixed: th.thFixed || th.thGroup, ID: th.th, Visible: th.thVisible, Class: thClass, Order: th.thOrder, Orderable: th.thOrderable, Template: th.Template, Content: null, Wrap: false };
1708
- if (th.thFixed)
1709
- this.TMPRowTHs.splice(0 + (fixed++), 0, toAdd);
1710
- else
1711
- this.TMPRowTHs.push(toAdd);
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
1712
2402
  if (groupingsUndefined && (th.thAggregation || th.thGroup)) {
1713
2403
  let groupAggregations = this.getGroupAggregations(th);
1714
2404
  if (!castedView.groupings)
@@ -1720,6 +2410,122 @@ class EsTableComponent {
1720
2410
  }
1721
2411
  }
1722
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
+ }
1723
2529
  /**
1724
2530
  * Data una direttiva EsTh restituisce la lista delle aggregazioni richiesta per questa colonna o il gruppo che rappresenta
1725
2531
  *
@@ -1732,7 +2538,11 @@ class EsTableComponent {
1732
2538
  // Es: '{min:dd/MM/yyyy} - {max:dd/MM/yyyy}'
1733
2539
  if (th.thAggregation) {
1734
2540
  this.getEsThDirectiveListOfAggregations(th).forEach((agg) => {
1735
- ret.push(new GroupOrAggregation(th.th, agg.func));
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'));
1736
2546
  });
1737
2547
  }
1738
2548
  else if (th.thGroup)
@@ -1749,6 +2559,9 @@ class EsTableComponent {
1749
2559
  getEsThDirectiveListOfAggregations(th) {
1750
2560
  if (!th.thAggregation)
1751
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;
1752
2565
  let ret = [];
1753
2566
  let display = th.thAggregation;
1754
2567
  var matches = display.match(/{[a-zA-Z0-9\/:]*}/gi);
@@ -1764,6 +2577,7 @@ class EsTableComponent {
1764
2577
  }
1765
2578
  ret.push({ func: func, format: format, match: m });
1766
2579
  });
2580
+ th._thAggregations = ret;
1767
2581
  return ret;
1768
2582
  }
1769
2583
  /**
@@ -1771,16 +2585,20 @@ class EsTableComponent {
1771
2585
  *
1772
2586
  * @param {AppSearch<any>} view AppSearch da utilizzare per questa operazione
1773
2587
  */
1774
- generateDefaultOrder(view) {
1775
- if (this.TMPRowTHs.length == 0)
2588
+ generateDefaultOrder(ths, view) {
2589
+ if (ths.length == 0)
1776
2590
  return;
2591
+ let orderings = this.viewMode ? view.column_ordering : this.arrayColumnOrdering;
1777
2592
  // Genero ordinamento di default da 0 fino a dove deve arrivare. Situazione attuale senza hotpotato
1778
- if (!view.column_ordering || view.column_ordering.length == 0) {
1779
- for (let i = 0; i < this.TMPRowTHs.length; i++)
1780
- this.OrderDirectives.push(this.TMPRowTHs[i].ID);
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
+ }
1781
2599
  }
1782
2600
  else
1783
- this.OrderDirectives = view.column_ordering;
2601
+ this.OrderDirectives = orderings;
1784
2602
  }
1785
2603
  /**
1786
2604
  * Applica l'ordine specificato alle varie colonne
@@ -1789,7 +2607,7 @@ class EsTableComponent {
1789
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
1790
2608
  * Senza finalize significa che mi aspetto altre operazioni che prima o poi richiameranno questa funzione col finalize.
1791
2609
  *
1792
- * Ad esempio, una volta selezionato ordinamento fisico/logico delle colonne so che parte un altra ricerca che mi rivalorizzera da "writeValue", che già chiama questa funzione.
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.
1793
2611
  * Mettendo solo la chiamata da "writeValue" come "finalizzante" mi assicuro che smanattamenti a frontend non causino flickering fino a quando non servono
1794
2612
  */
1795
2613
  applyOrdering(view, finalize) {
@@ -1813,7 +2631,10 @@ class EsTableComponent {
1813
2631
  this.TMPRowTDs[this.RowContexts[i]] = newContext;
1814
2632
  }
1815
2633
  }
1816
- view.column_ordering = this.OrderDirectives;
2634
+ if (this.viewMode)
2635
+ view.column_ordering = this.OrderDirectives;
2636
+ else
2637
+ this.arrayColumnOrdering = this.OrderDirectives;
1817
2638
  this.changed();
1818
2639
  }
1819
2640
  // #endregion
@@ -1824,24 +2645,40 @@ class EsTableComponent {
1824
2645
  * @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
1825
2646
  * facenti riferimento allo stesso contesto
1826
2647
  * @param {string} parent Parent path che rappresenta a quale gruppo è affibbiato questo separatore
2648
+ * @param {GroupRouteFragment[]} route Route path che rappresenta a quale gruppo è affibbiato questo separatore
1827
2649
  * @param {number} level Livello del gruppo di cui questo elemento è separatore, viene usato per applicare la classe "est-lvl-{{level}}"
1828
2650
  *
1829
2651
  * @returns {any} Elemento di separazione contenente tutti i bind per presentare una paginazione sotto questo gruppo lato interfaccia
1830
2652
  */
1831
- getGroupSeparator(view, parent, level) {
1832
- let item = {
1833
- _sep: true,
1834
- _parent: parent,
1835
- _grouplevel: level,
1836
- filters: view.requestedgroups.map(t => { return { column: t.column, value: t.value }; }),
1837
- page: view.page,
1838
- pages: view.pages,
1839
- itemsperpage: view.itemsperpageoverride,
1840
- count: view.objectcount
1841
- };
2653
+ getGroupSeparator(view, parent, route, level, searches) {
2654
+ let item = new GroupPager(level, route, parent, Object.assign({}, view), searches);
2655
+ item.buttons = this.getPagesArray(6, view.page, view.pages);
1842
2656
  this.calculateHash([item]);
1843
2657
  return item;
1844
2658
  }
2659
+ /**
2660
+ * Sposta la ricerca di una pagina in avanti (o indietro)
2661
+ *
2662
+ * @param {number} page Numero di pagine da aggiungere (o sottrarre, se negativo) alla pagina attuale
2663
+ * @param {any} pager Elemento di separazione su cui è effettuata la ricerca
2664
+ */
2665
+ addToPageGroup(page, pager) {
2666
+ this.goToPageGroup(pager.view.page + page, pager);
2667
+ }
2668
+ /**
2669
+ * Sposta la ricerca alla pagina specificata
2670
+ *
2671
+ * @param {number} page Pagina a cui navigare
2672
+ * @param {any} pager Elemento di separazione su cui è effettuata la ricerca
2673
+ */
2674
+ goToPageGroup(page, pager) {
2675
+ let appSearchElement = pager.view;
2676
+ if (page === 0 || page > appSearchElement.pages)
2677
+ return;
2678
+ appSearchElement.page = page;
2679
+ pager.buttons = this.getPagesArray(6, appSearchElement.page, appSearchElement.pages);
2680
+ this.emitSearchRequest(false, appSearchElement);
2681
+ }
1845
2682
  /**
1846
2683
  * Data una colonna effettua la riemissione di tutte le ricerche relative.
1847
2684
  *
@@ -1857,10 +2694,17 @@ class EsTableComponent {
1857
2694
  */
1858
2695
  emitRowGroupingSearches(column, orderings) {
1859
2696
  // Per tutte le ricerche intermedie che devo rivalutare le re-emitto in modo da aggiornargli i dati
1860
- var meaningfulAppSearches = this.groupSearchRequestsCache.filter(t => t.path.endsWith(column)).map(t => t.view);
2697
+ var meaningfulAppSearches = this.groupSearchRequestsCache.filter(t => t.group_column == column).map(t => t.view);
2698
+ // Se non ne trovo significa che ho fatto l'ordinamento o sugli item, o su colonne relative a un sottogruppo non caricato
2699
+ if (!meaningfulAppSearches || meaningfulAppSearches.length == 0)
2700
+ meaningfulAppSearches = this.groupSearchRequestsCache.filter(t => !t.group_column).map(t => t.view);
2701
+ // Se non ne trovo qui significa che sto ordinando su colonne relative a un sottogruppo non caricato
2702
+ if (!meaningfulAppSearches || meaningfulAppSearches.length == 0)
2703
+ return;
1861
2704
  meaningfulAppSearches.forEach(as => {
1862
2705
  // Ovviamente gli oridnamenti devono essere quelli appena generati
1863
2706
  as.orders = orderings;
2707
+ as.savedstate = true;
1864
2708
  this.emitSearchRequest(false, as);
1865
2709
  });
1866
2710
  }
@@ -1877,15 +2721,16 @@ class EsTableComponent {
1877
2721
  if (grp._sep)
1878
2722
  return "";
1879
2723
  let display = header.thAggregation;
1880
- if (grp.column == cell)
1881
- return grp.value;
2724
+ if (grp.column == cell) {
2725
+ let groupsPart = grp._groupscount ? " - " + grp._groupscount + " " + this.lc.loc("Groups") : "";
2726
+ return grp.value + " (" + grp.count + groupsPart + ")";
2727
+ }
1882
2728
  else {
1883
- let agg = grp.aggregations.filter(t => t.column == cell);
2729
+ let agg = grp._aggregationsCache.get(cell);
1884
2730
  if (!agg)
1885
2731
  return "";
1886
2732
  this.getEsThDirectiveListOfAggregations(header).forEach((itm) => {
1887
- let aggValue = agg.find(t => t.aggregation == itm.func).value;
1888
- display = display.replace(itm.match, this.formatAggregationValue(aggValue, itm.format));
2733
+ display = display.replace(itm.match, this.formatAggregationValue(agg.get(itm.func), itm.format));
1889
2734
  });
1890
2735
  return display;
1891
2736
  }
@@ -1900,20 +2745,30 @@ class EsTableComponent {
1900
2745
  */
1901
2746
  handleGroupClick(group) {
1902
2747
  let casted = this.View;
1903
- let anyGroup = group;
1904
- anyGroup._expanded = !anyGroup._expanded;
1905
- if (anyGroup._expanded) {
2748
+ let anyG = group;
2749
+ anyG._expanded = !anyG._expanded;
2750
+ // Sono in modalità raggruppamento virtuale da array: Espandere significa rendere visibili tutti gli oggetti relativi a questo gruppo, viceversa il contrarre
2751
+ if (this.ArrayGrouping) {
2752
+ let allRelatives = this.boundSource.filter(t => (t._group && ((anyG._expanded && t._parent == anyG._thisKey) || (!anyG._expanded && t._parent && t._parent.startsWith(anyG._thisKey)))) ||
2753
+ (t._item && ((anyG._expanded && t._thisKey == anyG._thisKey) || (!anyG._expanded && t._thisKey.startsWith(anyG._thisKey)))));
2754
+ allRelatives.forEach(t => { t._visible = anyG._expanded; if (t._group)
2755
+ t._expanded = false; });
2756
+ return;
2757
+ }
2758
+ if (anyG._expanded) {
2759
+ // Resetto ipp
2760
+ casted.itemsperpageoverride = 15;
1906
2761
  if (!casted.requestedgroups)
1907
2762
  casted.requestedgroups = [new GroupFilter(group.column, group.value)];
1908
2763
  else {
1909
- let level = anyGroup._grouplevel;
2764
+ let level = anyG._grouplevel;
1910
2765
  // se il gruppo cliccato non ha un livello è il primo gruppo, quindi ordinamento unico
1911
2766
  // altrimenti devo rimuovere tutti i filtri su livelli superiori al level cliccato e aggiungere il level cliccato
1912
2767
  if (!level)
1913
2768
  casted.requestedgroups = [new GroupFilter(group.column, group.value)];
1914
2769
  else {
1915
2770
  casted.requestedgroups = [];
1916
- anyGroup._parentRoute.forEach((step) => {
2771
+ anyG._parentRoute.forEach((step) => {
1917
2772
  casted.requestedgroups.push(new GroupFilter(step.column, step.value));
1918
2773
  });
1919
2774
  casted.requestedgroups.push(new GroupFilter(group.column, group.value));
@@ -1923,7 +2778,7 @@ class EsTableComponent {
1923
2778
  this.emitSearchRequest(true);
1924
2779
  }
1925
2780
  else {
1926
- let path = (anyGroup._parent || '') + group.value;
2781
+ let path = (anyG._parent || '') + group.value;
1927
2782
  // Se ho chiuso un gruppo non mi serve rieffettuare ricerce, mi basta eliminare dagli oggetti bindati tutti gli elementi sottostanti a quel gruppo
1928
2783
  this.boundSource = this.boundSource.filter(t => !t._parent || !t._parent.startsWith(path));
1929
2784
  // devo però anche rimuovere eventuali cache relative
@@ -1942,7 +2797,9 @@ class EsTableComponent {
1942
2797
  formatAggregationValue(value, format) {
1943
2798
  if (!format)
1944
2799
  return value;
1945
- let isNumber = !Number.isNaN(value) && !format || format.startsWith("F");
2800
+ let isNumber = !Number.isNaN(value) && (!format || format.startsWith("F"));
2801
+ if (isNumber && format.startsWith("F") && !Number.isNaN(format.substr(1)))
2802
+ return parseFloat(value).toFixed(parseInt(format.substr(1)));
1946
2803
  let date = null;
1947
2804
  // Alcune versione di extensions rischiano di crashare con cose non date... è stato risolto dopo quindi questo try - catch in realtà
1948
2805
  // torna utile solo con versioni vecchie/deprecate della libreria @esfaenza/extensions
@@ -1952,10 +2809,6 @@ class EsTableComponent {
1952
2809
  catch (_a) { }
1953
2810
  if (date)
1954
2811
  return this.dateExts.getFormatted(date, format == 'small', format == 'verylong');
1955
- else if (isNumber) {
1956
- if (format.startsWith("F") && !Number.isNaN(format.substr(1)))
1957
- return parseFloat(value).toFixed(parseInt(format.substr(1)));
1958
- }
1959
2812
  // Qui ci finisco sia per input che non sono né date né numeri, sia per formati non riconosciuti
1960
2813
  return value;
1961
2814
  }
@@ -1968,7 +2821,7 @@ class EsTableComponent {
1968
2821
  */
1969
2822
  sendUp(columnItem) {
1970
2823
  let itemIndex = this.TMPColumnsList.indexOf(columnItem);
1971
- if (this.TMPColumnsList[itemIndex - 1].fixed)
2824
+ if (this.TMPColumnsList[itemIndex - 1].fixed || this.TMPColumnsList[itemIndex - 1].pinned)
1972
2825
  return;
1973
2826
  this.utiExts.swap(this.TMPColumnsList, itemIndex, itemIndex - 1);
1974
2827
  // Non posso fare JSON.parse(JSON.stringify(this.ColumnsList)) perché contiene riferimenti a TemplateRef
@@ -1989,6 +2842,25 @@ class EsTableComponent {
1989
2842
  this.TMPColumnsList.forEach(c => { tmp.push(Object.assign({}, c)); });
1990
2843
  this.TMPColumnsList = tmp;
1991
2844
  }
2845
+ /**
2846
+ * All'interno della dialog "Ordinamento e Visibilità Colonne" pinna la colonna specificata
2847
+ *
2848
+ * @param {EsTableColumn} columnItem Colonna da spostare
2849
+ */
2850
+ pinOrUnpinColumn(columnItem) {
2851
+ let itemIndex = this.TMPColumnsList.indexOf(columnItem);
2852
+ // Sposto la colonna alla fine di tutte quelle pinnate. La cosa funziona in entrambi sensi:
2853
+ // 1) Se sto pinnando, devo metterla come ultima pinnata
2854
+ // 2) Se sto spinnando devo metterla come prima non pinnata
2855
+ // Coincidenza vuole che il punto 1 e 2 siano equivalenti
2856
+ for (let i = 0; i < this.TMPColumnsList.length; i++) {
2857
+ if (!this.TMPColumnsList[i].pinned) {
2858
+ this.arrayMove(this.TMPColumnsList, itemIndex, i);
2859
+ break;
2860
+ }
2861
+ }
2862
+ columnItem.pinned = !columnItem.pinned;
2863
+ }
1992
2864
  /**
1993
2865
  * All'interno della dialog "Ordinamento e Visibilità Colonne" inverte le impostazioni di visibilità della colonna
1994
2866
  *
@@ -2047,12 +2919,12 @@ class EsTableComponent {
2047
2919
  // Non permetto di non selezionare nulla
2048
2920
  if (this.TMPColumnsList.every(t => !t.visible))
2049
2921
  return false;
2050
- let castedView = this.View;
2922
+ let castedView = this.viewMode ? this.View : null;
2051
2923
  this.ColumnsList = [];
2052
2924
  this.TMPColumnsList.forEach(c => { this.ColumnsList.push(Object.assign({}, c)); });
2053
2925
  this.refreshColumnOrdering();
2054
- this.refreshColumnsVisibility(null, null, castedView);
2055
2926
  this.applyOrdering(castedView, false);
2927
+ this.refreshColumnsVisibility(null, null, castedView);
2056
2928
  //Salvo le preferences di questa view
2057
2929
  //Di default registro ordinamento e visibilità delle colonne nella vista. Solo le cose di UI
2058
2930
  if (this.SavePreferences) {
@@ -2064,11 +2936,17 @@ class EsTableComponent {
2064
2936
  console.error("Non posso utilizzare le preference senza che il pacchetto @esfaenza/preferences sia installato");
2065
2937
  return false;
2066
2938
  }
2067
- var toStore = { columns: JSON.parse(JSON.stringify(castedView.columns)), column_ordering: JSON.parse(JSON.stringify(castedView.column_ordering)) };
2939
+ let columns = this.arrayMode ? this.arrayColumns : castedView.columns;
2940
+ let columnsOrderings = this.arrayMode ? this.arrayColumnOrdering : castedView.column_ordering;
2941
+ var toStore = { columns: JSON.parse(JSON.stringify(columns)), column_ordering: JSON.parse(JSON.stringify(columnsOrderings)) };
2068
2942
  this.prefService.store(this.ngControl.name, toStore);
2069
2943
  }
2944
+ // Rieseguo l'ultima ricerca bindata alla tabella
2070
2945
  // Mi assicuro di farlo dopo l'espansione del changed o rischio che la ricerca mi ridia colonne che in realtà non esistono
2071
- setTimeout(() => { this.emitSearchRequest(false); });
2946
+ if (this.viewMode)
2947
+ setTimeout(() => { this.emitSearchRequest(false); });
2948
+ else if (this.arrayMode)
2949
+ setTimeout(() => { this.internalWriteValue(); });
2072
2950
  // Lo vorrei mettere lato template ma no
2073
2951
  this.lastSelectedItemID = null;
2074
2952
  return true;
@@ -2077,7 +2955,8 @@ class EsTableComponent {
2077
2955
  * Sul click nella checkbox di selezione globale si scorrono tutte le colonne e si impostano al valore della check globale
2078
2956
  */
2079
2957
  globalColVisCheckChanged() {
2080
- this.TMPColumnsList.forEach(t => { t.visible = this.globalColVisCheck; });
2958
+ this.TMPColumnsList.forEach(t => { if (!t.fixed)
2959
+ t.visible = this.globalColVisCheck; });
2081
2960
  }
2082
2961
  // #endregion
2083
2962
  // #region Gestione data source gerarchici
@@ -2125,9 +3004,9 @@ class EsTableComponent {
2125
3004
  let obj = objs[i];
2126
3005
  // Se la parentKey non è valorizzata, questo è il livello 0 (1... perché gli 0 son perciolosi)
2127
3006
  if (!obj[this.ParentKey] && levelToAssign == 1) {
2128
- obj.level = 1;
2129
- obj.visible = true;
2130
- obj.expanded = this.StartsExpanded;
3007
+ obj._level = 1;
3008
+ obj._visible = true;
3009
+ obj._expanded = this.StartsExpanded;
2131
3010
  assigned++;
2132
3011
  continue;
2133
3012
  }
@@ -2137,13 +3016,13 @@ class EsTableComponent {
2137
3016
  for (let p = 0; p < objs.length; p++) {
2138
3017
  let possibleParent = objs[p];
2139
3018
  // Trovato il parent dell'item, assegno all'item il livello giusto
2140
- if (possibleParent[this.OwnKey] == obj[this.ParentKey] && possibleParent.level == levelToAssign - 1) {
2141
- obj.level = levelToAssign;
3019
+ if (possibleParent[this.OwnKey] == obj[this.ParentKey] && possibleParent._level == levelToAssign - 1) {
3020
+ obj._level = levelToAssign;
2142
3021
  // So che questo item ha un parent. Ribadisco che il parent è espanso in base alle impostazione e stessa logica
2143
3022
  // per la visibilità del figlio
2144
- possibleParent.expanded = this.StartsExpanded;
3023
+ possibleParent._expanded = this.StartsExpanded;
2145
3024
  possibleParent.parent = true;
2146
- obj.visible = this.StartsExpanded;
3025
+ obj._visible = this.StartsExpanded;
2147
3026
  assigned++;
2148
3027
  break;
2149
3028
  }
@@ -2162,12 +3041,12 @@ class EsTableComponent {
2162
3041
  let obj = this.boundSource[i];
2163
3042
  // Trovo il parent con quell'id e lo espando
2164
3043
  if (obj[this.OwnKey] == key) {
2165
- obj.expanded = true;
3044
+ obj._expanded = true;
2166
3045
  for (let ic = 0; ic < this.boundSource.length; ic++) {
2167
3046
  let child = this.boundSource[ic];
2168
3047
  // Trovo tutti i child di quel parent e li rendo visibili
2169
3048
  if (child[this.ParentKey] == key)
2170
- child.visible = true;
3049
+ child._visible = true;
2171
3050
  }
2172
3051
  return;
2173
3052
  }
@@ -2183,7 +3062,7 @@ class EsTableComponent {
2183
3062
  let obj = this.boundSource[i];
2184
3063
  // Trovo il parent con quell'id e lo collasso
2185
3064
  if (obj[this.OwnKey] == key) {
2186
- obj.expanded = false;
3065
+ obj._expanded = false;
2187
3066
  // Collasso/nascondo tutti i child del parent
2188
3067
  this.collapseChildOfParent(key);
2189
3068
  return;
@@ -2201,10 +3080,10 @@ class EsTableComponent {
2201
3080
  // Trovo tutti i child di quel parent e li rendo invisibili. Se il child trovato è a sua volta un parent,
2202
3081
  // lo collasso e vado in ricorsione sui figli
2203
3082
  if (child[this.ParentKey] == parentKey && !child.parent)
2204
- child.visible = false;
3083
+ child._visible = false;
2205
3084
  else if (child[this.ParentKey] == parentKey && child.parent) {
2206
- child.expanded = false;
2207
- child.visible = false;
3085
+ child._expanded = false;
3086
+ child._visible = false;
2208
3087
  this.collapseChildOfParent(child[this.OwnKey]);
2209
3088
  }
2210
3089
  }
@@ -2239,22 +3118,29 @@ class EsTableComponent {
2239
3118
  * @param {ItemsSelection<any>} selectionItem Oggetto contenente lo stato attuale di selezione
2240
3119
  */
2241
3120
  handleSelectionEvaluation(items, selectionItem) {
2242
- let allSelected = items.length > 0;
2243
3121
  for (let i = 0; i < items.length; i++) {
2244
3122
  let itm = items[i];
3123
+ let hash = itm._hash;
3124
+ let itemGroup = itm._group ? null : this.getItemGroup(itm);
2245
3125
  // Reidrato la cache di selezione coi nuovi oggetti altrimenti non riuscirei a beccare gli indici giusti
2246
3126
  // Dopodiché la uso per calcolare istantaneamente se gli oggetti sono selezionati o no
2247
- if (this.selOrDeselCache[itm.hash])
2248
- this.selOrDeselCache[itm.hash] = itm;
2249
- if (selectionItem.all)
2250
- itm._selected = !this.selOrDeselCache[itm.hash];
2251
- else
2252
- itm._selected = !!this.selOrDeselCache[itm.hash];
2253
- allSelected = allSelected && itm._selected;
3127
+ this.rehidrateCache(itm);
3128
+ if (itm._item) {
3129
+ if (selectionItem.all)
3130
+ 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));
3131
+ else
3132
+ 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)));
3133
+ }
3134
+ else if (itm._group) {
3135
+ if (selectionItem.all)
3136
+ itm._selected = !this.group_exclusionsCache.has(hash) && this.parentTreeStatus(itm) != 'excluded';
3137
+ else
3138
+ itm._selected = this.groupsCache.has(hash) || (this.parentTreeStatus(itm) == 'included' && !this.group_exclusionsCache.has(hash));
3139
+ }
2254
3140
  }
2255
3141
  // Se tutti gli oggetti di questa pagina sono solezionati allora posso mettere il global check a true
2256
3142
  // Se sono in situazione di all-select anche metto la global checkbox, nonostante ci possano essere delle esclusioni
2257
- this.globalCheck = allSelected || selectionItem.all;
3143
+ this.globalCheck = this.boundSource.filter(t => t._group || t._item).every(t => t._selected);
2258
3144
  this.canSelectAll = selectionItem.count > 0 && this.SelectAll;
2259
3145
  // Potrebbe cambiare qualora qualcuno inserisse dati a manazza in modalità Array e desse il refresh manuale alla tabella
2260
3146
  // Comunque costa 0 quindi mi permetto di refreshare
@@ -2265,14 +3151,52 @@ class EsTableComponent {
2265
3151
  this.onSelectionChanged.emit(selectionItem);
2266
3152
  }
2267
3153
  }
3154
+ /**
3155
+ * Dato un oggetto trova la cella di cache in cui è registrato e aggiorna il contenuto
3156
+ *
3157
+ * @param {any} item Oggetto da aggiornare
3158
+ */
3159
+ rehidrateCache(item) {
3160
+ let ctx = item._hash;
3161
+ if (this.itemsCache.has(ctx))
3162
+ this.itemsCache.set(ctx, item);
3163
+ if (this.group_exclusionsCache.has(ctx))
3164
+ this.group_exclusionsCache.set(ctx, item);
3165
+ if (this.groupsCache.has(ctx))
3166
+ this.groupsCache.set(ctx, item);
3167
+ if (this.exclusionsCache.has(ctx))
3168
+ this.exclusionsCache.set(ctx, item);
3169
+ }
3170
+ /**
3171
+ * Dato un gruppo controlla ricorsivamente l'albero di cui fa parte se c'è stata una inclusione o esclusione diretta
3172
+ *
3173
+ * @param {any} grp Gruppo da controllare
3174
+ *
3175
+ * @returns {'none' | 'excluded' | 'included'}
3176
+ * 'none' se non ci sono informazioni su inclusioni o esclusioni
3177
+ * 'included' se il gruppo controllato è stato incluso in maniera esplicita dall'albero dei gruppi padri
3178
+ * 'excluded' se il gruppo controllato è stato escluso in maniera esplicita dall'albero dei gruppi padri
3179
+ */
3180
+ parentTreeStatus(grp) {
3181
+ if (!grp)
3182
+ return 'none';
3183
+ let parentGroup = this.rgGroupCache.get(grp._parent);
3184
+ if (!parentGroup)
3185
+ return 'none';
3186
+ if (this.group_exclusionsCache.has(parentGroup._hash))
3187
+ return 'excluded';
3188
+ if (this.groupsCache.has(parentGroup._hash))
3189
+ return 'included';
3190
+ return this.parentTreeStatus(parentGroup);
3191
+ }
2268
3192
  /**
2269
3193
  * Gestisce la selezione globale degli oggetti, sia per pagina che a livello di **SelectAll**
2270
3194
  *
2271
3195
  * @param {boolean} forcedVal Valore forzato di check da assegnare agli oggetti
2272
3196
  */
2273
3197
  globalCheckChanged(forcedVal = null) {
2274
- // Prendo tutti gli elementi presenti in questa vista che non siano gruppi
2275
- let items = this.boundSource.filter(t => !t._group);
3198
+ // 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
3199
+ let items = this.boundSource.find(t => t._group) ? this.boundSource.filter(t => t._group && !t._parent) : this.boundSource;
2276
3200
  var itemSelection = this.handleItemsSelection(items, forcedVal, this.globalCheck);
2277
3201
  this.changed();
2278
3202
  this.onSelectionChanged.emit(itemSelection);
@@ -2284,18 +3208,19 @@ class EsTableComponent {
2284
3208
  *
2285
3209
  * @param {any[]} items Oggetti da selezionare o deselezionare
2286
3210
  * @param {boolean} forcedVal Valore forzato di check da assegnare agli oggetti
3211
+ * @param {boolean} globalCheck Valore del check globale
2287
3212
  *
2288
3213
  * @returns {ItemsSelection<any>} Oggetto di selezione aggiornato con le informazioni sull'ultima operazione effettuata
2289
3214
  */
2290
3215
  handleItemsSelection(items, forcedVal = null, globalCheck = null) {
2291
- var _a, _b;
2292
- let selectionItem = ((_a = this.View) === null || _a === void 0 ? void 0 : _a.selection) || this.arraymodeSelection;
3216
+ var _a, _b, _c;
3217
+ let si = ((_a = this.View) === null || _a === void 0 ? void 0 : _a.selection) || this.arraymodeSelection;
2293
3218
  // Se sono in modalità di selezione singola e devo selezionare un'oggetto, per prima cosa devo deselezionare tutti gli altri
2294
- if (this.SingleSelection && ((_b = items[0]) === null || _b === void 0 ? void 0 : _b._selected)) {
3219
+ 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)) {
2295
3220
  if (items.length > 1 && forcedVal == null)
2296
3221
  throw "Tentativo di selezionare o deselezionare più di un elemento con SingleSelection attivo";
2297
3222
  if (items.length == 1 && forcedVal == null) {
2298
- selectionItem = this.handleItemsSelection(this.boundSource.filter(t => !t._group), false, null);
3223
+ si = this.handleItemsSelection(this.boundSource.filter(t => !t._group), false, null);
2299
3224
  items[0]._selected = true;
2300
3225
  }
2301
3226
  }
@@ -2305,59 +3230,343 @@ class EsTableComponent {
2305
3230
  // Se dev'essere overridato il valore di check effettuo l'override o col valore forzato o col valore globale
2306
3231
  if (toChange && !item.locked)
2307
3232
  item._selected = forcedVal != null ? forcedVal : this.globalCheck;
2308
- if (selectionItem.all) {
2309
- // In caso di "seleziona tutto"...
2310
- // N.B: la selOrDeselCache agisce come cache di DESELEZIONE in questo blocco di codice
2311
- if (item._selected && this.selOrDeselCache[item.hash]) {
2312
- // Oggetto selezionato: lo rimuovo dalle esclusioni di selezione
2313
- selectionItem.exclusions.splice(selectionItem.exclusions.indexOf(this.selOrDeselCache[item.hash]), 1);
2314
- delete this.selOrDeselCache[item.hash];
2315
- }
2316
- else if (!item._selected && !this.selOrDeselCache[item.hash]) {
2317
- // Oggetto deselezionato: lo aggiungo alle esclusioni di selezione
2318
- this.selOrDeselCache[item.hash] = item;
2319
- selectionItem.exclusions.push(item);
2320
- }
3233
+ // 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
3234
+ if (!toChange && globalCheck != null)
3235
+ continue;
3236
+ let allSelection = si.all;
3237
+ let isGroup = item._group;
3238
+ let isSelection = item._selected;
3239
+ let itemGroup = null, allItems = null, selectedItems = null, unselectedItems = null, allGroups = null, selectedGroups = null, unselectedGroups = null, parentGroupSelected = null, parentGroupUnselected = null;
3240
+ if (isGroup) {
3241
+ let pts = this.parentTreeStatus(item);
3242
+ parentGroupSelected = pts == 'included';
3243
+ parentGroupUnselected = pts == 'excluded';
3244
+ allItems = this.getGroupItems(si, item, null, true);
3245
+ selectedItems = this.getGroupItems(si, item, 'selected', true, allItems);
3246
+ unselectedItems = this.getGroupItems(si, item, 'unselected', true, allItems);
3247
+ allGroups = this.getGroupChildGroups(si, item, null, true);
3248
+ selectedGroups = this.getGroupChildGroups(si, item, 'selected', true, allGroups);
3249
+ unselectedGroups = this.getGroupChildGroups(si, item, 'unselected', true, allGroups);
2321
3250
  }
2322
3251
  else {
2323
- //In caso di non "seleziona tutto"...
2324
- // N.B: la selOrDeselCache agisce come cache di SELEZIONE in questo blocco di codice
2325
- if (item._selected && !this.selOrDeselCache[item.hash]) {
2326
- // Oggetto selezionato: lo aggiungo alla selezione attuale
2327
- this.selOrDeselCache[item.hash] = item;
2328
- selectionItem.items.push(item);
2329
- }
2330
- else if (!item._selected && this.selOrDeselCache[item.hash]) {
2331
- // Oggetto deselezionato: lo rimuovo dalla selezione attuale
2332
- selectionItem.items.splice(selectionItem.items.indexOf(this.selOrDeselCache[item.hash]), 1);
2333
- delete this.selOrDeselCache[item.hash];
2334
- }
3252
+ itemGroup = this.getItemGroup(item);
3253
+ parentGroupSelected = itemGroup == null ? null : itemGroup._selected;
3254
+ parentGroupUnselected = itemGroup == null ? null : !itemGroup._selected;
2335
3255
  }
3256
+ if (!this.ArrayGrouping)
3257
+ this.performSelectionOperations(si, item, allSelection, isGroup, isSelection, selectedItems, selectedGroups, unselectedItems, unselectedGroups, allItems, allGroups, parentGroupSelected, parentGroupUnselected);
3258
+ else
3259
+ this.performSimpleSelectionOperations(si, item, isGroup, isSelection, itemGroup, selectedItems, unselectedItems, allItems, allGroups);
2336
3260
  }
2337
3261
  // Imposto il check globale in base a se tutti gli elementi sono selezionati o meno.
2338
3262
  // Evito di fare queste operazioni se la selezione deriva proprio dal global Check
2339
- // Non è ottimizzatissimo mettere 2 some ma scrivere questo codice a for sono tipo 25 righe....
2340
3263
  if (globalCheck == null)
2341
- this.globalCheck = !items.some(t => !t._selected) && !this.boundSource.some(t => !t._selected && !t._group);
2342
- this.finalizeSelectionInformations(selectionItem);
2343
- return selectionItem;
3264
+ this.globalCheck = !this.boundSource.some(t => !t._selected && !t._sep);
3265
+ this.finalizeSelectionInformations(si);
3266
+ return si;
3267
+ }
3268
+ /**
3269
+ * Dato L'oggetto di selezione, l'oggetto da selezionare/deselezionare e tutti i parametri del caso effettua le operazioni che servono.
3270
+ *
3271
+ * Logica semplificata rispetto all'originale **performSelectionOperations** per lavorare in una modalità in cui tutti gli elementi sono caricati (**ArrayGrouping** = true)
3272
+ */
3273
+ performSimpleSelectionOperations(base, item, group, sel, itm_group, sel_itm, desel_itm, all_itms, all_grps) {
3274
+ let tripticItem = this.getTriptic('item', base);
3275
+ if (group) {
3276
+ if (sel) {
3277
+ all_grps.forEach(gr => { gr._selected = true; });
3278
+ if (desel_itm)
3279
+ desel_itm.forEach(el => { el._selected = true; this.addItem(el, tripticItem); });
3280
+ }
3281
+ else {
3282
+ all_grps.forEach(gr => { gr._selected = false; });
3283
+ if (sel_itm)
3284
+ sel_itm.forEach(el => { el._selected = false; this.removeItem(el, tripticItem); });
3285
+ }
3286
+ }
3287
+ else {
3288
+ if (sel) {
3289
+ this.addItem(item, tripticItem);
3290
+ if (itm_group && all_itms && all_itms.every(t => t._selected))
3291
+ this.selectGroup(itm_group);
3292
+ }
3293
+ else {
3294
+ this.removeItem(item, tripticItem);
3295
+ if (itm_group)
3296
+ itm_group._selected = false;
3297
+ }
3298
+ }
3299
+ }
3300
+ /**
3301
+ * Helper per selezionare un gruppo e, ricorsivamente, se tutti i gruppi sottostanti al parent sono selezionati, selezionare i gruppi padri
3302
+ *
3303
+ * @param {any} group Gruppo da selezionare
3304
+ */
3305
+ selectGroup(group) {
3306
+ group._selected = true;
3307
+ let parent = this.getGroupParent(group);
3308
+ if (parent && this.getGroupChildGroups(null, parent, null, true).every(t => t._selected))
3309
+ this.selectGroup(parent);
3310
+ }
3311
+ /**
3312
+ * Dato L'oggetto di selezione, l'oggetto da selezionare/deselezionare e tutti i parametri del caso effettua le operazioni che servono.
3313
+ *
3314
+ * La logica di questa funzione è nata essenzialmente da spam di trial & error ed è stata testata solo fino a due livelli di raggruppamento,
3315
+ * qualsiasi cosa vada oltre non è 100% detto che funzioni...
3316
+ */
3317
+ performSelectionOperations(base, item, all, group, sel, sel_itm, sel_grp, desel_itm, desel_grp, all_itms, all_grps, parent_incl, parent_excl) {
3318
+ let tripticGroup = this.getTriptic('group', base);
3319
+ let tripticItem = this.getTriptic('item', base);
3320
+ let tripticExcl = this.getTriptic('exclusion', base);
3321
+ let tripticgrpExcl = this.getTriptic('group_exclusion', base);
3322
+ if (group) {
3323
+ if (sel) {
3324
+ if (all || parent_incl)
3325
+ this.removeItem(item, tripticgrpExcl);
3326
+ else
3327
+ this.addItem(item, tripticGroup);
3328
+ if (sel_itm)
3329
+ sel_itm.forEach(el => this.removeItem(el, tripticItem));
3330
+ if (sel_grp)
3331
+ sel_grp.forEach(gr => this.removeItem(gr, tripticGroup));
3332
+ if (all_itms)
3333
+ all_itms.forEach(el => { el._selected = true; this.removeItem(el, tripticExcl); });
3334
+ if (all_grps)
3335
+ all_grps.forEach(gr => { gr._selected = true; this.removeItem(gr, tripticgrpExcl); });
3336
+ }
3337
+ else {
3338
+ if (all || parent_incl)
3339
+ this.addItem(item, tripticgrpExcl);
3340
+ else
3341
+ this.removeItem(item, tripticGroup);
3342
+ if (desel_itm)
3343
+ desel_itm.forEach(el => this.removeItem(el, tripticExcl));
3344
+ if (desel_grp)
3345
+ desel_grp.forEach(gr => this.removeItem(gr, tripticExcl));
3346
+ if (all_itms)
3347
+ all_itms.forEach(el => { el._selected = false; this.removeItem(el, tripticItem); });
3348
+ if (all_grps)
3349
+ all_grps.forEach(gr => { gr._selected = false; this.removeItem(gr, tripticGroup); });
3350
+ }
3351
+ }
3352
+ else {
3353
+ if (sel) {
3354
+ if ((parent_excl == null && all) || parent_incl)
3355
+ this.removeItem(item, tripticExcl);
3356
+ else
3357
+ this.addItem(item, tripticItem);
3358
+ }
3359
+ else {
3360
+ if (parent_excl || (!all && parent_excl == null))
3361
+ this.removeItem(item, tripticItem);
3362
+ else
3363
+ this.addItem(item, tripticExcl);
3364
+ }
3365
+ }
3366
+ }
3367
+ /**
3368
+ * Helper per evitare di riscrivere ogni santa volta array.splice(array.indexof(item), 1);
3369
+ */
3370
+ removeItem(item, triptic) {
3371
+ let index = triptic.index_cache.get(item._hash);
3372
+ if (index != null) {
3373
+ triptic.cache.delete(item._hash);
3374
+ triptic.index_cache.delete(item._hash);
3375
+ triptic.array[index] = null;
3376
+ }
3377
+ return !!index;
3378
+ }
3379
+ /**
3380
+ * Helper per evitare di riscrivere ogni santa volta array.push(item); e la gestione della
3381
+ */
3382
+ addItem(item, triptic) {
3383
+ if (triptic.index_cache.get(item._hash) == null) {
3384
+ let i = triptic.array.push(item) - 1;
3385
+ triptic.cache.set(item._hash, item);
3386
+ triptic.index_cache.set(item._hash, i);
3387
+ return true;
3388
+ }
3389
+ return false;
3390
+ }
3391
+ /**
3392
+ * Ottiene il trittico di selezione: L'array degli oggetti e le due cache
3393
+ */
3394
+ getTriptic(subject, base) {
3395
+ switch (subject) {
3396
+ case 'group':
3397
+ return new CacheTriptic(this.groupsCache, this.i_groupsCache, base.groups);
3398
+ case 'item':
3399
+ return new CacheTriptic(this.itemsCache, this.i_itemsCache, base.items);
3400
+ case 'group_exclusion':
3401
+ return new CacheTriptic(this.group_exclusionsCache, this.i_group_exclusionsCache, base.group_exclusions);
3402
+ case 'exclusion':
3403
+ return new CacheTriptic(this.exclusionsCache, this.i_exclusionsCache, base.exclusions);
3404
+ }
3405
+ }
3406
+ /**
3407
+ * Dato un oggetto restituisce il gruppo di cui fa parte, se esiste
3408
+ *
3409
+ * @param {any} item Oggetto di cui trovare il gruppo
3410
+ */
3411
+ getItemGroup(item) {
3412
+ let parent = this.rgGroupCache.get(item._thisKey);
3413
+ if (parent)
3414
+ return parent;
3415
+ return null;
3416
+ }
3417
+ /**
3418
+ * Data la chiave di un gruppo restituisce tutti gli oggetti con quella chiave
3419
+ *
3420
+ * @param {any} group Chiave da cercare
3421
+ * @param {'selected' | 'unselected'} status Stato degli elementi, selezionati o no
3422
+ * @param {boolean} recursive Indica se cercare solo gli elementi direttamente collegati o se prendere anche quelli dei gruppi figli
3423
+ *
3424
+ * @returns {any[]} Oggetti di tipo **_item** facenti capo alla chiave **groupKey**
3425
+ */
3426
+ getGroupItems(sel, group, status, recursive = false, allbase = null) {
3427
+ let items = [];
3428
+ if (allbase)
3429
+ items = allbase;
3430
+ else {
3431
+ if (recursive) {
3432
+ // In modalità ricorsiva prendo gli oggetti di tutte le chiavi simili che trovo
3433
+ for (let key of this.rgItemCache.keys())
3434
+ if (key.startsWith(group._thisKey))
3435
+ items.push(...this.rgItemCache.get(key));
3436
+ }
3437
+ else
3438
+ items = this.rgItemCache.get(group._thisKey);
3439
+ }
3440
+ items = items.filter(t => !status || (t._selected && status == 'selected') || (!t._selected && status == 'unselected'));
3441
+ // Non trovo nessun oggetto, però magari di oggetti ne ho all'interno dell'oggetto di selezione.
3442
+ // Questo può essere vero solo se NON sono in modalità array, in caso contrario gli oggetti li devo per forza avere tutti
3443
+ if (items.length != 0 || !sel || this.arrayMode)
3444
+ return items;
3445
+ if (status == 'unselected')
3446
+ items = sel.exclusions.filter(t => t != null &&
3447
+ (!recursive && t._thisKey == group._thisKey) ||
3448
+ (recursive && t._thisKey.startsWith(group._thisKey)));
3449
+ else if (status == 'selected')
3450
+ items = sel.items.filter(t => t != null &&
3451
+ (!recursive && t._thisKey == group._thisKey) ||
3452
+ (recursive && t._thisKey.startsWith(group._thisKey)));
3453
+ return items;
3454
+ }
3455
+ /**
3456
+ * Data la chiave di un gruppo restituisce tutti gli oggetti con quella chiave
3457
+ *
3458
+ * @param {any} group Gruppo di cui cercare il parent
3459
+ *
3460
+ * @returns {any} Oggetto di tipo **_group** rappresentante il parent del **group** attuale
3461
+ */
3462
+ getGroupParent(group) {
3463
+ let parent = this.rgGroupCache.get(group._parent);
3464
+ if (parent)
3465
+ return parent;
3466
+ return null;
3467
+ }
3468
+ /**
3469
+ * Data la chiave di un gruppo restituisce tutti i gruppi figli
3470
+ *
3471
+ * @param {string} group Gruppo che rappresenta il padre di cui cercare i figli
3472
+ * @param {'selected' | 'unselected'} status Stato dei gruppi, selezionati o no
3473
+ * @param {boolean} recursive Indica se cercare solo i gruppi direttamente collegati o se prendere anche quelli dei gruppi figli
3474
+ *
3475
+ * @returns {any[]} Oggetti di tipo **_group** facenti capo alla chiave **groupKey**
3476
+ */
3477
+ getGroupChildGroups(sel, group, status, recursive = false, allbase = null) {
3478
+ let thisGroup = this.rgGroupCache.get(group._thisKey);
3479
+ let items = [];
3480
+ if (allbase)
3481
+ items = allbase;
3482
+ else {
3483
+ if (recursive) {
3484
+ // In modalità ricorsiva prendo gli oggetti di tutte le chiavi simili che trovo
3485
+ for (let key of this.rgChildGroupsCache.keys())
3486
+ if (key.startsWith(group._thisKey))
3487
+ items.push(...this.rgChildGroupsCache.get(key));
3488
+ }
3489
+ else
3490
+ items = this.rgChildGroupsCache.get(group._thisKey);
3491
+ }
3492
+ items = items.filter(t => !status || (t._selected && status == 'selected') || (!t._selected && status == 'unselected'));
3493
+ // Non trovo nessun oggetto, però magari di oggetti ne ho all'interno dell'oggetto di selezione
3494
+ if (items.length != 0 || !sel)
3495
+ return items;
3496
+ if (status == 'unselected')
3497
+ items = sel.group_exclusions.filter((t) => t != null && ((!recursive && t._thisRoute.length == thisGroup._thisRoute.length + 1 && t._thisRoute.startsWith(group._thisKey)) ||
3498
+ (recursive && t._thisKey.startsWith(group._thisKey))));
3499
+ else
3500
+ items = sel.groups.filter((t) => t != null && ((!recursive && t._thisRoute.length == thisGroup._thisRoute.length + 1 && t._thisRoute.startsWith(group._thisKey)) ||
3501
+ (recursive && t._thisKey.startsWith(group._thisKey))));
3502
+ return items;
2344
3503
  }
2345
3504
  /**
2346
3505
  * Finalizza le informazioni di selezione del **ItemsSelection** corrente
2347
3506
  */
2348
3507
  finalizeSelectionInformations(selectionItem) {
3508
+ // Dato che le delete sono logiche dato che tengo la cache degli indici devo renderle fisiche
3509
+ let tmpGrp = [], tmpItems = [], tmpExcl = [], tmpGrpExcl = [];
3510
+ let grpRemoved = false, itemsRemoved = false, exclRemoved = false, grpExclRemoved = false;
3511
+ for (let i = 0; i < selectionItem.items.length; i++)
3512
+ if (selectionItem.items[i] != null)
3513
+ tmpItems.push(selectionItem.items[i]);
3514
+ else
3515
+ itemsRemoved = true;
3516
+ for (let i = 0; i < selectionItem.groups.length; i++)
3517
+ if (selectionItem.groups[i] != null)
3518
+ tmpGrp.push(selectionItem.groups[i]);
3519
+ else
3520
+ grpRemoved = true;
3521
+ for (let i = 0; i < selectionItem.exclusions.length; i++)
3522
+ if (selectionItem.exclusions[i] != null)
3523
+ tmpExcl.push(selectionItem.exclusions[i]);
3524
+ else
3525
+ exclRemoved = true;
3526
+ for (let i = 0; i < selectionItem.group_exclusions.length; i++)
3527
+ if (selectionItem.group_exclusions[i] != null)
3528
+ tmpGrpExcl.push(selectionItem.group_exclusions[i]);
3529
+ else
3530
+ grpExclRemoved = true;
3531
+ selectionItem.items = tmpItems;
3532
+ selectionItem.group_exclusions = tmpGrpExcl;
3533
+ selectionItem.exclusions = tmpExcl;
3534
+ selectionItem.groups = tmpGrp;
3535
+ // Le cache degli indici potrebbero avere buchi, risolvo
3536
+ if (grpRemoved)
3537
+ this.i_groupsCache = this.compactIndexMap(this.i_groupsCache);
3538
+ if (itemsRemoved)
3539
+ this.i_itemsCache = this.compactIndexMap(this.i_itemsCache);
3540
+ if (exclRemoved)
3541
+ this.i_exclusionsCache = this.compactIndexMap(this.i_exclusionsCache);
3542
+ if (grpExclRemoved)
3543
+ this.i_group_exclusionsCache = this.compactIndexMap(this.i_group_exclusionsCache);
3544
+ // Poi riprendo a fare tutto in normalità
2349
3545
  selectionItem.count = this.evaluateSelected();
2350
3546
  // Se ho fatto selezione "all" ma poi mi sono messo a togliere tutti gli elementi fino a rimanerne 0 resetto l'oggetto di selezione
2351
- if (selectionItem.count == 0 && selectionItem.all) {
3547
+ if (selectionItem.count == 0) {
3548
+ this.boundSource.forEach(t => t._selected = false);
2352
3549
  selectionItem.all = false;
2353
3550
  selectionItem.exclusions = [];
2354
3551
  selectionItem.items = [];
3552
+ selectionItem.groups = [];
3553
+ selectionItem.group_exclusions = [];
2355
3554
  // Ripulisco la cache altrimenti mi rimane piena di tutte le esclusioni
2356
- this.selOrDeselCache = {};
3555
+ this.clearSelectionCaches();
2357
3556
  }
2358
3557
  // Se la possibilità di fare "Seleziona tutto" è abilitata allora la considero appena mi viene selezionato qualcosa
2359
3558
  this.canSelectAll = selectionItem.count > 0 && this.SelectAll;
2360
3559
  }
3560
+ /**
3561
+ * Compatta una cache di indici
3562
+ */
3563
+ compactIndexMap(map) {
3564
+ let index = 0;
3565
+ let ret = new Map();
3566
+ for (let key of map.keys())
3567
+ ret.set(key, index++);
3568
+ return ret;
3569
+ }
2361
3570
  /**
2362
3571
  * Gestisce i click sulla tabella, gestendo eventualmente anche gli Shift + Click per selezionare un range di oggetti
2363
3572
  *
@@ -2376,7 +3585,7 @@ class EsTableComponent {
2376
3585
  let selecteditems = [];
2377
3586
  if (event.shiftKey && this.ShiftClick && !this.SingleSelection) {
2378
3587
  let startSelecting = false;
2379
- let items = this.boundSource.filter(t => !t.group);
3588
+ let items = this.boundSource.filter(t => !t._group && !t._sep);
2380
3589
  for (let i = 0; i < items.length; i++) {
2381
3590
  let t = items[i];
2382
3591
  if (startSelecting) {
@@ -2409,8 +3618,10 @@ class EsTableComponent {
2409
3618
  */
2410
3619
  evaluateSelected() {
2411
3620
  var _a;
2412
- let selectionItem = ((_a = this.View) === null || _a === void 0 ? void 0 : _a.selection) || this.arraymodeSelection;
2413
- this.selectedObjects = selectionItem.all ? (this.View.objectcount || this.View.length) - selectionItem.exclusions.length : selectionItem.items.length;
3621
+ let si = ((_a = this.View) === null || _a === void 0 ? void 0 : _a.selection) || this.arraymodeSelection;
3622
+ let excByGroup = si.group_exclusions.reduce((prev, curr) => prev + curr.count, 0);
3623
+ let incByGroup = si.groups.reduce((prev, curr) => prev + curr.count, 0);
3624
+ this.selectedObjects = (si.all ? this.BaseItemsCount : incByGroup) - excByGroup + si.items.length - si.exclusions.length;
2414
3625
  return this.selectedObjects;
2415
3626
  }
2416
3627
  /**
@@ -2418,9 +3629,11 @@ class EsTableComponent {
2418
3629
  */
2419
3630
  selectAllOrResetSelection() {
2420
3631
  let selectionItem = this.View.selection || this.arraymodeSelection;
2421
- this.selOrDeselCache = {};
3632
+ this.clearSelectionCaches();
2422
3633
  selectionItem.all = !selectionItem.all;
2423
3634
  selectionItem.exclusions = [];
3635
+ selectionItem.groups = [];
3636
+ selectionItem.group_exclusions = [];
2424
3637
  selectionItem.items = [];
2425
3638
  // Ripulisco gli stati UI di selezione globale se l'ho disattivata
2426
3639
  if (!selectionItem.all) {
@@ -2430,7 +3643,7 @@ class EsTableComponent {
2430
3643
  this.finalizeSelectionInformations(selectionItem);
2431
3644
  this.onSelectionChanged.emit(selectionItem);
2432
3645
  // Dopo aver resettato direttamente il solo oggetto this.View.selection devo anche riallineare a tutti gli oggetti bindati
2433
- this.evaluateSelection(this.viewMode ? this.View.items : this.View, selectionItem);
3646
+ this.evaluateSelection(this.boundSource, selectionItem);
2434
3647
  }
2435
3648
  // #endregion
2436
3649
  // #region Gestione Paginazione
@@ -2440,9 +3653,9 @@ class EsTableComponent {
2440
3653
  * @param {number} page Numero di pagine da aggiungere (o sottrarre, se negativo) alla pagina attuale
2441
3654
  */
2442
3655
  addToPage(page) {
2443
- if (!(this.View instanceof AppSearch) && !(this.SearchView instanceof AppSearch) && !(this.View instanceof ReportDefinition))
2444
- return;
2445
- this.goToPage((this.SearchView || this.View).page + page);
3656
+ var _a;
3657
+ let view = this.MainGroupView ? this.MainGroupView : this.View;
3658
+ this.goToPage((((_a = (this.SearchView || view)) === null || _a === void 0 ? void 0 : _a.page) || 0) + page);
2446
3659
  }
2447
3660
  /**
2448
3661
  * Sposta la ricerca alla pagina specificata
@@ -2450,21 +3663,35 @@ class EsTableComponent {
2450
3663
  * @param {number} page Pagina a cui navigare
2451
3664
  */
2452
3665
  goToPage(page) {
2453
- if (!(this.View instanceof AppSearch) && !(this.SearchView instanceof AppSearch) && !(this.View instanceof ReportDefinition))
3666
+ let view = this.MainGroupView ? this.MainGroupView : this.View;
3667
+ if (!view.page || !view.pages)
2454
3668
  return;
2455
- let appSearchElement = this.SearchView || this.View;
3669
+ let appSearchElement = this.SearchView || view;
2456
3670
  if (page === 0 || page > appSearchElement.pages)
2457
3671
  return;
2458
3672
  appSearchElement.page = page;
2459
3673
  this.arrayPulsanti = this.getPagesArray(6, appSearchElement.page, appSearchElement.pages);
2460
- this.emitSearchRequest(false);
3674
+ let hasGroupings = !!this.MainGroupView;
3675
+ this.emitSearchRequest(false, hasGroupings ? view : null);
2461
3676
  }
2462
3677
  /**
2463
3678
  * Evento richiamato sul cambio della paginazione. Verrà richiamato l'evento **emitSearchRequest**
2464
3679
  * per comunicare al componente che utilizza questa tabella che i dati sono da aggiornare
2465
3680
  */
2466
- onItemsPerPageChanged() {
2467
- this.emitSearchRequest(true);
3681
+ onItemsPerPageChanged(newIpp) {
3682
+ this.PagerOptions.View.itemsperpageoverride = newIpp;
3683
+ this.changed();
3684
+ if (this.MainGroupView)
3685
+ this.emitSearchRequest(true, this.MainGroupView);
3686
+ else
3687
+ this.emitSearchRequest(true);
3688
+ }
3689
+ /**
3690
+ * Evento richiamato sul cambio della paginazione. Verrà richiamato l'evento **emitSearchRequest** con la vista del separatore
3691
+ */
3692
+ onGroupItemsPerPageChanged(pager, newIpp) {
3693
+ pager.view.itemsperpageoverride = newIpp;
3694
+ this.emitSearchRequest(true, pager.view);
2468
3695
  }
2469
3696
  // #endregion
2470
3697
  // #region Gestione Export
@@ -2611,12 +3838,12 @@ class EsTableComponent {
2611
3838
  * @returns {any} Router link generato in base al parametri
2612
3839
  */
2613
3840
  generateRouterLink(path, parameterProps, item) {
2614
- if (this.DynamicTableRouterLinkCache[item.hash + path]) {
2615
- return this.DynamicTableRouterLinkCache[item.hash + path];
3841
+ if (this.DynamicTableRouterLinkCache[item._hash + path]) {
3842
+ return this.DynamicTableRouterLinkCache[item._hash + path];
2616
3843
  }
2617
3844
  else {
2618
3845
  let link = this.getRouterLink(path, parameterProps, item);
2619
- this.DynamicTableRouterLinkCache[item.hash + path] = link;
3846
+ this.DynamicTableRouterLinkCache[item._hash + path] = link;
2620
3847
  return link;
2621
3848
  }
2622
3849
  }
@@ -2799,11 +4026,13 @@ class EsTableComponent {
2799
4026
  for (let i = 0; i < items.length; i++) {
2800
4027
  let item = items[i];
2801
4028
  // Prima di calcolare l'hash rimuovo le proprietà interne prima che mi scompensino i calcoli successivi
2802
- delete item._selected;
2803
- delete item.hash;
2804
- let hash = this.hashExts.hashObject(item);
4029
+ let tmp = Object.assign({}, items[i]);
4030
+ delete tmp._selected;
4031
+ delete tmp._visible;
4032
+ delete tmp._hash;
4033
+ let hash = this.hashExts.hashObject(tmp);
2805
4034
  usedHashesCache[hash] = usedHashesCache[hash] ? usedHashesCache[hash] + 1 : 1;
2806
- item.hash = hash + (usedHashesCache[hash] > 1 ? "_" + usedHashesCache[hash] : "");
4035
+ item._hash = hash + (usedHashesCache[hash] > 1 ? "_" + usedHashesCache[hash] : "");
2807
4036
  }
2808
4037
  }
2809
4038
  /**
@@ -2831,13 +4060,15 @@ EsTableComponent.decorators = [
2831
4060
  viewProviders: [{ provide: LocalizationService, useClass: EsTableLoc }],
2832
4061
  changeDetection: ChangeDetectionStrategy.OnPush,
2833
4062
  encapsulation: ViewEncapsulation.None,
2834
- template: "<!-- Patacchino di autoaggiornamento -->\r\n<div class=\"w-100\" *ngIf=\"AutoUpdate\">\r\n <div class=\"pull-right\">\r\n {{'Update every' | localize : lc}}&nbsp;<input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control est-custom-input\" type=\"text\" [(ngModel)]=\"seconds\" />&nbsp;{{'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>&nbsp;{{'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 [attr.colspan]=\"allColumns\" [class.est-hidden]=\"!canSelectAll && !(View?.selection || arraymodeSelection).all\">\r\n <span>{{ (selectedObjects || 0).toString() + ' ' + ((selectedObjects == 1 ? 'Object Selected' : 'Objects Selected') | localize : lc) }}</span>&nbsp;\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 || '') + (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 <ng-container *ngFor=\"let rowHeader of RowTHs\">\r\n <ng-container *ngIf=\"rowHeader && rowHeader.Visible\">\r\n <th es-th=\"{{rowHeader.ID}}\" [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\">\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 }}:&nbsp;\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 : ''\" \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 [contextMenu]=\"!item.locked ? (ContextMenu || emptyMenu) : emptyMenu\" [contextMenuSubject]=\"item\"\r\n (click)=\"(!item.locked && !item._group && !item._sep && handleClick($event, item)) || item._group && handleGroupClick(item)\">\r\n \r\n <td *ngIf=\"!item.locked && !item._group && !item._sep;\"><input type=\"checkbox\" [disabled]=\"templateOptions.selDisabled\" [class.est-pointer]=\"!item.locked\" [(ngModel)]=\"item._selected\" name=\"check{{i}}\"></td>\r\n <td *ngIf=\"item.locked || item._group || item._sep\"></td>\r\n\r\n <ng-container *ngIf=\"item._sep\">\r\n <td [attr.colspan]=\"allColumns\" class=\"est-rg-sep est-l-{{item._grouplevel}}\">\r\n <div class=\"est-rg-ipp\"> \r\n <span class=\"est-rg-ipp-sel\">10</span>&nbsp;|&nbsp;\r\n <span class=\"est-rg-ipp-sel\">15</span>&nbsp;|&nbsp;\r\n <span class=\"est-rg-ipp-sel\">30</span>&nbsp;|&nbsp;\r\n <span class=\"est-rg-ipp-sel\">45</span>&nbsp;|&nbsp;\r\n <span class=\"est-rg-ipp-sel\">100</span>&nbsp;|&nbsp;\r\n <span class=\"est-rg-ipp-sel-all\">{{'All' | localize: lc}}</span>\r\n </div>\r\n <div class=\"est-rg-page\">\r\n <span class=\"est-rg-page-prev\">&lt;</span>\r\n <span class=\"est-rg-page-sel\">1</span>\r\n <span class=\"est-rg-page-sel\">2</span>\r\n <span class=\"est-rg-page-sel\">3</span>\r\n <span class=\"est-rg-page-sel\">4</span>\r\n <span class=\"est-rg-page-sel\">5</span>\r\n <span class=\"est-rg-page-next\">&gt;</span>\r\n </div>\r\n </td>\r\n </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 *ngTemplateOutlet=\"bodyDeleteAndExport; context: { $implicit: { even: even, item: item }}\"></ng-container>\r\n </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 (click)=\"item._group && handleGroupClick(item)\">\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\" [Context]=\"item.hash\">\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\" [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>\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 <!-- 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}}\" \r\n [class.est-rg-hdr]=\"rowItem.GroupHeader\"\r\n [class.est-rg-agg]=\"rowItem.GroupAggregation\" \r\n [class.est-nowrap]=\"Hierarchy || !rowItem.Wraps\"\r\n [Internal]=\"true\">\r\n\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\">{{rowItem.Content}}</span>\r\n\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=\"app-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.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 <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\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 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 &nbsp;\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\">&times;</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>",
2835
- 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}.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-ipp{text-align:left}.est-rg-ipp,.est-rg-page{width:50%;display:inline-block}.est-rg-page{text-align:right}.est-l-1{padding-right:20px!important}.est-l-2{padding-left:20px!important;padding-right:40px!important}.est-l-3{padding-left:40px!important;padding-right:60px!important}.est-l-4{padding-left:60px!important;padding-right:80px!important}.est-l-5{padding-left:800px!important;padding-right:100px!important}.est-rg-sep{font-size:12px}.est-rg-ipp-sel{color:#8b4513;margin-left:3px}.est-rg-page-sel{color:#2e8b57;margin-left:3px;margin-right:3px}.est-rg-ipp-sel-all{color:#708090;margin-left:3px;margin-right:3px}.est-rg-page-next,.est-rg-page-prev{color:#000;font-weight:700}"]
4063
+ template: "<!-- Patacchino di autoaggiornamento -->\r\n<div class=\"w-100\" *ngIf=\"AutoUpdate\">\r\n <div class=\"pull-right\">\r\n {{'Update every' | localize : lc}}&nbsp;<input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control est-custom-input\" type=\"text\" [(ngModel)]=\"seconds\" />&nbsp;{{'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>&nbsp;{{'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>&nbsp;\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 &nbsp;\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\">&times;</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>",
4064
+ 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}.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}"]
2836
4065
  },] }
2837
4066
  ];
2838
4067
  EsTableComponent.ctorParameters = () => [
2839
4068
  { type: NgControl, decorators: [{ type: Self }, { type: Optional }] },
2840
4069
  { type: PreferencesService, decorators: [{ type: Optional }] },
4070
+ { type: EsTableDefaultable, decorators: [{ type: Optional }, { type: Inject, args: [EST_DEFAULTS,] }] },
4071
+ { type: String, decorators: [{ type: Optional }, { type: Inject, args: [EST_LOCALE,] }] },
2841
4072
  { type: LocalizationService },
2842
4073
  { type: ChangeDetectorRef },
2843
4074
  { type: HashingService },
@@ -2863,7 +4094,7 @@ EsTableComponent.propDecorators = {
2863
4094
  CellActionPropagates: [{ type: Input }],
2864
4095
  UseCustomCells: [{ type: Input }],
2865
4096
  MaxHeight: [{ type: Input }],
2866
- Class: [{ type: Input }],
4097
+ ContainerClass: [{ type: Input }],
2867
4098
  XLSXExport: [{ type: Input }],
2868
4099
  CSVExport: [{ type: Input }],
2869
4100
  AllSearch: [{ type: Input }],
@@ -2874,14 +4105,12 @@ EsTableComponent.propDecorators = {
2874
4105
  RemovalCondition: [{ type: Input }],
2875
4106
  Export: [{ type: Input }],
2876
4107
  ShiftClick: [{ type: Input }],
2877
- ShowPaging: [{ type: Input }],
2878
4108
  HidePaging: [{ type: Input }],
2879
4109
  HidePagingCount: [{ type: Input }],
2880
4110
  HidePagingButtons: [{ type: Input }],
2881
4111
  ContextMenu: [{ type: Input }],
2882
4112
  ExportFileName: [{ type: Input }],
2883
4113
  TableClass: [{ type: Input }],
2884
- CountLabel: [{ type: Input }],
2885
4114
  ExportFunction: [{ type: Input }],
2886
4115
  HasHeaderGroup: [{ type: Input }],
2887
4116
  HasSecondaryHeaderGroup: [{ type: Input }],
@@ -2907,9 +4136,12 @@ EsTableComponent.propDecorators = {
2907
4136
  OwnKey: [{ type: Input }],
2908
4137
  StartsExpanded: [{ type: Input }],
2909
4138
  SavePreferences: [{ type: Input }],
4139
+ PagingStyle: [{ type: Input }],
4140
+ RowGroupingPagingStyle: [{ type: Input }],
2910
4141
  SecondarySource: [{ type: Input }],
2911
4142
  TertiarySource: [{ type: Input }],
2912
4143
  UseSelectionCache: [{ type: Input }],
4144
+ ShowItemGroupsColumns: [{ type: Input }],
2913
4145
  onOrderChanged: [{ type: Output }],
2914
4146
  onSearchRequest: [{ type: Output }],
2915
4147
  onSelectionChanged: [{ type: Output }],
@@ -2923,22 +4155,18 @@ EsTableComponent.propDecorators = {
2923
4155
  ArraymodeItemsPerPage: [{ type: Input }]
2924
4156
  };
2925
4157
 
2926
- /**
2927
- * Modello di configurazione per L'EsTable
2928
- */
4158
+ /** Modello di configurazione per L'EsTable */
2929
4159
  class EsTableModuleConfig {
2930
4160
  }
2931
4161
 
2932
- /**
2933
- * Classe di localizzazione per il componente **TablePagerComponent**
2934
- */
4162
+ /** Classe di localizzazione per il componente **TablePagerComponent** */
2935
4163
  class TablePagerLoc extends LocalizationService {
2936
- /**
2937
- * @ignore
2938
- */
4164
+ /** @ignore */
2939
4165
  constructor(LOC_LOCALE) {
2940
4166
  super(LOC_LOCALE !== null && LOC_LOCALE !== void 0 ? LOC_LOCALE : 'it-IT');
2941
4167
  super.set("en->it", "All", ["Tutto"]);
4168
+ super.set("en->it", "Shown Elements", ["Elementi visualizzati"]);
4169
+ super.set("en->it", "Shown Groups", ["Gruppi visualizzati"]);
2942
4170
  super.set("en->it", "Are you sure you want to retrieve all results?", ["Si è sicuri di voler caricare tutti i risultati?"]);
2943
4171
  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"]);
2944
4172
  }
@@ -2951,32 +4179,35 @@ TablePagerLoc.ctorParameters = () => [
2951
4179
  ];
2952
4180
 
2953
4181
  // Angular
2954
- /**
2955
- * Componente che si occupa della paginazione di una tabella
2956
- */
4182
+ /** Componente che si occupa della paginazione di una tabella */
2957
4183
  class TablePagerComponent {
2958
- /**
2959
- * @ignore
2960
- */
2961
- constructor(msgExts, lc) {
4184
+ /** @ignore */
4185
+ constructor(msgExts, lc, cdr, locale) {
2962
4186
  this.msgExts = msgExts;
2963
4187
  this.lc = lc;
2964
- /**
2965
- * Indica se deve mostrare un warning quando si cercano di solezionare come elementi da visualizzare "Tutti"
2966
- */
4188
+ this.cdr = cdr;
4189
+ this.locale = locale;
4190
+ /** Indica se deve mostrare un warning quando si cercano di solezionare come elementi da visualizzare "Tutti" */
2967
4191
  this.WarnOnAll = true;
2968
- /**
2969
- * Indica se dare la possibilità o meno di selezionare "Tutti" nelle opzioni di paginazione
2970
- */
4192
+ /** Indica se dare la possibilità o meno di selezionare "Tutti" nelle opzioni di paginazione */
2971
4193
  this.AllSearch = true;
2972
- /**
2973
- * Placeholder che identifica il "Tutti"
2974
- */
4194
+ /** Placeholder che identifica il "Tutti" */
2975
4195
  this.DefaultAll = 999999;
2976
- /**
2977
- * Output invocato quando il numero di elementi per pagina viene modificato da un click utente
2978
- */
4196
+ /** Indica se attivare la modalità gruppo con stili più snelli per apparire sotto ai raggruppamenti */
4197
+ this.GroupMode = false;
4198
+ /** Indica se utilizzare il conteggio dei gruppi o degli oggetti */
4199
+ this.GroupCount = false;
4200
+ /** Indica se visualizzare il numero totale di oggeti presenti */
4201
+ this.ShowCount = true;
4202
+ /** Output invocato quando il numero di elementi per pagina viene modificato da un click utente */
2979
4203
  this.pagingSelected = new EventEmitter();
4204
+ /** Opzioni di paginazione */
4205
+ this.PagingOptions = [10, 15, 30, 45, 100];
4206
+ }
4207
+ ngOnInit() {
4208
+ this.Model = this.View ? this.View.itemsperpageoverride : this.CurrentPageSize;
4209
+ if (this.AllSearch)
4210
+ this.PagingOptions.push(this.DefaultAll);
2980
4211
  }
2981
4212
  /**
2982
4213
  * Funzione richiamata dal template quando un utente clicca su un numero di paginazione.
@@ -2987,30 +4218,48 @@ class TablePagerComponent {
2987
4218
  */
2988
4219
  choice(pageSize) {
2989
4220
  if (pageSize == this.DefaultAll && this.WarnOnAll) {
2990
- 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); });
4221
+ 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; }, () => {
4222
+ // Dio solo sa perché mi tocca fare sta roba... qui dentro per qualche motivo la CD non prende
4223
+ let prevModel = this.Model;
4224
+ this.Model = null;
4225
+ this.cdr.detectChanges();
4226
+ this.Model = prevModel;
4227
+ this.cdr.detectChanges();
4228
+ });
2991
4229
  }
2992
- else
4230
+ else {
2993
4231
  this.pagingSelected.emit(pageSize);
4232
+ this.Model = pageSize;
4233
+ }
2994
4234
  }
2995
4235
  }
2996
4236
  TablePagerComponent.decorators = [
2997
4237
  { type: Component, args: [{
2998
4238
  selector: "app-paging",
2999
4239
  viewProviders: [{ provide: LocalizationService, useClass: TablePagerLoc }],
3000
- template: "<!--Se non ho almeno 10 elementi non ha senso far vedere le opzioni di paginazione-->\r\n<ng-container *ngIf=\"View ? ((View.objectcount && View.objectcount >= 10) || View.pagingavailable) : !Hidden\">\r\n {{'Paging' | localize : lc}}:&nbsp;\r\n <span class=\"app-link app-inline\"\r\n [class.app-bold]=\"View ? View.itemsperpageoverride && View.itemsperpageoverride == 10 : CurrentPageSize == 10\"\r\n (click)=\"choice(10);\">\r\n 10\r\n </span>&nbsp;|&nbsp;\r\n\r\n <span class=\"app-link app-inline\"\r\n [class.app-bold]=\"View ? View.itemsperpageoverride && View.itemsperpageoverride == 15 : CurrentPageSize == 15\"\r\n (click)=\"choice(15);\">\r\n 15\r\n </span>&nbsp;|&nbsp;\r\n\r\n <span class=\"app-link app-inline\"\r\n [class.app-bold]=\"View ? View.itemsperpageoverride && View.itemsperpageoverride == 30 : CurrentPageSize == 30\"\r\n (click)=\"choice(30);\">\r\n 30\r\n </span>&nbsp;|&nbsp;\r\n\r\n <span class=\"app-link app-inline\"\r\n [class.app-bold]=\"View ? View.itemsperpageoverride && View.itemsperpageoverride == 45 : CurrentPageSize == 45\"\r\n (click)=\"choice(45);\">\r\n 45\r\n </span>&nbsp;|&nbsp;\r\n\r\n <span class=\"app-link app-inline\"\r\n [class.app-bold]=\"View ? View.itemsperpageoverride && View.itemsperpageoverride == 100 : CurrentPageSize == 100\"\r\n (click)=\"choice(100);\">\r\n 100\r\n </span><span *ngIf=\"AllSearch\">&nbsp;|&nbsp;</span>\r\n <span *ngIf=\"AllSearch\" class=\"app-link app-inline\"\r\n [class.app-bold]=\"View ? View.itemsperpageoverride && View.itemsperpageoverride == DefaultAll : CurrentPageSize == DefaultAll\"\r\n (click)=\"choice(DefaultAll);\">\r\n {{'All' | localize : lc}}\r\n </span>\r\n</ng-container>"
4240
+ template: "<ng-container *ngIf=\"!Hidden\">\r\n <span class=\"est-fs-14\"> {{(GroupMode ? 'Shown Groups' : 'Shown Elements') | localize : lc}}:&nbsp;</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\">&nbsp;/&nbsp;{{PagerCount | number : '0.0-0' : locale}}\r\n </span>\r\n</ng-container>",
4241
+ encapsulation: ViewEncapsulation.None,
4242
+ changeDetection: ChangeDetectionStrategy.OnPush,
4243
+ 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}"]
3001
4244
  },] }
3002
4245
  ];
3003
4246
  TablePagerComponent.ctorParameters = () => [
3004
4247
  { type: MessageService },
3005
- { type: LocalizationService }
4248
+ { type: LocalizationService },
4249
+ { type: ChangeDetectorRef },
4250
+ { type: String, decorators: [{ type: Optional }, { type: Inject, args: [EST_LOCALE,] }] }
3006
4251
  ];
3007
4252
  TablePagerComponent.propDecorators = {
3008
4253
  CurrentPageSize: [{ type: Input }],
3009
4254
  View: [{ type: Input }],
3010
- Hidden: [{ type: Input }],
3011
4255
  WarnOnAll: [{ type: Input }],
3012
4256
  AllSearch: [{ type: Input }],
3013
4257
  DefaultAll: [{ type: Input }],
4258
+ GroupMode: [{ type: Input }],
4259
+ GroupCount: [{ type: Input }],
4260
+ ShowCount: [{ type: Input }],
4261
+ PagerCount: [{ type: Input }],
4262
+ Hidden: [{ type: Input }],
3014
4263
  pagingSelected: [{ type: Output }]
3015
4264
  };
3016
4265
 
@@ -3019,7 +4268,8 @@ class EsTableModule {
3019
4268
  return {
3020
4269
  ngModule: EsTableModule,
3021
4270
  providers: [
3022
- { provide: EST_LOCALE, useValue: (config === null || config === void 0 ? void 0 : config.locale) || 'it-IT' }
4271
+ { provide: EST_LOCALE, useValue: (config === null || config === void 0 ? void 0 : config.locale) || 'it-IT' },
4272
+ { provide: EST_DEBUG, useValue: (config === null || config === void 0 ? void 0 : config.debugMode) || false }
3023
4273
  ]
3024
4274
  };
3025
4275
  }
@@ -3034,7 +4284,9 @@ EsTableModule.decorators = [
3034
4284
  ModalModule,
3035
4285
  BsDropdownModule,
3036
4286
  CsvModule,
3037
- ContextMenuModule
4287
+ ContextMenuModule,
4288
+ MatSelectModule,
4289
+ MatInputModule
3038
4290
  ],
3039
4291
  declarations: [EsTh, EsTd, EsTableComponent, EsTdDirective, EsThDirective, TablePagerComponent],
3040
4292
  providers: [UtilityService, ExportService, HashingService, MessageService],
@@ -3050,5 +4302,5 @@ EsTableModule.decorators = [
3050
4302
  * Generated bundle index. Do not edit.
3051
4303
  */
3052
4304
 
3053
- export { AppOrdering, AppSearch, CornerMenuOption, EsTableColumn, EsTableColumnsDefinition, EsTableComponent, EsTableModule, EsTableModuleConfig, EsTableOperationDefinition, EsTd, EsTh, GenericItem, Group, GroupAggregation, GroupFilter, GroupOrAggregation, ItemsSelection, ReportColumn, ReportDefinition, ReportOrder, ReportParam, ReportResult, ReportRow, EsTableLoc as ɵa, EST_LOCALE as ɵb, EsTdDirective as ɵc, EsThDirective as ɵd, TablePagerComponent as ɵe, TablePagerLoc as ɵf };
4305
+ 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 };
3054
4306
  //# sourceMappingURL=esfaenza-es-table.js.map